S Srenix
Docs / DriftReport CRD

Docs

DriftReport CRD

Every active Srenix finding is a cluster-scoped DriftReport custom resource. kubectl get driftreports is your cluster's real-time drift state.

DriftReports are first-class Kubernetes objects. They persist in etcd, appear in kubectl get, work with OPA admission policies, and can be read by ArgoCD ApplicationSet generators and other tooling. The CRD is cluster-scoped (the affected resource's namespace lives in spec.resourceRef.namespace). Each cycle upserts one DriftReport per active diagnostic — re-detecting the same subject updates the existing CR (lastObserved, observationCount), and CRs whose subject no longer appears in the latest run are deleted.

Field reference generated from the chart's CRD (crd-driftreport.yaml, chart 0.1.0-alpha.1, OSS commit d6237fd, synced 2026-06-26). API: driftreports.srenix.ai/v1alpha1, short names drift, drifts.

Spec fields

Field Type Description
subject required string Stable identity for de-duplication across cron ticks. Examples: "Secret/mcp/openproject-secrets/openproject-url", "ExternalSecret/mail/mail-service-api-key", "Service:LiveKit-SIP".
severity required string One of: info | warning | critical.
source required string Producer of the report. One of: probe, analyzer-name, fixer-name. e.g. "Postgres", "SecretKeyMissing", "ProactiveSecretKeyCheck", "StaleErrorPods".
message required string Human-readable description, identical to what would have appeared in Slack. Includes the suggested remediation.
remediation string Optional kubectl-ready hint (a one-liner the operator can paste). Probes set this; analyzers usually embed the hint into `message` instead.
investigation string Layer-2 investigator summary attached when a registered pkg/ai.Investigator (OSS rule-based or paid LLM) produces a root-cause narrative for this finding. Surfaced as a 🔬 block in Slack and Alertmanager payloads.
category string Logical bucket: "probe", "analyzer", "fixer-action", "fixer-skipped". Useful for kubectl filtering. One of: probe | analyzer | fixer-action | fixer-skipped.
resourceRef object The Kubernetes resource the report is about, when identifiable. Allows `kubectl get drifts -l ...`.
resourceRef.apiVersion string
resourceRef.kind string
resourceRef.namespace string
resourceRef.name string
resourceRef.cloud object Set when this drift is about a cloud-provider resource (AWS RDS, GCP Cloud SQL, Azure SQL, etc.) — populated by pkg/cloud probes. Mutually exclusive with the K8s fields above (a drift targets either a K8s object OR a cloud resource, not both).
resourceRef.cloud.provider string aws | gcp | azure One of: aws | gcp | azure.
resourceRef.cloud.region string Cloud region or location (e.g. "us-east-1", "us-central1", "eastus"). Empty for global resources (IAM, KMS).
resourceRef.cloud.service string Cloud service identifier (e.g. "rds", "ebs", "eks", "iam", "alb", "acm", "kms", "s3", "vpc"; "cloudsql", "gke", "lb"; "sql", "aks", "appgw", "keyvault").
resourceRef.cloud.id string Cloud-provider resource identifier. Format varies by provider: AWS uses ARN or short id, GCP uses project/zone/name, Azure uses /subscriptions/.../resourceGroups/...

Status fields

Status is written by Srenix only (a status subresource). There is no open/resolved state machine — an active finding has a DriftReport; a cleared finding's CR is deleted on the next reconcile. The exception is ticket bookkeeping: status.ticket records the external ticket Srenix filed so subsequent cycles don't open duplicates.

Field Type Description
firstObserved string (date-time)
lastObserved string (date-time)
observationCount integer
runID string ID of the most recent srenix run that observed this drift.
ticket object Reference to the external issue-tracker ticket Srenix filed for this unfixable diagnostic. Populated by pkg/ticketing sinks (OpenProject in OSS; Jira / ServiceNow in Srenix Enterprise). Presence means a ticket already exists — Srenix will not open another one on subsequent cycles.
ticket.provider string Sink identifier. One of: "openproject", "jira", "servicenow".
ticket.key string Provider-native ticket key (e.g. "WP-1287", "OPS-42", "INC0012345").
ticket.url string Canonical URL an operator clicks through to view the ticket in the provider UI.
ticket.openedAt string Timestamp when Srenix first filed this ticket. Stable across subsequent cycles. (date-time)
ticket.severity string Severity stamped on the ticket at open / last comment. Lets Srenix detect a severity transition (M2) and comment the change to the existing ticket.
ticket.resolved boolean True once Srenix auto-closed this ticket because the finding cleared (M2 resolve-on-clear). Idempotency guard: Srenix never re-resolves an already-resolved ticket. Cleared back to false if the finding recurs.
ticket.resolvedAt string Timestamp Srenix resolved this ticket on clear (M2). (date-time)
ticket.lastCommentedAt string Timestamp of the most recent recurrence / severity comment Srenix posted. Drives the commentInterval debounce (M2) so a flapping finding can't spam the tracker. (date-time)

kubectl output columns

The CRD registers printer columns, so plain kubectl get driftreports is already useful (no NAMESPACE column — the CRD is cluster-scoped):

Column Type JSONPath
Severity string .spec.severity
Source string .spec.source
Subject string .spec.subject
Last Seen date .status.lastObserved
Count integer .status.observationCount
Ticket string .status.ticket.key

kubectl examples

# List all active findings (cluster-scoped — no namespace flag needed)
kubectl get driftreports
kubectl get drifts          # short name

# Filter by severity (lowercase enum: info | warning | critical)
kubectl get driftreports -o json \
  | jq '.items[] | select(.spec.severity == "critical")'

# Filter by category: probe | analyzer | fixer-action | fixer-skipped
kubectl get driftreports -o json \
  | jq '.items[] | select(.spec.category == "analyzer")'

# Findings about resources in one namespace (namespace lives in resourceRef)
kubectl get driftreports -o json \
  | jq '.items[] | select(.spec.resourceRef.namespace == "mcp")'

# Describe a specific finding (name is a hash of spec.subject)
kubectl describe driftreport <name>

# Watch findings appear/clear in real time
kubectl get driftreports -w

Using DriftReports in GitOps

DriftReports are standard Kubernetes CRs. You can reference them in OPA/Gatekeeper constraints (block deploys while Critical findings reference a namespace), ArgoCD ApplicationSet generators (exclude clusters with drift), or your own controllers via a standard informer on the driftreports.srenix.ai GVR.

← Back to docs