Skip to content

fix: skip mutation system construction when no mutation operation is assigned - #4777

Open
pujitha24 wants to merge 4 commits into
open-policy-agent:masterfrom
pujitha24:auto/issue-4772
Open

pujitha24 wants to merge 4 commits into
open-policy-agent:masterfrom
pujitha24:auto/issue-4772

Conversation

@pujitha24

Copy link
Copy Markdown
Contributor

What this PR does / why we need it:

Gatekeeper unconditionally constructs a mutation.System in setupControllers and unconditionally creates the mutator conflict-routing channels plus registers the routeConflictEvents runnable in pkg/controller/mutators/instances.Adder.Add, even for pods where no mutation operation (mutation-webhook, mutation-controller, mutation-status) is assigned (e.g. --operation=audit or --operation=generate only). That means a status-only, audit-only, or generate-only process still pays for an unused mutation system and an unused runnable/goroutine.

This PR gates both of those on the existing mutation.Enabled() single source of truth (already used by pkg/controller/mutators/core.Adder.add), so:

  • mutationSystem in main.go stays nil unless a mutation operation is assigned. expansion.NewSystem already supports a nil mutation system (see pkg/expansion/system.go, s.mutationSystem == nil short-circuits expand), so expansion of generated resources continues to work unchanged: it applies mutators when a mutation operation is present, and simply skips mutation when one isn't.
  • instances.Adder.Add now returns immediately when mutation.Enabled() is false, before creating the conflict-routing channels or registering routeConflictEvents with the manager.

This is a minimal, surgical subset of the full scope described in the issue (it does not additionally restructure how the external-data provider cache / client cert watcher options are wired into mutationOpts, since those are simply unused when mutation.NewSystem is never called — no behavior change needed there).

