Repository navigation
[bug] Fix header parsing - #649
Merged
Merged
Conversation
adam-singer
marked this pull request as ready for review
July 15, 2026 21:09
These were leftover output from manually running puller-app/merge-app against gcr.io during verification and were accidentally committed with the header-parsing fix.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
puller-appfailed to authenticate against gcr.io with an "Invalid auth header" error, even though the exact same code worked fine against Docker Hub.The root cause is in
BearerConfig::from_auth_header(src/registry/http/http_cli/private_impl.rs), which parses theWWW-Authenticate: Bearer ...challenge header returned on a 401. The original implementation split the header into a flat list of tokens using the regex(".*?"|[^",\s]+), then paired up tokens two-at-a-time assuming everykey=valuepair produces exactly onekey=token followed by one"value"token.That assumption only holds when values are quoted. Docker Hub quotes both
realmandservice:gcr.io, however, leaves
serviceunquoted:Since there's no quote or comma to stop it,
service=gcr.iomatches as a single token instead of splitting intoservice=andgcr.io. This produces an odd-length token list, which trips thepairs.len() % 2 != 0check and fails with "Invalid auth header" beforepuller-appever gets a chance to authenticate.Fix
Replace the split-then-pair logic with a regex that matches each
key=valuepair directly:([a-zA-Z_][a-zA-Z0-9_]*)=("[^"]*"|[^,]*). This correctly handles quoted values, unquoted values, and any mix of the two within the same header, without relying on token-count parity.Tests
Added coverage in
private_impl.rsfor the real-world header shapes registries send, in addition to the existing Docker Hub case:servicescopecontaining a comma (e.g.pull,push)realmnorservicequoted)servicebeforerealm)error=param present (RFC 6750 §3)service/ missingrealm(should error)Bearerscheme (should error)All pass via
cargo test --lib private_impl, and the full crate test suite (cargo test) shows no regressions.Manual testing
Build
puller-appand run it against gcr.io directly to confirm the auth handshake now succeeds end-to-end:Before the fix, this fails with
Invalid auth header. After the fix, it succeeds and printsConnected to registry https://gcr.io/before proceeding to pull the manifest/layers.To just exercise the parser without building the full binary:
cargo test --lib private_impl