ci: pin GitHub Actions to commit SHAs (S-1.01) - #295
Merged
Conversation
Resolves the supply-chain risk where mutable version tags (@v6, @stable, etc.) could be force-pushed by an action publisher to point at malicious content. release.yml is the highest-risk workflow because softprops/action-gh-release receives OAUTH_CLIENT_ID + OAUTH_CLIENT_SECRET from repo secrets — a compromised action would leak embedded OAuth credentials. - 15 uses: sites pinned in .github/workflows/ci.yml - 5 uses: sites pinned in .github/workflows/release.yml - Each pin: @<40-hex-sha> # <original-tag> for human readability - Dependabot github-actions ecosystem remains active for weekly SHA updates - AC-001: all 20 uses: lines now carry a 40-hex SHA (briefing said 19; actual count was 20 — dtolnay/rust-toolchain@stable in coverage job added) - AC-002: no floating semver, @stable, @main, or bare tool-name refs remain - AC-004: .github/dependabot.yml github-actions ecosystem unchanged - YAML syntax: both files validated clean with yq - No source code changes; 600 lib tests pass; clippy/fmt clean SHA pin table (10 distinct action+tag combinations): actions/checkout@v6 de0fac2e4500dabe0009e67214ff5f5447ce83dd Swatinem/rust-cache@v2 e18b497796c12c097a38f9edb9d0641fb99eee32 dtolnay/rust-toolchain@stable 29eef336d9b2848a0b548edc03f92a220660cdb8 dtolnay/rust-toolchain@1.85.0 c93f4f9c67595668add93d3d6895795ce52d8c2d EmbarkStudios/cargo-deny-action@v2 91bf2b620e09e18d6eb78b92e7861937469acedb taiki-e/install-action@cargo-llvm-cov e5de28abeb52d916c5e5875d54b21a9e738b61ec codecov/codecov-action@v6 57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 actions/upload-artifact@v7 043fb46d1a93c77aae656e7c1c64a875d1fc6a0a actions/download-artifact@v8 3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c softprops/action-gh-release@v2 3bb12739c298aeb8a4eeaf626c5b8d85266b0e65
Owner
Author
Code reviewNo issues found. Checked for bugs and CLAUDE.md compliance. Spot-checked 3 SHAs via GitHub API — all verified correct:
Additional checks:
🤖 Generated with Claude Code - If this code review was useful, please react with 👍. Otherwise, react with 👎. |
Zious11
added a commit
that referenced
this pull request
May 7, 2026
- S-1.01 (pin GitHub Actions SHAs): MERGED at adae3c5 via PR #295 - 20 uses: lines pinned (15 ci.yml + 5 release.yml); 10 action+tag → SHA - 7/7 CI green; review APPROVE 1 cycle; 0 deferred - Notable: dispatcher allowed clean merge (no admin bypass needed) - Lesson 4 captured: dispatcher policy variable per-PR; try non-admin first - sprint-state.yaml: S-1.01 → completed; S-1.02 → active - Phase 3 Wave 1 progress: 1/8
This was referenced May 7, 2026
Zious11
added a commit
that referenced
this pull request
May 7, 2026
Story: S-1.03 (Wave 1 — third story; first non-facade) NFR: NFR-O-A Changes: - Add tracing 0.1.41 + tracing-subscriber 0.3.19 (env-filter + fmt features) - src/main.rs: init_tracing() with EnvFilter (WARN/DEBUG/TRACE by --verbose/--verbose-bodies); RUST_LOG override - src/api/client.rs: rate-limit events migrated to tracing::debug!; method+URL retains [verbose] prefix per SD-003 contract (variable-extraction trick) - src/api/auth.rs: tracing::info!/debug! at OAuth login + refresh entry points; secrets never appear in tracing fields - src/observability.rs: docstring updated post-S-1.03 (SHOULD-FIX from review) - 10 new observability tests; 6 SD-003 verbose_bodies tests preserved; 600 lib baseline unchanged - cargo deny check exits 0 (no new duplicate-version conflicts from tracing transitives) Code review: APPROVE (1 SHOULD-FIX applied as commit 06c2252; 1 DEFER for body logging migration to tracing::trace! - tracked for Wave 2 cleanup). CI: 7/7 green. Related: follows PR #295 (S-1.01), #296 (S-1.02); preserves SD-003 contract from PR #294 (S-0.06).
10 tasks
Zious11
added a commit
that referenced
this pull request
May 7, 2026
) Story: S-1.04 (Wave 1 — fourth story; tdd_mode: facade) Risk: R-L12 Changes: - 6 timeout-minutes added in .github/workflows/ci.yml: fmt 5m, clippy 15m, test 30m, msrv 15m, deny 10m, coverage 30m - 2 timeout-minutes added in .github/workflows/release.yml: build 60m (matrix; LTO + cross-compile), release 30m - All values 12-17x historical observed runtime headroom - Resolves R-L12: hung jobs no longer consume full 6-hour GitHub default Code review: APPROVE (0 blocking, 0 SHOULD-FIX, 3 deferred non-blocking observations). CI: 7/7 green. Related: follows S-1.01 (#295), S-1.02 (#296), S-1.03 (#297).
11 tasks
Zious11
added a commit
that referenced
this pull request
May 8, 2026
- Final Wave 1 story (S-1.08): MERGED at ab19783 via PR #302 - Wave 1 sequence: PRs #295-#302 (S-1.01..S-1.08) - 0 production regressions; ~50 new tests - 5 deferred items in Drift Items; 1 PENDING_MANUAL (S-1.05-AC-001) - STATE.md compacted; Wave 1 narrative archived to wave-1-summary.md - Wave 1 retrospective in lessons.md (Lesson 5 candidate) - sprint-state: S-1.08 → completed; S-2.01 → active; Wave 2 ACTIVE - Phase 3 progress: 16/31 (~52%)
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
uses:line in CI/release workflows to a full 40-hex-character commit SHA with the original tag preserved as a trailing comment (e.g.,actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2)uses:sites pinned: 15 inci.yml, 5 inrelease.yml; 10 distinct action+tag combinations resolvedsoftprops/action-gh-release@v2inrelease.yml, which hascontents: writeand receivesJR_BUILD_OAUTH_CLIENT_ID/JR_BUILD_OAUTH_CLIENT_SECRETfrom repo secrets) could be silently redirected to malicious content by a compromised upstreamStory
S-1.01 — Wave 1, first HIGH-priority NFR/infra story
Traces to:
No story dependencies. This is independent infrastructure work.
Architecture Changes
graph TD A[".github/workflows/ci.yml<br/>15 uses: lines"] -->|tag → SHA + comment| B["SHA-pinned<br/>ci.yml"] C[".github/workflows/release.yml<br/>5 uses: lines"] -->|tag → SHA + comment| D["SHA-pinned<br/>release.yml"] E["Dependabot<br/>github-actions ecosystem<br/>(weekly)"] -->|automated SHA updates| B E -->|automated SHA updates| DBlast radius: CI configuration only. No source code, no binaries, no API surface changed. Purely mechanical text substitution — identical action code runs via immutable SHA resolution instead of mutable tag resolution.
Performance impact: None. SHA resolution is handled by the GitHub Actions runner identically to tag resolution.
Story Dependencies
graph LR S101["S-1.01<br/>Pin Actions SHAs<br/>(this PR)"] --> DEV["develop"] W0["Wave 0 (S-0.01…S-0.06)<br/>All merged"] --> DEVNo
depends_onentries. This story is independent of all Wave 0 stories.Spec Traceability
flowchart LR NFR["NFR-S-E<br/>Supply-chain security HIGH"] --> AC001["AC-001<br/>All uses: SHA-pinned"] NFR --> AC002["AC-002<br/>No floating refs"] NFR --> AC003["AC-003<br/>SHAs match claimed tags"] NFR --> AC004["AC-004<br/>Dependabot active"] AC001 --> GREP1["grep -E 'uses:.*@[a-f0-9]{40}'<br/>20/20 PASS"] AC002 --> GREP2["grep -E 'uses:.*@v[0-9]'<br/>0 matches PASS"] AC003 --> SHA_VER["SHA→tag verification<br/>10 combinations PASS"] AC004 --> DEP["dependabot.yml<br/>github-actions weekly PASS"] GREP1 --> COMMIT["2282874<br/>ci(S-1.01): pin all GitHub Actions<br/>to full commit SHAs"] GREP2 --> COMMIT SHA_VER --> COMMIT DEP --> COMMITAcceptance Criteria Status
uses:line ends in a 40-hex-char SHA; tag preserved as commentuses:line retains@v<N>,@stable,@<semver>, or@<tool-name>dependabot.ymlpackage-ecosystem: github-actionsweekly still activePinned Actions Reference
ci.yml (15 sites)
actions/checkoutv6de0fac2e4500dabe0009e67214ff5f5447ce83ddSwatinem/rust-cachev2e18b497796c12c097a38f9edb9d0641fb99eee32dtolnay/rust-toolchain1.85.0c93f4f9c67595668add93d3d6895795ce52d8c2ddtolnay/rust-toolchainstable29eef336d9b2848a0b548edc03f92a220660cdb8taiki-e/install-actioncargo-llvm-cove5de28abeb52d916c5e5875d54b21a9e738b61ecEmbarkStudios/cargo-deny-actionv291bf2b620e09e18d6eb78b92e7861937469acedbcodecov/codecov-actionv657e3a136b779b570ffcdbf80b3bdc90e7fab3de2release.yml (5 sites)
actions/checkoutv6de0fac2e4500dabe0009e67214ff5f5447ce83dddtolnay/rust-toolchainstable29eef336d9b2848a0b548edc03f92a220660cdb8actions/upload-artifactv7043fb46d1a93c77aae656e7c1c64a875d1fc6a0aactions/download-artifactv83e5f45b2cfb9172054b4087a40e8e0b5a5461e7csoftprops/action-gh-releasev23bb12739c298aeb8a4eeaf626c5b8d85266b0e65Test Evidence
tdd_mode: facade — no Rust tests; verification is grep + YAML parse.
grep -E 'uses:.*@[a-f0-9]{40}' .github/workflows/*.yml | wc -lgrep -E 'uses:.*@v[0-9]' .github/workflows/*.ymlgrep -E 'uses:.*@stable' .github/workflows/*.ymlgrep -E 'uses:.*@main' .github/workflows/*.ymlyq e '.' ci.yml > /dev/nullyq e '.' release.yml > /dev/nullcargo buildcargo test --libcargo clippy --all --all-features --tests -- -D warningscargo fmt --all -- --checkMutation kill rate: N/A — facade story.
Coverage delta: 0% — no Rust source changes.
Demo Evidence
N/A — facade story. The diff is the evidence. No UI or runtime behavior changed.
Verification commands for reviewer:
Validation Paradox Note
This PR's CI run will use the pinned SHAs introduced by this very PR. That is intentional and desirable: if a SHA is wrong (typo or stale), the CI job will fail with an action resolution error, surfacing the problem before merge. CI passing on this PR IS the validation that the SHAs resolve correctly. If CI fails on an action resolution error, that is a real SHA issue to investigate.
Holdout Evaluation
N/A — evaluated at wave gate. No Phase 4 holdout exists for CI infrastructure state.
Adversarial Review
N/A — evaluated at Phase 5. No adversarial review required for pure CI configuration changes.
Security Review
Risk addressed: Supply-chain attack via mutable tag references in GitHub Actions workflows.
Highest-risk mitigation:
softprops/action-gh-release@v2→ pinned SHA3bb12739c298aeb8a4eeaf626c5b8d85266b0e65. This action runs withpermissions: contents: writeand receivesJR_BUILD_OAUTH_CLIENT_IDandJR_BUILD_OAUTH_CLIENT_SECRETfrom repository secrets. A compromised tag ref in this position had direct read access to the embedded OAuth app credentials.Residual risk: SHA staleness — SHAs pinned at implementation time will drift from latest. Dependabot (
package-ecosystem: github-actions, weekly) mitigates by opening automated SHA update PRs.OWASP relevance: A06:2021 — Vulnerable and Outdated Components (CI/CD pipeline component integrity).
No CRITICAL or HIGH security findings. This PR closes a HIGH-severity gap rather than introducing one.
Risk Assessment
2282874; CI immediately reverts to tag-based resolutionAI Pipeline Metadata
2282874Pre-Merge Checklist
.github/workflows/ci.ymland.github/workflows/release.ymluses:lines pinned to 40-hex-char SHA@v<N>,@stable,@main)cargo build/cargo test --lib/cargo clippy/cargo fmtall cleangithub-actionsecosystem active