Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 2 additions & 41 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,6 @@ jobs:
with:
components: clippy
- uses: Swatinem/rust-cache@v2
# libudev-dev pulls in via fnox-core → ctap-hid-fido2 → hidapi for
# YubiKey/WebAuthn provider support. Matches upstream fnox CI.
- run: sudo apt-get update && sudo apt-get install -y pkg-config libudev-dev
- run: cargo clippy --all-targets --all-features -- -D warnings

test:
Expand All @@ -42,7 +39,6 @@ jobs:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- run: sudo apt-get update && sudo apt-get install -y pkg-config libudev-dev
- run: cargo build --all-targets --all-features
- run: cargo test --all-features

Expand All @@ -54,29 +50,12 @@ jobs:
- uses: rustsec/audit-check@v2.0.0
with:
token: ${{ secrets.GITHUB_TOKEN }}
# Keep in sync with deny.toml's [advisories].ignore. Each entry
# has a per-line rationale there. Revisit on every dep bump.
ignore: RUSTSEC-2024-0375,RUSTSEC-2023-0071,RUSTSEC-2025-0134,RUSTSEC-2026-0098,RUSTSEC-2026-0099,RUSTSEC-2026-0104

deny:
name: cargo deny
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: List accepted advisories (visibility)
# Surfaces deny.toml's [advisories].ignore list in every CI run
# so the six accepted RUSTSEC entries stay visible. Without this
# they're easy to forget and quietly become permanent.
run: |
echo "::group::Accepted RUSTSEC advisories (deny.toml ignore list)"
awk '
/^\[advisories\]/ { in_adv = 1; next }
/^\[/ && !/^\[advisories\]/ { in_adv = 0 }
in_adv && /RUSTSEC-/ {
print
}
' deny.toml
echo "::endgroup::"
- uses: EmbarkStudios/cargo-deny-action@v2
with:
command: check
Expand All @@ -87,25 +66,17 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# systemd-analyze fails the exec-check unless /usr/bin/remo-broker
# is present; stub with /bin/true so verify only complains about
# real unit-syntax issues.
- run: sudo install -m 0755 /bin/true /usr/bin/remo-broker
- run: systemd-analyze verify packaging/systemd/remo-broker.service

harnesses:
name: soak + killtest (short)
runs-on: ubuntu-latest
# Runs the SC-002 soak harness and SC-003 killtest at small scale
# on every PR — catches regressions in the patterns those harnesses
# exercise (concurrent fetches, restart cleanup, audit-log integrity
# under SIGKILL). Full SC-002 (50 sockets × 10 Hz × 1h) lives in
# the scheduled `.github/workflows/soak.yml` workflow.
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- run: sudo apt-get update && sudo apt-get install -y pkg-config libudev-dev
- run: cargo build --release # builds daemon binary (needed by killtest)
- run: cargo build --release --examples
- name: soak (5s smoke)
run: cargo run --release --example soak
Expand All @@ -115,30 +86,20 @@ jobs:
benches:
name: benches (compile)
runs-on: ubuntu-latest
# NFR-001/NFR-002 benchmarks live in benches/latency.rs. Full runs
# take ~15s and produce noisy timing data; CI just ensures they
# still compile and a `--quick` pass returns. Real numbers come
# from manual `cargo bench` runs by humans.
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- run: sudo apt-get update && sudo apt-get install -y pkg-config libudev-dev
- run: cargo bench --bench latency -- --quick

nfr:
name: NFR measurements
runs-on: ubuntu-latest
# Measures NFR-003 (startup ≤500ms), NFR-004 (idle RSS ≤30MB), and
# NFR-005 (binary size ≤15MB) against the release build. NFR-003 +
# NFR-004 hard-fail; NFR-005 is currently informational because the
# fnox-core dep chain (AWS SDK + ctap-hid-fido2 + transitives) puts
# the binary at ~32MiB. Track NFR-005 follow-up in the spec.
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- run: sudo apt-get update && sudo apt-get install -y pkg-config libudev-dev socat
- run: sudo apt-get update && sudo apt-get install -y socat
- run: cargo build --release
- name: Measure
run: bash ci/measure_nfr.sh
55 changes: 16 additions & 39 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Trigger: push of a vX.Y.Z tag.
# Publishes: stripped x86_64 + aarch64 Linux binaries, .sha256 files, and schema/remo-broker.v1.json.
# Cut a release: git tag v0.1.0 && git push --tags
# Publishes: stripped x86_64 + aarch64 Linux binaries, .sha256 files, and schema/remo-broker.v2.json.
# Cut a release: git tag v0.2.0 && git push --tags
name: Release

on:
Expand All @@ -10,9 +10,6 @@ on:

env:
CARGO_TERM_COLOR: always
# Keep -D warnings off here; release tags implicitly trust main (which
# CI already gated with -D warnings). We don't want a new compiler warning
# in a future stable Rust to block a hotfix tag from publishing.

permissions:
contents: write
Expand All @@ -34,61 +31,45 @@ jobs:

- name: Derive version from tag
id: version
# GITHUB_REF is refs/tags/vX.Y.Z; strip the refs/tags/v prefix.
run: |
version="${GITHUB_REF#refs/tags/v}"
echo "version=${version}" >> "$GITHUB_OUTPUT"
echo "Building remo-broker v${version} for ${{ matrix.target }}"

- uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}

