bug(release-prep): DRY_RUN early-check treats non-empty as truthy — DRY_RUN_INPUT='false' silently enables dry-run #70
Labels
No labels
bump
major
bump
minor
bump
patch
kind/bug
kind/chore
kind/docs
kind/feature
priority/critical
priority/high
priority/low
priority/medium
size/L
size/M
size/S
size/XL
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
frankenbit/release-toolkit#70
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Symptom
When the v0.4.0
_release.ymlreusable fires onpush:mainwith mode=update,release-prep.shruns in DRY-RUN even though the operator never set dry_run=true. No rolling PR is created. Workflow reportssuccessbecause release-prep.sh exits 0 normally.Surfaced live during the v0.4.0 dogfood cut (slice 4): fragment-PR #69 merged → workflow fired → release-decide.sh correctly emitted
mode=update, bump_level=minor, next_version=0.4.0→ act-step invokedrelease-prep.sh --rolling-mode --target-version 0.4.0→ release-prep silently ran in dry-run, printed[DRY-RUN] would: git checkout -B release-prep/rolling+METHOD POSTsummary, exited 0. No rolling PR opened. Workflow reported success at 6 seconds total elapsed.Root cause (verified at source)
scripts/release-prep.shlines 127-136:The first check (line 127) treats any non-empty
DRY_RUN_INPUTorDRY_RUN_ENVas a request to enable dry-run, regardless of value. It setsDRY_RUN=1.The second check (line 132) then sanitizes against
"false"or"0"— but it operates on$DRY_RUN(now"1"), not on the originalDRY_RUN_INPUT. So"1" != "false"→DRY_RUNstays1. The sanitization is structurally unable to catch theDRY_RUN_INPUT="false"case._release.yml's workflow_call inputs declaredry_runwithdefault: 'false'. For push events (where dry_run is not explicitly set), Forgejo Actions renders${{ inputs.dry_run }}as the default string'false'. This is passed to the act-step asDRY_RUN_INPUT="false"→ trips line 127 → silent dry-run.Why slice 2's merge didn't reveal this
Slice 2's first-fire was
mode=noop(no release-relevant content since v0.3.5). The act step short-circuits noop before invoking release-prep.sh, so the dry-run-when-input-false bug never executes on noop runs. Only manifests when mode=update or mode=cut fires.Tested fix
The first check should use truthy semantics matching the second check, OR the second check should sanitize the SOURCE env vars before promoting to
DRY_RUN. Cleanest: merge both checks into a single truthy probe across sources:Sibling silent-failure-class lessons
n=4 in the silent-failure-class series. Per the logical-vs-empirical promotion criterion (Surveyor 5898), the empirical path to memory-promotion is n=3 structurally-distinct instances. Four instances of "silent-wrong from substrate misinterpretation" might warrant promoting to a project-memory pin now.
Sequencing knot (same as #66)
_release.yml@v0.4.0-rc.1and_release-prep.yml@v0.3.5both contain the buggy script. The fix must land inrelease-prep.sh, ship as a new patch tag (v0.3.6), then_release.ymlconsumers re-pin via a new bootstrap-tagv0.4.0-rc.2at v0.3.6's SHA.Refs
Filed: 2026-06-25 from live dogfood-catch during v0.4.0 cut attempt (the architectural arc surfacing yet another substrate bug at the substrate level).
forgejo-actions referenced this issue2026-06-25 20:49:00 +02:00