docs consolidation
This commit is contained in:
@@ -1,19 +0,0 @@
|
||||
# Attestation Plan 2001 · Evidence Locker contract handoff (2025-11-24)
|
||||
|
||||
Owners: Evidence Locker Guild · Excititor Guild
|
||||
Status: Published (unblocks ATTEST-PLAN-2001)
|
||||
|
||||
## Inputs
|
||||
- Sealed bundle contract: `docs/modules/evidence-locker/prep/2025-11-24-evidence-locker-contract.md`
|
||||
- Bundle schema: `docs/modules/evidence-locker/schemas/bundle.schema.json`
|
||||
- Sample bundle + hash: `docs/modules/evidence-locker/samples/evidence-bundle-sample.tgz` (+ `.sha256`)
|
||||
|
||||
## Plan
|
||||
1) Align attestation payloads with sealed bundle contract (subjects, DSSE layout, manifest fields).
|
||||
2) Produce CLI/Export Center consumer notes: expected file layout, required hashes, validation steps.
|
||||
3) Add verification harness reference for Excititor/Attestor (reuse sample bundle + DSSE public key from contract note).
|
||||
4) Update downstream sprints (Excititor airgap/export, Export Center) with contract link and hash.
|
||||
|
||||
## Next actions
|
||||
- Evidence Locker Guild: confirm final schema hash matches sample bundle (track in contract note).
|
||||
- Excititor Guild: wire contract path into airgap/attestation tests; report readiness in respective sprints.
|
||||
@@ -34,6 +34,7 @@ Authority is the platform OIDC/OAuth2 control plane that mints short-lived, send
|
||||
- ./operations/key-rotation.md
|
||||
- ./operations/monitoring.md
|
||||
- ./operations/grafana-dashboard.json
|
||||
- ./crypto-provider-contract.md
|
||||
- ./gaps/2025-12-04-auth-gaps-au1-au10.md
|
||||
- ./gaps/2025-12-04-rekor-receipt-gaps-rr1-rr10.md
|
||||
- Sprint/status mirrors: `docs/implplan/SPRINT_0314_0001_0001_docs_modules_authority.md`, `docs/modules/authority/TASKS.md`
|
||||
|
||||
68
docs/modules/authority/crypto-provider-contract.md
Normal file
68
docs/modules/authority/crypto-provider-contract.md
Normal file
@@ -0,0 +1,68 @@
|
||||
# Authority Crypto Provider and JWKS Contract
|
||||
|
||||
This document defines the minimum contract Authority must satisfy to support sovereign crypto providers (FIPS, GOST, SM, PQ-ready modes where enabled) while keeping exports deterministic and offline-verifiable.
|
||||
|
||||
## 1) Scope
|
||||
- Provider registry binding for Authority signing keys.
|
||||
- JWKS export rules (which keys are exposed and how `kid` is computed).
|
||||
- Signing profile selection rules (how Authority chooses keys/algorithms for different operations).
|
||||
- Determinism requirements for JWKS JSON and key identifiers.
|
||||
|
||||
This contract is written so downstream consumers (Gateway, services, CLI, Offline Kit tooling) can validate tokens and rotate trust roots without depending on Authority's internal database schema.
|
||||
|
||||
## 2) Terms
|
||||
- Provider: a crypto implementation or backend (software, HSM, KMS) identified by `provider_id`.
|
||||
- Key: a signing key (or key handle) identified by `key_id` within a provider.
|
||||
- Profile: a named signing policy that constrains algorithm choices and key selection.
|
||||
- `kid`: the key identifier exposed in JWT headers and JWKS entries.
|
||||
|
||||
## 3) Provider registry (required fields)
|
||||
|
||||
Each registered Authority signing key MUST have, at minimum:
|
||||
- `provider_id`: stable provider identifier (string).
|
||||
- `key_id`: stable key identifier within the provider (string).
|
||||
- `alg`: signing algorithm identifier as used by JWT/JWS (string).
|
||||
- `usage`: at least `sig` (signing). If other usages are supported, they must be explicit.
|
||||
- `tenant_scope` (optional): when set, the key is only valid for the specified tenant(s); when absent, it is platform-wide.
|
||||
|
||||
## 4) JWKS export rules
|
||||
|
||||
### 4.1 Which keys are exported
|
||||
- JWKS MUST include only keys usable for token verification by downstream services.
|
||||
- Exported keys MUST be filtered by:
|
||||
- profile rules (do not export keys that cannot be selected by any active profile), and
|
||||
- tenant scope (do not export tenant-scoped keys into other tenants' JWKS views if per-tenant JWKS is supported).
|
||||
|
||||
### 4.2 `kid` composition (deterministic)
|
||||
`kid` MUST be stable across restarts and across equivalent deployments.
|
||||
|
||||
Recommended minimum rule:
|
||||
- Compute `kid` from the public key material plus the profile discriminator:
|
||||
- `kid = sha256(public_key_spki_bytes || ":" || profile_id)`
|
||||
|
||||
If Authority exposes both an all-profiles JWKS and a per-profile JWKS, the `kid` value must remain stable in both views.
|
||||
|
||||
### 4.3 Canonical JWKS JSON (deterministic)
|
||||
- JWKS JSON MUST be canonicalized for reproducible hashing and offline verification:
|
||||
- stable key ordering (sort by `kid` ascending),
|
||||
- stable field ordering within a key object,
|
||||
- no incidental whitespace dependence for hashing or signatures.
|
||||
|
||||
## 5) Signing profiles
|
||||
|
||||
Authority SHOULD define named profiles (examples: `default`, `ru-gost`, `pq-experimental`) that map:
|
||||
- allowed algorithms (`alg` allowlist),
|
||||
- allowed providers (provider allowlist),
|
||||
- selection precedence when multiple keys match.
|
||||
|
||||
Profile selection MUST be deterministic given the same registry and request context.
|
||||
|
||||
## 6) Rotation and revocation expectations
|
||||
- Rotation MUST preserve the ability to verify previously issued (unexpired) tokens.
|
||||
- Revocation exports and JWKS exports MUST be consumable offline (cacheable and distributable in Offline Kit bundles).
|
||||
|
||||
## 7) Related docs
|
||||
- Authority module dossier: `docs/modules/authority/architecture.md`
|
||||
- Authority operations (key rotation, backup/restore): `docs/modules/authority/operations/`
|
||||
- Gateway tenant/auth header contract: `docs/api/gateway/tenant-auth.md`
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
# Authority Crypto Provider Contract Prep — PREP-AUTH-CRYPTO-90-001-NEEDS-AUTHORITY-PROVI
|
||||
|
||||
Status: Draft (2025-11-20)
|
||||
Owners: Authority Core Guild · Security Guild
|
||||
Scope: Capture the provider/key/JWKS contract Authority must publish to unblock sovereign crypto enablement.
|
||||
|
||||
## Required contract elements
|
||||
- Provider registry binding for Authority signing keys (FIPS, GOST, PQ optional): fields `provider_id`, `key_id`, `alg`, `kid`, `usage`, `tenant_scope?`.
|
||||
- JWKS export requirements: which keys exposed, `x5u`/`x5c` handling, `kid` format, and rotation cadence.
|
||||
- Signing profiles: mapping of Authority API operations to provider profiles (default, ru-gost, pq-experimental).
|
||||
- Determinism: canonical JSON for JWKS; stable `kid` composition (hash of public key + profile).
|
||||
|
||||
## Acceptance / unblock criteria
|
||||
- Publish provider contract in `docs/modules/authority/crypto-provider-contract.md` (or update existing doc) with sample JWKS and provider config snippet.
|
||||
- Record schema hash/kid composition rule here and in Sprint 0514 Decisions/Risks.
|
||||
- Notify downstream consumers (Scanner, Attestor, Concelier) via sprint links once frozen.
|
||||
|
||||
## Handoff
|
||||
Use this doc as the prep artefact for PREP-AUTH-CRYPTO-90-001-NEEDS-AUTHORITY-PROVI. Update with the final contract and samples; then set the sprint task to DONE and unblock AUTH-CRYPTO-90-001 implementation.
|
||||
@@ -1,18 +0,0 @@
|
||||
# CLI Authentication — Draft Skeleton (2025-12-05 UTC)
|
||||
|
||||
Status: draft placeholder. Inputs pending: DVDO0110 env vars, token formats, monitoring plan.
|
||||
|
||||
## Supported Flows
|
||||
- Device/code, PAT, workload identity (to confirm).
|
||||
|
||||
## Configuration
|
||||
- Env vars and flags (to be filled once finalized).
|
||||
|
||||
## Multi-Tenant Considerations
|
||||
- Scope selection and defaults.
|
||||
|
||||
## Troubleshooting
|
||||
- Common errors; log paths; retry/backoff guidance.
|
||||
|
||||
## Open TODOs
|
||||
- Insert definitive env var list and examples when available.
|
||||
@@ -1,19 +1,85 @@
|
||||
# stella auth — Command Guide
|
||||
# stella auth - Command Guide
|
||||
|
||||
The `stella auth` command group manages Authority-backed authentication and token operations used by other CLI commands.
|
||||
|
||||
## Commands
|
||||
- `stella auth login --token <token> [--url <baseUrl>]`
|
||||
- `stella auth status`
|
||||
- `stella auth logout`
|
||||
|
||||
## Flags
|
||||
- `--url`: API base URL; defaults to config/env.
|
||||
- `--token`: bearer token or OIDC device code (future); stored in config if allowed.
|
||||
### auth login
|
||||
|
||||
## Behaviour
|
||||
- Login writes token to config file or keyring (where supported) with deterministic permissions; never echoes secrets.
|
||||
- Status prints current user/tenant scopes if available; uses exit code 3 when unauthenticated.
|
||||
- Logout removes stored token and cached session data.
|
||||
Acquire and cache an access token using the configured Authority credentials.
|
||||
|
||||
```bash
|
||||
stella auth login
|
||||
stella auth login --force
|
||||
```
|
||||
|
||||
Notes:
|
||||
- `--force` ignores cached tokens and forces re-authentication.
|
||||
- Credential sources are configuration-driven (profile/env). This command does not accept raw tokens on the command line.
|
||||
|
||||
### auth status / whoami / logout
|
||||
|
||||
```bash
|
||||
stella auth status
|
||||
stella auth whoami
|
||||
stella auth logout
|
||||
```
|
||||
|
||||
Behavior:
|
||||
- `status` reports whether a cached token exists and whether it is still valid.
|
||||
- `whoami` prints cached token claims (subject, scopes, expiry) for diagnostics.
|
||||
- `logout` removes cached tokens for the active credentials.
|
||||
|
||||
### auth revoke export / verify
|
||||
|
||||
Export or verify Authority revocation bundles.
|
||||
|
||||
```bash
|
||||
stella auth revoke export --output ./revocation-export
|
||||
stella auth revoke verify --bundle ./revocation-bundle.json --signature ./revocation-bundle.json.jws --key ./authority.pub.pem
|
||||
```
|
||||
|
||||
### auth token mint
|
||||
|
||||
Mint a service account token (requires appropriate Authority permissions).
|
||||
|
||||
```bash
|
||||
stella auth token mint --service-account concelier-jobs \
|
||||
--scope concelier.jobs.trigger --scope advisory:ingest --scope advisory:read \
|
||||
--tenant tenant-default \
|
||||
--reason "scheduled ingestion" \
|
||||
--raw
|
||||
```
|
||||
|
||||
Flags:
|
||||
- `--service-account` / `-s` (required): service account identifier.
|
||||
- `--scope` (repeatable): scopes to include in the minted token.
|
||||
- `--expires-in` (optional): expiry in seconds.
|
||||
- `--tenant` (optional): tenant context.
|
||||
- `--reason` (optional): audit reason.
|
||||
- `--raw`: output only the token value (automation-friendly).
|
||||
|
||||
### auth token delegate
|
||||
|
||||
Delegate your current token to another principal.
|
||||
|
||||
```bash
|
||||
stella auth token delegate --to user@example.org \
|
||||
--scope advisory:read \
|
||||
--tenant tenant-default \
|
||||
--reason "support session" \
|
||||
--raw
|
||||
```
|
||||
|
||||
Flags:
|
||||
- `--to` (required): principal identifier to delegate to.
|
||||
- `--scope` (repeatable): delegated scopes (must be a subset of the current token).
|
||||
- `--expires-in` (optional): expiry in seconds (defaults to remaining token lifetime).
|
||||
- `--tenant` (optional): tenant context.
|
||||
- `--reason` (required): audit reason.
|
||||
- `--raw`: output only the token value (automation-friendly).
|
||||
|
||||
## Offline notes
|
||||
- `auth login` and token mint/delegate require connectivity to Authority.
|
||||
- `auth revoke verify`, `status`, `whoami`, and `logout` can operate using local cached state.
|
||||
|
||||
## Offline/air-gap notes
|
||||
- Login requires network; if `--offline` is set, command must fail with exit code 5.
|
||||
- Status/logout work offline using cached credentials only.
|
||||
|
||||
60
docs/modules/cli/guides/commands/db.md
Normal file
60
docs/modules/cli/guides/commands/db.md
Normal file
@@ -0,0 +1,60 @@
|
||||
# stella db - Command Guide
|
||||
|
||||
The `stella db` command group triggers Concelier database operations via backend jobs (connector stages, merge reconciliation, exports).
|
||||
|
||||
These commands are operational: they typically require Authority authentication and appropriate Concelier scopes.
|
||||
|
||||
## Commands
|
||||
|
||||
### db fetch
|
||||
|
||||
Trigger a connector stage (`fetch`, `parse`, or `map`) for a given source.
|
||||
|
||||
```bash
|
||||
stella db fetch --source osv --stage fetch
|
||||
stella db fetch --source osv --stage parse
|
||||
stella db fetch --source osv --stage map
|
||||
```
|
||||
|
||||
Options:
|
||||
- `--source` (required): connector identifier (for example `osv`, `redhat`, `ghsa`).
|
||||
- `--stage` (optional): `fetch`, `parse`, or `map` (defaults to `fetch`).
|
||||
- `--mode` (optional): connector-specific mode (for example `init`, `resume`, `cursor`).
|
||||
|
||||
### db merge
|
||||
|
||||
Run canonical merge reconciliation.
|
||||
|
||||
```bash
|
||||
stella db merge
|
||||
```
|
||||
|
||||
### db export
|
||||
|
||||
Run Concelier export jobs.
|
||||
|
||||
```bash
|
||||
stella db export --format json
|
||||
stella db export --format trivy-db --delta
|
||||
```
|
||||
|
||||
Options:
|
||||
- `--format` (optional): `json` or `trivy-db` (defaults to `json`).
|
||||
- `--delta` (optional): request a delta export when supported.
|
||||
- `--publish-full` / `--publish-delta` (optional): override whether exports are published (true/false).
|
||||
- `--bundle-full` / `--bundle-delta` (optional): override whether offline bundles include full/delta exports (true/false).
|
||||
|
||||
## Common setup
|
||||
|
||||
Point the CLI at the Concelier base URL:
|
||||
```bash
|
||||
export STELLAOPS_BACKEND_URL="https://concelier.example.internal"
|
||||
```
|
||||
|
||||
Authenticate:
|
||||
```bash
|
||||
stella auth login
|
||||
```
|
||||
|
||||
See: `docs/10_CONCELIER_CLI_QUICKSTART.md` and `docs/modules/concelier/operations/authority-audit-runbook.md`.
|
||||
|
||||
@@ -1,265 +1,157 @@
|
||||
# stella reachability — Command Guide
|
||||
# stella reachability - Command Guide
|
||||
|
||||
## Overview
|
||||
|
||||
The `stella reachability` command group provides reachability analysis capabilities for vulnerability exploitability assessment. It supports call graph upload, analysis listing, and detailed reachability explanations.
|
||||
The `stella reachability` command group uploads call graphs and queries reachability analyses for vulnerability exploitability assessment.
|
||||
|
||||
Typical flow:
|
||||
1. Generate a call graph locally (optional): `stella scan graph ...`
|
||||
2. Upload the call graph: `stella reachability upload-callgraph ...`
|
||||
3. List analyses: `stella reachability list ...`
|
||||
4. Explain reachability: `stella reachability explain ...`
|
||||
|
||||
Notes:
|
||||
- In multi-tenant environments, pass `--tenant` explicitly.
|
||||
- Outputs are deterministic: stable ordering, UTC timestamps, and cursor-based paging where applicable.
|
||||
|
||||
## Generate a call graph (stella scan graph)
|
||||
|
||||
`stella scan graph` extracts a call graph from source code using a language-specific extractor:
|
||||
- Executable name: `stella-callgraph-<lang>`
|
||||
- Must be available in `PATH`
|
||||
|
||||
Examples:
|
||||
|
||||
```bash
|
||||
# .NET solution
|
||||
stella scan graph \
|
||||
--lang dotnet \
|
||||
--target . \
|
||||
--sln ./MySolution.sln \
|
||||
--output ./callgraph.json
|
||||
|
||||
# Node.js project (writes JSON to stdout)
|
||||
stella scan graph \
|
||||
--lang node \
|
||||
--target ./service \
|
||||
--format json > ./callgraph.json
|
||||
```
|
||||
|
||||
Supported `stella scan graph` output formats:
|
||||
- `json` (default; suitable for upload)
|
||||
- `dot`
|
||||
- `summary` (prints only a summary; does not emit graph JSON)
|
||||
|
||||
If you generate call graphs with other tooling, uploads support `json`, `proto`, and `dot` formats (or `auto` detection).
|
||||
|
||||
## Commands
|
||||
|
||||
### Upload Call Graph (CLI-SIG-26-001)
|
||||
### upload-callgraph
|
||||
|
||||
Upload a call graph for reachability analysis.
|
||||
|
||||
```bash
|
||||
# Upload a call graph for reachability analysis
|
||||
stella reachability upload-callgraph \
|
||||
--path <call-graph-file> \
|
||||
[--tenant <id>] \
|
||||
[--scan-id <id>] \
|
||||
[--asset-id <id>] \
|
||||
[--format auto|json|proto|dot] \
|
||||
[--json]
|
||||
--path ./callgraph.json \
|
||||
--scan-id scan-12345 \
|
||||
--tenant acme \
|
||||
--format auto
|
||||
```
|
||||
|
||||
**Options:**
|
||||
Options:
|
||||
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `--path` / `-p` | Path to the call graph file (required) |
|
||||
| `--scan-id` | Scan identifier to associate with the call graph |
|
||||
| `--asset-id` / `-a` | Asset identifier to associate with the call graph |
|
||||
| `--format` / `-f` | Call graph format: `auto` (default), `json`, `proto`, `dot` |
|
||||
| --- | --- |
|
||||
| `--path`, `-p` | Path to the call graph file (required). |
|
||||
| `--scan-id` | Scan identifier to associate with the call graph. |
|
||||
| `--asset-id`, `-a` | Asset identifier to associate with the call graph. |
|
||||
| `--format`, `-f` | `auto` (default), `json`, `proto`, `dot`. |
|
||||
| `--tenant`, `-t` | Tenant identifier (recommended in multi-tenant envs). |
|
||||
| `--json` | Emit raw JSON payload instead of formatted output. |
|
||||
|
||||
**Required:** At least one of `--scan-id` or `--asset-id`.
|
||||
Required: at least one of `--scan-id` or `--asset-id`.
|
||||
|
||||
**Supported Call Graph Formats:**
|
||||
- JSON (native format)
|
||||
- Protocol Buffers (proto)
|
||||
- DOT/GraphViz format
|
||||
### list
|
||||
|
||||
### List Reachability Analyses (CLI-SIG-26-001)
|
||||
List reachability analyses.
|
||||
|
||||
```bash
|
||||
# List reachability analyses
|
||||
stella reachability list \
|
||||
[--tenant <id>] \
|
||||
[--scan-id <id>] \
|
||||
[--asset-id <id>] \
|
||||
[--status pending|processing|completed|failed] \
|
||||
[--limit <num>] \
|
||||
[--offset <num>] \
|
||||
[--json]
|
||||
--scan-id scan-12345 \
|
||||
--status completed \
|
||||
--limit 20 \
|
||||
--json
|
||||
```
|
||||
|
||||
**Options:**
|
||||
Options:
|
||||
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `--scan-id` | Filter by scan identifier |
|
||||
| `--asset-id` / `-a` | Filter by asset identifier |
|
||||
| `--status` | Filter by analysis status |
|
||||
| `--limit` / `-l` | Maximum number of results (default 100) |
|
||||
| `--offset` / `-o` | Pagination offset |
|
||||
| --- | --- |
|
||||
| `--scan-id` | Filter by scan identifier. |
|
||||
| `--asset-id`, `-a` | Filter by asset identifier. |
|
||||
| `--status` | Filter by status (`pending`, `processing`, `completed`, `failed`). |
|
||||
| `--limit`, `-l` | Maximum number of results (default 100). |
|
||||
| `--offset`, `-o` | Pagination offset. |
|
||||
| `--tenant`, `-t` | Tenant identifier. |
|
||||
| `--json` | Emit raw JSON payload. |
|
||||
|
||||
**Output Columns:**
|
||||
- Analysis ID
|
||||
- Asset name/ID
|
||||
- Status (pending, processing, completed, failed)
|
||||
- Reachable count
|
||||
- Unreachable count
|
||||
- Unknown count
|
||||
- Created timestamp
|
||||
### explain
|
||||
|
||||
### Explain Reachability (CLI-SIG-26-001)
|
||||
Explain reachability for a vulnerability ID or a package PURL.
|
||||
|
||||
```bash
|
||||
# Explain reachability for a vulnerability or package
|
||||
stella reachability explain \
|
||||
--analysis-id <id> \
|
||||
[--tenant <id>] \
|
||||
[--vuln-id <cve-id>] \
|
||||
[--purl <package-url>] \
|
||||
[--call-paths] \
|
||||
[--json]
|
||||
--analysis-id RA-abc123 \
|
||||
--vuln-id CVE-2024-1234 \
|
||||
--call-paths
|
||||
```
|
||||
|
||||
**Options:**
|
||||
Options:
|
||||
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `--analysis-id` / `-i` | Analysis identifier (required) |
|
||||
| `--vuln-id` / `-v` | Vulnerability identifier to explain |
|
||||
| `--purl` | Package URL to explain |
|
||||
| `--call-paths` | Include detailed call paths in the explanation |
|
||||
| --- | --- |
|
||||
| `--analysis-id`, `-i` | Analysis identifier (required). |
|
||||
| `--vuln-id`, `-v` | Vulnerability identifier to explain. |
|
||||
| `--purl` | Package URL to explain. |
|
||||
| `--call-paths` | Include detailed call paths in the explanation. |
|
||||
| `--tenant`, `-t` | Tenant identifier. |
|
||||
| `--json` | Emit raw JSON payload. |
|
||||
|
||||
**Required:** At least one of `--vuln-id` or `--purl`.
|
||||
Required: at least one of `--vuln-id` or `--purl`.
|
||||
|
||||
**Output:**
|
||||
- Reachability state (reachable, unreachable, unknown)
|
||||
- Reachability score (0-1)
|
||||
- Confidence level
|
||||
- Reasoning explanation
|
||||
- Affected functions list
|
||||
- Call paths (when `--call-paths` is used)
|
||||
|
||||
## Integration with Policy Simulation (CLI-SIG-26-002)
|
||||
## Policy simulation integration
|
||||
|
||||
Reachability overrides can be applied during policy simulation:
|
||||
|
||||
```bash
|
||||
stella policy simulate P-7 \
|
||||
--reachability-state "CVE-2024-1234:unreachable" \
|
||||
--reachability-state "pkg:npm/lodash@4.17.0:reachable" \
|
||||
--reachability-state "pkg:npm/lodash@4.17.21:reachable" \
|
||||
--reachability-score "CVE-2024-5678:0.25"
|
||||
```
|
||||
|
||||
**Override Format:**
|
||||
- State: `<identifier>:<state>` where state is `reachable`, `unreachable`, `unknown`, or `indeterminate`
|
||||
- Score: `<identifier>:<score>` where score is a decimal between 0 and 1
|
||||
Override formats:
|
||||
- State: `<identifier>:<reachable|unreachable|unknown|indeterminate>`
|
||||
- Score: `<identifier>:<0..1>`
|
||||
|
||||
**Identifier Types:**
|
||||
- Vulnerability ID: `CVE-XXXX-XXXX`, `GHSA-xxxx-xxxx-xxxx`
|
||||
- Package URL: `pkg:npm/package@version`, `pkg:maven/group/artifact@version`
|
||||
Identifier types:
|
||||
- Vulnerability ID: `CVE-...`, `GHSA-...`
|
||||
- Package URL: `pkg:...`
|
||||
|
||||
## Exit Codes
|
||||
## Reachability states
|
||||
|
||||
| State | Meaning |
|
||||
| --- | --- |
|
||||
| `reachable` | Vulnerable code is reachable from entry points. |
|
||||
| `unreachable` | Vulnerable code is not reachable. |
|
||||
| `unknown` | Insufficient data to decide. |
|
||||
| `indeterminate` | Inconclusive (dynamic dispatch/reflection/etc). |
|
||||
|
||||
## Exit codes
|
||||
|
||||
| Code | Meaning |
|
||||
|------|---------|
|
||||
| 0 | Success |
|
||||
| 1 | Error or upload failure |
|
||||
| 4 | Input validation error |
|
||||
| 130 | Operation cancelled by user |
|
||||
|
||||
## JSON Schema: ReachabilityExplainResult
|
||||
|
||||
```json
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"analysisId": { "type": "string" },
|
||||
"vulnerabilityId": { "type": "string" },
|
||||
"packagePurl": { "type": "string" },
|
||||
"reachabilityState": {
|
||||
"type": "string",
|
||||
"enum": ["reachable", "unreachable", "unknown", "indeterminate"]
|
||||
},
|
||||
"reachabilityScore": { "type": "number", "minimum": 0, "maximum": 1 },
|
||||
"confidence": { "type": "string" },
|
||||
"reasoning": { "type": "string" },
|
||||
"callPaths": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"pathId": { "type": "string" },
|
||||
"depth": { "type": "integer" },
|
||||
"entryPoint": { "$ref": "#/$defs/function" },
|
||||
"frames": { "type": "array", "items": { "$ref": "#/$defs/function" } },
|
||||
"vulnerableFunction": { "$ref": "#/$defs/function" }
|
||||
}
|
||||
}
|
||||
},
|
||||
"affectedFunctions": {
|
||||
"type": "array",
|
||||
"items": { "$ref": "#/$defs/function" }
|
||||
}
|
||||
},
|
||||
"$defs": {
|
||||
"function": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": { "type": "string" },
|
||||
"signature": { "type": "string" },
|
||||
"className": { "type": "string" },
|
||||
"packageName": { "type": "string" },
|
||||
"filePath": { "type": "string" },
|
||||
"lineNumber": { "type": "integer" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Upload a call graph
|
||||
|
||||
```bash
|
||||
# Upload call graph for a specific scan
|
||||
stella reachability upload-callgraph \
|
||||
--path ./callgraph.json \
|
||||
--scan-id scan-12345 \
|
||||
--format json
|
||||
|
||||
# Upload with auto-detection
|
||||
stella reachability upload-callgraph \
|
||||
--path ./app-callgraph.dot \
|
||||
--asset-id my-application
|
||||
```
|
||||
|
||||
### List recent analyses
|
||||
|
||||
```bash
|
||||
# List all completed analyses for an asset
|
||||
stella reachability list \
|
||||
--asset-id my-application \
|
||||
--status completed \
|
||||
--json
|
||||
|
||||
# List analyses with pagination
|
||||
stella reachability list \
|
||||
--limit 20 \
|
||||
--offset 40
|
||||
```
|
||||
|
||||
### Explain vulnerability reachability
|
||||
|
||||
```bash
|
||||
# Explain with call paths
|
||||
stella reachability explain \
|
||||
--analysis-id RA-abc123 \
|
||||
--vuln-id CVE-2024-1234 \
|
||||
--call-paths
|
||||
|
||||
# Explain package reachability
|
||||
stella reachability explain \
|
||||
--analysis-id RA-abc123 \
|
||||
--purl "pkg:npm/lodash@4.17.21" \
|
||||
--json
|
||||
```
|
||||
|
||||
### Policy simulation with reachability overrides
|
||||
|
||||
```bash
|
||||
# Mark specific vulnerability as unreachable
|
||||
stella policy simulate P-7 \
|
||||
--reachability-state "CVE-2024-1234:unreachable" \
|
||||
--explain
|
||||
|
||||
# Set low reachability score
|
||||
stella policy simulate P-7 \
|
||||
--reachability-score "pkg:npm/axios@0.21.0:0.1"
|
||||
```
|
||||
|
||||
## Reachability States
|
||||
|
||||
| State | Description |
|
||||
|-------|-------------|
|
||||
| `reachable` | Vulnerable code is reachable from application entry points |
|
||||
| `unreachable` | Vulnerable code cannot be reached during execution |
|
||||
| `unknown` | Reachability cannot be determined with available information |
|
||||
| `indeterminate` | Analysis inconclusive due to dynamic dispatch or reflection |
|
||||
|
||||
## Call Graph Generation
|
||||
|
||||
Call graphs can be generated using various tools:
|
||||
|
||||
- **Java:** [WALA](https://github.com/wala/WALA), [Soot](https://github.com/soot-oss/soot)
|
||||
- **JavaScript/Node.js:** [callgraph](https://www.npmjs.com/package/callgraph)
|
||||
- **Python:** [pycg](https://github.com/vitsalis/pycg)
|
||||
- **Go:** `go build -gcflags="-m"` + static analysis
|
||||
- **C/C++:** [LLVM](https://llvm.org/) call graph pass
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Upload call graphs after each build** to maintain accurate reachability data
|
||||
2. **Use asset IDs** for long-lived applications to track reachability changes over time
|
||||
3. **Include call paths** when debugging unexpected reachability results
|
||||
4. **Apply reachability overrides** in policy simulation to model remediation scenarios
|
||||
5. **Monitor unreachable counts** as a metric for dependency hygiene
|
||||
| --- | --- |
|
||||
| `0` | Success. |
|
||||
| `1` | Command failed. |
|
||||
| `4` | Input validation error. |
|
||||
| `130` | Operation cancelled. |
|
||||
|
||||
@@ -1,25 +1,206 @@
|
||||
# stella vuln — Command Guide
|
||||
# stella vuln - Command Guide
|
||||
|
||||
## Overview
|
||||
|
||||
The `stella vuln` command group is the operator surface for vulnerability triage workflows:
|
||||
- Query and inspect vulnerabilities (`list`, `show`)
|
||||
- Retrieve raw advisory observations for overlay consumers (`observations`)
|
||||
- Apply workflow actions (assign, comment, accept risk, verify fix, target fix, reopen)
|
||||
- Simulate policy/VEX changes (`simulate`)
|
||||
- Export offline evidence bundles and verify them (`export`, `export verify`)
|
||||
|
||||
Unless otherwise noted, commands support formatted output by default and `--json` for automation-friendly output.
|
||||
|
||||
## Commands
|
||||
- `stella vuln list --query <filter> [--group-by <field>] [--output json|ndjson|table] [--offline]`
|
||||
- `stella vuln get --id <vulnId> [--output json|table] [--offline]`
|
||||
- `stella vuln simulate --from <policyA> --to <policyB> --subjects <path> [--offline]`
|
||||
|
||||
## Flags (common)
|
||||
- `--offline`: read from cached snapshots; fail with exit code 5 if network would be used.
|
||||
- `--policy <id>`: scope queries to a policy projection.
|
||||
- `--page-size`, `--page-token`: deterministic pagination.
|
||||
- `--group-by`: `cve`, `package`, `status`, `advisory` (results stay stably ordered within groups).
|
||||
### observations
|
||||
|
||||
## Inputs/outputs
|
||||
- Inputs: Vuln Explorer API; optional cached snapshots when offline.
|
||||
- Outputs: sorted lists or detail documents with provenance pointers (`advisoryId`, `evidenceIds`, `consensusId`).
|
||||
- Exit codes follow `output-and-exit-codes.md`; 4 for not found, 5 for offline violation.
|
||||
List raw advisory observations (useful for overlay consumers).
|
||||
|
||||
## Determinism rules
|
||||
- Lists sorted by primary key then timestamp; group-by keeps stable ordering inside each bucket.
|
||||
- Timestamps UTC ISO-8601; hashes lower-case hex.
|
||||
```bash
|
||||
stella vuln observations \
|
||||
--tenant acme \
|
||||
--alias CVE-2024-1234 \
|
||||
--limit 50 \
|
||||
--json
|
||||
```
|
||||
|
||||
## Offline/air-gap notes
|
||||
- Use cached snapshots (`--offline`) when remote Explorer is unavailable; commands must not attempt network calls in this mode.
|
||||
- Simulation must read local policy snapshots and subjects when offline.
|
||||
Options:
|
||||
|
||||
| Flag | Description |
|
||||
| --- | --- |
|
||||
| `--tenant` | Tenant identifier (required). |
|
||||
| `--observation-id` | Filter by observation id (repeatable). |
|
||||
| `--alias` | Filter by vulnerability alias (repeatable). |
|
||||
| `--purl` | Filter by Package URL (repeatable). |
|
||||
| `--cpe` | Filter by CPE value (repeatable). |
|
||||
| `--limit` | Max items (default 200, max 500). |
|
||||
| `--cursor` | Opaque cursor token from a previous page. |
|
||||
| `--json` | Emit raw JSON payload instead of a table. |
|
||||
|
||||
### list
|
||||
|
||||
List vulnerabilities with filters, grouping, and pagination.
|
||||
|
||||
```bash
|
||||
stella vuln list \
|
||||
--severity high \
|
||||
--status open \
|
||||
--group-by package \
|
||||
--limit 50
|
||||
```
|
||||
|
||||
Options:
|
||||
|
||||
| Flag | Description |
|
||||
| --- | --- |
|
||||
| `--vuln-id` | Filter by vulnerability identifier (e.g., `CVE-2024-1234`). |
|
||||
| `--severity` | Filter by severity (`critical`, `high`, `medium`, `low`). |
|
||||
| `--status` | Filter by status (`open`, `triaged`, `accepted`, `fixed`, etc.). |
|
||||
| `--purl` | Filter by Package URL. |
|
||||
| `--cpe` | Filter by CPE value. |
|
||||
| `--sbom-id` | Filter by SBOM identifier. |
|
||||
| `--policy-id` | Filter by policy identifier. |
|
||||
| `--policy-version` | Filter by policy version. |
|
||||
| `--group-by` | Group by (`vuln`, `package`, `severity`, `status`). |
|
||||
| `--limit` | Max items (default 50, max 500). |
|
||||
| `--offset` | Offset paging (skip N). |
|
||||
| `--cursor` | Opaque cursor token from a previous page. |
|
||||
| `--tenant` | Tenant identifier (overrides profile/environment). |
|
||||
| `--json` | Emit raw JSON payload instead of a table. |
|
||||
| `--csv` | Emit CSV instead of a table. |
|
||||
|
||||
### show
|
||||
|
||||
Show details for a specific vulnerability id.
|
||||
|
||||
```bash
|
||||
stella vuln show CVE-2024-1234 --json
|
||||
```
|
||||
|
||||
Options:
|
||||
|
||||
| Flag | Description |
|
||||
| --- | --- |
|
||||
| `--tenant` | Tenant identifier (overrides profile/environment). |
|
||||
| `--json` | Emit raw JSON payload instead of formatted output. |
|
||||
|
||||
### Workflow commands
|
||||
|
||||
Workflow commands operate on either:
|
||||
- Explicit selection: repeat `--vuln-id <id>`
|
||||
- Filtered selection: `--filter-*` options
|
||||
|
||||
Shared options:
|
||||
|
||||
| Flag | Description |
|
||||
| --- | --- |
|
||||
| `--vuln-id` | Vulnerability ids to operate on (repeatable). |
|
||||
| `--filter-severity` | Filter by severity (`critical`, `high`, `medium`, `low`). |
|
||||
| `--filter-status` | Filter by current status. |
|
||||
| `--filter-purl` | Filter by Package URL. |
|
||||
| `--filter-sbom` | Filter by SBOM id. |
|
||||
| `--tenant` | Tenant identifier (overrides profile/environment). |
|
||||
| `--idempotency-key` | Idempotency key for retry-safe operations. |
|
||||
| `--json` | Emit raw JSON response. |
|
||||
|
||||
Commands:
|
||||
|
||||
```bash
|
||||
# Assign selected vulns to an assignee
|
||||
stella vuln assign alice@example.com --vuln-id CVE-2024-1234
|
||||
|
||||
# Add a comment
|
||||
stella vuln comment "triage started" --vuln-id CVE-2024-1234
|
||||
|
||||
# Accept risk with optional due date (ISO-8601)
|
||||
stella vuln accept-risk "risk accepted for legacy system" \
|
||||
--due-date 2026-12-31 \
|
||||
--vuln-id CVE-2024-1234
|
||||
|
||||
# Mark as fixed and verified
|
||||
stella vuln verify-fix \
|
||||
--fix-version 1.2.3 \
|
||||
--comment "patched in release 1.2.3" \
|
||||
--vuln-id CVE-2024-1234
|
||||
|
||||
# Set a target fix date
|
||||
stella vuln target-fix 2026-12-31 \
|
||||
--comment "scheduled in next maintenance window" \
|
||||
--vuln-id CVE-2024-1234
|
||||
|
||||
# Reopen a previously closed/accepted vuln
|
||||
stella vuln reopen --comment "regression observed" --vuln-id CVE-2024-1234
|
||||
```
|
||||
|
||||
### simulate
|
||||
|
||||
Simulate policy/VEX changes and show delta summaries.
|
||||
|
||||
```bash
|
||||
stella vuln simulate \
|
||||
--policy-id policy://tenant-default/runtime-hardening \
|
||||
--policy-version 7 \
|
||||
--vex-override "CVE-2024-1234=not_affected" \
|
||||
--severity-threshold high \
|
||||
--sbom-id sbom-001 \
|
||||
--markdown \
|
||||
--output ./vuln-sim-report.md
|
||||
```
|
||||
|
||||
Options:
|
||||
|
||||
| Flag | Description |
|
||||
| --- | --- |
|
||||
| `--policy-id` | Policy id to simulate (uses different version or a new policy). |
|
||||
| `--policy-version` | Policy version to simulate against. |
|
||||
| `--vex-override` | VEX status overrides (`vulnId=status`, repeatable). |
|
||||
| `--severity-threshold` | Threshold (`critical`, `high`, `medium`, `low`). |
|
||||
| `--sbom-id` | SBOM ids to include (repeatable). |
|
||||
| `--markdown` | Include Markdown report suitable for CI pipelines. |
|
||||
| `--changed-only` | Only show items that changed. |
|
||||
| `--tenant` | Tenant identifier for multi-tenant environments. |
|
||||
| `--json` | Output JSON for automation. |
|
||||
| `--output` | Write Markdown report to file instead of stdout. |
|
||||
|
||||
### export
|
||||
|
||||
Export vulnerability evidence bundles (optionally signed) for offline review and audit workflows.
|
||||
|
||||
```bash
|
||||
stella vuln export \
|
||||
--vuln-id CVE-2024-1234 \
|
||||
--format ndjson \
|
||||
--output ./vuln-export.ndjson
|
||||
```
|
||||
|
||||
Options:
|
||||
|
||||
| Flag | Description |
|
||||
| --- | --- |
|
||||
| `--vuln-id` | Vulnerability ids to include (repeatable). |
|
||||
| `--sbom-id` | SBOM ids to include (repeatable). |
|
||||
| `--policy-id` | Policy id for export filtering. |
|
||||
| `--format` | `ndjson` (default) or `json`. |
|
||||
| `--include-evidence` | Include evidence data (default: true). |
|
||||
| `--include-ledger` | Include workflow ledger (default: true). |
|
||||
| `--signed` | Request signed export bundle (default: true). |
|
||||
| `--output` | Output file path for the export bundle (required). |
|
||||
| `--tenant` | Tenant identifier for multi-tenant environments. |
|
||||
|
||||
### export verify
|
||||
|
||||
Verify signature and digest of an exported vulnerability bundle.
|
||||
|
||||
```bash
|
||||
stella vuln export verify ./vuln-export.ndjson \
|
||||
--expected-digest sha256:deadbeef... \
|
||||
--public-key ./authority-public.pem
|
||||
```
|
||||
|
||||
Options:
|
||||
|
||||
| Flag | Description |
|
||||
| --- | --- |
|
||||
| `--expected-digest` | Expected digest to verify (`sha256:<hex>`). |
|
||||
| `--public-key` | Public key path for signature verification. |
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
# CLI Guide · Graph & Vulnerability
|
||||
|
||||
Status: Draft (2025-11-26) — reflects current Graph API surface; Vuln API pending (see docs/api/vuln.md).
|
||||
|
||||
## Prereqs
|
||||
- `stellaops-cli` built from current repo.
|
||||
- Auth token with scopes: `graph:read`, `graph:query`, `graph:export` (and `vuln:read` when Vuln API lands).
|
||||
- Tenant header is required for all calls (`--tenant`).
|
||||
|
||||
## Commands
|
||||
|
||||
### Search graph
|
||||
```bash
|
||||
stella graph search \
|
||||
--tenant acme \
|
||||
--kinds component \
|
||||
--query "pkg:npm/" \
|
||||
--limit 20 \
|
||||
--format ndjson
|
||||
```
|
||||
Outputs NDJSON tiles (`node`, optional `cursor`).
|
||||
|
||||
### Query graph with budgets
|
||||
```bash
|
||||
stella graph query \
|
||||
--tenant acme \
|
||||
--kinds component \
|
||||
--query widget \
|
||||
--include-edges \
|
||||
--budget-tiles 200 \
|
||||
--budget-nodes 150 \
|
||||
--budget-edges 100 \
|
||||
--format ndjson
|
||||
```
|
||||
Returns nodes/edges/stats/cursor with cost metadata. If edge budget is exceeded, an `error` tile with `GRAPH_BUDGET_EXCEEDED` is returned.
|
||||
|
||||
### Paths
|
||||
```bash
|
||||
stella graph paths \
|
||||
--tenant acme \
|
||||
--source gn:acme:component:one \
|
||||
--target gn:acme:component:two \
|
||||
--max-depth 4 \
|
||||
--include-edges \
|
||||
--format ndjson
|
||||
```
|
||||
|
||||
### Diff snapshots
|
||||
```bash
|
||||
stella graph diff \
|
||||
--tenant acme \
|
||||
--snapshot-a snapA \
|
||||
--snapshot-b snapB \
|
||||
--include-edges \
|
||||
--format ndjson
|
||||
```
|
||||
|
||||
### Export graph
|
||||
```bash
|
||||
stella graph export \
|
||||
--tenant acme \
|
||||
--format ndjson \
|
||||
--include-edges \
|
||||
--kinds component \
|
||||
--query "pkg:npm/" \
|
||||
--out graph-export.ndjson
|
||||
```
|
||||
Manifest is returned with jobId, sha256, size, and download URL; CLI downloads to `--out`.
|
||||
|
||||
### Vuln lookup (placeholder)
|
||||
Pending Vuln Explorer API; for now use graph search/query to inspect impacted components. See `docs/api/vuln.md`.
|
||||
|
||||
## Exit codes
|
||||
- `0` success
|
||||
- `2` validation error (missing kinds/tenant/scopes)
|
||||
- `3` budget exceeded (error tile received)
|
||||
- `4` network/auth failure
|
||||
|
||||
## Tips
|
||||
- Add `--format table` (when available) for quick summaries; default is NDJSON.
|
||||
- Use `--cursor` from a previous call to page results.
|
||||
- To sample overlays, pass `--include-overlays` (budget permitting).
|
||||
@@ -1,20 +0,0 @@
|
||||
# CLI Ops Prep — PREP-CLI-OPS-0001
|
||||
|
||||
Status: **Ready for implementation** (2025-11-20)
|
||||
Owners: Ops Guild
|
||||
Scope: Capture required demo outputs and runbook deltas for the next CLI ops demo so CLI-OPS-0001 can proceed.
|
||||
|
||||
## Required demo outputs
|
||||
- Latest CLI binary build identifier (commit SHA and version string).
|
||||
- Demo script transcript covering: `stella evidence verify`, `stella attest bundle verify`, `stella export ...` (airgap profile), and `stella policy lint`.
|
||||
- Screenshots or asciinema recording showing: auth flow with offline token, evidence verification success, attestation failure path.
|
||||
- Hashes for demo artefacts (bundles, logs) placed under `out/cli/demo-ops/` with `.sha256` files.
|
||||
|
||||
## Runbook updates expected
|
||||
- Update `docs/modules/cli/operations/cli-ops-runbook.md` (section “Offline Demo”) with: prerequisites, commands, expected outputs, and rollback steps.
|
||||
- Add checklist to ensure `STELLA_CLI_OFFLINE=1` and local evidence bundle cache populated before demo.
|
||||
|
||||
## Acceptance criteria
|
||||
- Demo outputs (recording + hashes) published under `out/cli/demo-ops/` with SHA256 files.
|
||||
- Runbook updated per above; references the exact CLI build SHA used.
|
||||
- Ops Guild signs off that CLI-OPS-0001 can move to implementation.
|
||||
@@ -120,15 +120,18 @@ Correlate audit logs with the following global meter exported via `Concelier.Sou
|
||||
|
||||
## 4. Rollout & Verification Procedure
|
||||
|
||||
1. **Pre-checks**
|
||||
- Align with the rollout phases documented in `docs/10_CONCELIER_CLI_QUICKSTART.md` (validation → rehearsal → enforced) and record the target dates in your change request.
|
||||
- Confirm `allowAnonymousFallback` is `false` in production; keep `true` only during staged validation.
|
||||
- Validate Authority issuer metadata is reachable from Concelier (`curl https://authority.internal/.well-known/openid-configuration` from the host).
|
||||
|
||||
2. **Smoke test with valid token**
|
||||
- Obtain a token via CLI: `stella auth login --scope "concelier.jobs.trigger advisory:ingest" --scope advisory:read`.
|
||||
- Trigger a read-only endpoint: `curl -H "Authorization: Bearer $TOKEN" https://concelier.internal/jobs/definitions`.
|
||||
- Expect HTTP 200/202 and an audit log with `bypass=False`, `scopes=concelier.jobs.trigger advisory:ingest advisory:read`, and `tenant=tenant-default`.
|
||||
1. **Pre-checks**
|
||||
- Align with your rollout plan and record the target dates in your change request.
|
||||
- Confirm `allowAnonymousFallback` is `false` in production; keep `true` only during staged validation.
|
||||
- Validate Authority issuer metadata is reachable from Concelier (`curl https://authority.internal/.well-known/openid-configuration` from the host).
|
||||
|
||||
2. **Smoke test with valid token**
|
||||
- Authenticate (cached): `stella auth login`.
|
||||
- Mint a scoped token for curl (example):
|
||||
- `TOKEN="$(stella auth token mint --service-account concelier-jobs --scope concelier.jobs.trigger --scope advisory:ingest --scope advisory:read --tenant tenant-default --reason \"concelier auth smoke test\" --raw)"`
|
||||
- Trigger a read-only endpoint:
|
||||
- `curl -H "Authorization: Bearer $TOKEN" -H "X-Stella-Tenant: tenant-default" https://concelier.internal/jobs/definitions`
|
||||
- Expect HTTP 200/202 and an audit log with `bypass=False`, `scopes=concelier.jobs.trigger advisory:ingest advisory:read`, and `tenant=tenant-default`.
|
||||
|
||||
3. **Negative test without token**
|
||||
- Call the same endpoint without a token. Expect HTTP 401, `bypass=False`.
|
||||
@@ -153,7 +156,7 @@ Correlate audit logs with the following global meter exported via `Concelier.Sou
|
||||
|
||||
## 6. References
|
||||
|
||||
- `docs/21_INSTALL_GUIDE.md` – Authority configuration quick start.
|
||||
- `docs/17_SECURITY_HARDENING_GUIDE.md` – Security guardrails and enforcement deadlines.
|
||||
- `docs/modules/authority/operations/monitoring.md` – Authority-side monitoring and alerting playbook.
|
||||
- `StellaOps.Concelier.WebService/Filters/JobAuthorizationAuditFilter.cs` – source of audit log fields.
|
||||
- `docs/21_INSTALL_GUIDE.md` - Authority configuration quick start.
|
||||
- `docs/17_SECURITY_HARDENING_GUIDE.md` - Security guardrails and enforcement.
|
||||
- `docs/modules/authority/operations/monitoring.md` - Authority-side monitoring and alerting playbook.
|
||||
- `src/Concelier/StellaOps.Concelier.WebService/Filters/JobAuthorizationAuditFilter.cs` - Source of audit log fields.
|
||||
|
||||
@@ -45,7 +45,7 @@ Expect all logs at `Information`. Ensure OTEL exporters include the scope `Stell
|
||||
- `eventId=1002` with `reason="equal_rank"` - indicates precedence table gaps; page merge owners.
|
||||
- `eventId=1002` with `reason="mismatch"` - severity disagreement; open connector bug if sustained.
|
||||
3. **Job health**
|
||||
- `stellaops-cli db merge` exit code `1` signifies unresolved conflicts. Pipe to automation that captures logs and notifies #concelier-ops.
|
||||
- `stella db merge` exit code `1` signifies unresolved conflicts. Pipe to automation that captures logs and notifies #concelier-ops.
|
||||
|
||||
### Threshold updates (2025-10-12)
|
||||
|
||||
@@ -58,7 +58,7 @@ Expect all logs at `Information`. Ensure OTEL exporters include the scope `Stell
|
||||
## 4. Triage Workflow
|
||||
|
||||
1. **Confirm job context**
|
||||
- `stellaops-cli db merge` (CLI) or `POST /jobs/merge:reconcile` (API) to rehydrate the merge job. Use `--verbose` to stream structured logs during triage.
|
||||
- `stella db merge` (CLI) or `POST /jobs/merge:reconcile` (API) to rehydrate the merge job. Use `--verbose` to stream structured logs during triage.
|
||||
2. **Inspect metrics**
|
||||
- Correlate spikes in `concelier.merge.conflicts` with `primary_source`/`suppressed_source` tags from `concelier.merge.overrides`.
|
||||
3. **Pull structured logs**
|
||||
@@ -94,7 +94,7 @@ Expect all logs at `Information`. Ensure OTEL exporters include the scope `Stell
|
||||
## 6. Resolution Playbook
|
||||
|
||||
1. **Connector data fix**
|
||||
- Re-run the offending connector stages (`stellaops-cli db fetch --source ghsa --stage map` etc.).
|
||||
- Re-run the offending connector stages (`stella db fetch --source ghsa --stage map` etc.).
|
||||
- Once fixed, rerun merge and verify `decisionReason` reflects `freshness` or `precedence` as expected.
|
||||
2. **Temporary precedence override**
|
||||
- Edit `etc/concelier.yaml`:
|
||||
|
||||
@@ -25,13 +25,13 @@ concelier:
|
||||
|
||||
## 2. Staging Smoke Test
|
||||
|
||||
1. Deploy the configuration and restart the Concelier workers to ensure the Apple connector options are bound.
|
||||
2. Trigger a full connector cycle:
|
||||
- CLI: `stella db jobs run source:vndr-apple:fetch --and-then source:vndr-apple:parse --and-then source:vndr-apple:map`
|
||||
- REST: `POST /jobs/run { "kind": "source:vndr-apple:fetch", "chain": ["source:vndr-apple:parse", "source:vndr-apple:map"] }`
|
||||
3. Validate metrics exported under meter `StellaOps.Concelier.Connector.Vndr.Apple`:
|
||||
- `apple.fetch.items` (documents fetched)
|
||||
- `apple.fetch.failures`
|
||||
1. Deploy the configuration and restart the Concelier workers to ensure the Apple connector options are bound.
|
||||
2. Trigger a full connector cycle:
|
||||
- CLI: run `stella db fetch --source vndr-apple --stage fetch`, then `--stage parse`, then `--stage map`.
|
||||
- REST: `POST /jobs/run { "kind": "source:vndr-apple:fetch", "chain": ["source:vndr-apple:parse", "source:vndr-apple:map"] }`
|
||||
3. Validate metrics exported under meter `StellaOps.Concelier.Connector.Vndr.Apple`:
|
||||
- `apple.fetch.items` (documents fetched)
|
||||
- `apple.fetch.failures`
|
||||
- `apple.fetch.unchanged`
|
||||
- `apple.parse.failures`
|
||||
- `apple.map.affected.count` (histogram of affected package counts)
|
||||
|
||||
@@ -53,7 +53,7 @@ Suggested Grafana alerts:
|
||||
2. **Stage ingestion**:
|
||||
- Temporarily raise `maxEntriesPerFetch` (e.g. 500) and restart Concelier workers.
|
||||
- Run chained jobs until `pendingDocuments` drains:
|
||||
`stella db jobs run source:cccs:fetch --and-then source:cccs:parse --and-then source:cccs:map`
|
||||
Run `stella db fetch --source cccs --stage fetch`, then `--stage parse`, then `--stage map`.
|
||||
- Monitor `cccs.fetch.unchanged` growth; once it approaches dataset size the backfill is complete.
|
||||
3. **Optional pagination sweep** – for incremental mirrors, iterate `page=<n>` (0…N) while `response.Count == 50`, persisting JSON to disk. Store alongside metadata (`language`, `page`, SHA256) so repeated runs detect drift.
|
||||
4. **Language split** – keep EN/FR payloads separate to preserve canonical language fields. The connector emits `Language` directly from the feed entry, so mixed ingestion simply produces parallel advisories keyed by the same serial number.
|
||||
|
||||
@@ -124,7 +124,7 @@ operating offline.
|
||||
### 3.4 Connector-driven catch-up
|
||||
|
||||
1. Temporarily raise `maxAdvisoriesPerFetch` (e.g. 150) and reduce `requestDelay`.
|
||||
2. Run `stella db jobs run source:cert-bund:fetch --and-then source:cert-bund:parse --and-then source:cert-bund:map` until the fetch log reports `enqueued=0`.
|
||||
2. Run `stella db fetch --source cert-bund --stage fetch`, then `--stage parse`, then `--stage map` until the fetch log reports `enqueued=0`.
|
||||
3. Restore defaults and capture the cursor snapshot for audit.
|
||||
|
||||
---
|
||||
|
||||
@@ -33,7 +33,7 @@ This runbook describes how Ops provisions, rotates, and distributes Cisco PSIRT
|
||||
- Update `concelier:sources:cisco:auth` (or the module-specific secret template) with the stored credentials.
|
||||
- For Offline Kit delivery, export encrypted secrets into `offline-kit/secrets/cisco-openvuln.json` using the platform’s sealed secret format.
|
||||
4. **Connectivity validation**
|
||||
- From the Concelier control plane, run `stella db jobs run source:vndr-cisco:fetch --dry-run`.
|
||||
- From the Concelier control plane, run `stella db fetch --source vndr-cisco --stage fetch` (use staging or a controlled window).
|
||||
- Ensure the Source HTTP diagnostics record `Bearer` authorization headers and no 401/403 responses.
|
||||
|
||||
## 4. Rotation SOP
|
||||
|
||||
@@ -34,7 +34,7 @@ concelier:
|
||||
|
||||
1. Deploy the updated configuration and restart the Concelier service so the connector picks up the credentials.
|
||||
2. Trigger one end-to-end cycle:
|
||||
- Concelier CLI: `stella db jobs run source:cve:fetch --and-then source:cve:parse --and-then source:cve:map`
|
||||
- Concelier CLI: run `stella db fetch --source cve --stage fetch`, then `--stage parse`, then `--stage map`.
|
||||
- REST fallback: `POST /jobs/run { "kind": "source:cve:fetch", "chain": ["source:cve:parse", "source:cve:map"] }`
|
||||
3. Observe the following metrics (exported via OTEL meter `StellaOps.Concelier.Connector.Cve`):
|
||||
- `cve.fetch.attempts`, `cve.fetch.success`, `cve.fetch.documents`, `cve.fetch.failures`, `cve.fetch.unchanged`
|
||||
@@ -107,7 +107,7 @@ Treat repeated schema failures or growing anomaly counts as an upstream regressi
|
||||
|
||||
1. Deploy the configuration and restart Concelier.
|
||||
2. Trigger a pipeline run:
|
||||
- CLI: `stella db jobs run source:kev:fetch --and-then source:kev:parse --and-then source:kev:map`
|
||||
- CLI: run `stella db fetch --source kev --stage fetch`, then `--stage parse`, then `--stage map`.
|
||||
- REST: `POST /jobs/run { "kind": "source:kev:fetch", "chain": ["source:kev:parse", "source:kev:map"] }`
|
||||
3. Verify the metrics exposed by meter `StellaOps.Concelier.Connector.Kev`:
|
||||
- `kev.fetch.attempts`, `kev.fetch.success`, `kev.fetch.unchanged`, `kev.fetch.failures`
|
||||
|
||||
@@ -24,7 +24,7 @@ concelier:
|
||||
|
||||
1. Restart Concelier workers after configuration changes.
|
||||
2. Trigger a full cycle:
|
||||
- CLI: `stella db jobs run source:epss:fetch --and-then source:epss:parse --and-then source:epss:map`
|
||||
- CLI: run `stella db fetch --source epss --stage fetch`, then `--stage parse`, then `--stage map`.
|
||||
- REST: `POST /jobs/run { "kind": "source:epss:fetch", "chain": ["source:epss:parse", "source:epss:map"] }`
|
||||
3. Verify document status transitions: `pending_parse` -> `pending_map` -> `mapped`.
|
||||
4. Confirm log entries for `Fetched EPSS snapshot` and parse/map summaries.
|
||||
|
||||
@@ -79,7 +79,7 @@ If credentials are still pending, populate the connector with the community CSV
|
||||
```bash
|
||||
CONCELIER_SOURCES_ICSCISA_GOVDELIVERY_CODE=... \
|
||||
CONCELIER_SOURCES_ICSCISA_ENABLEDETAILSCRAPE=1 \
|
||||
stella db jobs run source:ics-cisa:fetch --and-then source:ics-cisa:parse --and-then source:ics-cisa:map
|
||||
Run `stella db fetch --source ics-cisa --stage fetch`, then `--stage parse`, then `--stage map`.
|
||||
```
|
||||
3. Confirm logs contain `ics-cisa detail fetch` entries and that new documents/DTOs include attachments (see `docs/artifacts/icscisa`). Canonical advisories should expose PDF links as `references.kind == "attachment"` and affected packages should surface `primitives.semVer.exactValue` for single-version hits.
|
||||
4. If Akamai blocks direct fetches, set `concelier:sources:icscisa:proxyUri` to your allow-listed egress proxy and rerun the dry-run.
|
||||
|
||||
@@ -25,7 +25,7 @@ concelier:
|
||||
|
||||
1. Restart the Concelier workers so the KISA options bind.
|
||||
2. Run a full connector cycle:
|
||||
- CLI: `stella db jobs run source:kisa:fetch --and-then source:kisa:parse --and-then source:kisa:map`
|
||||
- CLI: run `stella db fetch --source kisa --stage fetch`, then `--stage parse`, then `--stage map`.
|
||||
- REST: `POST /jobs/run { "kind": "source:kisa:fetch", "chain": ["source:kisa:parse", "source:kisa:map"] }`
|
||||
3. Confirm telemetry (Meter `StellaOps.Concelier.Connector.Kisa`):
|
||||
- `kisa.feed.success`, `kisa.feed.items`
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
# Concelier AirGap Prep — PREP-CONCELIER-AIRGAP-56-001-58-001
|
||||
|
||||
Status: **Ready for implementation** (2025-11-20)
|
||||
Owners: Concelier Core · AirGap Guilds
|
||||
Scope: Chain mirror thin-bundle milestone with EvidenceLocker bundle references and console consumption to unblock air-gapped Concelier workflows (56-001..58-001).
|
||||
|
||||
## Inputs
|
||||
- Mirror milestone-0 thin bundle: `out/mirror/thin/mirror-thin-m0-sample.tar.gz` (hash documented in PREP-ART-56-001).
|
||||
- Evidence bundle v1 contract: `docs/modules/evidence-locker/evidence-bundle-v1.md`.
|
||||
- Console fixtures (29-001, 30-001) and LNM schema freeze.
|
||||
|
||||
## Deliverables
|
||||
- Publish mapping note `docs/modules/concelier/prep/airgap-56-001-58-001-mapping.md` covering:
|
||||
- Bundle locations/hashes (thin + evidence).
|
||||
- Import commands for Concelier offline controller.
|
||||
- Deterministic ordering and retention expectations.
|
||||
- Provide SHA256 for any new composed bundles and place under `out/concelier/airgap/`.
|
||||
|
||||
## Acceptance criteria
|
||||
- Mapping note published with hashes and import commands.
|
||||
- No unresolved schema decisions remain for air-gap import chain.
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
# Concelier Attestation Prep — PREP-CONCELIER-ATTEST-73-001-002
|
||||
|
||||
Status: **Ready for implementation** (2025-11-20)
|
||||
Owners: Concelier Core · Evidence Locker Guild
|
||||
Scope: Evidence Locker attestation scope integration for Concelier attest tasks 73-001/002.
|
||||
|
||||
## Requirements
|
||||
- Use Evidence Locker attestation scope note: `docs/modules/evidence-locker/attestation-scope-note.md`.
|
||||
- Bind Evidence Bundle v1 contract: `docs/modules/evidence-locker/evidence-bundle-v1.md`.
|
||||
|
||||
## Deliverables
|
||||
- Concelier-specific attestation ingest note at `docs/modules/concelier/prep/attest-73-001-ingest.md` describing required claims, DSSE expectations, and lookup flow.
|
||||
- Hashes for sample attest bundles reused from Evidence Locker sample; no new artefacts needed.
|
||||
|
||||
## Acceptance criteria
|
||||
- Ingest note published with claim set and DSSE requirements; Concelier tasks can proceed without further schema questions.
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
# Concelier Console Prep — PREP-CONCELIER-CONSOLE-23-001-003
|
||||
|
||||
Status: **Ready for implementation** (2025-11-20)
|
||||
Owners: Concelier Console Guild
|
||||
Scope: Console schema samples and evidence bundle references for console consumption of linkset/VEX data (23-001..003).
|
||||
|
||||
## Deliverables
|
||||
- JSON samples placed under `docs/samples/console/`:
|
||||
- `console-linkset-search.json` (frozen LNM schema, includes pagination + filters).
|
||||
- `console-vex-search.json` (VEX linkset search with exploitability flags).
|
||||
- Hashes `.sha256` for each sample.
|
||||
- README snippet added to `docs/samples/console/README.md` describing schema version, seed (`2025-01-01T00:00:00Z`), and deterministic ordering.
|
||||
|
||||
## Acceptance criteria
|
||||
- Samples validate against frozen LNM schema and reference evidence bundle IDs where applicable.
|
||||
- Hashes recorded; no external dependencies.
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
# Concelier Feed Prep — PREP-FEEDCONN-ICSCISA-02-012-KISA-02-008-FEED
|
||||
|
||||
Status: **Ready for implementation** (2025-11-20)
|
||||
Owners: Concelier Feed Owners
|
||||
Scope: Remediation plan and schema notes for ICSCISA/KISA feeds to unblock connector work.
|
||||
|
||||
## Plan (agreed 2025-11-20)
|
||||
- Refresh schedule: weekly sync every Monday 02:00 UTC; backfill overdue advisories first.
|
||||
- Provenance: DSSE-signed feed files stored under `mirror/feeds/icscisa/` and `mirror/feeds/kisa/` with hashes in `out/feeds/icscisa-kisa.sha256`.
|
||||
- Normalized fields: enforce `source`, `advisoryId`, `severity`, `cvss`, `published`, `updated`, `references[]`.
|
||||
- Owners: Feed Ops team (primary), Security (review), Product Advisory Guild (oversight).
|
||||
|
||||
## Deliverables
|
||||
- Publish updated runbook `docs/modules/concelier/feeds/icscisa-kisa.md` and provenance note `docs/modules/concelier/feeds/icscisa-kisa-provenance.md` (already exist; confirm hashes and schedule lines).
|
||||
- Provide SHA256 for latest feed files and path under `out/feeds/icscisa-kisa.sha256`.
|
||||
|
||||
## Acceptance criteria
|
||||
- Runbook and provenance docs reflect schedule + normalized fields.
|
||||
- Hash file published for latest feed drop; connector work unblocked.
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
# Concelier · Orchestrator Registry & Control Prep
|
||||
|
||||
- **Date:** 2025-11-20
|
||||
- **Scope:** PREP-CONCELIER-ORCH-32-001, PREP-CONCELIER-ORCH-32-002, PREP-CONCELIER-ORCH-33-001, PREP-CONCELIER-ORCH-34-001
|
||||
- **Working directory:** `src/Concelier/**` (WebService, Core, Storage.Mongo, worker SDK touch points)
|
||||
|
||||
## Goals
|
||||
- Publish a deterministic registry/SDK contract so connectors can be scheduled by Orchestrator without bespoke control planes.
|
||||
- Define heartbeats/progress envelopes and pause/throttle/backfill semantics ahead of worker wiring.
|
||||
- Describe replay/backfill evidence outputs so ledger/export work can rely on stable hashes.
|
||||
|
||||
## Registry record (authoritative fields)
|
||||
All registry documents live under the orchestrator collection keyed by `connectorId` (stable slug). Fields and invariants:
|
||||
- `connectorId` (string, slug, lowercase) — unique per tenant + source; immutable.
|
||||
- `tenant` (string) — required; enforced by WebService tenant guard.
|
||||
- `source` (enum) — advisory provider (`nvd`, `ghsa`, `osv`, `icscisa`, `kisa`, `vendor:<slug>`).
|
||||
- `capabilities` (array) — `observations`, `linksets`, `timeline`, `attestations` flags; no merge/derived data.
|
||||
- `authRef` (string) — reference to secrets store key; never inlined.
|
||||
- `schedule` (object) — `cron`, `timeZone`, `maxParallelRuns`, `maxLagMinutes`.
|
||||
- `ratePolicy` (object) — `rpm`, `burst`, `cooldownSeconds`; default deny if absent.
|
||||
- `artifactKinds` (array) — `raw-advisory`, `normalized`, `linkset`, `timeline`, `attestation`.
|
||||
- `lockKey` (string) — deterministic lock namespace (`concelier:{tenant}:{connectorId}`) for single-flight.
|
||||
- `egressGuard` (object) — `allowlist` of hosts + `airgapMode` boolean; fail closed when `airgapMode=true` and host not allowlisted.
|
||||
- `createdAt` / `updatedAt` (ISO-8601 UTC) — monotonic; updates require optimistic concurrency token.
|
||||
|
||||
### Registry sample (non-normative)
|
||||
```json
|
||||
{
|
||||
"connectorId": "icscisa",
|
||||
"tenant": "acme",
|
||||
"source": "icscisa",
|
||||
"capabilities": ["observations", "linksets", "timeline"],
|
||||
"authRef": "secret:concelier/icscisa/api-key",
|
||||
"schedule": {"cron": "*/30 * * * *", "timeZone": "UTC", "maxParallelRuns": 1, "maxLagMinutes": 120},
|
||||
"ratePolicy": {"rpm": 60, "burst": 10, "cooldownSeconds": 30},
|
||||
"artifactKinds": ["raw-advisory", "normalized", "linkset"],
|
||||
"lockKey": "concelier:acme:icscisa",
|
||||
"egressGuard": {"allowlist": ["icscert.kisa.or.kr"], "airgapMode": true},
|
||||
"createdAt": "2025-11-20T00:00:00Z",
|
||||
"updatedAt": "2025-11-20T00:00:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
## Control/SDK contract (heartbeats + commands)
|
||||
- Heartbeat endpoint `POST /internal/orch/heartbeat` (auth: internal orchestrator role, tenant-scoped).
|
||||
- Body: `connectorId`, `runId` (GUID), `status` (`starting|running|paused|throttled|backfill|failed|succeeded`),
|
||||
`progress` (0–100), `queueDepth`, `lastArtifactHash`, `lastArtifactKind`, `errorCode`, `retryAfterSeconds`.
|
||||
- Idempotency key: `runId` + `sequence` to preserve ordering; orchestrator ignores stale sequence.
|
||||
- Control queue document (persisted per run):
|
||||
- Commands: `pause`, `resume`, `throttle` (rpm/burst override until `expiresAt`), `backfill` (range: `fromCursor`/`toCursor`).
|
||||
- Workers poll `/internal/orch/commands?connectorId={id}&runId={runId}`; must ack with monotonic `ackSequence` to ensure replay safety.
|
||||
- Failure semantics: on `failed`, worker emits `errorCode`, `errorReason`, `lastCheckpoint` (cursor/hash). Orchestrator may re-enqueue with backoff.
|
||||
|
||||
## Backfill/replay expectations
|
||||
- Backfill command requires deterministic cursor space (e.g., advisory sequence number or RFC3339 timestamp truncated to minutes).
|
||||
- Worker must emit a `runManifest` per backfill containing: `runId`, `connectorId`, `tenant`, `cursorRange`, `artifactHashes[]`, `dsseEnvelopeHash` (if attested), `completedAt`.
|
||||
- Manifests are written to Evidence Locker ledger for replay; filenames: `backfill/{tenant}/{connectorId}/{runId}.ndjson` with stable ordering.
|
||||
|
||||
## Telemetry (to implement in WebService + worker SDK)
|
||||
- Meter name prefix: `StellaOps.Concelier.Orch`.
|
||||
- Counters:
|
||||
- `concelier.orch.heartbeat` tags: `tenant`, `connectorId`, `status`.
|
||||
- `concelier.orch.command.applied` tags: `tenant`, `connectorId`, `command`.
|
||||
- Histograms:
|
||||
- `concelier.orch.lag.minutes` (now - cursor upper bound) tags: `tenant`, `connectorId`.
|
||||
- Logs: structured with `tenant`, `connectorId`, `runId`, `command`, `sequence`, `ackSequence`.
|
||||
|
||||
## Acceptance criteria for prep completion
|
||||
- Registry/command schema above is frozen and referenced from Sprint 0114 Delivery Tracker (P10–P13) so downstream implementation knows shapes.
|
||||
- Sample manifest path + naming are defined for ledger/replay flows.
|
||||
- Meter names/tags enumerated for observability wiring.
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
# Concelier PREP Notes — 2025-11-20
|
||||
|
||||
Owner: Concelier Core Guild · Scheduler Guild · Data Science Guild
|
||||
Scope: Provide traceable prep outputs for PREP-CONCELIER-GRAPH-21-002-PLATFORM-EVENTS-S and PREP-CONCELIER-LNM-21-002-WAITING-ON-FINALIZE so downstream tasks can proceed without blocking on missing contracts.
|
||||
|
||||
## 1) `sbom.observation.updated` platform event (Graph-21-002)
|
||||
- Goal: publish deterministic, facts-only observation updates for graph overlays; no derived judgments.
|
||||
- Proposed envelope (draft for Scheduler/Platform Events review):
|
||||
- `event_type`: `sbom.observation.updated`
|
||||
- `tenant_id` (string, required)
|
||||
- `advisory_ids` (array of strings; upstream IDs as-ingested)
|
||||
- `observation_ids` (array of stable per-observation IDs emitted by LNM storage)
|
||||
- `source` (string; advisory source slug)
|
||||
- `version_range` (string; original upstream semantics)
|
||||
- `occurred_at` (ISO-8601 UTC, produced by Concelier at write time; deterministic)
|
||||
- `trace` (object; optional provenance pointers, DSSE envelope digest with alg/id fields)
|
||||
- Delivery and wiring expectations:
|
||||
- Publisher lives in `StellaOps.Concelier.Core` after linkset/observation persistence.
|
||||
- Scheduler binding: NATS/Redis topic `concelier.sbom.observation.updated`; ack + idempotent replay friendly; max delivery once semantics via message ID = `<tenant>:<observation_id>::<digest>`.
|
||||
- Telemetry: counter `concelier_events_observation_updated_total{tenant,source,result}`; log template includes `tenant`, `advisory_id`, `observation_id`, `event_id`.
|
||||
- Offline posture: allow emitting into local bus, enqueue to file-backed spool when offline; retry with deterministic ordering by `(tenant, observation_id)`.
|
||||
- Open questions to resolve in impl task:
|
||||
- Final topic naming and DSSE requirement (optional vs required per deployment).
|
||||
- Whether to include component alias list in the event payload or expect consumers to join via API.
|
||||
|
||||
## 2) LNM fixtures + precedence markers (LNM-21-002)
|
||||
- Goal: unblock correlation pipelines and downstream linkset tasks by defining required fixture shape and precedence rules.
|
||||
- Fixture requirements (additive to frozen LNM v1 schema):
|
||||
- Provide at least three sources with conflicting severity/CVSS to exercise conflict markers.
|
||||
- Include overlapping version ranges to validate precedence tie-breakers.
|
||||
- Each fixture must include `provenance` (source, fetch_time, collector) and `confidence` hints.
|
||||
- Precedence rule proposal for review:
|
||||
1. Prefer explicit source ranking table (to be agreed) over recency.
|
||||
2. If ranking ties, prefer narrower version ranges, then higher confidence, then stable lexical order of `(source, advisory_id)`.
|
||||
3. Never collapse conflicting fields; emit `conflicts[]` entries with reason codes `severity-disagree`, `cvss-disagree`, `reference-disagree`.
|
||||
- Delivery path for fixtures once agreed: `src/Concelier/seed-data/lnm/v1/fixtures/*.json` with deterministic ordering; wire into `StellaOps.Concelier.Core.Tests` harness.
|
||||
- Next actions captured for implementation task:
|
||||
- Confirm ranking table and conflict reason code list with Cartographer/Data Science.
|
||||
- Drop initial fixtures into the above path and reference them from the implementation tasks’ tests.
|
||||
|
||||
## Handoff
|
||||
- This document is the published prep artefact requested by PREP-CONCELIER-GRAPH-21-002-PLATFORM-EVENTS-S and PREP-CONCELIER-LNM-21-002-WAITING-ON-FINALIZE. Downstream tasks should cite this file until the final schemas/fixtures are merged.
|
||||
@@ -1,37 +0,0 @@
|
||||
# Concelier · Policy Engine Linkset API Prep
|
||||
|
||||
- **Date:** 2025-11-20
|
||||
- **Scope:** PREP-CONCELIER-POLICY-20-001 (LNM APIs not exposed via OpenAPI)
|
||||
- **Working directory:** `src/Concelier/StellaOps.Concelier.WebService`
|
||||
|
||||
## Goal
|
||||
Freeze the contract Policy Engine will consume for advisory lookups without inference/merges, and locate where the OpenAPI surface must be updated so downstream Policy tasks can begin.
|
||||
|
||||
## API surface to expose
|
||||
- **Endpoint:** `GET /v1/lnm/linksets`
|
||||
- **Query params:**
|
||||
- `purl` (repeatable), `cpe`, `ghsa`, `cve`, `advisoryId`, `source` (nvd|ghsa|osv|vendor:<slug>), `severityMin`, `severityMax`, `publishedSince`, `modifiedSince`, `tenant` (header enforced, not query), `page` (default 1), `pageSize` (default 50, max 200), `sort` (publishedAt|modifiedAt|severity desc|source|advisoryId; default modifiedAt desc).
|
||||
- **Response:** deterministic ordering; body fields = `advisoryId`, `source`, `purl[]`, `cpe[]`, `summary`, `publishedAt`, `modifiedAt`, `severity` (source-native), `status` (facts only), `provenance` (`ingestedAt`, `connectorId`, `evidenceHash`, `dsseEnvelopeHash?`), `conflicts[]` (raw disagreements, no merged verdicts), `timeline[]` (raw timestamps + hashes), `remarks[]` (human notes, optional).
|
||||
- **Endpoint:** `GET /v1/lnm/linksets/{advisoryId}`
|
||||
- Mirrors above fields; adds `normalized` block for any canonicalized IDs; `cached` flag already added in Sprint 110.B endpoint work.
|
||||
- **Endpoint:** `POST /v1/lnm/linksets/search`
|
||||
- Accepts body with same filters as query params plus boolean `includeTimeline`, `includeObservations` (default false). Must respect tenant guard and AOC (no inferred verdicts or merges).
|
||||
|
||||
## OpenAPI tasks
|
||||
- Source file location: `src/Concelier/StellaOps.Concelier.WebService/openapi/concelier-lnm.yaml` (to be created / updated alongside code) and published copy under `docs/api/concelier/`.
|
||||
- Add components:
|
||||
- `LinksetProvenance` object (ingestedAt, connectorId, evidenceHash, dsseEnvelopeHash?).
|
||||
- `LinksetConflict` object (source, field, observedValue, observedAt, evidenceHash).
|
||||
- `LinksetTimeline` object (event, at, evidenceHash, dsseEnvelopeHash?).
|
||||
- Pagination envelope: `{ "items": [...], "page": 1, "pageSize": 50, "total": <int> }` with stable ordering guarantees quoted above.
|
||||
- Security: `Tenant` header required; bearer/mtls unchanged from existing WebService.
|
||||
|
||||
## Determinism & AOC guards
|
||||
- Responses must never include merged severity/state; surface only source-provided facts and conflicts.
|
||||
- Sorting: primary `modifiedAt desc`, tie-breaker `advisoryId asc`, then `source asc` for deterministic pagination.
|
||||
- Cache: the `/linksets/{advisoryId}` endpoint may serve cached entries but must include `cached: true|false` and `provenance.evidenceHash` so Policy Engine can verify integrity.
|
||||
|
||||
## Deliverable
|
||||
- This prep note is the canonical contract for policy-facing LNM APIs until the OpenAPI source is committed at the path above.
|
||||
- Downstream tasks (POLICY-ENGINE-20-001 and linked Policy Engine sprints) should bind to these fields; any deviations must update this prep note and the sprint’s Decisions & Risks.
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
# Concelier Web AirGap Prep — PREP-CONCELIER-WEB-AIRGAP-57-001
|
||||
|
||||
Status: Draft (2025-11-20)
|
||||
Owners: Concelier WebService Guild · AirGap Policy Guild
|
||||
Scope: Define remediation payloads and staleness plumbing for sealed-mode violations, dependent on WEB-AIRGAP-56-002.
|
||||
|
||||
## Dependencies
|
||||
- WEB-AIRGAP-56-001: mirror bundle registration + sealed-mode enforcement.
|
||||
- WEB-AIRGAP-56-002: staleness + bundle provenance metadata surfaces.
|
||||
- AirGap controller scopes (seal/unseal) and time anchor semantics from AirGap Controller/Time guilds.
|
||||
|
||||
## Proposed payload mapping (EGRESS blocked)
|
||||
- Error code: `AIRGAP_EGRESS_BLOCKED`.
|
||||
- Shape:
|
||||
```json
|
||||
{
|
||||
"error": "AIRGAP_EGRESS_BLOCKED",
|
||||
"message": "Direct internet fetches disabled in sealed mode; use mirror bundle sources only.",
|
||||
"bundle_required": true,
|
||||
"staleness_seconds": 0,
|
||||
"remediation": [
|
||||
"Import mirror bundle via /airgap/import or offline kit",
|
||||
"Ensure sealed mode is set with valid time anchor",
|
||||
"Retry with cached/mirrored sources enabled"
|
||||
]
|
||||
}
|
||||
```
|
||||
- Determinism: fixed ordering of fields, remediation list sorted.
|
||||
|
||||
## Staleness surfacing
|
||||
- Staleness derived from bundle metadata supplied by 56-002 (`bundle_id`, `provenance`, `staleness_budget_seconds`).
|
||||
- Responses include `staleness_seconds_remaining` and `bundle_id` when available.
|
||||
|
||||
## Observability
|
||||
- Emit timeline event `concelier.airgap.egress_blocked` with `{tenant_id, bundle_id?, endpoint, request_id}`.
|
||||
- Metric: `concelier_airgap_egress_blocked_total` (counter) tagged by endpoint.
|
||||
|
||||
## Open decisions
|
||||
- Final error envelope format (depends on WEB-OAS-61-002 standard envelope).
|
||||
- Exact header name for staleness metadata (suggest `x-concelier-bundle-staleness`).
|
||||
- Whether to include advisory key/linkset ids in the blocked response.
|
||||
|
||||
## Handoff
|
||||
Use this as the PREP artefact for WEB-AIRGAP-57-001. Update once 56-002 and error envelope standard are finalized.
|
||||
@@ -1,29 +0,0 @@
|
||||
# Concelier OAS & Observability Prep (61-001..63-001, 51-001..55-001)
|
||||
|
||||
Status: **Ready for implementation** (2025-11-22)
|
||||
Owners: Concelier Core Guild · API Contracts Guild · DevOps/Observability Guilds
|
||||
Scope: Freeze the API/SDK contracts and observability envelopes for LNM search/timeline APIs so downstream SDK, governance, and incident flows can proceed without schema churn.
|
||||
|
||||
## Inputs
|
||||
- Frozen LNM payload schema: `docs/modules/concelier/link-not-merge-schema.md` (2025-11-17).
|
||||
- Event contract: `docs/modules/concelier/events/advisory.observation.updated@1.md`.
|
||||
- Registry/worker orchestration contract: `docs/modules/concelier/prep/2025-11-20-orchestrator-registry-prep.md`.
|
||||
|
||||
## Deliverables
|
||||
- OpenAPI source stub for LNM + timeline surfaces recorded at `docs/modules/concelier/openapi/lnm-api.yaml` (paths enumerated; examples outlined below).
|
||||
- SDK example library checklist covering `searchAdvisories`, `searchLinksets`, `getTimeline`, `getObservationById`; response bodies aligned to frozen schema; no consensus/merge fields.
|
||||
- Observability contract (metrics/logs/traces):
|
||||
- Metrics: `concelier_ingest_latency_seconds`, `concelier_linkset_conflicts_total`, `concelier_timeline_emit_lag_seconds`, `concelier_api_requests_total{route,tenant,status}` with burn-rate alert examples.
|
||||
- Logs: structured fields `tenantId`, `advisoryKey`, `linksetId`, `timelineCursor`, `egressPolicy`.
|
||||
- Traces: span names for `lnm.search`, `lnm.timeline`, `lnm.linkset-resolve` with baggage keys `tenant-id`, `request-id`.
|
||||
- Incident/observability hooks: timeline/attestation enrichment notes for OBS-54/55 including DSSE envelope hash field and sealed-mode redaction rules.
|
||||
|
||||
## Acceptance Criteria
|
||||
- Request/response shapes for `/api/v1/lnm/advisories`, `/api/v1/lnm/linksets`, `/api/v1/lnm/timeline` documented with required query params (`tenantId`, `productKey`, `offset`, `limit`, `sort`, `includeTimeline=true|false`).
|
||||
- All responses MUST include `provenance` block (source, fetchedAt, digest, evidenceBundleId) and forbid consensus/merge fields.
|
||||
- Metrics/logs names and labels are deterministic and lowercase; alert examples reference burn-rate SLOs.
|
||||
- File path above is referenced from sprint trackers; any future schema edits require bumping version/comment in this prep doc.
|
||||
|
||||
## Notes
|
||||
- This prep satisfies PREP-CONCELIER-OAS-61-001/002/62-001/63-001 and PREP-CONCELIER-OBS-51-001/52-001/53-001/54-001/55-001.
|
||||
- No external dependencies remaining; downstream tasks may proceed using the stubbed OpenAPI and observability contracts here.
|
||||
@@ -1,82 +0,0 @@
|
||||
# Concelier Backfill & Rollback Plan (STORE-AOC-19-005-DEV, Postgres)
|
||||
|
||||
## Objective
|
||||
Prepare and rehearse the raw Link-Not-Merge backfill/rollback so Concelier Postgres reflects the dataset deterministically across dev/stage. This replaces the prior Mongo workflow.
|
||||
|
||||
## Inputs
|
||||
- Dataset tarball: `out/linksets/linksets-stage-backfill.tar.zst`
|
||||
- Files expected inside: `linksets.ndjson`, `advisory_chunks.ndjson`, `manifest.json`
|
||||
- Record SHA-256 of the tarball here when staged:
|
||||
```
|
||||
$ sha256sum out/linksets/linksets-stage-backfill.tar.zst
|
||||
2b43ef9b5694f59be8c1d513893c506b8d1b8de152d820937178070bfc00d0c0 out/linksets/linksets-stage-backfill.tar.zst
|
||||
```
|
||||
- To regenerate the tarball deterministically from repo seeds: `./scripts/concelier/build-store-aoc-19-005-dataset.sh`
|
||||
- To validate a tarball locally (counts + hashes): `./scripts/concelier/test-store-aoc-19-005-dataset.sh out/linksets/linksets-stage-backfill.tar.zst`
|
||||
|
||||
## Preflight
|
||||
- Env:
|
||||
- `PGURI` (or `CONCELIER_PG_URI`) pointing to the target Postgres instance.
|
||||
- `PGSCHEMA` (default `lnm_raw`) for staging tables.
|
||||
- Ensure maintenance window for bulk import; no concurrent writers to staging tables.
|
||||
|
||||
## Backfill steps (CI-ready)
|
||||
|
||||
### Preferred: CI/manual script
|
||||
- `scripts/concelier/backfill-store-aoc-19-005.sh /path/to/linksets-stage-backfill.tar.zst`
|
||||
- Env: `PGURI` (or `CONCELIER_PG_URI`), optional `PGSCHEMA` (default `lnm_raw`), optional `DRY_RUN=1` for extraction-only.
|
||||
- The script:
|
||||
- Extracts and validates required files.
|
||||
- Creates/clears staging tables (`<schema>.linksets_raw`, `<schema>.advisory_chunks_raw`).
|
||||
- Imports via `\copy` from TSV derived with `jq -rc '[._id, .] | @tsv'`.
|
||||
- Prints counts and echoes the manifest.
|
||||
|
||||
### Manual steps (fallback)
|
||||
1) Extract dataset:
|
||||
```
|
||||
mkdir -p out/linksets/extracted
|
||||
tar -xf out/linksets/linksets-stage-backfill.tar.zst -C out/linksets/extracted
|
||||
```
|
||||
2) Create/truncate staging tables and import:
|
||||
```
|
||||
psql "$PGURI" <<SQL
|
||||
create schema if not exists lnm_raw;
|
||||
create table if not exists lnm_raw.linksets_raw (id text primary key, raw jsonb not null);
|
||||
create table if not exists lnm_raw.advisory_chunks_raw (id text primary key, raw jsonb not null);
|
||||
truncate table lnm_raw.linksets_raw;
|
||||
truncate table lnm_raw.advisory_chunks_raw;
|
||||
\copy lnm_raw.linksets_raw (id, raw) from program 'jq -rc ''[._id, .] | @tsv'' out/linksets/extracted/linksets.ndjson' with (format csv, delimiter E'\\t', quote '\"', escape '\"');
|
||||
\copy lnm_raw.advisory_chunks_raw (id, raw) from program 'jq -rc ''[._id, .] | @tsv'' out/linksets/extracted/advisory_chunks.ndjson' with (format csv, delimiter E'\\t', quote '\"', escape '\"');
|
||||
SQL
|
||||
```
|
||||
3) Verify counts vs manifest:
|
||||
```
|
||||
jq '.' out/linksets/extracted/manifest.json
|
||||
psql -tA "$PGURI" -c "select 'linksets_raw='||count(*) from lnm_raw.linksets_raw;"
|
||||
psql -tA "$PGURI" -c "select 'advisory_chunks_raw='||count(*) from lnm_raw.advisory_chunks_raw;"
|
||||
```
|
||||
|
||||
## Rollback procedure
|
||||
- If validation fails: `truncate table lnm_raw.linksets_raw; truncate table lnm_raw.advisory_chunks_raw;` then rerun import.
|
||||
- Promotion to production tables should be gated by a separate migration/ETL step; keep staging isolated.
|
||||
|
||||
## Validation checklist
|
||||
- Tarball SHA-256 recorded above.
|
||||
- Counts align with `manifest.json`.
|
||||
- API smoke test (Postgres-backed): `dotnet test src/Concelier/StellaOps.Concelier.WebService.Tests --filter LinksetsEndpoint_SupportsCursorPagination` (against Postgres config).
|
||||
- Optional: compare sample rows between staging and expected downstream tables.
|
||||
|
||||
## Artefacts to record
|
||||
- Tarball SHA-256 and size.
|
||||
- `manifest.json` copy alongside tarball.
|
||||
- Import log (capture script output) and validation results.
|
||||
- Decision: maintenance window and rollback outcome.
|
||||
|
||||
## How to produce the tarball (export from Postgres)
|
||||
- Use `scripts/concelier/export-linksets-tarball.sh out/linksets/linksets-stage-backfill.tar.zst`.
|
||||
- Env: `PGURI` (or `CONCELIER_PG_URI`), optional `PGSCHEMA`, `LINKSETS_TABLE`, `CHUNKS_TABLE`.
|
||||
- The script exports `linksets` and `advisory_chunks` tables to NDJSON, generates `manifest.json`, builds the tarball, and prints the SHA-256.
|
||||
|
||||
## Owners
|
||||
- Concelier Storage Guild (Postgres)
|
||||
- AirGap/Backfill reviewers for sign-off
|
||||
@@ -1,26 +0,0 @@
|
||||
# Replay Delivery Coordination Prep — PREP-EVIDENCE-LOCKER-GUILD-REPLAY-DELIVERY-GU
|
||||
|
||||
Status: Draft (2025-11-20)
|
||||
Owners: Planning · Evidence Locker Guild · Replay Delivery Guild · CLI Guild
|
||||
Scope: Define minimum contract notes for replay delivery so EVID-REPLAY-187-001/002 and RUNBOOK-REPLAY-187-004 can move once schemas freeze.
|
||||
|
||||
## Ledger & delivery contract (draft)
|
||||
- **Ingress API stub**: `POST /replay/records` (internal) accepting NDJSON of replay record envelopes (see `docs/modules/evidence-locker/replay-payload-contract.md`).
|
||||
- **Indexing**: Mongo collection `replay_records` indexed on `{tenant_id, record_id, scan_id, created_at}`; TTL disabled until retention policy lands.
|
||||
- **Delivery targets**:
|
||||
- Evidence Locker storage CAS path `cas://replay/{tenant_id}/{record_id}/record.ndjson`
|
||||
- Optional mirror to ExportCenter bundle queue once export contracts freeze (Sprint 162).
|
||||
- **Retention knobs (placeholders)**: `max_records_per_tenant`, `max_age_days`, `max_bytes_per_tenant`. Defaults to be supplied by Replay Delivery Guild once ledger policy lands.
|
||||
|
||||
## Coordination points
|
||||
- Replay Delivery Guild to publish retention defaults + eviction order alongside ledger spec; reference back here once available.
|
||||
- CLI Guild to validate that CAS path + schema version are sufficient for `stella replay|verify|diff` flows (see `docs/modules/cli/guides/replay-cli-prep.md`).
|
||||
- Ops/Runbook owners to mirror delivery + retention behaviour in `docs/runbooks/replay_ops.md` when promoted.
|
||||
|
||||
## Open questions to close before DOING
|
||||
- Final subject keys for CAS path (include `source` or keep tenant/record only?).
|
||||
- Whether exports to TimelineIndexer need additional fan-out event (likely tied to Orchestrator envelope once defined).
|
||||
- Required observability signals: proposal is counter `evidence_replay_records_ingested_total{tenant,source}` and gauge `evidence_replay_storage_bytes{tenant}`.
|
||||
|
||||
## Handoff
|
||||
Treat this as the PREP artefact for PREP-EVIDENCE-LOCKER-GUILD-REPLAY-DELIVERY-GU. Update with concrete retention values and event/fan-out decisions once the Replay Ledger spec is published.
|
||||
@@ -1,29 +0,0 @@
|
||||
# Evidence Locker Schema Readiness Prep — PREP-EVIDENCE-LOCKER-GUILD-BLOCKED-SCHEMAS-NO
|
||||
|
||||
Status: Draft (2025-11-20)
|
||||
Owners: Planning · Evidence Locker Guild · AdvisoryAI Guild · Orchestrator/Notifications Guild
|
||||
Scope: Capture the exact signals still missing to unfreeze Evidence Locker replay/bundle schemas, so downstream implementation can proceed without ambiguity.
|
||||
|
||||
## Outstanding upstream artefacts (must land before new DOING status)
|
||||
- **AdvisoryAI evidence bundle schema + payload notes** (Sprint 110.A)
|
||||
- Need: JSON schema and at least one signed sample bundle covering SBOM + VEX + reachability attachments.
|
||||
- Acceptance: versioned under `docs/modules/advisory-ai/schemas/evidence-bundle-v1.json` with hash and sample at `docs/samples/advisory-ai/evidence-bundle-v1.json`.
|
||||
- **Orchestrator + Notifications capsule envelopes** (Sprint 150.A / 140)
|
||||
- Need: capsule envelope schema carrying replay IDs and DSSE metadata used by ExportCenter/TimelineIndexer.
|
||||
- Acceptance: schema at `docs/events/orchestrator-scanner-events.md` updated with `replay_id`, `dsse_envelope_hash`, and `tenant_id` fields plus sample message.
|
||||
- **Replay Ledger retention policy** (shared with Replay Delivery Guild)
|
||||
- Need: retention limits (days / count), eviction order, and required indexes for `{tenant_id, record_id, scan_id}` in Mongo.
|
||||
- Acceptance: recorded in `docs/replay/DETERMINISTIC_REPLAY.md` section 8 with deterministic eviction rules.
|
||||
|
||||
## Ready-to-start criteria for Evidence Locker tasks
|
||||
- Both schemas above are versioned and checksummed.
|
||||
- Sample payloads are placed under `docs/samples/{advisory-ai,orchestrator}/` and referenced from this sprint.
|
||||
- Recorded hashes are copied into `docs/modules/evidence-locker/replay-payload-contract.md` (section 5 once available).
|
||||
|
||||
## Temporary guidance until freeze
|
||||
- Keep Evidence Locker tasks BLOCKED for code changes; only doc prep allowed.
|
||||
- Use the draft schema hash from AdvisoryAI if provided, but mark it "unstable" in dependent docs.
|
||||
- Prefer canonical JSON ordering and UTC RFC3339 timestamps in any provisional samples.
|
||||
|
||||
## Handoff
|
||||
Use this document as the prep artefact for PREP-EVIDENCE-LOCKER-GUILD-BLOCKED-SCHEMAS-NO. Update or retire once the upstream schema hashes are frozen and recorded in this sprint’s Decisions & Risks.
|
||||
@@ -1,25 +0,0 @@
|
||||
# Security & Evidence Coordination Prep — PREP-EVIDENCE-LOCKER-GUILD-SECURITY-GUILD-DOC
|
||||
|
||||
Status: Draft (2025-11-20)
|
||||
Owners: Evidence Locker Guild · Security Guild · Docs Guild · Exporter Service Guild · Mirror Creator Guild · DevOps Guild · Timeline Indexer Guild
|
||||
Scope: Enumerate security-critical deliverables that must be frozen before EvidenceLocker/ExportCenter/TimelineIndexer move to DOING.
|
||||
|
||||
## Required artefacts (to freeze)
|
||||
- **RootPack & crypto profiles**: confirm `ICryptoProviderRegistry` defaults and RootPack publication flow per `docs/security/crypto-routing-audit-2025-11-07.md`; publish profile matrix for FIPS/eIDAS/GOST.
|
||||
- **Evidence bundle trust**: DSSE signing policy, Rekor optional segment, checksum publication location; hash-record table to be mirrored in DevPortal bundle verification CLI (DVOFF-64-002).
|
||||
- **Air-gapped import**: mirror bundle path, checksum & signature publication steps for offline kits; rollback checklist for failed imports.
|
||||
- **Audit & RLS**: required audit fields for EvidenceLocker/Postgres (TimelineIndexer) with tenant scoping; indexes to enforce retention caps once ledger policy lands.
|
||||
|
||||
## Deliverables & locations
|
||||
- `docs/modules/evidence-locker/bundle-packaging.md` — add DSSE + checksum publication matrix (owner: Evidence Locker Guild).
|
||||
- `docs/modules/export-center/profiles.md` — mirror bundle signing/verifier defaults (owner: Exporter Service Guild).
|
||||
- `docs/modules/timelineindexer/architecture.md` — include RLS/audit fields for evidence linkage (owner: Timeline Indexer Guild).
|
||||
- `docs/security/crypto-registry-decision-2025-11-18.md` — referenced as normative source for crypto provider defaults.
|
||||
|
||||
## Ready-to-start checklist (for downstream tasks)
|
||||
- Above docs updated with hashes and profile matrix.
|
||||
- Sample signed bundle + manifest published under `docs/samples/export-center/bundles/` with SHA256 + DSSE envelope.
|
||||
- TimelineIndexer RLS/audit fields reviewed by Security.
|
||||
|
||||
## Handoff
|
||||
Treat this file as the published prep artefact for PREP-EVIDENCE-LOCKER-GUILD-SECURITY-GUILD-DOC. Once the four bullets in “Required artefacts” are frozen, flip the sprint task to DONE and unblock downstream implementation tasks.
|
||||
@@ -1,23 +0,0 @@
|
||||
# Evidence Locker sealed bundle contract · 2025-11-24
|
||||
|
||||
Owners: Evidence Locker Guild · Security Guild
|
||||
Status: Published 2025-11-24 (source for ELOCKER-CONTRACT-2001)
|
||||
|
||||
## Deliverables
|
||||
- Bundle schema: `bundle.schema.json` (sealed DSSE envelope + manifest) — stored under `docs/modules/evidence-locker/schemas/bundle.schema.json`.
|
||||
- DSSE layout: subject digests, payload (`evidence_bundle.json`), and signatures recorded; transparency optional; canonical hash: `SHA256:6f51d7a5c9d0c5db8a1f6e9d4a0af13e3e7eb5bcb4fa8457de99d8b1c2b3b8ff`.
|
||||
- Sample bundle: `docs/modules/evidence-locker/samples/evidence-bundle-sample.tgz` with accompanying `.sha256` file.
|
||||
|
||||
## Scope and guarantees
|
||||
- Sealed, offline-friendly; deterministic ordering of files in the tarball; UTC timestamps fixed to `1970-01-01T00:00:00Z` for reproducibility.
|
||||
- Payload includes: `manifest.json`, `evidence_bundle.json`, `signatures/` (DSSE), `checksums.txt`.
|
||||
- No network dependencies; validation and hashing performed locally.
|
||||
|
||||
## Validation
|
||||
- `docs/modules/evidence-locker/schemas/bundle.schema.json` validated via `ajv` offline run (see `prep/validate.sh`).
|
||||
- DSSE signature verifies with sample keypair; transparency step skipped (optional).
|
||||
|
||||
## Next steps
|
||||
- Publish NuGet contract (if needed) referencing the schema path.
|
||||
- Provide CLI/Export Center consumers with manifest path and hash above.
|
||||
- Unblock ATTEST-PLAN-2001; keep downstream sprints updated.
|
||||
@@ -1,27 +0,0 @@
|
||||
# Excititor · Consensus Removal Prep (AOC-19-004)
|
||||
|
||||
- **Date:** 2025-11-20
|
||||
- **Working directory:** `src/Excititor/__Libraries/StellaOps.Excititor.Core` + `src/Excititor/StellaOps.Excititor.WebService`
|
||||
- **Scope:** PREP-EXCITITOR-CORE-AOC-19-004-REMOVE-CONSENS
|
||||
|
||||
## Objective
|
||||
Define the cutover plan to remove legacy consensus/severity merge logic so Excititor remains aggregation-only and emits raw facts for downstream Policy/Concelier consumers.
|
||||
|
||||
## Required changes (contract)
|
||||
- **API/Storage:**
|
||||
- Deprecate/disable any fields representing merged severity/status (`mergedSeverity`, `consensusScore`, `computedStatus`).
|
||||
- Retain raw source fields: `status`, `justification`, `impact`, `affects`, `references`, `notes`, `provenance`, `reconciledFrom`.
|
||||
- Add boolean `consensusDisabled: true` to existing documents during migration for audit.
|
||||
- **Ingestion pipeline:**
|
||||
- When dual/conflicting statuses arrive, store both observations; no reconciliation beyond stable ordering.
|
||||
- Maintain deterministic ordering when multiple observations share `(tenant, advisoryId, component)` — sort by `ingestedAt`, then `source`, then `evidenceHash`.
|
||||
- **Feature flag:** `excititor:aoc:disableConsensus` default `true`; only temporary `false` allowed for rollback during migration.
|
||||
- **Telemetry:** counter `excititor.ingest.consensus.disabled` tagged by `tenant`, `source`, `connectorId`; increment once per batch after flag applied.
|
||||
|
||||
## Migration outline
|
||||
- Backfill step sets `consensusDisabled=true` where merged fields exist, and clears merged fields without touching raw observations.
|
||||
- Tests must assert merged fields are absent/null after migration and ingestion flows do not write them.
|
||||
|
||||
## Acceptance for prep completion
|
||||
- Cutover rules, telemetry, and migration outline frozen here; implementation tasks must follow or update this note and sprint risks.
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
# Console Cache & RBAC Prep — PREP-EXCITITOR-CONSOLE-23-003-DEPENDS-ON-23-001
|
||||
|
||||
Status: Draft (2025-11-20)
|
||||
Owners: Excititor WebService Guild
|
||||
Scope: Capture caching, RBAC, and precedence-context requirements for console VEX lookups once the base contract (23-001) is defined.
|
||||
|
||||
## Pending decisions
|
||||
- Tenant scoping contract from Authority (AUTH-TEN-47-001) alignment: whether to propagate `tenant_ids[]` or single `tenant_id` per request.
|
||||
- Caching TTLs and cache key shape: proposed key = hash of `(tenant_id, advisory_id, component_purl, version_range, include_precedence)`; TTL to follow Policy overlay freshness once defined.
|
||||
- Precedence trace payload (links to Policy Engine overlays) depends on POLICY-ENGINE-30-001/002.
|
||||
|
||||
## Proposed endpoints (draft)
|
||||
- `GET /console/vex/cache/entries?tenant_id=&component_purl=&advisory_id=` → returns cache metadata (`ttl_seconds`, `hits`, `last_refresh_at`, `materialization_version`).
|
||||
- `DELETE /console/vex/cache/entries/{materialization_version}` → force eviction for specific tenant/advisory/component.
|
||||
|
||||
## RBAC sketch
|
||||
- Roles: `console.viewer`, `console.operator`, `console.admin`.
|
||||
- Permissions:
|
||||
- viewer: read-only to `/console/vex` + counters.
|
||||
- operator: can invalidate cache and request refresh.
|
||||
- admin: can set cache policy per tenant/project.
|
||||
|
||||
## Handoff
|
||||
This document is the prep artefact for PREP-EXCITITOR-CONSOLE-23-003-DEPENDS-ON-23-001. Fill in TTLs, cache key fields, and precedence trace format once 23-001 and Policy overlay schemas land, then finalize and move task to DONE.
|
||||
@@ -1,23 +0,0 @@
|
||||
# Console Counters Prep — PREP-EXCITITOR-CONSOLE-23-002-DEPENDS-ON-23-001
|
||||
|
||||
Status: Draft (2025-11-20)
|
||||
Owners: Excititor WebService Guild
|
||||
Scope: Define the counter surfaces required for console delta cards, pending the `/console/vex` contract.
|
||||
|
||||
## Inputs still pending
|
||||
- Final `/console/vex` contract (23-001) including status buckets and justification categories.
|
||||
- Source-of-truth metrics/telemetry names from Policy Engine overlays (POLICY-ENGINE-30-001 once available).
|
||||
|
||||
## Proposed counter contract (to validate once 23-001 lands)
|
||||
- Endpoint: `GET /console/vex/counters?tenant_id=&component_purl=&advisory_id=&since=`
|
||||
- Response fields:
|
||||
- `total`, `affected`, `not_affected`, `under_investigation`, `mitigated`, `unknown`
|
||||
- `delta_since` (ISO-8601) and `window_seconds`
|
||||
- `evidence_refs[]` (DSSE hashes or linkset ids) optional
|
||||
- Metrics to emit:
|
||||
- Gauge `console_vex_active_total{tenant,status}`
|
||||
- Counter `console_vex_delta_total{tenant,status}` with `delta_since` label
|
||||
- Determinism: counters computed from immutable materialized views keyed by `(tenant, advisory_id, component_purl)`; avoid wall-clock beyond `since` parameter.
|
||||
|
||||
## Handoff
|
||||
Treat this as the prep artefact for PREP-EXCITITOR-CONSOLE-23-002-DEPENDS-ON-23-001. Update once status buckets are frozen in 23-001 and Policy metrics are published; then finalize endpoints and samples.
|
||||
@@ -1,25 +0,0 @@
|
||||
# Console / VEX Contract Prep — PREP-EXCITITOR-CONSOLE-23-001-AWAITING-CONCRE
|
||||
|
||||
Status: Draft (2025-11-20)
|
||||
Owners: Excititor WebService Guild · BE-Base Platform Guild
|
||||
Scope: Capture the required `/console/vex` API contract inputs so downstream tasks can proceed once the concrete spec lands.
|
||||
|
||||
## Missing inputs blocking final contract
|
||||
- LNM 21-* view specification (grouping, sorting, pagination) to align with Console UI cards.
|
||||
- Final status chip taxonomy and precedence rules from Policy/Concelier overlays.
|
||||
- SSE channel naming + retry/heartbeat semantics shared with Scheduler/Policy streams.
|
||||
|
||||
## Expectations for the final artefact
|
||||
- OpenAPI snippet covering endpoints:
|
||||
- `GET /console/vex` with filters: `component_purl`, `advisory_id`, `tenant_id`, `status`, `justification`, `page`, `page_size`, `sort` (stable ordering by `(tenant_id, component_purl, advisory_id, status, updated_at)`).
|
||||
- `GET /console/vex/{advisory_id}` returning grouped statements, precedence trace pointer, provenance links (DSSE hash + linkset id), and tenant scoping.
|
||||
- Response envelope: standard console error schema once WEB-OAS-61-002 is frozen; until then use draft shape with `error`, `message`, `trace_id`.
|
||||
- Determinism: results ordered by `(tenant_id, advisory_id, component_purl, version_range)`; pagination stable under new data.
|
||||
- Counters: return aggregate status counters `{status -> count}` in the response to power delta chips without extra queries.
|
||||
- Caching: allow short-lived (≤30s) in-memory cache keyed by tenant+filters for Console views; include `hasMore`+`cursor` to keep pagination stable.
|
||||
|
||||
## Placeholder samples to be replaced
|
||||
- Add samples under `docs/events/samples/console.vex@draft.json` once view spec is provided.
|
||||
|
||||
## Handoff
|
||||
Use this document as the prep artefact for PREP-EXCITITOR-CONSOLE-23-001-AWAITING-CONCRE. Update once LNM view spec and SSE envelope land; then freeze the OpenAPI excerpt and move the sprint task to DONE. (Initial implementation now live with caching + counters; SSE still pending.)
|
||||
@@ -1,32 +0,0 @@
|
||||
# Excititor · Graph Linkouts Prep (GRAPH-21-001)
|
||||
|
||||
- **Date:** 2025-11-20
|
||||
- **Scope:** PREP-EXCITITOR-GRAPH-21-001-NEEDS-CARTOGRAPHE
|
||||
- **Working directory:** `src/Excititor/__Libraries/StellaOps.Excititor.Core` + `src/Excititor/StellaOps.Excititor.WebService`
|
||||
|
||||
## Goal
|
||||
Define the Cartographer-facing contract for batched VEX/advisory reference fetches by PURL to unblock inspector linkouts.
|
||||
|
||||
## Batch request
|
||||
- Endpoint (to be hosted in Excititor WebService): `POST /internal/graph/linkouts`
|
||||
- Body:
|
||||
- `tenant` (string, required)
|
||||
- `purls` (array, required, max 500) — normalized PURL strings.
|
||||
- `includeJustifications` (bool, default false)
|
||||
- `includeProvenance` (bool, default true)
|
||||
- Idempotency key: `tenant` + SHA256 of sorted `purls` list.
|
||||
|
||||
## Response shape
|
||||
- `items[]` ordered by input PURL list:
|
||||
- `purl`
|
||||
- `advisories[]` — entries with `advisoryId`, `source`, `status`, `justification?`, `modifiedAt`, `evidenceHash`, `connectorId`, `dsseEnvelopeHash?`.
|
||||
- `conflicts[]` — optional disagreements (status/justification) with `source`, `observedAt`, `evidenceHash`.
|
||||
- `notFound[]` — PURLs with no VEX observations.
|
||||
|
||||
## Determinism & limits
|
||||
- Response ordering stable: by input PURL order, then `advisoryId`, then `source`.
|
||||
- Max rows: cap `advisories` to 200 per PURL; truncate with `truncated: true` flag and `nextCursor` (advisoryId, source).
|
||||
|
||||
## Acceptance for prep completion
|
||||
- Request/response contract frozen; Cartographer can stub to this interface. Downstream GRAPH-21-001 implementation must adhere or update doc + sprint risks.
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
# Excititor · Graph Overlay Prep (GRAPH-21-002)
|
||||
|
||||
- **Date:** 2025-11-20
|
||||
- **Depends on:** GRAPH-21-001 linkout contract
|
||||
- **Working directory:** `src/Excititor/StellaOps.Excititor.WebService`
|
||||
|
||||
## Overlay payload
|
||||
- Aggregates output of GRAPH-21-001 into overlay items for inspectors:
|
||||
- `purl`
|
||||
- `summary`: `open`, `not_affected`, `under_investigation`, `no_statement` counts
|
||||
- `latestModifiedAt` (ISO-8601 UTC)
|
||||
- `justifications[]` (optional) — unique justification codes present for the PURL
|
||||
- `provenance` — `sources[]` (unique source IDs), `lastEvidenceHash`
|
||||
- Endpoint: `GET /v1/graph/overlays?purl=<purl>[&purl=...]&includeJustifications=true|false`
|
||||
- Sorting: results ordered by input PURL list; within overlays, `justifications` sorted ascending.
|
||||
|
||||
## Caching
|
||||
- Cache key: tenant + sorted PURL list + `includeJustifications` flag; ttl 5 minutes default, configurable `excititor:graph:overlayTtlSeconds`.
|
||||
- Cache metadata returned: `cached: true|false`, `cacheAgeMs`.
|
||||
|
||||
## Acceptance for prep completion
|
||||
- Overlay shape and caching contract defined; implementation can proceed once GRAPH-21-001 is available.
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
# Excititor · Graph Indexes Prep (GRAPH-21-005)
|
||||
|
||||
- **Date:** 2025-11-20
|
||||
- **Depends on:** GRAPH-21-002 overlays
|
||||
- **Working directory:** `src/Excititor/__Libraries/StellaOps.Excititor.Storage.Mongo`
|
||||
|
||||
## Index plan
|
||||
- Collection: `vex_observations`
|
||||
- Compound index `{ tenant: 1, component.purl: 1, advisoryId: 1, source: 1, modifiedAt: -1 }` (supports overlay queries and truncation cursor).
|
||||
- Sparse index `{ tenant: 1, component.purl: 1, status: 1 }` for summary counts.
|
||||
- Collection: `vex_overlays` (materialized cache, optional)
|
||||
- Index `{ tenant: 1, purl: 1 }` unique.
|
||||
- TTL index on `cachedAt` configurable via `excititor:graph:overlayTtlSeconds`.
|
||||
|
||||
## Determinism
|
||||
- Materialization job must sort observations as per GRAPH-21-001 ordering before writing overlays so pagination/cursors align.
|
||||
- TTL applied identically across tenants; default 300s, override allowed via config but must be documented.
|
||||
|
||||
## Acceptance for prep completion
|
||||
- Index keys and TTL knobs defined; downstream storage tasks can implement without further contract churn.
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
# Linkset Extraction Prep — PREP-EXCITITOR-CORE-AOC-19-002-LINKSET-EXTRAC
|
||||
|
||||
Status: Draft (2025-11-20)
|
||||
Owners: Excititor Core Guild
|
||||
Scope: Identify the extraction rules and ordering needed to produce linksets from VEX/advisory inputs before idempotent raw upsert work starts.
|
||||
|
||||
## Required content to unblock
|
||||
- Canonical linkset schema version (pending Cartographer/Concelier alignment); need field list and conflict markers.
|
||||
- Source ranking/precedence table shared with Concelier LNM 21-002 fixtures.
|
||||
|
||||
## Proposed extraction rules (draft)
|
||||
- Inputs: advisory documents (component PURLs, version ranges, references, severities, CVSS vectors); output: linkset entries with `advisory_id`, `component_purl`, `version_range`, `references[]`, `severity`, `cvss`.
|
||||
- Ordering: sort entries by `(component_purl, advisory_id, version_range)`; within references, sort lexicographically.
|
||||
- Conflict handling: if multiple sources disagree, emit `conflicts[]` with `source`, `field`, `reason`; never collapse values.
|
||||
- Determinism: no wall-clock; timestamps only from source payloads (UTC ISO-8601) and preserved as-is.
|
||||
|
||||
## Handoff
|
||||
Treat this as the prep artefact for PREP-EXCITITOR-CORE-AOC-19-002-LINKSET-EXTRAC. Once the shared linkset schema and precedence table land, finalize the rules and move the sprint task to DONE.
|
||||
@@ -1,18 +0,0 @@
|
||||
# Raw Upsert Idempotency Prep — PREP-EXCITITOR-CORE-AOC-19-003-BLOCKED-ON-19
|
||||
|
||||
Status: Draft (2025-11-20)
|
||||
Owners: Excititor Core Guild
|
||||
Scope: Document the idempotent raw upsert and versioning requirements once linkset extraction (19-002) is defined.
|
||||
|
||||
## Pending inputs
|
||||
- Linkset schema and conflict markers from 19-002.
|
||||
- Storage model choice (Mongo vs Postgres) and required unique keys per tenant/advisory/component/version_range.
|
||||
|
||||
## Proposed rules (draft)
|
||||
- Unique key: `(tenant_id, advisory_id, component_purl, version_range, source)`; store a monotonic `revision` and `ingested_at` (UTC) for traceability.
|
||||
- Idempotency: compute content hash over canonicalized payload; if identical, no-op; otherwise append new revision with `supersedes` pointer.
|
||||
- Append-only log: keep prior revisions for audit; consumers read latest by hash or highest revision per key.
|
||||
- Determinism: canonical JSON ordering; stable sorting by `(tenant_id, advisory_id, component_purl, version_range, revision)`.
|
||||
|
||||
## Handoff
|
||||
Use this as the prep artefact for PREP-EXCITITOR-CORE-AOC-19-003-BLOCKED-ON-19. Finalize once 19-002 freezes schema and storage choice; then wire migrations/indexes accordingly.
|
||||
@@ -1,23 +0,0 @@
|
||||
# Excititor · Tenant-Aware Authority Prep (AOC-19-013)
|
||||
|
||||
- **Date:** 2025-11-20
|
||||
- **Scope:** PREP-EXCITITOR-CORE-AOC-19-013-SEED-TENANT-AW
|
||||
- **Working directory:** `src/Excititor/StellaOps.Excititor.WebService`, `src/Excititor/StellaOps.Excititor.Worker`, `src/Excititor/__Libraries/StellaOps.Excititor.Core`
|
||||
|
||||
## Goals
|
||||
- Enforce tenant-scoped Authority clients for all WebService/Worker actions to prevent cross-tenant leakage when consensus is removed.
|
||||
- Provide deterministic fixture/seed guidance for e2e tests.
|
||||
|
||||
## Contract
|
||||
- All Authority calls must be created through `IAuthorityClientFactory.Create(tenantId)`; factories that lack tenant must throw.
|
||||
- Configuration: `excititor:authority:baseUrl`, `excititor:authority:audience`, per-tenant `clientId/clientSecret` retrieved via internal secret resolver (no cross-tenant cache).
|
||||
- Headers: include `X-Tenant` on every outbound request; reject response lacking matching `tenant` claim.
|
||||
- Telemetry: meter `StellaOps.Excititor.Auth` counters `authority.call` tagged `tenant`, `operation`, `result` (`ok|unauthorized|forbidden|error`).
|
||||
|
||||
## Testing seeds
|
||||
- Provide seeded tenants `alpha`, `bravo` with stub secrets in test settings; integration tests must assert cross-tenant requests are rejected (401/403) when header mismatch or missing client mapping.
|
||||
- Fake Authority server returns tenant claim; tests validate enforcement and logs.
|
||||
|
||||
## Acceptance for prep completion
|
||||
- Tenant-scoped client contract, config keys, and test seeds documented; downstream tasks 19-013 can proceed using this as authority.
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
# Excititor Air-Gap Prep (56-001, 57-001, 58-001)
|
||||
|
||||
Status: **Ready for implementation** (2025-11-22)
|
||||
Owners: Excititor Core Guild · AirGap Policy Guild · Evidence Locker Guild
|
||||
Scope: Define ingestion/egress contracts for Excititor when operating in sealed/offline environments and align with mirror bundle + Evidence Locker artifacts.
|
||||
|
||||
## Inputs
|
||||
- Mirror bundle schema (thin) from `docs/modules/mirror/assembler.md`.
|
||||
- Evidence Locker attestation contract: `docs/modules/evidence-locker/attestation-contract.md`.
|
||||
- Link-Not-Merge schema for advisory evidence: `docs/modules/concelier/link-not-merge-schema.md`.
|
||||
|
||||
## Deliverables
|
||||
- Ingestion envelope for `POST /airgap/vex/import`:
|
||||
- Fields: `bundleId`, `mirrorGeneration`, `signedAt`, `publisher`, `payloadHash`, `payloadUrl?` (offline tar path), `signature`, `transparencyLog?`.
|
||||
- Validation: deterministic hash of NDJSON payloads; must reject mixed tenants; clock-skew tolerance ±5s.
|
||||
- Idempotency: duplicate `(bundleId, mirrorGeneration)` must return HTTP 409 `AIRGAP_IMPORT_DUPLICATE` and not write a new record.
|
||||
- Sealed-mode error catalog (57-001): `AIRGAP_EGRESS_BLOCKED`, `AIRGAP_PAYLOAD_STALE`, `AIRGAP_SIGNATURE_MISSING`, `AIRGAP_SOURCE_UNTRUSTED`; each with HTTP 4xx mapping and remediation text.
|
||||
- Notification hooks (58-001): timeline events `airgap.import.started/completed/failed` with attributes `{tenantId,bundleId,generation,stalenessSeconds}`; link to Evidence Locker bundle ID for audit.
|
||||
- Determinism rules: sort imported observations by `advisoryKey` then `productKey`; write timeline events in the same order; all timestamps UTC ISO-8601.
|
||||
- Connector trust (CONN-TRUST-01-001):
|
||||
- Trusted signer manifests reuse `docs/modules/excititor/schemas/connector-signer-metadata.schema.json`; require `fingerprint`, `issuer`, `validFrom/To`, `allowedProfiles`, `bundleHash`.
|
||||
- Validation: fail import with `AIRGAP_SOURCE_UNTRUSTED` when signer fingerprint not in manifest, signature algorithm not in `{rsa-pss-sha256, ecdsa-p256-sha256, gost-r3410-2012-256}`, or bundle hash mismatch.
|
||||
- Offline parity: store signer manifests alongside mirror bundle under `mirror/signers/` and include SHA256 in `SHA256SUMS.dsse`.
|
||||
|
||||
## Acceptance Criteria
|
||||
- API shapes captured in this prep are referenced from Sprint 0119 Delivery Tracker; no further blockers for Excititor AirGap tasks.
|
||||
- Error catalog and timeline events documented and consumed by downstream Policy/AirGap controller work.
|
||||
- Import path validated against mirror bundle schema; mismatch should raise `AIRGAP_PAYLOAD_STALE`.
|
||||
|
||||
## Notes
|
||||
- Satisfies PREP-EXCITITOR-AIRGAP-56-001, PREP-EXCITITOR-AIRGAP-57-001, and PREP-EXCITITOR-AIRGAP-58-001.
|
||||
@@ -1,27 +0,0 @@
|
||||
# Attestation Verifier Rehearsal — Excititor
|
||||
|
||||
Status: **Ready for implementation** (2025-11-22)
|
||||
Owners: Excititor Attestation Guild · Evidence Locker Guild
|
||||
Scope: Dry-run `IVexAttestationVerifier` against current Evidence Locker bundles to ensure Excititor attestation endpoints ship with deterministic verification.
|
||||
|
||||
## Test Matrix
|
||||
- Inputs: Evidence Bundle v1 sample (`docs/samples/evidence-bundle/*`), mirror bundle thin sample (`out/mirror/thin/mirror-thin-m0-sample.tar.gz`).
|
||||
- Verification steps:
|
||||
1. Validate DSSE envelope signature and Rekor entry (if present); offline mode skips transparency but records `rekorSkipped=true`.
|
||||
2. Verify manifest hash tree against payload NDJSON files; fail on first mismatch.
|
||||
3. Assert policy hash matches Policy Engine overlay hash (placeholder `policyHash` captured for now).
|
||||
4. Emit structured result JSON: `{bundleId, verified, dsseVerified, transparencyChecked, manifestRoot, failures[]}`.
|
||||
- Determinism: sorted failure list, timestamps set to supplied `--as-of` flag.
|
||||
|
||||
## Deliverables
|
||||
- Harness entry point: `tools/attestation/verifier-rehearsal.sh` (script stub path reserved).
|
||||
- Sample output recorded at `docs/modules/excititor/prep/artifacts/2025-11-22-attestation-rehearsal.json` (to be produced in implementation).
|
||||
- Logging fields to surface in Excititor: `attestationBundleId`, `evidenceBundleId`, `verified`, `failureCode`, `tenantId`.
|
||||
|
||||
## Acceptance Criteria
|
||||
- Rehearsal script runs offline using bundled samples and exits non-zero on any verification failure.
|
||||
- Output schema above is referenced by Excititor API tests and Policy attest replay tasks.
|
||||
- Downstream tasks EXCITITOR-GRAPH-21-00x and attestation endpoints can rely on this contract.
|
||||
|
||||
## Notes
|
||||
- Satisfies PREP-ATTESTATION-VERIFIER-REHEARSAL-EXCITITOR.
|
||||
@@ -1,17 +0,0 @@
|
||||
# Export Crypto Prep — PREP-EXPORT-CRYPTO-90-001
|
||||
|
||||
Status: Draft (2025-11-20)
|
||||
Owners: Exporter Service · Security Guild
|
||||
Scope: Capture crypto requirements pending Nov-18 review and reference implementation.
|
||||
|
||||
## Needs
|
||||
- Mapping of signing/encryption algorithms per export profile.
|
||||
- Integration with `ICryptoProviderRegistry` (same as Evidence Locker) for provider selection.
|
||||
- Hashing defaults (sha256) and optional sha512/sha3 for high-assurance paths.
|
||||
|
||||
## Open decisions
|
||||
- Final provider list and key storage (KMS/HSM) per profile.
|
||||
- Whether to sign both manifest and per-artifact hashes.
|
||||
|
||||
## Handoff
|
||||
Use as prep artefact for EXPORT-CRYPTO-90-001; fill once Security delivers profile list and reference implementation.
|
||||
@@ -1,42 +0,0 @@
|
||||
# DevPortal Offline Prep — PREP-DVOFF-64-002
|
||||
|
||||
Status: **Ready for implementation** (2025-11-20)
|
||||
Owners: DevPortal Offline Guild · AirGap Controller Guild
|
||||
Scope: Define sealed bundle sample + CLI verify flow for DevPortal offline verification (`stella devportal verify bundle.tgz`).
|
||||
|
||||
## Required inputs
|
||||
- EvidenceLocker sealed bundle contract: `docs/modules/evidence-locker/bundle-packaging.md` (bundle.tgz layout, determinism).
|
||||
- Portable bundle guidance: `docs/airgap/portable-evidence.md` (for redacted flow).
|
||||
|
||||
## Sample artefacts to publish
|
||||
- `out/devportal/samples/bundle.tgz` — copy of EvidenceLocker sealed bundle (write-once).
|
||||
- `out/devportal/samples/bundle.tgz.sha256` — `sha256 bundle.tgz` line.
|
||||
- `out/devportal/samples/verify-report.json` — expected CLI JSON output after verification (see below).
|
||||
|
||||
## CLI verification flow (contract)
|
||||
- Command: `stella devportal verify --bundle bundle.tgz --offline`
|
||||
- Steps performed:
|
||||
1) Validate SHA-256 against `.sha256` file.
|
||||
2) Extract `manifest.json`, `signature.json`, `bundle.json`, `checksums.txt` (no rewrite).
|
||||
3) Run DSSE verification (offline) using embedded signature; if TSA token present, report but do not fail when `--offline` is set.
|
||||
4) Emit JSON output:
|
||||
```json
|
||||
{
|
||||
"status": "verified",
|
||||
"bundleId": "<bundleId>",
|
||||
"rootHash": "sha256:0123deadbeef",
|
||||
"entries": 4,
|
||||
"createdAt": "2025-01-01T00:00:00Z",
|
||||
"portable": false
|
||||
}
|
||||
```
|
||||
- Exit codes: 0 success, 2 checksum mismatch, 3 signature failure, 4 TSA missing (when not offline), 5 unexpected.
|
||||
- Determinism: no network calls when `--offline`; output JSON keys sorted.
|
||||
|
||||
## Acceptance criteria
|
||||
- Sample bundle and .sha256 published under `out/devportal/samples/` with hashes listed in this sprint.
|
||||
- CLI flow documented above; exit codes and sample JSON provided.
|
||||
- Prep doc linked from Sprint 0162 P1 and DevPortal docs when implemented.
|
||||
|
||||
## Next steps
|
||||
- Publish the sample bundle + hashes; update sprint Delivery Tracker to DONE once artifacts exist.
|
||||
@@ -1,12 +0,0 @@
|
||||
# Export AirGap Prep — PREP-EXPORT-AIRGAP-56-001
|
||||
|
||||
Status: Draft (2025-11-20)
|
||||
Owners: Exporter Service Guild · Mirror Creator Guild
|
||||
Scope: EvidenceLocker contract + advisory schema to finalize DSSE contents for air-gapped exports.
|
||||
|
||||
## Needs
|
||||
- EvidenceLocker contract (bundle schema, retention).
|
||||
- Advisory schema alignment for DSSE contents.
|
||||
|
||||
## Handoff
|
||||
Use as prep artefact; update when EvidenceLocker spec is available.
|
||||
@@ -1,36 +0,0 @@
|
||||
# Export AirGap Prep — PREP-EXPORT-AIRGAP-56-002
|
||||
|
||||
Status: **Ready for implementation** (2025-11-20)
|
||||
Owners: Exporter Service Guild · DevOps Guild
|
||||
Scope: Bootstrap pack (images + charts) packaging for air-gap deploys, dependent on 56-001 evidence/mirror bundle inputs.
|
||||
|
||||
## Dependencies
|
||||
- Sealed bundle schema + advisory contents from 56-001 prep (`docs/modules/export-center/prep/2025-11-20-export-airgap-56-001-prep.md`).
|
||||
- Mirror/DevOps deployment expectations (values-airgap.yaml) to place bootstrap packs.
|
||||
|
||||
## Packaging contract
|
||||
- Produce deterministic OCI archive `bootstrap-pack-v1.tar` containing:
|
||||
- `charts/` Helm charts with pinned template timestamps (SOURCE_DATE_EPOCH=2025-01-01T00:00:00Z).
|
||||
- `images/` directory with referenced container layers/blobs; `manifest.json` aligning with `index.json` (OCI image layout).
|
||||
- `signatures/` optional DSSE/TUF metadata if provided by 56-001.
|
||||
- Tarball is gzip-compressed with mtime pinned to `2025-01-01T00:00:00Z`, `0644` perms, uid/gid 0.
|
||||
- Checksums: `bootstrap-pack-v1.tar.sha256` with `sha256 bootstrap-pack-v1.tar` exactly.
|
||||
|
||||
## API/endpoints
|
||||
- `POST /v1/exports/airgap/bootstrap` → stages pack build; returns `exportId` and profile `bootstrap`.
|
||||
- `GET /v1/exports/airgap/bootstrap/{exportId}` → status + `downloadUri`, `rootHash`, `artifactSha256`.
|
||||
- `GET /v1/exports/airgap/bootstrap/{exportId}/download` → serves `application/gzip` tarball; `ETag` = SHA-256.
|
||||
- Auth scopes: `export:write` for POST; `export:read` for GET/Download.
|
||||
|
||||
## Determinism & observability
|
||||
- Single build timestamp derived from SOURCE_DATE_EPOCH; no wall-clock elsewhere.
|
||||
- Structured logs `{exportId, profile:"bootstrap", rootHash, artifactSha256}`; metrics `export.bootstrap.completed`, `export.bootstrap.duration_ms`.
|
||||
|
||||
## Acceptance criteria
|
||||
- Tarball is byte-stable across reruns for same inputs; checksum file matches.
|
||||
- Status/download endpoints documented with headers (`ETag`, `Last-Modified`, quota headers).
|
||||
- Bootstrap pack content references evidence/mirror bundles from 56-001 (by digest/URL) without re-signing.
|
||||
|
||||
## Handoff
|
||||
- Implement pack build and endpoints in ExportCenter Worker/WebService; use same storage layout as evidence export (`exports/{tenant}/{exportId}/bootstrap-pack-v1.tar`).
|
||||
- Update Sprint 0162 Delivery Tracker entry P3 to DONE when contract is published.
|
||||
@@ -1,61 +0,0 @@
|
||||
# Export AirGap Prep — PREP-EXPORT-AIRGAP-57-001
|
||||
|
||||
Status: **Ready for implementation** (2025-11-20)
|
||||
Owners: Exporter Service Guild · Evidence Locker Guild
|
||||
Scope: Portable evidence export mode (air-gap) that reuses EvidenceLocker sealed/portable bundles and packages them for ExportCenter delivery.
|
||||
|
||||
## Dependencies (must remain green before coding)
|
||||
- EvidenceLocker packaging contract (sealed + portable): `docs/modules/evidence-locker/bundle-packaging.md`, `docs/airgap/portable-evidence.md`.
|
||||
- Upstream sealed bundle export readiness (56-001) and bootstrap pack alignment (56-002) — inputs are reused verbatim, no re-signing.
|
||||
- Orchestrator/Notifications envelopes for emission events remain pending; not required to start packaging but block notification wiring.
|
||||
|
||||
## Contract for EXPORT-AIRGAP-57-001
|
||||
1) **Input**: bundle id (`bundleId`) that is already sealed. Export service fetches the portable archive `portable-bundle-v1.tgz` via the EvidenceLocker portable endpoint (write-once cache).
|
||||
2) **Packaging**: create deterministic gzip/tar (`export-portable-bundle-v1.tgz`) with fixed mtime `2025-01-01T00:00:00Z`, PAX headers, and sorted entries:
|
||||
```
|
||||
export-portable-bundle-v1.tgz
|
||||
├── export.json # Export job metadata (bundleId, exportId, tenant, createdAtUtc, rootHash, sourceUri, portableVersion)
|
||||
├── portable-bundle-v1.tgz # Bit-for-bit copy from EvidenceLocker (no re-signing)
|
||||
├── checksums.txt # SHA256 for all files (portable bundle included) + Merkle root
|
||||
├── verify-export.sh # POSIX script: checksum portable bundle, call `stella evidence verify --bundle portable-bundle-v1.tgz`
|
||||
└── README.md # Operator instructions (ingress/egress steps, expected headers, schema links)
|
||||
```
|
||||
- Gzip header mtime and tar mtimes are pinned; permissions `0644`; owner/group `0`.
|
||||
- `checksums.txt` lists files in lexical order; first line `root <sha256(export-portable-bundle-v1.tgz)>`.
|
||||
- `verify-export.sh` uses only `tar` + `sha256sum`/`shasum`; no network calls.
|
||||
|
||||
3) **API surface (ExportCenter)**
|
||||
- `POST /v1/exports/airgap/evidence/{bundleId}`: stages the export; responds `202 Accepted` with `exportId` and link to poll.
|
||||
- `GET /v1/exports/airgap/evidence/{exportId}`: returns status + download link when ready; includes `rootHash`, `portableVersion`, `bundleId`.
|
||||
- `GET /v1/exports/airgap/evidence/{exportId}/download`: `application/gzip`, filename `export-portable-bundle-v1.tgz`, ETag = SHA256.
|
||||
- Auth: `export:read` for GET, `export:write` for POST; support tenant scoping identical to EvidenceLocker.
|
||||
|
||||
4) **Determinism & observability**
|
||||
- No wall-clock usage beyond the already fixed `createdAtUtc` written once per export job.
|
||||
- Emit structured log `{exportId,bundleId,portableVersion,rootHash}` on completion.
|
||||
- Metrics: counter `export.airgap.portable.completed`, histogram `export.airgap.portable.duration_ms`, gauge `export.airgap.portable.queue_depth`.
|
||||
|
||||
5) **Error handling**
|
||||
- If bundle not sealed → `409 SealedRequired` with `retryAfter`.
|
||||
- If portable artefact missing → trigger fetch from EvidenceLocker; return `202` with `pendingReason=PortableMaterialising`.
|
||||
- Verification failures of copied bundle (hash mismatch) → mark export `FAILED` and keep artefact; require operator acknowledgement.
|
||||
|
||||
## Acceptance criteria
|
||||
- Deterministic archive bytes for a given (`bundleId`, `exportId`) across reruns; gzip/tar timestamps and ordering pinned.
|
||||
- Export archive contains the unmodified EvidenceLocker portable bundle and top-level instructions for offline operators.
|
||||
- CLI verification path documented in README and script; succeeds with no network access using current `stella evidence verify`.
|
||||
- Status/Download endpoints documented and cover `202/404/409/500` cases; ETag and `Last-Modified` set.
|
||||
|
||||
## Implementation notes for developers
|
||||
- Reuse EvidenceLocker’s `PortableBundleVersion` constant to avoid drift; do not unzip/repack the inner portable archive.
|
||||
- Populate `export.json` using UTC ISO-8601; include `sourceUri` referencing the original EvidenceLocker portable endpoint used.
|
||||
- Store artefacts under object key `exports/{tenant}/{bundleId}/{exportId}/export-portable-bundle-v1.tgz` with write-once semantics.
|
||||
- Mirror logging/metrics naming with 56-001/56-002 to ease dashboard reuse.
|
||||
|
||||
## Open items / risks
|
||||
- Notifications/timeline emission remains pending on Wave 150/140 envelope drop; add once schemas land (tracked separately).
|
||||
- If portable bundle version bumps to v2, archive filename and `portableVersion` must be updated in tandem.
|
||||
|
||||
## Handoff
|
||||
- This prep artefact is ready to implement in `src/ExportCenter/StellaOps.ExportCenter.WebService` job + `StellaOps.ExportCenter.Worker` for queue processing.
|
||||
- Link back to this document from Sprint 0162 Delivery Tracker entry P4.
|
||||
@@ -1,58 +0,0 @@
|
||||
# Export AirGap Prep — PREP-EXPORT-AIRGAP-58-001
|
||||
|
||||
Status: **Ready for implementation** (2025-11-20)
|
||||
Owners: Exporter Service Guild · Notifications Guild
|
||||
Scope: Emit deterministic notifications/timeline events when portable evidence export (57-001) completes, without requiring enclave connectivity.
|
||||
|
||||
## Dependencies
|
||||
- Portable export artefact from 57-001: `export-portable-bundle-v1.tgz` (contains `portable-bundle-v1.tgz`).
|
||||
- Notification envelope decisions in Wave 150/140 (orchestrator/notifications), but this prep provides a concrete payload to unblock implementation.
|
||||
- EvidenceLocker bundle contracts: `docs/modules/evidence-locker/bundle-packaging.md`, `docs/airgap/portable-evidence.md`.
|
||||
|
||||
## Event contract (v1)
|
||||
- **Subject / type**: `export.airgap.ready.v1`
|
||||
- **Channel**: NATS topic `export.airgap.ready.v1` and mirrored to optional webhooks (`application/json`). Transport must be retryable with backoff and DLQ.
|
||||
- **Payload (canonical key order shown)**:
|
||||
```json
|
||||
{
|
||||
"type": "export.airgap.ready.v1",
|
||||
"export_id": "...",
|
||||
"bundle_id": "...",
|
||||
"tenant_id": "...",
|
||||
"profile_id": "airgap-evidence",
|
||||
"portable_version": "v1",
|
||||
"root_hash": "sha256:...",
|
||||
"artifact_uri": "/v1/exports/airgap/evidence/{exportId}/download",
|
||||
"artifact_sha256": "...",
|
||||
"created_at": "2025-11-20T00:00:00Z",
|
||||
"expires_at": "2026-11-20T00:00:00Z",
|
||||
"metadata": {
|
||||
"source_uri": "/evidence/{bundleId}/portable",
|
||||
"portable_size_bytes": 0,
|
||||
"export_size_bytes": 0
|
||||
}
|
||||
}
|
||||
```
|
||||
- Timestamps UTC, RFC3339; numeric sizes optional but deterministic when present.
|
||||
- `artifact_sha256` is the SHA-256 of `export-portable-bundle-v1.tgz`; `root_hash` is the Merkle root from `checksums.txt` (same as portable bundle root).
|
||||
- `expires_at` is optional; when omitted, receivers assume standard retention from EvidenceLocker policy.
|
||||
|
||||
## Determinism & delivery rules
|
||||
- Serialize JSON without whitespace changes that affect ordering; server must sort top-level keys alphabetically before emission.
|
||||
- When delivering via webhooks, include headers: `X-Stella-Event-Type`, `X-Stella-Signature` (HMAC-SHA256), `X-Stella-Sent-At` (UTC ISO-8601).
|
||||
- Retries: exponential backoff (1s, 2s, 4s, 8s, 16s) with maximum 5 attempts; failed deliveries go to DLQ topic `export.airgap.ready.dlq` with failure reason.
|
||||
|
||||
## API linkage
|
||||
- Notifications reference the download endpoint defined in 57-001: `GET /v1/exports/airgap/evidence/{exportId}/download`.
|
||||
- Optional timeline event mirror (`timeline.export.airgap.ready`) may be emitted once orchestrator envelope schema lands; payload mirrors the notification without headers.
|
||||
|
||||
## Acceptance criteria
|
||||
- Notification emits once per successful export; idempotent on replays (same `export_id` + hash).
|
||||
- Payload fields match the portable export artefact (hashes, URIs, versions) and require no further network calls for verification.
|
||||
- DLQ captures failed deliveries with reason and last response status.
|
||||
- Documentation of headers, payload, and retry guarantees is published for consuming guilds.
|
||||
|
||||
## Handoff
|
||||
- Implement emission in ExportCenter Worker when export job transitions to `Completed`.
|
||||
- Add webhook signature secret to configuration surface; default to disabled for air-gap unless explicitly allowed.
|
||||
- Link this document from Sprint 0162 Delivery Tracker entry P5.
|
||||
@@ -1,50 +0,0 @@
|
||||
# Export Attestation Prep — PREP-EXPORT-ATTEST-74-001
|
||||
|
||||
Status: **Ready for implementation** (2025-11-20)
|
||||
Owners: Attestation Bundle Guild · Exporter Service Guild
|
||||
Scope: Produce deterministic attestation export bundles for air-gap/offline delivery, leveraging EvidenceLocker DSSE layout and orchestrator events.
|
||||
|
||||
## Dependencies
|
||||
- EvidenceLocker packaging & DSSE conventions: `docs/modules/evidence-locker/bundle-packaging.md`.
|
||||
- Attestor air-gap guidance: `docs/modules/attestor/airgap.md` (statement + predicate expectations).
|
||||
- Orchestrator event envelopes (Wave 150/140) for optional timeline/notification mirrors; not required to start packaging.
|
||||
|
||||
## Export bundle contract (v1)
|
||||
- **Input**: attestation record id (`attestationId`) referencing a sealed DSSE statement (e.g., in-toto) stored by EvidenceLocker/Attestor.
|
||||
- **Packaging**: create deterministic gzip/tar `export-attestation-bundle-v1.tgz` with fixed mtime `2025-01-01T00:00:00Z`, PAX headers, `0644` perms, owner/group `0`.
|
||||
```
|
||||
export-attestation-bundle-v1.tgz
|
||||
├── attestation.dsse.json # Original DSSE envelope (statement + signature), unchanged
|
||||
├── statement.json # Extracted statement/predicate for quick inspection
|
||||
├── transparency.ndjson # Optional Rekor/CT entries (one per line, canonical JSON)
|
||||
├── metadata.json # exportId, attestationId, subject digests, rootHash, createdAtUtc, sourceUri
|
||||
├── checksums.txt # SHA256 hashes (lexical order); first line `root <sha256(export-attestation-bundle-v1.tgz)>`
|
||||
└── verify-attestation.sh # POSIX script: checksum, DSSE verify (invokes `stella attest verify` if available)
|
||||
```
|
||||
- No re-signing; DSSE envelope is copied bit-for-bit from source.
|
||||
- `transparency.ndjson` omitted when no log entries exist; maintain deterministic ordering otherwise.
|
||||
|
||||
## API surface (ExportCenter)
|
||||
- `POST /v1/exports/attestations/{attestationId}` → `202 Accepted` with `exportId`, `status=pending`.
|
||||
- `GET /v1/exports/attestations/{exportId}` → status + metadata (`rootHash`, `downloadUri`, `attestationDigests`).
|
||||
- `GET /v1/exports/attestations/{exportId}/download` → `application/gzip`, filename `export-attestation-bundle-v1.tgz`, `ETag`=SHA256.
|
||||
- Auth: `export:write` for POST, `export:read` for GET/Download; tenant scoped.
|
||||
|
||||
## Determinism & observability
|
||||
- All timestamps captured once at export creation (UTC ISO-8601) and reused; archive mtimes/gzip mtime pinned.
|
||||
- Structured log on completion `{exportId, attestationId, subjectDigests, rootHash}`; counter `export.attest.completed` and histogram `export.attest.duration_ms`.
|
||||
- Retries for fetch/pack errors use exponential backoff identical to 57-001 portable export.
|
||||
|
||||
## Acceptance criteria
|
||||
- Export archive is byte-identical across replays for the same (`attestationId`,`exportId`).
|
||||
- DSSE envelope and statement are unchanged relative to source; hashes in `checksums.txt` match download and DSSE payload.
|
||||
- API responses document 202/404/409/500 paths; `downloadUri` returns sealed artifact with deterministic ETag.
|
||||
- Verification script runs offline using only `tar` + `sha256sum`/`shasum`; optionally calls `stella attest verify` when present.
|
||||
|
||||
## Open items / risks
|
||||
- Notification/timeline emission pending envelope schema; add once Wave 150/140 lands.
|
||||
- If attestation format changes (predicate versions), bump `statementVersion` in `metadata.json` and announce.
|
||||
|
||||
## Handoff
|
||||
- Implement in `StellaOps.ExportCenter.Worker` export job + WebService endpoints above.
|
||||
- Link this document from Sprint 0162 entry P6 and close PREP when endpoints + packaging align.
|
||||
@@ -1,46 +0,0 @@
|
||||
# Export Attestation Prep — PREP-EXPORT-ATTEST-74-002
|
||||
|
||||
Status: **Ready for implementation** (2025-11-20)
|
||||
Owners: Attestation Bundle Guild · DevOps Guild
|
||||
Scope: Integrate attestation export bundle job (74-001) into CI/offline kit packaging, publish checksums, and ensure deterministic artefact promotion.
|
||||
|
||||
## Dependencies
|
||||
- Export bundle contract v1 from 74-001: `docs/modules/export-center/prep/2025-11-20-export-attest-74-001-prep.md`.
|
||||
- EvidenceLocker/Attestor attestation format (DSSE) — no re-signing allowed.
|
||||
- Air-gap kit structure (mirror/bootstrap packs) from Sprint 160/56-002 for placement of attestation bundles.
|
||||
|
||||
## CI/offline kit integration contract
|
||||
- **Build step**: Invoke ExportCenter job for targeted `attestationId` and stage `export-attestation-bundle-v1.tgz` under `out/export/attestations/{exportId}/`.
|
||||
- **Checksum publication**: emit `export-attestation-bundle-v1.tgz.sha256` alongside the archive; contents `sha256 filename` with filename exactly `export-attestation-bundle-v1.tgz`.
|
||||
- **Offline kit layout**:
|
||||
```
|
||||
offline-kit/
|
||||
checksums/
|
||||
attestations/
|
||||
export-attestation-bundle-v1.tgz.sha256
|
||||
attestations/
|
||||
export-attestation-bundle-v1.tgz
|
||||
```
|
||||
- **Promotion**: artefacts are immutable; CI publishes to `out/export/offline-kits/{kitVersion}/` with write-once semantics. Promotion between environments copies bytes; no rebuilds.
|
||||
- **Metadata**: append to `out/export/offline-kits/{kitVersion}/manifest.json`:
|
||||
```json
|
||||
{
|
||||
"kind": "attestation-export",
|
||||
"exportId": "...",
|
||||
"attestationId": "...",
|
||||
"rootHash": "sha256:...",
|
||||
"artifact": "attestations/export-attestation-bundle-v1.tgz",
|
||||
"checksum": "checksums/attestations/export-attestation-bundle-v1.tgz.sha256",
|
||||
"createdAt": "2025-11-20T00:00:00Z"
|
||||
}
|
||||
```
|
||||
- **Determinism**: CI must set `SOURCE_DATE_EPOCH=1735689600` (2025-01-01T00:00:00Z) for any tar/gzip operations when re-wrapping kits; do not re-tar the inner export bundle.
|
||||
|
||||
## Acceptance criteria
|
||||
- Export bundle generated by 74-001 is copied bit-for-bit into the offline kit; SHA256 in checksums file matches archive and `manifest.json` entry.
|
||||
- Kit manifest contains the attestation entry with UTC timestamp and root hash; promotion produces identical bytes across runs.
|
||||
- CI logs include the exportId and SHA256; failures stop the pipeline and do not overwrite prior artefacts.
|
||||
|
||||
## Handoff
|
||||
- Wire CI/packaging scripts in ExportCenter DevOps pipeline to consume the 74-001 export endpoint and assemble offline kit layout above.
|
||||
- Update Sprint 0162 Delivery Tracker entry P7 with status changes when implemented.
|
||||
@@ -1,44 +0,0 @@
|
||||
# Export Attestation Prep — PREP-EXPORT-ATTEST-75-001
|
||||
|
||||
Status: **Ready for implementation** (2025-11-20)
|
||||
Owners: Attestation Bundle Guild · CLI Attestor Guild
|
||||
Scope: Define CLI contract for verifying/importing attestation export bundles (from 74-002) in offline/air-gap environments.
|
||||
|
||||
## Dependencies
|
||||
- Attestation export bundle layout: `docs/modules/export-center/prep/2025-11-20-export-attest-74-001-prep.md` and CI/offline kit integration `...-74-002-prep.md`.
|
||||
- EvidenceLocker/Attestor verification library (`stella attest verify`).
|
||||
|
||||
## CLI experience
|
||||
- New command: `stella attest bundle verify --file export-attestation-bundle-v1.tgz`
|
||||
- Validates SHA256 against co-located `.sha256` file (see 74-002).
|
||||
- Runs DSSE verification using bundled statement/signature; prints subject digests, predicate type/version, and root hash.
|
||||
- Exit codes: 0 success, 2 checksum mismatch, 3 DSSE signature failure, 4 missing TSA/log when required, >4 unexpected error.
|
||||
- New command: `stella attest bundle import --file export-attestation-bundle-v1.tgz`
|
||||
- Performs verification first; then registers the attestation in the local/offline EvidenceLocker (when configured) and outputs new `attestationId`/`tenant` reference.
|
||||
- Supports `--tenant`, `--namespace` flags; defaults to current CLI profile.
|
||||
- No network calls beyond optional TSA/CT validations; provide `--offline` to skip.
|
||||
|
||||
## Determinism and I/O
|
||||
- CLI must avoid rewriting the archive; reads-only.
|
||||
- Output logs in JSON when `--output json` is passed, with stable key order:
|
||||
```json
|
||||
{
|
||||
"status": "verified",
|
||||
"exportId": "...",
|
||||
"attestationId": "...",
|
||||
"rootHash": "sha256:...",
|
||||
"subjects": ["sha256:..."],
|
||||
"predicateType": "slsa/v1",
|
||||
"bundlePath": "export-attestation-bundle-v1.tgz"
|
||||
}
|
||||
```
|
||||
- Human-readable output includes root hash, subject digests, predicate type/version, and trust root used.
|
||||
|
||||
## Acceptance criteria
|
||||
- CLI verifies bundles generated by 74-002 using only local artefacts; succeeds offline when `--offline` is used.
|
||||
- Import command registers attestation locally without modifying archive; errors if checksum/signature fail.
|
||||
- Exit codes and JSON schema documented for automation; tests cover checksum mismatch and invalid signature cases.
|
||||
|
||||
## Handoff
|
||||
- Implement commands in `src/Cli/StellaOps.Cli` (attestor plugin) and add docs/examples to `docs/modules/cli/artefacts/guardrails-artefacts-2025-11-19.md` or a new CLI guide.
|
||||
- Link back to this prep in Sprint 0162 Delivery Tracker entry P8.
|
||||
@@ -1,35 +0,0 @@
|
||||
# Export Attestation Prep — PREP-EXPORT-ATTEST-75-002
|
||||
|
||||
Status: **Ready for implementation** (2025-11-20)
|
||||
Owners: Exporter Service Guild
|
||||
Scope: Wire attestation export bundles (74-002) + CLI workflows (75-001) into full offline kit and mirror bundle distribution flows.
|
||||
|
||||
## Dependencies
|
||||
- 74-001/74-002 bundle + kit layout.
|
||||
- CLI verify/import contract: `docs/modules/export-center/prep/2025-11-20-export-attest-75-001-prep.md`.
|
||||
|
||||
## Distribution/kit contract
|
||||
- Place attestation bundles and checksum files into offline kit (same layout as 74-002) and publish to mirror locations used by ExportCenter air-gap profiles.
|
||||
- Provide `manifest-offline.json` entry per kit:
|
||||
```json
|
||||
{
|
||||
"kind": "attestation-kit",
|
||||
"kitVersion": "v1",
|
||||
"artifact": "attestations/export-attestation-bundle-v1.tgz",
|
||||
"checksum": "checksums/attestations/export-attestation-bundle-v1.tgz.sha256",
|
||||
"cliExample": "stella attest bundle verify --file attestations/export-attestation-bundle-v1.tgz",
|
||||
"importExample": "stella attest bundle import --file attestations/export-attestation-bundle-v1.tgz --offline",
|
||||
"rootHash": "sha256:...",
|
||||
"createdAt": "2025-11-20T00:00:00Z"
|
||||
}
|
||||
```
|
||||
- Copy the kit directory to mirror/air-gap repo: `mirror/export/attestations/{kitVersion}/` with same bytes; publish `manifest-offline.json` and `.sha256` for the manifest.
|
||||
|
||||
## Acceptance criteria
|
||||
- Offline kit includes attestation bundle + checksum + manifest entries; hashes match originals from 74-002.
|
||||
- Mirrors deliver identical bytes (bit-for-bit) across environments; manifests list CLI commands for operators.
|
||||
- No rebuild of attestation bundle during distribution; only copies allowed.
|
||||
|
||||
## Handoff
|
||||
- Implement packaging/copy steps in ExportCenter build pipeline and mirror publisher.
|
||||
- Update Sprint 0162 Delivery Tracker entry P9 when complete.
|
||||
@@ -1,54 +0,0 @@
|
||||
# ExportCenter OAS Prep — PREP-EXPORT-OAS-61-001
|
||||
|
||||
Status: **Ready for implementation** (2025-11-20)
|
||||
Owners: Exporter Service Guild · API Contracts Guild
|
||||
Scope: Freeze ExportCenter v1 OpenAPI surface (profiles/runs/downloads) with deterministic headers, ETag/versioning, and standard error envelope.
|
||||
|
||||
## Design targets
|
||||
- Cover the baseline export capabilities required for Wave 160.B: air-gap evidence exports, attestation exports, mirror/bootstrap exports, and discovery.
|
||||
- Keep payloads deterministic; avoid wall-clock dependence outside stamped fields returned by the service.
|
||||
- Provide strong cache/discovery signals: `ETag`, `Last-Modified`, `Cache-Control: private, must-revalidate`, plus `/.well-known/openapi` entry.
|
||||
|
||||
## Paths to include in v1 spec
|
||||
- `GET /.well-known/openapi` — returns OpenAPI document with `ETag` and `X-Export-Oas-Version` (value `v1`).
|
||||
- Evidence exports (portable bundles):
|
||||
- `POST /v1/exports/airgap/evidence/{bundleId}` → `202 Accepted` with `exportId`, `status=pending`.
|
||||
- `GET /v1/exports/airgap/evidence/{exportId}` → status document (`status`, `rootHash`, `artifactSha256`, `portableVersion`, `downloadUri`).
|
||||
- `GET /v1/exports/airgap/evidence/{exportId}/download` → `application/gzip`, filename `export-portable-bundle-v1.tgz`, `ETag` = archive SHA-256.
|
||||
- Attestation exports:
|
||||
- `POST /v1/exports/attestations/{attestationId}` → `202 Accepted` with `exportId`.
|
||||
- `GET /v1/exports/attestations/{exportId}` → status + `downloadUri`, `rootHash`, `statementDigest`.
|
||||
- `GET /v1/exports/attestations/{exportId}/download` → `application/gzip`, filename `export-attestation-bundle-v1.tgz`, `ETag` = archive SHA-256.
|
||||
- Mirror/bootstrap (profiles only, no payload schema change):
|
||||
- `GET /v1/exports/profiles` — lists available export profiles (e.g., `mirror`, `bootstrap`, `airgap-evidence`, `attestation`). Supports pagination (`limit`, `cursor`) and filtering by `kind`.
|
||||
- `GET /v1/exports/runs` — list export runs with status filters, tenant scoping, paging.
|
||||
- Observability hooks (metadata only):
|
||||
- `GET /v1/exports/runs/{exportId}/events` — optional timeline/event stream pointer (when notifications enabled). Can remain `x-stub: true` until envelopes land.
|
||||
|
||||
## Components
|
||||
- **Schemas**
|
||||
- `ExportStatus`: `{ exportId, profileId, status: pending|running|completed|failed, artifactSha256, rootHash, portableVersion?, attestationId?, bundleId?, createdAt, completedAt?, downloadUri }`
|
||||
- `ExportProfile`: `{ id, kind, description, version, retentionDays }`
|
||||
- `ErrorEnvelope`: `{ error: { code, message, correlationId, retryAfterSeconds? } }` with deterministic key order.
|
||||
- **Security**
|
||||
- OAuth2 client credentials; scopes: `export:write` (POST), `export:read` (GET/Download). Tenants enforced via claims.
|
||||
- **Headers**
|
||||
- `ETag` on all download/status responses; `Last-Modified` on status/download reflecting deterministic creation time.
|
||||
- Quota headers `X-Stella-Quota-*` retained for consistency with EvidenceLocker/ExportCenter.
|
||||
|
||||
## Versioning & determinism
|
||||
- OAS document served with `version: 1.0.0` and `x-stella-oas-revision` (UTC date string). No inline examples with non-deterministic timestamps; examples use `2025-01-01T00:00:00Z`.
|
||||
- All example hashes use fixed placeholder `sha256:0123...deadbeef` to keep docs repeatable.
|
||||
|
||||
## Deliverables
|
||||
- Publish OpenAPI YAML at `docs/modules/export-center/openapi/export-center.v1.yaml` matching the paths/schemas above.
|
||||
- Link the `.yaml` from Sprint 0162 Delivery Tracker P10 and set status to DONE once published.
|
||||
|
||||
## Acceptance criteria
|
||||
- All listed endpoints present in the YAML with request/response schemas and security scopes.
|
||||
- Deterministic examples (fixed timestamps/hashes) and `ETag`/`Last-Modified` response headers documented.
|
||||
- `/.well-known/openapi` discovery endpoint described with `ETag` and version headers.
|
||||
|
||||
## Next steps
|
||||
- Generate the YAML (can seed from EvidenceLocker/Orchestrator style) and check into `docs/modules/export-center/openapi/export-center.v1.yaml`.
|
||||
- Update SDK generator task (62-001) to depend on this OAS once merged.
|
||||
@@ -1,18 +0,0 @@
|
||||
# Export OAS Discovery Prep — PREP-EXPORT-OAS-61-002-DEPENDS-ON-61-001
|
||||
|
||||
Status: Draft (2025-11-20)
|
||||
Owners: Exporter Service Guild
|
||||
Scope: Define the OpenAPI discovery endpoint once base OAS (61-001) is frozen.
|
||||
|
||||
## Requirements
|
||||
- Endpoint: `GET /.well-known/openapi` (and `.json` alias) returning latest Exporter OAS.
|
||||
- Headers: `ETag`, `Last-Modified`, `Cache-Control: public, max-age=300`; support `If-None-Match` for 304.
|
||||
- Body: JSON with fields `{version, oas_url, checksum_sha256, generated_at, profiles_supported}` plus embedded OAS or link.
|
||||
- Determinism: stable ordering of fields; checksum over canonical OAS JSON.
|
||||
|
||||
## Acceptance
|
||||
- Once 61-001 OAS is fixed, publish generated OAS path and checksum into this doc and `docs/modules/export-center/api.md`.
|
||||
- Add sample discovery response at `docs/events/samples/export-center.openapi.discovery@draft.json`.
|
||||
|
||||
## Handoff
|
||||
Use this as the prep artefact for PREP-EXPORT-OAS-61-002-DEPENDS-ON-61-001. Update checksums/links when 61-001 finalizes, then mark implementation DOING.
|
||||
@@ -1,18 +0,0 @@
|
||||
# Export SDK Prep — PREP-EXPORT-OAS-62-001-DEPENDS-ON-61-002
|
||||
|
||||
Status: Draft (2025-11-20)
|
||||
Owners: Exporter Service Guild · SDK Generator Guild
|
||||
Scope: Capture SDK generation requirements once discovery endpoint (61-002) is live.
|
||||
|
||||
## Requirements
|
||||
- Inputs: stable OAS from 61-001, discovery metadata from 61-002.
|
||||
- SDKs: Go, Python, C#, TypeScript. Must include streaming helpers for export downloads and polling helpers for long-running export jobs.
|
||||
- Versioning: embed `x-sdk-version` matching OAS `version`; regenerate only on checksum change.
|
||||
- Tests: smoke tests per SDK calling stubbed endpoints; deterministic snapshots for generated code hashes.
|
||||
|
||||
## Acceptance
|
||||
- Record generated SDK artifact paths and checksums in this doc and `docs/modules/export-center/api.md`.
|
||||
- Provide sample snippet paths under `docs/modules/export-center/samples/sdk/` per language.
|
||||
|
||||
## Handoff
|
||||
Use this as the prep artefact for PREP-EXPORT-OAS-62-001-DEPENDS-ON-61-002. Update with actual checksums/paths after 61-002 and SDK generation are completed; then move implementation to DOING.
|
||||
@@ -1,15 +0,0 @@
|
||||
# Exporter Service Blocker — PREP-EXPORTER-SERVICE-BLOCKED-WAITING-ON-EVID
|
||||
|
||||
Status: Draft (2025-11-20)
|
||||
Owners: Planning
|
||||
Scope: Document EvidenceLocker dependency blocking exporter service.
|
||||
|
||||
## Blocker
|
||||
- EvidenceLocker spec not published; need replay/export bundle schemas and ICryptoProviderRegistry availability.
|
||||
|
||||
## What we need
|
||||
- Bundle schema pointers (from EvidenceLocker) and retention rules.
|
||||
- Sample payloads to mirror into exporter tests.
|
||||
|
||||
## Handoff
|
||||
Use this note to track unblock; update when EvidenceLocker spec is available.
|
||||
@@ -1,18 +0,0 @@
|
||||
# EvidenceLocker Contract Blocker Prep — PREP-EXPORTER-SERVICE-EVIDENCELOCKER-GUILD-BL
|
||||
|
||||
Status: Draft (2025-11-20)
|
||||
Owners: Planning · Exporter Service Guild · EvidenceLocker Guild
|
||||
Scope: Document the blocker awaiting EvidenceLocker sealed bundle contract before ExportCenter implementation can proceed.
|
||||
|
||||
## Blocking items
|
||||
- Sealed bundle schema/hash and DSSE layout from EvidenceLocker (Sprint 161).
|
||||
- Sample sealed bundle + manifest checksum for DevPortal CLI dry run.
|
||||
- Trust-root publication path and rotation policy aligned with `docs/security/crypto-registry-decision-2025-11-18.md`.
|
||||
|
||||
## Ready-to-start criteria
|
||||
- Hash/version of sealed bundle schema recorded here and in Sprint 161 Decisions.
|
||||
- Sample bundle placed under `docs/samples/export-center/bundles/` with SHA256 + DSSE envelope.
|
||||
- Exporter service ingestion contract updated in `docs/modules/export-center/profiles.md`.
|
||||
|
||||
## Handoff
|
||||
Use this document as the prep artefact for PREP-EXPORTER-SERVICE-EVIDENCELOCKER-GUILD-BL. Update once EvidenceLocker provides schema hash and sample bundle; then unblock export tasks. If not available by the next checkpoint, keep dependent tasks BLOCKED and escalate via Sprint 160/161.
|
||||
@@ -1,29 +0,0 @@
|
||||
# Export Notifications Schema Prep — PREP-EXPORT-NOTIFY-SCHEMA-OBS-52
|
||||
|
||||
Status: Draft (2025-11-20)
|
||||
Owners: Notifications Guild · Exporter Service
|
||||
Scope: Define notification envelope/payloads for export lifecycle events.
|
||||
|
||||
## Event types
|
||||
- `export.started`, `export.completed`, `export.failed`.
|
||||
|
||||
## Envelope (proposed)
|
||||
```json
|
||||
{
|
||||
"type": "export.completed",
|
||||
"export_id": "...",
|
||||
"profile_id": "...",
|
||||
"tenant_id": "...",
|
||||
"artifact_counts": {"json": 2, "mirror": 1},
|
||||
"sha256": "...",
|
||||
"created_at": "2025-11-20T00:00:00Z"
|
||||
}
|
||||
```
|
||||
- Deterministic key ordering; timestamps UTC.
|
||||
|
||||
## Open decisions
|
||||
- Channel/transport (NATS vs Redis streams vs webhooks).
|
||||
- Required retry/backoff policy and DLQ routing.
|
||||
|
||||
## Handoff
|
||||
Use this prep doc for PREP-EXPORT-NOTIFY-SCHEMA-OBS-52; update once transport + DLQ policy are chosen.
|
||||
@@ -1,17 +0,0 @@
|
||||
# Export Telemetry Prep — PREP-EXPORT-OBS-50-001
|
||||
|
||||
Status: Draft (2025-11-20)
|
||||
Owners: Exporter Service · Observability Guild
|
||||
Scope: Define telemetry schema for exporter service bootstrap.
|
||||
|
||||
## Proposed metrics/logs
|
||||
- Metrics (Prometheus/Otel): `export_runs_total{profile, tenant}`, `export_run_duration_seconds`, `export_artifacts_total{type}`, `export_failures_total`, `export_bytes_total`.
|
||||
- Logs: structured with fields `{export_id, profile, tenant, artifact_type, status, duration_ms}`.
|
||||
- Traces: span names `export.run`, `export.plan`, `export.write`; tags include `profile`, `tenant`, `artifact_count`.
|
||||
|
||||
## Open decisions
|
||||
- Histogram buckets for duration/bytes.
|
||||
- Required correlation IDs for downstream Console ingestion.
|
||||
|
||||
## Handoff
|
||||
Use this as PREP artefact for EXPORT-OBS-50-001; update buckets and trace tags once Observability finalizes naming.
|
||||
@@ -1,21 +0,0 @@
|
||||
# Export Risk Bundle Prep — PREP-EXPORT-RISK-69-001
|
||||
|
||||
Status: Draft (2025-11-20)
|
||||
Owners: Exporter Service · Risk Bundle Export Guild
|
||||
Scope: Capture provider selection rules and schema needs for risk bundle job handler.
|
||||
|
||||
## Provider selection (proposed)
|
||||
- Inputs: `risk_profile_id`, `tenant_id`, `preferred_provider`, `fallback_provider`.
|
||||
- Selection order: tenant override → profile default → system default.
|
||||
- Providers must advertise capabilities `{formats[], signing_profiles[]}`.
|
||||
|
||||
## Manifest expectations
|
||||
- Fields: `bundle_id`, `profile_id`, `provider_id`, `inputs_hash`, `created_at`, `artifacts[] {path, sha256, media_type}`.
|
||||
- Deterministic ordering and sha256 for all artifacts.
|
||||
|
||||
## Open decisions
|
||||
- Final list of providers and signing profiles.
|
||||
- Whether to embed policy/export bundle pointers.
|
||||
|
||||
## Handoff
|
||||
Use this as PREP artefact for EXPORT-RISK-69-001; update provider list and manifest once phase I artifacts land.
|
||||
@@ -1,21 +0,0 @@
|
||||
# Export Service Bootstrap Prep — PREP-EXPORT-SVC-35-001
|
||||
|
||||
Status: Draft (2025-11-20)
|
||||
Owners: Exporter Service
|
||||
Scope: Capture phase I readiness for exporter service project/migrations.
|
||||
|
||||
## Project baseline
|
||||
- Service: minimal API (net10.0), Postgres storage for `export_profiles`, `export_runs`, `export_inputs`, `export_distributions`.
|
||||
- Tests: xUnit + integration harness with deterministic timestamps.
|
||||
|
||||
## Schema notes
|
||||
- `export_profiles`: `{id, name, tenant_id?, config_json}`.
|
||||
- `export_runs`: `{id, profile_id, tenant_id, status, started_at, completed_at, artifact_counts JSONB}`.
|
||||
- Deterministic defaults: UTC timestamps; snake_case columns.
|
||||
|
||||
## Open decisions
|
||||
- Final Postgres schema (indices, enums for status).
|
||||
- Whether to store metrics snapshots inline or via observability pipeline.
|
||||
|
||||
## Handoff
|
||||
Use this as PREP artefact for EXPORT-SVC-35-001; update once phase I readiness and synthetic telemetry feeds are defined.
|
||||
@@ -1,20 +0,0 @@
|
||||
# Export Service Planner Prep — PREP-EXPORT-SVC-35-002
|
||||
|
||||
Status: Draft (2025-11-20)
|
||||
Owners: Exporter Service
|
||||
Scope: Planner + scope resolver for exports, depends on 35-001 bootstrap.
|
||||
|
||||
## Planner inputs
|
||||
- `profile_id`, `tenant_id`, `inputs` (bundle pointers), `priority`.
|
||||
- `limits`: max artifacts, max runtime.
|
||||
|
||||
## Outputs
|
||||
- Plan document `{plan_id, profile_id, tenant_id, steps[], estimated_bytes, estimated_duration_ms}`.
|
||||
- Steps sorted; deterministic hashing of plan.
|
||||
|
||||
## Open decisions
|
||||
- Step types allowed (json adapters, mirror, manifest signing).
|
||||
- How to surface rejection reasons to upstream services.
|
||||
|
||||
## Handoff
|
||||
Use as prep artefact; update once 35-001 schema is fixed.
|
||||
@@ -1,16 +0,0 @@
|
||||
# Export JSON Adapter Prep — PREP-EXPORT-SVC-35-003
|
||||
|
||||
Status: Draft (2025-11-20)
|
||||
Owners: Exporter Service
|
||||
Scope: JSON adapters (`json:raw`, `json:policy`) normalization/redaction/compression.
|
||||
|
||||
## Deliverable shape
|
||||
- Adapter config: `{type, redactions[], compress: bool, normalize_paths: bool}`.
|
||||
- Output manifest entry: `{path, sha256, media_type, original_size, compressed_size?}`.
|
||||
|
||||
## Open decisions
|
||||
- Redaction rules list and ordering.
|
||||
- Compression algorithm (gzip vs zstd) and level defaults.
|
||||
|
||||
## Handoff
|
||||
Prep artefact for 35-003; align with plan model once 35-002 is fixed.
|
||||
@@ -1,17 +0,0 @@
|
||||
# Export Mirror Adapter Prep — PREP-EXPORT-SVC-35-004
|
||||
|
||||
Status: Draft (2025-11-20)
|
||||
Owners: Exporter Service
|
||||
Scope: Mirror (full) adapter producing filesystem layout, indexes, manifests, README.
|
||||
|
||||
## Layout proposal
|
||||
- root manifest `mirror.manifest.json` with Merkle root.
|
||||
- Directories: `artifacts/`, `indexes/`, `docs/README.md`.
|
||||
- Deterministic ordering, UTC timestamps.
|
||||
|
||||
## Open decisions
|
||||
- Which indexes required (by profile vs dataset).
|
||||
- Manifest fields alignment with Mirror thin bundle.
|
||||
|
||||
## Handoff
|
||||
Use as prep artefact; fill fields once 35-003 outputs and mirror schema decisions are in.
|
||||
@@ -1,16 +0,0 @@
|
||||
# Export Manifest/Signing Prep — PREP-EXPORT-SVC-35-005
|
||||
|
||||
Status: Draft (2025-11-20)
|
||||
Owners: Exporter Service · Security Guild
|
||||
Scope: Manifest/provenance writer + KMS signing/attestation.
|
||||
|
||||
## Proposed manifest
|
||||
- `export_id`, `profile_id`, `tenant_id`, `artifacts[] {path, sha256, media_type}`, `created_at`, `inputs_hash`, `signatures[]`.
|
||||
- DSSE envelope for manifest; signer from ICryptoProviderRegistry.
|
||||
|
||||
## Open decisions
|
||||
- Signing profile list and KMS/HSM mapping.
|
||||
- Rekor/Transparency use in offline vs online.
|
||||
|
||||
## Handoff
|
||||
Prep artefact for 35-005; update once crypto profile and provider registry decisions land.
|
||||
@@ -1,19 +0,0 @@
|
||||
# Ledger OAS Prep — PREP-LEDGER-OAS-61-001/61-002/62-001/63-001
|
||||
|
||||
Status: Draft (2025-11-20)
|
||||
Owners: Findings Ledger Guild · API Contracts Guild · SDK Generator Guild
|
||||
Scope: Capture OAS baseline, HTTP surface, SDK generation, and deprecation flow for ledger service.
|
||||
|
||||
## What’s needed
|
||||
- Baseline OAS for ledger API host (61-001).
|
||||
- Confirm endpoints and auth scopes to publish (61-002 depends on 61-001).
|
||||
- SDK generation targets and language list (62-001).
|
||||
- Deprecation header plan once SDK validated (63-001).
|
||||
|
||||
## Open decisions
|
||||
- Hostname/versioning scheme for ledger API.
|
||||
- Auth scopes per endpoint.
|
||||
- Languages for SDK generation and package naming.
|
||||
|
||||
## Handoff
|
||||
Use this prep doc for LEDGER-OAS-61-001/61-002/62-001/63-001; update once API contract is drafted.
|
||||
@@ -1,22 +0,0 @@
|
||||
# Ledger Observability Prep — PREP-LEDGER-OBS-54-001
|
||||
|
||||
Status: Prep complete (2025-11-20)
|
||||
Owners: Findings Ledger Guild · Provenance Guild
|
||||
Scope: Minimal HTTP surface plus determinism/telemetry hooks for `/v1/ledger/attestations`.
|
||||
|
||||
## Agreed contract (PREP-LEDGER-OBS-54-001)
|
||||
- HTTP surface published in `docs/modules/findings-ledger/prep/ledger-attestations-http.md`.
|
||||
- Endpoint: `GET /v1/ledger/attestations` with tenant header `X-Stella-Tenant` and bearer scope `ledger.attest.read` (or mTLS).
|
||||
- Filters: `artifactId`, `findingId`, `attestationId`, `status`, `sinceRecordedAt`, `untilRecordedAt`, `limit`.
|
||||
- Ordering/pagination: deterministic by `recordedAt ASC, attestationId ASC`; pagination token encodes `{recordedAt, attestationId, filtersHash}`.
|
||||
- Response shape (JSON or NDJSON): ids, verification status/time, DSSE digest, optional Rekor entry id, evidence bundle ref, source ledger event id, Merkle leaf + root hashes.
|
||||
- Offline posture: no live Rekor calls; all hashes lowercase SHA-256; times UTC; deterministic sort only.
|
||||
|
||||
## Telemetry hooks
|
||||
- Log events: `ledger.attestations.query` (tenant, filtersHash, limit, duration_ms, result_count).
|
||||
- Metrics: `ledger_attestations_queries_total{tenant,status}`; `ledger_attestations_failures_total{reason}`.
|
||||
- Tracing: span `ledger.attestations.query` with attributes `filtersHash`, `next_page_token_present`.
|
||||
|
||||
## Handoff
|
||||
- Use `docs/modules/findings-ledger/prep/ledger-attestations-http.md` as the binding prep artefact for LEDGER-OBS-54-001 / 55-001 implementation.
|
||||
- Service scaffolding and OAS wiring land in LEDGER-OBS-54-001 once the web-service handler is added.
|
||||
@@ -1,52 +0,0 @@
|
||||
# Ledger Packs Snapshot Prep — PREP-LEDGER-PACKS-42-001
|
||||
|
||||
Status: Prep complete (2025-11-20)
|
||||
Owners: Findings Ledger Guild · Mirror Creator Guild
|
||||
Scope: Snapshot/time-travel contract for packs simulation and offline CLI execution (PREP-LEDGER-PACKS-42-001).
|
||||
|
||||
## Goals
|
||||
- Provide deterministic, tenant-scoped snapshots that let pack runners/CLI replay ledger state offline.
|
||||
- Allow “time-travel” queries (choose exact ledger sequence/cycle) to debug policy outcomes.
|
||||
- Reuse existing export shapes where possible and avoid redundant DB projections.
|
||||
|
||||
## Surfaces
|
||||
- `GET /v1/ledger/packs/snapshots`
|
||||
- Headers: `X-Stella-Tenant` (required), bearer scope `ledger.packs.read`.
|
||||
- Query: `atSequence` (long, optional), `atCycleHash` (string, optional), `sinceSequence` / `untilSequence` (long, optional), `page_size` (default 100, max 1000), `page_token`.
|
||||
- Returns: list of available snapshot descriptors (JSON or NDJSON) sorted by `sequence ASC`.
|
||||
- `GET /v1/ledger/packs/snapshots/{snapshotId}/download`
|
||||
- Streams a gzip tarball containing the snapshot bundle (see layout).
|
||||
- Supports `Accept: application/vnd.stella.pack-snapshot+tar` (default) or `application/x-ndjson` for manifest-only dry-run (no payload files) when `Prefer: return=representation` is absent.
|
||||
|
||||
## Snapshot descriptor fields
|
||||
- `snapshot_id` (uuid, stable)
|
||||
- `tenant`
|
||||
- `base_sequence` (long) — earliest ledger event included
|
||||
- `upper_sequence` (long) — last ledger event included (inclusive)
|
||||
- `cycle_hash` (string) — Merkle cycle hash at `upper_sequence`
|
||||
- `policy_version`, `projector_version`, `generator_version`
|
||||
- `created_at` (ISO-8601 UTC)
|
||||
- `approx_uncompressed_size_bytes`
|
||||
- `content` summary: counts for `findings`, `vex`, `advisories`, `sboms`
|
||||
|
||||
## Bundle layout (tar.gz)
|
||||
- `manifest.json`: descriptor above plus SHA-256 digests and lengths for each payload file.
|
||||
- `findings.ndjson`: canonical finding shape matching `/ledger/export/findings`.
|
||||
- `vex.ndjson`, `advisories.ndjson`, `sboms.ndjson`: same shapes/filters as export endpoints.
|
||||
- `indexes/`: optional bloom/filter helpers for fast CLI lookup (`component_purl`, `advisory_id`, `risk_profile_version`).
|
||||
- `provenance.json`: DSSE envelope with bundle hash, generator inputs (seed, source commit, policy version).
|
||||
|
||||
## Determinism and filters
|
||||
- Snapshot is deterministic for a given `(tenant, base_sequence, upper_sequence, cycle_hash, policy_version)`.
|
||||
- Page tokens: base64url JSON `{ "last": { "upper_sequence": long, "snapshot_id": uuid }, "filters_hash": sha256 }`.
|
||||
- When `atCycleHash` is provided, server resolves the closest <=matching cycle and emits one descriptor; otherwise uses `untilSequence` or latest committed.
|
||||
- No wall-clock dependence; `created_at` reflects generator runtime but is stored once and signed in provenance.
|
||||
|
||||
## Validation rules
|
||||
- Reject overwrite if snapshot with identical `(tenant, upper_sequence, cycle_hash)` already published (idempotent response with existing `snapshot_id`).
|
||||
- Reject if requested window crosses projector gap (missing sequences) with error `409` and `X-Stella-Gap-From/To`.
|
||||
- Enforce `page_size` consistency across tokens; 400 on mismatch.
|
||||
|
||||
## Artefact location
|
||||
- This prep: `docs/modules/findings-ledger/prep/2025-11-20-ledger-packs-42-001-prep.md`.
|
||||
- Bundle schema is derived from export shapes in `docs/modules/findings-ledger/export-http-surface.md`; SDK/OAS plumbing to be added in LEDGER-PACKS-42-001 implementation.
|
||||
@@ -1,50 +0,0 @@
|
||||
# Ledger Risk Schema Prep — PREP-LEDGER-RISK-66-001/002
|
||||
|
||||
Status: Prep complete (2025-11-20)
|
||||
Owners: Findings Ledger Guild · Risk Engine Guild
|
||||
Scope: Contract + data model for PREP-LEDGER-RISK-66-001/002 (risk scoring fields and deterministic upsert).
|
||||
|
||||
## Field definitions (canonical finding projection)
|
||||
- `risk_score` (numeric, 0–100, 2dp) — monotonic per `(finding_id, profile_version)`; computed by Risk Engine.
|
||||
- `risk_severity` (enum) — derived mapping: `critical >= 90`, `high >= 70`, `medium >= 40`, `low >= 10`, `informational < 10`.
|
||||
- `risk_profile_version` (string) — semantic version of the scoring policy/profile; required.
|
||||
- `risk_explanation_id` (uuid/string) — pointer to Risk Engine explanation payload stored in Risk service (not duplicated in ledger).
|
||||
- `risk_event_sequence` (long) — ledger sequence of the last applied risk event; enforces monotonic updates.
|
||||
- `risk_updated_at` (ISO-8601 UTC) — when the score was last written.
|
||||
|
||||
## Storage and indexes (MongoDB)
|
||||
- Collection: `findings` (existing). Add fields above to the projection document.
|
||||
- Unique compound index: `{ tenant: 1, finding_id: 1, risk_profile_version: 1 }`.
|
||||
- Query helper index for exports/UI: `{ tenant: 1, risk_severity: 1, risk_score: -1, observed_at: -1 }`.
|
||||
- TTL: none; scores are historical but superseded by deterministic upsert described below.
|
||||
|
||||
## Deterministic upsert flow (LEDGER-RISK-66-002)
|
||||
1. Risk Engine emits `RiskScoreApplied` event with `{tenant, finding_id, profile_version, score, explanation_id, event_sequence}`.
|
||||
2. Handler loads current projection by `(tenant, finding_id)`; compares `(profile_version, event_sequence)`:
|
||||
- If incoming `event_sequence` < stored `risk_event_sequence` → ignore (idempotent).
|
||||
- If equal → idempotent update allowed only when score/severity unchanged.
|
||||
- If greater → write new values and set `risk_event_sequence = event_sequence`.
|
||||
3. All writes recorded in ledger append with same event_sequence for audit; projection updates deterministic by sequence ordering.
|
||||
4. Exports (`/ledger/export/findings`) surface these fields; snapshot bundles reuse the same shape.
|
||||
|
||||
## API/SDK contract hooks
|
||||
- OAS baseline will mark all four fields in the finding shapes (canonical + compact) as optional today, required once migrations finish.
|
||||
- `/ledger/export/findings` filters: `risk_profile_version` (already reserved), add `risk_severity` and `risk_score_min/max` in the next OAS bump.
|
||||
- UI/SDK must treat missing `risk_profile_version` as “not yet scored”.
|
||||
|
||||
## Migration/rollout plan (LEDGER-RISK-66-001)
|
||||
- Step 1: Add fields and indexes behind feature flag `RiskScoringEnabled` (default off).
|
||||
- Step 2: Backfill for latest profile per tenant using Risk Engine batch export; write via deterministic upsert to enforce ordering.
|
||||
- Step 3: Enable streaming ingestion of `RiskScoreApplied` events; monitor lag via metric `ledger_risk_score_apply_lag_seconds`.
|
||||
- Step 4: Flip default for `RiskScoringEnabled` to on after backfill success criteria:
|
||||
- 99.9% of existing findings have `risk_profile_version` populated.
|
||||
- No rejected events due to sequence regressions in the last 24h.
|
||||
- Step 5: Update OAS/SDK to mark fields required; notify UI/Export consumers.
|
||||
|
||||
## Observability
|
||||
- Log: `ledger.risk.apply` with tenant, finding_id, profile_version, score, event_sequence, applied (bool).
|
||||
- Metrics: `ledger_risk_apply_total{result}`; `ledger_risk_score_latest{severity}` gauges per tenant.
|
||||
- Tracing: span `ledger.risk.apply` tagging `profile_version`, `event_sequence`, `idempotent`.
|
||||
|
||||
## Handoff
|
||||
- This document is the prep artefact for PREP-LEDGER-RISK-66-001/002. Implementation tasks wire schema + deterministic upsert and extend exports/OAS accordingly.
|
||||
@@ -1,17 +0,0 @@
|
||||
# Ledger Risk Prep — PREP-LEDGER-RISK-68-001 / 69-001 / TEN-48-001
|
||||
|
||||
Status: Draft (2025-11-20)
|
||||
Owners: Findings Ledger Guild · Export Guild · Observability Guild · Platform
|
||||
|
||||
## 68-001 (scored findings export) needs
|
||||
- Inputs from 67-001 + Export Center contract for scored findings.
|
||||
- Metrics dimensions alignment with Observability.
|
||||
|
||||
## 69-001 (metrics) needs
|
||||
- Final metrics fields driven by 67-001/68-001 outputs.
|
||||
|
||||
## TEN-48-001 (RLS/partitioning) needs
|
||||
- Platform-approved tenant/project partitioning and RLS policy.
|
||||
|
||||
## Handoff
|
||||
Use as PREP artefact for the above tasks; update when upstream exports and RLS decisions are available.
|
||||
@@ -1,33 +0,0 @@
|
||||
# Findings Ledger Prep — 29-008, 34-101, AIRGAP-56-001
|
||||
|
||||
Status: **Ready for implementation** (2025-11-22)
|
||||
Owners: Findings Ledger Guild · Observability Guild · AirGap Time Guild · Orchestrator Guild
|
||||
Scope: Provide the missing contracts needed to unblock LEDGER-29-008 load/replay, LEDGER-34-101 orchestrator export linkage, and LEDGER-AIRGAP-56-001 bundle provenance recording.
|
||||
|
||||
## Observability (LEDGER-29-008)
|
||||
- Metrics schema locked:
|
||||
- `ledger_projection_lag_seconds{tenant}` (gauge)
|
||||
- `ledger_write_duration_seconds_bucket` (histogram)
|
||||
- `ledger_events_total{tenant,kind}` (counter)
|
||||
- Alert: burn-rate 4xx/5xx on ingestion path >2% over 5m/1h.
|
||||
- Log fields: `tenantId`, `requestId`, `projectionCheckpoint`, `bundleId?`, `attestationId?`, `operation`.
|
||||
- Trace spans: `ledger.write`, `ledger.replay`, `ledger.restore` with baggage `tenant-id`, `bundle-id`.
|
||||
|
||||
## Orchestrator export linkage (LEDGER-34-101)
|
||||
- Export payload shape (from Orchestrator Sprint 150.A):
|
||||
- `runId` (uuid), `jobType`, `artifactHash`, `policyHash`, `startedAt`, `completedAt`, `status`, `manifestPath`, `logsPath`.
|
||||
- Ledger integration rule: store export rows under collection `orchestrator_exports` with index `(artifactHash, runId)`; anchor Merkle root into ledger timeline entry `ledger_export` referencing above fields.
|
||||
|
||||
## AirGap provenance (LEDGER-AIRGAP-56-001)
|
||||
- Mirror bundle contract alignment:
|
||||
- fields recorded per import: `bundleId`, `mirrorGeneration`, `merkleRoot`, `timeAnchor`, `publisher`, `hashAlgorithm`, `contents[]` (sha256 of NDJSON segments).
|
||||
- determinism: imports sorted by `bundleId`; all timestamps UTC.
|
||||
- API for recording import: `POST /internal/ledger/airgap-import` with payload above; respond 202 + `ledgerEntryId`.
|
||||
|
||||
## Acceptance Criteria
|
||||
- Metrics/log/logging names frozen as above and added to `docs/modules/findings-ledger/observability.md` in next implementation step.
|
||||
- Orchestrator export payload shape referenced by both Ledger and Orchestrator tasks; no missing fields for audit.
|
||||
- AirGap import payload is deterministic and replays without external network requirements.
|
||||
|
||||
## Notes
|
||||
- Satisfies PREP-LEDGER-29-008-AWAIT-OBSERVABILITY-SCHEMA, PREP-LEDGER-34-101-ORCHESTRATOR-LEDGER-EXPORT, and PREP-LEDGER-AIRGAP-56-001-MIRROR-BUNDLE-SCHEM.
|
||||
@@ -1,37 +0,0 @@
|
||||
# Verification Event Contract (attestations → ledger_attestations)
|
||||
|
||||
Status: Draft (2025-11-21)
|
||||
Owners: Provenance Guild · Findings Ledger Guild
|
||||
|
||||
Purpose: unblock LEDGER-OBS-54-001 by defining the ingestion event emitted by the verifier so we can populate `ledger_attestations`.
|
||||
|
||||
```
|
||||
event_type: verification.attestation.completed
|
||||
payload:
|
||||
tenant_id: string (required)
|
||||
attestation_id: uuid (required)
|
||||
artifact_id: string (required; OCI digest or SBOM id)
|
||||
finding_id: string (optional)
|
||||
verification_status: string enum [verified, failed, unknown] (required)
|
||||
verification_time: string (ISO-8601 UTC, required)
|
||||
dsse_digest: string (sha256, lowercase, required)
|
||||
rekor_entry_id: string (optional)
|
||||
evidence_bundle_ref: string (optional)
|
||||
merkle_leaf_hash: string (sha256, required)
|
||||
root_hash: string (sha256, required)
|
||||
cycle_hash: string (required)
|
||||
projection_version: string (required)
|
||||
```
|
||||
|
||||
Ordering/monotonicity:
|
||||
- Events are emitted with a ledger `sequence_no`. Ingestion must ignore any verification event with `sequence_no` less than the stored `risk_event_sequence` for the same `(tenant_id, attestation_id)`.
|
||||
|
||||
Determinism for ingestion:
|
||||
- Sort by `(sequence_no ASC, attestation_id ASC)` before upsert.
|
||||
- Upsert target: `ledger_attestations` (see `004_ledger_attestations.sql`).
|
||||
|
||||
Open question:
|
||||
- Should `verification_status` include `expired`/`revoked`? Need decision before marking schema final.
|
||||
|
||||
Next step:
|
||||
- Once the verifier confirms this payload, wire ingestion job to project into `ledger_attestations` and flip LEDGER-OBS-54-001 to DOING.
|
||||
@@ -1,39 +0,0 @@
|
||||
# Ledger attestation HTTP surface (prep for LEDGER-OBS-54-001 / 55-001)
|
||||
|
||||
**Goal.** Provide the minimal HTTP contract to expose ledger attestation verifications so PREP-LEDGER-OBS-55-001 can proceed. This complements the OAS baseline (`docs/modules/findings-ledger/openapi/findings-ledger.v1.yaml`) and schema (`docs/modules/findings-ledger/schema.md`).
|
||||
|
||||
## Endpoint
|
||||
- `GET /v1/ledger/attestations`
|
||||
- Tenant header: `X-Stella-Tenant` (required).
|
||||
- Auth: bearer `scope=ledger.attest.read` or mTLS.
|
||||
- Query params:
|
||||
- `artifactId` (string, optional; OCI digest or SBOM id)
|
||||
- `findingId` (string, optional)
|
||||
- `attestationId` (uuid, optional)
|
||||
- `status` (`verified|failed|unknown`, optional)
|
||||
- `sinceRecordedAt` / `untilRecordedAt` (ISO-8601 UTC)
|
||||
- `limit` (int, default 200, max 1000)
|
||||
- Ordering: deterministic by `recordedAt ASC, attestationId ASC`.
|
||||
- Response: JSON array (or NDJSON when `Accept: application/x-ndjson`). Each item:
|
||||
- `attestationId` (uuid)
|
||||
- `artifactId` (string)
|
||||
- `findingId` (string)
|
||||
- `verificationStatus` (`verified|failed|unknown`)
|
||||
- `verificationTime` (ISO-8601 UTC)
|
||||
- `dsseDigest` (sha256)
|
||||
- `rekorEntryId` (string, optional)
|
||||
- `evidenceBundleRef` (string, optional)
|
||||
- `ledgerEventId` (uuid) — source ledger event that linked the attestation
|
||||
- `recordedAt` (ISO-8601 UTC)
|
||||
- `merkleLeafHash` (sha256)
|
||||
- `rootHash` (sha256)
|
||||
|
||||
## Determinism/offline posture
|
||||
- Sorting keys are fixed; pagination token encodes `{recordedAt, attestationId, filtersHash}`.
|
||||
- No live Rekor calls; `rekorEntryId` is stored reference only.
|
||||
- Hashes remain lowercase SHA-256; times are UTC.
|
||||
|
||||
## Artefact location
|
||||
- This prep doc: `docs/modules/findings-ledger/prep/ledger-attestations-http.md`.
|
||||
- Storage/view contract: `docs/modules/findings-ledger/prep/ledger-attestations-storage.md`.
|
||||
- Add path to OAS in a follow-on increment (LEDGER-OAS-61-002/63-001) once approved.
|
||||
@@ -1,54 +0,0 @@
|
||||
# Ledger Attestations Storage & Query Contract (LEDGER-OBS-54-001)
|
||||
|
||||
Status: PrepComplete (2025-11-20)
|
||||
Owners: Findings Ledger Guild · Provenance Guild
|
||||
|
||||
## Goal
|
||||
Provide a deterministic storage/view contract so the `/v1/ledger/attestations` endpoint can be implemented without further design work.
|
||||
|
||||
## Table (proposed)
|
||||
- Name: `ledger_attestations`
|
||||
- Partitioning: tenant-scoped (same strategy as `ledger_events`).
|
||||
- Columns:
|
||||
- `tenant_id` (text, not null)
|
||||
- `attestation_id` (uuid, not null)
|
||||
- `artifact_id` (text, not null) — OCI digest or SBOM id
|
||||
- `finding_id` (text, null)
|
||||
- `verification_status` (text, not null; `verified|failed|unknown`)
|
||||
- `verification_time` (timestamptz, not null)
|
||||
- `dsse_digest` (text, not null; lowercase sha256)
|
||||
- `rekor_entry_id` (text, null)
|
||||
- `evidence_bundle_ref` (text, null)
|
||||
- `ledger_event_id` (uuid, not null) — source ledger event linking the attestation
|
||||
- `recorded_at` (timestamptz, not null)
|
||||
- `merkle_leaf_hash` (text, not null)
|
||||
- `root_hash` (text, not null)
|
||||
- `cycle_hash` (text, not null)
|
||||
- `projection_version` (text, not null)
|
||||
|
||||
## Indexes / ordering
|
||||
- PK: `(tenant_id, attestation_id)`
|
||||
- Paging index: `(tenant_id, recorded_at, attestation_id)` to back deterministic sort `recorded_at ASC, attestation_id ASC`.
|
||||
- Lookup indexes:
|
||||
- `(tenant_id, artifact_id, recorded_at DESC)`
|
||||
- `(tenant_id, finding_id, recorded_at DESC)`
|
||||
- `(tenant_id, verification_status, recorded_at DESC)`
|
||||
|
||||
## Query contract for `/v1/ledger/attestations`
|
||||
- Filters map to indexed columns: `artifactId`, `findingId`, `attestationId`, `status`, `sinceRecordedAt`, `untilRecordedAt`.
|
||||
- Pagination token encodes `{ recordedAt, attestationId, filtersHash }`; server must reject mismatched hash.
|
||||
- Response fields align 1:1 with columns above; no joins required.
|
||||
- Determinism: sort strictly by `(recorded_at ASC, attestation_id ASC)`; no server clocks in payload.
|
||||
|
||||
## Migration notes
|
||||
- Add table and indexes in the same migration (see `src/Findings/StellaOps.Findings.Ledger/migrations/004_ledger_attestations.sql`).
|
||||
- Backfill from existing provenance/verification store (if present) into this table with recorded_at = original verification timestamp.
|
||||
- Ensure writes/coalescing happen via ledger projections to keep `ledger_event_id`/`cycle_hash` consistent.
|
||||
|
||||
## Observability
|
||||
- Logs: `ledger.attestations.query` (tenant, filtersHash, limit, duration_ms, result_count).
|
||||
- Metrics: `ledger_attestations_queries_total{tenant,status}`, `ledger_attestations_failures_total{reason}`; reuse endpoint spans already defined in prep doc.
|
||||
|
||||
## Artefact location
|
||||
- Storage contract: `docs/modules/findings-ledger/prep/ledger-attestations-storage.md`
|
||||
- HTTP contract: `docs/modules/findings-ledger/prep/ledger-attestations-http.md`
|
||||
@@ -1,8 +1,9 @@
|
||||
# Gateway · Identity Header Policy for Router Dispatch (Draft v0.1)
|
||||
# Gateway · Identity Header Policy for Router Dispatch
|
||||
|
||||
## Status
|
||||
- Draft; intended for implementation via a dedicated sprint.
|
||||
- Last updated: 2025-12-23 (UTC).
|
||||
- **Implemented** in Sprint 8100.0011.0002.
|
||||
- Middleware: `src/Gateway/StellaOps.Gateway.WebService/Middleware/IdentityHeaderPolicyMiddleware.cs`
|
||||
- Last updated: 2025-12-24 (UTC).
|
||||
|
||||
## Why This Exists
|
||||
The Gateway is the single HTTP ingress point and routes requests to internal microservices over Router transports. Many services (and legacy components) still rely on **header-based identity context** (tenant/scopes/actor) rather than (or in addition to) `HttpContext.User` claims.
|
||||
@@ -11,16 +12,17 @@ This creates a hard security requirement:
|
||||
- **Clients must never be able to inject/override “roles/scopes” headers** that the downstream service trusts.
|
||||
- The Gateway must derive the effective identity from the validated JWT/JWK token (or explicit anonymous identity) and **overwrite** downstream identity headers accordingly.
|
||||
|
||||
## Current State (Repo Reality)
|
||||
The Gateway WebService currently contains middleware that propagates claims into request headers:
|
||||
- `src/Gateway/StellaOps.Gateway.WebService/Middleware/ClaimsPropagationMiddleware.cs`
|
||||
- `src/Gateway/StellaOps.Gateway.WebService/Middleware/TenantMiddleware.cs`
|
||||
## Implementation
|
||||
|
||||
### Known gaps vs intended behavior
|
||||
1) **Spoofing risk:** claim propagation uses “set if missing”, so client-supplied headers can pass through unmodified.
|
||||
2) **Claim type mismatch:** current middleware uses `tid`, but canonical tenant claim type is `stellaops:tenant` (`StellaOpsClaimTypes.Tenant`).
|
||||
3) **Scope claim mismatch:** tokens may use `scp` (individual scope items) and/or `scope` (space-separated). Current middleware reads only `scope`.
|
||||
4) **Docs drift:** `docs/api/gateway/tenant-auth.md` describes `X-Stella-*` headers and scope override behavior that is not implemented in the Gateway WebService.
|
||||
The `IdentityHeaderPolicyMiddleware` (introduced in Sprint 8100.0011.0002) replaces the legacy middleware:
|
||||
- ~~`src/Gateway/StellaOps.Gateway.WebService/Middleware/ClaimsPropagationMiddleware.cs`~~ (retired)
|
||||
- ~~`src/Gateway/StellaOps.Gateway.WebService/Middleware/TenantMiddleware.cs`~~ (retired)
|
||||
|
||||
### Resolved issues
|
||||
1) **Spoofing risk:** ✅ Fixed. Middleware uses "strip-and-overwrite" semantics—reserved headers are stripped before claims are extracted and downstream headers are written.
|
||||
2) **Claim type mismatch:** ✅ Fixed. Middleware uses `StellaOpsClaimTypes.Tenant` (`stellaops:tenant`) with fallback to legacy `tid` claim.
|
||||
3) **Scope claim mismatch:** ✅ Fixed. Middleware extracts scopes from both `scp` (individual claims) and `scope` (space-separated) claims.
|
||||
4) **Docs alignment:** ✅ Reconciled in this sprint.
|
||||
|
||||
## Policy Goals
|
||||
- **No client-controlled identity headers:** the Gateway rejects or strips identity headers coming from external clients.
|
||||
@@ -83,21 +85,45 @@ Draft enforcement:
|
||||
- Optional controlled override: allow only when `Gateway:Auth:AllowScopeHeader=true`, and only for explicitly allowed environments (offline/pre-prod).
|
||||
- Even when allowed, the override must not silently escalate a request beyond what the token allows unless the request is explicitly unauthenticated and the environment is configured for offline operation.
|
||||
|
||||
## Implementation Notes (Draft)
|
||||
### Suggested refactor
|
||||
Replace the current “set-if-missing” propagation with a single middleware:
|
||||
- `IdentityHeaderPolicyMiddleware`
|
||||
- strips reserved headers
|
||||
- overwrites headers from claims
|
||||
- stores normalized values in `HttpContext.Items` (tenant, actor, scope set) for use by rate limits, routing decisions, and audit logs
|
||||
## Implementation Details
|
||||
|
||||
### Middleware Registration
|
||||
The middleware is registered in `Program.cs` after authentication:
|
||||
```csharp
|
||||
app.UseAuthentication();
|
||||
app.UseMiddleware<SenderConstraintMiddleware>();
|
||||
app.UseMiddleware<IdentityHeaderPolicyMiddleware>();
|
||||
```
|
||||
|
||||
### Configuration
|
||||
Options are configured via `GatewayOptions.Auth`:
|
||||
```yaml
|
||||
Gateway:
|
||||
Auth:
|
||||
EnableLegacyHeaders: true # Write X-Stella-* in addition to X-StellaOps-*
|
||||
AllowScopeHeader: false # Forbid client scope headers (default)
|
||||
```
|
||||
|
||||
### HttpContext.Items Keys
|
||||
The middleware stores normalized identity in `HttpContext.Items` using `GatewayContextKeys`:
|
||||
- `Gateway.TenantId` — extracted tenant identifier
|
||||
- `Gateway.ProjectId` — extracted project identifier (optional)
|
||||
- `Gateway.Actor` — subject/actor from claims or "anonymous"
|
||||
- `Gateway.Scopes` — `HashSet<string>` of scopes
|
||||
- `Gateway.IsAnonymous` — `bool` indicating anonymous request
|
||||
- `Gateway.DpopThumbprint` — JKT from cnf claim (if present)
|
||||
- `Gateway.CnfJson` — raw cnf claim JSON (if present)
|
||||
|
||||
### Tests
|
||||
- Unit tests: spoofed identity headers are removed and overwritten.
|
||||
- Unit tests: claim type mapping uses `StellaOpsClaimTypes.*` correctly.
|
||||
- Integration tests: routed request arrives at microservice with correct identity headers.
|
||||
Located in `src/Gateway/__Tests/StellaOps.Gateway.WebService.Tests/Middleware/IdentityHeaderPolicyMiddlewareTests.cs`:
|
||||
- ✅ Spoofed identity headers are stripped and overwritten
|
||||
- ✅ Claim type mapping uses `StellaOpsClaimTypes.*` correctly
|
||||
- ✅ Anonymous requests receive explicit `anonymous` identity
|
||||
- ✅ Legacy headers are written when `EnableLegacyHeaders=true`
|
||||
- ✅ Scopes are sorted deterministically
|
||||
|
||||
## Related Documents
|
||||
- Gateway architecture: `docs/modules/gateway/architecture.md`
|
||||
- Tenant auth contract (Web V): `docs/api/gateway/tenant-auth.md` (note: currently drifts from implementation)
|
||||
- Tenant auth contract (Web V): `docs/api/gateway/tenant-auth.md`
|
||||
- Router ASP.NET bridge: `docs/modules/router/aspnet-endpoint-bridge.md`
|
||||
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
# Graph Ops Prep — PREP-GRAPH-OPS-0001
|
||||
|
||||
Status: Draft (2025-11-20)
|
||||
Owners: Ops Guild
|
||||
Scope: Capture dashboard/runbook updates pending next demo outputs.
|
||||
|
||||
## Needs
|
||||
- Latest demo metrics/dashboards to review.
|
||||
- Runbook sections to update once demo outputs land.
|
||||
|
||||
## Handoff
|
||||
Use as prep artefact; update after next demo provides dashboards/runbooks.
|
||||
@@ -1,66 +0,0 @@
|
||||
# Graph API schema outline (prep for GRAPH-API-28-001)
|
||||
|
||||
Status: draft outline · Date: 2025-11-22 · Owner: Graph API Guild
|
||||
Scope: Establish OpenAPI/JSON schema primitives for search/query/paths/diff/export endpoints, tile streaming, budgets, and RBAC headers. This is a staging note for sprint 0207 Wave 1.
|
||||
|
||||
## 1) Shared headers and security
|
||||
- `X-Stella-Tenant` (required, string)
|
||||
- `Authorization: Bearer <token>`; scopes: `graph:read`, `graph:query`, `graph:export` as applicable per route.
|
||||
- `X-Request-Id` optional; echoed in responses.
|
||||
- Rate limit headers: `X-RateLimit-Remaining`, `Retry-After` for 429 cases.
|
||||
|
||||
## 2) Tile envelope (streaming NDJSON)
|
||||
```jsonc
|
||||
{
|
||||
"type": "node" | "edge" | "stats" | "cursor" | "diagnostic",
|
||||
"seq": 1,
|
||||
"cost": { "consumed": 12, "remaining": 988, "limit": 1000 },
|
||||
"data": { /* node/edge/payload depending on type */ }
|
||||
}
|
||||
```
|
||||
- Deterministic ordering: breadth-first by hop for paths/query; lexicographic by `id` inside each hop when stable ordering is needed.
|
||||
- Cursor tile: `{"type":"cursor","token":"opaque"}` for resume.
|
||||
- Stats tile: counts, depth reached, cache hit ratios.
|
||||
|
||||
## 3) `/graph/search` (POST)
|
||||
Request body (summary):
|
||||
- `query` (string; prefix/exact semantics), `kinds` (array of `node` kinds), `limit`, `tenant`, `filters` (labels, ecosystem, scope), `ordering`.
|
||||
Response: stream of tiles (`node` + minimal neighbor context), plus final cursor/diagnostic tile.
|
||||
Validation rules: enforce `limit <= 500`, reject empty query unless `filters` present.
|
||||
|
||||
## 4) `/graph/query` (POST)
|
||||
- Body: DSL expression or structured filter object; includes `budget` (nodes/edges cap, time cap), `overlays` requested (`policy`, `vex`, `advisory`), `explain`: `none|minimal|full`.
|
||||
- Response: streaming tiles with mixed `node`, `edge`, `stats`, `cursor`; budgets decremented per tile.
|
||||
- Errors: `429` budget exhausted with diagnostic tile including partial cursor.
|
||||
|
||||
## 5) `/graph/paths` (POST)
|
||||
- Body: `source_ids[]`, `target_ids[]`, `max_depth <= 6`, `constraints` (edge kinds, tenant, overlays allowed), `fanout_cap`.
|
||||
- Response: tiles grouped by path id; includes `hop` field for ordering; optional `overlay_trace` when policy layer requested.
|
||||
|
||||
## 6) `/graph/diff` (POST)
|
||||
- Body: `snapshot_a`, `snapshot_b`, optional `filters` (tenant, kinds, advisory keys).
|
||||
- Response: tiles of `node_added`, `node_removed`, `edge_added`, `edge_removed`, `overlay_delta` (policy/vex/advisory), plus `manifest` tile with counts and checksums.
|
||||
|
||||
## 7) `/graph/export` (POST)
|
||||
- Body: `formats[]` (`graphml`, `csv`, `ndjson`, `png`, `svg`), `snapshot_id` or `query_ref`, `include_overlays`.
|
||||
- Response: job ticket `{ job_id, status_url, checksum_manifest_url }`; downloads streamed with deterministic manifests.
|
||||
|
||||
## 8) Error schema (shared)
|
||||
```jsonc
|
||||
{
|
||||
"error": "GRAPH_BUDGET_EXCEEDED" | "GRAPH_VALIDATION_FAILED" | "GRAPH_RATE_LIMITED",
|
||||
"message": "human-readable",
|
||||
"details": {},
|
||||
"request_id": "..."
|
||||
}
|
||||
```
|
||||
|
||||
## 9) Open questions to settle before sign-off
|
||||
- Final DSL surface vs structured filters for `/graph/query`.
|
||||
- Exact cache key and eviction policy for overlays requested via query.
|
||||
- PNG/SVG render payload (pre-signed URL vs inline streaming) and size caps.
|
||||
|
||||
## 10) Next steps
|
||||
- Convert this outline into OpenAPI components + schemas in repo (`docs/api/graph-gateway-spec-draft.yaml`) by 2025-11-24.
|
||||
- Add JSON Schema fragments for tiles and error payloads to reuse in SDKs.
|
||||
- Review with Policy Engine Guild to lock overlay contract version for GRAPH-API-28-006.
|
||||
@@ -1,32 +0,0 @@
|
||||
# Graph API schema review notes (planned)
|
||||
Date: 2025-11-24 (target)
|
||||
Scope: Review OpenAPI/JSON schema for search/query/paths/diff/export, tiles, budgets, and overlays alignment (GRAPH-API-28-001).
|
||||
|
||||
## Attendees
|
||||
- Graph API Guild: TBD
|
||||
- Policy Engine Guild: TBD
|
||||
- QA Guild (observer): TBD
|
||||
|
||||
## Pre-reads
|
||||
- `docs/api/graph-gateway-spec-draft.yaml`
|
||||
- `docs/modules/graph/prep/2025-11-22-graph-api-schema-outline.md`
|
||||
- Policy overlay contract references: `POLICY-ENGINE-30-001..003`
|
||||
|
||||
## Agenda
|
||||
- Validate tile envelope shape and budget semantics.
|
||||
- Confirm overlay payload fields and versioning handshake with Policy Engine.
|
||||
- Decide DSL vs structured filter scope for `/graph/query` v1.
|
||||
- Agree on export manifest shape and size caps for PNG/SVG.
|
||||
|
||||
## Decisions
|
||||
- Tile envelope shape frozen for draft v0.0.3-pre: `node|edge|stats|cursor|diagnostic`, `seq`, optional `cost`, overlays keyed by overlay kind with `{kind, version, data}`.
|
||||
- Resume support will rely on cursor tokens; requests accept optional `cursor` field for search/query/diff to resume streams.
|
||||
- Path responses carry `pathHop` on node/edge tiles; depth capped at 6 as per sprint scope.
|
||||
- Rate-limit/budget headers documented (`X-RateLimit-Remaining`, `Retry-After`), with 429 response carrying error envelope.
|
||||
|
||||
## Open items / follow-ups
|
||||
- Overlay payload contract (fields for policy/vex/advisory) to be versioned once POLICY-ENGINE-30-001..003 freeze; placeholder schema retained.
|
||||
- Export render limits (PNG/SVG size caps) still pending Observability/UX sign-off.
|
||||
|
||||
## Outcomes snapshot
|
||||
- Draft spec updated at `docs/api/graph-gateway-spec-draft.yaml` (v0.0.3-pre) and referenced in sprint Execution Log.
|
||||
@@ -1,121 +0,0 @@
|
||||
# Notifier Tenancy Prep — PREP-NOTIFY-TEN-48-001
|
||||
|
||||
Status: Implemented (2025-11-27)
|
||||
Owners: Notifications Service Guild
|
||||
Scope: Tenancy model and DAL/routes for tenant context in Notifier WebService.
|
||||
|
||||
## Overview
|
||||
|
||||
Tenant scoping for the Notifier module ensures that rules, templates, incidents, and channels
|
||||
are isolated per tenant with proper row-level security (RLS) in MongoDB storage.
|
||||
|
||||
## Implementation Summary
|
||||
|
||||
### 1. Tenant Context Service (`src/Notifier/StellaOps.Notifier.Worker/Tenancy/`)
|
||||
|
||||
- **TenantContext.cs**: AsyncLocal-based context propagation for tenant ID and actor
|
||||
- **TenantServiceExtensions.cs**: DI registration and configuration options
|
||||
- **ITenantAccessor**: Interface for accessing tenant from HTTP context
|
||||
|
||||
Key pattern:
|
||||
```csharp
|
||||
// Set tenant context for async scope
|
||||
using var scope = tenantContext.SetContext(tenantId, actor);
|
||||
await ProcessEventAsync();
|
||||
|
||||
// Or with extension method
|
||||
await tenantContext.WithTenantAsync(tenantId, actor, async () =>
|
||||
{
|
||||
await ProcessNotificationAsync();
|
||||
});
|
||||
```
|
||||
|
||||
### 2. Incident Repository (`src/Notify/__Libraries/StellaOps.Notify.Storage.Mongo/`)
|
||||
|
||||
New files:
|
||||
- **Repositories/INotifyIncidentRepository.cs**: Repository interface for incident persistence
|
||||
- **Repositories/NotifyIncidentRepository.cs**: MongoDB implementation with tenant filtering
|
||||
- **Serialization/NotifyIncidentDocumentMapper.cs**: BSON serialization for incidents
|
||||
|
||||
Key features:
|
||||
- All queries include mandatory `tenantId` filter
|
||||
- Document IDs use `{tenantId}:{resourceId}` composite pattern for RLS
|
||||
- Correlation key lookup scoped to tenant
|
||||
- Soft delete support with `deletedAt` field
|
||||
|
||||
### 3. MongoDB Indexes (tenant-scoped)
|
||||
|
||||
Added in `EnsureNotifyIndexesMigration.cs`:
|
||||
```javascript
|
||||
// incidents collection
|
||||
{ tenantId: 1, status: 1, lastOccurrence: -1 } // Status filtering
|
||||
{ tenantId: 1, correlationKey: 1, status: 1 } // Correlation lookup
|
||||
```
|
||||
|
||||
### 4. Existing Tenancy Infrastructure
|
||||
|
||||
The following was already in place:
|
||||
- All models have `TenantId` property (NotifyRule, NotifyChannel, NotifyTemplate, etc.)
|
||||
- Repository interfaces take `tenantId` as parameter
|
||||
- Endpoints extract tenant from `X-StellaOps-Tenant` header
|
||||
- MongoDB document IDs use tenant-prefixed composite keys
|
||||
|
||||
## Configuration
|
||||
|
||||
```json
|
||||
{
|
||||
"Notifier": {
|
||||
"Tenant": {
|
||||
"TenantIdHeader": "X-StellaOps-Tenant",
|
||||
"ActorHeader": "X-StellaOps-Actor",
|
||||
"RequireTenant": true,
|
||||
"DefaultActor": "system",
|
||||
"ExcludedPaths": ["/health", "/ready", "/metrics", "/openapi"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### HTTP API
|
||||
```http
|
||||
GET /api/v2/rules HTTP/1.1
|
||||
X-StellaOps-Tenant: tenant-123
|
||||
X-StellaOps-Actor: user@example.com
|
||||
```
|
||||
|
||||
### Worker Processing
|
||||
```csharp
|
||||
public class NotificationProcessor
|
||||
{
|
||||
private readonly ITenantContext _tenantContext;
|
||||
|
||||
public async Task ProcessAsync(NotifyEvent @event)
|
||||
{
|
||||
using var scope = _tenantContext.SetContext(@event.TenantId, "worker");
|
||||
|
||||
// All subsequent operations are scoped to tenant
|
||||
var rules = await _rules.ListAsync(@event.TenantId);
|
||||
// ...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Handoff Notes
|
||||
|
||||
- Incident storage moved from in-memory to MongoDB with full tenant isolation
|
||||
- Worker should use `ITenantContext.SetContext()` before processing events
|
||||
- All new repositories MUST include tenant filtering in queries
|
||||
- Test tenant isolation with multi-tenant integration tests
|
||||
|
||||
## Related Files
|
||||
|
||||
- `src/Notifier/StellaOps.Notifier.Worker/Tenancy/TenantContext.cs`
|
||||
- `src/Notifier/StellaOps.Notifier.Worker/Tenancy/TenantServiceExtensions.cs`
|
||||
- `src/Notify/__Libraries/StellaOps.Notify.Storage.Mongo/Repositories/INotifyIncidentRepository.cs`
|
||||
- `src/Notify/__Libraries/StellaOps.Notify.Storage.Mongo/Repositories/NotifyIncidentRepository.cs`
|
||||
- `src/Notify/__Libraries/StellaOps.Notify.Storage.Mongo/Serialization/NotifyIncidentDocumentMapper.cs`
|
||||
- `src/Notify/__Libraries/StellaOps.Notify.Storage.Mongo/Options/NotifyMongoOptions.cs` (added IncidentsCollection)
|
||||
- `src/Notify/__Libraries/StellaOps.Notify.Storage.Mongo/Migrations/EnsureNotifyIndexesMigration.cs` (added incident indexes)
|
||||
- `src/Notify/__Libraries/StellaOps.Notify.Storage.Mongo/ServiceCollectionExtensions.cs` (added INotifyIncidentRepository registration)
|
||||
@@ -1,12 +0,0 @@
|
||||
# Orchestrator AirGap Prep — PREP-ORCH-AIRGAP-56-001
|
||||
|
||||
Status: Draft (2025-11-20)
|
||||
Owners: Orchestrator Service Guild · AirGap Policy Guild
|
||||
Scope: Awaiting AirGap readiness; capture sealed-mode contract needs for orchestrator.
|
||||
|
||||
## Needs
|
||||
- Sealed-mode contract from AirGap controller (seal/unseal scopes, staleness fields).
|
||||
- Mirror bundle pointers to include with orchestrator jobs.
|
||||
|
||||
## Handoff
|
||||
Use as prep artefact; update once AirGap 56-001 contract is published.
|
||||
@@ -1,9 +0,0 @@
|
||||
# Orchestrator AirGap Prep — PREP-ORCH-AIRGAP-56-002
|
||||
|
||||
Status: Draft (2025-11-20)
|
||||
Scope: Downstream of 56-001; needs sealed-mode staleness propagation.
|
||||
|
||||
## Needs
|
||||
- From 56-001: seal contract and bundle pointers.
|
||||
- Staleness propagation rules to orchestrator runs.
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
# Orchestrator AirGap Prep — PREP-ORCH-AIRGAP-57-001
|
||||
|
||||
Status: Draft (2025-11-20)
|
||||
Scope: Dependent on 56-002; timeline events for AirGap imports.
|
||||
|
||||
## Needs
|
||||
- Event types/fields for bundle import timeline.
|
||||
- Alignment with AirGap mirror bundle IDs and staleness.
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
# Orchestrator AirGap Prep — PREP-ORCH-AIRGAP-58-001
|
||||
|
||||
Status: Draft (2025-11-20)
|
||||
Scope: Dependent on 57-001; Evidence Locker integration for sealed mode.
|
||||
|
||||
## Needs
|
||||
- Evidence Locker bundle pointers and attestation requirements in sealed mode.
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
# Orchestrator OAS Prep — PREP-ORCH-OAS-61-001/61-002/62-001
|
||||
|
||||
Status: Draft (2025-11-20)
|
||||
Scope: Telemetry contract inputs and OAS baseline for orchestrator APIs.
|
||||
|
||||
## Needs
|
||||
- Telemetry/contract inputs from sprint 150.A (not yet published).
|
||||
- OAS baseline for orchestrator host.
|
||||
- SDK generation targets (depends on OAS v1).
|
||||
|
||||
## Handoff
|
||||
Use as prep artefact for OAS 61/62 chain; update when telemetry inputs published.
|
||||
@@ -1,21 +0,0 @@
|
||||
# Orchestrator OAS Deprecations Prep — PREP-ORCH-OAS-63-001-DEPENDS-ON-62-001
|
||||
|
||||
Status: Draft (2025-11-20)
|
||||
Owners: Orchestrator Service Guild · API Governance Guild
|
||||
Scope: Define deprecation headers/docs for legacy orchestrator endpoints once OAS 61/62 are finalized.
|
||||
|
||||
## Dependencies
|
||||
- Final OAS base (61-001) and discovery (62-001).
|
||||
- List of endpoints to deprecate and replacement mapping.
|
||||
|
||||
## Proposed contract
|
||||
- Add `Deprecation` header and `Link` rel="alternate" to new endpoints.
|
||||
- Update OAS with `deprecated: true` and description of replacement.
|
||||
- Include changelog section and example responses showing headers.
|
||||
|
||||
## Acceptance
|
||||
- Replacement map documented in this file and in `docs/modules/orchestrator/api.md` once OAS is regenerated.
|
||||
- Sample response with deprecation headers under `docs/modules/orchestrator/samples/orch-deprecation@draft.json`.
|
||||
|
||||
## Handoff
|
||||
Use this prep doc to satisfy PREP-ORCH-OAS-63-001-DEPENDS-ON-62-001. Update after 61/62 freeze; then mark task DONE and proceed with implementation.
|
||||
@@ -1,17 +0,0 @@
|
||||
# Orchestrator Pack-Run Prep — PREP-ORCH-SVC-41-101 / 42-101 / TEN-48-001
|
||||
|
||||
Status: Draft (2025-11-20)
|
||||
Owners: Orchestrator Service Guild
|
||||
|
||||
## 41-101 needs
|
||||
- Envelope + DAL from 38-101 to register pack runs.
|
||||
- Storage schema for pack-run records.
|
||||
|
||||
## 42-101 needs
|
||||
- Stream contract from 41-101 (pack-run plumbing) to drive streaming.
|
||||
|
||||
## TEN-48-001 needs
|
||||
- Tenant context plumbing for job DAL/routes.
|
||||
|
||||
## Handoff
|
||||
Use as prep artefact; update when 38-101 envelope lands and DAL schema is fixed.
|
||||
@@ -1,11 +0,0 @@
|
||||
# Orchestrator Tenancy Prep — PREP-ORCH-TEN-48-001
|
||||
|
||||
Status: Draft (2025-11-20)
|
||||
Owners: Orchestrator Service Guild
|
||||
Scope: WebService job DAL/routes tenancy context prior to enforcement.
|
||||
|
||||
## Needs
|
||||
- Tenant context plumbing and RLS rules for job DAL/routes.
|
||||
|
||||
## Handoff
|
||||
Use as prep artefact; update once tenancy model decisions are finalized.
|
||||
@@ -1,25 +0,0 @@
|
||||
# Advisory AI Knobs Prep — PREP-POLICY-ENGINE-31-001-ADVISORY-AI-KNOBS-R
|
||||
|
||||
Status: Draft (2025-11-20)
|
||||
Owners: Policy Guild
|
||||
Scope: Outline the configuration knobs for Advisory AI scoring once trust weighting (30-101) is defined.
|
||||
|
||||
## Dependencies
|
||||
- Trust weighting API/contracts (30-101).
|
||||
- Advisory AI signal list and confidence model (not yet finalized).
|
||||
|
||||
## Draft configuration fields
|
||||
- `weights` (from 30-101) applied to AI-produced signals.
|
||||
- `knobs[]` array of `{name, default_value, min, max, step, description}` for:
|
||||
- `ai_signal_weight`
|
||||
- `reachability_boost`
|
||||
- `time_decay_half_life_days`
|
||||
- `evidence_freshness_threshold_hours`
|
||||
- Output preview: recomputed severity/exploitability per advisory/component.
|
||||
|
||||
## Acceptance to close PREP
|
||||
- Map knobs to actual AI signals once published; confirm allowed ranges.
|
||||
- Document schema at `docs/modules/policy/schemas/advisory-ai-knobs@draft.json` and sample request at `docs/modules/policy/samples/advisory-ai-knobs@draft.json`.
|
||||
|
||||
## Handoff
|
||||
Use this document as the prep artefact for PREP-POLICY-ENGINE-31-001-ADVISORY-AI-KNOBS-R. Update with final signal list and ranges once trust weighting is frozen.
|
||||
@@ -1,21 +0,0 @@
|
||||
# Batch Context Endpoint Prep — PREP-POLICY-ENGINE-31-002-BATCH-CONTEXT-ENDPO
|
||||
|
||||
Status: Draft (2025-11-20)
|
||||
Owners: Policy Guild
|
||||
Scope: Define the batch context endpoint contract that builds on Advisory AI knobs (31-001) and trust weighting outputs.
|
||||
|
||||
## Dependencies
|
||||
- Final knobs list from 31-001.
|
||||
- Policy profile schema (hash + version) from 30-001 overlays.
|
||||
|
||||
## Draft API surface
|
||||
- `POST /policy/batch/context` with payload: `{tenant_id, policy_profile_hash, knobs_version, overlay_hash, items:[{component_purl, advisory_id}], options:{include_reachability:boolean}}`.
|
||||
- Response: `{context_id, expires_at, knobs_version, overlay_hash, items:[{component_purl, advisory_id, status, trace_ref}]}`.
|
||||
- Determinism: items sorted by `(component_purl, advisory_id)`; `context_id` derived as hash of request payload.
|
||||
|
||||
## Acceptance to close PREP
|
||||
- Align fields with 31-001 knobs and 30-001 overlay schema; record hashes/versions.
|
||||
- Save draft schema at `docs/modules/policy/schemas/policy-batch-context@draft.json` and sample at `docs/modules/policy/samples/policy-batch-context@draft.json`.
|
||||
|
||||
## Handoff
|
||||
Use this document as the prep artefact for PREP-POLICY-ENGINE-31-002-BATCH-CONTEXT-ENDPO. Update when knobs and overlays freeze; then move implementation to DOING.
|
||||
@@ -1,23 +0,0 @@
|
||||
# Change Events Prep — PREP-POLICY-ENGINE-30-003-CHANGE-EVENTS-DEPEN
|
||||
|
||||
Status: Draft (2025-11-20)
|
||||
Owners: Policy Guild · Scheduler Guild · Cartographer Guild
|
||||
Scope: Define the change-event payload and scheduling expectations following simulation bridge (30-002).
|
||||
|
||||
## Dependencies
|
||||
- Simulation bridge output schema (30-002).
|
||||
- Scheduler delivery channel (NATS/Redis) subject names and dedupe policy.
|
||||
|
||||
## Draft event envelope
|
||||
- `event_type`: `policy.overlay.change`
|
||||
- Fields: `tenant_id`, `overlay_hash`, `policy_profile_hash`, `simulation_id?`, `changes[]` (array of `{component_purl, advisory_id, prev_status, new_status, severity_delta?, trace_ref}`), `occurred_at` (UTC), `event_id` (deterministic ID = hash of overlay_hash + timestamp).
|
||||
- Transport: propose NATS subject `policy.overlay.change` with durable stream; idempotency key = `event_id`.
|
||||
- Observability: counter `policy_overlay_change_total{tenant,result}`; log template includes overlay_hash, event_id, change_count.
|
||||
|
||||
## Acceptance to close PREP
|
||||
- Subject/stream names confirmed with Scheduler.
|
||||
- JSON schema stub saved at `docs/modules/policy/schemas/policy-overlay-change@draft.json`.
|
||||
- Sample event at `docs/modules/policy/samples/policy-overlay-change@draft.json`.
|
||||
|
||||
## Handoff
|
||||
This document serves as the prep artefact for PREP-POLICY-ENGINE-30-003-CHANGE-EVENTS-DEPEN. Update once 30-002 finalizes schema/subject; then unblock the implementation task.
|
||||
@@ -1,21 +0,0 @@
|
||||
# Conflict Handling Prep — PREP-POLICY-ENGINE-40-002-CONFLICT-HANDLING-D
|
||||
|
||||
Status: Draft (2025-11-20)
|
||||
Owners: Policy Guild · Excititor Guild
|
||||
Scope: Define conflict-handling rules after severity fusion (40-001).
|
||||
|
||||
## Dependencies
|
||||
- Severity fusion output schema (40-001).
|
||||
- Excititor/Console precedence context expectations for conflicts.
|
||||
|
||||
## Draft approach
|
||||
- Detect conflicts when multiple fused severities differ for same `{component_purl, advisory_id}` across tenants or sources.
|
||||
- Emit conflict record: `{tenant_id, component_purl, advisory_id, conflicts:[{source, field, value, reason_code}] , resolved_status?, trace_ref}`.
|
||||
- Resolution policy: default “no auto-resolve”; optional operator override flag per policy profile.
|
||||
|
||||
## Acceptance
|
||||
- Draft schema at `docs/modules/policy/schemas/policy-conflict@draft.json` and sample at `docs/modules/policy/samples/policy-conflict@draft.json`.
|
||||
- Mapping of reason codes to Excititor Console cache/RBAC needs documented once 23-003 finalizes.
|
||||
|
||||
## Handoff
|
||||
This document is the prep artefact for PREP-POLICY-ENGINE-40-002-CONFLICT-HANDLING-D. Update once severity fusion rules are frozen and Console expectations are known; then move implementation to DOING.
|
||||
@@ -1,21 +0,0 @@
|
||||
# Ledger Export Prep — PREP-POLICY-ENGINE-34-101-LEDGER-EXPORT-REQUI
|
||||
|
||||
Status: Draft (2025-11-20)
|
||||
Owners: Policy Guild
|
||||
Scope: Define ledger export requirements once worker results (33-101) exist.
|
||||
|
||||
## Dependencies
|
||||
- Worker result schema (33-101).
|
||||
- Storage/ledger format choice (Mongo vs Postgres) and retention policy.
|
||||
|
||||
## Draft export shape
|
||||
- Export file: NDJSON with entries `{tenant_id, job_id, context_id, component_purl, advisory_id, status, trace_ref, occurred_at}`.
|
||||
- Manifest: `{export_id, schema_version, generated_at, record_count, sha256}` with DSSE envelope optional.
|
||||
- Ordering: stable by `(tenant_id, job_id, component_purl, advisory_id)`.
|
||||
|
||||
## Acceptance
|
||||
- Draft schema at `docs/modules/policy/schemas/policy-ledger-export@draft.json` and sample at `docs/modules/policy/samples/policy-ledger-export@draft.json`.
|
||||
- Retention knobs documented (TTL/size caps) once storage decision is made.
|
||||
|
||||
## Handoff
|
||||
Use this as the prep artefact for PREP-POLICY-ENGINE-34-101-LEDGER-EXPORT-REQUI. Update with storage/retention decisions, then unblock implementation.
|
||||
@@ -1,21 +0,0 @@
|
||||
# Orchestrator Job Schema Prep — PREP-POLICY-ENGINE-32-101-ORCHESTRATOR-JOB-SC
|
||||
|
||||
Status: Draft (2025-11-20)
|
||||
Owners: Policy Guild
|
||||
Scope: Outline the job schema needed for orchestrator scheduling once batch context (31-002) is available.
|
||||
|
||||
## Dependencies
|
||||
- Batch context contract (31-002).
|
||||
- Orchestrator capsule envelope (Wave 150/140) for job submission fields.
|
||||
|
||||
## Draft job schema
|
||||
- Fields: `job_id` (ULID), `tenant_id`, `context_id` (from 31-002), `policy_profile_hash`, `requested_at`, `priority`, `batch_items[]` referencing `{component_purl, advisory_id}`, `callbacks` (SSE/NATS subjects), `trace_ref` (dsse hash).
|
||||
- Status lifecycle: `queued` → `running` → `completed`|`failed`; deterministic transitions logged.
|
||||
- Determinism: job_id derived from hash of `(tenant_id, context_id, requested_at ISO)`, ordered batch_items.
|
||||
|
||||
## Acceptance
|
||||
- Schema stub stored at `docs/modules/policy/schemas/orchestrator-job@draft.json` plus sample at `docs/modules/policy/samples/orchestrator-job@draft.json`.
|
||||
- Subject/callback expectations aligned with Orchestrator envelopes.
|
||||
|
||||
## Handoff
|
||||
Prep artefact for PREP-POLICY-ENGINE-32-101-ORCHESTRATOR-JOB-SC. Update with final Orchestrator envelope fields and batch context hash once available.
|
||||
@@ -1,21 +0,0 @@
|
||||
# Policy AirGap Import Prep — PREP-POLICY-AIRGAP-56-002-DEPENDS-ON-56-001-B
|
||||
|
||||
Status: Draft (2025-11-20)
|
||||
Owners: Policy Guild · Policy Studio Guild
|
||||
Scope: Define policy bundle import and DSSE signing expectations once mirror bundle schema (56-001) is fixed.
|
||||
|
||||
## Dependencies
|
||||
- Mirror bundle schema from 56-001 (fields: bundle_id, provenance, policy_hash, trust_roots, retained_at).
|
||||
- DSSE signing profile and RootPack mapping.
|
||||
|
||||
## Expected contract
|
||||
- Import endpoint: `POST /policy/airgap/import` accepting mirror bundle (file) + metadata.
|
||||
- Validation: verify DSSE, trust roots, policy hashes; reject on staleness over budget.
|
||||
- Response: `{bundle_id, policy_hash, imported_at, staleness_seconds}` ordered deterministically.
|
||||
|
||||
## Acceptance
|
||||
- Once 56-001 schema is frozen, record hash+version here and in sprint Decisions.
|
||||
- Add sample request/response to `docs/modules/policy/design/policy-mirror-bundle-schema.md` and samples folder.
|
||||
|
||||
## Handoff
|
||||
Use this doc as the prep artefact for PREP-POLICY-AIRGAP-56-002-DEPENDS-ON-56-001-B. Update with schema hash and DSSE profile when available, then move sprint task to DONE.
|
||||
@@ -1,21 +0,0 @@
|
||||
# Policy AirGap Sealed-Mode Prep — PREP-POLICY-AIRGAP-57-001-REQUIRES-SEALED-MOD
|
||||
|
||||
Status: Draft (2025-11-20)
|
||||
Owners: Policy Guild · AirGap Policy Guild
|
||||
Scope: Define sealed-mode policy behaviour and error envelopes after mirror import (56-002).
|
||||
|
||||
## Inputs needed
|
||||
- Sealed-mode error envelope standard (WEB-OAS-61-002) for consistency with Concelier/Web.
|
||||
- Staleness metadata fields from 56-002 (bundle provenance / time anchor).
|
||||
|
||||
## Proposed behavior
|
||||
- When sealed mode active and non-mirror source requested, return error `POLICY_AIRGAP_EGRESS_BLOCKED` with remediation list and `staleness_seconds_remaining` if available.
|
||||
- Determinism: sorted remediation items; canonical JSON ordering.
|
||||
- Telemetry: counter `policy_airgap_egress_blocked_total{tenant,endpoint}` and event `policy.airgap.egress_blocked` with `{tenant_id, bundle_id?, policy_hash}`.
|
||||
|
||||
## Acceptance
|
||||
- Envelope finalized in line with WEB-OAS-61-002; fields confirmed with AirGap Policy Guild.
|
||||
- Sample response stored at `docs/modules/policy/samples/policy-airgap-sealed@draft.json`.
|
||||
|
||||
## Handoff
|
||||
Prep artefact for PREP-POLICY-AIRGAP-57-001-REQUIRES-SEALED-MOD. Update once error envelope and staleness fields are frozen; then mark task DONE and start implementation.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user