- uses: Swatinem/rust-cache@v2
with:
key: release-${{ matrix.target }}

- name: Install native libudev (x86_64 fast path)
# cross's `target == host` heuristic falls back to native cargo for
# x86_64-unknown-linux-gnu on an x86_64 runner — no Docker, so the
# libudev that fnox-core -> ctap-hid-fido2 -> hidapi needs must
# come from the runner itself. aarch64 still goes through cross's
# Docker image which ships its own sysroot.
if: matrix.arch == 'x86_64'
- name: Install aarch64 cross-linker
if: matrix.arch == 'aarch64'
run: |
sudo apt-get update
sudo apt-get install -y libudev-dev pkg-config

- name: Install cross
# cross-rs handles aarch64 via prebuilt Docker images that include
# the C toolchains + libudev that fnox-core -> hidapi needs.
# Pinned by version (not SHA) because cross is a cargo-installed binary
# and we want a known-good release, not whatever git happens to be at.
run: cargo install cross --version 0.2.5 --locked
sudo apt-get install -y gcc-aarch64-linux-gnu

- name: Build release binary
run: cross build --release --locked --target ${{ matrix.target }}
run: |
if [ "${{ matrix.arch }}" = "aarch64" ]; then
export CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc
fi
cargo build --release --locked --target ${{ matrix.target }}

- name: Strip binary
# release profile already has strip = "symbols", but run strip again
# via the target's binutils to be defensive — covers anything the
# cargo profile missed (e.g. note sections from future toolchain bumps).
run: |
set -euo pipefail
bin="target/${{ matrix.target }}/release/remo-broker"
if [ "${{ matrix.arch }}" = "x86_64" ]; then
strip "$bin"
else
sudo apt-get update
sudo apt-get install -y binutils-aarch64-linux-gnu
aarch64-linux-gnu-strip "$bin"
fi

- name: Stage release artifacts
id: stage
# Canonical names match what remo's broker_install Ansible role expects:
# remo-broker-v<version>-<arch>-unknown-linux-gnu(.sha256)
# The .sha256 file uses GNU coreutils `sha256sum` format
# (`<hex> <filename>\n`); remo splits on whitespace and takes the
# first token, so this matches both `sha256sum -c` and remo's parser.
run: |
set -euo pipefail
version="${{ steps.version.outputs.version }}"
Expand Down Expand Up @@ -128,13 +109,12 @@ jobs:
run: |
set -euo pipefail
mkdir -p release
# Flatten the per-arch subdirs created by download-artifact.
find artifacts -type f -name 'remo-broker-v*' -exec cp {} release/ \;
# Schema artifact published as-is, alongside the binaries.
cp schema/remo-broker.v1.json release/
# v2 wire schema published alongside the binaries (FR-010).
cp schema/remo-broker.v2.json release/ 2>/dev/null || true
# v1 manifest schema also published for downstream tooling.
cp schema/remo-broker.v1.json release/ 2>/dev/null || true
ls -la release/
# Sanity: 5 files total (2 binaries + 2 .sha256 + 1 schema).
test "$(ls release | wc -l)" = "5"

- name: Create GitHub release
env:
Expand All @@ -147,9 +127,6 @@ jobs:
release/*

- name: Smoke-test the published x86_64 binary
# Downloads the just-published artifact through the public release API
# and runs --version on it, proving the upload round-tripped intact
# and the binary is executable on a stock ubuntu-latest runner.
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
Expand Down
1 change: 0 additions & 1 deletion .github/workflows/soak.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ jobs:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- run: sudo apt-get update && sudo apt-get install -y pkg-config libudev-dev
- run: cargo build --release --example soak
- name: soak (full SC-002 config)
env:
Expand Down
149 changes: 149 additions & 0 deletions .specify/extensions.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
installed:
- git
settings:
auto_execute_hooks: true
hooks:
before_constitution:
- extension: git
command: speckit.git.initialize
enabled: true
optional: false
prompt: Execute speckit.git.initialize?
description: Initialize Git repository before constitution setup
condition: null
before_specify:
- extension: git
command: speckit.git.feature
enabled: true
optional: false
prompt: Execute speckit.git.feature?
description: Create feature branch before specification
condition: null
before_clarify:
- extension: git
command: speckit.git.commit
enabled: true
optional: true
prompt: Commit outstanding changes before clarification?
description: Auto-commit before spec clarification
condition: null
before_plan:
- extension: git
command: speckit.git.commit
enabled: true
optional: true
prompt: Commit outstanding changes before planning?
description: Auto-commit before implementation planning
condition: null
before_tasks:
- extension: git
command: speckit.git.commit
enabled: true
optional: true
prompt: Commit outstanding changes before task generation?
description: Auto-commit before task generation
condition: null
before_implement:
- extension: git
command: speckit.git.commit
enabled: true
optional: true
prompt: Commit outstanding changes before implementation?
description: Auto-commit before implementation
condition: null
before_checklist:
- extension: git
command: speckit.git.commit
enabled: true
optional: true
prompt: Commit outstanding changes before checklist?
description: Auto-commit before checklist generation
condition: null
before_analyze:
- extension: git
command: speckit.git.commit
enabled: true
optional: true
prompt: Commit outstanding changes before analysis?
description: Auto-commit before analysis
condition: null
before_taskstoissues:
- extension: git
command: speckit.git.commit
enabled: true
optional: true
prompt: Commit outstanding changes before issue sync?
description: Auto-commit before tasks-to-issues conversion
condition: null
after_constitution:
- extension: git
command: speckit.git.commit
enabled: true
optional: true
prompt: Commit constitution changes?
description: Auto-commit after constitution update
condition: null
after_specify:
- extension: git
command: speckit.git.commit
enabled: true
optional: true
prompt: Commit specification changes?
description: Auto-commit after specification
condition: null
after_clarify:
- extension: git
command: speckit.git.commit
enabled: true
optional: true
prompt: Commit clarification changes?
description: Auto-commit after spec clarification
condition: null
after_plan:
- extension: git
command: speckit.git.commit
enabled: true
optional: true
prompt: Commit plan changes?
description: Auto-commit after implementation planning
condition: null
after_tasks:
- extension: git
command: speckit.git.commit
enabled: true
optional: true
prompt: Commit task changes?
description: Auto-commit after task generation
condition: null
after_implement:
- extension: git
command: speckit.git.commit
enabled: true
optional: true
prompt: Commit implementation changes?
description: Auto-commit after implementation
condition: null
after_checklist:
- extension: git
command: speckit.git.commit
enabled: true
optional: true
prompt: Commit checklist changes?
description: Auto-commit after checklist generation
condition: null
after_analyze:
- extension: git
command: speckit.git.commit
enabled: true
optional: true
prompt: Commit analysis results?
description: Auto-commit after analysis
condition: null
after_taskstoissues:
- extension: git
command: speckit.git.commit
enabled: true
optional: true
prompt: Commit after syncing issues?
description: Auto-commit after tasks-to-issues conversion
condition: null
Loading
Loading