Skip to content

feat: implement MatchStrategy for destination matching - #367

Draft
zachbernstein-sdx wants to merge 1 commit into
external-secrets:mainfrom
zachbernstein-sdx:feat/match-strategy
Draft

feat: implement MatchStrategy for destination matching#367
zachbernstein-sdx wants to merge 1 commit into
external-secrets:mainfrom
zachbernstein-sdx:feat/match-strategy

Conversation

@zachbernstein-sdx

Copy link
Copy Markdown

Problem

The Reloader docs describe MatchStrategy as a way to control how a destination is matched against an incoming event — evaluating a JSON path on the destination against configurable conditions like Contains or RegularExpression. It's defined in the CRD and documented with examples, but it's never actually evaluated: processor.go logs that it was provided and then falls through to each destination type's built-in matching logic instead.

That built-in logic only supports strict equality (or, for ExternalSecret, a regex on one specific field). It can't express a common real-world case: some notification sources surface a broader identifier for a secret than what a destination is configured with — for example, an AWS Secrets Manager rotation event carries the secret's full ARN, while an ExternalSecret conventionally references that same secret by its friendly name. MatchStrategy is the kind of configurable mechanism that could express that relationship, but without an implementation, there's no way to use it.

Fix

Implement MatchStrategy: it evaluates its configured path against the destination object and checks the values found there against its conditions, replacing the destination type's default matching when present. Condition values now support Go templating against the current event, so a condition can reference the event being processed rather than only a fixed string. Two new operations, ContainedBy and NotContainedBy, round out the existing Contains/NotContains pair to support matching in either direction.

Docs updated to describe the templating support and the new operations, including a worked example for the ARN/friendly-name case.

Testing

Added unit tests for the new matching logic and its integration into event handling, plus an end-to-end integration test exercising a MatchStrategy-based destination through the full reconcile path. Ran the complete existing test suite (including the controller integration tests) to confirm no regressions.

MatchStrategy has been defined in the Config CRD and documented (with
Equal/NotEqual/Contains/NotContains/RegularExpression operations) as a way
to control how a destination is matched against an incoming event, but
processor.go's HandleEvent only logged it and fell through to each
destination type's built-in References() check - matchStrategy was never
actually evaluated.

Implement it for real:

- internal/matchstrategy: evaluates a MatchStrategy's Path (Kubernetes
  JSONPath syntax) against a destination object, and checks every value
  found there against every configured Condition. A Condition's Value is
  rendered as a Go template with the current event bound as the template
  root, so conditions can reference the event being processed (e.g.
  "{{ .SecretIdentifier }}"), not just a static string.
- Two new condition operations, ContainedBy and NotContainedBy (the field
  value is/isn't a substring of the given value) - the inverse direction of
  the existing Contains/NotContains - needed to express "this destination's
  configured key is embedded in a larger identifier from the event", e.g.
  matching an ExternalSecret's friendly-name key against the full ARN an
  AWS Secrets Manager rotation event carries.
- processor.go: when a destination's MatchStrategy is set, it now replaces
  the built-in References() check entirely (per the intent already noted in
  schema.go's Handler interface comment), instead of being logged and
  ignored.
- docs/reference/strategies.md updated with the templating behavior, the
  two new operations, and a worked ARN-vs-friendly-name example.

Testing:
- internal/matchstrategy: 34 unit tests, 98.7% statement coverage (the only
  uncovered branch is a defensive json.Unmarshal error path that can't
  actually be triggered once json.Marshal has already succeeded).
- internal/handler: new processor_test.go covering MatchStrategy replacing
  References(), the no-match case, error propagation out of HandleEvent,
  fallback to default References() when no MatchStrategy is set, and
  unknown destination types being skipped.
- internal/controller: new envtest/ginkgo spec exercising the full
  reconcile path end-to-end with a MatchStrategy-based destination.
- Full existing suite (go vet, gofmt, all packages including envtest)
  still green.
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