Skip to content

Rotate the pinned supply-chain digests dependabot cannot reach - #44

Merged
Chris-ObtuseAI merged 5 commits into
mainfrom
chore/dependency-pin-rotation
Aug 1, 2026
Merged

Rotate the pinned supply-chain digests dependabot cannot reach#44
Chris-ObtuseAI merged 5 commits into
mainfrom
chore/dependency-pin-rotation

Conversation

@Chris-ObtuseAI

Copy link
Copy Markdown
Contributor

Four dependabot PRs could never go green on their own. Each bumps a dependency that is also guarded by a pin dependabot has no way to update, so its own change always fails the gate protecting it.

Why they were stuck

gate what it pins
tests/test_runtime_dependency_lock.py exact runtime version, and that requirements-runtime.lock matches the uv resolution
tests/test_validation_dependency_lock.py every validation tool version across pyproject.toml, uv.lock and requirements-validation.lock
tests/test_release_build_trust.py the exact commit digest of actions/attest
tests/test_doofus_external_trial_workflow.py the exact commit digest of actions/attest-build-provenance

These are good controls — a workflow-only bump should fail them. They just need the companion half of the change, which is what this PR is.

Digests were verified upstream, not taken on trust

actions/attest                  v4.2.0 = f7c74d28b9d84cb8768d0b8ca14a4bac6ef463e6
actions/attest                  v4.2.1 = 508db95dd578ae2727ebd6217d5ba78e4fbda05d
actions/attest-build-provenance v4.1.1 = 0f67c3f4856b2e3261c31976d6725780e5e4c373

Each was resolved from the upstream repo's own tag ref before being pinned. The old digest confirms the derivation: f7c74d28… is exactly what the test already pinned for v4.2.0.

Changes

Both lock files were regenerated with the pinned uv 0.11.15 rather than hand-edited, so every hash is machine-derived.

Deliberately excluded

