Development record
Every dependabot PR that bumps a pinned action in .github/workflows/release.yml or auto-release.yml fails TestSelfScaffoldParity and can never go green on its own. Observed on PR #211 (actions/attest 4.2.0 -> 4.2.2): 'release.yml: abcd rendering is not byte-identical to the committed workflow', failing check on BOTH platforms while gitleaks, record-lint, smoke and zizmor all pass. Root cause: the committed workflow is a GENERATED artefact. internal/core/launch/scaffold/templates/release.yml.tmpl:270 and .github/workflows/release.yml:248 both pin actions/attest@f7c74d28b9d84cb8768d0b8ca14a4bac6ef463e6 (v4.2.0), and TestSelfScaffoldParity asserts the two are byte-identical so that abcd's own release dogfoods the machinery a managed repo receives. Dependabot edits only the derived file, so parity breaks by construction on every such bump — this is recurring and structural, not a one-off. The obvious fix (bring the scaffold template into dependabot's scope) is NOT AVAILABLE: the github-actions ecosystem discovers only .github/workflows/*.yml and composite action.yml manifests under the configured directory, and no package-ecosystem scans an arbitrary .tmpl under internal/. .github/dependabot.yml today declares gomod and github-actions, both at directory /. Note also the wrong-direction trap: auto-rendering the scaffold on a dependabot PR would REVERT the bump, since render flows template -> workflow. Options, none adopted: (a) make the parity failure self-explaining — the message says 'not byte-identical' and prints the first diff but never names the template path or says 'an action bump must be applied to the template too', which is the cheapest change and matches the loud-staging principle; (b) propagate the bump backwards — a job on dependabot PRs that applies the changed pin to the template and commits to the bot branch, which is the durable fix but is custom automation writing to a bot branch; (c) drop these two workflows from dependabot's scope and manage their pins by hand from the template, trading automation for consistency. Secondary risk worth weighing: a permanently-red dependabot PR trains the maintainer to discount red CI on exactly the PRs where CI most needs to be trusted.
Every dependabot PR that bumps a pinned action in .github/workflows/release.yml or auto-release.yml fails TestSelfScaffoldParity and can never go green on its own. Observed on PR #211 (actions/attest 4.2.0 -> 4.2.2): 'release.yml: abcd rendering is not byte-identical to the committed workflow', failing check on BOTH platforms while gitleaks, record-lint, smoke and zizmor all pass. Root cause: the committed workflow is a GENERATED artefact. internal/core/launch/scaffold/templates/release.yml.tmpl:270 and .github/workflows/release.yml:248 both pin actions/attest@f7c74d28b9d84cb8768d0b8ca14a4bac6ef463e6 (v4.2.0), and TestSelfScaffoldParity asserts the two are byte-identical so that abcd's own release dogfoods the machinery a managed repo receives. Dependabot edits only the derived file, so parity breaks by construction on every such bump — this is recurring and structural, not a one-off. The obvious fix (bring the scaffold template into dependabot's scope) is NOT AVAILABLE: the github-actions ecosystem discovers only .github/workflows/*.yml and composite action.yml manifests under the configured directory, and no package-ecosystem scans an arbitrary .tmpl under internal/. .github/dependabot.yml today declares gomod and github-actions, both at directory /. Note also the wrong-direction trap: auto-rendering the scaffold on a dependabot PR would REVERT the bump, since render flows template -> workflow. Options, none adopted: (a) make the parity failure self-explaining — the message says 'not byte-identical' and prints the first diff but never names the template path or says 'an action bump must be applied to the template too', which is the cheapest change and matches the loud-staging principle; (b) propagate the bump backwards — a job on dependabot PRs that applies the changed pin to the template and commits to the bot branch, which is the durable fix but is custom automation writing to a bot branch; (c) drop these two workflows from dependabot's scope and manage their pins by hand from the template, trading automation for consistency. Secondary risk worth weighing: a permanently-red dependabot PR trains the maintainer to discount red CI on exactly the PRs where CI most needs to be trusted.
Half fixed 2026-08-11; the automation is a recorded DEAD END, do not re-attempt as described. The manual half shipped: make scaffold-sync propagates the workflow pins into the templates, TestSyncRepoPinsIsCleanToday fails preflight when a bump landed on a workflow alone and names the fixing command, and option (a) from the original entry is moot because the sync tool subsumes it. What remains open is option (b), the zero-touch propagation onto the dependabot branch.
A workflow_run implementation was built and REJECTED in review on 2026-08-11, for two reasons worth recording so the next attempt does not rediscover them. First, it cannot work at all: a push made with GITHUB_TOKEN raises no events, so the sync commit moves the PR head to a SHA that never gets a CI run — the PR goes from red to permanently pending, a weaker signal than the failure it set out to fix. This repo already documents the mechanism at .github/workflows/auto-release.yml ("A GITHUB_TOKEN-pushed tag raises no tag-push event, which is why the release below invokes release.yml explicitly rather than relying on the tag"). Second, the design was unsound: actions/checkout with ref: <head_branch> makes the BRANCH's tree the workspace, so a subsequent go run ./cmd/scaffold-sync executes branch-supplied code under the contents: write token that persist-credentials: true leaves in .git/config. workflow_run buys a trusted workflow DEFINITION, not a trusted WORKSPACE — the standard pitfall. Independent review also found the trigger fails zizmor --persona regular with dangerous-triggers (unverified locally; no docker daemon), and that committing as github-actions[bot] collides with the no-branch-commit tripwire in release.yml, which fails a release run when a bot commit lands on the default branch mid-job.
Any future attempt therefore needs, at minimum: a push credential that is NOT GITHUB_TOKEN (a GitHub App token preferred over a PAT — short-lived and scoped, and its pushes do raise events); a structure where the untrusted tree is never executed under the write token (compute the patch in a read-only job with persist-credentials: false, apply and push from a trusted one checked out at github.sha); a commit identity that is not github-actions[bot]; and a concurrency group keyed on workflow_run.event as well as the branch, since ci produces both a push-derived and a pull_request-derived run per dependabot branch and the useless one can otherwise cancel the working one.
Deferral 2026-09-30
Deferred past v0.11.1: The product thinker's ruling M3 of 2026-09-23: automate it, planned next cycle as its own intent with a security review. That intent is filed as the draft itd-2609301020001595 (a pinned-action bump syncs its scaffold template and lands re-authored), and this record now waits on that draft's planning interview. The credential sign-off M3 owed is given: ruling H2 (a GitHub App the person creates and installs pushes; the person is the landed commit's author) and ruling CG1 (the App token is minted in shell, openssl JWT and curl exchange, revoked on exit, no new action). The manual half ships (make scaffold-sync and TestSyncRepoPinsIsCleanToday), so a pin bump on a workflow alone reds preflight and names the fix; until the draft ships, a dependabot pull request bumping a pinned action is landed by a human.
Remedy grounds (2026-09-29)
- The credential shape was the open question and H2 answers it for dependency updates; the record's own rejected workflow_run attempt supplies the rest (never execute the bot tree under a write token). Renovate's regex custom manager can update pins in arbitrary files such as a .tmpl in the same PR: https://docs.renovatebot.com/modules/manager/regex/ (consulted 2026-09-29).
- Rejected for now: switching to Renovate, the simpler structural fix but a new tool and app needing the person's sign-off; worth putting to the person with the intent.
Deferral lapsed 2026-10-23
The deferral past v0.11.1 lapsed long ago and is withdrawn, on the old-majors triage of 2026-10-23. It stays open until itd-2609301020001595 ships. The reason it carried stays in the body above.
Frontmatter
| id | iss-209 |
|---|---|
| type | issue |
| lifecycle | open |
| severity | major |
.abcd/work/issues/open/iss-209-every-dependabot-pr-that-bumps-a-pinned.md
open on GitHub ↗ · commit history ↗
References1
- itd-2609301020001595A pinned-action bump syncs its scaffold template and lands re-authoredrelated
mentions4
- dcn-26082100000000012026-08-21 — Bug-hunt round 4, branch bughunt-b/round-4. Baseline (make preflight
- iss-211Multi-project adoption raises the priority of itd-91 (AI-attribution preference) and itd-92 (branch-protection verification) from 'good hygiene' to 'the product claim'. What abcd-cli has today is its OWN answer hard-coded: scripts/check-attribution.sh names specific banned footers and a fixed required trailer, and .github/workflows/attribution.yml is a hand-written file in one repo. Neither is portable, which is exactly the gap itd-91 already states — a project adopting abcd inherits abcd's preference by reading its docs but has no first-class way to declare its own (Co-Authored-By, none at all, or house style). The durable home is a rule in internal/core/lint beside deliverystate, indexdrift and citations: reachable from CLI and plugin, run in any managed repo, reading a declared per-repo preference rather than a constant. Two further observations from the 2026-08-11 session. (1) SCAFFOLD IS THE DELIVERY MECHANISM. internal/core/launch/scaffold renders exactly three artefacts into a managed repo today (release.yml, auto-release.yml, the runbook); an attribution workflow becomes the fourth, so every managed repo inherits the gate from one template instead of someone copying a file. It would automatically gain the self-scaffold parity property — and with it the dependabot pin problem of iss-209, which the sync tool merged in PR #215 already handles. The work just landed is the delivery rail for making this portable. (2) ITD-92 GATES EVERYTHING ELSE. A scaffolded gate that no repo adds to its required status checks is decoration; across N repos the required-check wiring and the enforce_admins policy stop being settings a maintainer clicks and become policy abcd asserts and verifies. That makes itd-92 arguably the higher-leverage of the pair: it is what converts every abcd-scaffolded check, present and future, from advisory into binding. itd-92's own capture note already says this in miniature — 'captured 2026-07-17, the day abcd-cli's own main was protected by hand — work the tool should carry for every repo it manages'. Both intents are still ungrilled drafts.
- iss-273Consolidate the build-provenance step onto actions/attest and drop the wrapper. Upstream states that as of version 4, actions/attest-build-provenance is simply a wrapper on top of actions/attest, and that new implementations should use actions/attest instead. This repo ALREADY invokes actions/attest directly at .github/workflows/release.yml:248, in the same job that uses the wrapper at :296 -- so it currently runs attest 4.2.2 directly and, after the gh-316 bump, 4.2.1 transitively through the wrapper. Consolidating would remove a trust layer, eliminate that version skew, and halve the dependabot churn that keeps tripping iss-209 (every pinned-action bump edits the generated workflow only, breaking template parity and reddening CI until a human runs make scaffold-sync). actions/attest generates SLSA provenance natively in src/provenance.ts, so the migration looks feasible; the work is to map the wrapper's inputs onto the underlying action's and confirm the emitted attestation predicate is unchanged. Found by the security review of the actions/attest-build-provenance 4.1.1 to 4.2.2 bump, which approved that bump on its merits.
- iss-2608211142496517cmd/scaffold-sync/main.go's package doc comment states the command is 'run by the scaffold-sync workflow on a dependabot branch', but no such workflow exists or ever existed: the string appears nowhere in .github/, and iss-209 records that a workflow_run automation was built and rejected in review (a GITHUB_TOKEN push raises no events, leaving the PR permanently pending; and it was unsound). Makefile:72-76 states the opposite outright ('Nothing in CI calls either target'). The false claim misdirects whoever debugs a red TestSelfScaffoldParity to wait for automation that will never run or re-attempt the dead end iss-209 exists to stop.