fix: Treat a rejected Docker Hub token like a missing one #51
No reviewers
Labels
No labels
priority/P0
priority/P1
priority/P2
priority/P3
size/L
size/M
size/S
size/XL
size/XS
state/done
state/in-progress
state/in-review
state/needs-refinement
state/ready
type/bug
type/chore
type/feature
type/refactor
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
amtronics/platform-actions!51
Loading…
Reference in a new issue
No description provided.
Delete branch "feature/50-tolerate-rejected-login"
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?
Issue
Closes #50
Problem
The
Log in to Docker Hubstep intemplates/release.ymlexists on one principle, stated in its own comment: a missing token must not stop a release. That is why it is hand-rolled rather thandocker/login-action, which fails a job on an empty password.It only honoured that for an absent token. A present but rejected one — expired, revoked, rotated — failed the step under
set -euo pipefail, takingpublishwith it. An expired token is the likelier future state than a missing one: tokens are registered once and then quietly age out, and nobody finds out until a release breaks. The failure is avoidable, because the anonymous path that would have worked is right there.Solution
Treat a failed login exactly like a missing one — warn, and continue anonymously.
Review notes
Driven with a stub
dockeron an otherwise emptyPATH, counting invocations. Before and after, so the change is visible rather than asserted:dockernot invokedDOCKER_HUB_USERsetdockernot invokedThe first three are regression guards: they pass on both heads and prove nothing about the fix, they only pin what must not change. The fourth is the kill.
check-actions.pyreportstemplates/release.yml: ok (7 run step(s) checked), its own suite passes 31/31, and README lint is clean.Risks and trade-offs
A build now proceeds anonymously where it previously failed loudly, so a stale credential is discoverable only from the warning rather than from a red job. That is the intended trade and the same one the missing-token branch already makes — an anonymous pull works until the per-IP cap is reached, and a release blocked by a rotated token is a worse outcome than one that pulls anonymously.
Found in review of
ahmad/portfolio#76. That PR copies this step verbatim, so it and the remaining ten repositories of #42 should pick this up rather than each fixing it locally — which is exactly the drift #38 exists to end.WIP: fix: Treat a rejected Docker Hub token like a missing oneto fix: Treat a rejected Docker Hub token like a missing oneMarked ready on
6dcc63e.validategreen.Verified against each acceptance criterion of #50, by extracting the step's
run:body and driving it with a stubdockeron an otherwise emptyPATH, counting invocations so "did not run" is distinguishable from "ran and said nothing":exit=0, onedockercall,::warning::Docker Hub login failed; pulling base images anonymously…. Against the unfixed template the identical input givesexit=1— that is the kill, and the only case that changes.exit=0, one call,Authenticated to Docker Hub as someone.dockernever invoked. Both sub-casesexit=0with zerodockercalls.Criteria 2 and 3 pass on both heads. They are regression guards pinning what must not change, not evidence the fix works — only criterion 1 is a kill, and a table that blurred the two would read as four proofs when it contains one.
Repository gates:
check-actions.pyreportstemplates/release.yml: ok (7 run step(s) checked), its own suite is 31/31, README lint clean.Note on what does not change: the token still reaches
dockerthrough--password-stdinfrom aprintfpipe, so it never entersargv. The pipe is now anifcondition, which alters nothing about how the secret is passed — worth stating explicitly since the review ofahmad/portfolio#76confirmed that property on the original form.Approved. CI green, and I reproduced the whole table against a stub
dockeron an otherwise emptyPATH, counting invocations so "did not call" is measured rather than inferred:The fourth row is the fix and the other three are unchanged, exactly as described.
Naming the first three as regression guards rather than counting them as kills is the right call, and it is the same distinction that came up on
#49two changes ago — applied here without being asked. A four-row table where three rows pass on both heads reads as much stronger evidence than it is unless someone says so.One thing the fix buys that the description does not claim. Wrapping the pipeline in
ifalso makes a missingdockerbinary degrade gracefully, because acommand not found(127) lands in the sameelse:Before, that would have failed the release too. Not a case that arises on this runner, but it is a real widening of the tolerance and it comes free with the shape you chose over, say,
|| trueon the login alone.set -edoes not interfere, which is the thing most likely to be wrong in this rewrite: a command in anifcondition is exempt, so the failing pipeline selects theelsebranch instead of ending the step. The measuredexit 0confirms it rather than my reading of the manual.Routing this upstream first was the correct order.
ahmad/portfolio#76carries a byte-identical copy — I verified that when reviewing it — so fixing it there alone would have started the drift#38exists to end, and the remaining repositories of#42now inherit the corrected version instead.