From 8f31500a85ec743e6ff89586ba419c4cfe87c0d6 Mon Sep 17 00:00:00 2001 From: Rajvardhan Patil Date: Mon, 24 Aug 2026 11:45:18 +0530 Subject: [PATCH 1/4] refine dashboard visual system for competition --- web/src/styles.css | 191 +++++++++++++++++++++++++++++++++------------ 1 file changed, 141 insertions(+), 50 deletions(-) diff --git a/web/src/styles.css b/web/src/styles.css index 67794f8..b3a4986 100644 --- a/web/src/styles.css +++ b/web/src/styles.css @@ -5,16 +5,14 @@ @custom-variant dark (&:is(.dark *)); /* - * Kernel Surface Ledger design system. - * - * Dark terminal world: near-black surfaces, JetBrains Mono everywhere, one - * amber accent reserved for the number that matters. All colors are oklch. - * Never hardcode color utilities in components — use these tokens. + * Kernel Surface Ledger — refined minimal competition system. + * Architectural grid, generous whitespace, black typography, and controlled + * dark-mode emphasis. Semantic tokens keep the data language stable. */ @theme inline { + --font-sans: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; --font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace; - --font-sans: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace; --radius-sm: calc(var(--radius) - 2px); --radius-md: var(--radius); @@ -41,7 +39,6 @@ --color-input: var(--input); --color-ring: var(--ring); - /* Semantic surface/report tokens */ --color-surface: var(--surface); --color-surface-raised: var(--surface-raised); --color-grid: var(--grid); @@ -56,45 +53,74 @@ } :root { - --radius: 0.25rem; - - --background: oklch(0.16 0.006 285); - --foreground: oklch(0.9 0.008 90); - - --surface: oklch(0.2 0.007 285); - --surface-raised: oklch(0.24 0.008 285); - --grid: oklch(0.3 0.008 285); - - --card: oklch(0.2 0.007 285); - --card-foreground: oklch(0.9 0.008 90); - --popover: oklch(0.2 0.007 285); - --popover-foreground: oklch(0.9 0.008 90); - - --amber: oklch(0.79 0.15 76); - --amber-dim: oklch(0.52 0.09 76); - - --primary: oklch(0.79 0.15 76); - --primary-foreground: oklch(0.16 0.006 285); - --secondary: oklch(0.26 0.008 285); - --secondary-foreground: oklch(0.9 0.008 90); - --muted: oklch(0.24 0.008 285); - --muted-foreground: oklch(0.65 0.01 90); - --accent: oklch(0.26 0.008 285); - --accent-foreground: oklch(0.9 0.008 90); - --destructive: oklch(0.62 0.19 25); - --destructive-foreground: oklch(0.97 0.005 90); - - --border: oklch(0.29 0.008 285); - --input: oklch(0.29 0.008 285); - --ring: oklch(0.79 0.15 76); - - --orphan: oklch(0.72 0.13 195); - --ok: oklch(0.72 0.11 150); - - --risk-none: oklch(0.72 0.11 150); - --risk-low: oklch(0.79 0.15 76); - --risk-medium: oklch(0.72 0.16 55); - --risk-high: oklch(0.62 0.19 25); + --radius: 0.125rem; + + --background: oklch(0.975 0.003 90); + --foreground: oklch(0.16 0.006 285); + --surface: oklch(0.99 0.002 90); + --surface-raised: oklch(0.94 0.004 90); + --grid: oklch(0.82 0.004 90); + + --card: oklch(0.99 0.002 90); + --card-foreground: oklch(0.16 0.006 285); + --popover: oklch(0.99 0.002 90); + --popover-foreground: oklch(0.16 0.006 285); + + --amber: oklch(0.28 0.015 285); + --amber-dim: oklch(0.48 0.008 285); + + --primary: oklch(0.16 0.006 285); + --primary-foreground: oklch(0.975 0.003 90); + --secondary: oklch(0.94 0.004 90); + --secondary-foreground: oklch(0.16 0.006 285); + --muted: oklch(0.94 0.004 90); + --muted-foreground: oklch(0.48 0.008 285); + --accent: oklch(0.92 0.004 90); + --accent-foreground: oklch(0.16 0.006 285); + --destructive: oklch(0.52 0.16 25); + --destructive-foreground: oklch(0.975 0.003 90); + + --border: oklch(0.78 0.004 90); + --input: oklch(0.78 0.004 90); + --ring: oklch(0.16 0.006 285); + + --orphan: oklch(0.42 0.07 195); + --ok: oklch(0.42 0.07 150); + --risk-none: oklch(0.42 0.07 150); + --risk-low: oklch(0.42 0.06 80); + --risk-medium: oklch(0.48 0.11 55); + --risk-high: oklch(0.52 0.16 25); +} + +.dark { + --background: oklch(0.14 0.006 285); + --foreground: oklch(0.92 0.006 90); + --surface: oklch(0.18 0.007 285); + --surface-raised: oklch(0.22 0.008 285); + --grid: oklch(0.32 0.008 285); + --card: oklch(0.18 0.007 285); + --card-foreground: oklch(0.92 0.006 90); + --popover: oklch(0.18 0.007 285); + --popover-foreground: oklch(0.92 0.006 90); + --amber: oklch(0.86 0.01 90); + --amber-dim: oklch(0.62 0.008 90); + --primary: oklch(0.92 0.006 90); + --primary-foreground: oklch(0.14 0.006 285); + --secondary: oklch(0.22 0.008 285); + --secondary-foreground: oklch(0.92 0.006 90); + --muted: oklch(0.22 0.008 285); + --muted-foreground: oklch(0.66 0.008 90); + --accent: oklch(0.24 0.008 285); + --accent-foreground: oklch(0.92 0.006 90); + --border: oklch(0.3 0.008 285); + --input: oklch(0.3 0.008 285); + --ring: oklch(0.92 0.006 90); + --orphan: oklch(0.72 0.11 195); + --ok: oklch(0.72 0.1 150); + --risk-none: oklch(0.72 0.1 150); + --risk-low: oklch(0.82 0.09 80); + --risk-medium: oklch(0.8 0.12 55); + --risk-high: oklch(0.74 0.16 25); } @layer base { @@ -103,20 +129,29 @@ } html { - color-scheme: dark; + color-scheme: light; + scroll-behavior: smooth; } body { background-color: var(--color-background); color: var(--color-foreground); - font-family: var(--font-mono); + font-family: var(--font-sans); font-variant-numeric: tabular-nums; -webkit-font-smoothing: antialiased; } + button, + a, + input, + textarea, + select { + font: inherit; + } + :focus-visible { - outline: 2px solid var(--color-amber); - outline-offset: 2px; + outline: 2px solid var(--color-foreground); + outline-offset: 3px; } } @@ -124,7 +159,63 @@ font-variant-numeric: tabular-nums; } +@utility mono { + font-family: var(--font-mono); +} + +@utility display-tight { + letter-spacing: -0.045em; +} + +@utility label-caps { + text-transform: uppercase; + letter-spacing: 0.18em; + font-size: 0.68rem; +} + +.section-shell { + position: relative; +} + +.section-shell::before { + content: ""; + position: absolute; + left: 50%; + top: 0; + bottom: 0; + width: 1px; + background: color-mix(in oklab, var(--color-grid) 38%, transparent); + pointer-events: none; +} + +.hero-grid { + background-image: linear-gradient(to right, color-mix(in oklab, var(--color-grid) 30%, transparent) 1px, transparent 1px), + linear-gradient(to bottom, color-mix(in oklab, var(--color-grid) 30%, transparent) 1px, transparent 1px); + background-size: 72px 72px; + background-position: center top; +} + +.data-grid { + background-image: linear-gradient(to right, color-mix(in oklab, var(--color-grid) 20%, transparent) 1px, transparent 1px), + linear-gradient(to bottom, color-mix(in oklab, var(--color-grid) 20%, transparent) 1px, transparent 1px); + background-size: 36px 36px; +} + +@media (max-width: 768px) { + .section-shell::before { + display: none; + } + + .hero-grid { + background-size: 40px 40px; + } +} + @media (prefers-reduced-motion: reduce) { + html { + scroll-behavior: auto; + } + *, *::before, *::after { From c9a63d25a80bc6e4ddd68954214d7070696a642f Mon Sep 17 00:00:00 2001 From: Rajvardhan Patil Date: Mon, 24 Aug 2026 11:45:27 +0530 Subject: [PATCH 2/4] upgrade minimal typography and grid primitives --- web/src/components/ksl/primitives.tsx | 94 ++++++++++++--------------- 1 file changed, 43 insertions(+), 51 deletions(-) diff --git a/web/src/components/ksl/primitives.tsx b/web/src/components/ksl/primitives.tsx index e1d0903..2a90ae9 100644 --- a/web/src/components/ksl/primitives.tsx +++ b/web/src/components/ksl/primitives.tsx @@ -17,16 +17,22 @@ export function Section({ children: ReactNode; }) { return ( -
-
-

{label}

-

- {title} -

- {lede ? ( -

{lede}

- ) : null} -
{children}
+
+
+
+

{label}

+
+
+

+ {title} +

+ {lede ? ( +

+ {lede} +

+ ) : null} +
{children}
+
); @@ -46,26 +52,26 @@ export function Figure({ hint?: string | undefined; }) { return ( -
-

{label}

-

+

+

{label}

+

{value} {projected ? ( - + after plan - {projected} + {projected} ) : null}

- {hint ?

{hint}

: null} + {hint ?

{hint}

: null}
); } @@ -80,17 +86,17 @@ export function Chip({ title?: string | undefined; }) { const tones: Record = { - neutral: "border-border bg-surface-raised text-muted-foreground", - amber: "border-amber-dim bg-surface-raised text-amber", - orphan: "border-orphan/40 bg-surface-raised text-orphan", - ok: "border-ok/40 bg-surface-raised text-ok", - danger: "border-destructive/50 bg-surface-raised text-destructive", + neutral: "border-border bg-surface text-muted-foreground", + amber: "border-foreground bg-foreground text-background", + orphan: "border-orphan/50 bg-surface text-orphan", + ok: "border-ok/50 bg-surface text-ok", + danger: "border-destructive/50 bg-surface text-destructive", }; return ( @@ -111,7 +117,7 @@ export function RiskBadge({ risk }: { risk: KslBreakageRisk }) { return ( @@ -126,14 +132,10 @@ export function BoolGlyph({ value, label }: { value: boolean; label: string }) { - {value ? ( - - ) : ( - - )} + {value ? : } {label}: {value ? "yes" : "no"} @@ -145,12 +147,8 @@ export function BoolGlyph({ value, label }: { value: boolean; label: string }) { export function WeightBar({ value, max }: { value: number; max: number }) { const pct = max > 0 ? Math.min(100, (value / max) * 100) : 0; return ( - - + + ); } @@ -178,22 +176,20 @@ export function CodeBlock({ return (
-
- {path ?? "artifact"} +
+ + {path ?? "artifact"} +
-
+      
         {content}
       
@@ -201,9 +197,5 @@ export function CodeBlock({ } export function NotCollected({ reason }: { reason?: string | undefined }) { - return ( - - not collected{reason ? ` — ${reason}` : ""} - - ); + return not collected{reason ? ` — ${reason}` : ""}; } From 268d628787dd7b6be000c7374faac55a72debba5 Mon Sep 17 00:00:00 2001 From: Rajvardhan Patil Date: Mon, 24 Aug 2026 11:45:42 +0530 Subject: [PATCH 3/4] reframe dashboard hero and navigation for submission --- web/src/components/ksl/HeaderBand.tsx | 258 ++++++++++++++------------ 1 file changed, 143 insertions(+), 115 deletions(-) diff --git a/web/src/components/ksl/HeaderBand.tsx b/web/src/components/ksl/HeaderBand.tsx index 9cf96bc..213b5ea 100644 --- a/web/src/components/ksl/HeaderBand.tsx +++ b/web/src/components/ksl/HeaderBand.tsx @@ -7,16 +7,18 @@ import { downloadHardeningPdf } from "@/lib/ksl-pdf"; import type { KslReport } from "@/lib/ksl-types"; const NAV = [ + { href: "#ask", label: "Ask" }, { href: "#ledger", label: "Ledger" }, - { href: "#orphaned", label: "Orphaned" }, + { href: "#orphaned", label: "Orphans" }, { href: "#gates", label: "Gates" }, { href: "#plan", label: "Plan" }, - { href: "#provenance", label: "Provenance" }, + { href: "#impact", label: "Impact" }, + { href: "#provenance", label: "AI boundary" }, ]; function MetaItem({ label, value }: { label: string; value: string }) { return ( - + {label} {value} @@ -42,25 +44,75 @@ export function HeaderBand({ const projected = score.projected_after_plan; return ( -
-
-
-

- Kernel Surface Ledger ksl -

-

- Every other tool tells you what kernel attack surface is exposed. This one - tells you who is responsible for it, what - nothing is using, and the shortest way out. -

+
+
+
+
+ 01. + KERNEL SURFACE LEDGER +
+
+ AI-assisted kernel attack surface analyzer +
+
+ +
+
+

AI / Linux / Security

+

+ See the +
+ attack surface. +

+
+

+ A read-only analyzer that maps kernel exposure to the workloads holding it open, + isolates unused surface, and ranks reversible hardening decisions. +

+

+ Rajvardhan Patil · competition build +

+
+
+ +
+
+
+

System

+

{meta.kernel_release}

+

{meta.arch}

+
+
+

Evidence

+

{meta.ran_as_root ? "root" : "partial"}

+

{meta.trace_backend ?? "no tracer"}

+
+
+

+ The interface is intentionally calm. The security signal lives in attribution, + reachability, provenance, and counterfactual planning—not decorative chrome. +

+
-
-
+
+ + +
- { - const file = e.target.files?.[0]; - if (file) onLoadFile(file); - e.target.value = ""; - }} - /> - source: {sourceLabel}
-
- {failure ? ( - inputRef.current?.click()} + { + const file = e.target.files?.[0]; + if (file) onLoadFile(file); + e.target.value = ""; + }} /> - ) : null} - + {failure ? ( + inputRef.current?.click()} + /> + ) : null} -
- - - - - - - -
+
+
+
+
+
+
- {meta.skipped && meta.skipped.length > 0 ? ( -
-

partial data — {meta.skipped.length} source(s) skipped

-
    - {meta.skipped.map((s, i) => ( -
  • - {s.source ?? "unknown source"}: {s.reason ?? "no reason given"} -
  • - ))} -
+
+ + + + +
- ) : null} -
-
-
-
-
+ {meta.skipped && meta.skipped.length > 0 ? ( +
+

+ partial data · {meta.skipped.length} source(s) skipped +

+
    + {meta.skipped.map((s, i) => ( +
  • + {s.source ?? "unknown source"}: {s.reason ?? "no reason given"} +
  • + ))} +
+
+ ) : null}
); From 13645dad8adf4e53c04a2a965f13df2c56137ae7 Mon Sep 17 00:00:00 2001 From: Rajvardhan Patil Date: Mon, 24 Aug 2026 11:45:53 +0530 Subject: [PATCH 4/4] refresh README for competition positioning --- README.md | 174 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 96 insertions(+), 78 deletions(-) diff --git a/README.md b/README.md index 5238be3..5bcf518 100644 --- a/README.md +++ b/README.md @@ -2,78 +2,94 @@ # Kernel Surface Ledger -### `ksl` — understand who holds your kernel attack surface open +### `ksl` — AI-assisted Linux kernel attack surface analyzer -**A read-only Linux analyzer that turns kernel exposure into a clear, reversible hardening decision.** +**Turn low-level kernel exposure into an explainable, evidence-backed hardening decision.** -[![Live dashboard](https://img.shields.io/badge/live%20dashboard-Vercel-0f172a?style=flat-square&logo=vercel&logoColor=white)](https://kernel-surface-ledger.vercel.app/) -[![Read-only collector](https://img.shields.io/badge/collector-read--only-0f766e?style=flat-square&logo=linux&logoColor=white)](#designed-for-cautious-use) -[![Deterministic scoring](https://img.shields.io/badge/scoring-deterministic-d97706?style=flat-square)](#the-ai-boundary) -[![MIT License](https://img.shields.io/badge/license-MIT-2563eb?style=flat-square)](LICENSE) +[![Linux](https://img.shields.io/badge/platform-Linux-111111?style=flat-square&logo=linux&logoColor=white)](#get-started) +[![Read-only](https://img.shields.io/badge/collector-read--only-111111?style=flat-square)](#designed-for-cautious-use) +[![Deterministic](https://img.shields.io/badge/security--scoring-deterministic-111111?style=flat-square)](#the-ai-boundary) +[![Live](https://img.shields.io/badge/dashboard-live-111111?style=flat-square)](https://kernel-surface-ledger.vercel.app/) +[![MIT](https://img.shields.io/badge/license-MIT-111111?style=flat-square)](LICENSE) -[Explore the dashboard](https://kernel-surface-ledger.vercel.app/)  ·  [Read the method](docs/PRIOR_ART.md)  ·  [Run a demo](#get-started)  ·  [Deploy your own](docs/DEPLOY_VERCEL.md) +**Rajvardhan Patil** · AI-assisted Kernel Attack Surface Analyzer · Linux-based hackathon build + +[Explore the dashboard](https://kernel-surface-ledger.vercel.app/) · [Run the demo](#reproduce-the-deterministic-demo) · [Read the method](docs/PRIOR_ART.md) · [Deploy your own](docs/DEPLOY_VERCEL.md)
-> **A kernel hardening report should end in a decision—not a longer checklist.** +> **The goal is not another kernel checklist. The goal is a defensible answer to one question: _what should we review first, and why?_** -Most kernel hardening tools identify settings and possible weaknesses. `ksl` takes the next step: it shows **which live workloads keep reachable kernel surface open**, **what is reachable but has no observed user**, and **which reversible changes remove the most risk for the least expected disruption**. +## 01 / What it does -## From exposure to a decision +Kernel Surface Ledger (`ksl`) is a **read-only Linux analyzer** that collects evidence about kernel configuration, loaded modules, processes, device nodes, sysctls, and optional syscall traces. It then turns that evidence into a deterministic report covering: -| Observe | Attribute | Act | -| --- | --- | --- | -| Read kernel configuration, modules, processes, device nodes, sysctls, and optional syscall traces—without modifying the host. | Separate surface that is merely present from surface reachable by unprivileged users, then divide responsibility across the workloads that use it. | Find orphaned surface and rank reviewable mitigations with their artifact, risk, verification command, and revert. | +- **Presence** — what kernel surface exists. +- **Reachability** — what an unprivileged local user can actually reach. +- **Attribution** — which live workloads keep that surface relevant. +- **Orphans** — reachable surface with no observed owner during the trace window. +- **Planning** — which reversible hardening steps remove the most reachable CVE mass for the least expected breakage. +- **Explanation** — optional AI narration that explains evidence without controlling security numbers. -The result is a **Surface Debt Ledger**: a compact explanation of who owns the exposure, what is shared, what has no observed owner, and what to change first. +The result is a **Surface Debt Ledger**: not a flat findings list, but an accountable model of exposure, ownership, and change. -## See the model work +## 02 / Why this fits the problem statement -The dashboard opens with a reproducible, schema-valid demo report. It is deliberately separate from the committed Linux-runner scan, so each visitor can distinguish repeatable walkthrough data from recorded host evidence. +**Problem statement:** Develop an AI-assisted tool that automatically analyzes Linux kernel configurations, loaded kernel modules, system calls, and exposed kernel interfaces to identify potential security weaknesses, assess attack surfaces, and generate explainable kernel hardening recommendations. -| Bundled demo · [`fixtures/demo.json`](fixtures/demo.json) | Result | +| Requirement | `ksl` implementation | | --- | --- | -| Reachable surface weight | **106.0 → 43.5** after the ranked plan | -| Reachable CVEs | **19 → 9** | -| Orphaned surface | **52.0** weighted units · **7** neutralizable CVEs | -| Report scope | 5 workloads · 22 surface elements · 5 plan steps | +| Kernel configuration | `collector/kconfig.py` | +| Loaded modules | `collector/modules.py` | +| System calls | `collector/syscalls.py` with optional trace adapters | +| Kernel interfaces | device nodes, sysctls, modules, and reachability engine | +| Attack-surface assessment | `engine/reachability.py` + deterministic scoring | +| Security weaknesses | CVE mapping + reachability-aware accounting | +| Explainability | `explain/` constrained narration + grounded dashboard Q&A | +| Hardening recommendations | `engine/setcover.py` + reviewable artifacts | +| Linux compatibility | read-only Linux host collector + Linux-first fixtures | -The scheduled Linux-runner snapshot, [`data/reports/report.json`](data/reports/report.json), currently records **61.5** reachable weighted units, **14 → 6** reachable CVEs, and **28.0** orphaned weighted units. +## 03 / The differentiator -## Built to be checked +Most hardening tools stop after finding a setting or a vulnerable component. `ksl` adds three questions that make the result operational: -| Property | Where to verify it | -| --- | --- | -| The report has a stable shape | [`report.schema.json`](report.schema.json) is the frozen contract; [`scripts/check_contract.py`](scripts/check_contract.py) validates it. | -| Scores are reproducible | [`tests/test_report.py`](tests/test_report.py) asserts byte-identical reports from the same raw snapshot. | -| AI cannot change security numbers | [`tests/test_explain.py`](tests/test_explain.py) verifies identical numeric output with and without narration. | -| Collection is safe to run | [`collector/`](collector) only reads host interfaces and records inaccessible sources in `meta.skipped`. | -| Recommendations are actionable | Every plan step includes an artifact, breakage context, detection command, and revert. | -| The product is immediately usable | The [live dashboard](https://kernel-surface-ledger.vercel.app/) works directly—no account, database, or sign-in required. | +**Who keeps it open?** Workload attribution separates shared surface from marginal responsibility. + +**Is anyone actually touching it?** Orphaned-surface analysis distinguishes reachable-but-unused surface from active dependencies. + +**What should change first?** Counterfactual planning ranks reversible mitigations by security impact versus estimated disruption. -## What sets `ksl` apart +That combination makes the report easier to review with an operator, security engineer, or judge. -| Existing approach | Strength | What `ksl` adds | -| --- | --- | --- | -| Kernel configuration checkers | Find deviations from recommended settings | Runtime reachability, workload ownership, and a ranked action plan | -| Per-application seccomp generators | Reduce one process or container’s syscall surface | A host-wide view of shared surface and the workloads with marginal responsibility | -| Kernel debloating systems | Produce tailored kernels | Live, read-only assessment without rebuilding or altering the kernel | +## 04 / AI boundary -The contribution is the combination of **workload attribution**, **orphaned-surface detection**, and **breakage-costed counterfactual planning**. Read the full sourced comparison in [`docs/PRIOR_ART.md`](docs/PRIOR_ART.md). +The security engine is deliberately conservative. -## The AI boundary +**Deterministic code owns:** scores, gates, weights, CVE counts, orphan classification, and plan order. -The deterministic engine owns every score, gate, weight, CVE count, orphan classification, and plan order. Human-curated inputs live in [`data/weights.yaml`](data/weights.yaml) and [`data/cve-map.json`](data/cve-map.json); the code does not invent them. +**The model may:** explain why a workload holds a surface element, summarize observed evidence, predict possible breakage, and render reviewable hardening artifacts. -The optional model layer can: +**The model may not:** change numeric scores, invent security findings, select the winning mitigation, or silently reorder the hardening plan. -- explain why a workload holds a surface element; -- predict possible breakage and detection steps; and -- render reviewable hardening artifacts. +The optional `--no-explain` path produces the same security numbers without AI narration, making the separation testable. + +## 05 / Demo signal + +The bundled dashboard opens directly on reproducible demo evidence, so a reviewer can understand the product without a Linux host, account, database, or API key. + +| Demo metric | Result | +| --- | --- | +| Reachable surface | **106.0 → 43.5** after ranked plan | +| Reachable CVEs | **19 → 9** | +| Orphaned surface | **52.0** weighted units | +| Neutralizable orphan CVEs | **7** | +| Workloads | **5** | +| Surface elements | **22** | +| Hardening steps | **5** | -It cannot select a mitigation, modify a score, or change ordering. Running `--no-explain` keeps all numeric results identical. The hosted dashboard also offers direct report Q&A, grounded only in the report currently loaded in the browser; its model key stays server-side. +The dashboard also supports loading a schema-valid `report.json`, rendering the same evidence model for a real Linux host. -## Get started +## 06 / Get started ### Reproduce the deterministic demo @@ -85,23 +101,23 @@ python3 -m venv .venv . .venv/bin/activate pip install -r requirements.txt -# Score the committed evidence snapshot—no host access or API key required. +# Score committed evidence without touching the host. python ksl.py scan --raw fixtures/raw-demo.json --no-explain -o report.json python ksl.py check report.json -# Run the deterministic engine and collector test suite. +# Run the deterministic test suite. python -m unittest discover -s tests -v ``` ### Scan a Linux host ```bash -# Read-only collection. Save the raw evidence as well as the scored report. +# Read-only host collection. python ksl.py scan --save-raw raw.json -o report.json python ksl.py check report.json ``` -Drag `report.json` onto the [live dashboard](https://kernel-surface-ledger.vercel.app/) or run it locally: +Then load `report.json` into the [live dashboard](https://kernel-surface-ledger.vercel.app/) or run the dashboard locally: ```bash cd web @@ -109,37 +125,39 @@ npm install --legacy-peer-deps npm run dev ``` -The dashboard runs without a login. Set `OPENROUTER_API_KEY` in `web/.env` only for live Q&A and fresh narration; all deterministic report views work without it. +Set `OPENROUTER_API_KEY` in `web/.env` only when you want live Q&A or fresh narration. The deterministic report views do not require it. -## Designed for cautious use +## 07 / Designed for cautious use -- **Read-only by design.** The collector never loads or unloads modules, changes a sysctl, or applies generated artifacts. -- **Evidence has a time window.** “Used” means observed during the selected trace window. A quiet nightly job can look unused at noon, so every recommendation includes verification and rollback guidance. -- **Missing access is reported.** Reads of `/proc`, `/sys`, and `/boot` degrade into partial evidence with a reason in `meta.skipped`; an unprivileged run remains useful instead of crashing. -- **No tracer is not false certainty.** When syscall tracing is unavailable, syscall surface is not called orphaned merely because no usage was observed. -- **Artifacts are for human review.** `ksl` produces candidate hardening files and commands; an operator decides whether to apply them. +- **Read-only by design.** The collector never loads or unloads modules, changes sysctls, or applies hardening automatically. +- **Evidence has a time window.** “Used” means observed during the selected trace period; a quiet service can look unused later. +- **Missing access is explicit.** Inaccessible sources are recorded in `meta.skipped` instead of becoming silent false certainty. +- **No tracer is not proof of absence.** Syscall surface is not called orphaned merely because a trace was unavailable. +- **Artifacts are reviewable.** Each recommendation carries its target artifact, expected breakage, detection command, and revert path. -## Explore the repository +## 08 / Repository map | Path | Purpose | | --- | --- | -| [`collector/`](collector) | Read-only Linux evidence collection: configuration, modules, processes, device nodes, sysctls, and syscall-trace adapters. | -| [`engine/`](engine) | Deterministic reachability, attribution, CVE accounting, and greedy set-cover planning. | -| [`artifacts/`](artifacts) | Deterministic templates for reviewable hardening artifacts. | -| [`explain/`](explain) | Optional constrained narration with cache and deterministic fallback. | -| [`web/`](web) | Direct-use TanStack Start dashboard deployed on Vercel. | -| [`fixtures/`](fixtures) | Reproducible raw and scored demo evidence. | -| [`tests/`](tests) | Contract, determinism, CLI, reachability, attribution, planner, and degradation tests. | -| [`scripts/fleet_rollup.py`](scripts/fleet_rollup.py) | Schema-preserving aggregation of multiple host reports. | - -## A good first tour - -1. Open the [dashboard](https://kernel-surface-ledger.vercel.app/). -2. Expand a ledger workload to see exactly what holds surface open. -3. Compare **Orphaned surface** with the **Hardening plan**; each plan card keeps risk, verification, and rollback in one place. -4. Drop your own schema-valid `report.json` to replace the bundled evidence. -5. Read [`docs/DEMO_RUNBOOK.md`](docs/DEMO_RUNBOOK.md) for a concise walkthrough or [`docs/PRIOR_ART.md`](docs/PRIOR_ART.md) for the technical context. - -## License - -MIT. See [`LICENSE`](LICENSE). +| `collector/` | Read-only Linux evidence collection | +| `engine/` | Deterministic reachability, attribution, CVE accounting, and planning | +| `artifacts/` | Reviewable hardening artifact templates | +| `explain/` | Optional constrained AI narration | +| `web/` | TanStack Start dashboard deployed on Vercel | +| `fixtures/` | Reproducible demo evidence | +| `tests/` | Contract, determinism, CLI, reachability, attribution, planner, and degradation tests | +| `docs/` | Demo runbook, prior-art research, testing, and deployment notes | + +## 09 / A good judge walkthrough + +1. Open the dashboard and read the top-level exposure metrics. +2. Expand a ledger workload to see what it owns and what remains shared. +3. Compare **Orphaned surface** with the **Hardening plan**. +4. Open a plan step to inspect artifact, expected breakage, verification, and rollback. +5. Open **Impact graph** to see the blast radius before applying a change. +6. Ask the report a question and verify that the answer remains grounded in the loaded evidence. +7. Read **Where the AI is — and is not** to see the deterministic security boundary. + +## 10 / License + +MIT. See [LICENSE](LICENSE).