chore: Authenticate Docker Hub pulls in the release template #41
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!41
Loading…
Reference in a new issue
No description provided.
Delete branch "feature/37-docker-hub-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
Part of #37 — deliberately not
Closes. Two of the four acceptance criteria are met here; one is handed to the platform admin and one is follow-up work in other repositories. Closing the issue on merge would hide both.Problem
Docker Hub counts anonymous pulls per IP, and every repository on this fleet shares one. A burst of releases therefore fails an unrelated build with
toomanyrequests, and the base images in eachDockerfileare pulled with no credentials at all.Solution
The
publishjob intemplates/release.ymllogs in todocker.iowith a read-only token before building, and the README documents both secrets by name, type, scope and location.It is a plain
docker login, notdocker/login-action. That action fails the job on an empty password, which would turn "no token configured" into "no releases" — the opposite of what is wanted. This warns and continues, so a caller without the secrets still builds, anonymously, exactly as it does today.Review notes
What is verified, and how. The repository's checker only parses
action.ymlfiles, sotemplates/release.ymlgets no CI coverage at all — the shell added here would ship unvalidated. I ran the checker's own technique over the template by hand (${{ }}replaced,bash -n): 7 run steps, 0 invalid. I also exercised the guard against a stubdockerthat refuses empty credentials the way the real one does:The last line is the control: with the guard deleted, the case the second criterion describes fails the job. No real credential was used — the token in the test is a literal string and the
dockeronPATHwas a stub.The token is piped through stdin rather than passed as an argument, so it does not appear in a process listing.
Criterion 3 is not done here, by choice. Registering
DOCKER_HUB_USERandDOCKER_HUB_READ_PUBLICon each org and on theahmaduser's repositories is credential handling; I do not read the token out of the workspace store or POST it anywhere. That step is the platform admin's, and until it happens every build simply keeps warning and pulling anonymously — which is the current behaviour, so nothing regresses in the meantime.Criterion 1 reaches new copies only. This template is copied, not called, so merging it authenticates a repository the next time it converges. Eleven repositories already carry their own copy and none has the login:
Editing eleven repositories from an issue that names none of them is not something to slip into this PR; it is filed separately.
Risks and trade-offs
DOCKER_HUB_USERis new — the workspace only had the token. A Docker Hub login needs both, so the alternative was baking an account name into a public repository.Both secrets are optional by design. That is the right default here, but it does mean a misconfiguration is a warning rather than an error, and warnings are easy to miss in a green run. If the fleet ever depends on authenticated pulls rather than merely preferring them, that choice should be revisited deliberately.
This does not help the runner fetching a job's own
container:image, which happens before any step runs. That is host-side, and isamtronics/infrastructure-vps#395.validategreen onadf6375. Verification against each acceptance criterion, including the one I cannot close.1 — "with the secret available, image pulls from
docker.ioare authenticated." Verified as far as it can be without the secrets existing anywhere yet. With both variables set, the step runsdocker login docker.io -u <user> --password-stdinbeforedocker/build-push-action, so the build's base-image pulls use the credential in the shared docker config. Against a stub standing in fordocker:What that does not prove is that Docker Hub accepts the token, which cannot be known until the secrets are registered. The step is positioned and shaped correctly; whether the credential works is the third criterion's business.
2 — "without the secret, it still runs anonymously with a visible warning rather than failing." Verified, with a control:
The third line is the point. Deleting the guard produces exactly the failure this criterion forbids, so the guard is doing the work rather than sitting there looking correct. The stub refuses empty credentials the way
dockeritself does; the middle case matters too — a half-configured caller warns rather than attempting a login destined to fail.3 — "the secret is registered and read back by name on each org and repository." Not done, and not mine. Registering
DOCKER_HUB_USERandDOCKER_HUB_READ_PUBLICmeans handling the credential; I do not read it out of the workspace store or send it anywhere. Until the platform admin registers them, every build warns and pulls anonymously — today's behaviour exactly, so nothing regresses while it waits. To verify presence without exposing a value:GET /api/v1/orgs/{org}/actions/secretsandGET /api/v1/repos/{owner}/{repo}/actions/secretslist names only.4 — "documented by name, type, scope and location, never by value." Done — a table in the README's release-flow section, both marked optional, neither with a value anywhere in the diff.
One thing found on the way, worth stating plainly. This repository's checker parses
action.ymlfiles only, sotemplates/release.yml— the file every application copies its pipeline from — has no validation at all. Shell added to it ships unchecked, which for a template is worse than for an action, because the mistake is copied before it is ever run. I validated this change by hand with the checker's own technique (7 run steps, 0 invalid), but that is me remembering, not CI. Not fixed here; it is not what #37 asks for. Worth an issue of its own, and I will file one rather than let it sit in a PR comment.Marking ready.
Part of #37, notCloses— the third criterion stays open until the secrets exist.WIP: chore: Authenticate Docker Hub pulls in the release templateto chore: Authenticate Docker Hub pulls in the release templateApproving — no defects. Two observations in the body, one of which is about what this will and will not fix.
Verified independently, including the control. I ran the checker's own technique over the whole template — every
run:body with${{ }}substituted, throughbash -n: 7 run steps, 0 invalid, matching your count. Then the guard against a stubdockerthat refuses an empty password the way the real client does:The control is the row that matters and it reproduces. (My first attempt at it did not: I deleted the guard with a
sedwhose indentation did not match the extracted block, so the "guard removed" case silently still had the guard and printed the warning. A broken fixture looks exactly like a passing control, which is the whole reason to check that the mutation actually changed something.)Piping the token through stdin rather than argv is right, and choosing a plain
docker loginoverdocker/login-actionfor the stated reason — that the action fails the job on an empty password, turning "no token" into "no releases" — is the correct trade for an optional credential.The observation worth acting on: this will not fix the failures the fleet actually had today. Every tail posted on
ahmad/expiro#31says the same thing:That is a connectivity failure, not
toomanyrequests— and it is a timeout reachingauth.docker.io, which is the same endpointdocker loginuses. An authenticated pull would have failed at the same handshake. So this is the right fix for the problem #37 describes, and the problem that cost several hours today is the one you have already filed asinfrastructure-vps#395. Worth being explicit in the issue, because "authenticate Docker Hub pulls" reads like the answer to what everyone just watched fail, and it is not.Second, smaller:
templates/release.ymlnow carries shell that eleven repositories copy, and nothing in CI checks it — the checkerrglobsaction.ymlonly. You did the check by hand and I reproduced it, but that is evidence about this commit rather than a guard against the next, which is the exact argument #31 made for testing the checker itself. Extending the checker totemplates/*.ymlis not this PR's job; it is worth an issue beside the eleven-repository rollout.Part of #37rather thanClosesis the right call, and saying which two criteria are met, which is the platform admin's, and which is follow-up in named repositories is what makes it verifiable rather than a promise. Approval does not merge.