Skip to content

Enqueue only a resolver's own ResolutionRequests - #10548

Merged
tekton-robot merged 2 commits into
tektoncd:mainfrom
somaz94:fix/resolver-promotefunc-label-selector
Sep 18, 2026
Merged

tekton-robot merged 2 commits into
tektoncd:mainfrom
somaz94:fix/resolver-promotefunc-label-selector

Conversation

@somaz94

@somaz94 somaz94 commented Aug 7, 2026 •

Copy link
Copy Markdown
Contributor

Changes

On leader promotion the resolver framework listed ResolutionRequests with labels.Everything() and enqueued every one of them into every resolver's workqueue. The reconciler has no label guard of its own, so whichever resolver dequeued a request first ran Validate() and Resolve() on it regardless of its resolution.tekton.dev/type label. A request addressed to the http resolver could therefore be failed by the hub resolver with missing required hub resolver params: name, version, and since the request is then already done the correct resolver skips it.

The informer's event handler was already filtered by FilterResolutionRequestsBySelector. Only the promote path was not.

This passes the resolver's selector into LeaderAwareFuncs and lists with labels.SelectorFromSet, which applies the same AND-of-equality match the event handler uses. Both frameworks now read the selector once and share it between the two paths, so the two filters cannot drift apart. It also answers the TODO(sbwsg) that has sat on LeaderAwareFuncs since it was introduced ("Should we use the filter selector from above in the call to lister.List here?"), which is yes.

Compatibility

No exported signature changes. LeaderAwareFuncs keeps its original one-argument form and its labels.Everything() behaviour, now marked deprecated; the filtered listing is a new LeaderAwareFuncsWithSelector, which is what the two in-tree NewController funcs call. Out-of-tree resolvers keep compiling untouched.

One behaviour note: an empty label set now maps to labels.Nothing() rather than labels.Everything(), and both controllers validate the selector and panic on an invalid one.

Validation

  • go build ./..., and every test binary under ./pkg/... and ./cmd/... compiles
  • go test ./pkg/resolution/... ./pkg/remoteresolution/..., 21 packages pass
  • pre-commit run on the changed files, including make test-unit over the whole repo
  • The lint-go hook could not run because the install script rejects the golangci-lint v2.12.2 darwin/arm64 tarball on a checksum mismatch (c8debe3b... vs the expected a9c54498...). I installed that same pinned v2.12.2 with go install instead and ran it over both framework packages: 0 issues. Worth knowing if others hit it.
  • The new TestLeaderAwareFuncsPromoteFiltersBySelector fails on all three table rows when the fix is reverted to labels.Everything(), with http-request and unlabeled-request leaking into the git resolver's queue.

Submitter Checklist

As the author of this PR, please check off the items in this checklist:

  • Has Docs if any changes are user facing, including updates to minimum requirements e.g. Kubernetes version bumps
  • Has Tests included if any functionality added or changed
  • pre-commit Passed
  • Follows the commit message standard
  • Meets the Tekton contributor standards (including functionality, content, code)
  • Has a kind label. You can add one by adding a comment on this PR that contains /kind <type>. Valid types are bug, cleanup, design, documentation, feature, flake, misc, question, tep
  • Release notes block below has been updated with any user facing changes (API changes, bug fixes, changes requiring upgrade notices or deprecation warnings). See some examples of good release notes.
  • Release notes contains the string "action required" if the change requires additional action from users switching to the new release

Fixes #10484

Relates to #

Release Notes

Resolvers no longer fail ResolutionRequests belonging to a different resolver after a leader election or a resolver pod restart.

@tekton-robot tekton-robot added do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. release-note Denotes a PR that will be considered when it comes time to generate release notes. labels Aug 7, 2026
@somaz94

somaz94 commented Aug 7, 2026

Copy link
Copy Markdown
Contributor Author

/kind bug

@tekton-robot
tekton-robot requested a review from aThorp96 August 7, 2026 03:40
@linux-foundation-easycla

linux-foundation-easycla Bot commented Aug 7, 2026 •

Copy link
Copy Markdown

CLA Signed
The committers listed above are authorized under a signed CLA.

  • ✅ login: somaz94 / name: somaz (6ae12cb)

@tekton-robot
tekton-robot requested a review from twoGiants August 7, 2026 03:40
@tekton-robot tekton-robot added kind/bug Categorizes issue or PR as related to a bug. size/L Denotes a PR that changes 100-499 lines, ignoring generated files. labels Aug 7, 2026
somaz94 added a commit to somaz94/somaz94 that referenced this pull request Aug 7, 2026
@waveywaves

Copy link
Copy Markdown
Member

@somaz94 thank you for opening this PR to make this feature furthermore performant using the selector, looking forward to this once ready for review

@waveywaves

Copy link
Copy Markdown
Member

cc @aThorp96 @twoGiants

somaz94 added a commit to somaz94/somaz94 that referenced this pull request Aug 7, 2026
@somaz94
somaz94 marked this pull request as ready for review August 7, 2026 07:10
@tekton-robot tekton-robot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Aug 7, 2026
@somaz94

somaz94 commented Aug 7, 2026

Copy link
Copy Markdown
Contributor Author

Marked this ready for review, thanks @waveywaves.

One thing that needs a maintainer click: the ready_for_review event did create a new ci run, but it came back action_required with no jobs executed — first-time contributor gate. The CI summary: fail currently showing is the previous run, whose only failing step was Block merge for draft PRs, so it is stale rather than a real failure. Could someone approve the workflow runs so the suite actually reports on this head?

For reference, on the draft run everything substantive passed, including the full e2e suite, Check generated code, lint and coverage.

@vdemeester vdemeester self-assigned this Aug 18, 2026
@waveywaves

Copy link
Copy Markdown
Member

@somaz94 you will have to rebase this PR looks like. Please do so.

On leader promotion the resolver framework listed ResolutionRequests
with labels.Everything() and enqueued every one of them into every
resolver's workqueue. The reconciler has no label guard of its own, so
whichever resolver dequeued a request first ran Validate() and
Resolve() on it regardless of its resolution.tekton.dev/type label. A
request addressed to the http resolver could therefore be failed by the
hub resolver with "missing required hub resolver params", and since the
request is then already done the http resolver skips it. The informer's
event handler was already filtered by FilterResolutionRequestsBySelector;
only the promote path was not.

Pass the resolver's selector into LeaderAwareFuncs and list with
labels.SelectorFromSet, which applies the same AND-of-equality match the
event handler uses. Both frameworks now read the selector once and share
it between the two paths so they cannot drift. This answers the TODO
that has sat on LeaderAwareFuncs since it was introduced.

Fixes #10484
@somaz94
somaz94 force-pushed the fix/resolver-promotefunc-label-selector branch from 6ae12cb to fc51fdc Compare August 19, 2026 02:01
@somaz94

somaz94 commented Aug 19, 2026

Copy link
Copy Markdown
Contributor Author

@waveywaves rebased on latest main and force-pushed — no conflicts, and the branch is up to date now.

Re-ran both resolver framework suites locally after the rebase:

ok  github.com/tektoncd/pipeline/pkg/resolution/resolver/framework
ok  github.com/tektoncd/pipeline/pkg/remoteresolution/resolver/framework

Ready for /lgtm whenever you get a chance. Also happy to /assign @vdemeester for the approve if that's the right path here.

@waveywaves waveywaves left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The promotion filtering and regression test look good. I am requesting changes for source compatibility and fail-closed selector handling. The resolver test suites, race tests, and go vet passed locally after rebasing onto current main.

