Skip to content

fix(no-ticket): report a missing Docker credential in the protocol format - #530

Open
cloudsmith-iduffy wants to merge 4 commits into
masterfrom
iduffy/fix-docker-helper-not-found
Open

cloudsmith-iduffy wants to merge 4 commits into
masterfrom
iduffy/fix-docker-helper-not-found

Conversation

@cloudsmith-iduffy

Copy link
Copy Markdown
Collaborator

Description

If you are logged out, or your SAML token has expired, docker pull of a public image from a Cloudsmith registry fails at the credential step:

$ docker pull docker.cloudsmith.io/acme/public/alpine:latest
Error: Unable to retrieve credentials. Provide credentials via the CLOUDSMITH_API_KEY environment variable, ...
error getting credentials - err: exit status 1, out: ``

The cause is the stdout of docker-credential-cloudsmith get. When no credential resolves, it exits 1 with nothing on stdout. Docker reads a helper's stdout and treats only credentials not found in native keychain as "no credential for this host". Any other output, including empty output, is a hard error. Docker then stops before it tries an anonymous pull. See errCredentialsNotFoundMessage in credentials/error.go and Get in client/client.go of docker/docker-credential-helpers.

With this change, the helper writes that exact string on stdout and exits 1. The guidance message stays on stderr. Docker continues without credentials:

$ docker pull docker.cloudsmith.io/acme/public/alpine:latest
Error: Unable to retrieve credentials. Provide credentials via the CLOUDSMITH_API_KEY environment variable, ...
Cannot connect to the Docker daemon at tcp://127.0.0.1:1. Is the docker daemon running?

(That run uses a temporary HOME and DOCKER_HOST=tcp://127.0.0.1:1, so the daemon error shows that Docker got past the credential step. Docker client 29.8.2.)

An empty or whitespace-only server URL on stdin now gives the protocol's no credentials server URL on stdout, not empty output. I also added type hints to _execute_get.

I checked the other actions. store and erase exit 0, and list prints {}. Docker accepts all of these, so I left them as they are. An unexpected exception inside get still exits 1 with empty stdout, so Docker reports a hard error. A real failure must not look like "no credential".

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update
  • Refactoring
  • Other (please describe)

Additional Notes

What changes for users and scripts:

  • docker-credential-cloudsmith get (and cloudsmith credential-helper docker) now prints credentials not found in native keychain on stdout when it has no credential. A script that expects empty stdout on failure sees this line. The exit code stays 1.
  • A pull from a private repository without a credential now fails with the 401 error of the registry, not with error getting credentials. This message tells the user less about the cause. To help, Docker connects the helper's stderr to its own stderr (ec.Stderr = os.Stderr in client/command.go), so the "Unable to retrieve credentials" guidance still shows in the terminal.
  • A public pull without a credential now works, and the same guidance line shows on stderr.

Tests: I updated the protocol tests in cloudsmith_cli/cli/tests/commands/test_credential_helper.py for the not-found and blank-URL cases. The full unit suite passes.

🤖 Generated with Claude Code

…rmat

When no credential resolves, the Docker credential helper now writes
"credentials not found in native keychain" to stdout. Docker then pulls
without credentials, so public images work again. The guidance message
stays on stderr. An empty server URL now gives the protocol message
"no credentials server URL" on stdout.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings October 23, 2026 21:40
@cloudsmith-iduffy cloudsmith-iduffy added the breaking change Changes behaviour that scripts or users can depend on label Oct 23, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Approval recommended

The focused changes match Docker’s credential-helper protocol, preserve unexpected-error handling, and include corresponding test assertions.

No open issues 🎉

What changed in this PR

This PR fixes Docker credential-helper responses so missing credentials do not prevent anonymous pulls from public Cloudsmith registries.

Changes:

  • Return Docker’s exact protocol messages for missing credentials and blank server URLs.
  • Update protocol tests to assert the new stdout responses.
  • Document the behavior change while retaining stderr guidance and exit codes.
File Description
cloudsmith_cli/​credential_helpers/​docker/​runtime.py Add protocol error strings and type hints for _execute_get.
cloudsmith_cli/​cli/​tests/​commands/​test_credential_helper.py Update assertions for missing credentials and whitespace-only input.
CHANGELOG.md Describe anonymous-pull support and private-repository failure behavior.

Review effort: Balanced

cloudsmith-iduffy and others added 2 commits October 28, 2026 12:01
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* origin/master: (25 commits)
  fix(ENG-15484): accept --color on click versions before 8.2 (#582)
  fix(no-ticket): stop retrying unknown hosts and show backoff retries (#542)
  fix(no-ticket): stop credential helpers from overwriting config files that do not parse (#540)
  fix(no-ticket): remove the pnpm launcher when .npmrc does not exist (#539)
  fix(no-ticket): keep the user's Cargo registry credential provider (#532)
  build(deps): bump pyasn1 (#580)
  build(deps): bump the actions-all group with 4 updates (#577)
  build(deps): bump the uv-all group with 7 updates (#578)
  build(deps): bump alpine from `294b683` to `be26560` (#576)
  fix(no-ticket): keep credentials.ini sections and save missing API keys (#533)
  fix(no-ticket): set a default timeout on each API request (#538)
  fix(no-ticket): print the result count when a list is empty (#545)
  fix(no-ticket): escape the args in the terraformrc block (#543)
  fix(no-ticket): show the dependencies help for list deps (#546)
  fix(no-ticket): show a correct summary for the pnpm credential helper (#547)
  fix(no-ticket): show a clean error when the SAML IdP response is not a JSON object (#559)
  fix(no-ticket): show the API error when mcp cannot load the API schema (#561)
  fix(no-ticket): treat an empty trailing OWNER/REPO part as not given (#550)
  fix(no-ticket): print a skipped API error one time in copy, move and resync (#552)
  fix(no-ticket): save credentials.ini with mode 0600 (#553)
  ...

# Conflicts:
#	CHANGELOG.md

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Approval recommended

No active review issues were identified for the Docker credential-helper protocol error update.

No open issues 🎉

Review effort: Balanced

…elper-not-found

# Conflicts:
#	CHANGELOG.md

Co-authored-by: cloudsmith-iduffy <178375997+cloudsmith-iduffy@users.noreply.github.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

breaking change Changes behaviour that scripts or users can depend on

Development

Successfully merging this pull request may close these issues.

3 participants