Skip to content

feat: support labels/annotations on connection secrets#1009

Open
derbauer97 wants to merge 1 commit into
crossplane:mainfrom
derbauer97:feat/connection-secret-metadata
Open

feat: support labels/annotations on connection secrets#1009
derbauer97 wants to merge 1 commit into
crossplane:mainfrom
derbauer97:feat/connection-secret-metadata

Conversation

@derbauer97
Copy link
Copy Markdown

@derbauer97 derbauer97 commented May 27, 2026

Why

Crossplane 1.20's publishConnectionDetailsTo.metadata allowed users to set labels and annotations on published connection secrets. After the migration to writeConnectionSecretToRef, this capability was lost. Users need it to integrate with secret consumers that select by labels (e.g. external-secrets, ArgoCD).

Closes #1008

What

Adds metadata.labels and metadata.annotations support to writeConnectionSecretToRef for modern (namespaced) managed resources and claims via LocalSecretReference.

Implementation

  • LocalConnectionSecretFor clones labels/annotations from ref.Metadata onto the desired Secret
  • connectionSecretNeedsUpdate detects metadata drift only when manageMetadata=true (i.e. spec.writeConnectionSecretToRef.metadata != nil)
  • When metadata is omitted, existing secret labels/annotations are preserved (merge patch omits nil fields)
  • When metadata is set, labels/annotations are declaratively reconciled (the merge patch replaces the full map)
  • Shared publishConnectionSecret helper eliminates duplication between both publishers
  • XRD schema generation includes metadata in claim writeConnectionSecretToRef validation

Dependency: crossplane/crossplane

This PR depends on a change to crossplane/crossplane/apis/v2/core/v2 that adds:

  • SecretReferenceMetadata struct with Labels and Annotations fields
  • Metadata *SecretReferenceMetadata field on LocalSecretReference
  • Corresponding deep copy generation

Checklist

  • Read and followed Crossplane's [contribution process].
  • Run ./nix.sh flake check to ensure this PR is ready for review.
  • Added or updated unit tests.
  • Linked a PR or a [docs tracking issue] to [document this change].
  • Added backport release-x.y labels to auto-backport this PR.

I can open this as well if this implementation is accepted

@derbauer97 derbauer97 requested a review from a team as a code owner May 27, 2026 13:46
@derbauer97 derbauer97 requested a review from haarchri May 27, 2026 13:46
@derbauer97 derbauer97 changed the title feat: support labels/annotations on connection secrets for modern MRs and claims feat: support labels/annotations on connection secrets May 27, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 27, 2026

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: Pro

Run ID: e5e918bd-61f3-4116-ba58-2087f442b8c5

📥 Commits

Reviewing files that changed from the base of the PR and between fbe2230 and 89fbad9.

📒 Files selected for processing (6)
  • pkg/reconciler/managed/api.go
  • pkg/reconciler/managed/api_test.go
  • pkg/resource/resource.go
  • pkg/resource/resource_test.go
  • pkg/xcrd/crd_test.go
  • pkg/xcrd/schemas.go
🚧 Files skipped from review as they are similar to previous changes (6)
  • pkg/resource/resource.go
  • pkg/xcrd/schemas.go
  • pkg/xcrd/crd_test.go
  • pkg/reconciler/managed/api_test.go
  • pkg/resource/resource_test.go
  • pkg/reconciler/managed/api.go

📝 Walkthrough

Walkthrough

This PR extends connection secret publishing to support optional metadata (labels and annotations) via writeConnectionSecretToRef: schema, secret construction, and publishers are updated to propagate and reconcile metadata when configured.

Changes

Connection Secret Metadata Support

