Skip to content

Harden the checker against supply-chain attacks#20

Merged
vdavid merged 1 commit into
mainfrom
supply-chain-hardening
May 18, 2026
Merged

Harden the checker against supply-chain attacks#20
vdavid merged 1 commit into
mainfrom
supply-chain-hardening

Conversation

@vdavid
Copy link
Copy Markdown
Owner

@vdavid vdavid commented May 18, 2026

Closes the high-severity gaps surfaced in our pre-launch supply-chain review (Shai-Hulud waves 1-4). Cmdr is already well-positioned on the npm side (pnpm 11 deny-default, SHA-pinned actions, no pull_request_target); this PR closes the Rust- and Go-side gaps and adds regression guards so the hardening can't silently regress on a future PR.

  • Pass --locked to every operational cargo command in checks: cargo clippy, cargo nextest run (both unit and integration tests), cargo +nightly udeps. Without it cargo silently re-resolves Cargo.lock on metadata drift, opening a window for a fresh malicious version to land mid-build across 1028 transitive crates.
  • Pin apps/desktop/rust-toolchain.toml channel from floating stable to 1.95.0. A floating channel means a compromised rustc release would land transparently.
  • Pin every tool install. cargo install now passes --version + --locked for cargo-audit, cargo-deny, cargo-machete, cargo-udeps, cargo-nextest. Every EnsureGoTool call replaced @latest with a specific tag/pseudo-version: staticcheck@v0.7.0, nilaway@v0.0.0-20260515015210-fd187751154f, misspell@v0.3.4, gocyclo@v0.6.0, ineffassign@v0.2.0, deadcode@v0.45.0. Closes the wave-1-2-class "the supply-chain tool itself gets trojaned" gap.
  • New workflows-hardening check at scripts/check/checks/desktop-workflows-hardening.go. Scans .github/workflows/*.{yml,yaml} and fails on three classes the wave-4 (TanStack, May 2026) attack chained: tag/branch-pinned third-party actions (must be SHA-pinned, with ./... local actions exempt), pull_request_target triggers, and workflow-scoped id-token: write (must be job-scoped). Cmdr passes today; the check is a regression guard. 192 lines of check + 199 lines of tests.
  • New govulncheck check at scripts/check/checks/scripts-go-govulncheck.go. Runs govulncheck@v1.3.0 against every go.mod. Mirrors cargo-audit's role on the Rust side: static-analysis-based, so only flags vulns reachable from your code (low false positive rate).
  • Bump .mise.toml Go from 1.25.7 to 1.25.10. The new govulncheck check found 7 reachable stdlib vulns in cmdr's tooling on its first run (CVE fixes in net, crypto/tls, crypto/x509, net/url, archive/tar, os). 1.25.10 is the latest patch in the 1.25 line.
  • Update scripts/check/CLAUDE.md with four new Decision entries (the --locked rule, the tool-version-pin rule, the workflow-hardening check, the govulncheck check) and the apps/checks table now lists govulncheck and a new Security row.

Test plan

  • ./scripts/check.sh --check workflows-hardening passes against cmdr's 6 real workflows (all already SHA-pinned, no pull_request_target, no workflow-scoped id-token: write).
  • ./scripts/check.sh --check govulncheck passes against all 7 Go modules under Go 1.25.10. Pre-bump it correctly failed on 7 reachable stdlib vulns, demonstrating the check works.
  • Unit tests for scanWorkflowFile cover all three violation classes plus the negative cases (SHA-pinned accepted, local action exempt, pull_request not pull_request_target, job-scoped id-token: write accepted, comments ignored). All pass.
  • ./scripts/check.sh --check gofmt --check go-vet --check staticcheck --check go-tests all pass.
  • Rebased cleanly on latest main; affected checks re-run green post-rebase.

- Pass `--locked` to every operational cargo command in checks (`cargo clippy`, `cargo nextest run` in both unit and integration tests, `cargo +nightly udeps`). Without it cargo silently re-resolves `Cargo.lock` on metadata drift, opening a window for a fresh malicious version to land mid-build across 1028 transitive crates.
- Pin `apps/desktop/rust-toolchain.toml` channel from floating `stable` to `1.95.0`.
- Pin every tool install. `cargo install` now passes `--version` + `--locked` for `cargo-audit`, `cargo-deny`, `cargo-machete`, `cargo-udeps`, `cargo-nextest`. Every `EnsureGoTool` call replaced `@latest` with a specific version: `staticcheck@v0.7.0`, `nilaway@v0.0.0-20260515015210-fd187751154f`, `misspell@v0.3.4`, `gocyclo@v0.6.0`, `ineffassign@v0.2.0`, `deadcode@v0.45.0`. Closes the wave-1-2-class "the supply-chain tool itself gets trojaned" gap.
- New `workflows-hardening` check at `scripts/check/checks/desktop-workflows-hardening.go`. Scans `.github/workflows/*.{yml,yaml}` and fails on three classes the wave-4 (TanStack, May 2026) attack chained: tag/branch-pinned third-party actions (must be SHA-pinned, with `./...` local actions exempt), `pull_request_target` triggers, and workflow-scoped `id-token: write` (must be job-scoped). Cmdr passes today; the check is a regression guard. ~190 lines + ~200 lines of tests.
- New `govulncheck` check at `scripts/check/checks/scripts-go-govulncheck.go`. Runs `govulncheck@v1.3.0` against every `go.mod`. Mirrors `cargo-audit`'s role on the Rust side: static-analysis-based, low false-positive rate.
- Bump `.mise.toml` go from `1.25.7` to `1.25.10`. The `govulncheck` check found 7 reachable stdlib vulns in cmdr's tooling on its first run (CVE fixes in `net`, `crypto/tls`, `crypto/x509`, `net/url`, `archive/tar`, `os`). 1.25.10 is the latest patch in the 1.25 line.
- Update `scripts/check/CLAUDE.md` with four new Decision entries (the `--locked` rule, the tool-version-pin rule, the workflow-hardening check, the govulncheck check) and the apps/checks table now lists `govulncheck` and the new Security row.

The Rust hardening is mostly defense in depth; cmdr already has `cargo-audit`, `cargo-deny` (licenses/bans/sources), SHA-pinned actions, and `pnpm install --frozen-lockfile` in every CI workflow. The two new checks close the gaps surfaced in our pre-launch supply-chain review: no Go-side vuln scanner, no regression guard on the workflow hardening that's already in place.
@vdavid vdavid merged commit 7d771ca into main May 18, 2026
8 of 10 checks passed
@vdavid vdavid deleted the supply-chain-hardening branch May 18, 2026 19:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant