feat(pipeline): close the three named triage gaps (nginx upstream, MDE presence, kernel inventory) #15
Loading…
Reference in a new issue
No description provided.
Delete branch "fm/dse-security-reports-pipeline-gaps"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Closes the three named pipeline gaps from the captain instruction
(2026-10-27): (a) nginx upstream tracking, (b) MDE presence assertion,
(c) running-vs-stale kernel classification. All three are implemented
end to end in both derivation lanes (stdlib scripts/derive_findings.py
and polars src/dse_security_reports/derive.py) so
just py-crosscheckstays byte-identical; nothing real is committed (all caches stay under
gitignored
.local/).What changed
(a) nginx upstream tracking -- complete
just nginx-upstream(
scripts/fetch_nginx_upstream.sh): fetches the nginx.org securityadvisories page once into
.local/nginx-cache/(never committed,snapshot-dated) and parses it into per-CVE numeric fixed floors and
vulnerable ranges. The parse lives in the fetch script, so both
derivation lanes read one canonical cache; an advisory that cannot be
reduced to numeric ranges (e.g. "Vulnerable: all") is recorded
unparsed: trueand never backs a clear verdict (fail-fast: zeroparsed advisories aborts the fetch).
token resolves to an installed
.ngxbuild carriesupstreamOrigin/upstreamVersion/upstreamVerdict. The verdictcompares the evidence-installed upstream version against the cached
advisory:
upstream-clearonly when an upstream advisory names theversion as not vulnerable;
upstream-affected,upstream-uncovered,no-upstream-advisory(distro-stream advisory that does not apply tothe .ngx build) and
upstream-no-cache(honest gap, never assumedclear) name the other outcomes. A payload-level
upstreamaggregate(snapshot, advisory count, per-build verdict distribution, affected
count) feeds the rendered P17 statement.
statement; the trivy-only table gains a "davon Upstream (.ngx)" count
column.
(b) MDE presence assertion -- complete
scripts/ssh_evidence.shruns a bounded, read-only Defender-sensorprobe (
rpm -q mdatp+systemctl is-active mdatp) per unit andrecords it in the evidence cache. A cached evidence file that
predates the probe gets a bounded mdatp-only refresh merged in; a
failed probe leaves the file untouched (never an error read as
clean).
defenderblock anddefenderCoverage:asserted(package installed and service active),missing(proberan, sensor absent or inactive),
unknown(probe could not run) --never assumed green.
(c) old-kernel inventory / running-vs-stale classification -- complete
installedCountandstaleInstalled(distinctinstalled kernel EVRs vs non-running retains, kernel and kernel-core
of one build counting once); rendered as the new Kernel-Bestand
column (running release tag + N installiert + M Altbestand).
kernelStance:running-affected(claimed version names the running kernel),stale-only(a retained non-running kernel -- the installonly_limitnoise),
claim-not-installed(matches no installed kernel), or nullwhen no kernel evidence exists (render states the gap). No hand-set
text anywhere.
Behaviour change
just nginx-upstreamis a new manual cache recipe; renders stayoffline and byte-identical and read the cache only. Without the
cache, upstream verdicts are the honest
upstream-no-cachegap.just evidencenow always probes mdatp; the fixed command sequencegained the MDE section (a fresh full collection requires it; existing
caches are refreshed bounded).
kernelStance,upstreamOrigin,upstreamVersion,upstreamVerdict; unit fieldsdefender,kernel
installedCount/staleInstalled; detection fieldsupstreamOrigin/upstreamVersion/upstreamVerdict; payload fieldupstream. Both lanes emit identical bytes (just py-crosscheck,just py-reprogreen).Proof (real caches, as prior tasks)
copied into
.local/, nginx.org snapshot fetched 2026-10-27 (67advisories), live mdatp refresh over SSH. Results:
upstream-clear per nginx.org, 3 without an upstream advisory, 0
affected -- the distro fix versions trivy names never apply to the
.ngx build.
(deallocated during the probe window, ~22:01-05:05; rerun
just evidencein their running window to assert) -- honestly not green.non-running retains; running kernel is the fixed newest one on all
units, matching the ranking rows' data-derived statements.
just triageandjust reportrenders from thesame caches: byte-identical (
cmpclean).just test(27 passed),just lint,just fmt,just py-crosscheck,just py-repro,just reproall green.Files changed
scripts/fetch_nginx_upstream.sh(new): one-shot nginx.org advisorycache fetch + parser.
scripts/ssh_evidence.sh: MDE probe in the fixed sequence; boundedmdatp refresh for caches predating the probe.
scripts/derive_findings.py: stance/coverage/upstream derivation,extended aggregates, new payload
upstream.src/dse_security_reports/derive.py: identical mirror of all of it.reports/defender-triage.typ: MDE + Kernel-Bestand columns,P17 upstream statement, trivy-only upstream count (no prose
rewritten).
tests/test_derive.py: outcome tests for all new logic + joinedcache-dataset assertions.
Justfile:nginx-upstreamrecipe; evidence comment updated.AGENTS.md: project-memory notes updated.