Repository navigation
feat(security): bridge live-only Kubescape findings into deduped backlog issuesΒ #2854
Description
π€ Generated by the Agentic Engineer
Part of #2451 (second of its two remaining slices). The first slice β the SARIF β Code Scanning gate β shipped in #2829/#2846 and is closed.
Evidence
The prevention gate now covers what a repo scan can see. It cannot see anything that only exists once workloads are running, and the survey the engineer drains its backlog from is GitHub-only. So live-only findings currently reach the backlog exactly when a human happens to file them, which is the structural reason posture drift went unnoticed for long stretches.
The API surface the bridge needs is present on the live cluster (verified 2026-07-29 by read-only api-resources, spdx.softwarecomposition.kubescape.io/v1beta1):
vulnerabilitymanifestsummaries,vulnerabilitysummariesβ CVE state per workload/clusterconfigurationscansummaries,workloadconfigurationscansummariesβ posture control state- plus the runtime alert state under
kubescape.io/v1
So this slice is buildable against real objects rather than a hypothesis.
Problem
Findings that exist only at runtime never become tracked work. Without an ingestion path they are invisible to oldest-first draining, and posture regressions are noticed by chance rather than by process.
Proposed direction
A scheduled job that reads those summaries read-only and opens, updates, and closes themed security issues β one per control or CVE theme, never one per resource.
Idempotency is the whole difficulty and should be treated as the primary design constraint, not an afterthought:
- a stable fingerprint per theme, so a re-run updates rather than re-files
- search-before-create against open and recently-closed issues
- close-when-gone, so a resolved finding stops occupying the backlog
- ship report-only first β emit what it would file, verify the fingerprints are stable across consecutive runs, and only then enable issue writes
Success signal
Baseline: live-only findings entering the backlog by process today β none. Target: every themed live-only finding is represented by exactly one open issue while it exists, and none after it is resolved. Guardrail: the run-over-run issue-churn count stays at zero for unchanged cluster state β a bridge that re-files or re-opens on a quiet cluster is a failure, not a partial success.
Acceptance criteria
- Report-only mode lands first and demonstrates stable fingerprints across at least two consecutive runs on unchanged state.
- Enabled writes produce at most one open issue per theme; a resolved finding is closed automatically.
- No issue spam: unchanged cluster state produces zero writes.
- Findings bodies carry the sanitized minimum β control/CVE class and affected public component β with detailed reachability evidence kept out of the public issue.
Rough size: MβL. Feature-flagged (report-only is the default-off state), per the feature-flag-first rule.
Metadata
Metadata
Assignees
Labels
Type
Fields
Priority
Start date
Target date
Effort
Projects
- StatusShow more project fieldsπ§ Icebox
Activity
coderabbitai commentedon Jul 29, 2026
π Related PRs
#2316 - fix(kubescape): make ClusterSecurityException posture exceptions take effect [merged]
#2443 - fix(kubescape): keep scheduled posture scans local so results persist [merged]
#2794 - fix(opencost): restore usage metrics [merged]
#2830 - feat(ci): publish Kubescape posture findings to Code Scanning [merged]
#2847 - fix(ci): report what the Kubescape scan actually found [merged]
π Issue Planner
Check the box below or use the
@coderabbitai plancommand to generate an implementation plan and prompts that you can use with your favorite coding assistant.π§ͺ Issue enrichment is currently in open beta.
You can configure auto-planning by selecting labels in the issue_enrichment configuration.
To disable automatic issue enrichment, add the following to your
.coderabbit.yaml:π¬ Have feedback or questions? Drop into our discord!
feat(security): derive themed, deduped backlog entries from live Kubeβ¦
devantler commentedon Aug 1, 2026
Claimed and in progress β the report-only half is up as a draft in #2876 (branch
claude/kubescape-backlog-bridge-2854). This issue deliberately stays open for the write half.Shipped in #2876: theme derivation (one entry per failed control / per CVE severity class, never per resource), stable fingerprints excluding counts and timestamps, sanitized component rendering,
-modegating with writes refused, and CI coverage.Still outstanding here: search-before-create against open and recently-closed issues, at-most-one-open-issue-per-theme on enabled writes, and close-when-gone.
One design constraint discovered while building, worth knowing before touching this: Kubescape's apiserver returns spec-stripped objects on LIST. The same workload reads
critical=0viakubectl get <crd> -A -o jsonandcritical=18via a per-objectGET;vulnerabilitymanifestslikewise read 0 matches on LIST and 509 on GET. Anything built here must read per-object or it will report a spotless cluster indefinitely. #2876 rejects that input shape rather than trusting it.devantler commentedon Aug 2, 2026
Acceptance criterion 1 is now demonstrated on live prod data
The tool's own
-mode=writerefusal names this as the gate for the next slice: "the issue-writinghalf lands behind the same flag once fingerprint stability is demonstrated on consecutive runs."
That demonstration had not been run. It has now.
Inputs. Every Kubescape summary object fetched individually from
admin@prodβ 2198workloadconfigurationscansummaries+ 114vulnerabilitymanifestsummaries= 2312 objects. Per-objectGETs throughout, never a LIST: the storage apiserver returns spec-stripped skeletons on LIST, which is
the false-all-clear this command's own guard exists to prevent. Exceptions from
go run ./scripts/generate-kubescape-exceptions(21 policies).Result. 63 themes, 1408 posture findings excepted, exit 0 on every run.
Two consecutive fresh fetches β necessary, but weak on its own
Fetch β run β re-fetch β run produced a byte-identical report.
Stated honestly: the two fetches were themselves byte-identical (Kubescape had not rescanned in the
interval), so this run pair only shows the pipeline is deterministic over identical bytes. That is
worth having, and it is not by itself evidence that volatile fields are excluded from the
fingerprint. So I ran two controls that are.
Control A β volatile fields perturbed, fingerprints must not move
resourceVersion,uidandcreationTimestamprewritten to sentinels on all 2312 objects(verified landed: 2198 posture files carry the sentinel
resourceVersion).Result: all 63 fingerprints unchanged. This is the substantive stability guarantee β it holds even
when the apiserver re-emits every object with fresh metadata, which is precisely what a scheduled
re-run will see.
Control B β identity changed, fingerprints must move by an expected amount
Control
C-0002renamed toC-9999across the 180 objects carrying it.Result: exactly 1 fingerprint removed, 1 added. Without this, Control A's green would be equally
consistent with a fingerprint that ignores its input entirely.
Incidental finding β the fail-closed guard works
The first attempt at Control B renamed only the map key and left the inner
controlID. The toolrefused the whole run: "keys a control as C-9999 but its controlID is C-0002; refusing to guess which
control an exception should match." Exactly right, and worth recording as covered behaviour.
What this unblocks
Criterion 1 is met. The remaining criteria are all write-side (one open issue per theme,
close-when-gone, zero writes on unchanged state, sanitized bodies), so the issue-writing half is now
free to proceed behind the same default-off flag.
Two notes for whoever takes it:
deliberately whether to cap the first run or seed it in severity order, because "no issue spam" is
easy to satisfy on steady state and easy to violate on day one.
remainder. Any write-side dedup must key off the same fingerprint, not off the raw finding set.
Evidence gathered read-only. No cluster mutation, no issue writes. Detailed per-resource output is
deliberately not reproduced here β the sanitized minimum only, per the publication rule.
feat(security): reconcile live Kubescape findings into deduped backloβ¦
fix(security): neutralise active GitHub syntax in scanner-derived issβ¦