Skip to content

support path-scoped registry credentials#1109

Open
tdewanNvidia wants to merge 3 commits into
mainfrom
tdewan/path-scoped-registry-credentials
Open

support path-scoped registry credentials#1109
tdewanNvidia wants to merge 3 commits into
mainfrom
tdewan/path-scoped-registry-credentials

Conversation

@tdewanNvidia

@tdewanNvidia tdewanNvidia commented Jun 16, 2026

Copy link
Copy Markdown
Collaborator

Description

OSMO previously resolved Docker registry credentials using only the registry hostname. This prevented users from configuring separate credentials for different repository paths under the same registry host.

Issue #1113

This PR adds path-scoped registry credential support and aligns OSMO more closely with Kubernetes docker config matching behavior.

What Changed

  • Preserve path-scoped registry profiles when credentials are created.
  • Add shared registry-scope matching helpers.
    • Match by path segment, not raw string prefix.
    • Prefer more specific scopes first.
    • Include non-default registry ports in scope matching.
    • Canonicalize the default HTTPS port so equivalent scopes match.
  • Update workflow image validation to try all matching registry credentials.
  • Update generated Kubernetes dockerconfigjson image pull secrets to include all matching auth entries.
  • Update CLI/UI text to clarify that registry credentials may target either a registry host or a registry path.
  • Normalize bulk registry credential lookup keys and decrypt only credentials that match the image scope.

Matching Behavior

For an image like:

<registry-host>/team-b/service/client

These credential scopes match:

  • <registry-host>/team-b
  • <registry-host>

These credential scopes do not match:

  • <registry-host>/team-a
  • <registry-host>/team-b/subpath

The generated docker config includes all matching credentials, ordered most-specific first.

Testing

Bazel Tests

bazel test \
  //src/lib/utils/tests:test_common \
  //src/utils/job/tests:test_task_pure \
  //src/utils/job/tests:test_task \
  //src/utils/job/tests:test_workflow_helpers \
  //src/service/core/workflow/tests:test_helpers \
  //src/cli/tests:test_credential

Result:

Executed 1 out of 6 tests: 6 tests pass.
INFO: Build completed successfully

Manual CLI Validation

Using the Bazel-built CLI, created multiple registry credentials under the same host:

  • one host-level credential
  • one parent path credential
  • one nested child path credential
  • one unrelated sibling path credential

Then verified:

  • credential list output preserved each distinct registry profile
  • an image under the parent path matched the parent path credential and host-level credential
  • the unrelated sibling path credential did not match
  • the nested child path credential did not match images outside that child path

This validates that OSMO now stores path-scoped registry credentials separately and resolves only path-segment-compatible credentials for image validation and image pull secret generation.

Checklist

  • I am familiar with the Contributing Guidelines.
  • New or existing tests cover these changes.
  • The documentation is up to date with these changes.

Summary by CodeRabbit

  • New Features

    • Registry credentials now support path-scoped matching on registry hosts, enabling more precise credential selection for image pulls and validation.
  • Documentation

    • Updated CLI help example for registry credential configuration.
    • Added design documentation for path-scoped registry credentials, including normalization and matching behavior.

@tdewanNvidia tdewanNvidia requested a review from a team as a code owner June 16, 2026 02:01
@coderabbitai

coderabbitai Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 543988e0-baa5-42d8-a6f8-f6a39c25901f

📥 Commits

Reviewing files that changed from the base of the PR and between 5393df0 and c8eeaf4.

📒 Files selected for processing (1)
  • projects/path-scoped-registry-credentials.md
✅ Files skipped from review due to trivial changes (1)
  • projects/path-scoped-registry-credentials.md

📝 Walkthrough

Walkthrough

Registry credential matching is upgraded from host-only lookup to path-scope-based matching. Five new scope utility functions are added to common.py. The PostgreSQL connector gains bulk and filtered credential retrieval methods. UserRegistryCredential.valid_cred, WorkflowSpec.validate_registry, and TaskGroup._get_registry_creds are updated to use scope normalization and matching. A CLI help example text is also corrected.

Changes

Path-scoped registry credential matching

Layer / File(s) Summary
Registry scope utility functions
src/lib/utils/common.py, src/lib/utils/tests/test_common.py, projects/path-scoped-registry-credentials.md
Adds normalize_registry_scope, image_registry_scope, registry_scope_contains, registry_scope_matches_image, and matching_registry_scopes with urlparse import; unit tests cover normalization, path-segment containment, scope ordering, and port-aware matching; design document specifies canonical normalization and segment-aware matching behavior.
PostgreSQL bulk and matching credential retrieval
src/utils/connectors/postgres.py, src/utils/job/tests/test_task_pure.py
Normalizes registry scope in existing get_registry_cred; adds get_all_registry_creds (all user registry creds keyed by scope) and get_matching_registry_creds (filtered by DockerImageInfo); test double and tests cover normalization and matching logic.
UserRegistryCredential scope-based validation
src/service/core/workflow/objects.py, src/service/core/workflow/tests/test_helpers.py
valid_cred() now normalizes registry to a scope, checks disabled registries via registry_scope_contains, derives auth host from the normalized scope; new test verifies registry_auth is called with correct URL.
WorkflowSpec.validate_registry scope-based auth
src/utils/job/workflow.py, src/utils/job/tests/test_workflow_helpers.py
Disabled-registry gate changed from host membership to registry_scope_matches_image; user-credential auth iterates get_matching_registry_creds returning on first success; error context uses image_scope; mock import and two new test cases added.
TaskGroup._get_registry_creds refactor
src/utils/job/task.py, src/utils/job/tests/test_task.py
Replaces per-image-host cached lookup with one get_all_registry_creds call and per-image matching_registry_scopes filtering; credential map keys become normalized scopes; osmo credential scope is normalized; base64 helper and TaskGroupRegistryCredsTest cover three scenarios.

CLI Help Text Fix

Layer / File(s) Summary
REGISTRY credential CLI example
src/cli/credential.py
Changes --payload example value from registry=your_s3_username to registry=your_registry_or_path.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant WorkflowSpec
  participant common
  participant PostgresConnector
  participant RegistryAPI

  Client->>WorkflowSpec: validate_registry(image_info, user, disabled_registries)
  WorkflowSpec->>common: registry_scope_matches_image(disabled_scope, image_info)
  alt any disabled scope matches
    WorkflowSpec-->>Client: return None
  else no match
    WorkflowSpec->>RegistryAPI: registry_auth(url, empty credentials)
    WorkflowSpec->>PostgresConnector: get_matching_registry_creds(user, image_info)
    PostgresConnector->>common: matching_registry_scopes(image_info, all_scopes)
    PostgresConnector-->>WorkflowSpec: [(scope, cred), ...]
    loop each matching credential
      WorkflowSpec->>RegistryAPI: registry_auth(url, username, token)
      alt auth succeeds
        WorkflowSpec-->>Client: return
      end
    end
    WorkflowSpec-->>Client: raise OSMOCredentialError(image_scope)
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

  • Support path-scoped registry credentials #1113 — This PR directly implements path-scoped registry credential matching requested in the issue by adding scope normalization and matching utilities (normalize_registry_scope, registry_scope_matches_image, registry_scope_contains), refactoring credential lookup from hostname-based to scope-based (get_matching_registry_creds, get_all_registry_creds), and updating validation and selection to use path-scoped matching instead of simple hostname comparison.

Poem

🐇 Hoppity-hop through the registry maze,
No longer just hostnames to cloud all our gaze!
With paths and with scopes we now find the right key,
The deepest match wins — most specific, you see.
The rabbit approves: neat scopes, tidy and bright! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 35.71% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly and accurately summarizes the main change: adding support for path-scoped registry credentials, which is the core feature across all modified files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch tdewan/path-scoped-registry-credentials

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

