Skip to content

feat: implement MatchStrategy for destination matching - #373

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

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

Conversation

@zachbernstein-sdx

@zachbernstein-sdx zachbernstein-sdx commented Sep 1, 2026

Copy link
Copy Markdown

We're trying to use external-secrets/reloader in our cluster to sync AWS SM secret updates down to the cluster via an SQS queue. However, the users of our cluster use the AWS secret "short-name" (i.e. not the full secret ARN) in their ExternalSecret objects and so every SQS update to the ES-reloader controller gets ignored as it's not an exact string match.

The docs describe "RegularExpression" as a possible value for "MatchStrategy" (even showing an example) but the code path is not currently implemented. This PR attempts to build out MatchStrategy to meet our use-case.

LLM Disclaimer: this PR was generated via an LLM using test-driven-design (specifically, with https://github.com/dsifry/metaswarm). Please feel free to use this as a starting point and modify as needed. This was my attempt to get an MVP out as this project is still in alpha.

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, make test with envtest) still green.

Signed-off-by: Zach Bernstein <zach.bernstein@smarterdx.com>
@zachbernstein-sdx
zachbernstein-sdx marked this pull request as ready for review September 1, 2026 19:09
@Skarlso

Skarlso commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

@zachbernstein-sdx Please don't use LLMs for descriptions of PRs. Use your own words to describe what you want.

@zachbernstein-sdx

Copy link
Copy Markdown
Author

@Skarlso Happy to! PR description is updated. :)

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.

2 participants