You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The Violations tab needs two per-row fields that don't exist today, both on ViolationRecord, both computable at merge time with data that already flows through the pipeline.
Occurrences. We only expose status.violationCount, a policy-level aggregate incremented in mergeScrapedViolations() for every scraped record — it can't be decomposed into "how many times did this executable/container/pod combo fire". The UI needs a per-row count distinct from that aggregate.
Age.ViolationRecord.timestamp is refreshed to the newest occurrence on every merge (the if v.Timestamp.After(...) branch), so it's a last-seen time. There's no first-seen timestamp to compute age from, and id is a monotonic counter, not wall-clock, so it can't stand in.
Both are cheap because the agent already buffers one record per violation event (violationbuf.Buffer.Record() once per reportViolation, 10k ring buffer) and the controller sees every raw event at merge — it just discards the count on dedup and never remembers the first sighting. So this is controller-side only: no agent/proto/BPF change. The existing Last Occurrence column keeps deriving from timestamp; only Occurrences and Age are new.
We should add occurrences (init 1 on first observation, ++ on each matched duplicate) and firstObservedTimestamp (set once at creation, never mutated).
Notes:
occurrences: new records init 1, matched records occurrences++. The merge loop iterates every scraped event, so multiple duplicates in one batch are counted naturally.
occurrences stays distinct from violationCount — the latter (per its own doc-comment) includes trimmed/cleared records and isn't strongly consistent, so don't try to make them reconcile exactly.
firstObservedTimestamp: set in the new-record (else) branch from the scraped event's own timestamp (the earliest we know of), nottime.Now(); never touch it on a match — that's the whole point vs timestamp.
Mark both +optional; occurrences gets +kubebuilder:default=1.
No agent/proto/BPF change; metav1.Time deepcopy is handled by codegen.
api/v1alpha1/violation_record.go: add Occurrences int64 and FirstObservedTimestamp metav1.Time to ViolationRecord; in mergeScrapedViolations() set occurrences: 1 + firstObservedTimestamp in the new-record branch, and s.Violations[idx].Occurrences++ in the matched branch.
api/v1alpha1/violation_record_test.go: assert per-record counts across multi-batch merges and across the maxViolationRecords trim; assert firstObservedTimestamp is stamped on creation and stays stable across re-scrapes while timestamp advances.
The Violations tab needs two per-row fields that don't exist today, both on
ViolationRecord, both computable at merge time with data that already flows through the pipeline.Occurrences. We only expose
status.violationCount, a policy-level aggregate incremented inmergeScrapedViolations()for every scraped record — it can't be decomposed into "how many times did this executable/container/pod combo fire". The UI needs a per-row count distinct from that aggregate.Age.
ViolationRecord.timestampis refreshed to the newest occurrence on every merge (theif v.Timestamp.After(...)branch), so it's a last-seen time. There's no first-seen timestamp to compute age from, andidis a monotonic counter, not wall-clock, so it can't stand in.Both are cheap because the agent already buffers one record per violation event (
violationbuf.Buffer.Record()once perreportViolation, 10k ring buffer) and the controller sees every raw event at merge — it just discards the count on dedup and never remembers the first sighting. So this is controller-side only: no agent/proto/BPF change. The existingLast Occurrencecolumn keeps deriving fromtimestamp; onlyOccurrencesandAgeare new.We should add
occurrences(init1on first observation,++on each matched duplicate) andfirstObservedTimestamp(set once at creation, never mutated).Notes:
occurrences: new records init1, matched recordsoccurrences++. The merge loop iterates every scraped event, so multiple duplicates in one batch are counted naturally.occurrencesstays distinct fromviolationCount— the latter (per its own doc-comment) includes trimmed/cleared records and isn't strongly consistent, so don't try to make them reconcile exactly.firstObservedTimestamp: set in the new-record (else) branch from the scraped event's own timestamp (the earliest we know of), nottime.Now(); never touch it on a match — that's the whole point vstimestamp.+optional;occurrencesgets+kubebuilder:default=1.metav1.Timedeepcopy is handled by codegen.Touchpoints:
api/v1alpha1/violation_record.go: addOccurrences int64andFirstObservedTimestamp metav1.TimetoViolationRecord; inmergeScrapedViolations()setoccurrences: 1+firstObservedTimestampin the new-record branch, ands.Violations[idx].Occurrences++in the matched branch.api/v1alpha1/violation_record_test.go: assert per-record counts across multi-batch merges and across themaxViolationRecordstrim; assertfirstObservedTimestampis stamped on creation and stays stable across re-scrapes whiletimestampadvances.make manifests generate), anddocs/crd.adoc/docs/crds.