feat(docker): Add support for multiple registries#657
Conversation
Extend the Docker target to support publishing to multiple container registries (Docker Hub, GHCR, GCR, etc.) with per-registry credentials. Key changes: - Auto-detect registry from target image path (e.g., ghcr.io/user/image) - Per-registry credentials via DOCKER_<REGISTRY>_USERNAME/PASSWORD env vars - Built-in GHCR defaults using GITHUB_ACTOR/GITHUB_TOKEN for zero-config in GitHub Actions - Optional registry config override to share credentials across regions - Optional usernameVar/passwordVar for explicit env var names (no fallback) - Use --password-stdin for secure password handling Closes #591
Recognize docker.io, index.docker.io, and registry-1.docker.io as Docker Hub aliases that should use default DOCKER_USERNAME/PASSWORD credentials instead of looking for DOCKER_DOCKER_IO_* env vars.
…ublishing When source and target registries differ, credentials can now be resolved independently for each registry. This enables cross-registry publishing (e.g., pulling from private GHCR and pushing to Docker Hub). - Source credentials use registry-specific env vars (no default fallback) - Add sourceRegistry, sourceUsernameVar, sourcePasswordVar config options - Login to both registries when source credentials are available - If source credentials are not found, assume source is public
fe9004d to
56969b7
Compare
56969b7 to
0b62470
Compare
| // Object form - prefer object properties over legacy, but allow legacy as fallback | ||
| return { | ||
| image: ref.image, | ||
| format: ref.format ?? legacyFormat, | ||
| registry: ref.registry ?? legacyRegistry, | ||
| usernameVar: ref.usernameVar ?? legacyUsernameVar, | ||
| passwordVar: ref.passwordVar ?? legacyPasswordVar, | ||
| skipLogin: ref.skipLogin ?? legacySkipLogin, | ||
| }; | ||
| } |
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
Allow source and target to be specified as either a string (image path) or an object with additional options (image, registry, format, usernameVar, passwordVar). This provides a cleaner API that groups related configuration. - Add ImageRefConfig and ImageRef types - Add normalizeImageRef() for backwards compatibility with legacy flat config - Update getDockerConfig() to use normalized config - Support both new nested format and legacy flat format - Add comprehensive tests for new format (12 new tests) - Update README with new configuration documentation
0b62470 to
0faa5a4
Compare
Throws a clear ConfigurationError if source or target is missing from the Docker target configuration, instead of crashing with an unhelpful TypeError: Cannot read property 'image' of undefined.
hubertdeng123
left a comment
There was a problem hiding this comment.
one more comment, hope this doesn't break anything 🤞
…t-ins - Use node:fs, node:os, node:path instead of fs, os, path - Use specific named imports (existsSync, homedir, join) instead of namespace imports
| const GCR_REGISTRY_PATTERNS = [ | ||
| /^gcr\.io$/, | ||
| /^[a-z]+-gcr\.io$/, // us-gcr.io, eu-gcr.io, asia-gcr.io, etc. | ||
| /^[a-z]+\.gcr\.io$/, // us.gcr.io, eu.gcr.io, asia.gcr.io, etc. | ||
| /^[a-z]+-docker\.pkg\.dev$/, // us-docker.pkg.dev, europe-docker.pkg.dev, etc. | ||
| ]; |
There was a problem hiding this comment.
Bug: The regex for Google Artifact Registry hostnames is too strict and doesn't account for numbers in region names, causing authentication failures for valid regional endpoints.
Severity: CRITICAL | Confidence: High
🔍 Detailed Analysis
The regular expression used to identify Google Cloud Registry (GCR) hosts is incorrect. The pattern /^[a-z]+-docker\.pkg\.dev$/ in isGoogleCloudRegistry only matches lowercase letters for the region, but valid Google Artifact Registry regions can contain numbers (e.g., us-west1). As a result, when a user specifies a valid regional endpoint like us-west1-docker.pkg.dev, the function returns false. This causes the application to incorrectly demand explicit DOCKER_..._USERNAME/PASSWORD credentials instead of using the available gcloud authentication, breaking the expected zero-configuration workflow.
💡 Suggested Fix
Update the regular expression on line 32 of src/targets/docker.ts to allow for numeric digits in the region part of the hostname. Change /^[a-z]+-docker\.pkg\.dev$/ to /^[a-z0-9-]+-docker\.pkg\.dev$/ to correctly match regional endpoints like us-west1-docker.pkg.dev.
🤖 Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.
Location: src/targets/docker.ts#L27-L32
Potential issue: The regular expression used to identify Google Cloud Registry (GCR)
hosts is incorrect. The pattern `/^[a-z]+-docker\.pkg\.dev$/` in `isGoogleCloudRegistry`
only matches lowercase letters for the region, but valid Google Artifact Registry
regions can contain numbers (e.g., `us-west1`). As a result, when a user specifies a
valid regional endpoint like `us-west1-docker.pkg.dev`, the function returns `false`.
This causes the application to incorrectly demand explicit
`DOCKER_..._USERNAME`/`PASSWORD` credentials instead of using the available `gcloud`
authentication, breaking the expected zero-configuration workflow.
Did we get this right? 👍 / 👎 to inform future reviews.
Reference ID: 7465936
|
@BYK do you have any plans to cut a release for this one? |
Summary
Extend the Docker target to support publishing to multiple container registries (Docker Hub, GHCR, GCR, etc.) with per-registry credentials, including cross-registry publishing from private sources.
Key Changes
Multi-Registry Support
ghcr.io/user/image→ghcr.io)DOCKER_<REGISTRY>_USERNAME/PASSWORDenv varsGITHUB_ACTOR/GITHUB_TOKENfor zero-config in GitHub Actionsdocker.io,index.docker.io,registry-1.docker.ioas Docker Hub aliasesCross-Registry Publishing
New Nested Object Config Format
Both
sourceandtargetnow support string or object format:Security Improvements
--password-stdinExample Configurations
Cross-registry publishing:
Multi-registry publishing:
Closes #591