Add not_applicable compliance control status

What does this MR do and why?

Adds not_applicable as a status for compliance controls. Use it when a control can't be evaluated for a project, for example because the resource it checks doesn't exist. Before this change, those controls had to be reported as pass, fail, or pending, which made compliance reports misleading.

  • Adds not_applicable: 3 to the control status enum. No migration is needed because the status column has no CHECK constraint.
  • Lets external controls set not_applicable, the same way they set pass and fail. This applies to both UpdateStatusService and the PATCH .../compliance_external_controls/:control_id/status REST endpoint. pending still can't be set from outside.
  • Adds a compliance_control_status_not_applicable audit event type. The service builds the audit event name from the new status, so the new value needs its own type definition.
  • The GraphQL ProjectComplianceControlStatus enum gets NOT_APPLICABLE ("Not applicable") automatically, because it is built from the Rails enum with each_key.
  • Updates the generated GraphQL reference, OpenAPI spec, and audit event types docs.
Differences from the workplan
  • No explicit GraphQL value 'NOT_APPLICABLE' override. 'not_applicable'.humanize already returns "Not applicable". Our GraphQL guidelines say to build enum values from the Rails enum with each_key, so an override would duplicate what the loop already does.
  • REST API allowlist updated. API::ComplianceExternalControls::VALID_STATUS_VALUES has its own %w[pass fail] list, separate from the service. Without this change, the planned update to compliance_external_controls_spec.rb would fail with a 400.
  • New audit event type YAML. The workplan didn't include this, but the audit event fails validation without it.

Out of scope (sibling tasks under https://gitlab.com/gitlab-org/gitlab/-/work_items/621132)

Until https://gitlab.com/gitlab-org/gitlab/-/work_items/622256 lands, RefreshStatusService ignores not_applicable controls when it counts statuses.

References

Screenshots or screen recordings

Not applicable: backend only.

How to set up and validate locally

  1. Set up an Ultimate project with a compliance framework that has an external control.

  2. In the Rails console:

    control = ComplianceManagement::ComplianceFramework::ComplianceRequirementsControl.external.last
    project = Project.find(<id>)
    ComplianceManagement::ComplianceFramework::ComplianceRequirementsControls::UpdateStatusService
      .new(current_user: User.first, control: control, project: project, status_value: 'not_applicable')
      .execute
    # => success, payload: { status: "not_applicable" }
  3. In GraphiQL, check that ProjectComplianceControlStatus includes NOT_APPLICABLE.

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

Merge request reports

Loading
Loading