Skip to content

CMP-4373: Fix stale compliance_state metric and suite result#1263

Open
Vincent056 wants to merge 2 commits into
masterfrom
cmp-4373-stale-compliance-state-metric
Open

CMP-4373: Fix stale compliance_state metric and suite result#1263
Vincent056 wants to merge 2 commits into
masterfrom
cmp-4373-stale-compliance-state-metric

Conversation

@Vincent056

Copy link
Copy Markdown

What

The ComplianceSuite controller could report a stale compliance result —
oc get compliancesuite / the compliance_operator_compliance_state gauge /
ScanSettingBinding events showing NON-COMPLIANT while the underlying
ComplianceScan was COMPLIANT — until the operator pod was restarted. This is CMP-4373.

Root cause

updateScanStatus refreshed the suite status (and therefore the metric and the
events derived from it) only on a scan phase transition:

if scanStatusWrap.Phase == scan.Status.Phase {
    return nil
}

A rescan returns a scan to the same terminal phase (DONE) it started from, so
when only the result changed (e.g. NON-COMPLIANT → COMPLIANT after
remediation) the phase-only check skipped the update and the suite result went stale.

Two related gauge-lifecycle gaps made it worse: compliance_state lives only in
the operator's in-memory registry and was written exclusively on that transition
path and never cleaned up — so a live suite could be missing from metrics after
a restart, and a deleted suite left a stale series firing alerts indefinitely.

Fix

  • Compare the scan result as well as the phase in updateScanStatus.
  • Re-assert compliance_state from the authoritative suite.Status.Result on
    every reconcile of a Done suite (survives operator restart).
  • Delete the compliance_state series for a suite in suiteDeleteHandler.

Tests

  • New unit regression test: a scan whose result flips while its phase stays DONE
    must update the suite result. Fails on master, passes with this change.
  • Verified end-to-end on an OCP 4.22 cluster: reproduced all three behaviours on
    the released 1.9.1 image (stale value, absent-after-restart, ghost-on-delete) and
    confirmed each is resolved by this build.

Jira

CMP-4373

@openshift-ci

openshift-ci Bot commented Jun 25, 2026

Copy link
Copy Markdown

Skipping CI for Draft Pull Request.
If you want CI signal for your change, please convert it to an actual PR.
You can still manually trigger a test run with /test all

@openshift-ci-robot

Copy link
Copy Markdown
Collaborator

@Vincent056: This pull request references CMP-4373 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the bug to target the "5.0.0" version, but no target version was set.

Details

In response to this:

What

The ComplianceSuite controller could report a stale compliance result —
oc get compliancesuite / the compliance_operator_compliance_state gauge /
ScanSettingBinding events showing NON-COMPLIANT while the underlying
ComplianceScan was COMPLIANT — until the operator pod was restarted. This is CMP-4373.

Root cause

updateScanStatus refreshed the suite status (and therefore the metric and the
events derived from it) only on a scan phase transition:

if scanStatusWrap.Phase == scan.Status.Phase {
   return nil
}

A rescan returns a scan to the same terminal phase (DONE) it started from, so
when only the result changed (e.g. NON-COMPLIANT → COMPLIANT after
remediation) the phase-only check skipped the update and the suite result went stale.

Two related gauge-lifecycle gaps made it worse: compliance_state lives only in
the operator's in-memory registry and was written exclusively on that transition
path and never cleaned up — so a live suite could be missing from metrics after
a restart, and a deleted suite left a stale series firing alerts indefinitely.

Fix

  • Compare the scan result as well as the phase in updateScanStatus.
  • Re-assert compliance_state from the authoritative suite.Status.Result on
    every reconcile of a Done suite (survives operator restart).
  • Delete the compliance_state series for a suite in suiteDeleteHandler.

Tests

  • New unit regression test: a scan whose result flips while its phase stays DONE
    must update the suite result. Fails on master, passes with this change.
  • Verified end-to-end on an OCP 4.22 cluster: reproduced all three behaviours on
    the released 1.9.1 image (stale value, absent-after-restart, ghost-on-delete) and
    confirmed each is resolved by this build.

Jira

CMP-4373

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 commented Jun 25, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: Vincent056

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

The ComplianceSuite controller only refreshed the suite status and the
compliance_state gauge on a scan *phase* transition. A rescan returns a
scan to the same terminal phase (DONE) it started from, so when only the
*result* changed (e.g. NON-COMPLIANT -> COMPLIANT after remediation) the
phase-only check in updateScanStatus skipped the update, leaving the suite
status, the ScanSettingBinding/Policy events, and the compliance_state
gauge reporting a stale value until the operator was restarted.

The gauge also lives only in the operator's in-memory registry and was
written exclusively on that transition path and never cleaned up. As a
result a live suite could be missing from metrics after a restart, and a
deleted suite left a stale series firing alerts indefinitely.

Fix:
- Compare the scan result as well as the phase in updateScanStatus so a
  result change at an unchanged phase is no longer skipped.
- Re-assert compliance_state from the authoritative suite result on every
  reconcile of a Done suite, so the gauge survives an operator restart.
- Delete the compliance_state series for a suite in suiteDeleteHandler so
  deleted suites stop being reported.

Add a regression test covering the result-changed-without-phase-change
case.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@Vincent056 Vincent056 force-pushed the cmp-4373-stale-compliance-state-metric branch from feb92d8 to 6a57249 Compare June 25, 2026 16:31
@github-actions

Copy link
Copy Markdown

🤖 To deploy this PR, run the following command:

make catalog-deploy CATALOG_IMG=ghcr.io/complianceascode/compliance-operator-catalog:1263-feb92d872c724476b070d3ef27413df1d33fc3cc

@github-actions

Copy link
Copy Markdown

🤖 To deploy this PR, run the following command:

make catalog-deploy CATALOG_IMG=ghcr.io/complianceascode/compliance-operator-catalog:1263-6a572494276caecc0c07b3579f0eaa03533f1185

Adds TestComplianceStateMetricSurvivesOperatorRestart (serial) covering the
two deterministically reproducible facets of CMP-4373:

- the compliance_state gauge is re-synced from the suite status after an
  operator restart (before the fix the in-memory series was lost), and
- the series is removed when the suite is deleted (before the fix a stale
  NON-COMPLIANT value lingered).

A NON-COMPLIANT platform scan is used so the gauge value (1) is
distinguishable from an absent series, which parses as 0. Adds a
RestartComplianceOperator framework helper used by the test.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

🤖 To deploy this PR, run the following command:

make catalog-deploy CATALOG_IMG=ghcr.io/complianceascode/compliance-operator-catalog:1263-f00b444a1bb0d826eee95b7256b2cc783e8e174e

@Vincent056 Vincent056 marked this pull request as ready for review July 1, 2026 15:03
@taimurhafeez

Copy link
Copy Markdown
Collaborator

/test e2e-aws-parallel

@openshift-ci

openshift-ci Bot commented Jul 3, 2026

Copy link
Copy Markdown

@Vincent056: The following test failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/e2e-aws-parallel f00b444 link true /test e2e-aws-parallel

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.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants