build-push: stop a whitespace-tainted REGISTRY_TOKEN failing as "denied" #154
No reviewers
Labels
No labels
Compat/Breaking
Kind/Bug
Kind/Documentation
Kind/Enhancement
Kind/Feature
Kind/Security
Kind/Testing
Priority
Critical
Priority
High
Priority
Low
Priority
Medium
Reviewed
Confirmed
Reviewed
Duplicate
Reviewed
Invalid
Reviewed
Won't Fix
Status
Abandoned
Status
Blocked
Status
Need More Info
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: Jinemi/thermograph#154
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/registry-login-whitespace"
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?
docker login --password-stdinstrips exactly one trailing newline.echo "$T"adds one. So a secret pasted with a trailing newline — what you get copying from a terminal, or from an editor that terminates files with one — arrives as"<token>\n"and the registry answers:with no further detail. That is indistinguishable from a revoked or wrong token.
On 2026-08-01 this stopped every build and deploy in the estate, and cost an afternoon diagnosing a credential that was in fact valid. Tested by hand against the live registry, the same token returned
200on/v2/and was issued apull,push-scoped registry token forjinemi/thermograph/backend.Changes
echoa credential into stdin.${{ }}is substituted before bash parses the line, so a value containing a quote or newline changes the shape of the command itself, not merely its arguments.[0-9a-f]), then attempt the login anyway. A hard assertion on token format would block every build the day Forgejo changes that format — a worse failure than the one being prevented. The warning is enough to turn the registry's opaquedenied:into a diagnosis.Verified
The cleaning logic was exercised against a clean token, one with a trailing newline, one with surrounding spaces, an empty value, and a malformed value: the first three all normalise to a valid 40-character token, empty fails fast, malformed warns with its length.
Not the username
Worth recording, because it looked like a candidate. Tested against the live registry, all of
admin_emi,emiandjinemiauthenticate identically with a valid token, and each is issued a push-scoped token. Forgejo's container registry authenticates on the token, not the username — so the--usernamevalue in this file (and indeploy.sh,deploy-stack.sh, and the Terraform module, which still sayemi) is cosmetic for auth purposes.This does not fix the current outage on its own —
REGISTRY_TOKENstill has to hold a valid token. It makes the next occurrence diagnose itself instead of presenting as a revoked credential.`docker login --password-stdin` strips exactly ONE trailing newline. `echo "$T"` adds one. So a secret pasted WITH a trailing newline -- which is what copying from a terminal, or an editor that terminates files with one, produces -- arrives at the registry as "<token>\n" and gets back: Error response from daemon: Get "https://.../v2/": denied: with no further detail. That is indistinguishable from a revoked or wrong token. On 2026-08-01 it stopped every build and deploy in the estate and cost an afternoon of diagnosis on a credential that was in fact valid: the same token, tested by hand, returned 200 on /v2/ and was issued a pull,push-scoped registry token for jinemi/thermograph/backend. So: strip leading/trailing whitespace and CR/LF before the pipe, and never `echo` a credential into stdin. The token now travels through the ENVIRONMENT rather than being interpolated into the script text. `${{ }}` is substituted before bash parses the line, so a value containing a quote or a newline changes the shape of the command itself, not merely its arguments. Two diagnostics, deliberately asymmetric: * empty/unset -> HARD FAILURE naming where to set it. There is no case where proceeding helps. * wrong shape -> WARNING only (length, and whether it is outside [0-9a-f]), then attempt the login anyway. A hard assertion on token format would block every build the day Forgejo changes that format, which is a worse failure than the one being prevented. The warning is enough to turn the registry's opaque "denied:" into a diagnosis. Neither diagnostic prints the value; only its length and character class. Note the username is not a factor: tested against the live registry, all of admin_emi, emi and jinemi authenticate identically with a valid token and are each issued a push-scoped token. Forgejo's container registry authenticates on the token, not the username.