Skip to content

authn: do not overwrite AuthConfig.Auth when username and password are empty - #2420

Merged
Subserial merged 2 commits into
google:mainfrom
nileshpatil6:fix/authconfig-marshal-preserve-auth
Aug 31, 2026
Merged

Subserial merged 2 commits into
google:mainfrom
nileshpatil6:fix/authconfig-marshal-preserve-auth

Conversation

@nileshpatil6

Copy link
Copy Markdown
Contributor

Fixes #1864.

The bug

AuthConfig.MarshalJSON unconditionally recomputes the auth field:

func (a AuthConfig) MarshalJSON() ([]byte, error) {
	shadow := (authConfig)(a)
	shadow.Auth = encodeDockerConfigFieldAuth(shadow.Username, shadow.Password)
	return json.Marshal(shadow)
}

When neither Username nor Password is set there is nothing to derive it from, so auth becomes the encoding of ":", which is Og==.

AuthConfig{Auth: "dXNlcjpwYXNz"}    -> {"auth":"Og=="}
AuthConfig{RegistryToken: "bearer"} -> {"auth":"Og==","registrytoken":"bearer"}
AuthConfig{IdentityToken: "id"}     -> {"auth":"Og==","identitytoken":"id"}

The first case silently discards a valid credential: a config carrying only an already encoded Auth marshals to a useless one, and round-tripping it yields Auth: "Og==" with empty username and password. The second and third invent an auth field for configs that never had one.

This is the case reported in #1864, which was closed by the stale bot rather than resolved, with a follow-up noting it was still broken.

The change

Derive auth only when a username or password is present, otherwise leave whatever the caller set:

if shadow.Username != "" || shadow.Password != "" {
	shadow.Auth = encodeDockerConfigFieldAuth(shadow.Username, shadow.Password)
}

Configs carrying a username and password are unaffected, including the existing auth field replaced case where a stale Auth is deliberately overwritten.

Testing

Two cases added to the existing TestAuthConfigMarshalJSON table: an auth-only config, and a token-only config. Without the change both fail:

--- FAIL: TestAuthConfigMarshalJSON/auth_field_preserved_when_username_and_password_are_empty
--- FAIL: TestAuthConfigMarshalJSON/no_auth_field_is_invented_for_a_token_only_config

With it, TestAuthConfigMarshalJSON and TestAuthConfigUnmarshalJSON pass in full. TestPodmanConfig fails identically before and after on my machine because it picks up a REGISTRY_AUTH_FILE from the environment; it is unrelated to this change.

…e empty

AuthConfig.MarshalJSON unconditionally recomputes the auth field from
Username and Password:

    shadow.Auth = encodeDockerConfigFieldAuth(shadow.Username, shadow.Password)

When neither is set there is nothing to derive it from, so the field is
overwritten with the encoding of ":", i.e. "Og==".

Two consequences:

    AuthConfig{Auth: "dXNlcjpwYXNz"}       -> {"auth":"Og=="}
    AuthConfig{RegistryToken: "bearer"}    -> {"auth":"Og==","registrytoken":"bearer"}

The first silently discards a valid credential. The second invents an
auth field for a config that never had one.

Only derive the auth field when a username or a password is present.
Configs that carry both are unaffected, including the existing case
where a stale Auth is deliberately replaced.

Fixes google#1864

@Subserial Subserial left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, but can you remove the comments? They are redundant after the fix, and the comments on the test are useless when the test case already has a name.

The condition and the test case names already say what they do.
@nileshpatil6

Copy link
Copy Markdown
Contributor Author

Done, comments removed from both the fix and the test cases. Tests still pass.

@codecov-commenter

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 57.57%. Comparing base (3f4ff3c) to head (1766c32).

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #2420   +/-   ##
=======================================
  Coverage   57.57%   57.57%           
=======================================
  Files         166      166           
  Lines       11564    11565    +1     
=======================================
+ Hits         6658     6659    +1     
  Misses       4127     4127           
  Partials      779      779           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@nileshpatil6

