Skip to content

fix: preserve connection secret namespace in multi-step pipelines#297

Closed
fabioaraujopt wants to merge 1 commit intocrossplane-contrib:mainfrom
fabioaraujopt:fix/v2-conn-secret-namespace-stickiness
Closed

fix: preserve connection secret namespace in multi-step pipelines#297
fabioaraujopt wants to merge 1 commit intocrossplane-contrib:mainfrom
fabioaraujopt:fix/v2-conn-secret-namespace-stickiness

Conversation

@fabioaraujopt
Copy link

@fabioaraujopt fabioaraujopt commented Mar 13, 2026

Summary

This PR fixes a bug in function-patch-and-transform where later pipeline steps can overwrite a previously resolved connection secret namespace with an empty one. This is particularly problematic for cluster-scoped XRs (e.g., S3 Buckets, Caches) because an empty namespace in a Secret reference is invalid in Crossplane's core reconciliation loop, leading to "poisoned" XRs that cannot self-heal.

Root Cause

The function re-composes the v2 connection secret at the end of every patch-and-transform step if connection details are present. If a later step does not explicitly provide a writeConnectionSecretToRef.namespace in its input, the function defaults to the XR's namespace. For cluster-scoped XRs, this is empty, causing the clobbering of any valid namespace set by an earlier step.

Example of the issue:

  1. Step 1: Patches namespace to my-tenant-ns. Connection secret is composed with namespace: my-tenant-ns.
  2. Step 2: Does not patch namespace. Connection secret is re-composed, defaulting to XR's namespace (empty for cluster-scoped XRs).
  3. Result: The XR's resourceRefs now contains a Secret with an empty namespace, causing reconciliation to fail.

Solution

Modified composeConnectionSecret to be "sticky". It now accepts the current desired state of the connection secret and preserves any non-empty Name or Namespace if the newly resolved reference would otherwise be empty. This ensures that once a valid namespace is patched or provided, it persists through subsequent steps in the same pipeline execution.

Test plan

  • Added TestComposeConnectionSecret in connection_test.go with StickyNamespace and StickyName cases.
  • Verified all tests pass with go test ./....
  • Verified that existing precedence rules (XR spec > Input > Default) are maintained but now behave stickily across steps.

Relates to #278

@fabioaraujopt fabioaraujopt force-pushed the fix/v2-conn-secret-namespace-stickiness branch 3 times, most recently from 6b50f97 to f44a215 Compare March 13, 2026 01:45
When a Composition uses multiple patch-and-transform steps, a later step
without a connection secret namespace could overwrite a previously
resolved namespace with an empty one. This is particularly problematic
for cluster-scoped XRs where the default namespace is empty.

This change makes the connection secret name and namespace 'sticky' by
preserving non-empty values from the current desired state if the newly
resolved reference has empty values.

Signed-off-by: fabioaraujopt <fabioaraujoorg@gmail.com>
@fabioaraujopt fabioaraujopt force-pushed the fix/v2-conn-secret-namespace-stickiness branch from f44a215 to 7a8020d Compare March 13, 2026 01:45
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