Repository navigation
Skip registering credentials for anonymous registries for egress allowlist - #303
Merged
Merged
Conversation
There was a problem hiding this comment.
🟡 Changes recommended
NuGet colon-token credentials remain authenticated, while colon-valued non-token secrets are incorrectly classified as anonymous.
1 open finding
What changed in this PR
Adds anonymous private-registry support while retaining dynamic egress allowlisting.
Changes:
- Skips static authentication registration for anonymous credentials across six handlers.
- Adds shared anonymous-credential classification.
- Adds authentication and exact-host allowlist regression tests.
| File | Description |
|---|---|
internal/handlers/credentials.go |
Adds anonymous credential detection. |
internal/handlers/npm_registry.go |
Skips anonymous npm credentials. |
internal/handlers/composer.go |
Skips anonymous Composer credentials. |
internal/handlers/helm_registry.go |
Skips anonymous Helm credentials. |
internal/handlers/docker_registry.go |
Skips anonymous Docker credentials. |
internal/handlers/python_index.go |
Skips anonymous Python credentials. |
internal/handlers/rubygems_server.go |
Skips anonymous RubyGems credentials. |
internal/handlers/anonymous_credentials_test.go |
Tests anonymous and authenticated behavior. |
internal/handlers/egress_allowlist_test.go |
Tests dynamic exact-host allowlisting. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
v-sachin-sandhu
approved these changes
Oct 7, 2026
5 tasks done
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

What are you trying to accomplish?
The egress allowlist builds its per-job allowlist from the job's credentials (
credentialHostsinegress_dynamic_hosts.go), so a private registry that needs no authentication has no way onto the allowlist and every request to it is rejected with403 * egress not allowlisted <host>.Supporting an anonymous registry means the credential must still be present in the job config, since that is the only route to a dynamic allowlist entry. But once present, the static-credential handlers attach an empty
Authorizationheader —Bearerwith no value, orBasic base64(":")— which Nexus and Artifactory reject outright instead of serving anonymously. The customer would simply trade a 403 from the proxy for a 401 from their registry.This change makes the proxy recognise a credential that names a registry but carries nothing to authenticate with, and skip registering it. The request is forwarded untouched, while the host stays allowlisted.
Anything you want to highlight for special attention from reviewers?
Only six handlers needed changing.
maven_repository,goproxy_server,cargo_registry,terraform_registry,pub_repository,hex_organization,hex_repository, andnuget_feedalready skip credential-free entries. The six that didn't arenpm_registry,composer,helm_registry,docker_registry,python_index, andrubygems_server.A username with no password is deliberately not anonymous. That's a misconfiguration rather than a declared anonymous registry, and treating it as anonymous would silently discard an intended credential.
usernameis therefore included incredentialSecretKeys, and there's a test pinning this.token: ":"is treated as absent. That's what dependabot-api'stoken_from_token_or_username_and_passwordemits when neither username nor password is set, and it decodes to an empty username and password. This incidentally fixes the existing latent bug for URL-only pip, Maven, and NuGet entries, whichdependabot-apialready accepts today.Placement is after OIDC registration in every constructor, matching the existing skip guards, so a credential that mints its token at request time is never mistaken for an anonymous one.
ECR is unaffected — it passes its AWS key pair through
username/password, so those credentials are never anonymous. An ECR entry configured with neither was already broken before this change, since the SDK is handed empty static credentials.The existing
proxy-onlyguards are left in place; the new check is purely additive, so noproxy-onlypath changes behaviour.How will you know you've accomplished your goal?
TestAnonymousCredentialsAreNotAuthenticatedcovers all six handlers, asserting noAuthorizationheader is added at all. Verified it's meaningful: commenting out the skip innpm_registry.gofails the npm subtest withRequest's auth header should be empty.TestEgressAllowlist_AnonymousCredentialAllowlistsHostproves the other half — a credential carrying only a registry location still contributes its host to the allowlist, acrossnpm_registry,docker_registry,python_index,maven_repository, andnuget_feed.TestEgressAllowlist_AnonymousCredentialDoesNotWidenBeyondExactHostholds the dynamic-host exact-match invariant, with theevil.<host>child probe this repository requires plus a sibling probe and a suffix-appending lookalike.TestAnonymousCredentialsStillAuthenticateWhenSecretPresentguards against the skip being too eager, andTestCredentialIsAnonymouspins the classification itself, including both empty-secret shapes and the username-only case.End-to-end validation against a real anonymous-read Nexus with
proxy-egress-enforceenabled is still pending; it cannot be covered by unit tests.Checklist