From 3001f281002f676743c6a794e873e43673fa67ab Mon Sep 17 00:00:00 2001 From: Jared Lunde Date: Tue, 19 May 2026 11:29:33 -0700 Subject: [PATCH 1/3] ci: unify workflow shape (parallel jobs, composites, weekly cargo-deny) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Restructure ci.yml around five parallel jobs (lint, generate-check, rust-test, handoff-test, ts-test) with distinct rust-cache slots so cargo target dirs no longer evict each other between phases. Replaces the single-job pipeline that ran dev-profile tests and release-profile compilation in the same cache slot. Adds .github/actions/setup-rust composite — checkout + mise + rustup components + Swatinem/rust-cache with per-job shared-key — shared across every Rust-touching job. Same shape will be vendored into kv/auth/queue. Drops build:rs:release from CI; release-api/release-sdk workflows already produce release artifacts. CI verifies the dev-profile path which links the same crates via clippy + tests. Moves security scanning to a weekly cargo-deny workflow (advisories + licenses + bans + sources) that opens a GitHub issue on regression instead of blocking PRs. Replaces the cargo-audit step that was bolted on then removed because it was per-push churn without an owner. Concurrency group cancels in-flight PR runs on force-push (main pushes are unaffected). Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/actions/setup-rust/action.yml | 23 +++++++++ .github/workflows/ci.yml | 73 +++++++++++++++++---------- .github/workflows/security.yml | 31 ++++++++++++ deny.toml | 47 +++++++++++++++++ 4 files changed, 147 insertions(+), 27 deletions(-) create mode 100644 .github/actions/setup-rust/action.yml create mode 100644 .github/workflows/security.yml create mode 100644 deny.toml diff --git a/.github/actions/setup-rust/action.yml b/.github/actions/setup-rust/action.yml new file mode 100644 index 0000000..abeb6fd --- /dev/null +++ b/.github/actions/setup-rust/action.yml @@ -0,0 +1,23 @@ +name: setup-rust +description: | + Common setup for jobs that need Rust + mise. Caller must run + actions/checkout@v6 before this composite. Pass a distinct cache-key per + job so rust-cache slots do not evict each other (which is the single + biggest source of cold-rebuild waste in the old CI). +inputs: + cache-key: + description: rust-cache shared-key. Use a unique value per job (e.g. lint, rust-test, handoff-test, ts-test, sqlx-check, gen). + required: true +runs: + using: composite + steps: + - uses: jdx/mise-action@v4 + with: + cache: true + - name: rustup components + shell: bash + run: rustup component add rustfmt clippy + - uses: Swatinem/rust-cache@v2 + with: + shared-key: ${{ inputs.cache-key }} + cache-on-failure: true diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 62937b5..514779b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,43 +4,62 @@ on: branches: [main] pull_request: branches: [main] +concurrency: + group: ci-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} env: CARGO_TERM_COLOR: always + jobs: - ci: + lint: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - - uses: jdx/mise-action@v4 - - uses: Swatinem/rust-cache@v2 - - name: ensure rustfmt/clippy components - run: rustup component add rustfmt clippy - - name: check:fmt - run: mise run check:fmt - - name: check:rs - run: mise run check:rs - - name: test:unit:rs - run: mise run test:unit:rs - - name: test:integration:rs - run: mise run test:integration:rs - - name: test:handoff:rs - run: mise run test:handoff:rs - - name: check:ts - run: mise run check:ts - - name: build:rs:release - run: mise run build:rs:release - - name: build:ts - run: mise run build:ts - - name: test:integration:ts - run: mise run test:integration:ts + - uses: ./.github/actions/setup-rust + with: + cache-key: lint + - run: mise run check:fmt + - run: mise run check:rs + generate-check: name: generated files up-to-date runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - - uses: jdx/mise-action@v4 - - uses: Swatinem/rust-cache@v2 - - name: generate - run: mise run generate:openapi && mise run generate:types + - uses: ./.github/actions/setup-rust + with: + cache-key: gen + - run: mise run generate:openapi + - run: mise run generate:types - name: check no diff run: git diff --exit-code -- openapi/v1.json sdk/ts/src/types.ts + + rust-test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - uses: ./.github/actions/setup-rust + with: + cache-key: rust-test + - run: mise run test:unit:rs + - run: mise run test:integration:rs + + handoff-test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - uses: ./.github/actions/setup-rust + with: + cache-key: handoff-test + - run: mise run test:handoff:rs + + ts-test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - uses: ./.github/actions/setup-rust + with: + cache-key: ts-test + - run: mise run check:ts + - run: mise run build:ts + - run: mise run test:integration:ts diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml new file mode 100644 index 0000000..b3e7f40 --- /dev/null +++ b/.github/workflows/security.yml @@ -0,0 +1,31 @@ +name: Security +on: + schedule: + # Mondays 14:00 UTC. Weekly cadence — real advisory churn, not per-push theater. + - cron: "0 14 * * 1" + workflow_dispatch: + +permissions: + contents: read + issues: write + +jobs: + cargo-deny: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - uses: EmbarkStudios/cargo-deny-action@v2 + id: deny + with: + command: check advisories licenses bans sources + arguments: --workspace --all-features + - name: open regression issue + if: failure() + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + run: | + gh issue create \ + --title "cargo-deny regression ($(date -u +%Y-%m-%d))" \ + --label security,automation \ + --body "Weekly cargo-deny found a new advisory/license/ban/source issue. Run: $RUN_URL" diff --git a/deny.toml b/deny.toml new file mode 100644 index 0000000..c151b59 --- /dev/null +++ b/deny.toml @@ -0,0 +1,47 @@ +# cargo-deny config. Scoped weekly via .github/workflows/security.yml. +# Not run on PR — that was the cargo-audit theater this replaces. Real +# regressions open a GitHub issue. + +[graph] +all-features = true + +[advisories] +version = 2 +yanked = "deny" +ignore = [] + +[licenses] +version = 2 +# Permissive licenses allowed across the workspace + transitive deps. +allow = [ + "MIT", + "Apache-2.0", + "Apache-2.0 WITH LLVM-exception", + "BSD-2-Clause", + "BSD-3-Clause", + "ISC", + "Unicode-3.0", + "Unicode-DFS-2016", + "Zlib", + "MPL-2.0", + "CC0-1.0", + "0BSD", +] +confidence-threshold = 0.8 +# Weak-copyleft / corporate-unfriendly licenses are denied by omission from +# `allow`. Per-crate exceptions (e.g. ring's BoringSSL bits) go in `exceptions`. +exceptions = [] + +[bans] +multiple-versions = "allow" +wildcards = "allow" +# Populate when concrete bans are decided (e.g. ban openssl<0.10, tokio<1). +deny = [] +skip = [] +skip-tree = [] + +[sources] +unknown-registry = "deny" +unknown-git = "deny" +allow-registry = ["https://github.com/rust-lang/crates.io-index"] +allow-git = [] From 2a97c6f12c8ab023aba2c4d7211060182da3ccb5 Mon Sep 17 00:00:00 2001 From: Jared Lunde Date: Tue, 19 May 2026 11:37:00 -0700 Subject: [PATCH 2/3] ci: dprint fmt on new workflow + deny.toml files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Same lint job that caught this is the one we want to stay loud — fix the formatting now rather than .dprintignore it. Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/ci.yml | 5 ----- .github/workflows/security.yml | 2 -- deny.toml | 24 ++++++++++++------------ 3 files changed, 12 insertions(+), 19 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 514779b..20d1872 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,7 +9,6 @@ concurrency: cancel-in-progress: ${{ github.event_name == 'pull_request' }} env: CARGO_TERM_COLOR: always - jobs: lint: runs-on: ubuntu-latest @@ -20,7 +19,6 @@ jobs: cache-key: lint - run: mise run check:fmt - run: mise run check:rs - generate-check: name: generated files up-to-date runs-on: ubuntu-latest @@ -33,7 +31,6 @@ jobs: - run: mise run generate:types - name: check no diff run: git diff --exit-code -- openapi/v1.json sdk/ts/src/types.ts - rust-test: runs-on: ubuntu-latest steps: @@ -43,7 +40,6 @@ jobs: cache-key: rust-test - run: mise run test:unit:rs - run: mise run test:integration:rs - handoff-test: runs-on: ubuntu-latest steps: @@ -52,7 +48,6 @@ jobs: with: cache-key: handoff-test - run: mise run test:handoff:rs - ts-test: runs-on: ubuntu-latest steps: diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index b3e7f40..8ee03f0 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -4,11 +4,9 @@ on: # Mondays 14:00 UTC. Weekly cadence — real advisory churn, not per-push theater. - cron: "0 14 * * 1" workflow_dispatch: - permissions: contents: read issues: write - jobs: cargo-deny: runs-on: ubuntu-latest diff --git a/deny.toml b/deny.toml index c151b59..156bd81 100644 --- a/deny.toml +++ b/deny.toml @@ -14,18 +14,18 @@ ignore = [] version = 2 # Permissive licenses allowed across the workspace + transitive deps. allow = [ - "MIT", - "Apache-2.0", - "Apache-2.0 WITH LLVM-exception", - "BSD-2-Clause", - "BSD-3-Clause", - "ISC", - "Unicode-3.0", - "Unicode-DFS-2016", - "Zlib", - "MPL-2.0", - "CC0-1.0", - "0BSD", + "MIT", + "Apache-2.0", + "Apache-2.0 WITH LLVM-exception", + "BSD-2-Clause", + "BSD-3-Clause", + "ISC", + "Unicode-3.0", + "Unicode-DFS-2016", + "Zlib", + "MPL-2.0", + "CC0-1.0", + "0BSD", ] confidence-threshold = 0.8 # Weak-copyleft / corporate-unfriendly licenses are denied by omission from From 14be140d6b1fe7657f8bcd4c63454c3479a52d61 Mon Sep 17 00:00:00 2001 From: Jared Lunde Date: Tue, 19 May 2026 11:43:48 -0700 Subject: [PATCH 3/3] deny: allow BSL-1.0 (xxhash-rust via fjall), silence unmatched allow warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cargo-deny on the workspace surfaced one real license signal: BSL-1.0 (Boost Software License 1.0) used by xxhash-rust through the fjall LSM tree dep. BSL-1.0 is permissive, OSI-approved, FSF-libre — same shape as the other allow entries. unused-allowed-license = "allow" silences warnings for permissive licenses in the allow list that aren't currently in the tree; keeps them ready so new transitive deps don't trip the check. Advisories (rustls-webpki 0.101.7 RUSTSEC-2026-0099/0104) are NOT suppressed — that's intended. They'll surface as the first auto-opened issue when security.yml's weekly cron fires after merge. Fix in a follow-up PR via `cargo update -p rustls-webpki`. Co-Authored-By: Claude Opus 4.7 (1M context) --- deny.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/deny.toml b/deny.toml index 156bd81..bd99b12 100644 --- a/deny.toml +++ b/deny.toml @@ -26,8 +26,10 @@ allow = [ "MPL-2.0", "CC0-1.0", "0BSD", + "BSL-1.0", ] confidence-threshold = 0.8 +unused-allowed-license = "allow" # Weak-copyleft / corporate-unfriendly licenses are denied by omission from # `allow`. Per-crate exceptions (e.g. ring's BoringSSL bits) go in `exceptions`. exceptions = []