// selector must be non-empty: labels.SelectorFromSet treats an empty set as
// labels.Everything(). Callers get this from ValidateResolver, which rejects a
// selector without a resolution.tekton.dev/type label.
func LeaderAwareFuncs(lister rrlister.ResolutionRequestLister, selector map[string]string) reconciler.LeaderAwareFuncs {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LeaderAwareFuncs is exported, so changing its arguments breaks external callers. Please keep the existing function and add LeaderAwareFuncsWithSelector for internal use.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done in 42e5b5a. LeaderAwareFuncs is back to the original one-argument signature and still lists with labels.Everything(), so callers outside the repo keep compiling and behave exactly as before. The filtered listing moved to a new LeaderAwareFuncsWithSelector. I also added a test that pins the old function to enqueueing everything, so it cannot get quietly narrowed later.

// The promote path and the informer's event handler below must filter
// ResolutionRequests with the same selector, or a resolver reconciles
// requests that are not addressed to it.
selector := resolver.GetSelector(ctx)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This selector is fetched again after validation. If it is empty, SelectorFromSet matches every request. Please validate this exact value in both controllers.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good catch — that second GetSelector really was unchecked. Both controllers now call ValidateResolver on the exact value they hand to the promote path and the event handler, inside the closure. The existing call at NewController entry runs with a different context and before Initialize, so it cannot stand in for it.

return reconciler.LeaderAwareFuncs{
PromoteFunc: func(bkt reconciler.Bucket, enq func(reconciler.Bucket, types.NamespacedName)) error {
all, err := lister.List(labels.Everything())
all, err := lister.List(labels.SelectorFromSet(selector))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

SelectorFromSet(nil) matches everything. Please fail closed when the resolver type selector is missing and add a nil/empty test case.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done in 42e5b5a. promotionSelector maps an empty set to labels.Nothing() rather than letting SelectorFromSet widen it to Everything(). Added nil and empty selector cases to the table test — I checked both fail if I take the guard back out.

Addresses review feedback on the promote-path selector.

Restore the exported LeaderAwareFuncs to its original one-argument
signature and its original labels.Everything() behaviour, and add
LeaderAwareFuncsWithSelector for the filtered listing. Changing the
arguments of an exported function breaks callers outside this repository
without them touching a line of their own code, so the old entry point
stays and is marked deprecated instead. A test pins its behaviour.

Fail closed when the selector is empty. labels.SelectorFromSet maps the
empty set to labels.Everything(), so a resolver reaching promotion
without a selector would re-enqueue every ResolutionRequest in the
cluster -- the exact bug the filtering exists to fix. promotionSelector
maps the empty set to labels.Nothing(), and nil and empty selector cases
cover it.

Validate the exact selector both paths use, in both controllers. The
ValidateResolver call at NewController entry runs with a different
context and before Initialize, then GetSelector is called a second time
inside the closure and that value was never checked. Re-validate it
where it is used rather than assume the two calls agree.
@somaz94

somaz94 commented Aug 21, 2026

Copy link
Copy Markdown
Contributor Author

@waveywaves all three points are addressed in 42e5b5ac7, replies are on the individual threads.

Short version: LeaderAwareFuncs is back to its original one-argument signature and Everything() behaviour with a test pinning it, the filtered listing moved to LeaderAwareFuncsWithSelector, an empty selector now resolves to labels.Nothing() instead of Everything(), and both controllers validate the exact selector they pass to the promote path and the event handler.

One thing that needs a click from your side: the push queued 7 workflow runs and all of them came back action_required with no jobs executed — the first-time-contributor gate, same as when I marked this ready for review. So the CI signal will stay empty until someone approves the runs.

Locally on the rebased branch: go build ./..., gofmt, go vet, and go test -race ./pkg/resolution/... ./pkg/remoteresolution/... are all green. I also checked the fail-closed guard by removing it, which fails exactly the two new nil/empty cases and nothing else.

@codecov

codecov Bot commented Aug 21, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 78.94737% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 87.36%. Comparing base (dd0937b) to head (42e5b5a).
⚠️ Report is 66 commits behind head on main.

Files with missing lines Patch % Lines
.../remoteresolution/resolver/framework/controller.go 60.00% 1 Missing and 1 partial ⚠️
pkg/resolution/resolver/framework/controller.go 85.71% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##             main   #10548       +/-   ##
===========================================
+ Coverage   51.19%   87.36%   +36.16%     
===========================================
  Files         334      291       -43     
  Lines       40495    25101    -15394     
===========================================
+ Hits        20733    21929     +1196     
+ Misses      18801     2265    -16536     
+ Partials      961      907       -54     
Flag Coverage Δ
unit-tests 87.36% <78.94%> (+36.16%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Filters leader-promotion requeues by resolver selector, preventing cross-resolver failures.

Changes:

  • Shares one validated selector across promotion and informer paths.
  • Preserves the legacy helper while adding a selector-aware replacement.
  • Adds tests for matching, nonmatching, and empty selectors.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
pkg/resolution/resolver/framework/controller.go Adds selector-aware promotion filtering.
pkg/resolution/resolver/framework/controller_test.go Tests promotion filtering and compatibility behavior.
pkg/remoteresolution/resolver/framework/controller.go Uses the shared selector for both controller paths.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines 176 to +177
func LeaderAwareFuncs(lister rrlister.ResolutionRequestLister) reconciler.LeaderAwareFuncs {
return leaderAwareFuncs(lister, labels.Everything())
@tekton-robot

Copy link
Copy Markdown
Collaborator

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: vdemeester

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@tekton-robot tekton-robot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Aug 27, 2026
@somaz94

somaz94 commented Aug 31, 2026

Copy link
Copy Markdown
Contributor Author

@waveywaves — could I get another look when you have a moment? I addressed your review in 42e5b5a back on 21 Aug and the full suite is green now, including all the e2e legs. I've also corrected the Compatibility section, which still described the earlier source-breaking version. @vdemeester approved on 27 Aug, so I think this just needs an lgtm.

@waveywaves

Copy link
Copy Markdown
Member

/lgtm

@tekton-robot tekton-robot added the lgtm Indicates that a PR is ready to be merged. label Sep 18, 2026
@tekton-robot
tekton-robot merged commit 83246ab into tektoncd:main Sep 18, 2026
30 of 31 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. kind/bug Categorizes issue or PR as related to a bug. lgtm Indicates that a PR is ready to be merged. release-note Denotes a PR that will be considered when it comes time to generate release notes. size/L Denotes a PR that changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Resolver PromoteFunc enqueues all ResolutionRequests into every resolver workqueue, causing cross-resolver failures

5 participants