From 88c4670f5e57cc85e3d8b3827ab487693a3d9ca7 Mon Sep 17 00:00:00 2001 From: claude-release Date: Tue, 21 Jul 2026 02:26:14 +0100 Subject: [PATCH 1/3] ci: share Rust builds across jobs (sccache + build-once CLI artifact) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every compiling CI job recompiled the same dependency graph in its own per-job cache namespace, so nothing was shared across jobs. This wires three levers to fix that: 1. sccache — the setup-rust composite now installs mozilla-actions/ sccache-action and sets RUSTC_WRAPPER=sccache with the GHA backend, so a crate compiled once (in any job/runner) is reused everywhere its inputs match. Added to ci.yml jobs, node-sdk, python-sdk, verify-commits, and test-windows-build. 2. build-once, fan-out — a new build-cli job compiles auths-cli + auths-mcp-gateway once per OS and uploads the binaries as an artifact; smoke and e2e download and run them instead of recompiling (and drop the Rust toolchain entirely). e2e keeps its gate via needs: [test, build-cli]. 3. consolidated caching — the composite is now the single place that configures the toolchain and swaps the hand-rolled actions/cache for Swatinem/rust-cache (deps-only, auto-pruned). Jobs whose build dir is not the workspace target (fuzz-smoke, node-sdk, python-sdk) pass cache: false and keep their own scoped cache. No CI check was removed: same jobs (plus build-cli), same lint/test/ verify commands; only build and cache plumbing changed. Validated with actionlint (clean) and a before/after check inventory. Auths-Scope: sign_commit Auths-Id: did:keri:EB5cPHY0t-ejNC_rUzPS1dclTvd6kG-R9mQzjozCuGgd Auths-Device: did:keri:EO1cBsYoV5izKvdIL6TstN5TOQl1hYN3WnhtAOh1lwAp Auths-Anchor-Seq: 13 --- .github/actions/setup-rust/action.yml | 55 ++++++-- .github/workflows/ci.yml | 160 ++++++++++------------- .github/workflows/node-sdk.yml | 12 +- .github/workflows/python-sdk.yml | 8 +- .github/workflows/test-windows-build.yml | 8 ++ .github/workflows/verify-commits.yml | 9 ++ 6 files changed, 145 insertions(+), 107 deletions(-) diff --git a/.github/actions/setup-rust/action.yml b/.github/actions/setup-rust/action.yml index 6ad9f97c5..31f05bfe6 100644 --- a/.github/actions/setup-rust/action.yml +++ b/.github/actions/setup-rust/action.yml @@ -1,9 +1,25 @@ name: Setup Rust -description: Install Rust toolchain from rust-toolchain.toml and cache cargo artifacts +description: Install the pinned Rust toolchain, wire sccache as a shared compiler cache, and cache cargo artifacts. inputs: + toolchain: + description: 'Rust toolchain to install (e.g. "1.93", "stable", "nightly").' + required: false + default: "1.93" components: - description: Rust components to install (comma-separated) + description: Rust components to install (comma-separated). + required: false + default: "" + targets: + description: Rust targets to install (comma-separated). + required: false + default: "" + cache: + description: 'Cache cargo deps + target with Swatinem/rust-cache. Set "false" for jobs whose build dir is not the workspace target (they keep their own cache).' + required: false + default: "true" + cache-shared-key: + description: Swatinem/rust-cache shared-key. Set the same value on two jobs to share one dependency cache; empty keeps the cache per-job. required: false default: "" @@ -12,14 +28,31 @@ runs: steps: - uses: dtolnay/rust-toolchain@master with: - toolchain: "1.93" + toolchain: ${{ inputs.toolchain }} components: ${{ inputs.components }} - - uses: actions/cache@v4 + targets: ${{ inputs.targets }} + + # Content-addressed compiler cache shared across every job and runner: a crate + # compiled once (in any job) is reused everywhere its inputs match. This is what + # lets the parallel fmt/clippy/test/build jobs stop recompiling the same + # dependency graph — the per-job target cache below cannot cross job boundaries. + - uses: mozilla-actions/sccache-action@v0.0.9 + + - name: Wire sccache as the rustc wrapper + shell: bash + run: | + { + echo "RUSTC_WRAPPER=sccache" + echo "SCCACHE_GHA_ENABLED=true" + echo "CARGO_INCREMENTAL=0" + } >> "$GITHUB_ENV" + + # Restores a warm ~/.cargo (registry + git) and target/ for repeat runs of the + # SAME job, caching dependencies only (not the fast-changing workspace crates) + # and pruning stale artifacts so the cache does not grow unbounded. Complements + # sccache, which is what shares compiled crates ACROSS jobs. + - uses: Swatinem/rust-cache@v2 + if: inputs.cache == 'true' with: - path: | - ~/.cargo/registry - ~/.cargo/git - ~/.cargo/bin - target - key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ runner.os }}-cargo- + shared-key: ${{ inputs.cache-shared-key }} + cache-on-failure: "true" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5a767ff13..fbcd53af8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,17 +49,10 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@stable + - uses: ./.github/actions/setup-rust with: + toolchain: stable components: clippy - - uses: actions/cache@v4 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ${{ runner.os }}-clippy-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ runner.os }}-clippy- # `fips`/`cnsa` are mutually exclusive (RT-012 compile_error! in # auths-crypto/src/provider.rs), so --all-features can't compile. Lint the # bulk workspace minus the five dual-provider crypto crates, then lint those @@ -77,17 +70,10 @@ jobs: - uses: actions/setup-python@v5 with: python-version: '3.12' - - uses: dtolnay/rust-toolchain@stable + - uses: ./.github/actions/setup-rust with: + toolchain: stable components: rustfmt, clippy - - uses: actions/cache@v4 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ${{ runner.os }}-precommit-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ runner.os }}-precommit- # Run the same hooks developers run locally, so a commit that passes local # hooks cannot fail CI on format/lint/hygiene drift. The workspace # cargo-fmt and cargo-clippy hooks run byte-identical commands in the @@ -124,24 +110,49 @@ jobs: - name: Crypto primitive inventory is current run: python3 scripts/check_primitive_inventory.py + build-cli: + name: Build CLI binaries (${{ matrix.os }}) + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-latest] + steps: + - uses: actions/checkout@v4 + - uses: ./.github/actions/setup-rust + # Build the debug binaries once and share them as an artifact so the smoke + # and e2e jobs run against a prebuilt CLI instead of each recompiling it. + # sccache already dedupes the compiles across jobs; the artifact additionally + # lets those downstream jobs drop the Rust toolchain entirely. + - name: Build auths CLI + MCP gateway + run: cargo build --package auths-cli --package auths-mcp-gateway + - name: Stage binaries + run: | + mkdir -p cli-bins + cp target/debug/auths target/debug/auths-sign target/debug/auths-verify target/debug/auths-mcp-gateway cli-bins/ + - name: Upload CLI binaries + uses: actions/upload-artifact@v4 + with: + name: cli-bins-${{ matrix.os }} + path: cli-bins/ + smoke: name: Golden-path smoke test + needs: build-cli runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@stable - - uses: actions/cache@v4 + - name: Download CLI binaries + uses: actions/download-artifact@v4 with: - path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ${{ runner.os }}-smoke-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ runner.os }}-smoke- - - name: Build CLI - run: cargo build -p auths-cli + name: cli-bins-ubuntu-latest + path: cli-bins + - name: Make binaries executable + run: chmod +x cli-bins/* - name: Run golden-path smoke test run: python3 docs/smoketests/end_to_end.py + env: + AUTHS_BIN: ${{ github.workspace }}/cli-bins/auths - name: Upload smoke results if: always() uses: actions/upload-artifact@v4 @@ -154,15 +165,9 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@stable - - uses: actions/cache@v4 + - uses: ./.github/actions/setup-rust with: - path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ${{ runner.os }}-schemas-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ runner.os }}-schemas- + toolchain: stable - name: Regenerate schemas and check for drift run: | cargo run -p xtask -- generate-schemas @@ -186,16 +191,9 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@stable - - - uses: actions/cache@v4 + - uses: ./.github/actions/setup-rust with: - path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ${{ runner.os }}-test-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ runner.os }}-test- + toolchain: stable - name: Install nextest uses: taiki-e/install-action@nextest @@ -291,15 +289,9 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@stable - - uses: actions/cache@v4 + - uses: ./.github/actions/setup-rust with: - path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ${{ runner.os }}-pq-hybrid-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ runner.os }}-pq-hybrid- + toolchain: stable - name: Install nextest uses: taiki-e/install-action@nextest # fn-129.T10: exercise the experimental `pq-hybrid` feature. The @@ -317,32 +309,17 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@1.93 - - uses: actions/cache@v4 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ${{ runner.os }}-msrv-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ runner.os }}-msrv- + - uses: ./.github/actions/setup-rust - run: cargo check --workspace wasm: name: WASM build (auths-verifier) runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@stable + - uses: ./.github/actions/setup-rust with: + toolchain: stable targets: wasm32-unknown-unknown - - uses: actions/cache@v4 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ${{ runner.os }}-wasm-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ runner.os }}-wasm- - name: Install wasm-pack run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh - name: Build WASM with wasm-pack @@ -375,7 +352,13 @@ jobs: targets: fuzz_cesr_import fuzz_parse_cesr fuzz_validate_kel fuzz_receipt_couples fuzz_attachment_parse steps: - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@nightly + # cache: false — the fuzz build dir is ${{ matrix.dir }}/target, not the + # workspace target Swatinem manages, so this job keeps its own matrix-keyed + # cache below and only takes the toolchain + shared sccache from the composite. + - uses: ./.github/actions/setup-rust + with: + toolchain: nightly + cache: "false" - uses: actions/cache@v4 with: path: | @@ -405,15 +388,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@1.93 - - uses: actions/cache@v4 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ${{ runner.os }}-conformance-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ runner.os }}-conformance- + - uses: ./.github/actions/setup-rust - uses: astral-sh/setup-uv@v4 # keripy's crypto (pysodium) loads libsodium via ctypes at runtime. - name: Install libsodium (keripy runtime dependency) @@ -447,7 +422,7 @@ jobs: e2e-tests: name: E2E Tests (${{ matrix.os }}) - needs: [test] + needs: [test, build-cli] runs-on: ${{ matrix.os }} strategy: fail-fast: false @@ -455,19 +430,18 @@ jobs: os: [ubuntu-latest, macos-latest] steps: - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@1.93 - - uses: actions/cache@v4 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ${{ runner.os }}-e2e-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ runner.os }}-e2e- - uses: astral-sh/setup-uv@v4 - - name: Build auths binaries - run: cargo build --package auths-cli --package auths-mcp-gateway + # Consume the prebuilt CLI + gateway from build-cli instead of recompiling. + # Restoring them into target/debug keeps the AUTHS_*_BIN paths below and the + # harness's target/debug fallback (for auths-mcp-gateway) unchanged. + - name: Download auths binaries + uses: actions/download-artifact@v4 + with: + name: cli-bins-${{ matrix.os }} + path: target/debug + - name: Make binaries executable + run: chmod +x target/debug/auths target/debug/auths-sign target/debug/auths-verify target/debug/auths-mcp-gateway - name: Configure git run: | diff --git a/.github/workflows/node-sdk.yml b/.github/workflows/node-sdk.yml index 7630e594a..142f7afe9 100644 --- a/.github/workflows/node-sdk.yml +++ b/.github/workflows/node-sdk.yml @@ -33,7 +33,13 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@stable + # cache: false — this build's target dir is packages/auths-node/target, not + # the workspace target, so keep the package-scoped cache below and take only + # the toolchain + shared sccache from the composite. + - uses: ./.github/actions/setup-rust + with: + toolchain: stable + cache: "false" - uses: actions/cache@v4 with: @@ -85,9 +91,11 @@ jobs: # Pin to the repo's toolchain (1.93) so this fmt/clippy gate is # reproducible; an unpinned @stable drifts ahead of the pinned formatting # and fails spuriously (was red on main for exactly this reason). - - uses: dtolnay/rust-toolchain@1.93.0 + - uses: ./.github/actions/setup-rust with: + toolchain: "1.93.0" components: rustfmt, clippy + cache: "false" - uses: actions/cache@v4 with: diff --git a/.github/workflows/python-sdk.yml b/.github/workflows/python-sdk.yml index 6e5ba97a2..f77b93c5e 100644 --- a/.github/workflows/python-sdk.yml +++ b/.github/workflows/python-sdk.yml @@ -30,7 +30,13 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@stable + # cache: false — this build's target dir is packages/auths-python/target, not + # the workspace target, so keep the package-scoped cache below and take only + # the toolchain + shared sccache from the composite. + - uses: ./.github/actions/setup-rust + with: + toolchain: stable + cache: "false" - uses: actions/cache@v4 with: diff --git a/.github/workflows/test-windows-build.yml b/.github/workflows/test-windows-build.yml index 5ffb68c66..d0b48b657 100644 --- a/.github/workflows/test-windows-build.yml +++ b/.github/workflows/test-windows-build.yml @@ -9,6 +9,10 @@ permissions: jobs: build: runs-on: windows-latest + env: + RUSTC_WRAPPER: sccache + SCCACHE_GHA_ENABLED: "true" + CARGO_INCREMENTAL: "0" steps: - uses: actions/checkout@v4 @@ -18,6 +22,10 @@ jobs: rustup default 1.93 rustup target add x86_64-pc-windows-msvc + # Shared compiler cache, layered on the Swatinem dependency cache below. + - name: Set up sccache + uses: mozilla-actions/sccache-action@v0.0.9 + - uses: Swatinem/rust-cache@v2 with: key: x86_64-pc-windows-msvc diff --git a/.github/workflows/verify-commits.yml b/.github/workflows/verify-commits.yml index fe9bcdfe4..9423852d2 100644 --- a/.github/workflows/verify-commits.yml +++ b/.github/workflows/verify-commits.yml @@ -10,6 +10,10 @@ permissions: jobs: verify: runs-on: ubuntu-latest + env: + RUSTC_WRAPPER: sccache + SCCACHE_GHA_ENABLED: "true" + CARGO_INCREMENTAL: "0" steps: - uses: actions/checkout@v4 with: @@ -26,6 +30,11 @@ jobs: with: toolchain: "1.93" + # Shared compiler cache: the release build reuses crates compiled by other + # jobs/runs whose inputs match, layered on the Swatinem dependency cache below. + - name: Set up sccache + uses: mozilla-actions/sccache-action@v0.0.9 + - name: Cache Rust dependencies uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 with: From 0cbf63b97e61392c2a8153c3463c64c105ed34ca Mon Sep 17 00:00:00 2001 From: claude-release Date: Tue, 21 Jul 2026 03:13:34 +0100 Subject: [PATCH 2/3] ci: cancel superseded in-progress PR runs (concurrency) Auths-Scope: sign_commit Auths-Id: did:keri:EB5cPHY0t-ejNC_rUzPS1dclTvd6kG-R9mQzjozCuGgd Auths-Device: did:keri:EO1cBsYoV5izKvdIL6TstN5TOQl1hYN3WnhtAOh1lwAp Auths-Anchor-Seq: 13 --- .github/workflows/ci.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fbcd53af8..070898da7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,6 +19,12 @@ on: permissions: contents: read +concurrency: + # Cancel superseded in-progress runs on the same PR to save runner minutes; + # never cancel a main-branch run (each pushed commit must be fully verified). + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + env: CARGO_TERM_COLOR: always RUSTFLAGS: -D warnings From 71ddf1f10a4d058c331ab9cea8eba3a81ec11d97 Mon Sep 17 00:00:00 2001 From: claude-release Date: Tue, 21 Jul 2026 03:48:12 +0100 Subject: [PATCH 3/3] ci: run postgres integration tests against a real Postgres service They had no server in CI, so each spent the 30s sqlx acquire_timeout retrying a dead socket then skipped (PASS, ~13min serial, zero coverage). Give them a dedicated ubuntu job with a postgres:16 service (service containers are Linux-only; the macOS leg never enabled backend-postgres) and filter the binary out of the main run so it no longer times out there. Auths-Scope: sign_commit Auths-Id: did:keri:EB5cPHY0t-ejNC_rUzPS1dclTvd6kG-R9mQzjozCuGgd Auths-Device: did:keri:EO1cBsYoV5izKvdIL6TstN5TOQl1hYN3WnhtAOh1lwAp Auths-Anchor-Seq: 13 --- .github/workflows/ci.yml | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 070898da7..1c1765988 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -240,9 +240,12 @@ jobs: # dual-provider crypto crates, then run those five under FIPS (the provider # this job has always exercised — aws-lc-rs needs the Go/CMake toolchain # installed above). + # postgres_integration is excluded here — it needs a live Postgres and runs + # in the dedicated `postgres-tests` job. Without a server it would spend the + # sqlx acquire_timeout (30s) per test retrying a dead socket, then skip. - name: Run tests (Ubuntu — all features, crypto crates excluded) if: matrix.os == 'ubuntu-latest' - run: cargo nextest run --workspace --all-features --no-fail-fast --exclude auths-crypto --exclude auths-core --exclude auths-keri --exclude auths-pairing-protocol --exclude auths-pairing-daemon + run: cargo nextest run --workspace --all-features --no-fail-fast --exclude auths-crypto --exclude auths-core --exclude auths-keri --exclude auths-pairing-protocol --exclude auths-pairing-daemon -E 'not binary(postgres_integration)' - name: Run tests (Ubuntu — crypto crates under FIPS) if: matrix.os == 'ubuntu-latest' run: cargo nextest run -p auths-crypto -p auths-core -p auths-keri -p auths-pairing-protocol -p auths-pairing-daemon --features fips --no-fail-fast @@ -261,6 +264,40 @@ jobs: if: matrix.os == 'ubuntu-latest' run: cargo audit + postgres-tests: + name: Postgres integration tests + needs: [fmt, clippy] + runs-on: ubuntu-latest + services: + postgres: + image: postgres:16 + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: postgres + ports: + - 5432:5432 + options: >- + --health-cmd "pg_isready -U postgres" + --health-interval 10s + --health-timeout 5s + --health-retries 5 + env: + # The harness reads these first (overriding its passwordless localhost + # default): the admin URL provisions auths_registry_test, the test URL + # connects to it. Service containers are Linux-only, so these tests get + # their own ubuntu job rather than the cross-OS matrix — the macOS test leg + # never enables backend-postgres, so it does not run them anyway. + AUTHS_TEST_ADMIN_DATABASE_URL: postgres://postgres:postgres@127.0.0.1:5432/postgres + AUTHS_TEST_DATABASE_URL: postgres://postgres:postgres@127.0.0.1:5432/auths_registry_test + steps: + - uses: actions/checkout@v4 + - uses: ./.github/actions/setup-rust + - name: Install nextest + uses: taiki-e/install-action@nextest + - name: Run Postgres integration tests + run: cargo nextest run -p auths-storage --features backend-postgres -E 'binary(postgres_integration)' + # capsec-audit: # name: Capability Audit # runs-on: ubuntu-latest