Skip to content

fix(registry): derive bearer service from realm - #1895

Merged
nicholas-fedor merged 7 commits into
nicholas-fedor:mainfrom
llc1123:fix/gcp-artifact-registry-auth
Jul 15, 2026
Merged

fix(registry): derive bearer service from realm#1895
nicholas-fedor merged 7 commits into
nicholas-fedor:mainfrom
llc1123:fix/gcp-artifact-registry-auth

Conversation

@llc1123

@llc1123 llc1123 commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Summary

  • derive missing Bearer service values from the challenge realm host
  • keep existing scope derivation for registry challenges that omit scope
  • add regression coverage for GCP Artifact Registry's realm-only /v2/ challenge

Fixes #1894

Testing

  • go test ./pkg/registry/... -count=1
  • go test ./... -count=1
  • go test -race ./pkg/registry/... -count=1

Summary by CodeRabbit

  • Bug Fixes

    • Improved registry Bearer authentication by normalizing the image name and deriving missing service from the realm, ensuring correct /token exchanges and more reliable auth URL generation.
    • Strengthened validation of Bearer WWW-Authenticate challenges, rejecting malformed or incomplete headers more consistently (including cases with missing scheme or unusable realm/service).
  • Tests

    • Added and expanded coverage for Bearer challenges that omit service, asserting correct query parameter derivation and successful token retrieval behavior.
    • Updated error/invalid-challenge scenarios to confirm proper failures and no redirect.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Registry authentication now derives service from a Bearer challenge’s realm host when omitted, constructs the auth URL before bearer-token retrieval, and validates realm-only challenges with token and URL tests.

Changes

Registry auth service derivation

Layer / File(s) Summary
ProcessChallenge derives service from realm
pkg/registry/auth/auth.go, pkg/registry/auth/auth_test.go
ProcessChallenge derives service from realm when omitted and rejects challenges when required values remain unavailable; token tests verify the derived service and scope.
Bearer request flow uses normalized image name
pkg/registry/auth/auth.go
handleBearerAuth constructs the auth URL first, sets challengeHost from its host, and passes the normalized image name through bearer-token helpers.
GetAuthURL derives service from realm
pkg/registry/auth/auth_test.go, pkg/registry/auth/auth.go
GetAuthURL derives service before validation and URL construction; tests cover malformed and realm-only challenges.

Sequence Diagram(s)

sequenceDiagram
  participant GetToken
  participant ProcessChallenge
  participant GetAuthURL
  participant Registry

  GetToken->>Registry: GET /v2/
  Registry-->>GetToken: Bearer challenge with realm only
  GetToken->>ProcessChallenge: parse challenge values
  ProcessChallenge->>ProcessChallenge: derive service from realm host
  ProcessChallenge-->>GetToken: challenge values
  GetToken->>GetAuthURL: build auth URL
  GetAuthURL-->>GetToken: auth URL with derived service
  GetToken->>Registry: GET /token with service and scope
  Registry-->>GetToken: bearer token
  GetToken-->>GetToken: return token
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely matches the main change: deriving bearer service from the realm.
Linked Issues check ✅ Passed The PR addresses #1894 by deriving the missing Bearer service from the realm host and keeping scope derivation intact.
Out of Scope Changes check ✅ Passed The code and tests stay focused on bearer challenge parsing and auth URL/token construction, with no obvious unrelated changes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codacy-production

codacy-production Bot commented Jul 6, 2026

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 25 duplication

Metric Results
Duplication 25

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

@coderabbitai coderabbitai Bot 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.

🧹 Nitpick comments (1)
pkg/registry/auth/auth.go (1)

528-538: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value

Avoid re-parsing the challenge
ProcessChallenge’s derived service never reaches GetBearerHeader; GetAuthURL parses the raw challenge again, so this path keeps two service derivations in sync. Reuse the parsed values instead of recomputing them.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/registry/auth/auth.go` around lines 528 - 538, ProcessChallenge currently
derives service from realm, but GetAuthURL re-parses the raw challenge and
recomputes the same values, so the derived result never gets reused. Update the
auth flow around ProcessChallenge and GetAuthURL so the parsed challenge values
(realm/service/scope) are passed through and reused instead of parsing the
challenge twice, keeping the service derivation in one place.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@pkg/registry/auth/auth.go`:
- Around line 528-538: ProcessChallenge currently derives service from realm,
but GetAuthURL re-parses the raw challenge and recomputes the same values, so
the derived result never gets reused. Update the auth flow around
ProcessChallenge and GetAuthURL so the parsed challenge values
(realm/service/scope) are passed through and reused instead of parsing the
challenge twice, keeping the service derivation in one place.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 13f09301-8f71-40cd-965a-86e616ea3f01

📥 Commits

Reviewing files that changed from the base of the PR and between 9829937 and 8122325.

📒 Files selected for processing (2)
  • pkg/registry/auth/auth.go
  • pkg/registry/auth/auth_test.go

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

@coderabbitai coderabbitai Bot 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.

🧹 Nitpick comments (1)
pkg/registry/auth/auth.go (1)

276-280: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Misleading error classification for auth-URL construction failure.

A failure from GetAuthURL is a challenge/URL construction problem, but it is wrapped with errFailedDecodeResponse. Consider errInvalidChallengeHeader (Line 58) or a dedicated construction error so operators get an accurate cause.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/registry/auth/auth.go` around lines 276 - 280, The failure path in
GetAuthURL is using the wrong error classification: when bearer auth URL
construction fails, it should not be wrapped with errFailedDecodeResponse.
Update the return in the GetAuthURL error branch to use
errInvalidChallengeHeader or a dedicated auth-URL construction error so the
wrapped cause matches the actual failure, and keep the existing debug log with
logrus.WithError and fields.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@pkg/registry/auth/auth.go`:
- Around line 276-280: The failure path in GetAuthURL is using the wrong error
classification: when bearer auth URL construction fails, it should not be
wrapped with errFailedDecodeResponse. Update the return in the GetAuthURL error
branch to use errInvalidChallengeHeader or a dedicated auth-URL construction
error so the wrapped cause matches the actual failure, and keep the existing
debug log with logrus.WithError and fields.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5865093e-7014-4c3b-8ea3-ad2b6df50efa

📥 Commits

Reviewing files that changed from the base of the PR and between 8122325 and 40a4b6c.

📒 Files selected for processing (1)
  • pkg/registry/auth/auth.go

llc1123 and others added 2 commits July 6, 2026 18:25
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
@codecov

codecov Bot commented Jul 14, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 87.87879% with 8 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
pkg/registry/auth/auth.go 87.87% 6 Missing and 2 partials ⚠️

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #1895      +/-   ##
==========================================
+ Coverage   74.80%   75.95%   +1.14%     
==========================================
  Files          61       90      +29     
  Lines       10415    11722    +1307     
==========================================
+ Hits         7791     8903    +1112     
- Misses       2339     2479     +140     
- Partials      285      340      +55     
Files with missing lines Coverage Δ
pkg/registry/auth/auth.go 81.45% <87.87%> (+1.77%) ⬆️

... and 53 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

- Group errFailedConstructBearerAuthURL with related bearer token errors
- Fix formatting in ProcessChallenge, addBasicAuth, and auth_test.go
- Test deriving service from realm when service field is empty
- Test deriving service from realm host with port and trailing slash
- Test error handling for realm without scheme and missing service

@coderabbitai coderabbitai Bot 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.

🧹 Nitpick comments (1)
pkg/registry/auth/auth_test.go (1)

1030-1031: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider restoring the original value of WATCHTOWER_REGISTRY_TLS_SKIP.

The current implementation sets the config value to false and then uses defer to redundantly set it to false again, rather than restoring its original value. To ensure no side effects leak into other test suites, consider capturing and restoring the initial value.

♻️ Proposed refactor
-			viper.Set("WATCHTOWER_REGISTRY_TLS_SKIP", false)
-			defer viper.Set("WATCHTOWER_REGISTRY_TLS_SKIP", false)
+			originalTLSSkip := viper.GetBool("WATCHTOWER_REGISTRY_TLS_SKIP")
+			viper.Set("WATCHTOWER_REGISTRY_TLS_SKIP", false)
+			defer viper.Set("WATCHTOWER_REGISTRY_TLS_SKIP", originalTLSSkip)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/registry/auth/auth_test.go` around lines 1030 - 1031, Update the test
setup around WATCHTOWER_REGISTRY_TLS_SKIP to capture its original value before
setting it to false, then defer restoring that captured value instead of
assigning false again. Keep the test’s false configuration while preserving the
surrounding suite’s prior state.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@pkg/registry/auth/auth_test.go`:
- Around line 1030-1031: Update the test setup around
WATCHTOWER_REGISTRY_TLS_SKIP to capture its original value before setting it to
false, then defer restoring that captured value instead of assigning false
again. Keep the test’s false configuration while preserving the surrounding
suite’s prior state.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d6aa334d-c0e0-403d-bccd-5e6d9286f2e7

📥 Commits

Reviewing files that changed from the base of the PR and between d634704 and 56df7b7.

📒 Files selected for processing (1)
  • pkg/registry/auth/auth_test.go

@nicholas-fedor

Copy link
Copy Markdown
Owner

@llc1123 Thank you for submitting this PR. Sorry for holding off on getting to this while working through the API refactor.

I added a few more tests and a few minor stylistic changes.
Otherwise, it looks good to me.

@nicholas-fedor
nicholas-fedor merged commit 528c332 into nicholas-fedor:main Jul 15, 2026
14 of 15 checks passed
@llc1123
llc1123 deleted the fix/gcp-artifact-registry-auth branch July 20, 2026 10:31
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.

GCP Artifact Registry auth fails when /v2/ challenge omits service

2 participants