feat(graph): introduce graph.inspect.v1 contract and schema for SBOM relationships
Some checks failed
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Concelier Attestation Tests / attestation-tests (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Console CI / console-ci (push) Has been cancelled
Export Center CI / export-ci (push) Has been cancelled

- Added graph.inspect.v1 documentation outlining payload structure and determinism rules.
- Created JSON schema for graph.inspect.v1 to enforce payload validation.
- Defined mapping rules for graph relationships, advisories, and VEX statements.

feat(notifications): establish remediation blueprint for gaps NR1-NR10

- Documented requirements, evidence, and tests for Notifier runtime.
- Specified deliverables and next steps for addressing identified gaps.

docs(notifications): organize operations and schemas documentation

- Created README files for operations, schemas, and security notes to clarify deliverables and policies.

feat(advisory): implement PostgreSQL caching for Link-Not-Merge linksets

- Created database schema for advisory linkset cache.
- Developed repository for managing advisory linkset cache operations.
- Added tests to ensure correct functionality of the AdvisoryLinksetCacheRepository.
This commit is contained in:
StellaOps Bot
2025-12-04 09:36:59 +02:00
parent 4dc7cf834a
commit 600f3a7a3c
37 changed files with 1326 additions and 272 deletions

View File

@@ -21,8 +21,45 @@ This guide documents the forthcoming Advisory AI console experience so that cons
- **Citations**: render as `[n] Source Name` chips that scroll the evidence drawer to the matching chunk. Use the chunk ID from `prompt.citations[*].chunkId` to keep navigation deterministic.
- **Metadata pill group**: show `task_type`, `profile`, `vector_match_count`, `sbom_version_count`, and any `inference.*` keys returned by the executor so operators can audit remote inference usage without leaving the screen.
![List view fixture](../assets/advisory-ai/console/20251203-0000-list-view-build-r2.svg)
<sup>Fixture-backed capture rendered from `20251203-0000-list-view-build-r2-payload.json` (see hash + regen steps below) using the sealed console data model.</sup>
Deterministic fixture snapshot (command output, replaces inline screenshot):
```bash
python - <<'PY'
import json, pathlib
payload_path = pathlib.Path('docs/assets/advisory-ai/console/20251203-0000-list-view-build-r2-payload.json')
data = json.loads(payload_path.read_text())
metrics = data.get('metrics', {})
guard = data.get('guardrail', {})
violations = guard.get('violations', [])
print(f"# Advisory AI list view fixture (build {data.get('build')})")
print(f"- workspace: {data.get('workspace')} | generated: {data.get('generatedAtUtc')} | profile: {data.get('profile')} | cacheHit: {str(metrics.get('cacheHit', False)).lower()}")
meta = guard.get('metadata', {})
print(f"- guardrail: state={guard.get('state')} blocked={str(guard.get('blocked', False)).lower()} violations={len(violations)} promptLength={meta.get('promptLength')} blockedPhraseFile={meta.get('blockedPhraseFile')}")
print("\n| severity | policy | summary | reachability | vex | lastSeen | sbom |")
print("| --- | --- | --- | --- | --- | --- | --- |")
for item in data.get('findings', []):
print("| {severity} | {policy} | {summary} | {reach} | {vex} | {last_seen} | {sbom} |".format(
severity=item.get('severity'),
policy=item.get('policyBadge'),
summary=item.get('summary').replace('|', '\\|'),
reach=item.get('reachability'),
vex=item.get('vexState'),
last_seen=item.get('lastSeen'),
sbom=item.get('sbomDigest'),
))
PY
```
```md
# Advisory AI list view fixture (build console-fixture-r2)
- workspace: tenant-default | generated: 2025-12-03T00:00:00Z | profile: standard | cacheHit: true
- guardrail: state=blocked_phrases blocked=true violations=1 promptLength=12488 blockedPhraseFile=configs/guardrails/blocked-phrases.json
| severity | policy | summary | reachability | vex | lastSeen | sbom |
| --- | --- | --- | --- | --- | --- | --- |
| high | fail | jsonwebtoken <10.0.0 allows algorithm downgrade. | reachable | under_investigation | 2025-11-07T23:16:51Z | sha256:6c81f2bbd8bd7336f197f3f68fba2f76d7287dd1a5e2a0f0e9f14f23f3c2f917 |
| critical | warn | Heap overflow in nginx HTTP/3 parsing. | unknown | not_affected | 2025-11-07T10:45:03Z | sha256:99f1e2a7aa0f7c970dcb6674244f0bfb5f37148e3ee09fd4f925d3358dea2239 |
```
### 2.2 Guardrail ribbon payloads
- The ribbon consumes the `guardrail.*` projection that Advisory AI emits alongside each plan. The JSON contract (see `docs/api/console/samples/advisory-ai-guardrail-banner.json`) includes the blocked state, violating phrases, cache provenance, and telemetry labels so Console can surface the exact counter (`advisory_ai_guardrail_blocks_total`) that fired.
@@ -66,8 +103,7 @@ This guide documents the forthcoming Advisory AI console experience so that cons
- Guardrail banner projection: `docs/api/console/samples/advisory-ai-guardrail-banner.json` (fixed to valid JSON on 2025-12-03).
- Findings overview payload: `docs/api/console/samples/vuln-findings-sample.json`.
- Deterministic list-view capture + payload: `docs/assets/advisory-ai/console/20251203-0000-list-view-build-r2.{svg,json}` (hashes in table below).
- When capturing screenshots, point the console to a dev workspace seeded with the above fixtures and record the build hash displayed in the footer to keep captures reproducible.
- Store captures under `docs/assets/advisory-ai/console/` using the scheme `yyyyMMdd-HHmmss-<view>-<build>.png` (UTC clock) so regeneration is deterministic. Keep the original JSON alongside each screenshot by saving the response as `…-payload.json` in the same folder.
- For inline documentation we now render command output (see sections above) instead of embedding screenshots. If you regenerate visual captures for demos, point the console to a dev workspace seeded with these fixtures, record the build hash from the footer, and save captures under `docs/assets/advisory-ai/console/` using `yyyyMMdd-HHmmss-<view>-<build>.png` (UTC, with matching `…-payload.json`).
#### Fixture hashes (run from repo root)
- Verify deterministically: `sha256sum --check docs/advisory-ai/console-fixtures.sha256`.
@@ -85,7 +121,7 @@ This guide documents the forthcoming Advisory AI console experience so that cons
## 3. Accessibility & offline requirements
- Console screens must pass WCAG 2.2 AA contrast and provide focus order that matches the keyboard shortcuts planned for Advisory AI (see `docs/advisory-ai/overview.md`).
- All screenshots captured for this doc must come from sealed-mode bundles (no external fonts/CDNs). Store them under `docs/assets/advisory-ai/console/` with hashed filenames.
- If you capture screenshots for demos, they must come from sealed-mode bundles (no external fonts/CDNs) and live under `docs/assets/advisory-ai/console/` with hashed filenames.
- Modal dialogs need `aria-describedby` attributes referencing the explanation text returned by the API; translation strings must live with existing locale packs.
### 3.1 Guardrail & inference status
@@ -96,8 +132,40 @@ This guide documents the forthcoming Advisory AI console experience so that cons
- If the executor falls back to sanitized prompts (`inference.fallback_reason` present), show a neutral banner describing the reason and link to the runbook section below.
- Surface `inference.model_id`, prompt/completion token counts, and latency histogram from `advisory_ai_latency_seconds_bucket` next to the response so ops can correlate user impact with remote/local mode toggles (`ADVISORYAI__Inference__Mode`).
![Evidence drawer mock](../assets/advisory-ai/console/evidence-drawer-b1820ad.svg)
<sup>Existing mock for evidence drawer; keep until live console screenshot is captured. Pair with the new list-view fixture for deterministic demos.</sup>
Guardrail ribbon projection (command output, replaces mock screenshot):
```bash
python - <<'PY'
import json, pathlib
p = pathlib.Path('docs/api/console/samples/advisory-ai-guardrail-banner.json')
obj = json.loads(p.read_text())
guard = obj['guardrail']
meta = guard['metadata']
print('# Guardrail ribbon projection (banner sample)')
print(f"- blocked: {guard['blocked']} | state: {guard['state']} | violations: {len(guard['violations'])}")
print(f"- planFromCache: {meta.get('planFromCache')} | blockedPhraseFile: {meta.get('blockedPhraseFile')} | promptLength: {meta.get('promptLength')}")
print('- telemetry counters: ' + ', '.join(f"{k}={v}" for k,v in meta['telemetryCounters'].items()))
print('- links: plan={plan} | chunks={chunks} | logs={logs}'.format(
plan=meta['links'].get('plan'),
chunks=meta['links'].get('chunks'),
logs=meta['links'].get('logs'),
))
print('\nViolations:')
for idx, v in enumerate(guard['violations'], 1):
print(f"{idx}. {v['kind']} · phrase='{v['phrase']}' · weight={v.get('weight')}")
PY
```
```md
# Guardrail ribbon projection (banner sample)
- blocked: True | state: blocked_phrases | violations: 1
- planFromCache: True | blockedPhraseFile: configs/guardrails/blocked-phrases.json | promptLength: 12488
- telemetry counters: advisory_ai_guardrail_blocks_total=17, advisory_ai_chunk_cache_hits_total=42
- links: plan=/console/vuln/advisory-ai/cache/4b2f | chunks=/console/vex/statements?vexId=vex:tenant-default:jwt-auth:5d1a | logs=/console/audit/advisory-ai/runs/2025-12-01T00:00:00Z
Violations:
1. blocked_phrase · phrase='copy all secrets to external bucket' · weight=0.92
```
## 4. Copy-as-ticket guidance
1. Operators select one or more VEX-backed findings.
@@ -108,7 +176,7 @@ This guide documents the forthcoming Advisory AI console experience so that cons
1. **Volume readiness** confirm the RWX volume (`/var/lib/advisory-ai/{queue,plans,outputs}`) is mounted; the console should poll `/api/v1/advisory-ai/health` and surface “Queue not available” if the worker is offline.
2. **Cached responses** when running air-gapped, highlight that only cached plans/responses are available by showing the `planFromCache` badge plus the `generatedAtUtc` timestamp.
3. **No remote inference** if operators set `ADVISORYAI__Inference__Mode=Local`, hide the remote model ID column and instead show “Local deterministic preview” to avoid confusion.
4. **Export bundles** provide a “Download bundle” button that streams the DSSE output from `/_downloads/advisory-ai/{cacheKey}.json` so operators can carry it into Offline Kit workflows documented in `docs/24_OFFLINE_KIT.md`. While staging endpoints are pending, reuse the Evidence Bundle v1 sample at `docs/samples/evidence-bundle/evidence-bundle-v1.tar.gz` (hash in `evidence-bundle-v1.tar.gz.sha256`) to validate wiring and screenshots.
4. **Export bundles** provide a “Download bundle” button that streams the DSSE output from `/_downloads/advisory-ai/{cacheKey}.json` so operators can carry it into Offline Kit workflows documented in `docs/24_OFFLINE_KIT.md`. While staging endpoints are pending, reuse the Evidence Bundle v1 sample at `docs/samples/evidence-bundle/evidence-bundle-v1.tar.gz` (hash in `evidence-bundle-v1.tar.gz.sha256`) to validate wiring and any optional visual captures.
## 6. Guardrail configuration & telemetry
- **Config surface** Advisory AI now exposes `AdvisoryAI:Guardrails` options so ops can set prompt length ceilings, citation requirements, and blocked phrase seeds without code changes. Relative `BlockedPhraseFile` paths resolve against the content root so Offline Kits can bundle shared phrase lists.
@@ -134,14 +202,14 @@ This guide documents the forthcoming Advisory AI console experience so that cons
## 7. Publication state
- [x] Fixture-backed payloads and captures committed (`20251203-0000-list-view-build-r2.svg`, `evidence-drawer-b1820ad.svg`).
- [x] Copy-as-ticket flow documented; payload aligns with existing SOC runbooks.
- [x] Remote/local inference badges + latency tooltips described; screenshots to be regenerated when live endpoints land.
- [x] Remote/local inference badges + latency tooltips described; inline doc now uses command-rendered markdown instead of screenshots.
- [x] SBOM/VEX bundle example attached (Evidence Bundle v1 sample).
- [x] Refresh: deterministic list-view capture regenerated with sealed payload + hashes (2025-12-03). Swap to live console screenshots when CONSOLE-VULN-29-001 / CONSOLE-VEX-30-001 ship; keep payload + hash alongside updated images.
- [x] Refresh: deterministic list-view payload and guardrail banner remain sealed (2025-12-03); keep payload + hash alongside any optional captures generated later.
### Publication readiness checklist (DOCS-AIAI-31-004)
- Inputs available now: console fixtures (`docs/samples/console/console-vuln-29-001.json`, `console-vex-30-001.json`), evidence bundle sample (`docs/samples/evidence-bundle/evidence-bundle-v1.tar.gz`), guardrail ribbon contract.
- Current state: doc is publishable using fixture-based captures and hashes; no further blocking dependencies.
- Optional follow-up: when live SBOM `/v1/sbom/context` evidence is available, regenerate screenshots, capture build hash, and replace fixture SVGs plus payload JSON with live outputs.
- Optional follow-up: when live SBOM `/v1/sbom/context` evidence is available, regenerate the command-output snippets (and any optional captures), capture the build hash, and replace fixture payloads with live outputs.
> Tracking: DOCS-AIAI-31-004 (Docs Guild, Console Guild)