@codecov

codecov Bot commented Jun 16, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 75.40984% with 15 lines in your changes missing coverage. Please review.
✅ Project coverage is 57.50%. Comparing base (022c533) to head (c8eeaf4).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
src/utils/job/task.py 16.66% 4 Missing and 1 partial ⚠️
src/lib/utils/common.py 86.20% 2 Missing and 2 partials ⚠️
src/utils/connectors/postgres.py 84.21% 1 Missing and 2 partials ⚠️
src/utils/job/workflow.py 33.33% 1 Missing and 1 partial ⚠️
src/service/core/workflow/objects.py 75.00% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1109      +/-   ##
==========================================
+ Coverage   57.41%   57.50%   +0.08%     
==========================================
  Files         211      211              
  Lines       26658    26707      +49     
  Branches     4046     4054       +8     
==========================================
+ Hits        15306    15357      +51     
+ Misses      10659    10654       -5     
- Partials      693      696       +3     
Flag Coverage Δ
backend 59.73% <75.40%> (+0.08%) ⬆️
ui 34.73% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
src/cli/credential.py 100.00% <ø> (ø)
src/service/core/workflow/objects.py 58.55% <75.00%> (+0.44%) ⬆️
src/utils/job/workflow.py 60.58% <33.33%> (+0.87%) ⬆️
src/utils/connectors/postgres.py 71.32% <84.21%> (+0.16%) ⬆️
src/lib/utils/common.py 93.98% <86.20%> (-0.35%) ⬇️
src/utils/job/task.py 63.68% <16.66%> (-0.16%) ⬇️

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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

Actionable comments posted: 3

🤖 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.

Inline comments:
In `@src/lib/utils/common.py`:
- Around line 459-465: The normalize_registry_scope() function needs to
canonicalize the default HTTPS port to match the behavior of
image_registry_scope(). After calling registry_parse() on the parsed netloc to
get the registry value, strip the explicit default port 443 (`:443`) from the
registry string before using it in the return statement. This ensures that
equivalent scopes like `registry.example.com:443/org` and
`registry.example.com/org` normalize to the same value and can be properly
matched.

In `@src/utils/connectors/postgres.py`:
- Around line 1562-1566: The bulk registry credential API returns raw
row.profile keys without normalization, causing inconsistency with the
single-item get_registry_cred() function which normalizes lookup keys. In the
dictionary comprehension that returns the registry credentials (in the section
showing row.profile as the key), normalize the row.profile value using the same
normalization logic applied in get_registry_cred() before using it as the
dictionary key. This ensures equivalent scopes behave consistently between
direct and bulk lookups and properly matches path-scoped credentials regardless
of whether persisted profiles are already in canonical form.
- Around line 1574-1579: Refactor this code to filter matching registry scopes
before decrypting credentials rather than decrypting all and filtering. Instead
of calling get_all_registry_creds(user) which decrypts every credential, first
get only the registry credential keys, use common.matching_registry_scopes() to
identify which scopes match the image_info, and then decrypt only those specific
matching credentials. This prevents unrelated bad credentials from failing valid
image auth paths and eliminates unnecessary decryption work.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: f835dd78-05d8-4c80-a9d4-e29a5289da8e

📥 Commits

Reviewing files that changed from the base of the PR and between 022c533 and 4b1699a.

📒 Files selected for processing (10)
  • src/cli/credential.py
  • src/lib/utils/common.py
  • src/lib/utils/tests/test_common.py
  • src/service/core/workflow/objects.py
  • src/service/core/workflow/tests/test_helpers.py
  • src/utils/connectors/postgres.py
  • src/utils/job/task.py
  • src/utils/job/tests/test_task.py
  • src/utils/job/tests/test_workflow_helpers.py
  • src/utils/job/workflow.py

Comment thread src/lib/utils/common.py
Comment thread src/utils/connectors/postgres.py Outdated
Comment thread src/utils/connectors/postgres.py Outdated
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