Copy link
Copy Markdown
Contributor Author

The failing e2e windows-latest job looks like a runner problem rather than something in this change.

The job pushed and tagged the image fine, then docker run aborted with:

failed to connect to the docker API at npipe:////./pipe/docker_engine; check if the path is correct and if the daemon is running: open //./pipe/docker_engine: The system cannot find the file specified.

so the Docker daemon was not up on that runner. The same job passed on other branches the same day (run 33007300693), and this change only affects JSON marshalling in pkg/authn, which the e2e script does not exercise.

I do not have permission to re-run the job. Could you kick it off when you get a chance?

@Subserial
Subserial merged commit 6056250 into google:main Aug 31, 2026
20 of 21 checks passed
social4hyq pushed a commit to social4hyq/homebrew-core that referenced this pull request Sep 20, 2026
crane 0.22.1

Created-by: HarmonybrewBot
Commit-by: HarmonybrewBot
Merged-by: HarmonybrewBot
Description: Created by `brew bump`

---

Created with `brew bump-formula-pr`.<details>
  <summary>release notes</summary>
  <pre>## What's Changed
* Reject non-canonical IP literals in all SSRF guards by @shaggyinsomniac in google/go-containerregistry#2426
* daemon: fix stale docker/docker reference in WithClient docs by @BobDu in google/go-containerregistry#2428
* build(deps): bump the go-deps group across 2 directories with 4 updates by @dependabot[bot] in google/go-containerregistry#2422
* authn: do not overwrite AuthConfig.Auth when username and password are empty by @nileshpatil6 in google/go-containerregistry#2420
* build(deps): bump the actions group across 1 directory with 8 updates by @dependabot[bot] in google/go-containerregistry#2423
* Support pulling images by sha512 digest by @BobDu in google/go-containerregistry#2427
* Allow empty label and annotation values in crane mutate by @theadsingh in google/go-containerregistry#2418
* fix(build): Use dependencies.gitSource in cloudbuild_v2.yaml by @tprussak in google/go-containerregistry#2434
* validate: support index attestation manifests and empty configs by @Subserial in google/go-containerregistry#2414
* name: improve error when parsing a reference with a URL scheme by @locker95 in google/go-containerregistry#2431
* fix(build): install binaries to /ko-app and add to PATH (#2424) by @tprussak in google/go-containerregistry#2436
* fix(release): honor declared Go toolchain by @rksharma-owg in google/go-containerregistry#2435
* remote: apply checkRedirectSSRF to writer-side HTTP clients by @locker95 in google/go-containerregistry#2432
* flatten: preserve config and layer media types when flattening by @Subserial in google/go-containerregistry#2438
* fix(mutate): make Time layer updates lazy by @amarkdotdev in google/go-containerregistry#2429
* build(deps): bump the go-deps group across 2 directories with 3 updates by @dependabot[bot] in google/go-containerregistry#2439
* remote: copy manifest annotations to referrers fallback tag descriptors by @codysoyland in google/go-containerregistry#2441

## New Contributors
* @shaggyinsomniac made their first contribution in google/go-containerregistry#2426
* @BobDu made their first contribution in google/go-containerregistry#2428
* @nileshpatil6 made their first contribution in google/go-containerregistry#2420
* @theadsingh made their first contribution in google/go-containerregistry#2418
* @locker95 made their first contribution in google/go-containerregistry#2431
* @rksharma-owg made their first contribution in google/go-containerregistry#2435
* @codysoyland made their first contribution in google/go-containerregistry#2441

**Full Changelog**: https://github.com/google/go-containerregistry/compare/v0.22.0...v0.22.1</pre>
  <p>View the full release notes at <a href="https://github.com/google/go-containerregistry/releases/tag/v0.22.1">https://github.com/google/go-containerregistry/releases/tag/v0.22.1</a>.</p>
</details>
<hr>

See merge request: Harmonybrew/homebrew-core!18250
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ggcr: authn.AuthConfig JSON marshaling logic does not handle some edge cases correctly

3 participants