Skip to content

fix(nb-36647): drop the image from Job-collapsed backoff fingerprints - #582

Open
mayankpande88 wants to merge 3 commits into
mainfrom
fix/nb-36647-imagepull-drop-image-for-job-family
Open

fix(nb-36647): drop the image from Job-collapsed backoff fingerprints#582
mayankpande88 wants to merge 3 commits into
mainfrom
fix/nb-36647-imagepull-drop-image-for-job-family

Conversation

@mayankpande88

@mayankpande88 mayankpande88 commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

What

Follow-up to #580, found by verifying that change on the dev cluster rather than trusting the projection in its PR body.

#580 collapsed a Job owner to its family so repeated runs of one logical job would share a fingerprint — but kept the failing image in the hash. For a one-Job-per-image creator the image is the per-run identity, so it re-forked the fingerprint immediately and the collapse achieved nothing.

Observed in nudgebee-agent-dev ~25 minutes after #580 rolled out — every scan Job still had its own fingerprint:

trivy-image-scan-020c9475  fp 3f485711404c  .../nudgebee-ticket-server:2026-08-20T09-31-55_2a48d6b
trivy-image-scan-9d22cbf9  fp 5d64210242b4  .../nudgebee-llm-server:2026-08-20T09-12-54_b8f84d9
trivy-image-scan-73c22c16  fp e885087c86bd  .../nudgebee-benchmark-server:2026-08-20T09-34-41_2a48d6b

This drops the image from the fingerprint only when a Job owner was collapsed. Ordinary workloads keep it, so a single typo'd container is still its own Finding. The failing image stays in the evidence blocks either way — it just no longer forks the identity.

Whose noise this actually fixes — read this before the numbers

30 days of production kubernetes_api_server events come from exactly two places: our own tenants (Nudgebee + the iteration-* demo tenants) and one customer, "mohan's Org" / blinq-k8s. Every other tenant with a registered k8s account emits via prometheus / Azure_Monitor_Alert / pagerduty_webhook — they are not on the Go agent yet. So the population this PR measurably affects is us plus one customer.

For that customer, image_pull_backoff_reporter has 1 fingerprint in 30 days. The headline below is our own image scanner running against our own dev registry.

owner kind fingerprints today after
job 3,961 9
deployment 35 35
daemonset 8 8
statefulset 3 3
(none) 20 17

That is still worth doing — it is a real defect and our demo tenants are what prospects look at — but it should not be read as customer-facing impact. The customer-facing part of this work is the ConfigurationChange fix in #580, which is validated on blinq's own application workloads (blinq-prediction-hasura-graph: 618 events, 618 fingerprints, max occurrence 1) and rests on a structural cause — resourceVersion advances on every write in every cluster — rather than on our sample.

The one genuine customer benefit here is indirect: 25 of blinq's 27 job_failure fingerprints are kube-bench-scan-* in the nudgebee-agent namespace — our own agent's scanner generating noise inside their cluster. The job-family collapse takes that to 1. Their two real jobs (blinq-api-healthchecks, CronJob-owned; blinq-clob-indexer-cleardb, no generated suffix) are untouched.

cd runner && make validate — exit 0, 37 packages, no failures.

Correction to #580

That PR claimed image_pull_backoff 4,008 -> 72, labelled "excl. image component". The caveat was doing all the work: I measured the collapse with the image excluded and then shipped code that included it. The ConfigurationChange and job_failure numbers in #580 were not affected and are confirmed working on dev — kube-system/calico-typha produced 4 config-change events over 11 minutes on a single fingerprint, occurrence 1 -> 4, against a 14-day pre-fix baseline of 1,871 chains all stuck at occurrence 1.

Risk

Two different unpullable images within one scan-Job family now collapse to one Finding with a climbing occurrence count instead of one Finding each. That is the intended grouping — "the scanner cannot pull images" is one problem — and the per-image detail is preserved in evidence.

JobFamily is calibrated on a thin sample. It strips -<digits> / -<8+ hex> / -<uuid> tails, and the five job-name families in the data are trivy-image-scan, kube-bench-scan, pinot-segment-push-v2, grade-astropy--astropy and blinq-api-healthchecks — three of them ours. The only customer job names available to test against are two, and neither exercises the heuristic. A customer running etl-20240101 / etl-20240102 gets the intended grouping; one running genuinely unrelated report-a1b2c3d4 and report-deadbeef would see them merged. There is no data to bound that today. If it becomes a problem, the containment is to restrict stripping to CronJob-owned Jobs plus an explicit prefix allowlist.

Part of nudgebee/nudgebee-enterprise#36647

@mayankpande88
mayankpande88 requested a review from a team as a code owner August 20, 2026 11:18
@github-actions

Copy link
Copy Markdown
Contributor

📦 Image Tags Updated

I've automatically updated the image tags in `charts/nudgebee-agent/values.yaml` to the latest versions from GHCR for the `main` branch.

The image tags are now synchronized with the latest builds and ready for release.

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request updates the fingerprinting logic for the image_pull_backoff matcher. For Job-owned Pods, the failing image is now excluded from the fingerprint to prevent fingerprint fanout in one-Job-per-image workflows, while image-based discrimination is retained for non-Job workloads. Unit tests have been added to verify these behaviors. Feedback was provided to optimize FingerprintFn by avoiding the unconditional call to firstFailingImage(obj) when the owner is a Job, which prevents unnecessary heap allocations and CPU overhead on a hot path.

Comment thread runner/pkg/triggers/predicates.go Outdated
mayankpande88 added a commit that referenced this pull request Aug 20, 2026
Review feedback on #582: the image was computed and then discarded for
every Job-owned Pod, walking all container statuses for a result the
fingerprint never uses. Hoist the job-owned check and compute the image
only when it is part of the identity. No behaviour change.
@github-actions

Copy link
Copy Markdown
Contributor

📦 Image Tags Updated

I've automatically updated the image tags in `charts/nudgebee-agent/values.yaml` to the latest versions from GHCR for the `main` branch.

The image tags are now synchronized with the latest builds and ready for release.

Follow-up to #580, caught verifying that change on the dev cluster.

#580 collapsed a Job owner to its family so repeated runs would share a
fingerprint, but kept the failing image in the hash. For a one-Job-per-
image creator the image IS the per-run identity, so it re-forked the
fingerprint immediately: after #580 shipped, every trivy-image-scan Job
in nudgebee-agent-dev still had its own fingerprint, each pulling a
different image under scan.

Drop the image only when we collapsed a Job owner. Ordinary workloads
keep it, so a single typo'd container is still its own Finding. The
failing image remains in the evidence blocks either way.

Measured on 30d of prod: job-owned 3961 -> 9 fingerprints. Every other
owner kind is unchanged (deployment 35, daemonset 8, statefulset 3) —
the image component only ever forked identity for Job-owned Pods.
Review feedback on #582: the image was computed and then discarded for
every Job-owned Pod, walking all container statuses for a result the
fingerprint never uses. Hoist the job-owned check and compute the image
only when it is part of the identity. No behaviour change.
@mayankpande88
mayankpande88 force-pushed the fix/nb-36647-imagepull-drop-image-for-job-family branch from 094b03e to da3f60f Compare August 20, 2026 14:11
@github-actions

Copy link
Copy Markdown
Contributor

📦 Image Tags Updated

I've automatically updated the image tags in `charts/nudgebee-agent/values.yaml` to the latest versions from GHCR for the `main` branch.

The image tags are now synchronized with the latest builds and ready for release.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant