fix: stop rereading files in content digest #153
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # ────────────────────────────────────────────────────────────────────── | |
| # CI — runs on every PR, push to main, and weekly on a schedule. | |
| # | |
| # PURPOSE: | |
| # Gate merges behind automated checks: lint, test, and security | |
| # scanning. This prevents regressions and catches vulnerabilities | |
| # before code reaches the release workflow. | |
| # | |
| # JOBS (run in parallel where possible): | |
| # changes — detects which files changed (dorny/paths-filter) | |
| # check — fmt → clippy → test (skipped for docs-only changes) | |
| # supply-chain — cargo-deny + cargo-audit (dep changes OR schedule) | |
| # secrets — gitleaks (always runs — any file can contain secrets) | |
| # unsafe-audit — cargo-geiger (dep changes OR schedule) | |
| # | |
| # OPTIMIZATIONS: | |
| # • Path filtering: dorny/paths-filter skips expensive Rust jobs when | |
| # only docs/scripts/config changed (saves ~35s+ per docs-only PR). | |
| # • Concurrency: cancel-in-progress prevents wasted runs when you | |
| # push again quickly or when push+PR events both fire. | |
| # • Fail-fast: steps in `check` ordered cheapest-first (fmt → clippy | |
| # → test) so broken PRs fail in seconds, not minutes. | |
| # | |
| # SUPPLY CHAIN SECURITY: | |
| # • All Actions pinned to full commit SHAs (see release.yml header). | |
| # • `cargo deny` checks licenses and advisories on every PR. | |
| # • `cargo audit` catches known CVEs in the dependency tree. | |
| # • `gitleaks` scans for accidentally committed secrets. | |
| # • `cargo-geiger` audits unsafe code surface area. | |
| # • Minimal permissions — only `contents: read` for checkout. | |
| # • Audit tool versions are pinned and verified via SHA-256 checksums | |
| # before execution — no silent upgrades from upstream `latest`. | |
| # • Scheduled weekly run ensures new advisories are caught even when | |
| # no dependency files changed. | |
| # | |
| # RUNNERS: | |
| # • Blacksmith runners for Linux (2× faster, colocated cache). | |
| # • Swatinem/rust-cache automatically uses Blacksmith's cache backend | |
| # when running on Blacksmith runners — no special config needed. | |
| # ────────────────────────────────────────────────────────────────────── | |
| name: CI | |
| on: | |
| pull_request: | |
| push: | |
| branches: [main] | |
| schedule: | |
| # Weekly on Monday at 06:00 UTC — catches new advisories even | |
| # when no dependency files have changed since the last PR. | |
| - cron: '0 6 * * 1' | |
| # Cancel in-progress runs when a new push arrives on the same branch. | |
| # This prevents wasted compute when you push rapid fixes, and deduplicates | |
| # the push + pull_request events that GitHub fires simultaneously. | |
| # On main/schedule, use run_id so runs don't cancel each other. | |
| concurrency: | |
| group: ci-${{ (github.event_name == 'push' || github.event_name == 'schedule') && github.run_id || github.head_ref }} | |
| cancel-in-progress: true | |
| # Least-privilege: CI only needs to read the repo | |
| permissions: | |
| contents: read | |
| env: | |
| CARGO_TERM_COLOR: always | |
| jobs: | |
| # ── Path Detection ─────────────────────────────────────────────── | |
| # Runs in <5s on a minimal runner. Downstream jobs use its outputs | |
| # to skip expensive work when only docs/scripts/config changed. | |
| changes: | |
| name: Detect changes | |
| runs-on: blacksmith-2vcpu-ubuntu-2204 | |
| outputs: | |
| rust: ${{ steps.filter.outputs.rust }} | |
| deps: ${{ steps.filter.outputs.deps }} | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1 | |
| id: filter | |
| with: | |
| filters: | | |
| rust: | |
| - 'crates/**' | |
| - 'Cargo.toml' | |
| - 'Cargo.lock' | |
| - 'rust-toolchain.toml' | |
| - 'deny.toml' | |
| - '.github/workflows/**' | |
| deps: | |
| - 'Cargo.toml' | |
| - 'Cargo.lock' | |
| - 'crates/**/Cargo.toml' | |
| - 'deny.toml' | |
| check: | |
| name: Lint & test | |
| needs: changes | |
| if: needs.changes.outputs.rust == 'true' | |
| runs-on: blacksmith-4vcpu-ubuntu-2204 | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable | |
| with: | |
| components: clippy, rustfmt | |
| # rust-toolchain.toml overrides action inputs, so ensure | |
| # components are installed. This is a no-op if they're | |
| # already listed in rust-toolchain.toml (belt + suspenders). | |
| - name: Ensure toolchain components | |
| run: rustup component add clippy rustfmt | |
| # Blacksmith intercepts cache calls on its runners — this | |
| # uses the colocated cache automatically, no extra config. | |
| - name: Cache Cargo | |
| uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 | |
| # ── Fail-fast: cheapest checks first ──────────────────── | |
| # ~1s — pure text check, no compilation. Catches formatting | |
| # issues before waiting for a full compile. | |
| - name: Formatting | |
| run: cargo fmt --check | |
| # ~30s — compiles all targets AND lints in a single pass. | |
| # No separate `cargo build` step needed — clippy does both. | |
| # -D warnings ensures zero warnings merge. | |
| - name: Clippy | |
| run: cargo clippy --locked --all-targets -- -D warnings | |
| # ~3s — reuses build artifacts from clippy above, so this | |
| # is essentially just running the test harness. | |
| - name: Test | |
| run: cargo test --locked | |
| # Runs in parallel with check — no dependency between them. | |
| # Uses pre-built binaries (not `cargo install`) to avoid the 60s+ | |
| # compile-from-source overhead of building cargo-audit. | |
| supply-chain: | |
| name: Supply chain audit | |
| needs: changes | |
| if: needs.changes.outputs.deps == 'true' || github.event_name == 'schedule' | |
| runs-on: blacksmith-2vcpu-ubuntu-2204 | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| # Download pre-built binaries (~2s each) instead of | |
| # `cargo install` which compiles from source (~60s+). | |
| # Versions are pinned; SHA-256 checksums are verified before | |
| # extraction to detect tampering or download corruption. | |
| - name: Install cargo-deny | |
| run: | | |
| DENY_VERSION="0.19.1" | |
| DENY_SHA256="baa0d618ce06bd1fb352115de47e31acba439c3e639b990dc43429c948364d70" | |
| curl -sSL "https://github.com/EmbarkStudios/cargo-deny/releases/download/${DENY_VERSION}/cargo-deny-${DENY_VERSION}-x86_64-unknown-linux-musl.tar.gz" \ | |
| -o cargo-deny.tar.gz | |
| echo "${DENY_SHA256} cargo-deny.tar.gz" | sha256sum --check --strict | |
| tar xzf cargo-deny.tar.gz --strip-components=1 -C /usr/local/bin | |
| rm cargo-deny.tar.gz | |
| cargo-deny --version | |
| # rustsec/rustsec is a monorepo; cargo-audit releases don't | |
| # include a checksums file, so the SHA-256 is embedded here | |
| # (computed from the official release asset at pin time). | |
| - name: Install cargo-audit | |
| run: | | |
| AUDIT_VERSION="0.22.1" | |
| AUDIT_SHA256="c32506f338bdcdaef5a17fb9f33abb6ecf9561324cfd34237fd335f9283a1eab" | |
| curl -sSL "https://github.com/rustsec/rustsec/releases/download/cargo-audit%2Fv${AUDIT_VERSION}/cargo-audit-x86_64-unknown-linux-musl-v${AUDIT_VERSION}.tgz" \ | |
| -o cargo-audit.tgz | |
| echo "${AUDIT_SHA256} cargo-audit.tgz" | sha256sum --check --strict | |
| tar xzf cargo-audit.tgz --strip-components=1 -C /usr/local/bin | |
| rm cargo-audit.tgz | |
| cargo-audit --version | |
| # cargo-deny checks: advisories, licenses, bans, sources | |
| - name: cargo deny check | |
| run: cargo deny check | |
| # cargo-audit is a second layer — checks the RustSec advisory DB | |
| - name: cargo audit | |
| run: cargo audit | |
| # ── Secrets Scanning ───────────────────────────────────────────── | |
| # Gitleaks detects hardcoded secrets (API keys, tokens, passwords) | |
| # in the repo history and staged changes. Runs on a minimal runner | |
| # since it's I/O-bound, not CPU-bound. Blocks the build on any | |
| # finding — secrets in the repo are always a hard stop. | |
| secrets: | |
| name: Secrets scan | |
| runs-on: blacksmith-2vcpu-ubuntu-2204 | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| fetch-depth: 0 # full history for scanning all commits | |
| - name: Install gitleaks | |
| run: | | |
| GL_VERSION="8.30.1" | |
| GL_SHA256="551f6fc83ea457d62a0d98237cbad105af8d557003051f41f3e7ca7b3f2470eb" | |
| curl -sSL "https://github.com/gitleaks/gitleaks/releases/download/v${GL_VERSION}/gitleaks_${GL_VERSION}_linux_x64.tar.gz" \ | |
| -o gitleaks.tar.gz | |
| echo "${GL_SHA256} gitleaks.tar.gz" | sha256sum --check --strict | |
| tar xzf gitleaks.tar.gz -C /usr/local/bin gitleaks | |
| rm gitleaks.tar.gz | |
| gitleaks version | |
| # Scan the full repo history for secrets. On PRs, you could | |
| # scope to just the diff with --log-opts="origin/main..HEAD" | |
| # but scanning everything catches pre-existing issues too. | |
| - name: Scan for secrets | |
| run: gitleaks detect --source . --config .gitleaks.toml --verbose | |
| # ── Unsafe Code Audit ──────────────────────────────────────────── | |
| # cargo-geiger counts `unsafe` usage across the entire dependency | |
| # tree. This is informational (non-blocking) — many safe crates | |
| # use unsafe internally (e.g. ring for crypto, libc for FFI). | |
| # The value is visibility: track unsafe surface area over time | |
| # and catch unexpected new unsafe dependencies in PRs. | |
| unsafe-audit: | |
| name: Unsafe code audit | |
| needs: changes | |
| if: needs.changes.outputs.deps == 'true' || github.event_name == 'schedule' | |
| runs-on: blacksmith-4vcpu-ubuntu-2204 | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable | |
| - name: Ensure toolchain components | |
| run: rustup component add clippy rustfmt | |
| # Blacksmith caches the compiled cargo-geiger binary after | |
| # the first run — subsequent runs skip the 60s+ compile. | |
| - name: Cache Cargo | |
| uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 | |
| - name: Install cargo-geiger | |
| run: cargo install cargo-geiger --locked | |
| # Non-blocking (|| true) — geiger can exit non-zero if it | |
| # encounters crates it can't analyze. The output itself is | |
| # the valuable part: review it in PR checks to spot new | |
| # unsafe dependencies entering the tree. | |
| - name: Audit unsafe code usage | |
| run: cargo geiger --all-targets --output-format ascii 2>&1 || true |