Skip to content

feat(bootstrap): fall back to anonymous pull when registry credentials are rejected#351

Closed
drew wants to merge 1 commit intomainfrom
auth-fallback
Closed

feat(bootstrap): fall back to anonymous pull when registry credentials are rejected#351
drew wants to merge 1 commit intomainfrom
auth-fallback

Conversation

@drew
Copy link
Collaborator

@drew drew commented Mar 16, 2026

Summary

When pulling container images from ghcr.io, credentials are always sent. If the token lacks access to a specific repo (e.g., a public repo the caller's PAT cannot read), the pull fails with 401/403 even though an unauthenticated pull would succeed. This PR adds fallback-to-anonymous logic across all three image pull paths.

Changes

  • crates/openshell-bootstrap/src/image.rs: Added is_auth_failure() helper that detects auth errors by HTTP status (401/403) and message patterns. Added consume_pull_stream() helper for reusable stream consumption. Modified pull_remote_image() to retry anonymously on auth failure. Added 6 unit tests.
  • crates/openshell-bootstrap/src/docker.rs: Modified ensure_image() to detect auth failure mid-stream, break out, and retry with None credentials.
  • deploy/docker/cluster-entrypoint.sh: Added test_registry_credentials() shell function that validates credentials against the GHCR token endpoint via curl before writing auth config to registries.yaml. Skips auth block when credentials are rejected so containerd falls back to anonymous pulls.
  • deploy/docker/Dockerfile.cluster: Added curl to runtime stage dependencies for the credential validation test.
  • crates/openshell-bootstrap/src/errors.rs: Updated diagnose_image_pull_auth_failure to mention that anonymous fallback was also attempted.

Testing

  • mise run pre-commit passes
  • Unit tests added/updated (6 new is_auth_failure tests)
  • E2E tests added/updated (manual testing needed: deploy with invalid token against public GHCR image)

Checklist

  • Follows Conventional Commits
  • Commits are signed off (DCO)
  • Architecture docs updated (if applicable)

…s are rejected

When pulling container images from ghcr.io, credentials are always
sent. If the token lacks access to a specific repo (e.g., a public
repo the caller's PAT cannot read), the pull fails with a 401/403
even though an unauthenticated pull would succeed.

Add fallback logic across all three pull paths:

- ensure_image() (local Docker daemon): detect auth failure from the
  pull stream and retry with no credentials.
- pull_remote_image() (remote SSH daemon): same pattern using the new
  consume_pull_stream() helper.
- cluster-entrypoint.sh (k3s/containerd): validate credentials via
  the GHCR token endpoint before writing auth config to
  registries.yaml; skip auth block when credentials are rejected so
  containerd uses anonymous pulls.

Also adds is_auth_failure() helper that matches 401/403 status codes
and common Docker error messages (pull access denied, unauthorized,
denied: access forbidden), curl to the cluster runtime image for the
credential test, and updated error diagnosis messaging.
@drew drew self-assigned this Mar 16, 2026
@drew drew closed this Mar 16, 2026
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.

1 participant