Layer / File(s) Summary
CRD schema for metadata field
pkg/xcrd/schemas.go, pkg/xcrd/crd_test.go
The writeConnectionSecretToRef schema now includes an optional metadata object containing labels and annotations fields as string maps; expected CRD test fixtures are updated in three places.
Secret construction with metadata propagation
pkg/resource/resource.go, pkg/resource/resource_test.go
Connection secret constructors cache the write reference, set the Secret Name/Namespace from it, and clone Metadata.Labels/Metadata.Annotations onto the Secret ObjectMeta, defaulting missing maps to empty maps. Tests verify propagation, label-only metadata, and empty-metadata coercion.
Metadata-aware secret publishing and update detection
pkg/reconciler/managed/api.go, pkg/reconciler/managed/api_test.go
APISecretPublisher and APILocalSecretPublisher delegate to a shared publishConnectionSecret helper that centralizes update eligibility and error wrapping. Updates are triggered when Data differs, or when manageMetadata is enabled and labels/annotations differ; tests cover metadata-only updates, no-op preservation, and clearing annotations.

🎯 3 (Moderate) | ⏱️ ~25 minutes

Thanks for the clear changes — could you add a short note in the commit message indicating that metadata reconciliation is conditional on WriteConnectionSecretToReference.Metadata being non-nil?

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: adding support for labels and annotations on connection secrets, with appropriate length under 72 characters.
Description check ✅ Passed The description is well-related to the changeset, explaining the 'why', 'what', and 'how' with implementation details, checklist, and dependency information.
Linked Issues check ✅ Passed The PR implementation fully satisfies issue #1008's requirements: adds metadata.labels/annotations support to writeConnectionSecretToRef, implements declarative reconciliation, preserves behavior when metadata is omitted, and eliminates need for external post-processing.
Out of Scope Changes check ✅ Passed All changes are scoped to implementing metadata support on connection secrets as specified in issue #1008; no unrelated modifications are present.
Breaking Changes ✅ Passed All modifications are additions of new code in new files (api.go, resource.go, schemas.go). No existing exported APIs were removed, renamed, or had signature changes.

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


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 and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
pkg/reconciler/managed/api_test.go (1)

335-393: ⚡ Quick win

Great test coverage for the main metadata scenarios!

The two new test cases nicely cover:

  1. MetadataChanged: Verifies that metadata-only changes (labels/annotations) trigger secret publishing even when data hasn't changed
  2. MetadataOmittedPreservesExisting: Confirms that when metadata is nil in the reference, existing secret labels/annotations are preserved

This demonstrates the declarative vs. preserve behavior clearly.

One suggestion: consider adding a test case for partially-specified metadata, such as when labels are set but annotations are omitted from the metadata block (or vice versa). This would help verify the behavior when ref.Metadata is non-nil but only one of Labels or Annotations is specified. It would clarify whether omitting a field within the metadata block means "don't touch existing values" or "clear existing values."

