Skip to content

feat(sca): show runtime evidence in the SCA dashboard (#57) - #90

Merged
karthickmk2001 merged 2 commits into
mainfrom
feat/57-runtime-in-sca-dashboard
Nov 11, 2026
Merged

karthickmk2001 merged 2 commits into
mainfrom
feat/57-runtime-in-sca-dashboard

Conversation

@karthickmk2001

Copy link
Copy Markdown
Collaborator

Closes #57

Stacked on #88 (#53). It reads the runtime tables #88 adds, so this branch contains #88's commit. Merge #88 first; this diff then shrinks to the dashboard commit only. It doesn't need #89.

What does this change, and why?

Shows #53's runtime evidence next to the static reachability verdict, as #57 describes.

SCA vulnerabilities list with the Runtime column and a highlighted conflict

Demo data from a throwaway store. pyyaml was rated Not reachable but was reached on POST /upload, so the row is highlighted. jinja2 ran at startup (Executed). requests is loaded at 2.31.0 while 2.19.0 was scanned (version drift).

States. Each (project, finding) gets one state, strongest first (src/secfoo/web/sca_runtime.py):

State Shown as
Reached from traffic Reached · POST /upload (anonymous) · 312: a hit on a request route
Executed Executed · 13 hits · last 2026-11-08: hits on startup / job:* / unknown / no route
Loaded Loaded · no watched call, plus · version drift when the loaded version isn't the scanned one (#68)
Not loaded Sessions recorded an inventory without this package: Not loaded · 74% coverage · 6h
Not observed Sessions without inventory: Not observed · 74% coverage · 6h
No runtime data No sessions for the project

"Not observed" and "Not loaded" always carry the coverage % and observation window (#51 rule 4). The detail page also says outright that it isn't proof of unreachability.

Where it shows:

  • Vulnerabilities list (sca_vulnerabilities_list.html): a new Runtime column with the strongest state across affected projects.
  • Priority hint: a static Not reachable that was Executed or Reached gets a highlighted row and a "Conflicts with static verdict" badge.
  • Vulnerability detail (sca_vulnerability_detail.html): per project, the state, source (sensor / coverage), and a hits table (symbol, route, auth, hits, last seen, app/env, entry frame, stack sample). Loaded versions and drift are shown too. A conflict gets an alert at the top.
  • Overview (sca_dashboard.html): a Runtime-confirmed reachable card, split into reached from traffic and executed, plus the conflict count. It renders only once a project has runtime data, so with no sensor the page is unchanged (Tracking: Runtime reachability for SCA (in-app probe + live sensor) #51 rule 0).

Styling: existing badge classes only (badge--error/warning/primary/teal/neutral). The conflict row uses the existing --color-error / --color-error-bg tokens, with no new colors.

Joining evidence to rows: the dashboard is built from report text, so each Risk Register row gets its persisted sca_findings.fingerprint via the existing findings_with_fingerprints(). That's the key runtime hits attach to.

Out of scope here: the "via E1 (B1)" threat-model entry-point annotation, which needs #70.

Testing

  • pytest tests passes. 1066 passed locally. The only failures are the 4 existing Windows-only POSIX permission and symlink tests that fail on main too; Linux CI is unaffected.
  • ruff check . adds no new findings.
  • Added tests/test_web/test_sca_runtime.py (16 tests). Data goes in through Runtime evidence format, storage and secfoo runtime ingest #53's real ingest_events. They cover:
    • every runtime state
    • the strongest state across projects
    • the conflict highlight: on for Not reachable plus a request route or startup; off for Reachable plus ran, and for Not reachable plus only loaded
    • the rendered list, detail and overview pages
    • the overview card staying hidden without runtime data

The existing SCA dashboard and route tests still pass unchanged.

🤖 Generated with Claude Code

karthickmk2001 and others added 2 commits November 11, 2026 20:43
NDJSON session/load/hit events as specified in #53, a JSON Schema, three new tables (runtime_sessions, runtime_evidence with an FK to sca_findings, runtime_packages), and secfoo runtime ingest. Validation and the idempotent upsert live in secfoo/runtime/evidence.py so the live ingest API (#66) can reuse them. Malformed lines and unknown fingerprints are skipped and reported, never abort; re-ingesting a file replaces running totals instead of double-counting; unknown fields, concrete URLs and non file:line frames never reach the database.

Closes #53

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each SCA finding gets a runtime state from #53's tables, strongest first: reached from traffic, executed, loaded (with version drift), not loaded / not observed (always shown with coverage % and observation time), or no runtime data. The vulnerabilities list gains a Runtime column and highlights findings the static scan called Not reachable whose code ran; the detail page shows sessions, routes with auth state, entry frames and stack samples; the overview counts runtime-confirmed findings once runtime data exists. Existing badge styles and color tokens only.

Closes #57

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@karthickmk2001
karthickmk2001 merged commit fdbae76 into main Nov 11, 2026
6 checks passed
@karthickmk2001
karthickmk2001 deleted the feat/57-runtime-in-sca-dashboard branch November 11, 2026 21:26
@github-actions

Copy link
Copy Markdown

Leaderboard update

karthickmk2001 now has 19 points (rank #1). 6 more to reach Bronze.

Full leaderboard

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.

Runtime evidence in the SCA dashboard

1 participant