chore(llm-security): v7.7.2 — language consistency pass
~/.claude/CLAUDE.md specifies English for code and documentation, Norwegian for dialog only. Norwegian had crept into surface text across v7.5-v7.7. Translated to English in eight surfaces. No scanner, hook, or behavior changes — purely surface text. - 18 skill commands: the HTML Report-step now reads "HTML report: [Open in browser]" instead of "HTML-rapport: [Åpne i nettleser]" - scripts/lib/report-renderers.mjs: key-stat labels, lede defaults, table headers, maturity-ladder descriptions, action-tier labels, clean buckets, dry-run/apply copy, and JS comments. Regex alternations /^high|^høy/ and /resolution|løsning/i preserved. - playground/llm-security-playground.html: same renderer changes mirrored bit-identical, plus playground-only UI strings (catalog, breadcrumb aria-label, theme toggle, builder-modal hint, guide-panel "no projects yet", delete confirmation, alert/copy). Demo-state fixture content for dft-komplett-demo preserved (intentional Norwegian persona). - agents/skill-scanner-agent.md + agents/mcp-scanner-agent.md: Generaliseringsgrense + Parallell Read-strategi sections translated to Generalization boundary + Parallel Read strategy. - README.md: playground architecture prose + Recent versions table (v7.5.0 — v7.7.1). - CLAUDE.md: v7.7.1 highlights translated, new v7.7.2 highlights added. - ../../README.md: llm-security v7.5.0 — v7.7.1 bullets. - ../../CLAUDE.md: llm-security catalog entry. - docs/scanner-reference.md: six runnable-examples table cells. - docs/version-history.md: new v7.7.2 entry. v7.5-v7.7 narrative sections left in original language (deferred per operator). - Version bumped 7.7.1 → 7.7.2 in package.json, .claude-plugin/plugin.json, README badge + Recent versions, CLAUDE.md header + state, docs/version-history.md, playground renderHome hardcoded string, root README + CLAUDE.md llm-security entries. Tests: 1820/1820 green. CLI smoke-test: 18/18 commandIds produce >138 KB self-contained HTML. Browser-dogfood verified. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
4f6fc4a2a5
commit
03b8885b6e
31 changed files with 467 additions and 359 deletions
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"name": "llm-security",
|
||||
"description": "Security scanning, auditing, and threat modeling for Claude Code projects. Detects secrets, validates MCP servers, assesses security posture, and generates threat models aligned with OWASP LLM Top 10.",
|
||||
"version": "7.7.1"
|
||||
"version": "7.7.2"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,83 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
## [7.7.2] - 2026-05-19
|
||||
|
||||
Language consistency pass. Norwegian had crept into surface text across
|
||||
v7.5-v7.7. Per the `~/.claude/CLAUDE.md` convention (English for code and
|
||||
documentation, Norwegian for dialog only), surface text was translated to
|
||||
English. No scanner, hook, or behavior changes — purely surface text.
|
||||
|
||||
### Changed
|
||||
|
||||
- **18 skill commands `commands/*.md`** — the "HTML Report"-step appended
|
||||
by each `/security <cmd>` flow now reads
|
||||
`> **HTML report:** [Open in browser](file:///abs/path.html)` (previously
|
||||
Norwegian).
|
||||
- **CLI canonical module `scripts/lib/report-renderers.mjs`** — translated
|
||||
KEY_STATS_CONFIG labels (`TOTALT` → `TOTAL`, `KRITISK` → `CRITICAL`,
|
||||
`HØY` → `HIGH`, `FUNN` → `FINDINGS`, `PROSJEKTER` → `PROJECTS`,
|
||||
`MASKINKLASSE` → `MACHINE GRADE`, `SVAKEST` → `WEAKEST`,
|
||||
`NÅ-GRADE` → `CURRENT GRADE`, `AKSJONER` → `ACTIONS`, `MODUS` → `MODE`),
|
||||
the 5-step maturity ladder descriptions, the suppressed-group desc,
|
||||
4 table-header sets, the 6 renderer `lede` defaults (plugin-audit,
|
||||
mcp-audit, harden, diff, watch, clean), the action tier labels
|
||||
(Umiddelbar/Høy prioritet/Medium prioritet → Immediate/High priority/
|
||||
Medium priority), the clean buckets, and the dry-run/apply text. JS
|
||||
comments translated for consistency. Preserved the regex alternations
|
||||
`/^high|^høy/` and `/resolution|løsning/i` — they intentionally match
|
||||
Norwegian-language report markdown.
|
||||
- **Playground `playground/llm-security-playground.html`** — the same
|
||||
display strings as the canonical module (kept bit-identical), plus
|
||||
playground-specific UI text: catalog row labels, search placeholder,
|
||||
breadcrumb aria-label, theme-toggle labels, primary nav aria-label,
|
||||
builder-modal hints, "no projects yet" guide-panel, delete-project
|
||||
confirmation, alert/copy-confirm strings, and the field-from-tag
|
||||
"felles" pill (now "shared"). The hardcoded `Plugin v7.7.1` in
|
||||
`renderHome` bumped to `Plugin v7.7.2`, and `prosjekter`/`kommandoer`
|
||||
there became `projects`/`commands`. Demo-state fixture content for the
|
||||
`dft-komplett-demo` project (intentional Norwegian persona) and regex
|
||||
tokens were preserved.
|
||||
- **Agent prompts `agents/skill-scanner-agent.md` +
|
||||
`agents/mcp-scanner-agent.md`** — translated the `Generaliseringsgrense`
|
||||
and `Parallell Read-strategi` sections (identical content in both files)
|
||||
to `Generalization boundary` and `Parallel Read strategy`.
|
||||
- **`README.md`** — translated the Recent versions table rows for v7.5.0
|
||||
→ v7.7.1 and the playground architecture prose (L495-553). Version
|
||||
badge bumped to 7.7.2.
|
||||
- **`CLAUDE.md`** — translated the v7.7.1 highlights paragraph and added a
|
||||
new v7.7.2 highlights paragraph. Header and "release notes" sentinel
|
||||
bumped to v7.7.2.
|
||||
- **Marketplace root `../../README.md`** — translated the v7.5.0 → v7.7.1
|
||||
llm-security bullet entries (lines 39-43). Version label in the
|
||||
header bumped to v7.7.2. The voyage and ms-ai-architect entries on
|
||||
lines 90-91 / 192-197 were not touched (strict plugin scope).
|
||||
- **Marketplace root `../../CLAUDE.md`** — translated the llm-security
|
||||
catalog entry on line 13 and bumped its version to v7.7.2.
|
||||
- **`docs/scanner-reference.md`** — translated the six runnable-examples
|
||||
table cells (L114-122) and the surrounding paragraph.
|
||||
- **`docs/version-history.md`** — added a v7.7.2 entry describing this
|
||||
pass. The v7.5.0 → v7.7.1 narrative sections retain the Norwegian they
|
||||
were written in (deferred per operator decision).
|
||||
- **`package.json` + `.claude-plugin/plugin.json`** — version 7.7.1 →
|
||||
7.7.2.
|
||||
|
||||
### Preserved (intentional Norwegian)
|
||||
|
||||
- Demo-state `dft-komplett-demo` JSON `description`, `system_description`,
|
||||
and parsed-data `"label": "HØY"` / `"label": "NÅ-GRADE"` entries —
|
||||
intentional Norwegian persona for the public-sector reference scenario.
|
||||
- Regex alternations `/^high|^høy/` and `/resolution|løsning/i` in both
|
||||
the canonical renderer and the playground inline copy — they let
|
||||
reports written in Norwegian still parse and route correctly.
|
||||
- `knowledge/norwegian-context.md` and other knowledge files — out of
|
||||
scope.
|
||||
- The v7.5.0 → v7.7.1 entries in CHANGELOG.md and `docs/version-history.md`
|
||||
remain in the language they were written in; rewriting historical
|
||||
release notes was deferred.
|
||||
- `REMEMBER.md`, `TODO.md`, `ROADMAP.md`, `*.local.md`, commit messages,
|
||||
test fixtures, and the `playground/A11Y-RAPPORT.md` artifact.
|
||||
|
||||
## [7.7.1] - 2026-05-18
|
||||
|
||||
Playground UX-strip etter v7.7.0-operatør-feedback. Hjem-overflaten ledet
|
||||
|
|
|
|||
|
|
@ -1,12 +1,14 @@
|
|||
# LLM Security Plugin (v7.7.1)
|
||||
# LLM Security Plugin (v7.7.2)
|
||||
|
||||
Security scanning, auditing, and threat modeling for Claude Code projects. 5 frameworks: OWASP LLM Top 10, Agentic AI Top 10 (ASI), Skills Top 10 (AST), MCP Top 10, AI Agent Traps (DeepMind). 1820+ unit, integration, and end-to-end tests (`tests/e2e/` covers the multi-hook attack chain, multi-session state simulation, and the full scan-orchestrator pipeline); mutation-testing coverage not published.
|
||||
|
||||
Release notes for v7.0.0 → v7.7.1: see `docs/version-history.md` — read on demand.
|
||||
Release notes for v7.0.0 → v7.7.2: see `docs/version-history.md` — read on demand.
|
||||
|
||||
**v7.7.1 highlights** — Playground UX-strip etter operatør-feedback: katalog er nå eneste levende overflate (onboarding/home/project-render-funksjonene er bevart i kildekoden men ikke rutbare før funksjonalitet legges til igjen). Topbar-breadcrumb leser ikke lenger demo-state-orgnavn; viser nøytralt `llm-security · Katalog`. Hardkodet versjons-streng i `renderHome` synket. Ingen scanner- eller hook-atferdsendringer.
|
||||
**v7.7.2 highlights** — Language consistency pass. Norwegian had crept into the playground UI strings, the canonical CLI renderer (`scripts/lib/report-renderers.mjs`), the HTML Report-step appended by all 18 skill commands, two agent prompts, and the marketplace + plugin README/CLAUDE.md state sections. Per the `~/.claude/CLAUDE.md` convention (English for code and documentation, Norwegian for dialog only), surface text was translated to English. Demo-state fixture content for the `dft-komplett-demo` project (intentional Norwegian persona) and regex alternations that match Norwegian-language report markdown (`/^high|^høy/`, `/resolution|løsning/`) were preserved. No scanner, hook, or behavior changes.
|
||||
|
||||
**v7.7.0 highlights** — All 18 report-producing skill commands now emit a clickable `file://` link to a self-contained HTML version of their markdown report. The new `scripts/render-report.mjs` CLI converts any of the 18 report types via a canonical `scripts/lib/report-renderers.mjs` (18 parsers + 18 renderers, bit-identical to the playground). HTML wraps the Tier 1/2/3 design system inline; no external assets, system fonts only (~140 KB per report). Playground also got list-view, copy-button, and prosjekt-surface cleanup.
|
||||
**v7.7.1 highlights** — Playground UX strip after operator feedback: the catalog is now the only routable surface (the onboarding/home/project render functions remain in source but are not routable until the feature is restored). The topbar breadcrumb no longer reads the demo-state org name; it shows a neutral `llm-security · Catalog`. The hardcoded version string in `renderHome` was synced. No scanner or hook behavior changes.
|
||||
|
||||
**v7.7.0 highlights** — All 18 report-producing skill commands now emit a clickable `file://` link to a self-contained HTML version of their markdown report. The new `scripts/render-report.mjs` CLI converts any of the 18 report types via a canonical `scripts/lib/report-renderers.mjs` (18 parsers + 18 renderers, bit-identical to the playground). HTML wraps the Tier 1/2/3 design system inline; no external assets, system fonts only (~140 KB per report). Playground also got list-view, copy-button, and project-surface cleanup.
|
||||
|
||||
## Commands
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
*AI-generated: all code produced by Claude Code through dialog-driven development. [Full disclosure →](../../README.md#ai-generated-code-disclosure)*
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
|
|
@ -492,16 +492,16 @@ a browser (Chrome/Firefox/Safari over `file://`) — no build step, no
|
|||
network calls, no npm install. Theme-bootstrap with FOUC-prevention; state
|
||||
persisted in IndexedDB primary + localStorage fallback.
|
||||
|
||||
**v7.6.0 Tier 3-referanse-case:** Playgroundet er nå en visuelt og
|
||||
strukturelt fullført referanse for `shared/playground-design-system/`
|
||||
Tier 3-supplementet. 8 nye DS-komponenter integrert i de 18 rapport-
|
||||
rendererne: `tfa-flow` (lethal trifecta-kjede), `mat-ladder` (modenhets-
|
||||
stige), `suppressed-group` (narrative-audit), `codepoint-reveal` (Unicode-
|
||||
steganografi), `top-risks` (rangert top-funn), `recommendation-card[data-
|
||||
severity]` (severity-tinted advisory), `risk-meter` (band-visualisering
|
||||
0-100), `card--severity-{level}` (severity-color findings-cards). Pluss
|
||||
`badge--scope-security`, `verdict-pill-lg` og `form-progress`+`fp-step`
|
||||
fra wave 1.
|
||||
**v7.6.0 Tier 3 reference case:** The playground is now a visually and
|
||||
structurally complete reference for the `shared/playground-design-system/`
|
||||
Tier 3 supplement. 8 new DS components integrated into the 18 report
|
||||
renderers: `tfa-flow` (lethal trifecta chain), `mat-ladder` (maturity
|
||||
ladder), `suppressed-group` (narrative audit), `codepoint-reveal` (Unicode
|
||||
steganography), `top-risks` (ranked top findings), `recommendation-card
|
||||
[data-severity]` (severity-tinted advisory), `risk-meter` (band
|
||||
visualization 0-100), `card--severity-{level}` (severity-color findings
|
||||
cards). Plus `badge--scope-security`, `verdict-pill-lg`, and
|
||||
`form-progress`+`fp-step` from wave 1.
|
||||
|
||||
**Layout:**
|
||||
|
||||
|
|
@ -509,48 +509,50 @@ fra wave 1.
|
|||
playground/
|
||||
├── llm-security-playground.html ← single-file SPA (~10 700 lines)
|
||||
├── vendor/
|
||||
│ └── playground-design-system/ ← synket fra shared/, sjekksum-låst
|
||||
├── test-fixtures/ ← markdown-fixtures (én per kommando)
|
||||
├── screenshots/v7.5.0/ ← Playwright-genererte demobilder (12)
|
||||
├── screenshots/v7.6.0/ ← v7.6.0 demobilder (12, manuelt generert)
|
||||
└── A11Y-RAPPORT.md ← WCAG 2.1 AA verifisering + Tier 3 ARIA
|
||||
│ └── playground-design-system/ ← synced from shared/, checksum-locked
|
||||
├── test-fixtures/ ← markdown fixtures (one per command)
|
||||
├── screenshots/v7.5.0/ ← Playwright-generated demo images (12)
|
||||
├── screenshots/v7.6.0/ ← v7.6.0 demo images (12, hand-generated)
|
||||
└── A11Y-RAPPORT.md ← WCAG 2.1 AA verification + Tier 3 ARIA
|
||||
```
|
||||
|
||||
**Hva playgroundet dekker:**
|
||||
**What the playground covers:**
|
||||
|
||||
- **Onboarding (5 grupper):** organisasjon, scope, profil, plattform,
|
||||
compliance. Verdier persisteres som `shared`-state og prefylles automatisk
|
||||
i alle command-skjemaer.
|
||||
- **Home:** prosjekt-grid, fleet-tracks for posture/scan/red-team. «Last
|
||||
inn demo-data»-knappen aktiverer 3 prosjekter inkludert `dft-komplett-demo`
|
||||
med alle 18 rapporter ferdig parsed.
|
||||
- **Catalog:** alle 20 kommandoer gruppert i 5 kategorier. Søk filtrerer
|
||||
cards, og «Åpne skjema»-knapp bygger ferdig pipeline-streng for klipp-og-
|
||||
lim til terminalen.
|
||||
- **Project surface:** 4 skjermer (Oversikt / Rapporter / Kontekst /
|
||||
Eksport). Rapporter-tabben har category-tabs (discover / posture /
|
||||
findings-ops / hardening / adversarial / mcp-ops) og lim-inn-import for
|
||||
hver rapport-kommando.
|
||||
- **Onboarding (5 groups):** organization, scope, profile, platform,
|
||||
compliance. Values persist as `shared` state and prefill every command
|
||||
form automatically.
|
||||
- **Home:** project grid, fleet tracks for posture/scan/red-team. The
|
||||
"Load demo data" button activates 3 projects, including
|
||||
`dft-komplett-demo` with all 18 reports parsed in advance.
|
||||
- **Catalog:** all 20 commands grouped into 5 categories. Search filters
|
||||
cards, and the "Open form" button builds a ready-to-paste pipeline
|
||||
string for the terminal.
|
||||
- **Project surface:** 4 screens (Overview / Reports / Context / Export).
|
||||
The Reports tab has category tabs (discover / posture / findings-ops /
|
||||
hardening / adversarial / mcp-ops) and paste-import for every report
|
||||
command.
|
||||
|
||||
**Parser/renderer-arkitektur:** Hver `produces_report=true`-kommando i
|
||||
`CATALOG` har en parser (markdown → struktur) og en renderer (struktur
|
||||
→ DS-komponenter). 18 archetypes støttes: `findings`, `findings-grade`,
|
||||
`risk-score-meter`, `posture-cards`, `dashboard-fleet`, `red-team-results`,
|
||||
`diff-report`, `kanban-buckets`, `matrix-risk`. Parser-kontrakten er
|
||||
`{ ok: true, data: {...} } | { ok: false, errors: [...] }`. Test-fixtures
|
||||
under `playground/test-fixtures/` er kontrakt-anker — én markdown-fil per
|
||||
kommando som speiler `templates/unified-report.md`-formatet.
|
||||
**Parser/renderer architecture:** Every `produces_report=true` command in
|
||||
`CATALOG` has a parser (markdown → structure) and a renderer (structure
|
||||
→ DS components). 18 archetypes are supported: `findings`,
|
||||
`findings-grade`, `risk-score-meter`, `posture-cards`, `dashboard-fleet`,
|
||||
`red-team-results`, `diff-report`, `kanban-buckets`, `matrix-risk`. The
|
||||
parser contract is `{ ok: true, data: {...} } | { ok: false, errors:
|
||||
[...] }`. The test fixtures under `playground/test-fixtures/` are the
|
||||
contract anchor — one markdown file per command, mirroring the
|
||||
`templates/unified-report.md` format.
|
||||
|
||||
**Eksponerte testing/automasjons-globaler:** `__store`, `__navigate`,
|
||||
**Exposed testing/automation globals:** `__store`, `__navigate`,
|
||||
`__loadDemoState`, `__scheduleRender`, `__PARSERS`, `__RENDERERS`,
|
||||
`__CATALOG`, `__inferVerdict`, `__inferKeyStats`, `__renderPageShell`,
|
||||
`__handlePasteImport`. Aktiverer Playwright-styrt navigasjon og
|
||||
programmatisk parser/renderer-test mot fixture-katalogen.
|
||||
`__handlePasteImport`. They enable Playwright-driven navigation and
|
||||
programmatic parser/renderer tests against the fixture catalog.
|
||||
|
||||
**Begrensninger:** SPA er en lim-inn-overflate — den kjører ingen scannere
|
||||
selv. Output må komme fra Claude Code (`/security scan ...`), CLI
|
||||
(`node scanners/...`) eller stub-fixtures. Demo-state inneholder kun de
|
||||
3 inline-prosjektene; nye prosjekter er per-bruker og lagres lokalt.
|
||||
**Limitations:** The SPA is a paste-in surface — it does not run any
|
||||
scanners itself. Output must come from Claude Code (`/security scan
|
||||
...`), the CLI (`node scanners/...`), or stub fixtures. Demo state only
|
||||
contains the 3 inline projects; new projects are per-user and stored
|
||||
locally.
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -626,11 +628,12 @@ demonstrations — each with `README.md`, fixture, run script, and
|
|||
|
||||
| Version | Date | Highlights |
|
||||
|---------|------|------------|
|
||||
| **7.7.1** | 2026-05-18 | **Playground UX-strip.** Operatør-feedback umiddelbart etter v7.7.0: hjem-overflaten ledet med tre prosjekt-tracks (Re-onboard / Nytt prosjekt / Command-katalog) selv om katalog var det viktige. Minimum-strip levert som tre atomic commits (`b732eee` + `2a6f73f` + `81b7beb`): (1) router tvinger alltid `activeSurface = 'catalog'` (onboarding/home/project-render-funksjonene bevart men ikke rutbare); (2) topbar `Hjem` + `Re-onboard`-knapper fjernet, `Katalog` beholdt; (3) breadcrumb-orgname (`shared.organization.name` fra demo-state) erstattet med statisk `llm-security` som nøytralt scope-anker. Fix: hardkodet `'Plugin v7.6.1'` på linje 6933 i `renderHome` (template-litteral som v7.7.0-grep-en ikke fanget) synket. Onboarding-konseptet dokumentert som v7.8.0-kandidat (per-kommando kontekst-injeksjon) i `ROADMAP.md`. Ingen scanner- eller hook-atferdsendringer. |
|
||||
| **7.7.0** | 2026-05-18 | **HTML-rapport for alle 18 skill-kommandoer.** Hver `/security <cmd>` som produserer rapport printer nå en klikkbar `file://`-lenke til en self-contained HTML-versjon. Levert over 5 sesjoner. (1) Playground katalog list-view + builder-pane med copy-knapp. (2) Playground prosjekt-surface opprydding (stub-screen-håndtering, topbar-splitt). (3) De 18 inline parserne + rendererne i playground-HTML flyttet til canonical ESM-modul `scripts/lib/report-renderers.mjs` (playground beholder bit-identisk inline-kopi siden ESM `import` ikke fungerer fra `file://`). (4) Ny zero-dep CLI `scripts/render-report.mjs` — stdin/file/stdout-modus, kebab→camel commandId-routing, inliner 6 DS-stylesheets + lokal `.report-table`-CSS, ~140 KB self-contained HTML, system-font-fallback, absolutte `file://`-paths for Ghostty cmd-click. (5) Alle 18 skills wired (4 i sesjon 4: scan/audit/posture/deep-scan, 14 i sesjon 5: plugin-audit/mcp-audit/mcp-inspect/ide-scan/supply-check/dashboard/pre-deploy/diff/watch/registry/clean/harden/threat-model/red-team). Output: `reports/<command>-<YYYYMMDD-HHmmss>.html` relativt til CWD. Ingen scanner- eller hook-atferdsendringer — purely additive. |
|
||||
| **7.6.1** | 2026-05-06 | **Playground v7.6.0 visuell-patch.** Seks bugs fanget under maintainer-verifisering i nettleser. Alle skyldtes mismatch mellom DS-klasser og rendrer-bruk (eller manglende DS-implementasjoner playground antok eksisterte). (1) `renderFindingsBlock` brukte `.findings` outer som er DS' 2-kolonners list+detail-grid → erstattet med `<section class="report-meta">` + korrekt `findings__list > findings__group`-mønster. (2) `.report-table` manglet helt i DS men brukes i 7+ rendrere → lokal CSS-implementasjon i playground-HTML. (3) `renderPreDeploy` traffic-lights brukte `.sm-card__grade` (28×28 px for én A-F-bokstav) for "PASS"/"PASS-WITH-NOTES"/"FAIL" → erstattet med bredde-tilpasset status-pill. (4) Threat-model matrix-bobler ikke klikkbare → `<button>` med `data-threat-id` + click-handler som scroller til Trusler-tabellen. (5) Radar-labels overlappet ved 6+ akser → SVG 280→380, R 105→125, dynamisk `text-anchor` (start/end/middle) basert på horisontal-posisjon. (6) `recommendation-card__body` overflow på lange tekster → `overflow-wrap: anywhere`. 4/4 fix-spesifikke smoke-tester + 18/18 renderer-regresjon passerer. Ingen scanner- eller hook-atferdsendringer — purely additive surface. |
|
||||
| **7.6.0** | 2026-05-06 | **Playground Tier 3-referanse-case.** Playground (`playground/llm-security-playground.html`) hevet til visuelt og strukturelt fullført referanse for `shared/playground-design-system/` Tier 3-supplementet. 8 nye DS-komponenter integrert i de 18 rapport-rendererne: `tfa-flow` + `tfa-leg` + `tfa-arrow` (lethal trifecta-kjede med `<button>`-elementer + ARIA), `mat-ladder` + `mat-step` (5-trinns modenhets-stige med terskler 0/25/50/75/95% PASS), `suppressed-group` (narrative-audit fra `summary.narrative_audit.suppressed_findings`), `codepoint-reveal` + `cp-tag`/`cp-zw`/`cp-bidi` (Unicode-steganografi side-ved-side), `top-risks` + `top-risk[data-severity]` (rangert top-funn-listing, semantisk `<ol>`), `recommendation-card[data-severity]` (severity-tinted advisory på `clean`/`harden`/`audit`/`posture`/`pre-deploy`/`plugin-audit`), `risk-meter` (band-visualisering 0-100 på 5 archetypes), `card--severity-{level}` (severity-color modifier på findings-cards). Wave 1: `badge--scope-security` (identitets-chip), `verdict-pill-lg` (DS Tier 3-pill), `form-progress` + `fp-step` (onboarding-wizard). Slettet ~30 duplikat-CSS-deklarasjoner (DS vinner cascade). 5 nye DS-helpers + `mapSeverityToCardLevel` + `parseNarrativeAudit`. Filendring 10209 → 10677 linjer. Levert over 5 sesjoner, atomic commits. A11Y-rapport oppdatert. Ingen scanner- eller hook-behavior-changes — purely additive surface. |
|
||||
| **7.5.0** | 2026-05-05 | **Playground.** Single-file SPA at `playground/llm-security-playground.html` (~10 200 lines) for onboarding, demoer og workshop-bruk uten Claude Code-installasjon. Parsere + renderere for alle 18 `produces_report=true`-kommandoer (Fase 2: 10 høy-prio + Fase 3: 8 gjenstående: mcp-inspect, supply-check, pre-deploy, diff, watch, registry, clean, threat-model). 18 markdown test-fixtures under `playground/test-fixtures/` som kontrakt-anker. Komplett demo-prosjekt `dft-komplett-demo` har alle 18 rapporter ferdig parsed inline. Vendor-synket design-system under `playground/vendor/` (sjekksum-låst). 9 Playwright-genererte screenshots i `playground/screenshots/v7.5.0/`. 11 nye `window`-globaler for testing/automasjon. 2 nye `KEY_STATS_CONFIG`-archetypes (`kanban-buckets`, `matrix-risk`). Bug-fix: `normalizeVerdictText` regex-rekkefølge oppdatert så GO-WITH-CONDITIONS / CONDITIONAL / BETINGET ikke lenger kollapser til ALLOW. Ingen scanner- eller hook-behavior-changes — purely additive surface. |
|
||||
| **7.7.2** | 2026-05-19 | **Language consistency pass.** Norwegian had crept into surface text across v7.5-v7.7. Per the `~/.claude/CLAUDE.md` convention (English for code and documentation, Norwegian for dialog only), this release translates: the HTML Report-step appended by all 18 skill commands, the canonical CLI renderer `scripts/lib/report-renderers.mjs` (display strings + JS comments), the playground UI strings, the `skill-scanner-agent` and `mcp-scanner-agent` system prompts, the Recent versions table and playground architecture prose in this README, the v7.7.x highlights in `CLAUDE.md`, and the llm-security entries in the marketplace root `README.md` + `CLAUDE.md`, plus six table cells in `docs/scanner-reference.md`. Demo-state fixture content for the `dft-komplett-demo` project (intentional Norwegian persona) and regex alternations that match Norwegian-language report markdown (`/^high\|^høy/`, `/resolution\|løsning/`) were preserved. No scanner, hook, or behavior changes — purely surface text. |
|
||||
| **7.7.1** | 2026-05-18 | **Playground UX strip.** Operator feedback immediately after v7.7.0: the home surface led with three project tracks (Re-onboard / New project / Command catalog) even though the catalog was the important entry point. Minimum strip delivered as three atomic commits (`b732eee` + `2a6f73f` + `81b7beb`): (1) the router always forces `activeSurface = 'catalog'` (the onboarding/home/project render functions are preserved in source but no longer routable); (2) the topbar `Home` and `Re-onboard` buttons removed, `Catalog` retained; (3) the breadcrumb org-name (`shared.organization.name` from demo state) replaced with a static `llm-security` neutral scope anchor. Fix: the hardcoded `'Plugin v7.6.1'` on line 6933 of `renderHome` (template literal not caught by the v7.7.0 grep) was synced. The onboarding concept is documented as a v7.8.0 candidate (per-command context injection) in `ROADMAP.md`. No scanner or hook behavior changes. |
|
||||
| **7.7.0** | 2026-05-18 | **HTML report for all 18 skill commands.** Every `/security <cmd>` that produces a report now prints a clickable `file://` link to a self-contained HTML version. Delivered across 5 sessions. (1) Playground catalog list-view + builder-pane with a copy button. (2) Playground project-surface cleanup (stub-screen handling, topbar split). (3) The 18 inline parsers + renderers in the playground HTML were moved to a canonical ESM module `scripts/lib/report-renderers.mjs` (the playground keeps a bit-identical inline copy since ESM `import` does not work from `file://`). (4) New zero-dep CLI `scripts/render-report.mjs` — stdin/file/stdout mode, kebab→camel commandId routing, inlines 6 DS stylesheets + a local `.report-table` CSS, ~140 KB self-contained HTML, system-font fallback, absolute `file://` paths for Ghostty cmd-click. (5) All 18 skills wired (4 in session 4: scan/audit/posture/deep-scan; 14 in session 5: plugin-audit/mcp-audit/mcp-inspect/ide-scan/supply-check/dashboard/pre-deploy/diff/watch/registry/clean/harden/threat-model/red-team). Output: `reports/<command>-<YYYYMMDD-HHmmss>.html` relative to CWD. No scanner or hook behavior changes — purely additive. |
|
||||
| **7.6.1** | 2026-05-06 | **Playground v7.6.0 visual patch.** Six bugs caught during maintainer verification in the browser. All were mismatches between DS classes and renderer usage (or missing DS implementations the playground assumed existed). (1) `renderFindingsBlock` used the `.findings` outer class, which is the DS 2-column list+detail grid → replaced with `<section class="report-meta">` + the correct `findings__list > findings__group` pattern. (2) `.report-table` was missing entirely from the DS but used in 7+ renderers → local CSS implementation in the playground HTML. (3) `renderPreDeploy` traffic-lights used `.sm-card__grade` (28×28 px for one A-F letter) for "PASS"/"PASS-WITH-NOTES"/"FAIL" → replaced with a width-adapting status pill. (4) Threat-model matrix bubbles were not clickable → `<button>` with `data-threat-id` + click handler that scrolls to the Threats table. (5) Radar labels overlapped at 6+ axes → SVG 280→380, R 105→125, dynamic `text-anchor` (start/end/middle) based on horizontal position. (6) `recommendation-card__body` overflow on long text → `overflow-wrap: anywhere`. 4/4 fix-specific smoke tests + 18/18 renderer regression passing. No scanner or hook behavior changes — purely additive surface. |
|
||||
| **7.6.0** | 2026-05-06 | **Playground Tier 3 reference case.** The playground (`playground/llm-security-playground.html`) raised to a visually and structurally complete reference for the `shared/playground-design-system/` Tier 3 supplement. 8 new DS components integrated into the 18 report renderers: `tfa-flow` + `tfa-leg` + `tfa-arrow` (lethal trifecta chain with `<button>` elements + ARIA), `mat-ladder` + `mat-step` (5-step maturity ladder with thresholds 0/25/50/75/95% PASS), `suppressed-group` (narrative audit from `summary.narrative_audit.suppressed_findings`), `codepoint-reveal` + `cp-tag`/`cp-zw`/`cp-bidi` (Unicode steganography side-by-side), `top-risks` + `top-risk[data-severity]` (ranked top-findings listing, semantic `<ol>`), `recommendation-card[data-severity]` (severity-tinted advisory on `clean`/`harden`/`audit`/`posture`/`pre-deploy`/`plugin-audit`), `risk-meter` (0-100 band visualization across 5 archetypes), `card--severity-{level}` (severity-color modifier on findings cards). Wave 1: `badge--scope-security` (identity chip), `verdict-pill-lg` (DS Tier 3 pill), `form-progress` + `fp-step` (onboarding wizard). Removed ~30 duplicate CSS declarations (DS wins the cascade). 5 new DS helpers + `mapSeverityToCardLevel` + `parseNarrativeAudit`. File size 10209 → 10677 lines. Delivered across 5 sessions, atomic commits. A11Y report updated. No scanner or hook behavior changes — purely additive surface. |
|
||||
| **7.5.0** | 2026-05-05 | **Playground.** Single-file SPA at `playground/llm-security-playground.html` (~10 200 lines) for onboarding, demos and workshop use without a Claude Code installation. Parsers + renderers for all 18 `produces_report=true` commands (Phase 2: 10 high-priority + Phase 3: 8 remaining: mcp-inspect, supply-check, pre-deploy, diff, watch, registry, clean, threat-model). 18 markdown test fixtures under `playground/test-fixtures/` as contract anchors. The complete demo project `dft-komplett-demo` has all 18 reports parsed inline. Vendor-synced design-system under `playground/vendor/` (checksum-locked). 9 Playwright-generated screenshots under `playground/screenshots/v7.5.0/`. 11 new `window` globals for testing/automation. 2 new `KEY_STATS_CONFIG` archetypes (`kanban-buckets`, `matrix-risk`). Bug-fix: `normalizeVerdictText` regex order updated so GO-WITH-CONDITIONS / CONDITIONAL / BETINGET no longer collapse to ALLOW. No scanner or hook behavior changes — purely additive surface. |
|
||||
| **7.4.0** | 2026-05-05 | **Examples + e2e suite.** Seven runnable demonstration walkthroughs under `examples/` (`prompt-injection-showcase`, `lethal-trifecta-walkthrough`, `mcp-rug-pull`, `supply-chain-attack`, `poisoned-claude-md`, `bash-evasion-gallery`, `toxic-agent-demo`, `pre-compact-poisoning`) — each with `README.md`, runtime-isolated fixture, single-command run-script, and `expected-findings.md` testable contract. Three new `tests/e2e/` suites (attack-chain 17 tests + multi-session 9 tests + scan-pipeline 19 tests = +45 tests, total 1822) prove the framework works as a coordinated system, not just isolated units. No scanner or hook behavior changes — purely additive surface. Scanner `VERSION` constants synced across `dashboard-aggregator.mjs`, `posture-scanner.mjs`, `ide-extension-scanner.mjs`. |
|
||||
| **7.3.1** | 2026-05-01 | **Stabilization patch.** Project repositioned as solo, stabilization-only, with explicit "fork & own" stance for enterprise features. New public docs: `CONTRIBUTING.md` (fork-and-own model), README "Project scope" section (out-of-scope table with commercial alternatives), updated `SECURITY.md` (v7.3.x supported, v7.0–v7.2 best-effort, < v7.0 EOL). Coherence: `package.json` files whitelist + `bugs` URL + repo URL fix; scanner `VERSION` constants synced across `dashboard-aggregator.mjs`, `posture-scanner.mjs`, `ide-extension-scanner.mjs`. Test ceiling raised on flaky pre-compact-scan timing test (500 ms → 1000 ms; design target unchanged). No behavior changes. |
|
||||
| **7.3.0** | 2026-05-01 | **Batch C release.** Wave A (T7-T9 bash normalization + rot13 comment-block decoder), Wave B (`.gitattributes` post-clone advisory + npm scope-hop typosquat + GitHub/Forgejo workflow-scanner with 23-field blacklist + re-interpolation tracking + auth-bypass detection), Wave C (MCP cumulative-drift baseline + `/security mcp-baseline-reset`), Wave D (riskScoreV1 `@deprecated`; sandbox-architecture rationale docs; env-var deprecation runway to v8.0.0; CLAUDE.md hooks count + consistency test). 1665+ → 1777 tests. Wave E (additional attack-simulator scenarios) deferred indefinitely |
|
||||
|
|
|
|||
|
|
@ -25,19 +25,21 @@ Your output is a structured security report per MCP server, including trust rati
|
|||
findings mapped to OWASP categories, and prioritized recommendations. You operate read-only —
|
||||
never modify files or install packages.
|
||||
|
||||
## Step 0: Generaliseringsgrense
|
||||
## Step 0: Generalization boundary
|
||||
|
||||
Opus 4.7 tolker instruks mer literalt enn tidligere modeller. Ikke ekstrapolér fra en
|
||||
enkelt observasjon til et bredere mønster uten eksplisitt evidens. Rapporter det du
|
||||
faktisk ser; merk spekulasjon som spekulasjon. Ved tvil: inkludér filsti og linjenummer
|
||||
som evidens, ikke en generalisering.
|
||||
Opus 4.7 interprets instructions more literally than earlier models. Do not
|
||||
extrapolate from a single observation to a broader pattern without explicit
|
||||
evidence. Report what you actually see; mark speculation as speculation. When
|
||||
in doubt, cite the filepath and line number as evidence rather than a
|
||||
generalization.
|
||||
|
||||
## Parallell Read-strategi
|
||||
## Parallel Read strategy
|
||||
|
||||
Når du trenger å lese tre eller flere filer som ikke avhenger av hverandre, send alle
|
||||
Read-kallene i samme melding (parallell), ikke sekvensielt. Dette gjelder spesielt:
|
||||
knowledge-files i oppstart, og batcher av MCP-server-filer. Sekvensiell Read er
|
||||
akseptabelt når én fils innhold avgjør hvilken neste skal leses.
|
||||
When you need to read three or more files that do not depend on each other,
|
||||
send all the Read calls in the same message (parallel), not sequentially. This
|
||||
applies especially to knowledge files during startup and to batches of
|
||||
MCP-server files. Sequential Read is acceptable when one file's contents
|
||||
determine which file to read next.
|
||||
|
||||
Reference knowledge base files before scanning:
|
||||
- `knowledge/mcp-threat-patterns.md` — 9 threat categories with detection signals (MCP01-MCP10 mapping)
|
||||
|
|
|
|||
|
|
@ -24,19 +24,21 @@ You are invoked by `/security scan` with a target path. Your `tools:` frontmatte
|
|||
simply does not grant file-modifying tools. Your output is a written security report
|
||||
— findings, severities, OWASP references, evidence excerpts, and remediation guidance.
|
||||
|
||||
## Step 0: Generaliseringsgrense
|
||||
## Step 0: Generalization boundary
|
||||
|
||||
Opus 4.7 tolker instruks mer literalt enn tidligere modeller. Ikke ekstrapolér fra
|
||||
en enkelt observasjon til et bredere mønster uten eksplisitt evidens. Rapporter det
|
||||
du faktisk ser; merk spekulasjon som spekulasjon. Ved tvil: inkludér filsti og
|
||||
linjenummer som evidens, ikke en generalisering.
|
||||
Opus 4.7 interprets instructions more literally than earlier models. Do not
|
||||
extrapolate from a single observation to a broader pattern without explicit
|
||||
evidence. Report what you actually see; mark speculation as speculation. When
|
||||
in doubt, cite the filepath and line number as evidence rather than a
|
||||
generalization.
|
||||
|
||||
## Parallell Read-strategi
|
||||
## Parallel Read strategy
|
||||
|
||||
Når du trenger å lese tre eller flere filer som ikke avhenger av hverandre, send
|
||||
alle Read-kallene i samme melding (parallell), ikke sekvensielt. Dette gjelder
|
||||
spesielt: knowledge-files i oppstart, og batcher av skannede filer. Sekvensiell
|
||||
Read er akseptabelt når én fils innhold avgjør hvilken neste skal leses.
|
||||
When you need to read three or more files that do not depend on each other,
|
||||
send all the Read calls in the same message (parallel), not sequentially. This
|
||||
applies especially to knowledge files during startup and to batches of scanned
|
||||
files. Sequential Read is acceptable when one file's contents determine which
|
||||
file to read next.
|
||||
|
||||
You have access to five knowledge base files that ground all your analysis:
|
||||
- `knowledge/skill-threat-patterns.md` — 7 threat categories with documented attack variants
|
||||
|
|
|
|||
|
|
@ -65,6 +65,6 @@ After producing the markdown audit report above:
|
|||
The CLI writes `reports/audit-<YYYYMMDD-HHmmss>.html` relative to CWD and prints `file:///abs/path.html` on stdout.
|
||||
4. Append to your response (markdown link, no bare URL):
|
||||
|
||||
> **HTML-rapport:** [Åpne i nettleser](file:///abs/path.html)
|
||||
> **HTML report:** [Open in browser](file:///abs/path.html)
|
||||
|
||||
If the CLI exits non-zero, mention the error but do not block — the markdown audit above is the primary deliverable.
|
||||
|
|
|
|||
|
|
@ -76,6 +76,6 @@ After producing the markdown clean report above:
|
|||
The CLI writes `reports/clean-<YYYYMMDD-HHmmss>.html` relative to CWD and prints `file:///abs/path.html` on stdout.
|
||||
4. Append to your response (markdown link, no bare URL):
|
||||
|
||||
> **HTML-rapport:** [Åpne i nettleser](file:///abs/path.html)
|
||||
> **HTML report:** [Open in browser](file:///abs/path.html)
|
||||
|
||||
If the CLI exits non-zero, mention the error but do not block — the markdown report above is the primary deliverable.
|
||||
|
|
|
|||
|
|
@ -76,6 +76,6 @@ After producing the markdown dashboard above:
|
|||
The CLI writes `reports/dashboard-<YYYYMMDD-HHmmss>.html` relative to CWD and prints `file:///abs/path.html` on stdout.
|
||||
4. Append to your response (markdown link, no bare URL):
|
||||
|
||||
> **HTML-rapport:** [Åpne i nettleser](file:///abs/path.html)
|
||||
> **HTML report:** [Open in browser](file:///abs/path.html)
|
||||
|
||||
If the CLI exits non-zero, mention the error but do not block — the markdown dashboard above is the primary deliverable.
|
||||
|
|
|
|||
|
|
@ -57,6 +57,6 @@ After producing the markdown deep-scan report (banner + synthesizer output or fa
|
|||
The CLI writes `reports/deep-scan-<YYYYMMDD-HHmmss>.html` relative to CWD and prints `file:///abs/path.html` on stdout.
|
||||
4. Append to your response (markdown link, no bare URL):
|
||||
|
||||
> **HTML-rapport:** [Åpne i nettleser](file:///abs/path.html)
|
||||
> **HTML report:** [Open in browser](file:///abs/path.html)
|
||||
|
||||
If the CLI exits non-zero, mention the error but do not block — the markdown report above is the primary deliverable.
|
||||
|
|
|
|||
|
|
@ -113,6 +113,6 @@ After producing the markdown diff report above:
|
|||
The CLI writes `reports/diff-<YYYYMMDD-HHmmss>.html` relative to CWD and prints `file:///abs/path.html` on stdout.
|
||||
4. Append to your response (markdown link, no bare URL):
|
||||
|
||||
> **HTML-rapport:** [Åpne i nettleser](file:///abs/path.html)
|
||||
> **HTML report:** [Open in browser](file:///abs/path.html)
|
||||
|
||||
If the CLI exits non-zero, mention the error but do not block — the markdown report above is the primary deliverable.
|
||||
|
|
|
|||
|
|
@ -87,6 +87,6 @@ After producing the markdown harden report above:
|
|||
The CLI writes `reports/harden-<YYYYMMDD-HHmmss>.html` relative to CWD and prints `file:///abs/path.html` on stdout.
|
||||
4. Append to your response (markdown link, no bare URL):
|
||||
|
||||
> **HTML-rapport:** [Åpne i nettleser](file:///abs/path.html)
|
||||
> **HTML report:** [Open in browser](file:///abs/path.html)
|
||||
|
||||
If the CLI exits non-zero, mention the error but do not block — the markdown report above is the primary deliverable.
|
||||
|
|
|
|||
|
|
@ -121,6 +121,6 @@ After producing the markdown IDE-scan report above:
|
|||
The CLI writes `reports/ide-scan-<YYYYMMDD-HHmmss>.html` relative to CWD and prints `file:///abs/path.html` on stdout.
|
||||
4. Append to your response (markdown link, no bare URL):
|
||||
|
||||
> **HTML-rapport:** [Åpne i nettleser](file:///abs/path.html)
|
||||
> **HTML report:** [Open in browser](file:///abs/path.html)
|
||||
|
||||
If the CLI exits non-zero, mention the error but do not block — the markdown report above is the primary deliverable.
|
||||
|
|
|
|||
|
|
@ -62,6 +62,6 @@ After producing the markdown MCP audit report (Step 3 + optional Step 4 Live Ins
|
|||
The CLI writes `reports/mcp-audit-<YYYYMMDD-HHmmss>.html` relative to CWD and prints `file:///abs/path.html` on stdout.
|
||||
4. Append to your response (markdown link, no bare URL):
|
||||
|
||||
> **HTML-rapport:** [Åpne i nettleser](file:///abs/path.html)
|
||||
> **HTML report:** [Open in browser](file:///abs/path.html)
|
||||
|
||||
If the CLI exits non-zero, mention the error but do not block — the markdown report above is the primary deliverable.
|
||||
|
|
|
|||
|
|
@ -69,6 +69,6 @@ After producing the markdown live-inspection report above:
|
|||
The CLI writes `reports/mcp-inspect-<YYYYMMDD-HHmmss>.html` relative to CWD and prints `file:///abs/path.html` on stdout.
|
||||
4. Append to your response (markdown link, no bare URL):
|
||||
|
||||
> **HTML-rapport:** [Åpne i nettleser](file:///abs/path.html)
|
||||
> **HTML report:** [Open in browser](file:///abs/path.html)
|
||||
|
||||
If the CLI exits non-zero, mention the error but do not block — the markdown report above is the primary deliverable.
|
||||
|
|
|
|||
|
|
@ -89,6 +89,6 @@ After producing the markdown plugin-audit report (Step 5) and any cleanup (Step
|
|||
The CLI writes `reports/plugin-audit-<YYYYMMDD-HHmmss>.html` relative to CWD and prints `file:///abs/path.html` on stdout.
|
||||
4. Append to your response (markdown link, no bare URL):
|
||||
|
||||
> **HTML-rapport:** [Åpne i nettleser](file:///abs/path.html)
|
||||
> **HTML report:** [Open in browser](file:///abs/path.html)
|
||||
|
||||
If the CLI exits non-zero, mention the error but do not block — the markdown report above is the primary deliverable.
|
||||
|
|
|
|||
|
|
@ -75,6 +75,6 @@ After producing the markdown scorecard above:
|
|||
The CLI writes `reports/posture-<YYYYMMDD-HHmmss>.html` relative to CWD and prints `file:///abs/path.html` on stdout.
|
||||
4. Append to your response (markdown link, no bare URL):
|
||||
|
||||
> **HTML-rapport:** [Åpne i nettleser](file:///abs/path.html)
|
||||
> **HTML report:** [Open in browser](file:///abs/path.html)
|
||||
|
||||
If the CLI exits non-zero, mention the error but do not block — the markdown scorecard above is the primary deliverable.
|
||||
|
|
|
|||
|
|
@ -116,6 +116,6 @@ After producing the markdown pre-deploy checklist + verdict above:
|
|||
The CLI writes `reports/pre-deploy-<YYYYMMDD-HHmmss>.html` relative to CWD and prints `file:///abs/path.html` on stdout.
|
||||
4. Append to your response (markdown link, no bare URL):
|
||||
|
||||
> **HTML-rapport:** [Åpne i nettleser](file:///abs/path.html)
|
||||
> **HTML report:** [Open in browser](file:///abs/path.html)
|
||||
|
||||
If the CLI exits non-zero, mention the error but do not block — the markdown checklist above is the primary deliverable.
|
||||
|
|
|
|||
|
|
@ -110,6 +110,6 @@ After producing the markdown red-team narrative report above:
|
|||
The CLI writes `reports/red-team-<YYYYMMDD-HHmmss>.html` relative to CWD and prints `file:///abs/path.html` on stdout.
|
||||
4. Append to your response (markdown link, no bare URL):
|
||||
|
||||
> **HTML-rapport:** [Åpne i nettleser](file:///abs/path.html)
|
||||
> **HTML report:** [Open in browser](file:///abs/path.html)
|
||||
|
||||
If the CLI exits non-zero, mention the error but do not block — the markdown report above is the primary deliverable.
|
||||
|
|
|
|||
|
|
@ -136,6 +136,6 @@ After producing the markdown registry output above (stats / scan-result / search
|
|||
The CLI writes `reports/registry-<YYYYMMDD-HHmmss>.html` relative to CWD and prints `file:///abs/path.html` on stdout.
|
||||
4. Append to your response (markdown link, no bare URL):
|
||||
|
||||
> **HTML-rapport:** [Åpne i nettleser](file:///abs/path.html)
|
||||
> **HTML report:** [Open in browser](file:///abs/path.html)
|
||||
|
||||
If the CLI exits non-zero, mention the error but do not block — the markdown output above is the primary deliverable.
|
||||
|
|
|
|||
|
|
@ -172,6 +172,6 @@ After producing the markdown report (Step 5) and any cleanup (Step 7):
|
|||
The CLI writes `reports/scan-<YYYYMMDD-HHmmss>.html` relative to CWD and prints `file:///abs/path.html` on stdout (one line).
|
||||
4. Append this to your response (markdown link, no bare URL):
|
||||
|
||||
> **HTML-rapport:** [Åpne i nettleser](file:///abs/path.html)
|
||||
> **HTML report:** [Open in browser](file:///abs/path.html)
|
||||
|
||||
If the CLI exits non-zero, mention the error but do not block — the markdown report above is the primary deliverable.
|
||||
|
|
|
|||
|
|
@ -62,6 +62,6 @@ After producing the markdown supply-check report above:
|
|||
The CLI writes `reports/supply-check-<YYYYMMDD-HHmmss>.html` relative to CWD and prints `file:///abs/path.html` on stdout.
|
||||
4. Append to your response (markdown link, no bare URL):
|
||||
|
||||
> **HTML-rapport:** [Åpne i nettleser](file:///abs/path.html)
|
||||
> **HTML report:** [Open in browser](file:///abs/path.html)
|
||||
|
||||
If the CLI exits non-zero, mention the error but do not block — the markdown report above is the primary deliverable.
|
||||
|
|
|
|||
|
|
@ -42,6 +42,6 @@ After the threat-modeler agent has produced the complete threat-model markdown d
|
|||
The CLI writes `reports/threat-model-<YYYYMMDD-HHmmss>.html` relative to CWD and prints `file:///abs/path.html` on stdout.
|
||||
4. Append to your response (markdown link, no bare URL):
|
||||
|
||||
> **HTML-rapport:** [Åpne i nettleser](file:///abs/path.html)
|
||||
> **HTML report:** [Open in browser](file:///abs/path.html)
|
||||
|
||||
If the CLI exits non-zero, mention the error but do not block — the markdown threat-model document above is the primary deliverable.
|
||||
|
|
|
|||
|
|
@ -73,6 +73,6 @@ After producing the markdown watch banner above (before starting the loop):
|
|||
The CLI writes `reports/watch-<YYYYMMDD-HHmmss>.html` relative to CWD and prints `file:///abs/path.html` on stdout.
|
||||
4. Append to your response (markdown link, no bare URL):
|
||||
|
||||
> **HTML-rapport:** [Åpne i nettleser](file:///abs/path.html)
|
||||
> **HTML report:** [Open in browser](file:///abs/path.html)
|
||||
|
||||
If the CLI exits non-zero, mention the error but do not block — the markdown banner above is the primary deliverable.
|
||||
|
|
|
|||
|
|
@ -105,18 +105,18 @@ Scan reports are stored in `reports/` as `.docx` (for sharing) with `.md` source
|
|||
|
||||
## Examples (runnable demonstrations)
|
||||
|
||||
Self-contained, deterministic threat-fixture mappes under `examples/`. Each mappe har `README.md`, fixture/script/transcript, `run-*.{sh,mjs}`, og `expected-findings.md`. Demonstrasjoner — ikke unit-tester.
|
||||
Self-contained, deterministic threat fixtures live under `examples/`. Each directory has a `README.md`, fixture/script/transcript, `run-*.{sh,mjs}`, and `expected-findings.md`. They are demonstrations — not unit tests.
|
||||
|
||||
| Mappe | Demonstrerer | Hooks/scanners | Sentinel |
|
||||
| Directory | Demonstrates | Hooks/scanners | Sentinel |
|
||||
|-------|--------------|----------------|----------|
|
||||
| `malicious-skill-demo/` | Skill scanner end-to-end (UNI/ENT/PRM/DEP/TNT/NET + 7 LLM-kategorier) | `scan-orchestrator` + agents | BLOCK 100/100 |
|
||||
| `prompt-injection-showcase/` | 61 payloads × 19 kategorier mot `pre-prompt-inject-scan`, `post-mcp-verify`, `pre-bash-destructive` | runtime hooks | per-kategori expected outcome |
|
||||
| `lethal-trifecta-walkthrough/` | Rule-of-Two advisory på leg 3 (WebFetch → Read .env → Bash curl POST) + suppression | `post-session-guard` | advisory på stage 3 |
|
||||
| `mcp-rug-pull/` | Cumulative drift-advisory (E14, v7.3.0) — 7 stadier under per-update-terskel, kumulativt over 25% baseline | `post-mcp-verify` + `mcp-description-cache.mjs` | advisory på stage 7 |
|
||||
| `supply-chain-attack/` | PreToolUse-blokk på kompromittert pakke + scope-hop advisory + dep-auditor typosquats + postinstall curl-pipe | `pre-install-supply-chain` + `dep-auditor` + `supply-chain-data` | 6+ funn, 2 advisories, 1 BLOCK |
|
||||
| `poisoned-claude-md/` | 6 detektorer (injection / shell / URL / credential paths / permission expansion / encoded payloads) inkl. E15 agent-fil-overflate | `memory-poisoning-scanner` | ≥18 funn fordelt på 2 filer |
|
||||
| `bash-evasion-gallery/` | T1-T9 disguised destructive commands → normalisert + blokkert (defense-in-depth over Claude Code 2.1.98+) | `pre-bash-destructive` + `bash-normalize` | 10 BLOCK eksitkoder |
|
||||
| `toxic-agent-demo/` | Single-component lethal trifecta — agent med [Bash, Read, WebFetch] uten hook-guards = CRITICAL TFA-finding | `toxic-flow-analyzer` (TFA) | 1 CRITICAL `Lethal trifecta:` |
|
||||
| `pre-compact-poisoning/` | PreCompact-hook fanger injection + AWS-shaped credential i syntetisk transcript på tvers av off/warn/block-modus | `pre-compact-scan` | 9 pass: block exit 2 + reason; warn systemMessage; off skip; benign passes |
|
||||
| `malicious-skill-demo/` | Skill scanner end-to-end (UNI/ENT/PRM/DEP/TNT/NET + 7 LLM categories) | `scan-orchestrator` + agents | BLOCK 100/100 |
|
||||
| `prompt-injection-showcase/` | 61 payloads × 19 categories against `pre-prompt-inject-scan`, `post-mcp-verify`, `pre-bash-destructive` | runtime hooks | per-category expected outcome |
|
||||
| `lethal-trifecta-walkthrough/` | Rule-of-Two advisory on leg 3 (WebFetch → Read .env → Bash curl POST) + suppression | `post-session-guard` | advisory at stage 3 |
|
||||
| `mcp-rug-pull/` | Cumulative drift advisory (E14, v7.3.0) — 7 stages below the per-update threshold, cumulatively over a 25% baseline shift | `post-mcp-verify` + `mcp-description-cache.mjs` | advisory at stage 7 |
|
||||
| `supply-chain-attack/` | PreToolUse block on a compromised package + scope-hop advisory + dep-auditor typosquats + postinstall curl-pipe | `pre-install-supply-chain` + `dep-auditor` + `supply-chain-data` | 6+ findings, 2 advisories, 1 BLOCK |
|
||||
| `poisoned-claude-md/` | 6 detectors (injection / shell / URL / credential paths / permission expansion / encoded payloads) including the E15 agent-file surface | `memory-poisoning-scanner` | ≥18 findings split across 2 files |
|
||||
| `bash-evasion-gallery/` | T1-T9 disguised destructive commands → normalized + blocked (defense-in-depth over Claude Code 2.1.98+) | `pre-bash-destructive` + `bash-normalize` | 10 BLOCK exit codes |
|
||||
| `toxic-agent-demo/` | Single-component lethal trifecta — an agent with [Bash, Read, WebFetch] and no hook guards = CRITICAL TFA finding | `toxic-flow-analyzer` (TFA) | 1 CRITICAL `Lethal trifecta:` |
|
||||
| `pre-compact-poisoning/` | The PreCompact hook catches injection + an AWS-shaped credential in a synthetic transcript across off/warn/block modes | `pre-compact-scan` | 9 cases: block exit 2 + reason; warn systemMessage; off skip; benign passes |
|
||||
|
||||
State-isolering: alle eksempler som muterer global state bruker run-script PID (post-session-guard via `${ppid}.jsonl`) eller env-overrides (`LLM_SECURITY_MCP_CACHE_FILE` for MCP-cache). Brukerens reelle `/tmp/llm-security-session-*.jsonl` og `~/.cache/llm-security/` røres aldri.
|
||||
State isolation: every example that mutates global state uses the run-script PID (post-session-guard via `${ppid}.jsonl`) or env overrides (`LLM_SECURITY_MCP_CACHE_FILE` for the MCP cache). The user's real `/tmp/llm-security-session-*.jsonl` and `~/.cache/llm-security/` are never touched.
|
||||
|
|
|
|||
|
|
@ -2,6 +2,25 @@
|
|||
|
||||
Per-release notes for v7.0.0 onward. Imported from `CLAUDE.md` via `@docs/version-history.md`.
|
||||
|
||||
## v7.7.2 — Language consistency pass
|
||||
|
||||
Norwegian had crept into surface text across v7.5–v7.7. Per the
|
||||
`~/.claude/CLAUDE.md` convention (English for code and documentation,
|
||||
Norwegian for dialog only), this release translates: the HTML Report-step in
|
||||
all 18 skill commands, the canonical CLI renderer
|
||||
`scripts/lib/report-renderers.mjs` (display strings + JS comments), the
|
||||
playground UI strings, the `skill-scanner-agent` and `mcp-scanner-agent`
|
||||
system prompts, the playground architecture prose + Recent versions table in
|
||||
the plugin `README.md`, the v7.7.x highlights in the plugin `CLAUDE.md`, the
|
||||
llm-security entries in the marketplace root `README.md` + `CLAUDE.md`, and
|
||||
six table cells in `docs/scanner-reference.md`. Demo-state fixture content
|
||||
for the `dft-komplett-demo` project (intentional Norwegian persona) and
|
||||
regex alternations that match Norwegian-language report markdown
|
||||
(`/^high|^høy/`, `/resolution|løsning/`) were preserved. CHANGELOG and this
|
||||
version-history file were deferred per operator decision — they remain in
|
||||
the language they were written in. No scanner, hook, or behavior changes —
|
||||
purely surface text.
|
||||
|
||||
## v7.0.0 — Severity-dominated risk scoring (v2 model, BREAKING)
|
||||
|
||||
Three changes target the false-positive cascade on real codebases (hyperframes.com gave `BLOCK / Extreme / 100`, ~70% noise):
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "llm-security",
|
||||
"version": "7.7.1",
|
||||
"version": "7.7.2",
|
||||
"description": "Security scanning, auditing, and threat modeling for Claude Code projects",
|
||||
"type": "module",
|
||||
"bin": {
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -79,7 +79,7 @@ function renderKeyStatsGrid(stats) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Render page-shell — DS Tier 3 page__header-klyngen brukt på alle 4 overflater:
|
||||
* Render the page-shell — the DS Tier 3 page__header cluster used on all 4 surfaces:
|
||||
* - onboarding: page__eyebrow="ONBOARDING · n av 5 grupper komplette"
|
||||
* - home: page__eyebrow="HJEM" (m/ hero-modifier for editorial type-hierarki)
|
||||
* - catalog: page__eyebrow="KATALOG"
|
||||
|
|
@ -197,16 +197,16 @@ const KEY_STATS_CONFIG = {
|
|||
const crit = fs.filter(function (f) { return /crit|kritisk/i.test(f.severity || ''); }).length;
|
||||
const high = fs.filter(function (f) { return /^high|^høy/i.test(f.severity || ''); }).length;
|
||||
return [
|
||||
{ label: 'TOTALT', value: fs.length },
|
||||
{ label: 'KRITISK', value: crit, modifier: crit > 0 ? 'critical' : null },
|
||||
{ label: 'HØY', value: high, modifier: high > 0 ? 'high' : null }
|
||||
{ label: 'TOTAL', value: fs.length },
|
||||
{ label: 'CRITICAL', value: crit, modifier: crit > 0 ? 'critical' : null },
|
||||
{ label: 'HIGH', value: high, modifier: high > 0 ? 'high' : null }
|
||||
];
|
||||
},
|
||||
'findings-grade': function (d) {
|
||||
const out = [];
|
||||
if (d.grade) out.push({ label: 'GRADE', value: String(d.grade).toUpperCase(), modifier: /a|b/i.test(d.grade) ? 'low' : (/c|d/i.test(d.grade) ? 'medium' : 'critical') });
|
||||
if (d.score != null) out.push({ label: 'SCORE', value: d.score });
|
||||
if (d.findings) out.push({ label: 'FUNN', value: d.findings.length });
|
||||
if (d.findings) out.push({ label: 'FINDINGS', value: d.findings.length });
|
||||
return out;
|
||||
},
|
||||
'risk-score-meter': function (d) {
|
||||
|
|
@ -220,16 +220,16 @@ const KEY_STATS_CONFIG = {
|
|||
},
|
||||
'red-team-results': function (d) {
|
||||
return [
|
||||
{ label: 'TOTALT', value: d.total || 0 },
|
||||
{ label: 'TOTAL', value: d.total || 0 },
|
||||
{ label: 'PASS', value: d.pass_count || 0, modifier: 'low' },
|
||||
{ label: 'FAIL', value: d.fail_count || 0, modifier: (d.fail_count > 0 ? 'critical' : null) }
|
||||
];
|
||||
},
|
||||
'dashboard-fleet': function (d) {
|
||||
return [
|
||||
{ label: 'PROSJEKTER', value: (d.projects || []).length },
|
||||
{ label: 'MASKINKLASSE', value: String(d.machine_grade || 'n/a').toUpperCase() },
|
||||
{ label: 'SVAKEST', value: d.weakest_link || '–' }
|
||||
{ label: 'PROJECTS', value: (d.projects || []).length },
|
||||
{ label: 'MACHINE GRADE', value: String(d.machine_grade || 'n/a').toUpperCase() },
|
||||
{ label: 'WEAKEST', value: d.weakest_link || '–' }
|
||||
];
|
||||
},
|
||||
'posture-cards': function (d) {
|
||||
|
|
@ -246,8 +246,8 @@ const KEY_STATS_CONFIG = {
|
|||
const newCount = (d['new'] || []).length;
|
||||
const unchangedCount = (d.unchanged || []).length;
|
||||
return [
|
||||
{ label: 'NÅ-GRADE', value: String(d.current_grade || '?').toUpperCase() },
|
||||
{ label: 'AKSJONER', value: newCount, modifier: newCount > 0 ? 'medium' : 'low' },
|
||||
{ label: 'CURRENT GRADE', value: String(d.current_grade || '?').toUpperCase() },
|
||||
{ label: 'ACTIONS', value: newCount, modifier: newCount > 0 ? 'medium' : 'low' },
|
||||
{ label: 'SKIPPED', value: unchangedCount }
|
||||
];
|
||||
},
|
||||
|
|
@ -435,7 +435,7 @@ function gradeFromText(s) {
|
|||
return m ? m[1] : null;
|
||||
}
|
||||
|
||||
// Hjelper: parse Risk Dashboard-tabellen (fellesmønster)
|
||||
// Helper: parse the Risk Dashboard table (shared pattern)
|
||||
function parseRiskDashboard(md) {
|
||||
const out = {};
|
||||
const score = extractField(md, 'Risk Score');
|
||||
|
|
@ -486,7 +486,7 @@ function parseFindingsTables(md) {
|
|||
});
|
||||
if (!findingsSection) return findings;
|
||||
const body = findingsSection.body;
|
||||
// Splitt på ### -headere
|
||||
// Split on ### headers
|
||||
const subRe = /^###\s+(.+)$/gm;
|
||||
const matches = [];
|
||||
let m;
|
||||
|
|
@ -578,7 +578,7 @@ function parseNarrativeAudit(md) {
|
|||
}
|
||||
|
||||
// ============================================================
|
||||
// 10 PARSERS — én per høy-prio kommando.
|
||||
// 10 PARSERS — one per high-priority command.
|
||||
// Returner { ok: true, data: { ...domain-specific } } eller
|
||||
// { ok: false, errors: [{ section, reason }] }
|
||||
// ============================================================
|
||||
|
|
@ -1047,7 +1047,7 @@ const parseDashboard = safeOk(function (md) {
|
|||
});
|
||||
}
|
||||
}
|
||||
// Weakest link = første prosjekt sortert worst-first (allerede sortert i fixture)
|
||||
// Weakest link = first project, sorted worst-first (already sorted in the fixture)
|
||||
const weakest = projects.length ? projects[0].name : '';
|
||||
return { ok: true, data: Object.assign({}, dash, {
|
||||
machine_grade: machine_grade,
|
||||
|
|
@ -1195,8 +1195,8 @@ const parseRedTeam = safeOk(function (md) {
|
|||
});
|
||||
|
||||
// ============================================================
|
||||
// FASE 3: 8 PARSERS — én per gjenstående produces_report-kommando.
|
||||
// Mønstre gjenbrukes fra Fase 2 (parseRiskDashboard + parseFindingsTables
|
||||
// PHASE 3: 8 PARSERS — one per remaining produces_report command.
|
||||
// Patterns are reused from Phase 2 (parseRiskDashboard + parseFindingsTables
|
||||
// + safeOk). Matrix-risk-parsing er kopiert fra ms-ai-architect.
|
||||
// ============================================================
|
||||
const parseMcpInspect = safeOk(function (md) {
|
||||
|
|
@ -1614,7 +1614,7 @@ function renderEmptyState(message) {
|
|||
return '<div class="guide-panel guide-panel--info">' +
|
||||
'<div class="guide-panel__icon" aria-hidden="true">i</div>' +
|
||||
'<div class="guide-panel__body">' +
|
||||
'<p class="guide-panel__text">' + escapeHtml(message || 'Ingen data å vise.') + '</p>' +
|
||||
'<p class="guide-panel__text">' + escapeHtml(message || 'No data to display.') + '</p>' +
|
||||
'</div>' +
|
||||
'</div>';
|
||||
}
|
||||
|
|
@ -1627,7 +1627,7 @@ function renderFindingsBlock(findings, label) {
|
|||
});
|
||||
const items = sorted.map(function (f) {
|
||||
const sev = String(f.severity || 'info').toLowerCase();
|
||||
// DS Tier 3 (v7.6.0 fase 5h): card--severity-{level} modifier på outer
|
||||
// DS Tier 3 (v7.6.0 phase 5h): card--severity-{level} modifier on the outer
|
||||
// .findings__item gir severity-tinted left-border. Beholdes ved siden av
|
||||
// den eksisterende .findings__item-severity-dot for ARIA + visuell
|
||||
// redundans (border-farge + dot-fyll signaliserer samme severity).
|
||||
|
|
@ -1649,8 +1649,8 @@ function renderFindingsBlock(findings, label) {
|
|||
);
|
||||
}).join('');
|
||||
// DS .findings outer-class er et 2-kolonners grid (360px list + 1fr detail-panel) —
|
||||
// playgroundet bruker bare list-delen, så vi wrapper i .findings__list (uten outer
|
||||
// .findings) for å unngå at headeren ender i venstre 360px-kolonne. v7.6.1 fix.
|
||||
// the playground uses only the list part, so we wrap in .findings__list (no outer
|
||||
// .findings) to avoid the header landing in the left 360px column. v7.6.1 fix.
|
||||
return (
|
||||
'<section class="report-meta">' +
|
||||
'<h4>' + escapeHtml(label || 'Funn') + '</h4>' +
|
||||
|
|
@ -1684,7 +1684,7 @@ function renderRecommendationsList(recs, label, severity) {
|
|||
|
||||
/**
|
||||
* Map severity-string til DS-tier3 recommendation-card data-severity.
|
||||
* Aksepterer både severity-konvensjoner (critical/high/medium/low/info)
|
||||
* Accepts both severity conventions (critical/high/medium/low/info)
|
||||
* og action-types (CREATE/APPEND/MERGE/SKIP/NONE).
|
||||
*/
|
||||
function mapSeverityToCardLevel(input) {
|
||||
|
|
@ -1753,9 +1753,9 @@ function renderSmallMultiples(items) {
|
|||
function renderRadarSvg(axes) {
|
||||
// axes: [{ name, score (0-5) }]
|
||||
if (!axes || axes.length < 3) return '';
|
||||
// v7.6.1 fix: øk SVG-bredden fra 280 til 380 og r fra 105 til 125 for å gi
|
||||
// labels mer plass. Bruk text-anchor basert på horisontal-posisjon for å
|
||||
// unngå at bottom-labels overlapper hverandre ved 6+ akser.
|
||||
// v7.6.1 fix: widen the SVG from 280 to 380 and r from 105 to 125 to give
|
||||
// labels more room. Use text-anchor based on horizontal position to keep
|
||||
// bottom labels from overlapping each other at 6+ axes.
|
||||
const size = 380, cx = size / 2, cy = size / 2, r = 125;
|
||||
const n = axes.length;
|
||||
const axisRows = axes.map(function (a) {
|
||||
|
|
@ -1766,7 +1766,7 @@ function renderRadarSvg(axes) {
|
|||
const ang = angle(i);
|
||||
const lx = cx + Math.cos(ang) * (r + 28);
|
||||
const ly = cy + Math.sin(ang) * (r + 28);
|
||||
// Velg text-anchor basert på posisjon: ankerene til venstre/høyre snur.
|
||||
// Pick text-anchor based on position: left/right anchors flip.
|
||||
const dx = Math.cos(ang);
|
||||
const anchor = Math.abs(dx) < 0.2 ? 'middle' : (dx > 0 ? 'start' : 'end');
|
||||
return '<text class="radar__label" x="' + lx.toFixed(1) + '" y="' + ly.toFixed(1) + '" text-anchor="' + anchor + '" dominant-baseline="middle">' + escapeHtml(a.name) + '</text>';
|
||||
|
|
@ -1804,7 +1804,7 @@ function renderRadarSvg(axes) {
|
|||
|
||||
/**
|
||||
* Render tfa-flow + tfa-leg + tfa-arrow for et lethal trifecta-funn.
|
||||
* Brukes på scan + deep-scan-rapporter når findings inneholder
|
||||
* Used on scan + deep-scan reports when findings contain
|
||||
* en trifecta-pattern (f.eks. SCN-002 "Lethal trifecta: [Bash, Read, WebFetch]").
|
||||
* Synthesiserer 3-leddet kjede: untrusted-input → sensitive-access → exfil-sink.
|
||||
*/
|
||||
|
|
@ -1835,7 +1835,7 @@ function renderToxicFlow(findings) {
|
|||
}
|
||||
const legs = [
|
||||
{ label: 'Untrusted input', name: tools[0], source: fileLine, mit: 'unmitigated', mitText: 'Ingen pre-prompt-inject-scan eller post-mcp-verify guard' },
|
||||
{ label: 'Sensitive access', name: tools[1], source: '.env / credentials / git-history', mit: 'unmitigated', mitText: 'Ingen pre-write-pathguard på sti' },
|
||||
{ label: 'Sensitive access', name: tools[1], source: '.env / credentials / git-history', mit: 'unmitigated', mitText: 'No pre-write-pathguard on path' },
|
||||
{ label: 'Exfil sink', name: tools[2], source: 'curl / fetch til ekstern host', mit: 'unmitigated', mitText: 'Ingen post-session-guard trifecta-deteksjon' }
|
||||
];
|
||||
const legHtml = function (leg) {
|
||||
|
|
@ -1874,13 +1874,13 @@ function renderMatLadder(categories, postureScore, postureApplicable) {
|
|||
? Number(postureApplicable)
|
||||
: categories.filter(function (c) { return c.status !== 'N-A' && c.status !== 'N/A'; }).length;
|
||||
const pct = total > 0 ? Math.round((passCount / total) * 100) : 0;
|
||||
// 5 modenhetstrinn — terskler basert på % PASS
|
||||
// 5 maturity steps — thresholds based on % PASS
|
||||
const steps = [
|
||||
{ num: 1, name: 'Initial', threshold: 0, desc: 'Bare bones — ingen hooks eller minimal posture.' },
|
||||
{ num: 2, name: 'Aware', threshold: 25, desc: 'Posture-skanning aktiv, kjenner risikoene.' },
|
||||
{ num: 3, name: 'Defensive', threshold: 50, desc: 'Hooks engasjert på kritiske flater (PreToolUse, UserPromptSubmit).' },
|
||||
{ num: 4, name: 'Mature', threshold: 75, desc: 'De fleste 16 kategoriene dekket; trifecta-deteksjon på.' },
|
||||
{ num: 5, name: 'Optimized', threshold: 95, desc: 'Full coverage; A-grade på posture; aktiv overvåking.' }
|
||||
{ num: 1, name: 'Initial', threshold: 0, desc: 'Bare bones — no hooks or minimal posture.' },
|
||||
{ num: 2, name: 'Aware', threshold: 25, desc: 'Posture scanning is active and the risks are known.' },
|
||||
{ num: 3, name: 'Defensive', threshold: 50, desc: 'Hooks engaged on critical surfaces (PreToolUse, UserPromptSubmit).' },
|
||||
{ num: 4, name: 'Mature', threshold: 75, desc: 'Most of the 16 categories covered; trifecta detection on.' },
|
||||
{ num: 5, name: 'Optimized', threshold: 95, desc: 'Full coverage; A-grade on posture; active monitoring.' }
|
||||
];
|
||||
const currentIdx = steps.reduce(function (acc, s, i) {
|
||||
return pct >= s.threshold ? i : acc;
|
||||
|
|
@ -1890,7 +1890,7 @@ function renderMatLadder(categories, postureScore, postureApplicable) {
|
|||
const icon = state === 'completed' ? '✓' : String(s.num);
|
||||
const pillCls = state === 'current' ? ' mat-step__pill mat-step__pill--current' :
|
||||
state === 'completed' ? ' mat-step__pill mat-step__pill--complete' : '';
|
||||
const pillText = state === 'current' ? 'Du er her' : state === 'completed' ? 'Oppnådd' : '';
|
||||
const pillText = state === 'current' ? 'You are here' : state === 'completed' ? 'Reached' : '';
|
||||
const pill = pillText ? '<span class="' + pillCls.trim() + '">' + escapeHtml(pillText) + '</span>' : '';
|
||||
const progress = state === 'current' ? (
|
||||
'<div class="mat-step__progress">' +
|
||||
|
|
@ -1912,7 +1912,7 @@ function renderMatLadder(categories, postureScore, postureApplicable) {
|
|||
return (
|
||||
'<section class="report-meta">' +
|
||||
'<h4>Modenhetsstige — posture-progresjon</h4>' +
|
||||
'<p style="font-size: var(--font-size-sm); opacity: 0.78; margin: 0 0 var(--space-3);">Posture-score på ' + passCount + ' av ' + total + ' kategorier (' + pct + '%) plasserer dette prosjektet på trinn ' + (currentIdx + 1) + ' av 5.</p>' +
|
||||
'<p style="font-size: var(--font-size-sm); opacity: 0.78; margin: 0 0 var(--space-3);">A posture score of ' + passCount + ' of ' + total + ' categories (' + pct + '%) places this project at step ' + (currentIdx + 1) + ' of 5.</p>' +
|
||||
'<div class="mat-ladder" role="list" aria-label="Posture-modenhet over 5 trinn">' + stepHtml + '</div>' +
|
||||
'</section>'
|
||||
);
|
||||
|
|
@ -1973,7 +1973,7 @@ function renderSuppressedGroup(data) {
|
|||
return (
|
||||
'<section class="report-meta">' +
|
||||
'<h4>Narrative audit — supprimerte signaler</h4>' +
|
||||
'<p class="suppressed-group__desc">' + totalCount + ' signaler ble supprimert pre-rapport (v7.1.1 narrative_audit). Disse er ikke false-positives walked-back i prosa, men auto-suppress før klassifisering.</p>' +
|
||||
'<p class="suppressed-group__desc">' + totalCount + ' signals were suppressed pre-report (v7.1.1 narrative_audit). These are not false-positives walked back in prose — they were auto-suppressed before classification.</p>' +
|
||||
groupsHtml +
|
||||
'</section>'
|
||||
);
|
||||
|
|
@ -1981,7 +1981,7 @@ function renderSuppressedGroup(data) {
|
|||
|
||||
/**
|
||||
* Render codepoint-reveal + cp-tag for Unicode-steganografi (UNI-funn).
|
||||
* Brukes på mcp-inspect-rapporter — bytter plain table mot side-by-side
|
||||
* Used on mcp-inspect reports — swaps a plain table for a side-by-side
|
||||
* "synlig vs. decoded codepoint"-visning per tool.
|
||||
*/
|
||||
function renderCodepointReveal(codepoints) {
|
||||
|
|
@ -1999,7 +1999,7 @@ function renderCodepointReveal(codepoints) {
|
|||
const sev = /high/i.test(risk) ? 'critical' : /medium/i.test(risk) ? 'medium' : 'low';
|
||||
const isClean = /clean|—|^-$/i.test(c.codepoints || '') || risk === '—' || risk === '-';
|
||||
const cps = String(c.codepoints || '');
|
||||
// Highlight U+XXXX-mønstre
|
||||
// Highlight U+XXXX patterns
|
||||
const highlighted = cps.replace(/U\+[0-9A-Fa-f]{4,6}/g, function (m) {
|
||||
return '<span class="' + tagFor(m) + '">' + m + '</span>';
|
||||
});
|
||||
|
|
@ -2042,7 +2042,7 @@ function renderCodepointReveal(codepoints) {
|
|||
|
||||
/**
|
||||
* Render top-risks + top-risk for rangert top-funn-listing.
|
||||
* Tar de N (default 5) høyeste alvorlighetsnivåene fra findings og
|
||||
* Takes the N (default 5) highest-severity findings and
|
||||
* viser dem som ordnet liste. Bruker `.top-risks` / `.top-risk` med
|
||||
* `data-severity` for severity-tinted left-border per DS Tier 3-supplement.
|
||||
* Returnerer tom streng hvis ingen findings (eller kun info-funn).
|
||||
|
|
@ -2089,7 +2089,7 @@ function renderTopRisks(findings, n) {
|
|||
}
|
||||
|
||||
// ============================================================
|
||||
// 10 RENDERERS — én per høy-prio kommando.
|
||||
// 10 RENDERERS — one per high-priority command.
|
||||
// ============================================================
|
||||
function renderScan(data, slot) {
|
||||
const meterHtml = renderRiskMeter(data.risk_score, data.riskBand);
|
||||
|
|
@ -2190,7 +2190,7 @@ function renderPluginAudit(data, slot) {
|
|||
) : '';
|
||||
const permHtml = (data.permissions && data.permissions.length) ? (
|
||||
'<section class="report-meta"><h4>Permission-matrise</h4>' +
|
||||
'<table class="report-table"><thead><tr><th>Verktøy</th><th>Krevet av</th><th>Begrunnet</th></tr></thead><tbody>' +
|
||||
'<table class="report-table"><thead><tr><th>Tool</th><th>Required by</th><th>Justified</th></tr></thead><tbody>' +
|
||||
data.permissions.map(function (p) {
|
||||
const isYes = /^yes|^ja/i.test(p.justified);
|
||||
const isNo = /^no$|^nei/i.test(p.justified);
|
||||
|
|
@ -2220,7 +2220,7 @@ function renderPluginAudit(data, slot) {
|
|||
slot.innerHTML = renderPageShell({
|
||||
eyebrow: 'PLUGIN-AUDIT',
|
||||
title: data.title || 'Plugin trust-vurdering',
|
||||
lede: data.lede || 'Trust-verdikt basert på maintainer, lisens, permissions og MCP-deskripsjoner.',
|
||||
lede: data.lede || 'Trust verdict based on maintainer, license, permissions, and MCP descriptions.',
|
||||
verdict: data.verdict || inferVerdict(data, 'risk-score-meter'),
|
||||
keyStats: data.keyStats || inferKeyStats(data, 'risk-score-meter')
|
||||
}, body);
|
||||
|
|
@ -2285,7 +2285,7 @@ function renderMcpAudit(data, slot) {
|
|||
slot.innerHTML = renderPageShell({
|
||||
eyebrow: 'MCP-AUDIT',
|
||||
title: data.title || 'MCP-konfig audit',
|
||||
lede: data.lede || 'Permissions, trust og deskripsjon-drift på tvers av installerte MCP-servere.',
|
||||
lede: data.lede || 'Permissions, trust, and description drift across installed MCP servers.',
|
||||
verdict: data.verdict || inferVerdict(data, 'findings'),
|
||||
keyStats: data.keyStats || inferKeyStats(data, 'findings')
|
||||
}, body);
|
||||
|
|
@ -2392,7 +2392,7 @@ function renderAudit(data, slot) {
|
|||
'<ol class="recommendation-card__body">' + items.map(function (a) { return '<li>' + escapeHtml(a) + '</li>'; }).join('') + '</ol>' +
|
||||
'</section>';
|
||||
};
|
||||
const actionHtml = tierHtml('immediate', 'Umiddelbar', 'critical') + tierHtml('high', 'Høy prioritet', 'high') + tierHtml('medium', 'Medium prioritet', 'medium');
|
||||
const actionHtml = tierHtml('immediate', 'Immediate', 'critical') + tierHtml('high', 'High priority', 'high') + tierHtml('medium', 'Medium priority', 'medium');
|
||||
const meterHtml = (data.risk_score != null) ? renderRiskMeter(data.risk_score, data.riskBand) : '';
|
||||
const topRisksHtml = renderTopRisks(data.findings || [], 5);
|
||||
const findingsHtml = renderFindingsBlock(data.findings || [], 'Funn');
|
||||
|
|
@ -2504,12 +2504,12 @@ function renderHarden(data, slot) {
|
|||
slot.innerHTML = renderPageShell({
|
||||
eyebrow: 'HARDEN',
|
||||
title: data.title || 'Grade A reference config',
|
||||
lede: data.lede || 'Diff-forhåndsvisning av settings.json, CLAUDE.md og .gitignore-endringer.',
|
||||
lede: data.lede || 'Diff preview of settings.json, CLAUDE.md, and .gitignore changes.',
|
||||
verdict: data.verdict || inferVerdict(data, 'diff-report'),
|
||||
keyStats: data.keyStats || [
|
||||
{ label: 'NÅ-GRADE', value: String(data.current_grade || '?') },
|
||||
{ label: 'AKSJONER', value: data.actionable + '/' + data.total },
|
||||
{ label: 'MODUS', value: data.mode || 'dry-run' }
|
||||
{ label: 'CURRENT GRADE', value: String(data.current_grade || '?') },
|
||||
{ label: 'ACTIONS', value: data.actionable + '/' + data.total },
|
||||
{ label: 'MODE', value: data.mode || 'dry-run' }
|
||||
]
|
||||
}, body);
|
||||
}
|
||||
|
|
@ -2564,7 +2564,7 @@ function renderRedTeam(data, slot) {
|
|||
RENDERERS.renderRedTeam = renderRedTeam;
|
||||
|
||||
// ============================================================
|
||||
// FASE 3: 8 RENDERERS — én per gjenstående kommando.
|
||||
// PHASE 3: 8 RENDERERS — one per remaining command.
|
||||
// ============================================================
|
||||
function renderMcpInspect(data, slot) {
|
||||
const invRows = (data.server_inventory || []).map(function (s) {
|
||||
|
|
@ -2602,7 +2602,7 @@ function renderMcpInspect(data, slot) {
|
|||
RENDERERS.renderMcpInspect = renderMcpInspect;
|
||||
|
||||
function renderSupplyCheck(data, slot) {
|
||||
// Ecosystem-cards (small-multiples-mønster)
|
||||
// Ecosystem cards (small-multiples pattern)
|
||||
const ecos = (data.ecosystems || []).filter(function (e) { return Number(e.packages) > 0 || Number(e.osv_hits) > 0 || Number(e.typosquats) > 0; });
|
||||
const ecoCards = ecos.length ? '<div class="small-multiples">' + ecos.map(function (e) {
|
||||
const issues = (Number(e.osv_hits) || 0) + (Number(e.typosquats) || 0);
|
||||
|
|
@ -2640,7 +2640,7 @@ function renderPreDeploy(data, slot) {
|
|||
if (u === 'FAIL' || u === 'BLOCK' || u === 'NO-GO') return 'critical';
|
||||
return 'info';
|
||||
};
|
||||
// v7.6.1 fix: sm-card__grade er fast 28×28 px (designet for én A-F-bokstav), så
|
||||
// v7.6.1 fix: sm-card__grade is fixed at 28×28 px (designed for one A-F letter), so
|
||||
// "PASS"/"PASS-WITH-NOTES"/"FAIL" ble kuttet til "AS"/"PASS-WITH-..."/"FA". Bytt
|
||||
// til en bredde-tilpasset status-pill via inline styling (ingen DS-klasse-endring).
|
||||
const cards = lights.map(function (l) {
|
||||
|
|
@ -2665,7 +2665,7 @@ function renderPreDeploy(data, slot) {
|
|||
const lightsHtml = cards ? '<section class="report-meta"><h4>Traffic-light kategorier</h4><div class="small-multiples">' + cards + '</div></section>' : '';
|
||||
const condHtml = (data.conditions && data.conditions.length) ? (
|
||||
'<section class="recommendation-card" data-severity="high">' +
|
||||
'<span class="recommendation-card__label">Vilkår å løse</span>' +
|
||||
'<span class="recommendation-card__label">Conditions to resolve</span>' +
|
||||
'<ol class="recommendation-card__body">' + data.conditions.map(function (c) { return '<li>' + escapeHtml(c) + '</li>'; }).join('') + '</ol>' +
|
||||
'</section>'
|
||||
) : '';
|
||||
|
|
@ -2708,7 +2708,7 @@ function renderDiff(data, slot) {
|
|||
'</div>' +
|
||||
'<div class="pair-before-after__arrow" aria-hidden="true"></div>' +
|
||||
'<div class="pair-before-after__cell">' +
|
||||
'<span class="pair-before-after__cell-label">NÅ</span>' +
|
||||
'<span class="pair-before-after__cell-label">NOW</span>' +
|
||||
'<span class="pair-before-after__cell-value">' + gradeBadge(data.current_grade) + '</span>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
|
|
@ -2741,7 +2741,7 @@ function renderDiff(data, slot) {
|
|||
'</section>';
|
||||
};
|
||||
const newHtml = sectionFor('Nye funn', newItems, 'new');
|
||||
const resHtml = sectionFor('Løste funn', resolvedItems, 'resolved');
|
||||
const resHtml = sectionFor('Resolved findings', resolvedItems, 'resolved');
|
||||
const unchHtml = sectionFor('Uendret', unchangedItems, 'unchanged');
|
||||
const movHtml = (movedItems.length) ? sectionFor('Flyttet', movedItems.map(function (m) {
|
||||
return { id: m.id, severity: 'info', description: m.from + ' → ' + m.to };
|
||||
|
|
@ -2751,7 +2751,7 @@ function renderDiff(data, slot) {
|
|||
slot.innerHTML = renderPageShell({
|
||||
eyebrow: 'DIFF',
|
||||
title: data.title || 'Scan diff mot baseline',
|
||||
lede: data.lede || 'Sammenligner nåværende scan mot lagret baseline.',
|
||||
lede: data.lede || 'Compares the current scan against the stored baseline.',
|
||||
verdict: data.verdict || inferVerdict(data, 'diff-report'),
|
||||
keyStats: data.keyStats || inferKeyStats(data, 'diff-report')
|
||||
}, body);
|
||||
|
|
@ -2797,7 +2797,7 @@ function renderWatch(data, slot) {
|
|||
slot.innerHTML = renderPageShell({
|
||||
eyebrow: 'WATCH',
|
||||
title: data.title || 'Continuous monitoring',
|
||||
lede: data.lede || 'Kjører diff på rekursivt intervall via /loop. Notify ved nye funn.',
|
||||
lede: data.lede || 'Runs diff on a recurring interval via /loop. Notifies on new findings.',
|
||||
verdict: data.verdict || inferVerdict(data, 'findings'),
|
||||
keyStats: data.keyStats || inferKeyStats(data, 'findings')
|
||||
}, body);
|
||||
|
|
@ -2829,7 +2829,7 @@ function renderRegistry(data, slot) {
|
|||
}).join('');
|
||||
const sigHtml = sigRows ? (
|
||||
'<section class="report-meta"><h4>Signaturer</h4>' +
|
||||
'<table class="report-table"><thead><tr><th>Skill</th><th>Kilde</th><th>Fingerprint</th><th>Status</th><th>Første sett</th></tr></thead><tbody>' + sigRows + '</tbody></table>' +
|
||||
'<table class="report-table"><thead><tr><th>Skill</th><th>Source</th><th>Fingerprint</th><th>Status</th><th>First seen</th></tr></thead><tbody>' + sigRows + '</tbody></table>' +
|
||||
'</section>'
|
||||
) : '';
|
||||
const fs = (data.findings || []).map(function (f) {
|
||||
|
|
@ -2874,11 +2874,11 @@ function renderClean(data, slot) {
|
|||
cardFor('suppressed', 'Undertrykt', 'info') +
|
||||
'</div>';
|
||||
// Advisory recommendation-cards per bucket — DS Tier 3 data-severity (v7.6.0 fase 5f).
|
||||
// Hver bucket med items > 0 får én recommendation-card med severity-tinted border + label.
|
||||
// Every bucket with items > 0 gets one recommendation-card with a severity-tinted border + label.
|
||||
const bucketAdvisoryDefs = [
|
||||
{ key: 'auto', label: 'Auto-fixable', sev: 'positive', desc: 'Plugin kan fikse disse uten ekstra bekreftelse — deterministiske, lavrisiko-handlinger.' },
|
||||
{ key: 'semi-auto', label: 'Semi-auto — krever bekreftelse', sev: 'medium', desc: 'Foreslåtte tiltak vises som diff. Bruker bekrefter per finding før endring anvendes.' },
|
||||
{ key: 'manual', label: 'Manual remediation', sev: 'high', desc: 'Krever menneskelig vurdering — kontekst, scope eller side-effekter er ikke deterministisk avgjørbare.' },
|
||||
{ key: 'semi-auto', label: 'Semi-auto — requires confirmation', sev: 'medium', desc: 'Proposed changes are shown as a diff. The user confirms per finding before the change is applied.' },
|
||||
{ key: 'manual', label: 'Manual remediation', sev: 'high', desc: 'Requires human judgement — context, scope, or side-effects are not deterministically decidable.' },
|
||||
{ key: 'suppressed', label: 'Undertrykt', sev: 'low', desc: 'Allowlist-treff via .llm-security-ignore — ingen handling.' }
|
||||
];
|
||||
const advisoryHtml = bucketAdvisoryDefs.map(function (b) {
|
||||
|
|
@ -2897,14 +2897,14 @@ function renderClean(data, slot) {
|
|||
const intro = data.mode ? (
|
||||
'<section class="recommendation-card" data-severity="' + (isDry ? 'low' : 'medium') + '">' +
|
||||
'<span class="recommendation-card__label">Modus · ' + escapeHtml(data.mode) + '</span>' +
|
||||
'<p class="recommendation-card__body">' + (isDry ? 'Dry-run: ingen filer endres. Forhåndsvis tiltak før <code>--apply</code>.' : 'Fixes anvendes med automatisk backup i <code>.llm-security-backup/</code>.') + '</p>' +
|
||||
'<p class="recommendation-card__body">' + (isDry ? 'Dry-run: no files are modified. Preview the actions before <code>--apply</code>.' : 'Fixes are applied with an automatic backup in <code>.llm-security-backup/</code>.') + '</p>' +
|
||||
'</section>'
|
||||
) : '';
|
||||
const body = intro + advisoryHtml + kanbanHtml + findingsHtml + recHtml;
|
||||
slot.innerHTML = renderPageShell({
|
||||
eyebrow: 'CLEAN',
|
||||
title: data.title || 'Remediation-kanban',
|
||||
lede: data.lede || 'Funn fordelt på Auto / Semi-auto / Manual / Undertrykt.',
|
||||
lede: data.lede || 'Findings split across Auto / Semi-auto / Manual / Suppressed.',
|
||||
verdict: data.verdict || inferVerdict(data, 'kanban-buckets'),
|
||||
keyStats: data.keyStats || inferKeyStats(data, 'kanban-buckets')
|
||||
}, body);
|
||||
|
|
@ -2929,7 +2929,7 @@ function renderThreatModel(data, slot) {
|
|||
for (let prob = 1; prob <= probSize; prob++) {
|
||||
const score = prob * cons;
|
||||
const items = byPC[prob + '_' + cons] || [];
|
||||
// v7.6.1 fix: bobler er nå <button> så de er klikkbare og fokuserbare.
|
||||
// v7.6.1 fix: bubbles are now <button> so they are clickable and focusable.
|
||||
// data-threat-id lar event-handler senere mappe til detalj-modal.
|
||||
const bubblesHtml = items.length
|
||||
? '<div class="matrix__cell-bubbles">' +
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue