feat: typed oci credentials and identity (Phase 2)#2360
Conversation
✅ Deploy Preview for ocm-website ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
📝 WalkthroughWalkthroughThis PR implements Phase 1 (Foundation) of typed credentials (ADR 0017) by introducing ChangesTyped Credentials Foundation and Resolution
Sequence DiagramsequenceDiagram
participant T as OCI Transformer<br/>(e.g., GetOCIArtifact)
participant R as resolveCredentialsMap
participant CR as Credential Resolver<br/>(ResolveTyped)
participant S as Runtime Scheme<br/>(Credential Provider)
T->>R: resolveCredentialsMap(ctx, identity)
R->>CR: ResolveTyped(identity)
CR->>S: Lookup typed credential<br/>in config/scheme
S-->>CR: *OCICredentials or<br/>*DirectCredentials
CR-->>R: typed credential
alt OCICredentials
R->>R: Extract Username,<br/>Password, Tokens
R->>R: Build map[string]string
R-->>T: credentials map
else DirectCredentials
R->>R: Clone Properties
R-->>T: properties map
else ErrNotFound
R-->>T: nil, nil<br/>(no error)
else Unsupported Type
R-->>T: nil,<br/>error: "unsupported"
end
T->>T: Use credentials map<br/>in transform operation
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
a7f8b13 to
f956f7f
Compare
f956f7f to
ac7090e
Compare
341efd6 to
606ee13
Compare
a930ef8 to
3ab33dd
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (4)
bindings/go/oci/spec/credentials/identity/v1/oci_registry_identity_test.go (1)
45-48: Also assertTypesurvives round-trip conversion.Line 31 initializes
Type, but the current assertions only verify auxiliary fields. Adding aTypeassertion will catch regressions in typed identity conversion behavior.✅ Suggested test addition
assert.Equal(t, original.Hostname, restored.Hostname) assert.Equal(t, original.Scheme, restored.Scheme) assert.Equal(t, original.Port, restored.Port) assert.Equal(t, original.Path, restored.Path) + assert.Equal(t, original.Type, restored.Type)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@bindings/go/oci/spec/credentials/identity/v1/oci_registry_identity_test.go` around lines 45 - 48, Add an assertion that verifies the identity Type survives round-trip conversion by asserting original.Type equals restored.Type in the same test that already checks Hostname, Scheme, Port, and Path (look for the variables original and restored in oci_registry_identity_test.go); update the assertions block to include assert.Equal(t, original.Type, restored.Type) so regressions in typed identity conversion are caught.bindings/go/oci/transformer/credentials_test.go (1)
42-45: Prefer credential key constants over string literals in assertions.Using
ocicredsv1.CredentialKey*constants here will keep tests resilient to key renames.♻️ Suggested assertion update
- assert.Equal(t, "user", creds["username"]) - assert.Equal(t, "pass", creds["password"]) - assert.Equal(t, "tok", creds["accessToken"]) - assert.Equal(t, "ref", creds["refreshToken"]) + assert.Equal(t, "user", creds[ocicredsv1.CredentialKeyUsername]) + assert.Equal(t, "pass", creds[ocicredsv1.CredentialKeyPassword]) + assert.Equal(t, "tok", creds[ocicredsv1.CredentialKeyAccessToken]) + assert.Equal(t, "ref", creds[ocicredsv1.CredentialKeyRefreshToken])🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@bindings/go/oci/transformer/credentials_test.go` around lines 42 - 45, Replace the string literal keys used in the assertions with the ocicredsv1 credential key constants to make tests robust to renames: change accesses of creds["username"], creds["password"], creds["accessToken"], and creds["refreshToken"] in the test (where the variable creds is asserted) to use ocicredsv1.CredentialKeyUsername, ocicredsv1.CredentialKeyPassword, ocicredsv1.CredentialKeyAccessToken, and ocicredsv1.CredentialKeyRefreshToken respectively so the assert.Equal calls reference the constant keys.bindings/go/oci/spec/credentials/v1/oci_credentials_test.go (1)
104-110: Cover the unversioned alias in the registration test.
MustRegisterCredentialTypeadvertises backward compatibility by registering bothOCICredentials/v1andOCICredentials, but this test only exercises the versioned path. Adding an assertion forruntime.NewUnversionedType(OCICredentialsType)would protect the alias contract from regressing unnoticed.Suggested test addition
func TestMustRegisterCredentialType(t *testing.T) { scheme := runtime.NewScheme() MustRegisterCredentialType(scheme) obj, err := scheme.NewObject(runtime.NewVersionedType(OCICredentialsType, Version)) require.NoError(t, err) assert.IsType(t, &OCICredentials{}, obj) + + obj, err = scheme.NewObject(runtime.NewUnversionedType(OCICredentialsType)) + require.NoError(t, err) + assert.IsType(t, &OCICredentials{}, obj) }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@bindings/go/oci/spec/credentials/v1/oci_credentials_test.go` around lines 104 - 110, The test TestMustRegisterCredentialType only verifies the versioned registration; update it to also exercise the unversioned alias by calling scheme.NewObject(runtime.NewUnversionedType(OCICredentialsType)) after MustRegisterCredentialType and assert no error and that the returned object is of type *OCICredentials; this ensures MustRegisterCredentialType registers both runtime.NewVersionedType(OCICredentialsType, Version) and the unversioned alias.bindings/go/oci/transformer/credentials.go (1)
34-35: Return a copy ofDirectCredentials.Properties.This branch leaks the resolver-owned map as-is. Unlike the
OCICredentialspath, any downstream normalization or augmentation of the returned credentials would mutate the storedDirectCredentialsinstance and affect later resolutions.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@bindings/go/oci/transformer/credentials.go` around lines 34 - 35, The DirectCredentials branch currently returns the resolver-owned map directly (case *credconfigv1.DirectCredentials: return c.Properties, nil), which leaks internal state; modify the branch to return a shallow copy of c.Properties instead (create a new map, copy each key/value from c.Properties into it) so callers can mutate the returned map without affecting the stored DirectCredentials instance — mirror the safe behavior used in the OCICredentials path by returning the cloned map and nil error.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@bindings/go/oci/spec/credentials/v1/oci_credentials.go`:
- Around line 39-52: The schema enum for the OCICredentials.Type field only
lists the versioned value but the scheme registers both the versioned and
unversioned aliases in MustRegisterCredentialType; update the Type field's
annotation (the // +ocm:jsonschema-gen:enum on OCICredentials.Type) to include
the deprecated unversioned name (e.g., add "OCICredentials" alongside
"OCICredentials/v1"), so the generated JSON schema accepts the alias, or
alternatively remove the unversioned registration call in
MustRegisterCredentialType if you intend to forbid the alias—modify either the
OCICredentials struct annotation or the alias registration in
MustRegisterCredentialType accordingly.
---
Nitpick comments:
In `@bindings/go/oci/spec/credentials/identity/v1/oci_registry_identity_test.go`:
- Around line 45-48: Add an assertion that verifies the identity Type survives
round-trip conversion by asserting original.Type equals restored.Type in the
same test that already checks Hostname, Scheme, Port, and Path (look for the
variables original and restored in oci_registry_identity_test.go); update the
assertions block to include assert.Equal(t, original.Type, restored.Type) so
regressions in typed identity conversion are caught.
In `@bindings/go/oci/spec/credentials/v1/oci_credentials_test.go`:
- Around line 104-110: The test TestMustRegisterCredentialType only verifies the
versioned registration; update it to also exercise the unversioned alias by
calling scheme.NewObject(runtime.NewUnversionedType(OCICredentialsType)) after
MustRegisterCredentialType and assert no error and that the returned object is
of type *OCICredentials; this ensures MustRegisterCredentialType registers both
runtime.NewVersionedType(OCICredentialsType, Version) and the unversioned alias.
In `@bindings/go/oci/transformer/credentials_test.go`:
- Around line 42-45: Replace the string literal keys used in the assertions with
the ocicredsv1 credential key constants to make tests robust to renames: change
accesses of creds["username"], creds["password"], creds["accessToken"], and
creds["refreshToken"] in the test (where the variable creds is asserted) to use
ocicredsv1.CredentialKeyUsername, ocicredsv1.CredentialKeyPassword,
ocicredsv1.CredentialKeyAccessToken, and ocicredsv1.CredentialKeyRefreshToken
respectively so the assert.Equal calls reference the constant keys.
In `@bindings/go/oci/transformer/credentials.go`:
- Around line 34-35: The DirectCredentials branch currently returns the
resolver-owned map directly (case *credconfigv1.DirectCredentials: return
c.Properties, nil), which leaks internal state; modify the branch to return a
shallow copy of c.Properties instead (create a new map, copy each key/value from
c.Properties into it) so callers can mutate the returned map without affecting
the stored DirectCredentials instance — mirror the safe behavior used in the
OCICredentials path by returning the cloned map and nil error.
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 59923ba1-c477-49bd-bd88-58515ab944cd
📒 Files selected for processing (24)
bindings/go/oci/credentials/docker_config.gobindings/go/oci/spec/credentials/identity/v1/oci_registry_identity.gobindings/go/oci/spec/credentials/identity/v1/oci_registry_identity_test.gobindings/go/oci/spec/credentials/identity/v1/register.gobindings/go/oci/spec/credentials/identity/v1/schemas/OCIRegistryIdentity.schema.jsonbindings/go/oci/spec/credentials/identity/v1/type.gobindings/go/oci/spec/credentials/identity/v1/zz_generated.deepcopy.gobindings/go/oci/spec/credentials/identity/v1/zz_generated.ocm_jsonschema.gobindings/go/oci/spec/credentials/identity/v1/zz_generated.ocm_type.gobindings/go/oci/spec/credentials/v1/oci_credentials.gobindings/go/oci/spec/credentials/v1/oci_credentials_test.gobindings/go/oci/spec/credentials/v1/schemas/OCICredentials.schema.jsonbindings/go/oci/spec/credentials/v1/zz_generated.deepcopy.gobindings/go/oci/spec/credentials/v1/zz_generated.ocm_jsonschema.gobindings/go/oci/spec/credentials/v1/zz_generated.ocm_type.gobindings/go/oci/transformer/add_component_version.gobindings/go/oci/transformer/add_local_resource.gobindings/go/oci/transformer/add_oci_artifact.gobindings/go/oci/transformer/add_oci_artifact_test.gobindings/go/oci/transformer/credentials.gobindings/go/oci/transformer/credentials_test.gobindings/go/oci/transformer/get_component_version.gobindings/go/oci/transformer/get_local_resource.gobindings/go/oci/transformer/get_oci_artifact.go
Add the deprecated unversioned enum value (OCICredentials) to the Type field annotation to match the alias registration in MustRegisterCredentialType. This ensures the generated JSON schema accepts the unversioned alias, which is already supported by the runtime scheme. Addresses CodeRabbit comment: open-component-model#2360 (comment)
On-behalf-of: SAP <matthias.bruns@sap.com> Signed-off-by: Matthias Bruns <git@matthiasbruns.com> # Conflicts: # bindings/go/credentials/go.sum # Conflicts: # bindings/go/credentials/graph.go # bindings/go/credentials/ingest.go # bindings/go/credentials/ingest_test.go # bindings/go/credentials/interface.go # bindings/go/credentials/resolve_direct.go # bindings/go/credentials/resolve_indirect.go # bindings/go/credentials/resolve_static.go # bindings/go/credentials/spec/config/v1/config.go # bindings/go/credentials/type_registry.go
On-behalf-of: SAP <matthias.bruns@sap.com> Signed-off-by: Matthias Bruns <git@matthiasbruns.com>
On-behalf-of: SAP <matthias.bruns@sap.com> Signed-off-by: Matthias Bruns <git@matthiasbruns.com>
On-behalf-of: SAP <matthias.bruns@sap.com> Signed-off-by: Matthias Bruns <git@matthiasbruns.com> # Conflicts: # bindings/go/runtime/registry.go # bindings/go/runtime/registry_test.go
On-behalf-of: SAP <matthias.bruns@sap.com> Signed-off-by: Matthias Bruns <git@matthiasbruns.com>
On-behalf-of: SAP <matthias.bruns@sap.com> Signed-off-by: Matthias Bruns <git@matthiasbruns.com>
On-behalf-of: SAP <matthias.bruns@sap.com> Signed-off-by: Matthias Bruns <git@matthiasbruns.com>
On-behalf-of: SAP <matthias.bruns@sap.com> Signed-off-by: Matthias Bruns <git@matthiasbruns.com>
On-behalf-of: SAP <matthias.bruns@sap.com> Signed-off-by: Matthias Bruns <git@matthiasbruns.com>
On-behalf-of: SAP <matthias.bruns@sap.com> Signed-off-by: Matthias Bruns <git@matthiasbruns.com> # Conflicts: # bindings/go/oci/transformer/add_component_version.go # bindings/go/oci/transformer/add_local_resource.go # bindings/go/oci/transformer/add_oci_artifact.go # bindings/go/oci/transformer/add_oci_artifact_test.go # bindings/go/oci/transformer/get_component_version.go # bindings/go/oci/transformer/get_local_resource.go # bindings/go/oci/transformer/get_oci_artifact.go
On-behalf-of: SAP <matthias.bruns@sap.com> Signed-off-by: Matthias Bruns <git@matthiasbruns.com>
On-behalf-of: SAP <matthias.bruns@sap.com> Signed-off-by: Matthias Bruns <git@matthiasbruns.com>
On-behalf-of: SAP <matthias.bruns@sap.com> Signed-off-by: Matthias Bruns <git@matthiasbruns.com>
On-behalf-of: SAP <matthias.bruns@sap.com> Signed-off-by: Matthias Bruns <git@matthiasbruns.com>
On-behalf-of: SAP <matthias.bruns@sap.com> Signed-off-by: Matthias Bruns <git@matthiasbruns.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
bindings/go/oci/transformer/credentials_test.go (1)
48-64: 💤 Low valueConsider adding a test for all-empty
OCICredentials.The implementation returns
nil, nilwhen all fields are empty (viaif len(result) == 0). This edge case isn't explicitly covered. Optional addition:func TestResolveCredentialsMap_OCICredentials_AllEmpty(t *testing.T) { resolver := &stubResolver{ typed: &ocicredsv1.OCICredentials{}, } creds, err := resolveCredentialsMap(t.Context(), resolver, runtime.Identity{"type": "OCIRegistry"}) require.NoError(t, err) assert.Nil(t, creds, "all-empty credentials should return nil map") }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@bindings/go/oci/transformer/credentials_test.go` around lines 48 - 64, Add a unit test that verifies resolveCredentialsMap returns nil (not an empty map) when OCICredentials has all empty fields: create a stubResolver with typed equal to &ocicredsv1.OCICredentials{} and call resolveCredentialsMap(t.Context(), resolver, runtime.Identity{"type":"OCIRegistry"}); assert no error and assert.Nil on the returned creds. Name the test e.g. TestResolveCredentialsMap_OCICredentials_AllEmpty and keep it alongside the existing TestResolveCredentialsMap_OCICredentials_SkipsEmptyFields.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@bindings/go/oci/spec/identity/v1/register.go`:
- Around line 6-11: MustRegisterIdentityType is only used in tests and not
invoked during normal startup, so production schemes won't know
OCIRegistryIdentity; either add an init() that calls
MustRegisterIdentityType(scheme) on the global/runtime scheme used by the app,
or register the type during the package's initialization path used for other
bindings (similar to the credentials package). Locate the global/runtime scheme
initialization (or the package init functions that auto-register other types)
and call MustRegisterIdentityType there (or replace it by an init() in the same
package that registers &OCIRegistryIdentity{} with VersionedType and Type
aliases) so runtime resolution succeeds without test-only invocation.
---
Nitpick comments:
In `@bindings/go/oci/transformer/credentials_test.go`:
- Around line 48-64: Add a unit test that verifies resolveCredentialsMap returns
nil (not an empty map) when OCICredentials has all empty fields: create a
stubResolver with typed equal to &ocicredsv1.OCICredentials{} and call
resolveCredentialsMap(t.Context(), resolver,
runtime.Identity{"type":"OCIRegistry"}); assert no error and assert.Nil on the
returned creds. Name the test e.g.
TestResolveCredentialsMap_OCICredentials_AllEmpty and keep it alongside the
existing TestResolveCredentialsMap_OCICredentials_SkipsEmptyFields.
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: f7520074-0f81-4ed6-b8bf-2fd37df5bb93
📒 Files selected for processing (16)
bindings/go/oci/repository/provider/provider.gobindings/go/oci/repository/resource/resource_repository.gobindings/go/oci/spec/credentials/v1/oci_credentials.gobindings/go/oci/spec/credentials/v1/oci_credentials_test.gobindings/go/oci/spec/identity/v1/oci_registry_identity.gobindings/go/oci/spec/identity/v1/oci_registry_identity_test.gobindings/go/oci/spec/identity/v1/register.gobindings/go/oci/spec/identity/v1/schemas/OCIRegistryIdentity.schema.jsonbindings/go/oci/spec/identity/v1/type.gobindings/go/oci/spec/identity/v1/type_test.gobindings/go/oci/spec/identity/v1/zz_generated.deepcopy.gobindings/go/oci/spec/identity/v1/zz_generated.ocm_jsonschema.gobindings/go/oci/spec/identity/v1/zz_generated.ocm_type.gobindings/go/oci/transformer/add_oci_artifact_test.gobindings/go/oci/transformer/credentials.gobindings/go/oci/transformer/credentials_test.go
✅ Files skipped from review due to trivial changes (6)
- bindings/go/oci/spec/identity/v1/schemas/OCIRegistryIdentity.schema.json
- bindings/go/oci/spec/identity/v1/oci_registry_identity_test.go
- bindings/go/oci/spec/identity/v1/zz_generated.ocm_jsonschema.go
- bindings/go/oci/spec/identity/v1/zz_generated.ocm_type.go
- bindings/go/oci/spec/identity/v1/zz_generated.deepcopy.go
- bindings/go/oci/spec/credentials/v1/oci_credentials_test.go
🚧 Files skipped from review as they are similar to previous changes (2)
- bindings/go/oci/transformer/credentials.go
- bindings/go/oci/spec/credentials/v1/oci_credentials.go
…del#2360) <!-- markdownlint-disable MD041 --> #### What this PR does / why we need it **Phase 2** typed oci bindings [ADR](https://github.com/open-component-model/open-component-model/blob/main/docs/adr/0018_typed_credentials.md) #### Which issue(s) this PR fixes Contributes: open-component-model/ocm-project#986 You can see the whole picture in open-component-model#2148 #### Testing ##### How to test the changes Unit & integration tests only. I ran `task init/go.work` with the updated `credentials` binding to see if the update breaks ocm - it does not :) ##### Verification - [x] I have added/updated tests for my changes (see [Test Requirements](../CONTRIBUTING.md#test-requirements)) - [x] Tests pass locally (`task test` and `task test/integration` if applicable) - [x] My changes do not decrease test coverage --------- Signed-off-by: Matthias Bruns <git@matthiasbruns.com> Co-authored-by: DevBot <devbot@openclaw.ai> 26020bb
On-behalf-of: SAP <matthias.bruns@sap.com> <!-- markdownlint-disable MD041 --> #### What this PR does / why we need it Follow up of #2360 after rolling back identity to `runtime.Identity` - Updates internal `identity` usage to `OCIRegistryIdentity` where sensible. - Updates internal credential usage nearly everywhere, if it would not just lead to a map->typed->map conversion chain #### Which issue(s) this PR fixes Contributes: open-component-model/ocm-project#986 #### Breaking changes - `bindings/go/oci/credentials/docker_config.go` `CredentialFunc` now accepts typed identity and credentials (this shouldn't be exposed in the first place imho) - reverting ResolveTyped to use `runtime.Identity` #### Testing ##### How to test the changes I ran `task init/go.work` with the updated `credentials` binding to see if the update breaks ocm - it does not :) ##### Verification - [x] I have added/updated tests for my changes (see [Test Requirements](../CONTRIBUTING.md#test-requirements)) - [x] Tests pass locally (`task test` and `task test/integration` if applicable) - [x] My changes do not decrease test coverage --------- Signed-off-by: Matthias Bruns <git@matthiasbruns.com>
What this PR does / why we need it
Phase 2 typed oci bindings ADR
Which issue(s) this PR fixes
Contributes: open-component-model/ocm-project#986
You can see the whole picture in #2148
Testing
How to test the changes
Unit & integration tests only.
I ran
task init/go.workwith the updatedcredentialsbinding to see if the update breaks ocm - it does not :)Verification
task testandtask test/integrationif applicable)