docs consolidation

This commit is contained in:
StellaOps Bot
2025-12-24 12:38:14 +02:00
parent 7503c19b8f
commit 9a08d10b89
215 changed files with 2188 additions and 9623 deletions

View File

@@ -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.

View File

@@ -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`

View 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`

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View 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`.

View File

@@ -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. |

View File

@@ -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. |

View File

@@ -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).

View File

@@ -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.

View File

@@ -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.

View File

@@ -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`:

View File

@@ -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)

View File

@@ -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.

View File

@@ -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.
---

View File

@@ -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 platforms 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

View File

@@ -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`

View File

@@ -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.

View File

@@ -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.

View File

@@ -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`

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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` (0100), `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 (P10P13) so downstream implementation knows shapes.
- Sample manifest path + naming are defined for ledger/replay flows.
- Meter names/tags enumerated for observability wiring.

View File

@@ -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.

View File

@@ -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 sprints Decisions & Risks.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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

View File

@@ -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.

View File

@@ -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 sprints Decisions & Risks.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.)

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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 EvidenceLockers `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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.
## Whats 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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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, 0100, 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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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`

View File

@@ -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`

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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)

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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