ruff 0.16.0 (#16) is not here. It changes default rule behaviour and reports 893 errors (497 auto-fixable) against this tree. That is a lint migration, not a dependency bump, and mixing it in would bury this diff. #16 stays open.

Verification

55 passed, 2 skipped, 43 subtests passed
ruff check src/dumbmoney tests scripts  -> All checks passed
scripts/validate_workspace.py           -> "status": "PASS"

Full suite runs in CI.

🤖 Generated with Claude Code

Chris-ObtuseAI and others added 4 commits July 31, 2026 22:25
Dependabot proposes a dependency bump but cannot update the pins that
guard it, so these PRs could never go green on their own:

  - tests/test_runtime_dependency_lock.py pins the exact runtime version
    and asserts requirements-runtime.lock matches the uv resolution
  - tests/test_validation_dependency_lock.py pins every validation tool
    version across pyproject, uv.lock and requirements-validation.lock
  - tests/test_release_build_trust.py and
    tests/test_doofus_external_trial_workflow.py pin the exact commit
    digest of each attestation action, so a workflow-only bump fails

Every digest below was verified against the upstream tag before use,
not taken from dependabot's word:

  actions/attest v4.2.0 = f7c74d28b9d84cb8768d0b8ca14a4bac6ef463e6
  actions/attest v4.2.1 = 508db95dd578ae2727ebd6217d5ba78e4fbda05d
  actions/attest-build-provenance v4.1.1
                        = 0f67c3f4856b2e3261c31976d6725780e5e4c373

Changes:
  - cryptography 48.0.1 -> 49.0.0, constraint <49 -> <50 (closes #13)
  - pip-audit 2.9.0 -> 2.10.1, which drops toml for tomli/tomli-w
    (closes #17)
  - actions/attest v4.2.0 -> v4.2.1 in ui.yml and
    nimrod-external-witness.yml (closes #10)
  - actions/attest-build-provenance v3 -> v4.1.1 in
    doofus-external-trial.yml (closes #12)

Both lock files were regenerated with the pinned uv 0.11.15 rather than
hand-edited, so every hash is machine-derived.

ruff 0.16.0 is deliberately NOT included. It changes default rule
behaviour and reports 893 errors (497 auto-fixable) against this tree.
That is a lint migration, not a dependency bump, and it belongs in its
own change. #16 stays open.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
validate_release_python.py regenerates the file with
--only-group validation --no-annotate and byte-compares. The first
export omitted --no-annotate, so the committed file carried 37 lines of
"# via" provenance comments the gate never produces, and
validation_lock_reproducible failed.

Both lock files are now written with exactly the commands the gate uses:
  runtime:    uv export --locked --no-default-groups --format requirements-txt --no-header --no-emit-project
  validation: uv export --locked --only-group validation --no-annotate --format requirements-txt --no-header --no-emit-project

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
EXPECTED_TOOL_VERSIONS in scripts/validate_release_python.py asserts the
INSTALLED tool versions match the contract, so pip-audit is pinned in
five places, not four: pyproject.toml, uv.lock,
requirements-validation.lock, tests/test_validation_dependency_lock.py,
and this validator.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
`concurrency.group` was the fixed string `pages`, so every pull request
and every push to main contended for a single slot. With
`cancel-in-progress: false` GitHub keeps only the newest queued run and
supersedes the rest, and because `Build synthetic-only Organism` is a
REQUIRED status check on main, any PR whose run was superseded became
permanently unmergeable — the check never reports at all, so it can
never be satisfied by re-running CI.

Observed on four open dependabot PRs, all `completed/cancelled` for this
workflow while a fifth succeeded:

  cancelled  dependabot/cargo/ui/src-tauri/reqwest-0.13   3385339  #19
  cancelled  dependabot/npm_and_yarn/ui/vitest-4.1.10     50eef14  #15
  cancelled  dependabot/npm_and_yarn/ui/multi-223fb6760   e32b73b  #20
  cancelled  dependabot/github_actions/actions/setup-py   2a9c4d3  #11
  success    dependabot/cargo/ui/src-tauri/getrandom-0.   cd54a61  #37

Keying the group by `github.ref` serialises per branch, so pushes to
main still queue against each other and real Pages deployments remain
ordered, while pull requests no longer compete for the same slot.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@Chris-ObtuseAI

Copy link
Copy Markdown
Contributor Author

Two follow-up findings while getting this green.

1. The lock export had to match the gate byte-for-byte. scripts/validate_release_python.py regenerates each lock into a temp dir and byte-compares. My first export omitted --no-annotate, so the committed file carried 37 lines of # via provenance comments the gate never produces — surfacing as {"failed_gate": "validation_lock_reproducible"}. Both files are now written with exactly the gate's own commands.

2. pip-audit is pinned in five places, not four. EXPECTED_TOOL_VERSIONS in validate_release_python.py asserts the installed version, separately from every locked one.

3. Four other dependabot PRs were permanently unmergeable, and it was not their fault. pages.yml had concurrency: {group: pages, cancel-in-progress: false} — a fixed string, not keyed by ref. Every PR and every push to main contended for one slot, and GitHub supersedes all but the newest queued run. Because Build synthetic-only Organism is a required check, a superseded PR's check never reports at all, so branch protection can never be satisfied and re-running CI does not help:

cancelled  dependabot/cargo/ui/src-tauri/reqwest-0.13   3385339d  #19
cancelled  dependabot/npm_and_yarn/ui/vitest-4.1.10     50eef143  #15
cancelled  dependabot/npm_and_yarn/ui/multi-223fb6760   e32b73b6  #20
cancelled  dependabot/github_actions/actions/setup-py   2a9c4d31  #11
success    dependabot/cargo/ui/src-tauri/getrandom-0.   cd54a614  #37

Keying the group by github.ref fixes it — main still serialises against itself so real Pages deploys stay ordered, but PRs no longer starve each other. This would have silently blocked any two PRs landing close together, indefinitely.

@Chris-ObtuseAI
Chris-ObtuseAI merged commit b743d5a into main Aug 1, 2026
10 checks passed
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