Which issue(s) this PR fixes (optional, using fixes #<issue number>(, fixes #<issue_number>, ...) format, will close the issue(s) when the PR gets merged):
Fixes #

Special notes for your reviewer:

I traced every consumer of MutationSystem/mutationSystem that could now receive nil:

  • pkg/webhook/mutation.go AddMutatingWebhook already returns early unless operations.IsAssigned(operations.MutationWebhook) is true, before touching deps.MutationSystem.
  • pkg/webhook/policy.go stores a mutationSystem field but never dereferences it.
  • pkg/controller/mutators/core/adder.go (*Adder).add already guarded on mutation.Enabled() before this change (pre-existing).
  • pkg/controller/controller.go's MutationSystemInjector interface is implemented only by instances.Adder, which now guards on mutation.Enabled() itself, per this diff.
  • pkg/expansion/system.go already nil-checks s.mutationSystem before calling Mutate.

So there is no remaining path where a nil *mutation.System gets dereferenced.

Validation: go build ./..., go vet ./..., and golangci-lint run ./pkg/controller/mutators/instances/... . (locally installed golangci-lint v2.12.2; repo pins v2.9.0 via Docker in make lint, which I could not run here because Docker wasn't available in this environment — the local binary run against the same config found 0 issues on both the changed packages and the whole repo) are all clean. I added a targeted unit test, TestAddSkipsRegistrationWhenMutationDisabled, that narrows the process --operation flag to audit and calls (&Adder{}).Add(nil); it fails with a nil-pointer panic on mgr.GetScheme() against the pre-fix code and passes against the fix (verified both ways, including repeated runs with -count=5 and -race -count=3 to confirm the flag-mutating test itself is stable). I also ran the full existing suites for the directly affected packages with envtest: go test ./pkg/controller/mutators/... ./pkg/webhook/... ./pkg/expansion/... (KUBEBUILDER_ASSETS via setup-envtest) and the broader go test ./pkg/controller/... — all pass. I could not run the full make native-test/make native-race-test targets across the entire repo (./pkg/... ./apis/... ./cmd/gator/...) or any live e2e/dev-stack scenario in this environment; I believe this change is safe based on the nil-safety trace above plus the passing targeted and package-level tests.

Fixes #4772

@pujitha24
pujitha24 requested a review from a team as a code owner August 24, 2026 22:24
Copilot AI balanced review requested due to automatic review settings August 24, 2026 22:24

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@codecov-commenter

codecov-commenter commented Aug 24, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 0% with 7 lines in your changes missing coverage. Please review.
✅ Project coverage is 49.19%. Comparing base (3350319) to head (db8d818).
⚠️ Report is 889 commits behind head on master.

Files with missing lines Patch % Lines
main.go 0.00% 5 Missing ⚠️
...ntroller/mutators/instances/mutator_controllers.go 0.00% 2 Missing ⚠️

❗ There is a different number of reports uploaded between BASE (3350319) and HEAD (db8d818). Click for more details.

HEAD has 1 upload less than BASE
Flag BASE (3350319) HEAD (db8d818)
unittests 2 1
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #4777      +/-   ##
==========================================
- Coverage   54.49%   49.19%   -5.30%     
==========================================
  Files         134      292     +158     
  Lines       12329    24027   +11698     
==========================================
+ Hits         6719    11821    +5102     
- Misses       5116    11138    +6022     
- Partials      494     1068     +574     
Flag Coverage Δ
unittests 49.19% <0.00%> (-5.30%) ⬇️

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.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Copilot AI review requested due to automatic review settings August 26, 2026 18:28

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Copilot AI review requested due to automatic review settings August 27, 2026 08:53

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

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

Comment on lines +29 to +35
func TestAddSkipsRegistrationWhenMutationDisabled(t *testing.T) {
if err := flag.CommandLine.Set("operation", string(operations.Audit)); err != nil {
t.Fatalf("setting operation flag: %v", err)
}

a := &Adder{}
if err := a.Add(nil); err != nil {
Copilot AI review requested due to automatic review settings August 28, 2026 21:27

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Copilot AI review requested due to automatic review settings August 31, 2026 23:27

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Copilot AI review requested due to automatic review settings September 1, 2026 21:30

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Focused coverage does not verify conditional mutation-system construction or mutation-enabled operation sets.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details
  • Files reviewed: 3/3 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment thread main.go Outdated
Comment on lines +513 to +516
var mutationSystem *mutation.System
if mutation.Enabled() {
mutationSystem = mutation.NewSystem(mutationOpts)
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is a valid concern.

Copilot AI review requested due to automatic review settings September 2, 2026 17:30

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

Comment thread pkg/controller/mutators/instances/mutator_controllers_test.go
Comment thread pkg/controller/mutators/instances/mutator_controllers_test.go
@JaydipGabani

Copy link
Copy Markdown
Contributor

@abhisheksheth28 can you review this?

Copilot AI review requested due to automatic review settings September 3, 2026 09:55

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Focused coverage for mutation-system construction and injection remains missing, as noted in the unresolved review thread.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details
  • Files reviewed: 3/3 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

Copilot AI review requested due to automatic review settings September 6, 2026 08:44

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

The acknowledged focused-test gap for the main.go construction branch remains unresolved.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details
  • Files reviewed: 3/3 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

Copilot AI review requested due to automatic review settings September 6, 2026 09:05

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

The tests do not verify that production setup uses the conditional constructor, leaving a stated acceptance criterion uncovered.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details
  • Files reviewed: 4/4 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment thread main.go
}

mutationSystem := mutation.NewSystem(mutationOpts)
mutationSystem := newMutationSystem(mutationOpts)
Copilot AI review requested due to automatic review settings September 7, 2026 08:55

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Approval recommended

The operation guards are consistent with existing mutation semantics and the affected paths have focused regression coverage.

Review details
  • Files reviewed: 4/4 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

@pujitha24

Copy link
Copy Markdown
Contributor Author

Added TestAddProceedsWhenMutationEnabled in mutator_controllers_test.go and TestNewMutationSystemDisabledWhenNoMutationOperation / TestNewMutationSystemEnabledWhenMutationOperationAssigned in main_test.go, each re-execing the test binary so the operation flag can be narrowed to audit vs mutation-webhook independently per process. The main.go tests exercise newMutationSystem directly, which is what setupControllers now calls at line 525, so both the Add early-return and the construction branch are covered for both operation classes. I haven't added a test that drives setupControllers itself through a real manager to catch a future revert of that call site — that felt like more scope than this PR needs, but happy to add it if you'd rather have it.

@pujitha24

Copy link
Copy Markdown
Contributor Author

@abhisheksheth28 I've pushed changes addressing your review — the branch is now at 6962db9 and CI is green. Could you take another look when you have a moment? Happy to keep iterating if anything is still off.

Copilot AI review requested due to automatic review settings September 10, 2026 09:56

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Approval recommended

The guards align with existing operation semantics, preserve nil-safe expansion, and have focused regression coverage.

Review details
  • Files reviewed: 4/4 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

@abhisheksheth28 abhisheksheth28 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

lgtm. thanks! please pick up the CI fix from #4779 before merging so the root package tests run automatically.

Copilot AI review requested due to automatic review settings September 10, 2026 23:50

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

The root-level construction tests are excluded from the standard CI unit-test target.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details
  • Files reviewed: 4/4 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment thread main_test.go
// setupControllers unconditionally constructing a *mutation.System: when only
// a non-mutation operation (e.g. audit) is assigned, newMutationSystem must
// return nil.
func TestNewMutationSystemDisabledWhenNoMutationOperation(t *testing.T) {
Copilot AI review requested due to automatic review settings September 11, 2026 11:54

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

…assigned

Motivation:
setupControllers in main.go always calls mutation.NewSystem(...), and
pkg/controller/mutators/instances.Adder.Add always creates the mutator
conflict-routing channels and registers the routeConflictEvents runnable
with the manager, regardless of which --operation values are assigned. A
pod running e.g. --operation=audit or --operation=generate only therefore
still constructs an unused mutation system and starts an unused runnable
and goroutine, even though it never ingests, applies, or reports on any
mutator.

Approach:
Gate both call sites on mutation.Enabled() (pkg/mutation/mutation.go),
which is already the single source of truth used by
pkg/controller/mutators/core.Adder.add for the same purpose:
- main.go only constructs mutationSystem via mutation.NewSystem when
  mutation.Enabled() is true; otherwise it stays nil.
  expansion.NewSystem already supports a nil mutation system
  (pkg/expansion/system.go short-circuits Expand's mutation step when
  s.mutationSystem == nil), so expansion of generated resources is
  unaffected: mutators still apply when a mutation operation is present,
  and are simply skipped when one isn't.
- instances.Adder.Add now returns nil immediately when mutation.Enabled()
  is false, before creating the conflict-routing channels or registering
  routeConflictEvents.

Traced every remaining consumer of the (now possibly nil) mutation system
to confirm none can dereference nil: pkg/webhook/mutation.go's
AddMutatingWebhook already gates on operations.IsAssigned(MutationWebhook)
before use; pkg/webhook/policy.go stores the system but never dereferences
it; pkg/controller/mutators/core/adder.go already gated on
mutation.Enabled(); and instances.Adder is the only implementer of
pkg/controller/controller.go's MutationSystemInjector, now self-gating.

This is a minimal subset of the fuller scope described in the issue; it
does not restructure how the external-data provider cache / client cert
watcher options are wired into mutationOpts, since those remain unused
(harmless) when mutation.NewSystem is never called.

Validation:
- go build ./..., go vet ./..., and golangci-lint run (local v2.12.2,
  repo pins v2.9.0 via Docker which was unavailable here) on the changed
  packages and the whole repo: clean, 0 issues.
- Added a targeted unit test, TestAddSkipsRegistrationWhenMutationDisabled,
  in pkg/controller/mutators/instances/mutator_controllers_test.go. It
  narrows the process --operation flag to audit only and calls
  (&Adder{}).Add(nil): against the pre-fix code this panics with a nil
  pointer dereference on mgr.GetScheme(); against the fix it passes.
  Verified both directions, plus stability under
  `go test -run TestAddSkipsRegistrationWhenMutationDisabled -count=5`
  and `go test -race -count=3` for the whole package.
- go test ./pkg/controller/mutators/... ./pkg/webhook/... ./pkg/expansion/...
  and the broader ./pkg/controller/... (with KUBEBUILDER_ASSETS from
  setup-envtest) all pass.
- Not run here: the repo's full make native-test/native-race-test across
  ./pkg/... ./apis/... ./cmd/gator/..., and any live e2e/dev-stack
  scenario. No Kubernetes API/CRD types changed, so make generate/manifests
  should be a no-op.

Report: open-policy-agent#4772
Signed-off-by: Pujitha Paladugu <10557236+pujitha24@users.noreply.github.com>
Assisted-by: claude-sonnet-5 (via Claude Code)
…operation flag state

Adds TestAddProceedsWhenMutationEnabled alongside the existing
mutation-disabled test, and runs each in a re-exec'd subprocess so their
process-wide "operation" flag mutations no longer leak into each other or
future tests in the package.

Signed-off-by: Pujitha Paladugu <10557236+pujitha24@users.noreply.github.com>
…peration classes

Extracts the mutation.Enabled() guard around mutation.NewSystem in
setupControllers into newMutationSystem, and adds subprocess-isolated
tests exercising it for both a non-mutation operation (audit) and a
mutation operation, addressing the main.go:516 review comment.

Signed-off-by: Pujitha Paladugu <10557236+pujitha24@users.noreply.github.com>
The subprocess isolation added for the new operation-flag-narrowing
tests re-execs the current test binary (os.Args[0]) with a
compile-time-constant -test.run filter, which gosec's G204 flags as a
"tainted input" false positive since neither argument is externally
controlled.

Signed-off-by: Pujitha Paladugu <10557236+pujitha24@users.noreply.github.com>
Copilot AI review requested due to automatic review settings September 18, 2026 14:55

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

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.

Initialize mutation dependencies only for mutation operations

5 participants