🤖 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/reconciler/managed/api_test.go` around lines 335 - 393, Add a new
table-driven test case in the same file that covers partially-specified metadata
(e.g., ref.Metadata non-nil with Labels set and Annotations nil, and another
variant with Annotations set and Labels nil) to assert whether labels are
updated and annotations preserved/cleared; reuse the existing patterns
(fields.secret using resource.ApplyFn, fake.ModernManaged,
resource.LocalConnectionSecretFor, and LocalConnectionSecretWriterTo.Ref) and
set expected want.published and want.err accordingly so the behavior when a
metadata block is present but only one subfield is specified is explicitly
validated.
pkg/resource/resource.go (1)

98-117: ⚡ Quick win

Clarify nil vs. empty map semantics for declarative metadata reconciliation.

The metadata propagation logic looks solid overall! I have one clarifying question about the intended behavior:

When a user specifies metadata: {} (non-nil but with nil Labels/Annotations), maps.Clone(nil) will produce nil maps in the Secret. When this Secret is applied via merge patch, will Labels: nil correctly clear existing labels on the server, or will the nil field be omitted from the patch (preserving existing values)?

For true declarative reconciliation, setting metadata: {labels: {}} should remove existing labels, but if labels is omitted within metadata (like metadata: {annotations: {...}}), I want to confirm the expected behavior. Could you verify this works as intended with your patching strategy?

Consider adding a test case covering partially-specified metadata (e.g., labels set but annotations omitted, or vice versa) to verify the patch semantics work correctly.

🤖 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/resource/resource.go` around lines 98 - 117, The current creation of the
Secret in NewConnectionSecretFromObject uses maps.Clone(ref.Metadata.Labels) /
Annotations which yields nil when the user provided an empty metadata block with
nil labels/annotations; to ensure declarative behavior (explicit empty => clear
on server) change the logic in the GetWriteConnectionSecretToReference handling
path so that when ref.Metadata != nil you set Labels and Annotations to non-nil
empty maps if the original slices are nil (e.g., coerce to map[string]string{}
rather than leaving nil), while still cloning non-empty maps; update the code
around GetWriteConnectionSecretToReference/ref.Metadata and the Secret
construction (ObjectMeta.Labels/Annotations) and add unit tests exercising
partial metadata cases (metadata:{} with nil labels/annotations,
metadata:{labels:{}} only, metadata:{annotations:{}} only) to validate
merge/patch semantics with your chosen patch strategy.
🤖 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/reconciler/managed/api_test.go`:
- Around line 335-393: Add a new table-driven test case in the same file that
covers partially-specified metadata (e.g., ref.Metadata non-nil with Labels set
and Annotations nil, and another variant with Annotations set and Labels nil) to
assert whether labels are updated and annotations preserved/cleared; reuse the
existing patterns (fields.secret using resource.ApplyFn, fake.ModernManaged,
resource.LocalConnectionSecretFor, and LocalConnectionSecretWriterTo.Ref) and
set expected want.published and want.err accordingly so the behavior when a
metadata block is present but only one subfield is specified is explicitly
validated.

In `@pkg/resource/resource.go`:
- Around line 98-117: The current creation of the Secret in
NewConnectionSecretFromObject uses maps.Clone(ref.Metadata.Labels) / Annotations
which yields nil when the user provided an empty metadata block with nil
labels/annotations; to ensure declarative behavior (explicit empty => clear on
server) change the logic in the GetWriteConnectionSecretToReference handling
path so that when ref.Metadata != nil you set Labels and Annotations to non-nil
empty maps if the original slices are nil (e.g., coerce to map[string]string{}
rather than leaving nil), while still cloning non-empty maps; update the code
around GetWriteConnectionSecretToReference/ref.Metadata and the Secret
construction (ObjectMeta.Labels/Annotations) and add unit tests exercising
partial metadata cases (metadata:{} with nil labels/annotations,
metadata:{labels:{}} only, metadata:{annotations:{}} only) to validate
merge/patch semantics with your chosen patch strategy.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 0bbbb974-7635-481d-a832-95ad667e45a7

📥 Commits

Reviewing files that changed from the base of the PR and between d331401 and 0e2d66d.

📒 Files selected for processing (6)
  • pkg/reconciler/managed/api.go
  • pkg/reconciler/managed/api_test.go
  • pkg/resource/resource.go
  • pkg/resource/resource_test.go
  • pkg/xcrd/crd_test.go
  • pkg/xcrd/schemas.go

@derbauer97 derbauer97 force-pushed the feat/connection-secret-metadata branch from 0e2d66d to fbe2230 Compare May 27, 2026 14:02
… and claims

Add metadata.labels and metadata.annotations to writeConnectionSecretToRef
for modern (namespaced) managed resources and claims via LocalSecretReference.

- LocalConnectionSecretFor clones labels/annotations from ref.Metadata
- connectionSecretNeedsUpdate detects metadata drift when manageMetadata=true
- Omitted metadata preserves existing secret labels/annotations (merge patch)
- Set metadata declaratively reconciles (merge patch replaces full map)
- Shared publishConnectionSecret helper deduplicates both publishers
- XRD schema includes metadata in claim writeConnectionSecretToRef validation

Closes: crossplane#1008
Signed-off-by: Florian Fl Bauer <florian.fl.bauer@deutschebahn.com>
@derbauer97 derbauer97 force-pushed the feat/connection-secret-metadata branch from fbe2230 to 89fbad9 Compare May 27, 2026 15:15
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.

Support labels and annotations on connection secrets created via writeConnectionSecretToRef

1 participant