Skip to content

Inverted error check in NewRegistryClient discards auth credentials #583

@jeffwidman

Description

@jeffwidman

Summary

In NewRegistryClient() in internal/infra/registry_client.go, the error check for getRegistryAuthHeader() is inverted, causing auth credentials to be discarded when available and empty credentials to be set when unavailable.

Details

func NewRegistryClient(image string) *RegistryClient {
    // ...
    user, pass, err := getRegistryAuthHeader(domain)
    if err != nil {    // err != nil means credentials NOT found
        remoteOptions = []remote.Option{
            remote.WithAuth(&authn.Basic{Username: user, Password: pass}),
            // sets auth with empty user/pass since getRegistryAuthHeader
            // returns ("", "", error) on failure
        }
    } else {           // err == nil means credentials ARE available
        remoteOptions = []remote.Option{}
        // discards valid credentials, uses no auth
    }
    // ...
}

getRegistryAuthHeader() returns (user, pass, nil) on success and ("", "", error) on failure. The branches should be swapped.

Impact

GetLatestDigest() and DigestExists() always query GHCR unauthenticated (since for ghcr.io images, valid credentials are returned with err == nil, which hits the else branch with empty options).

For public images this still works because GHCR serves public manifests without auth, but unauthenticated requests may hit a cached CDN layer that returns stale tag-to-digest mappings. This could cause the freshness check in pullImage() to incorrectly conclude "image is already up to date" when a newer image has been pushed.

Fix

Swap the branches:

user, pass, err := getRegistryAuthHeader(domain)
if err == nil {
    remoteOptions = []remote.Option{
        remote.WithAuth(&authn.Basic{Username: user, Password: pass}),
    }
} else {
    remoteOptions = []remote.Option{}
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions