Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
- Introduced `SbomService` tasks documentation. - Updated `StellaOps.sln` to include new projects: `StellaOps.AirGap.Time` and `StellaOps.AirGap.Importer`. - Added unit tests for `BundleImportPlanner`, `DsseVerifier`, `ImportValidator`, and other components in the `StellaOps.AirGap.Importer.Tests` namespace. - Implemented `InMemoryBundleRepositories` for testing bundle catalog and item repositories. - Created `MerkleRootCalculator`, `RootRotationPolicy`, and `TufMetadataValidator` tests. - Developed `StalenessCalculator` and `TimeAnchorLoader` tests in the `StellaOps.AirGap.Time.Tests` namespace. - Added `fetch-sbomservice-deps.sh` script for offline dependency fetching.
58 lines
2.4 KiB
Markdown
58 lines
2.4 KiB
Markdown
# Console Consumption of LNM Linksets (Sprint 110)
|
|
|
|
Goal: unblock CONCELIER-CONSOLE-23-001..003 by defining how Console reads Link-Not-Merge (LNM) data now that the schema is frozen (2025-11-17) and cache plan exists.
|
|
|
|
## Data sources
|
|
- Primary collection: `advisory_linksets` (see `docs/modules/concelier/link-not-merge-schema.md`).
|
|
- Cache: `advisory_linkset_cache` (see `docs/modules/concelier/operations/lnm-cache-plan.md`). Console should read from cache when present; fall back to live rebuild otherwise.
|
|
|
|
## API shape (WebService)
|
|
- Endpoint to expose via Console: `GET /v1/lnm/linksets/{advisoryId}`
|
|
- Query: `source` (required), `tenant`, optional `includeConflicts=true|false` (default true).
|
|
- Response JSON (deterministic key order):
|
|
```json
|
|
{
|
|
"advisoryId": "GHSA-123",
|
|
"source": "ghsa",
|
|
"observations": ["<mongoId>", "<mongoId2>"],
|
|
"normalized": {
|
|
"purls": ["pkg:npm/foo@1.0.0"],
|
|
"versions": ["1.0.0"],
|
|
"ranges": [],
|
|
"severities": [{"system":"cvssv3","score":7.5}]
|
|
},
|
|
"conflicts": [
|
|
{"field":"severities","reason":"disagreement","values":["7.5","9.8"]}
|
|
],
|
|
"provenance": {
|
|
"observationHashes": ["..."],
|
|
"toolVersion": "lnm-1.0"
|
|
},
|
|
"createdAt": "2025-11-20T00:00:00Z"
|
|
}
|
|
```
|
|
- Sorting: observations sorted by `source, advisoryId, fetchedAt` before hashing; response preserves that order.
|
|
- Caching: when cache hit, return cached document; when miss, rebuild, write cache, then return.
|
|
|
|
## Console rendering contract
|
|
- Fields to surface:
|
|
- `normalized.purls` (list) and `normalized.versions`
|
|
- `conflicts` if non-empty: show field + reason text; keep order as returned.
|
|
- `provenance.observationHashes` as “evidence anchors” (list); do not prettify.
|
|
- Tenant header required; no cross-tenant leakage. Scope `concelier:lnm.read`.
|
|
|
|
## Error handling
|
|
- 404 when linkset missing for advisory/source.
|
|
- 409 when tenant header missing/invalid.
|
|
- Deterministic error body: `{ "error": "<code>", "message": "..." }`.
|
|
|
|
## Telemetry (reuse existing meters)
|
|
- Increment `lnm.cache.hit_total` / `lnm.cache.write_total` as defined in cache plan.
|
|
- Log template on returns: `lnm_console_success tenant={Tenant} advisoryId={AdvisoryId} source={Source} cached={Cached}`.
|
|
|
|
## Owners
|
|
- Concelier Console Guild (primary)
|
|
- Concelier Core Guild (review)
|
|
|
|
This document is authoritative for CONCELIER-CONSOLE-23-001..003 in Sprint 110.
|