Skip to content

CNV-80608: management: add update alert rule APIs#1047

Open
sradco wants to merge 5 commits into
openshift:main-alerts-management-apifrom
sradco:alert-mgmt-restructured-05-update-rule
Open

CNV-80608: management: add update alert rule APIs#1047
sradco wants to merge 5 commits into
openshift:main-alerts-management-apifrom
sradco:alert-mgmt-restructured-05-update-rule

Conversation

@sradco

@sradco sradco commented Jul 8, 2026

Copy link
Copy Markdown

Add PATCH /api/v1/alerting/rules for bulk
update of platform and user-defined alert
rules with drop/restore, label overrides,
and per-rule update support.

Signed-off-by: Shirly Radco sradco@redhat.com
Signed-off-by: João Vilaça jvilaca@redhat.com
Signed-off-by: Aviv Litman alitman@redhat.com
Co-authored-by: AI Assistant noreply@cursor.com

Made with Cursor

Summary by CodeRabbit

  • New Features
    • Added a bulk alert-rule update API (PATCH /rules) with per-rule results.
    • Supports label overrides (including removal via null/empty), classification overrides, and alert enable/disable with drop/restore.
  • Bug Fixes
    • Improved management enforcement for GitOps- and operator-managed rules, including clearer per-rule outcomes for mixed success, not-found, and invalid IDs.
  • Tests
    • Added unit and end-to-end coverage for bulk updates, drop/restore, classification behavior, and request validation limits/error cases.

@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Jul 8, 2026
@openshift-ci-robot

openshift-ci-robot commented Jul 8, 2026

Copy link
Copy Markdown

@sradco: This pull request references CNV-80608 which is a valid jira issue.

Details

In response to this:

Add PATCH /api/v1/alerting/rules for bulk
update of platform and user-defined alert
rules with drop/restore, label overrides,
and per-rule update support.

Signed-off-by: Shirly Radco sradco@redhat.com
Signed-off-by: João Vilaça jvilaca@redhat.com
Signed-off-by: Aviv Litman alitman@redhat.com
Co-authored-by: AI Assistant noreply@cursor.com

Made with Cursor

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@openshift-ci openshift-ci Bot requested review from etmurasaki and zhuje July 8, 2026 18:31
@openshift-ci

openshift-ci Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: sradco
Once this PR has been reviewed and has the lgtm label, please assign zhuje for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found 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

@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

This PR adds a bulk PATCH /rules API with per-rule results, user and platform rule updates, classification and label overrides, ARC drop/restore behavior, ownership checks, deletion cleanup, generated routing, and unit/e2e coverage.

Changes

Alert-rule bulk update workflow

Layer / File(s) Summary
Bulk update API and handler
api/openapi.yaml, internal/managementrouter/*
Defines, wires, validates, and executes bulk label, classification, enablement, and restoration updates with per-rule status results.
Management contracts and preconditions
pkg/management/types.go, pkg/management/alert_rule_preconditions.go, pkg/management/label_utils.go, pkg/management/get_rule_by_id.go
Adds lifecycle operations, stable-ID lookup, protected-label detection, and GitOps/operator ownership checks.
User-defined rule mutation
pkg/management/update_user_defined_alert_rule.go, pkg/management/update_alert_rule_labels.go, related tests
Updates PrometheusRule entries, validates severity and ID collisions, routes label changes, and migrates ARC overrides when IDs change.
Platform ARC lifecycle and cleanup
pkg/management/update_platform_alert_rule.go, pkg/management/delete_user_defined_alert_rule_by_id.go, related tests
Updates platform labels, manages ARC relabel entries and drop/restore state, and performs associated ARC cleanup.
Integration validation
test/e2e/*
Adds platform rule discovery, scoped-user helpers, and end-to-end coverage for drop/restore, classification, and RBAC outcomes.

Estimated code review effort: 5 (Critical) | ~120 minutes

Suggested reviewers: etmurasaki, zhuje

🚥 Pre-merge checks | ✅ 12 | ❌ 3

❌ Failed checks (3 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 18.52% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Test Structure And Quality ⚠️ Warning The new e2e tests rely on fixed time.Sleep(2s) waits and ignore cleanup errors; user provisioning also leaves partial resources behind on failure. Replace fixed sleeps with bounded Eventually-style waits, make cleanup return/report errors, and roll back SA/Role/RoleBinding creation on any provisioning failure.
Microshift Test Compatibility ⚠️ Warning New e2e tests use openshift-monitoring AlertRelabelConfigs/AlertingRules via MonitoringV1() with no MicroShift skip guard; these APIs/features aren’t on MicroShift. Add a MicroShift guard ([Skipped:MicroShift] or exutil.IsMicroShiftCluster() + g.Skip()), or avoid monitoring-stack APIs/resources in MicroShift-runnable tests.
✅ Passed checks (12 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: new alert rule update APIs in management.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Stable And Deterministic Test Names ✅ Passed No Ginkgo spec titles or dynamic subtest names were added; changed tests use static Test... names and fixed t.Run strings.
Single Node Openshift (Sno) Test Compatibility ✅ Passed The new e2e tests only patch alert rules, check ARCs, and do RBAC via namespaces/service accounts; no multi-node/HA assumptions or SNO guards are present.
Topology-Aware Scheduling Compatibility ✅ Passed PR changes are API/management/test code only; no deployment manifests or pod scheduling constraints (affinity/nodeSelector/topologySpread/PDB) were added or changed.
Ote Binary Stdout Contract ✅ Passed No process-level stdout writes or suite hooks were added; main uses logrus, and searches found no fmt.Print/println, klog stdout setup, or TestMain/BeforeSuite hooks.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed New e2e tests use cluster-internal APIs and PluginURL, with no hardcoded IPv4s, localhost, or public internet dependencies.
No-Weak-Crypto ✅ Passed No MD5/SHA1/DES/RC4/3DES/Blowfish/ECB, custom crypto, or non-constant-time secret/token comparisons were found in the changed files.
Container-Privileges ✅ Passed Repo-wide scan found no privileged/hostPID/hostNetwork/hostIPC/SYS_ADMIN/allowPrivilegeEscalation settings; spot-checked Helm/devspace manifests too.
No-Sensitive-Data-In-Logs ✅ Passed Only generic warn/error logs and test diagnostics were added; no code logs bearer tokens, passwords, API keys, or PII.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 2

🧹 Nitpick comments (6)
pkg/management/get_rule_by_id.go (1)

9-9: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Add a doc comment on the exported method.

GetRuleById is an exported method but lacks a doc comment beginning with the method name. As per coding guidelines, "Exported Go functions and methods must have doc comments beginning with the function name".

📝 Proposed fix
+// GetRuleById retrieves a specific alert rule by its ID, returning a
+// NotFoundError when the rule is not present.
 func (c *client) GetRuleById(ctx context.Context, alertRuleId string) (monitoringv1.Rule, error) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/management/get_rule_by_id.go` at line 9, Add a Go doc comment for the
exported client method GetRuleById so it begins with the method name and
describes what it returns; place it directly above GetRuleById on the client
type, following the same comment style used for exported methods in this
package.

Source: Coding guidelines

pkg/management/alert_rule_preconditions.go (1)

87-95: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Optional: reuse validateGitOpsPreconditions to avoid duplicated GitOps checks.

Lines 88-95 replicate the rule-label and parent-PrometheusRule GitOps checks already implemented in validateGitOpsPreconditions (Lines 76-83). Delegating keeps the two paths in sync if GitOps gating logic changes.

♻️ Proposed refactor
 func validatePlatformUpdatePreconditions(relabeled monitoringv1.Rule, pr *monitoringv1.PrometheusRule, arc *osmv1.AlertRelabelConfig) error {
-	if isRuleManagedByGitOpsLabel(relabeled) {
-		return notAllowedGitOpsEdit()
-	}
-	if pr != nil {
-		if gitOpsManaged, _ := k8s.IsExternallyManagedObject(pr); gitOpsManaged {
-			return notAllowedGitOpsEdit()
-		}
-	}
+	if err := validateGitOpsPreconditions(relabeled, pr); err != nil {
+		return err
+	}
 	if arc != nil {
 		if k8s.IsManagedByGitOps(arc.Annotations, arc.Labels) {
 			return notAllowedGitOpsEdit()
 		}
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/management/alert_rule_preconditions.go` around lines 87 - 95, The GitOps
checks in validatePlatformUpdatePreconditions are duplicated from
validateGitOpsPreconditions, so update validatePlatformUpdatePreconditions to
delegate to validateGitOpsPreconditions instead of repeating the rule-label and
parent PrometheusRule checks. Keep the existing behavior by passing the same
relabeled, pr, and arc inputs through the shared helper so the GitOps gating
logic stays centralized and consistent.
internal/managementrouter/alert_rule_bulk_update_test.go (2)

152-163: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use httptest.NewRequestWithContext instead of httptest.NewRequest.

golangci-lint's noctx linter flags three calls to httptest.NewRequest (lines 158, 322, 342). If this linter is enabled in CI, these will fail the build.

🔧 Fix: pass context to httptest.NewRequest
 func (f *buFixture) do(t *testing.T, body any) *httptest.ResponseRecorder {
 	t.Helper()
 	buf, err := json.Marshal(body)
 	if err != nil {
 		t.Fatalf("marshal: %v", err)
 	}
-	req := httptest.NewRequest(http.MethodPatch, "/api/v1/alerting/rules", bytes.NewReader(buf))
+	req := httptest.NewRequestWithContext(context.Background(), http.MethodPatch, "/api/v1/alerting/rules", bytes.NewReader(buf))
 	req.Header.Set("Authorization", "Bearer test-token")
 	w := httptest.NewRecorder()
 	f.router.ServeHTTP(w, req)
 	return w
 }

Apply the same change to lines 322 and 342:

-	req := httptest.NewRequest(http.MethodPatch, "/api/v1/alerting/rules", bytes.NewBufferString("{"))
+	req := httptest.NewRequestWithContext(context.Background(), http.MethodPatch, "/api/v1/alerting/rules", bytes.NewBufferString("{"))
-	req := httptest.NewRequest(http.MethodPatch, "/api/v1/alerting/rules", bytes.NewReader(large))
+	req := httptest.NewRequestWithContext(context.Background(), http.MethodPatch, "/api/v1/alerting/rules", bytes.NewReader(large))

Also applies to: 320-333, 335-353

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/managementrouter/alert_rule_bulk_update_test.go` around lines 152 -
163, The test helper and the other two request builders in
alert_rule_bulk_update_test are using httptest.NewRequest, which trips the noctx
linter. Update do and the two other request-creation sites to use
httptest.NewRequestWithContext instead, passing an appropriate context such as
context.Background() or the test context already available. Keep the same
request method, URL, body, and headers, and make sure the change is applied
consistently across the helper and the related bulk update tests.

176-579: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Good test coverage — consider adding combined-operation tests.

The suite covers validation, label updates (set/drop via empty-string and null), toggle (drop/restore), classification, mixed platform/user, not-found, and invalid rule IDs. Two gaps worth considering:

  • Toggle + labels combined: Verify the "silently absorbed" behavior when alertingRuleEnabled is set on a user-defined rule alongside labels that succeed (spec says result should be 204).
  • Toggle + classification combined: Same absorbed-rejection behavior with classification instead of labels.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/managementrouter/alert_rule_bulk_update_test.go` around lines 176 -
579, Add two combined-operation tests in TestBulkUpdateAlertRules: one for
alertingRuleEnabled with labels on a user-defined rule, and one for
alertingRuleEnabled with classification. Use the existing bulk-update
fixture/helpers (newBUFixture, f.do, f.rebuild, buFixtureIDs) to assert the
user-rule toggle rejection is silently absorbed while the successful
labels/classification update still returns 204 for the rule and 200 overall.
Reuse the same response shape checks used in the other bulk update tests to
confirm the returned rule status codes.
pkg/management/update_user_defined_alert_rule.go (1)

128-135: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

alertName parameter is unused.

The body derives the alert name from the re-fetched updatedRule.Alert (Lines 196, 199) and never references the alertName argument. Either drop the parameter or use it in place of the re-fetch to avoid confusion about intent.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/management/update_user_defined_alert_rule.go` around lines 128 - 135, The
migrateClassificationOverrideIfRuleIDChanged function currently accepts
alertName but never uses it, while the alert name is re-derived from
updatedRule.Alert later in the flow. Either remove the alertName parameter from
the function signature and its callers, or replace the re-fetched alert name
usage with this argument consistently so the intent is clear and the API does
not expose an unused parameter.
pkg/management/update_platform_alert_rule.go (1)

31-31: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add doc comments to exported methods.

UpdatePlatformAlertRule (Line 31), DropPlatformAlertRule (Line 279), and RestorePlatformAlertRule (Line 335) are exported but lack doc comments beginning with the method name.

As per coding guidelines, "Exported Go functions and methods must have doc comments beginning with the function name."

📝 Example
+// UpdatePlatformAlertRule applies label overrides to a platform alert rule via
+// its AlertingRule or AlertRelabelConfig.
 func (c *client) UpdatePlatformAlertRule(ctx context.Context, alertRuleId string, alertRule monitoringv1.Rule) error {

Also applies to: 279-279, 335-335

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/management/update_platform_alert_rule.go` at line 31, Add Go doc comments
for the exported methods in this client: UpdatePlatformAlertRule,
DropPlatformAlertRule, and RestorePlatformAlertRule. Each comment should start
with the exact method name and briefly describe what the method does, so the
exported API follows the standard Go documentation convention. Update the
declarations in the client type near those method definitions to include the
missing comments.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/managementrouter/router.go`:
- Around line 107-118: `parseParam` is incorrectly URL-decoding rule IDs coming
from JSON body payloads, which can alter literal `%` sequences and differs from
the bulk delete flow. Update the bulk update path that uses `parseParam` to trim
the JSON `payload.RuleIds` values directly with `strings.TrimSpace`, matching
`user_defined_alert_rule_bulk_delete.go`, and keep `parseParam` reserved for
actual URL path parameters where `url.PathUnescape` belongs.

In `@pkg/management/delete_user_defined_alert_rule_by_id.go`:
- Around line 161-164: In deleteAssociatedARC, the current `if err != nil ||
!found { return nil }` path hides real `AlertRelabelConfigs().Get` failures by
treating them the same as a missing ARC. Update the lookup handling so `found ==
false` still returns nil, but any non-nil error is returned to the caller; keep
the existing delete flow in deleteAssociatedARC and let the higher-level caller
observe genuine API failures instead of silently skipping them.

---

Nitpick comments:
In `@internal/managementrouter/alert_rule_bulk_update_test.go`:
- Around line 152-163: The test helper and the other two request builders in
alert_rule_bulk_update_test are using httptest.NewRequest, which trips the noctx
linter. Update do and the two other request-creation sites to use
httptest.NewRequestWithContext instead, passing an appropriate context such as
context.Background() or the test context already available. Keep the same
request method, URL, body, and headers, and make sure the change is applied
consistently across the helper and the related bulk update tests.
- Around line 176-579: Add two combined-operation tests in
TestBulkUpdateAlertRules: one for alertingRuleEnabled with labels on a
user-defined rule, and one for alertingRuleEnabled with classification. Use the
existing bulk-update fixture/helpers (newBUFixture, f.do, f.rebuild,
buFixtureIDs) to assert the user-rule toggle rejection is silently absorbed
while the successful labels/classification update still returns 204 for the rule
and 200 overall. Reuse the same response shape checks used in the other bulk
update tests to confirm the returned rule status codes.

In `@pkg/management/alert_rule_preconditions.go`:
- Around line 87-95: The GitOps checks in validatePlatformUpdatePreconditions
are duplicated from validateGitOpsPreconditions, so update
validatePlatformUpdatePreconditions to delegate to validateGitOpsPreconditions
instead of repeating the rule-label and parent PrometheusRule checks. Keep the
existing behavior by passing the same relabeled, pr, and arc inputs through the
shared helper so the GitOps gating logic stays centralized and consistent.

In `@pkg/management/get_rule_by_id.go`:
- Line 9: Add a Go doc comment for the exported client method GetRuleById so it
begins with the method name and describes what it returns; place it directly
above GetRuleById on the client type, following the same comment style used for
exported methods in this package.

In `@pkg/management/update_platform_alert_rule.go`:
- Line 31: Add Go doc comments for the exported methods in this client:
UpdatePlatformAlertRule, DropPlatformAlertRule, and RestorePlatformAlertRule.
Each comment should start with the exact method name and briefly describe what
the method does, so the exported API follows the standard Go documentation
convention. Update the declarations in the client type near those method
definitions to include the missing comments.

In `@pkg/management/update_user_defined_alert_rule.go`:
- Around line 128-135: The migrateClassificationOverrideIfRuleIDChanged function
currently accepts alertName but never uses it, while the alert name is
re-derived from updatedRule.Alert later in the flow. Either remove the alertName
parameter from the function signature and its callers, or replace the re-fetched
alert name usage with this argument consistently so the intent is clear and the
API does not expose an unused parameter.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: c5fe80fb-3711-47a6-a729-28a333d7b34d

📥 Commits

Reviewing files that changed from the base of the PR and between 826838d and 9997bc6.

📒 Files selected for processing (17)
  • api/openapi.yaml
  • internal/managementrouter/alert_rule_bulk_update.go
  • internal/managementrouter/alert_rule_bulk_update_test.go
  • internal/managementrouter/api_generated.go
  • internal/managementrouter/router.go
  • internal/managementrouter/user_defined_alert_rule_bulk_delete.go
  • pkg/management/alert_rule_preconditions.go
  • pkg/management/delete_user_defined_alert_rule_by_id.go
  • pkg/management/get_rule_by_id.go
  • pkg/management/get_rule_by_id_test.go
  • pkg/management/label_utils.go
  • pkg/management/types.go
  • pkg/management/update_platform_alert_rule.go
  • pkg/management/update_platform_alert_rule_test.go
  • pkg/management/update_user_defined_alert_rule.go
  • pkg/management/update_user_defined_alert_rule_test.go
  • test/e2e/update_alert_rule_test.go

Comment thread internal/managementrouter/router.go Outdated
Comment thread pkg/management/delete_user_defined_alert_rule_by_id.go
@sradco sradco force-pushed the alert-mgmt-restructured-05-update-rule branch from 9997bc6 to 5a3282e Compare July 8, 2026 18:43
Comment thread api/openapi.yaml Outdated
Comment thread internal/managementrouter/alert_rule_bulk_update.go Outdated
Comment thread internal/managementrouter/alert_rule_bulk_update.go Outdated
Comment thread internal/managementrouter/alert_rule_bulk_update.go
Comment thread internal/managementrouter/alert_rule_bulk_update.go Outdated
Comment thread pkg/management/update_platform_alert_rule.go
Comment thread pkg/management/label_utils.go
Comment thread internal/managementrouter/alert_rule_bulk_update.go Outdated
Comment thread internal/managementrouter/alert_rule_bulk_update.go Outdated
Comment thread internal/managementrouter/alert_rule_bulk_update.go
@sradco sradco force-pushed the alert-mgmt-restructured-05-update-rule branch from 5a3282e to 79db1db Compare July 13, 2026 17:58

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 7

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/managementrouter/alert_rule_bulk_update.go`:
- Around line 68-123: The per-rule update flow in the bulk handler must produce
one atomic outcome: do not suppress a toggle NotAllowedError when classification
or labels are also requested, and do not report success after a partial
mutation. Update the logic around the visible toggle handling and classification
update calls to either preflight all requested changes and apply them as one
management operation, or reject combined updates before mutation; return 204
only when every requested field succeeds. Add regression coverage for combined
toggle, label, and classification updates.

In `@pkg/management/delete_user_defined_alert_rule_by_id.go`:
- Around line 146-154: Update cleanupARCForDeletedRule to propagate errors
returned by arcNamespaceForRule instead of unconditionally returning nil. Only
treat the explicit “ARC not applicable” result as a successful no-op, while
returning all other namespace-resolution failures to the caller.
- Around line 89-101: The delete flow around the primary AlertingRule
deletion/update and deleteAssociatedARC must remain recoverable when ARC cleanup
fails. Make cleanup idempotent or ensure a retry/reconciliation path can remove
the retained ARC even when the rule is already absent, while preserving the
existing primary operation behavior in both len(newGroups) branches.

In `@pkg/management/get_rule_by_id_test.go`:
- Around line 79-83: Update the error assertion in the test around the errors.As
call to stop execution immediately when the error is not a
management.NotFoundError, using the test framework’s fatal assertion so nf is
never dereferenced while nil. Preserve the existing diagnostic message and
Resource validation for successful type matches.

In `@pkg/management/update_platform_alert_rule.go`:
- Around line 366-374: After findARCByAlertRuleID returns a non-nil existingArc
in the fallback branch, apply the same shared ARC ownership validation used by
the normal path before proceeding to deletion or update. Preserve the existing
nil return for a missing ARC and ensure GitOps-managed ARCs cannot be restored
through the cache-miss path.
- Around line 404-413: Update findARCByAlertRuleID to return an error alongside
its existing results, and return any AlertRelabelConfigs().List failure instead
of continuing silently. Propagate that error through RestorePlatformAlertRule
and ensure restore does not report success when ARC discovery fails; update all
callers and return paths accordingly.
- Around line 208-214: Update the nextChanges-empty branch in the
AlertRelabelConfig update flow to preserve existingRuleDrops: rebuild or retain
the ARC with its stamp and rule drops when drops remain, rather than deleting it
solely because label overrides are gone. Delete the ARC only when both
nextChanges and existingRuleDrops are empty.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: b66ef24d-96b5-4343-a538-f47ae1b1f33f

📥 Commits

Reviewing files that changed from the base of the PR and between 9997bc6 and 79db1db.

📒 Files selected for processing (18)
  • api/openapi.yaml
  • internal/managementrouter/alert_rule_bulk_update.go
  • internal/managementrouter/alert_rule_bulk_update_test.go
  • internal/managementrouter/api_generated.go
  • internal/managementrouter/router.go
  • internal/managementrouter/user_defined_alert_rule_bulk_delete.go
  • pkg/management/alert_rule_preconditions.go
  • pkg/management/delete_user_defined_alert_rule_by_id.go
  • pkg/management/get_rule_by_id.go
  • pkg/management/get_rule_by_id_test.go
  • pkg/management/label_utils.go
  • pkg/management/types.go
  • pkg/management/update_platform_alert_rule.go
  • pkg/management/update_platform_alert_rule_test.go
  • pkg/management/update_user_defined_alert_rule.go
  • pkg/management/update_user_defined_alert_rule_test.go
  • test/e2e/helpers_test.go
  • test/e2e/update_alert_rule_test.go
🚧 Files skipped from review as they are similar to previous changes (10)
  • pkg/management/get_rule_by_id.go
  • pkg/management/label_utils.go
  • pkg/management/update_platform_alert_rule_test.go
  • internal/managementrouter/api_generated.go
  • test/e2e/update_alert_rule_test.go
  • pkg/management/update_user_defined_alert_rule.go
  • pkg/management/alert_rule_preconditions.go
  • pkg/management/update_user_defined_alert_rule_test.go
  • pkg/management/types.go
  • api/openapi.yaml

Comment thread internal/managementrouter/alert_rule_bulk_update.go Outdated
Comment thread pkg/management/delete_user_defined_alert_rule_by_id.go
Comment thread pkg/management/delete_user_defined_alert_rule_by_id.go
Comment thread pkg/management/get_rule_by_id_test.go
Comment thread pkg/management/update_platform_alert_rule.go
Comment thread pkg/management/update_platform_alert_rule.go
Comment thread pkg/management/update_platform_alert_rule.go Outdated
@sradco sradco force-pushed the alert-mgmt-restructured-05-update-rule branch from 79db1db to 7474fcb Compare July 15, 2026 15:33

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

♻️ Duplicate comments (1)
internal/managementrouter/alert_rule_bulk_update.go (1)

66-153: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Make each rule update produce one coherent outcome.

The logic currently allows partial mutations and suppresses errors. If a toggle operation encounters a NotAllowedError, it sets notAllowedEnabled = true and proceeds. If a subsequent Classification or Labels update succeeds, the final response returns 204 No Content because of the check on line 141 (payload.Labels == nil && payload.Classification == nil), hiding the fact that the toggle failed. Conversely, if the toggle succeeds but the Classification or Labels update fails, the rule is left partially updated while a failure status is returned.

Preflight all requested changes and apply them as one management operation, or reject combined updates before any mutation. Return a success status only when every requested field for a rule succeeds.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/managementrouter/alert_rule_bulk_update.go` around lines 66 - 153,
Update the per-rule flow around the toggle, classification, and label operations
so combined requests cannot produce partial mutations or hide failures.
Preflight all requested changes and apply them atomically through the management
client, or reject requests containing multiple update types before invoking any
mutation; remove the notAllowedEnabled success path. Ensure each rule appends
exactly one result, returning success only when every requested field succeeds
and preserving the relevant error status otherwise.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pkg/management/alert_rule_preconditions.go`:
- Around line 52-56: Update validateUserUpdatePreconditions to also detect when
the parent PrometheusRule is GitOps-managed, alongside the existing
IsExternallyManagedObject check. Reuse the same GitOps management detection and
rejection behavior established by validateGitOpsPreconditions, so user-defined
rule edits return notAllowedOperatorUpdate() when either management mechanism
controls the parent.

---

Duplicate comments:
In `@internal/managementrouter/alert_rule_bulk_update.go`:
- Around line 66-153: Update the per-rule flow around the toggle,
classification, and label operations so combined requests cannot produce partial
mutations or hide failures. Preflight all requested changes and apply them
atomically through the management client, or reject requests containing multiple
update types before invoking any mutation; remove the notAllowedEnabled success
path. Ensure each rule appends exactly one result, returning success only when
every requested field succeeds and preserving the relevant error status
otherwise.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: adddd952-4128-4a7b-939c-39c9f526a1ea

📥 Commits

Reviewing files that changed from the base of the PR and between 79db1db and 7474fcb.

📒 Files selected for processing (19)
  • api/openapi.yaml
  • internal/managementrouter/alert_rule_bulk_update.go
  • internal/managementrouter/alert_rule_bulk_update_test.go
  • internal/managementrouter/api_generated.go
  • internal/managementrouter/router.go
  • internal/managementrouter/user_defined_alert_rule_bulk_delete.go
  • pkg/management/alert_rule_preconditions.go
  • pkg/management/delete_user_defined_alert_rule_by_id.go
  • pkg/management/get_rule_by_id.go
  • pkg/management/get_rule_by_id_test.go
  • pkg/management/label_utils.go
  • pkg/management/types.go
  • pkg/management/update_alert_rule_labels.go
  • pkg/management/update_platform_alert_rule.go
  • pkg/management/update_platform_alert_rule_test.go
  • pkg/management/update_user_defined_alert_rule.go
  • pkg/management/update_user_defined_alert_rule_test.go
  • test/e2e/helpers_test.go
  • test/e2e/update_alert_rule_test.go
🚧 Files skipped from review as they are similar to previous changes (15)
  • pkg/management/get_rule_by_id.go
  • internal/managementrouter/router.go
  • pkg/management/label_utils.go
  • test/e2e/helpers_test.go
  • pkg/management/get_rule_by_id_test.go
  • pkg/management/types.go
  • api/openapi.yaml
  • test/e2e/update_alert_rule_test.go
  • internal/managementrouter/api_generated.go
  • internal/managementrouter/alert_rule_bulk_update_test.go
  • pkg/management/delete_user_defined_alert_rule_by_id.go
  • pkg/management/update_user_defined_alert_rule_test.go
  • pkg/management/update_user_defined_alert_rule.go
  • pkg/management/update_platform_alert_rule.go
  • pkg/management/update_platform_alert_rule_test.go

Comment thread pkg/management/alert_rule_preconditions.go
@sradco sradco force-pushed the alert-mgmt-restructured-05-update-rule branch 5 times, most recently from 23c541d to e395513 Compare July 15, 2026 16:01
Add PATCH /api/v1/alerting/rules for bulk
update of platform and user-defined alert
rules with drop/restore, label overrides,
and per-rule update support.

Refactor: introduce UpdateAlertRuleLabels
unified method that routes internally to
platform (ARC) or user-defined (PR mutation)
paths, replacing the error-sniffing fallback
pattern in the HTTP handler.

Extend drop/restore to user-defined rules
via ARC (when ENABLE_USER_WORKLOAD_ARCS is
enabled). Rename DropPlatformAlertRule and
RestorePlatformAlertRule to DropAlertRule and
RestoreAlertRule respectively.

Add validateDropRestorePreconditions that
checks the PrometheusRule and AlertingRule CR
for GitOps management while still allowing
drops on operator-managed rules (their whole
purpose).

Reject requests that combine alertingRuleEnabled
with labels or classification — these are
mutually exclusive operations to prevent
partial-apply inconsistencies.

Fix user label updates to read source labels
from the PrometheusRule directly instead of
the relabeled cache, preventing ARC overlay
values from being baked into the PR source.

Fixes:
- Propagate errors from cleanupARCForDeletedRule
  instead of swallowing them (nilerr lint)
- Preserve rule Drops when clearing the last
  label override (prevent silent restore)
- Validate ARC ownership on fallback restore
  path (block GitOps-managed ARC modification)
- Return errors from findARCByAlertRuleID
  instead of silently continuing
- Use t.Fatalf in get_rule_by_id_test to
  prevent nil deref on type assertion failure
- Use httptest.NewRequestWithContext (noctx)
- Add ErrSkip handling in e2e tests matching
  repo convention

Signed-off-by: Shirly Radco <sradco@redhat.com>
Signed-off-by: João Vilaça <jvilaca@redhat.com>
Signed-off-by: Aviv Litman <alitman@redhat.com>
Co-authored-by: AI Assistant <noreply@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@sradco sradco force-pushed the alert-mgmt-restructured-05-update-rule branch from e395513 to bad70c3 Compare July 15, 2026 16:12
sradco and others added 2 commits July 15, 2026 19:16
validateUserUpdatePreconditions now checks both return values from
IsExternallyManagedObject, returning notAllowedGitOpsEdit() when the
parent PrometheusRule is managed by GitOps. Previously only
operator-management was detected, allowing edits that a GitOps
controller would immediately overwrite.

Co-authored-by: Cursor <cursoragent@cursor.com>
gci requires project-local imports to be sorted lexically.
Move internal/managementrouter before pkg/ entries.

Co-authored-by: Cursor <cursoragent@cursor.com>

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/managementrouter/alert_rule_bulk_update.go`:
- Around line 39-46: The generated documentation for
BulkUpdateAlertRulesRequest.AlertingRuleEnabled is outdated and describes toggle
conflicts as silently absorbed. Regenerate or update the AlertingRuleEnabled
contract in api_generated.go to state that combining it with labels or
classification returns HTTP 400, matching the validation in the bulk update
handler.

In `@pkg/management/alert_rule_preconditions.go`:
- Around line 89-112: The shared validatePlatformUpdatePreconditions logic must
allow the ARC fallback used by operator-managed platform rules instead of
rejecting ManagedByOperator on the relabeled rule or ARC. Add the narrow
carve-out needed for the UpdatePlatformAlertRule path, preserving existing
rejection behavior for other update paths, and add coverage for the
operator-managed branch in the relevant tests. The sibling site in
pkg/management/update_platform_alert_rule.go requires no direct change; it
identifies the caller relying on this precondition adjustment.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: a2e1b0dc-9cea-4b48-a5cc-77c1744b250b

📥 Commits

Reviewing files that changed from the base of the PR and between 7474fcb and b437a23.

📒 Files selected for processing (19)
  • api/openapi.yaml
  • internal/managementrouter/alert_rule_bulk_update.go
  • internal/managementrouter/alert_rule_bulk_update_test.go
  • internal/managementrouter/api_generated.go
  • internal/managementrouter/router.go
  • internal/managementrouter/user_defined_alert_rule_bulk_delete.go
  • pkg/management/alert_rule_preconditions.go
  • pkg/management/delete_user_defined_alert_rule_by_id.go
  • pkg/management/get_rule_by_id.go
  • pkg/management/get_rule_by_id_test.go
  • pkg/management/label_utils.go
  • pkg/management/types.go
  • pkg/management/update_alert_rule_labels.go
  • pkg/management/update_platform_alert_rule.go
  • pkg/management/update_platform_alert_rule_test.go
  • pkg/management/update_user_defined_alert_rule.go
  • pkg/management/update_user_defined_alert_rule_test.go
  • test/e2e/helpers_test.go
  • test/e2e/update_alert_rule_test.go
🚧 Files skipped from review as they are similar to previous changes (14)
  • internal/managementrouter/router.go
  • pkg/management/get_rule_by_id.go
  • pkg/management/label_utils.go
  • pkg/management/update_alert_rule_labels.go
  • pkg/management/get_rule_by_id_test.go
  • test/e2e/update_alert_rule_test.go
  • internal/managementrouter/api_generated.go
  • api/openapi.yaml
  • test/e2e/helpers_test.go
  • pkg/management/update_user_defined_alert_rule.go
  • pkg/management/update_user_defined_alert_rule_test.go
  • pkg/management/delete_user_defined_alert_rule_by_id.go
  • pkg/management/update_platform_alert_rule_test.go
  • internal/managementrouter/alert_rule_bulk_update_test.go

Comment thread internal/managementrouter/alert_rule_bulk_update.go
Comment thread pkg/management/alert_rule_preconditions.go
…docs

Two fixes addressing CodeRabbit review:

1. Remove isRuleManagedByOperator check from validatePlatformUpdatePreconditions.
   The ARC path modifies a separate AlertRelabelConfig, not the operator-managed
   resource itself, so operator management should not block it. The check was
   preventing UpdatePlatformAlertRule from using its designed ARC fallback for
   operator-managed AlertingRules.

2. Update stale BulkUpdateAlertRulesRequest.AlertingRuleEnabled comment in
   api_generated.go to reflect that the toggle now works for both platform and
   user-defined rules and cannot be combined with labels/classification (400).

Co-authored-by: Cursor <cursoragent@cursor.com>
@openshift-ci

openshift-ci Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

@sradco: all tests passed!

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

@PeterYurkovich PeterYurkovich 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.

If there is an operator owned alert in a non-platform namespace is there any way to manage labels?

@simonpasquier

Copy link
Copy Markdown
Contributor

/cc @simonpasquier

@openshift-ci openshift-ci Bot requested a review from simonpasquier July 16, 2026 14:40
"github.com/openshift/monitoring-plugin/test/e2e/framework"
)

func TestUpdateAlertRule_DropRestore(t *testing.T) {

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.

Do we have tests verifying that requests with unauthorized users are denied?

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.

Ideally we need to cover

  • User A has no permission to update PrometheusRule in any namespace
    • Request fails for namespace Y
  • User B has permission to update PrometheusRule in namespace Y
    • Request succeeds for namespace Y
    • Request fails for namespace Z
  • User C has permission to update PrometheusRule in any namespace
    • Request succeeds for namespace Y
    • Request succeeds for namespace Z

@sradco

sradco commented Jul 16, 2026

Copy link
Copy Markdown
Author

If there is an operator owned alert in a non-platform namespace is there any way to manage labels?

Unfortunately no. Users can only silence these alerts. They can then copy them and update to their needs.
This is a know limitation.
I did add a knob, in case that CMO will decide to support ARC also for the non-platform stack.

Address review comments from PeterYurkovich and simonpasquier:

1. Remove redundant isPlatform guard in UpdatePlatformAlertRule. The
   caller (updatePlatformRuleLabels) already guarantees platform context,
   so the AlertingRule CR lookup is now unconditional. The fallback to
   applyLabelChangesViaAlertRelabelConfig still handles cases where no AR
   exists.

2. Add RBAC e2e tests (TestUpdateAlertRule_RBAC) verifying that:
   - User A (no permissions) is denied in any namespace
   - User B (namespace-scoped) succeeds in namespace Y, fails in Z
   - User C (cluster-admin) succeeds everywhere

   Adds framework helpers CreateScopedUser and CreateUnprivilegedUser for
   creating ServiceAccounts with specific RBAC policies and obtaining
   short-lived tokens.

Co-authored-by: Cursor <cursoragent@cursor.com>

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 3

🧹 Nitpick comments (2)
pkg/management/update_platform_alert_rule.go (1)

78-81: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Reuse the notAllowedGitOpsEdit helper.

For consistency and to reduce duplication, reuse the existing notAllowedGitOpsEdit() helper instead of hardcoding the identical error message.

♻️ Proposed refactor
-		if gitOpsManaged, operatorManaged := k8s.IsExternallyManagedObject(ar); gitOpsManaged {
-			return &NotAllowedError{Message: "This alert is managed by GitOps; edit it in Git."}
-		} else if operatorManaged {
+		if gitOpsManaged, operatorManaged := k8s.IsExternallyManagedObject(ar); gitOpsManaged {
+			return notAllowedGitOpsEdit()
+		} else if operatorManaged {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/management/update_platform_alert_rule.go` around lines 78 - 81, In the
GitOps-managed branch of the alert update flow, replace the hardcoded
NotAllowedError construction with the existing notAllowedGitOpsEdit() helper,
preserving the current return behavior and leaving the operator-managed path
unchanged.
pkg/management/alert_rule_preconditions.go (1)

93-105: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consistently use k8s.IsExternallyManagedObject for ARC resources.

Both of these sites check GitOps management for an AlertRelabelConfig by calling k8s.IsManagedByGitOps manually, whereas checks for other resources—and the Operator check for ARCs—use the k8s.IsExternallyManagedObject helper. Consolidating these checks improves consistency and reduces duplicate logic.

  • pkg/management/alert_rule_preconditions.go#L93-L105: consolidate the GitOps and operator checks into a single gitOpsManaged, operatorManaged := k8s.IsExternallyManagedObject(arc) call.
  • pkg/management/alert_rule_preconditions.go#L126-L130: replace the manual GitOps check with gitOpsManaged, _ := k8s.IsExternallyManagedObject(arc); if gitOpsManaged { ... }.
♻️ Proposed refactors

pkg/management/alert_rule_preconditions.go#L93-L105

-	if arc != nil {
-		if k8s.IsManagedByGitOps(arc.Annotations, arc.Labels) {
-			return notAllowedGitOpsEdit()
-		}
-	}
-	// Note: operator-managed rules are intentionally allowed here. The ARC path
-	// modifies a separate AlertRelabelConfig resource, not the operator-managed
-	// PrometheusRule/AlertingRule, so the operator won't reconcile away changes.
-	if arc != nil {
-		if _, operatorManaged := k8s.IsExternallyManagedObject(arc); operatorManaged {
-			return notAllowedOperatorUpdate()
-		}
-	}
+	// Note: operator-managed rules are intentionally allowed to reach this point.
+	// The ARC path modifies a separate AlertRelabelConfig resource, not the
+	// operator-managed PrometheusRule/AlertingRule, so the operator won't
+	// reconcile away changes.
+	if arc != nil {
+		if gitOpsManaged, operatorManaged := k8s.IsExternallyManagedObject(arc); gitOpsManaged {
+			return notAllowedGitOpsEdit()
+		} else if operatorManaged {
+			return notAllowedOperatorUpdate()
+		}
+	}

pkg/management/alert_rule_preconditions.go#L126-L130

-	if arc != nil {
-		if k8s.IsManagedByGitOps(arc.Annotations, arc.Labels) {
-			return notAllowedGitOpsEdit()
-		}
-	}
+	if arc != nil {
+		if gitOpsManaged, _ := k8s.IsExternallyManagedObject(arc); gitOpsManaged {
+			return notAllowedGitOpsEdit()
+		}
+	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/management/alert_rule_preconditions.go` around lines 93 - 105,
Consolidate ARC management detection in
pkg/management/alert_rule_preconditions.go lines 93-105 by using one
k8s.IsExternallyManagedObject(arc) result for both GitOps and operator checks,
preserving their existing rejection behavior. At lines 126-130, replace the
manual k8s.IsManagedByGitOps check with the helper’s GitOps result while
ignoring the operator result.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/e2e/framework/framework.go`:
- Around line 228-268: The resource-provisioning flow around the visible
ServiceAccount, Role, RoleBinding, and token creation calls must roll back
resources created earlier when a later step fails. Track creation ownership,
delete previously created resources before each error return, and update
CreateUnprivilegedUser to remove its ServiceAccount when token creation fails;
preserve AlreadyExists resources rather than deleting them.
- Around line 270-275: Stop discarding errors across the cleanup flows: in
test/e2e/framework/framework.go lines 270-275, update the cleanup closure to
attempt every deletion and return aggregated errors; at lines 298-301, return
the ServiceAccount deletion error. In test/e2e/update_alert_rule_test.go lines
263, 269, 283, and 291, register or report cleanup errors through the test
cleanup mechanisms for the relevant resources. At lines 367-369, handle the
io.ReadAll error before logging the response body.

In `@test/e2e/update_alert_rule_test.go`:
- Around line 296-318: Update the denied-case assertions in
UserA_NoPerms_FailsNamespaceY and UserB_ScopedPerms_FailsNamespaceZ to require
http.StatusForbidden exactly, replacing the current non-204 checks. Keep the
existing success assertion for UserB_ScopedPerms_SucceedsNamespaceY unchanged.

---

Nitpick comments:
In `@pkg/management/alert_rule_preconditions.go`:
- Around line 93-105: Consolidate ARC management detection in
pkg/management/alert_rule_preconditions.go lines 93-105 by using one
k8s.IsExternallyManagedObject(arc) result for both GitOps and operator checks,
preserving their existing rejection behavior. At lines 126-130, replace the
manual k8s.IsManagedByGitOps check with the helper’s GitOps result while
ignoring the operator result.

In `@pkg/management/update_platform_alert_rule.go`:
- Around line 78-81: In the GitOps-managed branch of the alert update flow,
replace the hardcoded NotAllowedError construction with the existing
notAllowedGitOpsEdit() helper, preserving the current return behavior and
leaving the operator-managed path unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: 1c017622-1e8b-444c-a4d1-ffbe66c19dc9

📥 Commits

Reviewing files that changed from the base of the PR and between b437a23 and aa760ff.

📒 Files selected for processing (5)
  • internal/managementrouter/api_generated.go
  • pkg/management/alert_rule_preconditions.go
  • pkg/management/update_platform_alert_rule.go
  • test/e2e/framework/framework.go
  • test/e2e/update_alert_rule_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • internal/managementrouter/api_generated.go

Comment on lines +228 to +268
if _, err := f.Clientset.CoreV1().ServiceAccounts(namespace).Create(ctx, sa, metav1.CreateOptions{}); err != nil && !apierrors.IsAlreadyExists(err) {
return nil, fmt.Errorf("creating service account %s/%s: %w", namespace, name, err)
}

role := &rbacv1.Role{
ObjectMeta: metav1.ObjectMeta{Name: name},
Rules: []rbacv1.PolicyRule{{
APIGroups: []string{apiGroup},
Resources: resources,
Verbs: verbs,
}},
}
if _, err := f.Clientset.RbacV1().Roles(namespace).Create(ctx, role, metav1.CreateOptions{}); err != nil && !apierrors.IsAlreadyExists(err) {
return nil, fmt.Errorf("creating role %s/%s: %w", namespace, name, err)
}

rb := &rbacv1.RoleBinding{
ObjectMeta: metav1.ObjectMeta{Name: name},
Subjects: []rbacv1.Subject{{
Kind: rbacv1.ServiceAccountKind,
Name: name,
Namespace: namespace,
}},
RoleRef: rbacv1.RoleRef{
APIGroup: rbacv1.GroupName,
Kind: "Role",
Name: name,
},
}
if _, err := f.Clientset.RbacV1().RoleBindings(namespace).Create(ctx, rb, metav1.CreateOptions{}); err != nil && !apierrors.IsAlreadyExists(err) {
return nil, fmt.Errorf("creating role binding %s/%s: %w", namespace, name, err)
}

expSeconds := int64(3600)
treq := &authv1.TokenRequest{
Spec: authv1.TokenRequestSpec{ExpirationSeconds: &expSeconds},
}
tokenResp, err := f.Clientset.CoreV1().ServiceAccounts(namespace).CreateToken(ctx, name, treq, metav1.CreateOptions{})
if err != nil {
return nil, fmt.Errorf("requesting token for %s/%s: %w", namespace, name, err)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Roll back resources when user provisioning fails.

Role, RoleBinding, or token creation failures leave previously created resources behind. Track which resources were created and delete them before returning each error; CreateUnprivilegedUser should similarly remove its ServiceAccount if token creation fails.

Also applies to: 285-296

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/e2e/framework/framework.go` around lines 228 - 268, The
resource-provisioning flow around the visible ServiceAccount, Role, RoleBinding,
and token creation calls must roll back resources created earlier when a later
step fails. Track creation ownership, delete previously created resources before
each error return, and update CreateUnprivilegedUser to remove its
ServiceAccount when token creation fails; preserve AlreadyExists resources
rather than deleting them.

Comment on lines +270 to +275
cleanup := func() error {
_ = f.Clientset.RbacV1().RoleBindings(namespace).Delete(ctx, name, metav1.DeleteOptions{})
_ = f.Clientset.RbacV1().Roles(namespace).Delete(ctx, name, metav1.DeleteOptions{})
_ = f.Clientset.CoreV1().ServiceAccounts(namespace).Delete(ctx, name, metav1.DeleteOptions{})
return nil
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Propagate and assert cleanup errors.

These sites discard errors, hiding leaked cluster resources and currently triggering errcheck.

  • test/e2e/framework/framework.go#L270-L275: attempt every deletion and return their aggregated errors.
  • test/e2e/framework/framework.go#L298-L301: return the ServiceAccount deletion error.
  • test/e2e/update_alert_rule_test.go#L263-L263: register cleanup with t.Cleanup and report its error.
  • test/e2e/update_alert_rule_test.go#L269-L269: report namespace cleanup failures.
  • test/e2e/update_alert_rule_test.go#L283-L283: report user cleanup failures.
  • test/e2e/update_alert_rule_test.go#L291-L291: report scoped-user cleanup failures.
  • test/e2e/update_alert_rule_test.go#L367-L369: handle the io.ReadAll error before logging the body.

As per path instructions, “Never ignore error returns.” As per coding guidelines, “required CI checks must pass before merging.”

📍 Affects 2 files
  • test/e2e/framework/framework.go#L270-L275 (this comment)
  • test/e2e/framework/framework.go#L298-L301
  • test/e2e/update_alert_rule_test.go#L263-L263
  • test/e2e/update_alert_rule_test.go#L269-L269
  • test/e2e/update_alert_rule_test.go#L283-L283
  • test/e2e/update_alert_rule_test.go#L291-L291
  • test/e2e/update_alert_rule_test.go#L367-L369
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/e2e/framework/framework.go` around lines 270 - 275, Stop discarding
errors across the cleanup flows: in test/e2e/framework/framework.go lines
270-275, update the cleanup closure to attempt every deletion and return
aggregated errors; at lines 298-301, return the ServiceAccount deletion error.
In test/e2e/update_alert_rule_test.go lines 263, 269, 283, and 291, register or
report cleanup errors through the test cleanup mechanisms for the relevant
resources. At lines 367-369, handle the io.ReadAll error before logging the
response body.

Sources: Coding guidelines, Path instructions, Linters/SAST tools

Comment on lines +296 to +318
t.Run("UserA_NoPerms_FailsNamespaceY", func(t *testing.T) {
status := bulkUpdateLabelsWithToken(t, f, ctx, userA.Token, ruleIDY)
if status == http.StatusNoContent {
t.Fatalf("Expected user A to be denied, got per-rule status 204")
}
t.Logf("User A correctly denied for namespace Y (per-rule status: %d)", status)
})

t.Run("UserB_ScopedPerms_SucceedsNamespaceY", func(t *testing.T) {
status := bulkUpdateLabelsWithToken(t, f, ctx, userB.Token, ruleIDY)
if status != http.StatusNoContent {
t.Fatalf("Expected user B to succeed in namespace Y, got per-rule status %d", status)
}
t.Log("User B correctly allowed for namespace Y")
})

t.Run("UserB_ScopedPerms_FailsNamespaceZ", func(t *testing.T) {
status := bulkUpdateLabelsWithToken(t, f, ctx, userB.Token, ruleIDZ)
if status == http.StatusNoContent {
t.Fatalf("Expected user B to be denied for namespace Z, got per-rule status 204")
}
t.Logf("User B correctly denied for namespace Z (per-rule status: %d)", status)
})

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Require the expected authorization failure status.

Both denied cases pass for any non-204 result, including 404 or 500. Assert the documented authorization status—normally http.StatusForbidden—so unrelated failures cannot satisfy the RBAC test.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/e2e/update_alert_rule_test.go` around lines 296 - 318, Update the
denied-case assertions in UserA_NoPerms_FailsNamespaceY and
UserB_ScopedPerms_FailsNamespaceZ to require http.StatusForbidden exactly,
replacing the current non-204 checks. Keep the existing success assertion for
UserB_ScopedPerms_SucceedsNamespaceY unchanged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

jira/valid-reference Indicates that this PR references a valid Jira ticket of any type.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants