Update module architecture docs and workflow tutorials
- Module dossiers: attestor, authority, cli, graph, scanner - Policy assistant parameters guide - UI v2-rewire navigation rendering policy - Test suite overview update - Workflow engine requirements and tutorial series (01-08) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,20 +1,20 @@
|
|||||||
# component_architecture_attestor.md — **Stella Ops Attestor** (2025Q4)
|
# component_architecture_attestor.md — **Stella Ops Attestor** (2025Q4)
|
||||||
|
|
||||||
> Derived from Epic 19 – Attestor Console with provenance hooks aligned to the Export Center bundle workflows scoped in Epic 10.
|
> Derived from Epic 19 – Attestor Console with provenance hooks aligned to the Export Center bundle workflows scoped in Epic 10.
|
||||||
|
|
||||||
> **Scope.** Implementation‑ready architecture for the **Attestor**: the service that **submits** DSSE envelopes to **Rekor v2**, retrieves/validates inclusion proofs, caches results, and exposes verification APIs. It accepts DSSE **only** from the **Signer** over mTLS, enforces chain‑of‑trust to Stella Ops roots, and returns `{uuid, index, proof, logURL}` to calling services (Scanner.WebService for SBOMs; backend for final reports; Excititor exports when configured).
|
> **Scope.** Implementation‑ready architecture for the **Attestor**: the service that **submits** DSSE envelopes to **Rekor v2**, retrieves/validates inclusion proofs, caches results, and exposes verification APIs. It accepts DSSE **only** from the **Signer** over mTLS, enforces chain‑of‑trust to Stella Ops roots, and returns `{uuid, index, proof, logURL}` to calling services (Scanner.WebService for SBOMs; backend for final reports; Excititor exports when configured).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 0) Mission & boundaries
|
## 0) Mission & boundaries
|
||||||
|
|
||||||
**Mission.** Turn a signed DSSE envelope from the Signer into a **transparency‑logged, verifiable fact** with a durable, replayable proof (Merkle inclusion + (optional) checkpoint anchoring). Provide **fast verification** for downstream consumers and a stable retrieval interface for UI/CLI.
|
**Mission.** Turn a signed DSSE envelope from the Signer into a **transparency‑logged, verifiable fact** with a durable, replayable proof (Merkle inclusion + (optional) checkpoint anchoring). Provide **fast verification** for downstream consumers and a stable retrieval interface for UI/CLI.
|
||||||
|
|
||||||
**Boundaries.**
|
**Boundaries.**
|
||||||
|
|
||||||
* Attestor **does not sign**; it **must not** accept unsigned or third‑party‑signed bundles.
|
* Attestor **does not sign**; it **must not** accept unsigned or third‑party‑signed bundles.
|
||||||
* Attestor **does not decide PASS/FAIL**; it logs attestations for SBOMs, reports, and export artifacts.
|
* Attestor **does not decide PASS/FAIL**; it logs attestations for SBOMs, reports, and export artifacts.
|
||||||
* Rekor v2 backends may be **local** (self‑hosted) or **remote**; Attestor handles both with retries, backoff, and idempotency.
|
* Rekor v2 backends may be **local** (self‑hosted) or **remote**; Attestor handles both with retries, backoff, and idempotency.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -24,22 +24,22 @@
|
|||||||
|
|
||||||
**Dependencies:**
|
**Dependencies:**
|
||||||
|
|
||||||
* **Signer** (caller) — authenticated via **mTLS** and **Authority** OpToks.
|
* **Signer** (caller) — authenticated via **mTLS** and **Authority** OpToks.
|
||||||
* **Rekor v2** — tile‑backed transparency log endpoint(s).
|
* **Rekor v2** — tile‑backed transparency log endpoint(s).
|
||||||
* **RustFS (S3-compatible)** — optional archive store for DSSE envelopes & verification bundles.
|
* **RustFS (S3-compatible)** — optional archive store for DSSE envelopes & verification bundles.
|
||||||
* **PostgreSQL** — local cache of `{uuid, index, proof, artifactSha256, bundleSha256}`; job state; audit.
|
* **PostgreSQL** — local cache of `{uuid, index, proof, artifactSha256, bundleSha256}`; job state; audit.
|
||||||
* **Valkey** — dedupe/idempotency keys and short‑lived rate‑limit buckets.
|
* **Valkey** — dedupe/idempotency keys and short‑lived rate‑limit buckets.
|
||||||
* **Licensing Service (optional)** — “endorse†call for cross‑log publishing when customer opts‑in.
|
* **Licensing Service (optional)** — “endorse” call for cross‑log publishing when customer opts‑in.
|
||||||
|
|
||||||
Trust boundary: **Only the Signer** is allowed to call submission endpoints; enforced by **mTLS peer cert allowlist** + `aud=attestor` OpTok.
|
Trust boundary: **Only the Signer** is allowed to call submission endpoints; enforced by **mTLS peer cert allowlist** + `aud=attestor` OpTok.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Roles, identities & scopes
|
### Roles, identities & scopes
|
||||||
- **Subjects** — immutable digests for artifacts (container images, SBOMs, reports) referenced in DSSE envelopes.
|
- **Subjects** — immutable digests for artifacts (container images, SBOMs, reports) referenced in DSSE envelopes.
|
||||||
- **Issuers** — authenticated builders/scanners/policy engines signing evidence; tracked with mode (`keyless`, `kms`, `hsm`, `fido2`) and tenant scope.
|
- **Issuers** — authenticated builders/scanners/policy engines signing evidence; tracked with mode (`keyless`, `kms`, `hsm`, `fido2`) and tenant scope.
|
||||||
- **Consumers** — Scanner, Export Center, CLI, Console, Policy Engine that verify proofs using Attestor APIs.
|
- **Consumers** — Scanner, Export Center, CLI, Console, Policy Engine that verify proofs using Attestor APIs.
|
||||||
- **Authority scopes** — `attestor.write`, `attestor.verify`, `attestor.read`, and administrative scopes for key management; all calls mTLS/DPoP-bound.
|
- **Authority scopes** — `attestor.write`, `attestor.verify`, `attestor.read`, and administrative scopes for key management; all calls mTLS/DPoP-bound.
|
||||||
|
|
||||||
### Supported predicate types
|
### Supported predicate types
|
||||||
- `StellaOps.BuildProvenance@1`
|
- `StellaOps.BuildProvenance@1`
|
||||||
@@ -76,9 +76,9 @@ Each predicate embeds subject digests, issuer metadata, policy context, material
|
|||||||
The Attestor implements RFC 6962-compliant Merkle inclusion proof verification for Rekor transparency log entries:
|
The Attestor implements RFC 6962-compliant Merkle inclusion proof verification for Rekor transparency log entries:
|
||||||
|
|
||||||
**Components:**
|
**Components:**
|
||||||
- `MerkleProofVerifier` — Verifies Merkle audit paths per RFC 6962 Section 2.1.1
|
- `MerkleProofVerifier` — Verifies Merkle audit paths per RFC 6962 Section 2.1.1
|
||||||
- `CheckpointSignatureVerifier` — Parses and verifies Rekor checkpoint signatures (ECDSA/Ed25519)
|
- `CheckpointSignatureVerifier` — Parses and verifies Rekor checkpoint signatures (ECDSA/Ed25519)
|
||||||
- `RekorVerificationOptions` — Configuration for public keys, offline mode, and checkpoint caching
|
- `RekorVerificationOptions` — Configuration for public keys, offline mode, and checkpoint caching
|
||||||
|
|
||||||
**Verification Flow:**
|
**Verification Flow:**
|
||||||
1. Parse checkpoint body (origin, tree size, root hash)
|
1. Parse checkpoint body (origin, tree size, root hash)
|
||||||
@@ -93,10 +93,10 @@ The Attestor implements RFC 6962-compliant Merkle inclusion proof verification f
|
|||||||
- `AllowOfflineWithoutSignature` for fully disconnected scenarios (reduced security)
|
- `AllowOfflineWithoutSignature` for fully disconnected scenarios (reduced security)
|
||||||
|
|
||||||
**Metrics:**
|
**Metrics:**
|
||||||
- `attestor.rekor_inclusion_verify_total` — Verification attempts by result
|
- `attestor.rekor_inclusion_verify_total` — Verification attempts by result
|
||||||
- `attestor.rekor_checkpoint_verify_total` — Checkpoint signature verifications
|
- `attestor.rekor_checkpoint_verify_total` — Checkpoint signature verifications
|
||||||
- `attestor.rekor_offline_verify_total` — Offline mode verifications
|
- `attestor.rekor_offline_verify_total` — Offline mode verifications
|
||||||
- `attestor.rekor_checkpoint_cache_hits/misses` — Checkpoint cache performance
|
- `attestor.rekor_checkpoint_cache_hits/misses` — Checkpoint cache performance
|
||||||
|
|
||||||
### UI & CLI touchpoints
|
### UI & CLI touchpoints
|
||||||
- Console: Evidence browser, verification report, chain-of-custody graph, issuer/key management, attestation workbench, bulk verification views.
|
- Console: Evidence browser, verification report, chain-of-custody graph, issuer/key management, attestation workbench, bulk verification views.
|
||||||
@@ -104,7 +104,7 @@ The Attestor implements RFC 6962-compliant Merkle inclusion proof verification f
|
|||||||
- SDKs expose sign/verify primitives for build pipelines.
|
- SDKs expose sign/verify primitives for build pipelines.
|
||||||
|
|
||||||
### Performance & observability targets
|
### Performance & observability targets
|
||||||
- Throughput goal: ≥1 000 envelopes/minute per worker with cached verification.
|
- Throughput goal: ≥1 000 envelopes/minute per worker with cached verification.
|
||||||
- Metrics: `attestor_submission_total`, `attestor_verify_seconds`, `attestor_rekor_latency_seconds`, `attestor_cache_hit_ratio`.
|
- Metrics: `attestor_submission_total`, `attestor_verify_seconds`, `attestor_rekor_latency_seconds`, `attestor_cache_hit_ratio`.
|
||||||
- Logs include `tenant`, `issuer`, `subjectDigest`, `rekorUuid`, `proofStatus`; traces cover submission → Rekor → cache → response path.
|
- Logs include `tenant`, `issuer`, `subjectDigest`, `rekorUuid`, `proofStatus`; traces cover submission → Rekor → cache → response path.
|
||||||
|
|
||||||
@@ -172,8 +172,8 @@ Database: `attestor`
|
|||||||
Indexes:
|
Indexes:
|
||||||
|
|
||||||
* `entries`: indexes on `artifact_sha256`, `bundle_sha256`, `created_at`, and composite `(status, created_at DESC)`.
|
* `entries`: indexes on `artifact_sha256`, `bundle_sha256`, `created_at`, and composite `(status, created_at DESC)`.
|
||||||
* `dedupe`: unique index on `key`; scheduled job cleans rows where `ttl_at < NOW()` (24–48h retention).
|
* `dedupe`: unique index on `key`; scheduled job cleans rows where `ttl_at < NOW()` (24–48h retention).
|
||||||
* `audit`: index on `ts` for time‑range queries.
|
* `audit`: index on `ts` for time‑range queries.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -375,10 +375,10 @@ The exception signing service provides endpoints for signing, verifying, and ren
|
|||||||
|
|
||||||
**Attestor accepts only** DSSE envelopes that satisfy all of:
|
**Attestor accepts only** DSSE envelopes that satisfy all of:
|
||||||
|
|
||||||
1. **mTLS** peer certificate maps to `signer` service (CA‑pinned).
|
1. **mTLS** peer certificate maps to `signer` service (CA‑pinned).
|
||||||
2. **Authority** OpTok with `aud=attestor`, `scope=attestor.write`, DPoP or mTLS bound.
|
2. **Authority** OpTok with `aud=attestor`, `scope=attestor.write`, DPoP or mTLS bound.
|
||||||
3. DSSE envelope is **signed by the Signer’s key** (or includes a **Fulcio‑issued** cert chain) and **chains to configured roots** (Fulcio/KMS).
|
3. DSSE envelope is **signed by the Signer’s key** (or includes a **Fulcio‑issued** cert chain) and **chains to configured roots** (Fulcio/KMS).
|
||||||
4. **Predicate type** is one of Stella Ops types (sbom/report/vex‑export) with valid schema.
|
4. **Predicate type** is one of Stella Ops types (sbom/report/vex‑export) with valid schema.
|
||||||
5. `subject[*].digest.sha256` is present and canonicalized.
|
5. `subject[*].digest.sha256` is present and canonicalized.
|
||||||
|
|
||||||
**Wire shape (JSON):**
|
**Wire shape (JSON):**
|
||||||
@@ -405,7 +405,7 @@ The exception signing service provides endpoints for signing, verifying, and ren
|
|||||||
|
|
||||||
`POST /api/v1/attestations:sign` *(mTLS + OpTok required)*
|
`POST /api/v1/attestations:sign` *(mTLS + OpTok required)*
|
||||||
|
|
||||||
* **Purpose**: Deterministically wrap Stella Ops payloads in DSSE envelopes before Rekor submission. Reuses the submission rate limiter and honours caller tenancy/audience scopes.
|
* **Purpose**: Deterministically wrap Stella Ops payloads in DSSE envelopes before Rekor submission. Reuses the submission rate limiter and honours caller tenancy/audience scopes.
|
||||||
* **Body**:
|
* **Body**:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
@@ -428,7 +428,7 @@ The exception signing service provides endpoints for signing, verifying, and ren
|
|||||||
|
|
||||||
* **Behaviour**:
|
* **Behaviour**:
|
||||||
* Resolve the signing key from `attestor.signing.keys[]` (includes algorithm, provider, and optional KMS version).
|
* Resolve the signing key from `attestor.signing.keys[]` (includes algorithm, provider, and optional KMS version).
|
||||||
* Compute DSSE pre‑authentication encoding, sign with the resolved provider (default EC, BouncyCastle Ed25519, or File‑KMS ES256), and add static + request certificate chains.
|
* Compute DSSE pre‑authentication encoding, sign with the resolved provider (default EC, BouncyCastle Ed25519, or File‑KMS ES256), and add static + request certificate chains.
|
||||||
* Canonicalise the resulting bundle, derive `bundleSha256`, and mirror the request meta shape used by `/api/v1/rekor/entries`.
|
* Canonicalise the resulting bundle, derive `bundleSha256`, and mirror the request meta shape used by `/api/v1/rekor/entries`.
|
||||||
* Emit `attestor.sign_total{result,algorithm,provider}` and `attestor.sign_latency_seconds{algorithm,provider}` metrics and append an audit row (`action=sign`).
|
* Emit `attestor.sign_total{result,algorithm,provider}` and `attestor.sign_latency_seconds{algorithm,provider}` metrics and append an audit row (`action=sign`).
|
||||||
* **Response 200**:
|
* **Response 200**:
|
||||||
@@ -461,13 +461,13 @@ The exception signing service provides endpoints for signing, verifying, and ren
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"uuid": "…",
|
"uuid": "…",
|
||||||
"index": 123456,
|
"index": 123456,
|
||||||
"proof": {
|
"proof": {
|
||||||
"checkpoint": { "origin": "rekor@site", "size": 987654, "rootHash": "…", "timestamp": "…" },
|
"checkpoint": { "origin": "rekor@site", "size": 987654, "rootHash": "…", "timestamp": "…" },
|
||||||
"inclusion": { "leafHash": "…", "path": ["…","…"] }
|
"inclusion": { "leafHash": "…", "path": ["…","…"] }
|
||||||
},
|
},
|
||||||
"logURL": "https://rekor…/api/v2/log/…/entries/…",
|
"logURL": "https://rekor…/api/v2/log/…/entries/…",
|
||||||
"status": "included"
|
"status": "included"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -480,28 +480,28 @@ The exception signing service provides endpoints for signing, verifying, and ren
|
|||||||
* Returns `entries` row (refreshes proof from Rekor if stale/missing).
|
* Returns `entries` row (refreshes proof from Rekor if stale/missing).
|
||||||
* Accepts `?refresh=true` to force backend query.
|
* Accepts `?refresh=true` to force backend query.
|
||||||
|
|
||||||
### 4.4 Verification (third‑party or internal)
|
### 4.4 Verification (third‑party or internal)
|
||||||
|
|
||||||
`POST /api/v1/rekor/verify`
|
`POST /api/v1/rekor/verify`
|
||||||
|
|
||||||
* **Body** (one of):
|
* **Body** (one of):
|
||||||
|
|
||||||
* `{ "uuid": "…" }`
|
* `{ "uuid": "…" }`
|
||||||
* `{ "bundle": { …DSSE… } }`
|
* `{ "bundle": { …DSSE… } }`
|
||||||
* `{ "artifactSha256": "…" }` *(looks up most recent entry)*
|
* `{ "artifactSha256": "…" }` *(looks up most recent entry)*
|
||||||
|
|
||||||
* **Checks**:
|
* **Checks**:
|
||||||
|
|
||||||
1. **Bundle signature** → cert chain to Fulcio/KMS roots configured.
|
1. **Bundle signature** → cert chain to Fulcio/KMS roots configured.
|
||||||
2. **Inclusion proof** → recompute leaf hash; verify Merkle path against checkpoint root.
|
2. **Inclusion proof** → recompute leaf hash; verify Merkle path against checkpoint root.
|
||||||
3. Optionally verify **checkpoint** against local trust anchors (if Rekor signs checkpoints).
|
3. Optionally verify **checkpoint** against local trust anchors (if Rekor signs checkpoints).
|
||||||
4. Confirm **subject.digest** matches caller‑provided hash (when given).
|
4. Confirm **subject.digest** matches caller‑provided hash (when given).
|
||||||
5. Fetch **transparency witness** statement when enabled; cache results and downgrade status to WARN when endorsements are missing or mismatched.
|
5. Fetch **transparency witness** statement when enabled; cache results and downgrade status to WARN when endorsements are missing or mismatched.
|
||||||
|
|
||||||
* **Response**:
|
* **Response**:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{ "ok": true, "uuid": "…", "index": 123, "logURL": "…", "checkedAt": "…" }
|
{ "ok": true, "uuid": "…", "index": 123, "logURL": "…", "checkedAt": "…" }
|
||||||
```
|
```
|
||||||
|
|
||||||
### 4.5 Bulk verification
|
### 4.5 Bulk verification
|
||||||
@@ -512,9 +512,9 @@ The exception signing service provides endpoints for signing, verifying, and ren
|
|||||||
|
|
||||||
**Worker path:** `BulkVerificationWorker` claims queued jobs (`status=queued → running`), executes items sequentially through the cached verification service, updates progress counters, and records metrics:
|
**Worker path:** `BulkVerificationWorker` claims queued jobs (`status=queued → running`), executes items sequentially through the cached verification service, updates progress counters, and records metrics:
|
||||||
|
|
||||||
- `attestor.bulk_jobs_total{status}` – completed/failed jobs
|
- `attestor.bulk_jobs_total{status}` – completed/failed jobs
|
||||||
- `attestor.bulk_job_duration_seconds{status}` – job runtime
|
- `attestor.bulk_job_duration_seconds{status}` – job runtime
|
||||||
- `attestor.bulk_items_total{status}` – per-item outcomes (`succeeded`, `verification_failed`, `exception`)
|
- `attestor.bulk_items_total{status}` – per-item outcomes (`succeeded`, `verification_failed`, `exception`)
|
||||||
|
|
||||||
The worker honours `bulkVerification.itemDelayMilliseconds` for throttling and reschedules persistence conflicts with optimistic version checks. Results hydrate the verification cache; failed items record the error reason without aborting the overall job.
|
The worker honours `bulkVerification.itemDelayMilliseconds` for throttling and reschedules persistence conflicts with optimistic version checks. Results hydrate the verification cache; failed items record the error reason without aborting the overall job.
|
||||||
|
|
||||||
@@ -524,7 +524,7 @@ The worker honours `bulkVerification.itemDelayMilliseconds` for throttling and r
|
|||||||
|
|
||||||
* **Canonicalization**: DSSE envelopes are **normalized** (stable JSON ordering, no insignificant whitespace) before hashing and submission.
|
* **Canonicalization**: DSSE envelopes are **normalized** (stable JSON ordering, no insignificant whitespace) before hashing and submission.
|
||||||
* **Transport**: HTTP/2 with retries (exponential backoff, jitter), budgeted timeouts.
|
* **Transport**: HTTP/2 with retries (exponential backoff, jitter), budgeted timeouts.
|
||||||
* **Idempotency**: if backend returns “already exists,†map to existing `uuid`.
|
* **Idempotency**: if backend returns “already exists,” map to existing `uuid`.
|
||||||
* **Proof acquisition**:
|
* **Proof acquisition**:
|
||||||
|
|
||||||
* In synchronous mode, poll the log for inclusion up to `proofTimeoutMs`.
|
* In synchronous mode, poll the log for inclusion up to `proofTimeoutMs`.
|
||||||
@@ -532,25 +532,25 @@ The worker honours `bulkVerification.itemDelayMilliseconds` for throttling and r
|
|||||||
* **Mirrors/dual logs**:
|
* **Mirrors/dual logs**:
|
||||||
|
|
||||||
* When `logPreference="both"`, submit to primary and mirror; store **both** UUIDs (primary canonical).
|
* When `logPreference="both"`, submit to primary and mirror; store **both** UUIDs (primary canonical).
|
||||||
* Optional **cloud endorsement**: POST to the Stella Ops cloud `/attest/endorse` with `{uuid, artifactSha256}`; store returned endorsement id.
|
* Optional **cloud endorsement**: POST to the Stella Ops cloud `/attest/endorse` with `{uuid, artifactSha256}`; store returned endorsement id.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 6) Security model
|
## 6) Security model
|
||||||
|
|
||||||
* **mTLS required** for submission from **Signer** (CA‑pinned).
|
* **mTLS required** for submission from **Signer** (CA‑pinned).
|
||||||
* **Authority token** with `aud=attestor` and DPoP/mTLS binding must be presented; Attestor verifies both.
|
* **Authority token** with `aud=attestor` and DPoP/mTLS binding must be presented; Attestor verifies both.
|
||||||
* **Bundle acceptance policy**:
|
* **Bundle acceptance policy**:
|
||||||
|
|
||||||
* DSSE signature must chain to the configured **Fulcio** (keyless) or **KMS/HSM** roots.
|
* DSSE signature must chain to the configured **Fulcio** (keyless) or **KMS/HSM** roots.
|
||||||
* SAN (Subject Alternative Name) must match **Signer identity** policy (e.g., `urn:stellaops:signer` or pinned OIDC issuer).
|
* SAN (Subject Alternative Name) must match **Signer identity** policy (e.g., `urn:stellaops:signer` or pinned OIDC issuer).
|
||||||
* Predicate `predicateType` must be on allowlist (sbom/report/vex-export).
|
* Predicate `predicateType` must be on allowlist (sbom/report/vex-export).
|
||||||
* `subject.digest.sha256` values must be present and well‑formed (hex).
|
* `subject.digest.sha256` values must be present and well‑formed (hex).
|
||||||
* **No public submission** path. **Never** accept bundles from untrusted clients.
|
* **No public submission** path. **Never** accept bundles from untrusted clients.
|
||||||
* **Client certificate allowlists**: optional `security.mtls.allowedSubjects` / `allowedThumbprints` tighten peer identity checks beyond CA pinning.
|
* **Client certificate allowlists**: optional `security.mtls.allowedSubjects` / `allowedThumbprints` tighten peer identity checks beyond CA pinning.
|
||||||
* **Rate limits**: token-bucket per caller derived from `quotas.perCaller` (QPS/burst) returns `429` + `Retry-After` when exceeded.
|
* **Rate limits**: token-bucket per caller derived from `quotas.perCaller` (QPS/burst) returns `429` + `Retry-After` when exceeded.
|
||||||
* **Scope enforcement**: API separates `attestor.write`, `attestor.verify`, and `attestor.read` policies; verification/list endpoints accept read or verify scopes while submission endpoints remain write-only.
|
* **Scope enforcement**: API separates `attestor.write`, `attestor.verify`, and `attestor.read` policies; verification/list endpoints accept read or verify scopes while submission endpoints remain write-only.
|
||||||
* **Request hygiene**: JSON content-type is mandatory (415 returned otherwise); DSSE payloads are capped (default 2 MiB), certificate chains limited to six entries, and signatures to six per envelope to mitigate parsing abuse.
|
* **Request hygiene**: JSON content-type is mandatory (415 returned otherwise); DSSE payloads are capped (default 2 MiB), certificate chains limited to six entries, and signatures to six per envelope to mitigate parsing abuse.
|
||||||
* **Redaction**: Attestor never logs secret material; DSSE payloads **should** be public by design (SBOMs/reports). If customers require redaction, enforce policy at Signer (predicate minimization) **before** Attestor.
|
* **Redaction**: Attestor never logs secret material; DSSE payloads **should** be public by design (SBOMs/reports). If customers require redaction, enforce policy at Signer (predicate minimization) **before** Attestor.
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -588,8 +588,8 @@ The worker honours `bulkVerification.itemDelayMilliseconds` for throttling and r
|
|||||||
|
|
||||||
SLO guardrails:
|
SLO guardrails:
|
||||||
|
|
||||||
* `attestor.verify_latency_seconds` P95 ≤ 2 s per policy.
|
* `attestor.verify_latency_seconds` P95 ≤ 2 s per policy.
|
||||||
* `attestor.verify_total{result="failed"}` ≤ 1 % of `attestor.verify_total` over 30 min rolling windows.
|
* `attestor.verify_total{result="failed"}` ≤ 1 % of `attestor.verify_total` over 30 min rolling windows.
|
||||||
|
|
||||||
**Correlation**:
|
**Correlation**:
|
||||||
|
|
||||||
@@ -682,7 +682,7 @@ attestor:
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 10) End‑to‑end sequences
|
## 10) End‑to‑end sequences
|
||||||
|
|
||||||
**A) Submit & include (happy path)**
|
**A) Submit & include (happy path)**
|
||||||
|
|
||||||
@@ -741,8 +741,8 @@ sequenceDiagram
|
|||||||
* Stateless; scale horizontally.
|
* Stateless; scale horizontally.
|
||||||
* **Targets**:
|
* **Targets**:
|
||||||
|
|
||||||
* Submit+proof P95 ≤ **300 ms** (warm log; local Rekor).
|
* Submit+proof P95 ≤ **300 ms** (warm log; local Rekor).
|
||||||
* Verify P95 ≤ **30 ms** from cache; ≤ **120 ms** with live proof fetch.
|
* Verify P95 ≤ **30 ms** from cache; ≤ **120 ms** with live proof fetch.
|
||||||
* 1k submissions/minute per replica sustained.
|
* 1k submissions/minute per replica sustained.
|
||||||
* **Hot caches**: `dedupe` (bundle hash → uuid), recent `entries` by artifact sha256.
|
* **Hot caches**: `dedupe` (bundle hash → uuid), recent `entries` by artifact sha256.
|
||||||
|
|
||||||
@@ -752,8 +752,8 @@ sequenceDiagram
|
|||||||
|
|
||||||
* **Happy path**: valid DSSE, inclusion within timeout.
|
* **Happy path**: valid DSSE, inclusion within timeout.
|
||||||
* **Idempotency**: resubmit same `bundleSha256` → same `uuid`.
|
* **Idempotency**: resubmit same `bundleSha256` → same `uuid`.
|
||||||
* **Security**: reject non‑Signer mTLS, wrong `aud`, DPoP replay, untrusted cert chain, forbidden predicateType.
|
* **Security**: reject non‑Signer mTLS, wrong `aud`, DPoP replay, untrusted cert chain, forbidden predicateType.
|
||||||
* **Rekor variants**: promise‑then‑proof, proof delayed, mirror dual‑submit, mirror failure.
|
* **Rekor variants**: promise‑then‑proof, proof delayed, mirror dual‑submit, mirror failure.
|
||||||
* **Verification**: corrupt leaf path, wrong root, tampered bundle.
|
* **Verification**: corrupt leaf path, wrong root, tampered bundle.
|
||||||
* **Throughput**: soak test with 10k submissions; latency SLOs, zero drops.
|
* **Throughput**: soak test with 10k submissions; latency SLOs, zero drops.
|
||||||
|
|
||||||
@@ -764,16 +764,16 @@ sequenceDiagram
|
|||||||
* Language: **.NET 10** minimal API; `HttpClient` with **sockets handler** tuned for HTTP/2.
|
* Language: **.NET 10** minimal API; `HttpClient` with **sockets handler** tuned for HTTP/2.
|
||||||
* JSON: **canonical writer** for DSSE payload hashing.
|
* JSON: **canonical writer** for DSSE payload hashing.
|
||||||
* Crypto: use **BouncyCastle**/**System.Security.Cryptography**; PEM parsing for cert chains.
|
* Crypto: use **BouncyCastle**/**System.Security.Cryptography**; PEM parsing for cert chains.
|
||||||
* Rekor client: pluggable driver; treat backend errors as retryable/non‑retryable with granular mapping.
|
* Rekor client: pluggable driver; treat backend errors as retryable/non‑retryable with granular mapping.
|
||||||
* Safety: size caps on bundles; decompress bombs guarded; strict UTF‑8.
|
* Safety: size caps on bundles; decompress bombs guarded; strict UTF‑8.
|
||||||
* CLI integration: `stellaops verify attestation <uuid|bundle|artifact>` calls `/rekor/verify`.
|
* CLI integration: `stellaops verify attestation <uuid|bundle|artifact>` calls `/rekor/verify`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 15) Optional features
|
## 15) Optional features
|
||||||
|
|
||||||
* **Dual‑log** write (primary + mirror) and **cross‑log proof** packaging.
|
* **Dual‑log** write (primary + mirror) and **cross‑log proof** packaging.
|
||||||
* **Cloud endorsement**: send `{uuid, artifactSha256}` to Stella Ops cloud; store returned endorsement id for marketing/chain‑of‑custody.
|
* **Cloud endorsement**: send `{uuid, artifactSha256}` to Stella Ops cloud; store returned endorsement id for marketing/chain‑of‑custody.
|
||||||
* **Checkpoint pinning**: periodically pin latest Rekor checkpoints to an external audit store for independent monitoring.
|
* **Checkpoint pinning**: periodically pin latest Rekor checkpoints to an external audit store for independent monitoring.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# component_architecture_authority.md — **Stella Ops Authority** (2025Q4)
|
# component_architecture_authority.md — **Stella Ops Authority** (2025Q4)
|
||||||
|
|
||||||
> **Current tenant-selection ADR:** `docs/architecture/decisions/ADR-002-multi-tenant-same-api-key-selection.md`
|
> **Current tenant-selection ADR:** `docs/architecture/decisions/ADR-002-multi-tenant-same-api-key-selection.md`
|
||||||
> **Service impact ledger:** `docs/technical/architecture/multi-tenant-service-impact-ledger.md`
|
> **Service impact ledger:** `docs/technical/architecture/multi-tenant-service-impact-ledger.md`
|
||||||
@@ -8,18 +8,18 @@
|
|||||||
|
|
||||||
> Consolidates identity and tenancy requirements documented across the AOC, Policy, and Platform guides, along with the dedicated Authority implementation plan.
|
> Consolidates identity and tenancy requirements documented across the AOC, Policy, and Platform guides, along with the dedicated Authority implementation plan.
|
||||||
|
|
||||||
> **Scope.** Implementation‑ready architecture for **Stella Ops Authority**: the on‑prem **OIDC/OAuth2** service that issues **short‑lived, sender‑constrained operational tokens (OpToks)** to first‑party services and tools. Covers protocols (DPoP & mTLS binding), token shapes, endpoints, storage, rotation, HA, RBAC, audit, and testing. This component is the trust anchor for *who* is calling inside a Stella Ops installation. (Entitlement is proven separately by **PoE** from the cloud Licensing Service; Authority does not issue PoE.)
|
> **Scope.** Implementation‑ready architecture for **Stella Ops Authority**: the on‑prem **OIDC/OAuth2** service that issues **short‑lived, sender‑constrained operational tokens (OpToks)** to first‑party services and tools. Covers protocols (DPoP & mTLS binding), token shapes, endpoints, storage, rotation, HA, RBAC, audit, and testing. This component is the trust anchor for *who* is calling inside a Stella Ops installation. (Entitlement is proven separately by **PoE** from the cloud Licensing Service; Authority does not issue PoE.)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 0) Mission & boundaries
|
## 0) Mission & boundaries
|
||||||
|
|
||||||
**Mission.** Provide **fast, local, verifiable** authentication for Stella Ops microservices and tools by minting **very short‑lived** OAuth2/OIDC tokens that are **sender‑constrained** (DPoP or mTLS‑bound). Support RBAC scopes, multi‑tenant claims, and deterministic validation for APIs (Scanner, Signer, Attestor, Excititor, Concelier, UI, CLI, Zastava).
|
**Mission.** Provide **fast, local, verifiable** authentication for Stella Ops microservices and tools by minting **very short‑lived** OAuth2/OIDC tokens that are **sender‑constrained** (DPoP or mTLS‑bound). Support RBAC scopes, multi‑tenant claims, and deterministic validation for APIs (Scanner, Signer, Attestor, Excititor, Concelier, UI, CLI, Zastava).
|
||||||
|
|
||||||
**Boundaries.**
|
**Boundaries.**
|
||||||
|
|
||||||
* Authority **does not** validate entitlements/licensing. That’s enforced by **Signer** using **PoE** with the cloud Licensing Service.
|
* Authority **does not** validate entitlements/licensing. That’s enforced by **Signer** using **PoE** with the cloud Licensing Service.
|
||||||
* Authority tokens are **operational only** (2–5 min TTL) and must not be embedded in long‑lived artifacts or stored in SBOMs.
|
* Authority tokens are **operational only** (2–5 min TTL) and must not be embedded in long‑lived artifacts or stored in SBOMs.
|
||||||
* Authority is **stateless for validation** (JWT) and **optional introspection** for services that prefer online checks.
|
* Authority is **stateless for validation** (JWT) and **optional introspection** for services that prefer online checks.
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -29,16 +29,16 @@
|
|||||||
* **OIDC Discovery**: `/.well-known/openid-configuration`
|
* **OIDC Discovery**: `/.well-known/openid-configuration`
|
||||||
* **OAuth2** grant types:
|
* **OAuth2** grant types:
|
||||||
|
|
||||||
* **Client Credentials** (service↔service, with mTLS or private_key_jwt)
|
* **Client Credentials** (service↔service, with mTLS or private_key_jwt)
|
||||||
* **Device Code** (CLI login on headless agents; optional)
|
* **Device Code** (CLI login on headless agents; optional)
|
||||||
* **Authorization Code + PKCE** (browser login for UI; optional)
|
* **Authorization Code + PKCE** (browser login for UI; optional)
|
||||||
* **Sender constraint options** (choose per caller or per audience):
|
* **Sender constraint options** (choose per caller or per audience):
|
||||||
|
|
||||||
* **DPoP** (Demonstration of Proof‑of‑Possession): proof JWT on each HTTP request, bound to the access token via `cnf.jkt`.
|
* **DPoP** (Demonstration of Proof‑of‑Possession): proof JWT on each HTTP request, bound to the access token via `cnf.jkt`.
|
||||||
* **OAuth 2.0 mTLS** (certificate‑bound tokens): token bound to client certificate thumbprint via `cnf.x5t#S256`.
|
* **OAuth 2.0 mTLS** (certificate‑bound tokens): token bound to client certificate thumbprint via `cnf.x5t#S256`.
|
||||||
* **Signing algorithms**: **EdDSA (Ed25519)** preferred; fallback **ES256 (P‑256)**. Rotation is supported via **kid** in JWKS.
|
* **Signing algorithms**: **EdDSA (Ed25519)** preferred; fallback **ES256 (P‑256)**. Rotation is supported via **kid** in JWKS.
|
||||||
* **Token format**: **JWT** access tokens (compact), optionally opaque reference tokens for services that insist on introspection.
|
* **Token format**: **JWT** access tokens (compact), optionally opaque reference tokens for services that insist on introspection.
|
||||||
* **Clock skew tolerance**: ±60 s; issue `nbf`, `iat`, `exp` accordingly.
|
* **Clock skew tolerance**: ±60 s; issue `nbf`, `iat`, `exp` accordingly.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -47,7 +47,7 @@
|
|||||||
* **Incident mode tokens** require the `obs:incident` scope, a human-supplied `incident_reason`, and remain valid only while `auth_time` stays within a five-minute freshness window. Resource servers enforce the same window and persist `incident.reason`, `incident.auth_time`, and the fresh-auth verdict in `authority.resource.authorize` events. Authority exposes `/authority/audit/incident` so auditors can review recent activations.
|
* **Incident mode tokens** require the `obs:incident` scope, a human-supplied `incident_reason`, and remain valid only while `auth_time` stays within a five-minute freshness window. Resource servers enforce the same window and persist `incident.reason`, `incident.auth_time`, and the fresh-auth verdict in `authority.resource.authorize` events. Authority exposes `/authority/audit/incident` so auditors can review recent activations.
|
||||||
|
|
||||||
|
|
||||||
### 2.1 Access token (OpTok) — short‑lived (120–300 s)
|
### 2.1 Access token (OpTok) — short‑lived (120–300 s)
|
||||||
|
|
||||||
**Registered claims**
|
**Registered claims**
|
||||||
|
|
||||||
@@ -62,7 +62,7 @@ jti = <uuid>
|
|||||||
scope = "scanner.scan scanner.export signer.sign ..."
|
scope = "scanner.scan scanner.export signer.sign ..."
|
||||||
```
|
```
|
||||||
|
|
||||||
**Sender‑constraint (`cnf`)**
|
**Sender‑constraint (`cnf`)**
|
||||||
|
|
||||||
* **DPoP**:
|
* **DPoP**:
|
||||||
|
|
||||||
@@ -84,11 +84,11 @@ roles = [ "svc.scanner", "svc.signer", "ui.admin", ... ]
|
|||||||
plan? = <plan name> // optional hint for UIs; not used for enforcement
|
plan? = <plan name> // optional hint for UIs; not used for enforcement
|
||||||
```
|
```
|
||||||
|
|
||||||
> **Note**: Do **not** copy PoE claims into OpTok; OpTok ≠entitlement. Only **Signer** checks PoE.
|
> **Note**: Do **not** copy PoE claims into OpTok; OpTok ≠ entitlement. Only **Signer** checks PoE.
|
||||||
|
|
||||||
### 2.2 Refresh tokens (optional)
|
### 2.2 Refresh tokens (optional)
|
||||||
|
|
||||||
* Default **disabled**. If enabled (for UI interactive logins), pair with **DPoP‑bound** refresh tokens or **mTLS** client sessions; short TTL (≤ 8 h), rotating on use (replay‑safe).
|
* Default **disabled**. If enabled (for UI interactive logins), pair with **DPoP‑bound** refresh tokens or **mTLS** client sessions; short TTL (≤ 8 h), rotating on use (replay‑safe).
|
||||||
|
|
||||||
### 2.3 ID tokens (optional)
|
### 2.3 ID tokens (optional)
|
||||||
|
|
||||||
@@ -100,8 +100,8 @@ plan? = <plan name> // optional hint for UIs; not used for e
|
|||||||
|
|
||||||
### 3.1 OIDC discovery & keys
|
### 3.1 OIDC discovery & keys
|
||||||
|
|
||||||
* `GET /.well-known/openid-configuration` → endpoints, algs, jwks_uri
|
* `GET /.well-known/openid-configuration` → endpoints, algs, jwks_uri
|
||||||
* `GET /jwks` → JSON Web Key Set (rotating, at least 2 active keys during transition)
|
* `GET /jwks` → JSON Web Key Set (rotating, at least 2 active keys during transition)
|
||||||
|
|
||||||
> **KMS-backed keys.** When the signing provider is `kms`, Authority fetches only the public coordinates (`Qx`, `Qy`) and version identifiers from the backing KMS. Private scalars never leave the provider; JWKS entries are produced by re-exporting the public material via the `kms.version` metadata attached to each key. Retired keys keep the same `kms.version` metadata so audits can trace which cloud KMS version produced a token.
|
> **KMS-backed keys.** When the signing provider is `kms`, Authority fetches only the public coordinates (`Qx`, `Qy`) and version identifiers from the backing KMS. Private scalars never leave the provider; JWKS entries are produced by re-exporting the public material via the `kms.version` metadata attached to each key. Retired keys keep the same `kms.version` metadata so audits can trace which cloud KMS version produced a token.
|
||||||
|
|
||||||
@@ -111,12 +111,12 @@ plan? = <plan name> // optional hint for UIs; not used for e
|
|||||||
|
|
||||||
> Legacy aliases under `/oauth/token` are deprecated as of 1 November 2025 and now emit `Deprecation/Sunset/Warning` headers. See [`docs/api/authority-legacy-auth-endpoints.md`](../../api/authority-legacy-auth-endpoints.md) for timelines and migration guidance.
|
> Legacy aliases under `/oauth/token` are deprecated as of 1 November 2025 and now emit `Deprecation/Sunset/Warning` headers. See [`docs/api/authority-legacy-auth-endpoints.md`](../../api/authority-legacy-auth-endpoints.md) for timelines and migration guidance.
|
||||||
|
|
||||||
* **Client Credentials** (service→service):
|
* **Client Credentials** (service→service):
|
||||||
|
|
||||||
* **mTLS**: mutual TLS + `client_id` → bound token (`cnf.x5t#S256`)
|
* **mTLS**: mutual TLS + `client_id` → bound token (`cnf.x5t#S256`)
|
||||||
* `security.senderConstraints.mtls.enforceForAudiences` forces the mTLS path when requested `aud`/`resource` values intersect high-value audiences (defaults include `signer`). Authority rejects clients attempting to use DPoP/basic secrets for these audiences.
|
* `security.senderConstraints.mtls.enforceForAudiences` forces the mTLS path when requested `aud`/`resource` values intersect high-value audiences (defaults include `signer`). Authority rejects clients attempting to use DPoP/basic secrets for these audiences.
|
||||||
* Stored `certificateBindings` are authoritative: thumbprint, subject, issuer, serial number, and SAN values are matched against the presented certificate, with rotation grace applied to activation windows. Failures surface deterministic error codes (e.g. `certificate_binding_subject_mismatch`).
|
* Stored `certificateBindings` are authoritative: thumbprint, subject, issuer, serial number, and SAN values are matched against the presented certificate, with rotation grace applied to activation windows. Failures surface deterministic error codes (e.g. `certificate_binding_subject_mismatch`).
|
||||||
* **private_key_jwt**: JWT‑based client auth + **DPoP** header (preferred for tools and CLI)
|
* **private_key_jwt**: JWT‑based client auth + **DPoP** header (preferred for tools and CLI)
|
||||||
* **Device Code** (CLI): `POST /oauth/device/code` + `POST /oauth/token` poll
|
* **Device Code** (CLI): `POST /oauth/device/code` + `POST /oauth/token` poll
|
||||||
* **Authorization Code + PKCE** (UI): standard
|
* **Authorization Code + PKCE** (UI): standard
|
||||||
|
|
||||||
@@ -134,7 +134,7 @@ plan? = <plan name> // optional hint for UIs; not used for e
|
|||||||
|
|
||||||
signed with the DPoP private key; header carries JWK.
|
signed with the DPoP private key; header carries JWK.
|
||||||
3. Authority validates proof; issues access token with `cnf.jkt=<thumbprint(JWK)>`.
|
3. Authority validates proof; issues access token with `cnf.jkt=<thumbprint(JWK)>`.
|
||||||
4. Client uses the same DPoP key to sign **every subsequent API request** to services (Signer, Scanner, …).
|
4. Client uses the same DPoP key to sign **every subsequent API request** to services (Signer, Scanner, …).
|
||||||
|
|
||||||
**mTLS flow**
|
**mTLS flow**
|
||||||
|
|
||||||
@@ -142,11 +142,11 @@ plan? = <plan name> // optional hint for UIs; not used for e
|
|||||||
|
|
||||||
### 3.3 Introspection & revocation (optional)
|
### 3.3 Introspection & revocation (optional)
|
||||||
|
|
||||||
* `POST /introspect` → `{ active, sub, scope, aud, exp, cnf, ... }`
|
* `POST /introspect` → `{ active, sub, scope, aud, exp, cnf, ... }`
|
||||||
* `POST /revoke` → revokes refresh tokens or opaque access tokens.
|
* `POST /revoke` → revokes refresh tokens or opaque access tokens.
|
||||||
|
|
||||||
> Requests targeting the legacy `/oauth/{introspect|revoke}` paths receive deprecation headers and are scheduled for removal after 1 May 2026.
|
> Requests targeting the legacy `/oauth/{introspect|revoke}` paths receive deprecation headers and are scheduled for removal after 1 May 2026.
|
||||||
* **Replay prevention**: maintain **DPoP `jti` cache** (TTL ≤ 10 min) to reject duplicate proofs when services supply DPoP nonces (Signer requires nonce for high‑value operations).
|
* **Replay prevention**: maintain **DPoP `jti` cache** (TTL ≤ 10 min) to reject duplicate proofs when services supply DPoP nonces (Signer requires nonce for high‑value operations).
|
||||||
|
|
||||||
### 3.4 UserInfo (optional for UI)
|
### 3.4 UserInfo (optional for UI)
|
||||||
|
|
||||||
@@ -156,19 +156,19 @@ plan? = <plan name> // optional hint for UIs; not used for e
|
|||||||
|
|
||||||
### 3.5 Vuln Explorer workflow safeguards
|
### 3.5 Vuln Explorer workflow safeguards
|
||||||
|
|
||||||
* **Anti-forgery flow** — Vuln Explorer’s mutation verbs call
|
* **Anti-forgery flow** — Vuln Explorer’s mutation verbs call
|
||||||
* `POST /vuln/workflow/anti-forgery/issue`
|
* `POST /vuln/workflow/anti-forgery/issue`
|
||||||
* `POST /vuln/workflow/anti-forgery/verify`
|
* `POST /vuln/workflow/anti-forgery/verify`
|
||||||
|
|
||||||
Callers must hold `vuln:operate` scopes. Issued tokens embed the actor, tenant, whitelisted actions, ABAC selectors (environment/owner/business tier), and optional context key/value pairs. Tokens are EdDSA/ES256 signed via the primary Authority signing key and default to a 10‑minute TTL (cap: 30 minutes). Verification enforces nonce reuse prevention, tenant match, and action membership before forwarding the request to Vuln Explorer.
|
Callers must hold `vuln:operate` scopes. Issued tokens embed the actor, tenant, whitelisted actions, ABAC selectors (environment/owner/business tier), and optional context key/value pairs. Tokens are EdDSA/ES256 signed via the primary Authority signing key and default to a 10‑minute TTL (cap: 30 minutes). Verification enforces nonce reuse prevention, tenant match, and action membership before forwarding the request to Vuln Explorer.
|
||||||
|
|
||||||
* **Attachment access** — Evidence bundles and attachments reference a ledger hash. Vuln Explorer obtains a scoped download token through:
|
* **Attachment access** — Evidence bundles and attachments reference a ledger hash. Vuln Explorer obtains a scoped download token through:
|
||||||
* `POST /vuln/attachments/tokens/issue`
|
* `POST /vuln/attachments/tokens/issue`
|
||||||
* `POST /vuln/attachments/tokens/verify`
|
* `POST /vuln/attachments/tokens/verify`
|
||||||
|
|
||||||
These tokens bind the ledger event hash, attachment identifier, optional finding/content metadata, and the actor. They default to a 30‑minute TTL (cap: 4 hours) and require `vuln:investigate`.
|
These tokens bind the ledger event hash, attachment identifier, optional finding/content metadata, and the actor. They default to a 30‑minute TTL (cap: 4 hours) and require `vuln:investigate`.
|
||||||
|
|
||||||
* **Audit trail** — Both flows emit `vuln.workflow.csrf.*` and `vuln.attachment.token.*` audit records with tenant, actor, ledger hash, nonce, and filtered context metadata so Offline Kit operators can reconcile actions against ledger entries.
|
* **Audit trail** — Both flows emit `vuln.workflow.csrf.*` and `vuln.attachment.token.*` audit records with tenant, actor, ledger hash, nonce, and filtered context metadata so Offline Kit operators can reconcile actions against ledger entries.
|
||||||
|
|
||||||
* **Configuration**
|
* **Configuration**
|
||||||
|
|
||||||
@@ -200,7 +200,7 @@ plan? = <plan name> // optional hint for UIs; not used for e
|
|||||||
|
|
||||||
### 4.1 Audiences
|
### 4.1 Audiences
|
||||||
|
|
||||||
* `signer` — only the **Signer** service should accept tokens with `aud=signer`.
|
* `signer` — only the **Signer** service should accept tokens with `aud=signer`.
|
||||||
* `attestor`, `scanner`, `concelier`, `excititor`, `ui`, `zastava` similarly.
|
* `attestor`, `scanner`, `concelier`, `excititor`, `ui`, `zastava` similarly.
|
||||||
|
|
||||||
Services **must** verify `aud` and **sender constraint** (DPoP/mTLS) per their policy.
|
Services **must** verify `aud` and **sender constraint** (DPoP/mTLS) per their policy.
|
||||||
@@ -227,13 +227,13 @@ Services **must** verify `aud` and **sender constraint** (DPoP/mTLS) per their p
|
|||||||
| `authority:branding.read` / `authority:branding.write` | Authority | Branding admin |
|
| `authority:branding.read` / `authority:branding.write` | Authority | Branding admin |
|
||||||
| `zastava.emit` / `zastava.enforce` | Scanner/Zastava | Runtime events / admission |
|
| `zastava.emit` / `zastava.enforce` | Scanner/Zastava | Runtime events / admission |
|
||||||
|
|
||||||
**Roles → scopes mapping** is configured centrally (Authority policy) and pushed during token issuance.
|
**Roles → scopes mapping** is configured centrally (Authority policy) and pushed during token issuance.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 5) Storage & state
|
## 5) Storage & state
|
||||||
|
|
||||||
* **Configuration DB** (PostgreSQL/MySQL): clients, audiences, role→scope maps, tenant/installation registry, device code grants, persistent consents (if any).
|
* **Configuration DB** (PostgreSQL/MySQL): clients, audiences, role→scope maps, tenant/installation registry, device code grants, persistent consents (if any).
|
||||||
* **Cache** (Valkey):
|
* **Cache** (Valkey):
|
||||||
|
|
||||||
* DPoP **jti** replay cache (short TTL)
|
* DPoP **jti** replay cache (short TTL)
|
||||||
@@ -247,20 +247,20 @@ Services **must** verify `aud` and **sender constraint** (DPoP/mTLS) per their p
|
|||||||
|
|
||||||
* Maintain **at least 2 signing keys** active during rotation; tokens carry `kid`.
|
* Maintain **at least 2 signing keys** active during rotation; tokens carry `kid`.
|
||||||
* Prefer **Ed25519** for compact tokens; maintain **ES256** fallback for FIPS contexts.
|
* Prefer **Ed25519** for compact tokens; maintain **ES256** fallback for FIPS contexts.
|
||||||
* Rotation cadence: 30–90 days; emergency rotation supported.
|
* Rotation cadence: 30–90 days; emergency rotation supported.
|
||||||
* Publish new JWKS **before** issuing tokens with the new `kid` to avoid cold‑start validation misses.
|
* Publish new JWKS **before** issuing tokens with the new `kid` to avoid cold‑start validation misses.
|
||||||
* Keep **old keys** available **at least** for max token TTL + 5 minutes.
|
* Keep **old keys** available **at least** for max token TTL + 5 minutes.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 7) HA & performance
|
## 7) HA & performance
|
||||||
|
|
||||||
* **Stateless issuance** (except device codes/refresh) → scale horizontally behind a load‑balancer.
|
* **Stateless issuance** (except device codes/refresh) → scale horizontally behind a load‑balancer.
|
||||||
* **DB** only for client metadata and optional flows; token checks are JWT‑local; introspection endpoints hit cache/DB minimally.
|
* **DB** only for client metadata and optional flows; token checks are JWT‑local; introspection endpoints hit cache/DB minimally.
|
||||||
* **Targets**:
|
* **Targets**:
|
||||||
|
|
||||||
* Token issuance P95 ≤ **20 ms** under warm cache.
|
* Token issuance P95 ≤ **20 ms** under warm cache.
|
||||||
* DPoP proof validation ≤ **1 ms** extra per request at resource servers (Signer/Scanner).
|
* DPoP proof validation ≤ **1 ms** extra per request at resource servers (Signer/Scanner).
|
||||||
* 99.9% uptime; HPA on CPU/latency.
|
* 99.9% uptime; HPA on CPU/latency.
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -269,7 +269,7 @@ Services **must** verify `aud` and **sender constraint** (DPoP/mTLS) per their p
|
|||||||
|
|
||||||
* **Strict TLS** (1.3 preferred); HSTS; modern cipher suites.
|
* **Strict TLS** (1.3 preferred); HSTS; modern cipher suites.
|
||||||
* **mTLS** enabled where required (Signer/Attestor paths).
|
* **mTLS** enabled where required (Signer/Attestor paths).
|
||||||
* **Replay protection**: DPoP `jti` cache, nonce support for **Signer** (add `DPoP-Nonce` header on 401; clients re‑sign).
|
* **Replay protection**: DPoP `jti` cache, nonce support for **Signer** (add `DPoP-Nonce` header on 401; clients re‑sign).
|
||||||
* **Rate limits** per client & per IP; exponential backoff on failures.
|
* **Rate limits** per client & per IP; exponential backoff on failures.
|
||||||
* **Secrets**: clients use **private_key_jwt** or **mTLS**; never basic secrets over the wire.
|
* **Secrets**: clients use **private_key_jwt** or **mTLS**; never basic secrets over the wire.
|
||||||
* **CSP/CSRF** hardening on UI flows; `SameSite=Lax` cookies; PKCE enforced.
|
* **CSP/CSRF** hardening on UI flows; `SameSite=Lax` cookies; PKCE enforced.
|
||||||
@@ -277,10 +277,10 @@ Services **must** verify `aud` and **sender constraint** (DPoP/mTLS) per their p
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 9) Multi‑tenancy & installations
|
## 9) Multi‑tenancy & installations
|
||||||
|
|
||||||
* **Tenant (`tid`)** and **Installation (`inst`)** registries define which audiences/scopes a client can request.
|
* **Tenant (`tid`)** and **Installation (`inst`)** registries define which audiences/scopes a client can request.
|
||||||
* Cross‑tenant isolation enforced at issuance (disallow rogue `aud`), and resource servers **must** check that `tid` matches their configured tenant.
|
* Cross‑tenant isolation enforced at issuance (disallow rogue `aud`), and resource servers **must** check that `tid` matches their configured tenant.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -293,7 +293,7 @@ Authority exposes two admin tiers:
|
|||||||
```
|
```
|
||||||
POST /admin/clients # create/update client (confidential/public)
|
POST /admin/clients # create/update client (confidential/public)
|
||||||
POST /admin/audiences # register audience resource URIs
|
POST /admin/audiences # register audience resource URIs
|
||||||
POST /admin/roles # define role→scope mappings
|
POST /admin/roles # define role→scope mappings
|
||||||
POST /admin/tenants # create tenant/install entries
|
POST /admin/tenants # create tenant/install entries
|
||||||
POST /admin/keys/rotate # rotate signing key (zero-downtime)
|
POST /admin/keys/rotate # rotate signing key (zero-downtime)
|
||||||
GET /admin/metrics # Prometheus exposition (token issue rates, errors)
|
GET /admin/metrics # Prometheus exposition (token issue rates, errors)
|
||||||
@@ -306,10 +306,10 @@ Declared client `audiences` flow through to the issued JWT `aud` claim and the t
|
|||||||
|
|
||||||
## 11) Integration hard lines (what resource servers must enforce)
|
## 11) Integration hard lines (what resource servers must enforce)
|
||||||
|
|
||||||
Every Stella Ops service that consumes Authority tokens **must**:
|
Every Stella Ops service that consumes Authority tokens **must**:
|
||||||
|
|
||||||
1. Verify JWT signature (`kid` in JWKS), `iss`, `aud`, `exp`, `nbf`.
|
1. Verify JWT signature (`kid` in JWKS), `iss`, `aud`, `exp`, `nbf`.
|
||||||
2. Enforce **sender‑constraint**:
|
2. Enforce **sender‑constraint**:
|
||||||
|
|
||||||
* **DPoP**: validate DPoP proof (`htu`, `htm`, `iat`, `jti`) and match `cnf.jkt`; cache `jti` for replay defense; honor nonce challenges.
|
* **DPoP**: validate DPoP proof (`htu`, `htm`, `iat`, `jti`) and match `cnf.jkt`; cache `jti` for replay defense; honor nonce challenges.
|
||||||
* **mTLS**: match presented client cert thumbprint to token `cnf.x5t#S256`.
|
* **mTLS**: match presented client cert thumbprint to token `cnf.x5t#S256`.
|
||||||
@@ -322,8 +322,8 @@ Every Stella Ops service that consumes Authority tokens **must**:
|
|||||||
## 12) Error surfaces & UX
|
## 12) Error surfaces & UX
|
||||||
|
|
||||||
* Token endpoint errors follow OAuth2 (`invalid_client`, `invalid_grant`, `invalid_scope`, `unauthorized_client`).
|
* Token endpoint errors follow OAuth2 (`invalid_client`, `invalid_grant`, `invalid_scope`, `unauthorized_client`).
|
||||||
* Resource servers use RFC 6750 style (`WWW-Authenticate: DPoP error="invalid_token", error_description="…", dpop_nonce="…" `).
|
* Resource servers use RFC 6750 style (`WWW-Authenticate: DPoP error="invalid_token", error_description="…", dpop_nonce="…" `).
|
||||||
* For DPoP nonce challenges, clients retry with the server‑supplied nonce once.
|
* For DPoP nonce challenges, clients retry with the server‑supplied nonce once.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -431,8 +431,8 @@ authority:
|
|||||||
* **JWT validation**: wrong `aud`, expired `exp`, skewed `nbf`, stale `kid`.
|
* **JWT validation**: wrong `aud`, expired `exp`, skewed `nbf`, stale `kid`.
|
||||||
* **DPoP**: invalid `htu`/`htm`, replayed `jti`, stale `iat`, wrong `jkt`, nonce dance.
|
* **DPoP**: invalid `htu`/`htm`, replayed `jti`, stale `iat`, wrong `jkt`, nonce dance.
|
||||||
* **mTLS**: wrong client cert, wrong CA, thumbprint mismatch.
|
* **mTLS**: wrong client cert, wrong CA, thumbprint mismatch.
|
||||||
* **RBAC**: scope enforcement per audience; over‑privileged client denied.
|
* **RBAC**: scope enforcement per audience; over‑privileged client denied.
|
||||||
* **Rotation**: JWKS rotation while load‑testing; zero‑downtime verification.
|
* **Rotation**: JWKS rotation while load‑testing; zero‑downtime verification.
|
||||||
* **HA**: kill one Authority instance; verify issuance continues; JWKS served by peers.
|
* **HA**: kill one Authority instance; verify issuance continues; JWKS served by peers.
|
||||||
* **Performance**: 1k token issuance/sec on 2 cores with Valkey enabled for jti caching.
|
* **Performance**: 1k token issuance/sec on 2 cores with Valkey enabled for jti caching.
|
||||||
|
|
||||||
@@ -442,18 +442,18 @@ authority:
|
|||||||
|
|
||||||
| Threat | Vector | Mitigation |
|
| Threat | Vector | Mitigation |
|
||||||
| ------------------- | ---------------- | ------------------------------------------------------------------------------------------ |
|
| ------------------- | ---------------- | ------------------------------------------------------------------------------------------ |
|
||||||
| Token theft | Copy of JWT | **Short TTL**, **sender‑constraint** (DPoP/mTLS); replay blocked by `jti` cache and nonces |
|
| Token theft | Copy of JWT | **Short TTL**, **sender‑constraint** (DPoP/mTLS); replay blocked by `jti` cache and nonces |
|
||||||
| Replay across hosts | Reuse DPoP proof | Enforce `htu`/`htm`, `iat` freshness, `jti` uniqueness; services may require **nonce** |
|
| Replay across hosts | Reuse DPoP proof | Enforce `htu`/`htm`, `iat` freshness, `jti` uniqueness; services may require **nonce** |
|
||||||
| Impersonation | Fake client | mTLS or `private_key_jwt` with pinned JWK; client registration & rotation |
|
| Impersonation | Fake client | mTLS or `private_key_jwt` with pinned JWK; client registration & rotation |
|
||||||
| Key compromise | Signing key leak | HSM/KMS storage, key rotation, audit; emergency key revoke path; narrow token TTL |
|
| Key compromise | Signing key leak | HSM/KMS storage, key rotation, audit; emergency key revoke path; narrow token TTL |
|
||||||
| Cross‑tenant abuse | Scope elevation | Enforce `aud`, `tid`, `inst` at issuance and resource servers |
|
| Cross‑tenant abuse | Scope elevation | Enforce `aud`, `tid`, `inst` at issuance and resource servers |
|
||||||
| Downgrade to bearer | Strip DPoP | Resource servers require DPoP/mTLS based on `aud`; reject bearer without `cnf` |
|
| Downgrade to bearer | Strip DPoP | Resource servers require DPoP/mTLS based on `aud`; reject bearer without `cnf` |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 17) Deployment & HA
|
## 17) Deployment & HA
|
||||||
|
|
||||||
* **Stateless** microservice, containerized; run ≥ 2 replicas behind LB.
|
* **Stateless** microservice, containerized; run ≥ 2 replicas behind LB.
|
||||||
* **DB**: HA Postgres (or MySQL) for clients/roles; **Valkey** for device codes, DPoP nonces/jtis.
|
* **DB**: HA Postgres (or MySQL) for clients/roles; **Valkey** for device codes, DPoP nonces/jtis.
|
||||||
* **Secrets**: mount client JWKs via K8s Secrets/HashiCorp Vault; signing keys via KMS.
|
* **Secrets**: mount client JWKs via K8s Secrets/HashiCorp Vault; signing keys via KMS.
|
||||||
* **Backups**: DB daily; Valkey not critical (ephemeral).
|
* **Backups**: DB daily; Valkey not critical (ephemeral).
|
||||||
@@ -470,7 +470,7 @@ authority:
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 19) Quick reference — wire examples
|
## 19) Quick reference — wire examples
|
||||||
|
|
||||||
**Access token (payload excerpt)**
|
**Access token (payload excerpt)**
|
||||||
|
|
||||||
@@ -507,10 +507,10 @@ Signer validates that `hash(JWK)` in the proof matches `cnf.jkt` in the token.
|
|||||||
|
|
||||||
## 20) Rollout plan
|
## 20) Rollout plan
|
||||||
|
|
||||||
1. **MVP**: Client Credentials (private_key_jwt + DPoP), JWKS, short OpToks, per‑audience scopes.
|
1. **MVP**: Client Credentials (private_key_jwt + DPoP), JWKS, short OpToks, per‑audience scopes.
|
||||||
2. **Add**: mTLS‑bound tokens for Signer/Attestor; device code for CLI; optional introspection.
|
2. **Add**: mTLS‑bound tokens for Signer/Attestor; device code for CLI; optional introspection.
|
||||||
3. **Hardening**: DPoP nonce support; full audit pipeline; HA tuning.
|
3. **Hardening**: DPoP nonce support; full audit pipeline; HA tuning.
|
||||||
4. **UX**: Tenant/installation admin UI; role→scope editors; client bootstrap wizards.
|
4. **UX**: Tenant/installation admin UI; role→scope editors; client bootstrap wizards.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -1,26 +1,26 @@
|
|||||||
# component_architecture_cli.md — **Stella Ops CLI** (2025Q4)
|
# component_architecture_cli.md — **Stella Ops CLI** (2025Q4)
|
||||||
|
|
||||||
> Consolidates requirements captured in the Policy Engine, Policy Studio, Vulnerability Explorer, Export Center, and Notifications implementation plans and module guides.
|
> Consolidates requirements captured in the Policy Engine, Policy Studio, Vulnerability Explorer, Export Center, and Notifications implementation plans and module guides.
|
||||||
|
|
||||||
> **Scope.** Implementation‑ready architecture for **Stella Ops CLI**: command surface, process model, auth (Authority/DPoP), integration with Scanner/Excititor/Concelier/Signer/Attestor, Buildx plug‑in management, offline kit behavior, packaging, observability, security posture, and CI ergonomics.
|
> **Scope.** Implementation‑ready architecture for **Stella Ops CLI**: command surface, process model, auth (Authority/DPoP), integration with Scanner/Excititor/Concelier/Signer/Attestor, Buildx plug‑in management, offline kit behavior, packaging, observability, security posture, and CI ergonomics.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 0) Mission & boundaries
|
## 0) Mission & boundaries
|
||||||
|
|
||||||
**Mission.** Provide a **fast, deterministic, CI‑friendly** command‑line interface to drive Stella Ops workflows:
|
**Mission.** Provide a **fast, deterministic, CI‑friendly** command‑line interface to drive Stella Ops workflows:
|
||||||
|
|
||||||
* Build‑time SBOM generation via **Buildx generator** orchestration.
|
* Build‑time SBOM generation via **Buildx generator** orchestration.
|
||||||
* Post‑build **scan/compose/diff/export** against **Scanner.WebService**.
|
* Post‑build **scan/compose/diff/export** against **Scanner.WebService**.
|
||||||
* **Policy** operations and **VEX/Vuln** data pulls (operator tasks).
|
* **Policy** operations and **VEX/Vuln** data pulls (operator tasks).
|
||||||
* **Verification** (attestation, referrers, signatures) for audits.
|
* **Verification** (attestation, referrers, signatures) for audits.
|
||||||
* Air‑gapped/offline **kit** administration.
|
* Air‑gapped/offline **kit** administration.
|
||||||
|
|
||||||
**Boundaries.**
|
**Boundaries.**
|
||||||
|
|
||||||
* CLI **never** signs; it only calls **Signer**/**Attestor** via backend APIs when needed (e.g., `report --attest`).
|
* CLI **never** signs; it only calls **Signer**/**Attestor** via backend APIs when needed (e.g., `report --attest`).
|
||||||
* CLI **does not** store long‑lived credentials beyond OS keychain; tokens are **short** (Authority OpToks).
|
* CLI **does not** store long‑lived credentials beyond OS keychain; tokens are **short** (Authority OpToks).
|
||||||
* Heavy work (scanning, merging, policy) is executed **server‑side** (Scanner/Excititor/Concelier).
|
* Heavy work (scanning, merging, policy) is executed **server‑side** (Scanner/Excititor/Concelier).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -41,7 +41,7 @@ src/
|
|||||||
|
|
||||||
**Plug-in verbs.** Non-core verbs (Excititor, runtime helpers, future integrations) ship as restart-time plug-ins under `plugins/cli/**` with manifest descriptors. The launcher loads plug-ins on startup; hot reloading is intentionally unsupported. The inaugural bundle, `StellaOps.Cli.Plugins.NonCore`, packages the Excititor, runtime, and offline-kit command groups and publishes its manifest at `plugins/cli/StellaOps.Cli.Plugins.NonCore/`.
|
**Plug-in verbs.** Non-core verbs (Excititor, runtime helpers, future integrations) ship as restart-time plug-ins under `plugins/cli/**` with manifest descriptors. The launcher loads plug-ins on startup; hot reloading is intentionally unsupported. The inaugural bundle, `StellaOps.Cli.Plugins.NonCore`, packages the Excititor, runtime, and offline-kit command groups and publishes its manifest at `plugins/cli/StellaOps.Cli.Plugins.NonCore/`.
|
||||||
|
|
||||||
**OS targets**: linuxâ€'x64/arm64, windowsâ€'x64/arm64, macOSâ€'x64/arm64.
|
**OS targets**: linux‑x64/arm64, windows‑x64/arm64, macOS‑x64/arm64.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -118,19 +118,19 @@ See [migration-v3.md](./guides/migration-v3.md) for user-facing migration instru
|
|||||||
|
|
||||||
* `auth login`
|
* `auth login`
|
||||||
|
|
||||||
* Modes: **device‑code** (default), **client‑credentials** (service principal).
|
* Modes: **device‑code** (default), **client‑credentials** (service principal).
|
||||||
* Produces **Authority** access token (OpTok) + stores **DPoP** keypair in OS keychain.
|
* Produces **Authority** access token (OpTok) + stores **DPoP** keypair in OS keychain.
|
||||||
* `auth status` — show current issuer, subject, audiences, expiry.
|
* `auth status` — show current issuer, subject, audiences, expiry.
|
||||||
* `auth logout` — wipe cached tokens/keys.
|
* `auth logout` — wipe cached tokens/keys.
|
||||||
|
|
||||||
### 2.2 Build‑time SBOM (Buildx)
|
### 2.2 Build‑time SBOM (Buildx)
|
||||||
|
|
||||||
* `buildx install` — install/update the **StellaOps.Scanner.Sbomer.BuildXPlugin** on the host.
|
* `buildx install` — install/update the **StellaOps.Scanner.Sbomer.BuildXPlugin** on the host.
|
||||||
* `buildx verify` — ensure generator is usable.
|
* `buildx verify` — ensure generator is usable.
|
||||||
* `buildx build` — thin wrapper around `docker buildx build --attest=type=sbom,generator=stellaops/sbom-indexer` with convenience flags:
|
* `buildx build` — thin wrapper around `docker buildx build --attest=type=sbom,generator=stellaops/sbom-indexer` with convenience flags:
|
||||||
|
|
||||||
* `--attest` (request Signer/Attestor via backend post‑push)
|
* `--attest` (request Signer/Attestor via backend post‑push)
|
||||||
* `--provenance` pass‑through (optional)
|
* `--provenance` pass‑through (optional)
|
||||||
|
|
||||||
### 2.3 Scanning & artifacts
|
### 2.3 Scanning & artifacts
|
||||||
|
|
||||||
@@ -138,20 +138,20 @@ See [migration-v3.md](./guides/migration-v3.md) for user-facing migration instru
|
|||||||
|
|
||||||
* Options: `--force`, `--wait`, `--view=inventory|usage|both`, `--format=cdx-json|cdx-pb|spdx-json`, `--attest` (ask backend to sign/log).
|
* Options: `--force`, `--wait`, `--view=inventory|usage|both`, `--format=cdx-json|cdx-pb|spdx-json`, `--attest` (ask backend to sign/log).
|
||||||
* Streams progress; exits early unless `--wait`.
|
* Streams progress; exits early unless `--wait`.
|
||||||
* `diff image --old <digest> --new <digest> [--view ...]` — show layer‑attributed changes.
|
* `diff image --old <digest> --new <digest> [--view ...]` — show layer‑attributed changes.
|
||||||
* `export sbom <digest> [--view ... --format ... --out file]` — download artifact.
|
* `export sbom <digest> [--view ... --format ... --out file]` — download artifact.
|
||||||
* `sbom upload --file <path> --artifact <ref> [--format cyclonedx|spdx]` - BYOS upload into the scanner analysis pipeline (ledger join uses the SBOM digest).
|
* `sbom upload --file <path> --artifact <ref> [--format cyclonedx|spdx]` - BYOS upload into the scanner analysis pipeline (ledger join uses the SBOM digest).
|
||||||
* `report final <digest> [--policy-revision ... --attest]` — request PASS/FAIL report from backend (policy+vex) and optional attestation.
|
* `report final <digest> [--policy-revision ... --attest]` — request PASS/FAIL report from backend (policy+vex) and optional attestation.
|
||||||
### 2.3.1 Compare Commands & Baseline Selection (SPRINT_20260208_029)
|
### 2.3.1 Compare Commands & Baseline Selection (SPRINT_20260208_029)
|
||||||
|
|
||||||
The `compare` command group supports diffing scan snapshots with automatic baseline resolution.
|
The `compare` command group supports diffing scan snapshots with automatic baseline resolution.
|
||||||
|
|
||||||
#### Commands
|
#### Commands
|
||||||
|
|
||||||
* `compare diff --base <digest> --target <digest>` â€" Full comparison showing detailed diff.
|
* `compare diff --base <digest> --target <digest>` — Full comparison showing detailed diff.
|
||||||
* `compare summary --base <digest> --target <digest>` â€" Quick summary of changes.
|
* `compare summary --base <digest> --target <digest>` — Quick summary of changes.
|
||||||
* `compare can-ship --base <digest> --target <digest>` â€" Check if target passes policy (exit code: 0=pass, 1=fail).
|
* `compare can-ship --base <digest> --target <digest>` — Check if target passes policy (exit code: 0=pass, 1=fail).
|
||||||
* `compare vulns --base <digest> --target <digest>` â€" List vulnerability changes only.
|
* `compare vulns --base <digest> --target <digest>` — List vulnerability changes only.
|
||||||
|
|
||||||
#### Baseline Selection Strategies
|
#### Baseline Selection Strategies
|
||||||
|
|
||||||
@@ -165,9 +165,9 @@ All compare commands support `--baseline-strategy` for automatic baseline resolu
|
|||||||
|
|
||||||
**Options:**
|
**Options:**
|
||||||
|
|
||||||
* `--baseline-strategy <explicit|last-green|previous-release>` â€" Strategy for baseline selection
|
* `--baseline-strategy <explicit|last-green|previous-release>` — Strategy for baseline selection
|
||||||
* `--artifact <purl|oci-ref>` â€" Artifact identifier for auto-resolution strategies
|
* `--artifact <purl|oci-ref>` — Artifact identifier for auto-resolution strategies
|
||||||
* `--current-version <tag>` â€" Current version (helps `previous-release` find older releases)
|
* `--current-version <tag>` — Current version (helps `previous-release` find older releases)
|
||||||
* `--verification-report <path>` - Attach `bundle verify --output json` checks to compare output (hash/signature overlay)
|
* `--verification-report <path>` - Attach `bundle verify --output json` checks to compare output (hash/signature overlay)
|
||||||
* `--reverify-bundle <directory>` - Recompute artifact hash and DSSE-sidecar status from local evidence bundle for live re-verification
|
* `--reverify-bundle <directory>` - Recompute artifact hash and DSSE-sidecar status from local evidence bundle for live re-verification
|
||||||
* `--determinism-manifest <path>` - Attach determinism manifest score/threshold summary to compare output
|
* `--determinism-manifest <path>` - Attach determinism manifest score/threshold summary to compare output
|
||||||
@@ -214,32 +214,32 @@ public interface IBaselineResolver
|
|||||||
```
|
```
|
||||||
### 2.4 Policy & data
|
### 2.4 Policy & data
|
||||||
|
|
||||||
* `policy get/set/apply` — fetch active policy, apply staged policy, compute digest.
|
* `policy get/set/apply` — fetch active policy, apply staged policy, compute digest.
|
||||||
* `concelier export` — trigger/export canonical JSON or Trivy DB (admin).
|
* `concelier export` — trigger/export canonical JSON or Trivy DB (admin).
|
||||||
* `excititor export` — trigger/export consensus/raw claims (admin).
|
* `excititor export` — trigger/export consensus/raw claims (admin).
|
||||||
|
|
||||||
### 2.5 Verification
|
### 2.5 Verification
|
||||||
|
|
||||||
* `verify attestation --uuid <rekor-uuid> | --artifact <sha256> | --bundle <path>` — call **Attestor /verify** and print proof summary.
|
* `verify attestation --uuid <rekor-uuid> | --artifact <sha256> | --bundle <path>` — call **Attestor /verify** and print proof summary.
|
||||||
* `verify referrers <digest>` — ask **Signer /verify/referrers** (is image Stella‑signed?).
|
* `verify referrers <digest>` — ask **Signer /verify/referrers** (is image Stella‑signed?).
|
||||||
* `verify image-signature <ref|digest>` — standalone cosign verification (optional, local).
|
* `verify image-signature <ref|digest>` — standalone cosign verification (optional, local).
|
||||||
* `verify release <bundle> [--sbom <path>] [--vex <path>] [--trust-root <path>] [--checkpoint <path>]` — run promotion bundle verification and fail if source/build/rekor/signature links cannot be validated.
|
* `verify release <bundle> [--sbom <path>] [--vex <path>] [--trust-root <path>] [--checkpoint <path>]` — run promotion bundle verification and fail if source/build/rekor/signature links cannot be validated.
|
||||||
|
|
||||||
### 2.6 Runtime (Zastava helper)
|
### 2.6 Runtime (Zastava helper)
|
||||||
|
|
||||||
* `runtime policy test --image/-i <digest> [--file <path> --ns <name> --label key=value --json]` — ask backend `/policy/runtime` like the webhook would (accepts multiple `--image`, comma/space lists, or stdin pipelines).
|
* `runtime policy test --image/-i <digest> [--file <path> --ns <name> --label key=value --json]` — ask backend `/policy/runtime` like the webhook would (accepts multiple `--image`, comma/space lists, or stdin pipelines).
|
||||||
|
|
||||||
### 2.7 Offline kit
|
### 2.7 Offline kit
|
||||||
|
|
||||||
* `offline kit pull` — fetch latest **Concelier JSON + Trivy DB + Excititor exports** as a tarball from a mirror.
|
* `offline kit pull` — fetch latest **Concelier JSON + Trivy DB + Excititor exports** as a tarball from a mirror.
|
||||||
* `offline kit import <tar>` — upload the kit to on‑prem services (Concelier/Excititor).
|
* `offline kit import <tar>` — upload the kit to on‑prem services (Concelier/Excititor).
|
||||||
* `offline kit status` — list current seed versions.
|
* `offline kit status` — list current seed versions.
|
||||||
|
|
||||||
### 2.8 Utilities
|
### 2.8 Utilities
|
||||||
|
|
||||||
* `config set/get` — endpoint & defaults.
|
* `config set/get` — endpoint & defaults.
|
||||||
* `whoami` — short auth display.
|
* `whoami` — short auth display.
|
||||||
* `version` — CLI + protocol versions; release channel.
|
* `version` — CLI + protocol versions; release channel.
|
||||||
* `tools policy-dsl-validate <paths...> [--strict] [--json]`
|
* `tools policy-dsl-validate <paths...> [--strict] [--json]`
|
||||||
* `tools policy-schema-export [--output <dir>] [--repo-root <path>]`
|
* `tools policy-schema-export [--output <dir>] [--repo-root <path>]`
|
||||||
* `tools policy-simulation-smoke [--scenario-root <path>] [--output <dir>] [--repo-root <path>] [--fixed-time <ISO-8601>]`
|
* `tools policy-simulation-smoke [--scenario-root <path>] [--output <dir>] [--repo-root <path>] [--fixed-time <ISO-8601>]`
|
||||||
@@ -356,7 +356,7 @@ Both subcommands honour offline-first expectations (no network access) and norma
|
|||||||
- `decision compare`
|
- `decision compare`
|
||||||
|
|
||||||
* Executes the benchmark harness against baseline scanners (Trivy/Syft/Grype/Snyk/Xray), capturing false-positive reduction, mean-time-to-decision, and reproducibility metrics into `results/summary.csv`.
|
* Executes the benchmark harness against baseline scanners (Trivy/Syft/Grype/Snyk/Xray), capturing false-positive reduction, mean-time-to-decision, and reproducibility metrics into `results/summary.csv`.
|
||||||
* Flags regressions when Stella Ops produces more false positives or slower MTTD than the configured target.
|
* Flags regressions when Stella Ops produces more false positives or slower MTTD than the configured target.
|
||||||
|
|
||||||
All verbs require scopes `policy.findings:read`, `signer.verify`, and (for Rekor lookups) `attestor.read`. They honour sealed-mode rules by falling back to offline verification only when Rekor/Signer endpoints are unreachable.
|
All verbs require scopes `policy.findings:read`, `signer.verify`, and (for Rekor lookups) `attestor.read`. They honour sealed-mode rules by falling back to offline verification only when Rekor/Signer endpoints are unreachable.
|
||||||
|
|
||||||
@@ -379,15 +379,15 @@ All verbs require scopes `policy.findings:read`, `signer.verify`, and (for Rekor
|
|||||||
|
|
||||||
### 3.1 Token acquisition
|
### 3.1 Token acquisition
|
||||||
|
|
||||||
* **Device‑code**: the CLI opens an OIDC device code flow against **Authority**; the browser login is optional for service principals.
|
* **Device‑code**: the CLI opens an OIDC device code flow against **Authority**; the browser login is optional for service principals.
|
||||||
* **Client‑credentials**: service principals use **private_key_jwt** or **mTLS** to get tokens.
|
* **Client‑credentials**: service principals use **private_key_jwt** or **mTLS** to get tokens.
|
||||||
|
|
||||||
### 3.2 DPoP key management
|
### 3.2 DPoP key management
|
||||||
|
|
||||||
* On first login, the CLI generates an **ephemeral JWK** (Ed25519) and stores it in the **OS keychain** (Keychain/DPAPI/KWallet/Gnome Keyring).
|
* On first login, the CLI generates an **ephemeral JWK** (Ed25519) and stores it in the **OS keychain** (Keychain/DPAPI/KWallet/Gnome Keyring).
|
||||||
* Every request to backend services includes a **DPoP proof**; CLI refreshes tokens as needed.
|
* Every request to backend services includes a **DPoP proof**; CLI refreshes tokens as needed.
|
||||||
|
|
||||||
### 3.3 Multi‑audience & scopes
|
### 3.3 Multi‑audience & scopes
|
||||||
|
|
||||||
* CLI requests **audiences** as needed per verb:
|
* CLI requests **audiences** as needed per verb:
|
||||||
|
|
||||||
@@ -409,10 +409,10 @@ CLI rejects verbs if required scopes are missing.
|
|||||||
|
|
||||||
### 4.2 Streaming
|
### 4.2 Streaming
|
||||||
|
|
||||||
* `scan` and `report` support **server‑sent JSON lines** (progress events).
|
* `scan` and `report` support **server‑sent JSON lines** (progress events).
|
||||||
* `--json` prints machine events; human mode shows compact spinners and crucial updates only.
|
* `--json` prints machine events; human mode shows compact spinners and crucial updates only.
|
||||||
|
|
||||||
### 4.3 Exit codes (CI‑safe)
|
### 4.3 Exit codes (CI‑safe)
|
||||||
|
|
||||||
| Code | Meaning |
|
| Code | Meaning |
|
||||||
| ---- | ------------------------------------------- |
|
| ---- | ------------------------------------------- |
|
||||||
@@ -424,7 +424,7 @@ CLI rejects verbs if required scopes are missing.
|
|||||||
| 6 | Rate limited / quota exceeded |
|
| 6 | Rate limited / quota exceeded |
|
||||||
| 7 | Backend unavailable (retryable) |
|
| 7 | Backend unavailable (retryable) |
|
||||||
| 9 | Invalid arguments |
|
| 9 | Invalid arguments |
|
||||||
| 11–17 | Aggregation-only guard violation (`ERR_AOC_00x`) |
|
| 11–17 | Aggregation-only guard violation (`ERR_AOC_00x`) |
|
||||||
| 18 | Verification truncated (increase `--limit`) |
|
| 18 | Verification truncated (increase `--limit`) |
|
||||||
| 70 | Transport/authentication failure |
|
| 70 | Transport/authentication failure |
|
||||||
| 71 | CLI usage error (missing tenant, invalid cursor) |
|
| 71 | CLI usage error (missing tenant, invalid cursor) |
|
||||||
@@ -468,9 +468,9 @@ Environment variables: `STELLAOPS_AUTHORITY`, `STELLAOPS_SCANNER_URL`, etc.
|
|||||||
|
|
||||||
* `--attest=type=sbom,generator=stellaops/sbom-indexer`
|
* `--attest=type=sbom,generator=stellaops/sbom-indexer`
|
||||||
* `--label org.stellaops.request=sbom`
|
* `--label org.stellaops.request=sbom`
|
||||||
* Post‑build: CLI optionally calls **Scanner.WebService** to **verify referrers**, **compose** image SBOMs, and **attest** via Signer/Attestor.
|
* Post‑build: CLI optionally calls **Scanner.WebService** to **verify referrers**, **compose** image SBOMs, and **attest** via Signer/Attestor.
|
||||||
|
|
||||||
**Detection**: If Buildx or generator unavailable, CLI falls back to **post‑build scan** with a warning.
|
**Detection**: If Buildx or generator unavailable, CLI falls back to **post‑build scan** with a warning.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -484,27 +484,27 @@ Environment variables: `STELLAOPS_AUTHORITY`, `STELLAOPS_SCANNER_URL`, etc.
|
|||||||
## 8) Security posture
|
## 8) Security posture
|
||||||
|
|
||||||
* **DPoP private keys** stored in **OS keychain**; metadata cached in config.
|
* **DPoP private keys** stored in **OS keychain**; metadata cached in config.
|
||||||
* **No plaintext tokens** on disk; short‑lived **OpToks** held in memory.
|
* **No plaintext tokens** on disk; short‑lived **OpToks** held in memory.
|
||||||
* **TLS**: verify backend certificates; allow custom CA bundle for on‑prem.
|
* **TLS**: verify backend certificates; allow custom CA bundle for on‑prem.
|
||||||
* **Redaction**: CLI logs remove `Authorization`, DPoP headers, PoE tokens.
|
* **Redaction**: CLI logs remove `Authorization`, DPoP headers, PoE tokens.
|
||||||
* **Supply chain**: CLI distribution binaries are **cosign‑signed**; `stellaops version --verify` checks its own signature.
|
* **Supply chain**: CLI distribution binaries are **cosign‑signed**; `stellaops version --verify` checks its own signature.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 9) Observability
|
## 9) Observability
|
||||||
|
|
||||||
* `--verbose` adds request IDs, timings, and retry traces.
|
* `--verbose` adds request IDs, timings, and retry traces.
|
||||||
* **Metrics** (optional, disabled by default): Prometheus text file exporter for local monitoring in long‑running agents.
|
* **Metrics** (optional, disabled by default): Prometheus text file exporter for local monitoring in long‑running agents.
|
||||||
* **Structured logs** (`--json`): per‑event JSON lines with `ts`, `verb`, `status`, `latencyMs`.
|
* **Structured logs** (`--json`): per‑event JSON lines with `ts`, `verb`, `status`, `latencyMs`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 10) Performance targets
|
## 10) Performance targets
|
||||||
|
|
||||||
* Startup ≤ **20 ms** (AOT).
|
* Startup ≤ **20 ms** (AOT).
|
||||||
* `scan image` request/response overhead ≤ **5 ms** (excluding server work).
|
* `scan image` request/response overhead ≤ **5 ms** (excluding server work).
|
||||||
* Buildx wrapper overhead negligible (<1 ms).
|
* Buildx wrapper overhead negligible (<1 ms).
|
||||||
* Large artifact download (100 MB) sustained ≥ **80 MB/s** on local networks.
|
* Large artifact download (100 MB) sustained ≥ **80 MB/s** on local networks.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -512,7 +512,7 @@ Environment variables: `STELLAOPS_AUTHORITY`, `STELLAOPS_SCANNER_URL`, etc.
|
|||||||
|
|
||||||
* **Unit tests**: argument parsing, config precedence, URL resolution, DPoP proof creation.
|
* **Unit tests**: argument parsing, config precedence, URL resolution, DPoP proof creation.
|
||||||
* **Integration tests** (Testcontainers): mock Authority/Scanner/Attestor; CI pipeline with fake registry.
|
* **Integration tests** (Testcontainers): mock Authority/Scanner/Attestor; CI pipeline with fake registry.
|
||||||
* **Golden outputs**: verb snapshots for `--json` across OSes; kept in `tests/golden/…`.
|
* **Golden outputs**: verb snapshots for `--json` across OSes; kept in `tests/golden/…`.
|
||||||
* **Contract tests**: ensure API shapes match service OpenAPI; fail build if incompatible.
|
* **Contract tests**: ensure API shapes match service OpenAPI; fail build if incompatible.
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -523,8 +523,8 @@ Environment variables: `STELLAOPS_AUTHORITY`, `STELLAOPS_SCANNER_URL`, etc.
|
|||||||
|
|
||||||
```
|
```
|
||||||
✖ Policy FAIL: 3 high, 1 critical (VEX suppressed 12)
|
✖ Policy FAIL: 3 high, 1 critical (VEX suppressed 12)
|
||||||
- pkg:rpm/openssl (CVE-2025-12345) — affected (vendor) — fixed in 3.0.14
|
- pkg:rpm/openssl (CVE-2025-12345) — affected (vendor) — fixed in 3.0.14
|
||||||
- pkg:npm/lodash (GHSA-xxxx) — affected — no fix
|
- pkg:npm/lodash (GHSA-xxxx) — affected — no fix
|
||||||
See: https://ui.internal/scans/sha256:...
|
See: https://ui.internal/scans/sha256:...
|
||||||
Exit code: 2
|
Exit code: 2
|
||||||
```
|
```
|
||||||
@@ -551,7 +551,7 @@ Exit code: 2
|
|||||||
|
|
||||||
* Emits **CycloneDX Protobuf** directly to stdout when `export sbom --format cdx-pb --out -`.
|
* Emits **CycloneDX Protobuf** directly to stdout when `export sbom --format cdx-pb --out -`.
|
||||||
* Pipes to `jq`/`yq` cleanly in JSON mode.
|
* Pipes to `jq`/`yq` cleanly in JSON mode.
|
||||||
* Can act as a **credential helper** for scripts: `stellaops auth token --aud scanner` prints a one‑shot token for curl.
|
* Can act as a **credential helper** for scripts: `stellaops auth token --aud scanner` prints a one‑shot token for curl.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -559,16 +559,16 @@ Exit code: 2
|
|||||||
|
|
||||||
* **Installers**: deb/rpm (postinst registers completions), Homebrew, Scoop, Winget, MSI/MSIX.
|
* **Installers**: deb/rpm (postinst registers completions), Homebrew, Scoop, Winget, MSI/MSIX.
|
||||||
* **Shell completions**: bash/zsh/fish/pwsh.
|
* **Shell completions**: bash/zsh/fish/pwsh.
|
||||||
* **Update channel**: `stellaops self-update` (optional) fetches cosign‑signed release manifest; corporate environments can disable.
|
* **Update channel**: `stellaops self-update` (optional) fetches cosign‑signed release manifest; corporate environments can disable.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 16) Security hard lines
|
## 16) Security hard lines
|
||||||
|
|
||||||
* Refuse to print token values; redact Authorization headers in verbose output.
|
* Refuse to print token values; redact Authorization headers in verbose output.
|
||||||
* Disallow `--insecure` unless `STELLAOPS_CLI_ALLOW_INSECURE=1` set (double opt‑in).
|
* Disallow `--insecure` unless `STELLAOPS_CLI_ALLOW_INSECURE=1` set (double opt‑in).
|
||||||
* Enforce **short token TTL**; refresh proactively when <30 s left.
|
* Enforce **short token TTL**; refresh proactively when <30 s left.
|
||||||
* Device‑code cache binding to **machine** and **user** (protect against copy to other machines).
|
* Device‑code cache binding to **machine** and **user** (protect against copy to other machines).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -622,14 +622,14 @@ sequenceDiagram
|
|||||||
|
|
||||||
* `scan fs <path>` (local filesystem tree) → upload to backend for analysis.
|
* `scan fs <path>` (local filesystem tree) → upload to backend for analysis.
|
||||||
* `policy test --sbom <file>` (simulate policy results offline using local policy bundle).
|
* `policy test --sbom <file>` (simulate policy results offline using local policy bundle).
|
||||||
* `runtime capture` (developer mode) — capture small `/proc/<pid>/maps` for troubleshooting.
|
* `runtime capture` (developer mode) — capture small `/proc/<pid>/maps` for troubleshooting.
|
||||||
* Pluggable output renderers for SARIF/HTML (admin‑controlled).
|
* Pluggable output renderers for SARIF/HTML (admin‑controlled).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 19) Example CI snippets
|
## 19) Example CI snippets
|
||||||
|
|
||||||
**GitHub Actions (post‑build)**
|
**GitHub Actions (post‑build)**
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- name: Login (device code w/ OIDC broker)
|
- name: Login (device code w/ OIDC broker)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Graph architecture
|
# Graph architecture
|
||||||
|
|
||||||
> Derived from Epic 5 – SBOM Graph Explorer; this section captures the core model, pipeline, and API expectations. Extend with diagrams as implementation matures.
|
> Derived from Epic 5 – SBOM Graph Explorer; this section captures the core model, pipeline, and API expectations. Extend with diagrams as implementation matures.
|
||||||
|
|
||||||
## 1) Core model
|
## 1) Core model
|
||||||
|
|
||||||
@@ -25,11 +25,11 @@
|
|||||||
|
|
||||||
## 3) APIs
|
## 3) APIs
|
||||||
|
|
||||||
- `POST /graph/search` — NDJSON node tiles with cursor paging, tenant + scope guards.
|
- `POST /graph/search` — NDJSON node tiles with cursor paging, tenant + scope guards.
|
||||||
- `POST /graph/query` — NDJSON nodes/edges/stats/cursor with budgets (tiles/nodes/edges) and optional inline overlays (`includeOverlays=true`) emitting `policy.overlay.v1` and `openvex.v1` payloads; overlay IDs are `sha256(tenant|nodeId|overlayKind)`; policy overlay may include a sampled `explainTrace`.
|
- `POST /graph/query` — NDJSON nodes/edges/stats/cursor with budgets (tiles/nodes/edges) and optional inline overlays (`includeOverlays=true`) emitting `policy.overlay.v1` and `openvex.v1` payloads; overlay IDs are `sha256(tenant|nodeId|overlayKind)`; policy overlay may include a sampled `explainTrace`.
|
||||||
- `POST /graph/paths` — bounded BFS (depth ≤6) returning path nodes/edges/stats; honours budgets and overlays.
|
- `POST /graph/paths` — bounded BFS (depth ≤6) returning path nodes/edges/stats; honours budgets and overlays.
|
||||||
- `POST /graph/diff` — compares `snapshotA` vs `snapshotB`, streaming node/edge added/removed/changed tiles plus stats; budget enforcement mirrors `/graph/query`.
|
- `POST /graph/diff` — compares `snapshotA` vs `snapshotB`, streaming node/edge added/removed/changed tiles plus stats; budget enforcement mirrors `/graph/query`.
|
||||||
- `POST /graph/export` — async job producing deterministic manifests (`sha256`, size, format) for `ndjson/csv/graphml/png/svg`; download via `/graph/export/{jobId}`.
|
- `POST /graph/export` — async job producing deterministic manifests (`sha256`, size, format) for `ndjson/csv/graphml/png/svg`; download via `/graph/export/{jobId}`.
|
||||||
- `POST /graph/lineage` - returns SBOM lineage nodes/edges anchored by `artifactDigest` or `sbomDigest`, with optional relationship filters and depth limits.
|
- `POST /graph/lineage` - returns SBOM lineage nodes/edges anchored by `artifactDigest` or `sbomDigest`, with optional relationship filters and depth limits.
|
||||||
- **Edge Metadata API** (added 2025-01):
|
- **Edge Metadata API** (added 2025-01):
|
||||||
- `POST /graph/edges/metadata` — batch query for edge explanations; request contains `EdgeIds[]`, response includes `EdgeTileWithMetadata[]` with full provenance.
|
- `POST /graph/edges/metadata` — batch query for edge explanations; request contains `EdgeIds[]`, response includes `EdgeTileWithMetadata[]` with full provenance.
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
# Advisory AI Assistant Parameters
|
# Advisory AI Assistant Parameters
|
||||||
|
|
||||||
_Primary audience: platform operators & policy authors • Updated: 2026-01-13_
|
_Primary audience: platform operators & policy authors • Updated: 2026-01-13_
|
||||||
|
|
||||||
This note centralises the tunable knobs that control Advisory AI’s planner, retrieval stack, inference clients, and guardrails. All options live under the `AdvisoryAI` configuration section and can be set via `appsettings.*` files or environment variables using ASP.NET Core’s double-underscore convention (`ADVISORYAI__Inference__Mode`, etc.). Chat quotas and tool allowlists can also be overridden per tenant/user via the chat settings endpoints; appsettings/env values are defaults.
|
This note centralises the tunable knobs that control Advisory AI’s planner, retrieval stack, inference clients, and guardrails. All options live under the `AdvisoryAI` configuration section and can be set via `appsettings.*` files or environment variables using ASP.NET Core’s double-underscore convention (`ADVISORYAI__Inference__Mode`, etc.). Chat quotas and tool allowlists can also be overridden per tenant/user via the chat settings endpoints; appsettings/env values are defaults.
|
||||||
|
|
||||||
**Policy/version pin** — For Sprint 0111, use the policy bundle hash shipped on 2025-11-19 (same drop as `CLI-VULN-29-001` / `CLI-VEX-30-001`). Set `AdvisoryAI:PolicyVersion` or `ADVISORYAI__POLICYVERSION=2025.11.19` in deployments; include the hash in DSSE metadata for Offline Kits.
|
**Policy/version pin** — For Sprint 0111, use the policy bundle hash shipped on 2025-11-19 (same drop as `CLI-VULN-29-001` / `CLI-VEX-30-001`). Set `AdvisoryAI:PolicyVersion` or `ADVISORYAI__POLICYVERSION=2025.11.19` in deployments; include the hash in DSSE metadata for Offline Kits.
|
||||||
|
|
||||||
| Area | Key(s) | Environment variable | Default | Notes |
|
| Area | Key(s) | Environment variable | Default | Notes |
|
||||||
| --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- |
|
||||||
| Inference mode | `AdvisoryAI:Inference:Mode` | `ADVISORYAI__INFERENCE__MODE` | `Local` | `Local` runs the deterministic pipeline only; `Remote` posts sanitized prompts to `Remote.BaseAddress`. |
|
| Inference mode | `AdvisoryAI:Inference:Mode` | `ADVISORYAI__INFERENCE__MODE` | `Local` | `Local` runs the deterministic pipeline only; `Remote` posts sanitized prompts to `Remote.BaseAddress`. |
|
||||||
| Remote base URI | `AdvisoryAI:Inference:Remote:BaseAddress` | `ADVISORYAI__INFERENCE__REMOTE__BASEADDRESS` | — | Required when `Mode=Remote`. HTTPS strongly recommended. |
|
| Remote base URI | `AdvisoryAI:Inference:Remote:BaseAddress` | `ADVISORYAI__INFERENCE__REMOTE__BASEADDRESS` | — | Required when `Mode=Remote`. HTTPS strongly recommended. |
|
||||||
| Remote API key | `AdvisoryAI:Inference:Remote:ApiKey` | `ADVISORYAI__INFERENCE__REMOTE__APIKEY` | — | Injected as `Authorization: Bearer <key>` when present. |
|
| Remote API key | `AdvisoryAI:Inference:Remote:ApiKey` | `ADVISORYAI__INFERENCE__REMOTE__APIKEY` | — | Injected as `Authorization: Bearer <key>` when present. |
|
||||||
| Remote timeout | `AdvisoryAI:Inference:Remote:TimeoutSeconds` | `ADVISORYAI__INFERENCE__REMOTE__TIMEOUTSECONDS` | `30` | Failing requests fall back to the sanitized prompt with `inference.fallback_reason=remote_timeout`. |
|
| Remote timeout | `AdvisoryAI:Inference:Remote:TimeoutSeconds` | `ADVISORYAI__INFERENCE__REMOTE__TIMEOUTSECONDS` | `30` | Failing requests fall back to the sanitized prompt with `inference.fallback_reason=remote_timeout`. |
|
||||||
| Guardrail prompt cap | `AdvisoryAI:Guardrails:MaxPromptLength` | `ADVISORYAI__GUARDRAILS__MAXPROMPTLENGTH` | `16000` | Prompts longer than the cap are blocked with `prompt_too_long`. |
|
| Guardrail prompt cap | `AdvisoryAI:Guardrails:MaxPromptLength` | `ADVISORYAI__GUARDRAILS__MAXPROMPTLENGTH` | `16000` | Prompts longer than the cap are blocked with `prompt_too_long`. |
|
||||||
| Guardrail citations | `AdvisoryAI:Guardrails:RequireCitations` | `ADVISORYAI__GUARDRAILS__REQUIRECITATIONS` | `true` | When `true`, at least one citation must accompany every prompt. |
|
| Guardrail citations | `AdvisoryAI:Guardrails:RequireCitations` | `ADVISORYAI__GUARDRAILS__REQUIRECITATIONS` | `true` | When `true`, at least one citation must accompany every prompt. |
|
||||||
@@ -39,12 +39,12 @@ This note centralises the tunable knobs that control Advisory AI’s planne
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 1. Inference knobs & “temperatureâ€
|
## 1. Inference knobs & “temperature”
|
||||||
|
|
||||||
Advisory AI supports two inference modes:
|
Advisory AI supports two inference modes:
|
||||||
|
|
||||||
- **Local (default)** – The orchestrator emits deterministic prompts and the worker returns the sanitized prompt verbatim. This mode is offline-friendly and does **not** call any external LLMs. There is no stochastic “temperature†here—the pipeline is purely rule-based.
|
- **Local (default)** – The orchestrator emits deterministic prompts and the worker returns the sanitized prompt verbatim. This mode is offline-friendly and does **not** call any external LLMs. There is no stochastic “temperature” here—the pipeline is purely rule-based.
|
||||||
- **Remote** – Sanitized prompts, citations, and metadata are POSTed to `Remote.BaseAddress + Remote.Endpoint` (default `/v1/inference`). Remote providers control sampling temperature on their side. StellaOps treats remote responses deterministically: we record the provider’s `modelId`, token usage, and any metadata they return. If your remote tier exposes a temperature knob, set it there; Advisory AI simply forwards the prompt.
|
- **Remote** – Sanitized prompts, citations, and metadata are POSTed to `Remote.BaseAddress + Remote.Endpoint` (default `/v1/inference`). Remote providers control sampling temperature on their side. StellaOps treats remote responses deterministically: we record the provider’s `modelId`, token usage, and any metadata they return. If your remote tier exposes a temperature knob, set it there; Advisory AI simply forwards the prompt.
|
||||||
|
|
||||||
### Remote inference quick sample
|
### Remote inference quick sample
|
||||||
|
|
||||||
@@ -68,14 +68,14 @@ Advisory AI supports two inference modes:
|
|||||||
|
|
||||||
| Setting | Default | Explanation |
|
| Setting | Default | Explanation |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `MaxPromptLength` | 16000 chars | Upper bound enforced after redaction. Increase cautiously—remote providers typically cap prompts at 32k tokens. |
|
| `MaxPromptLength` | 16000 chars | Upper bound enforced after redaction. Increase cautiously—remote providers typically cap prompts at 32k tokens. |
|
||||||
| `RequireCitations` | `true` | Forces each prompt to include at least one citation. Disable only when testing synthetic prompts. |
|
| `RequireCitations` | `true` | Forces each prompt to include at least one citation. Disable only when testing synthetic prompts. |
|
||||||
| `BlockedPhrases[]` | `ignore previous instructions`, `disregard earlier instructions`, `you are now the system`, `override the system prompt`, `please jailbreak` | Inline list merged with the optional file. Comparisons are case-insensitive. |
|
| `BlockedPhrases[]` | `ignore previous instructions`, `disregard earlier instructions`, `you are now the system`, `override the system prompt`, `please jailbreak` | Inline list merged with the optional file. Comparisons are case-insensitive. |
|
||||||
| `BlockedPhraseFile` | — | Points to a newline-delimited list. Relative paths resolve against the content root (`AdvisoryAI.Hosting` sticks to AppContext base). |
|
| `BlockedPhraseFile` | — | Points to a newline-delimited list. Relative paths resolve against the content root (`AdvisoryAI.Hosting` sticks to AppContext base). |
|
||||||
| `EntropyThreshold` | `3.5` | Shannon entropy threshold for high-risk token redaction. Set to `0` to disable entropy checks. |
|
| `EntropyThreshold` | `3.5` | Shannon entropy threshold for high-risk token redaction. Set to `0` to disable entropy checks. |
|
||||||
| `EntropyMinLength` | `20` | Minimum token length evaluated by the entropy scrubber. |
|
| `EntropyMinLength` | `20` | Minimum token length evaluated by the entropy scrubber. |
|
||||||
| `AllowlistPatterns` | Defaults (sha256/sha1/sha384/sha512) | Regex patterns that bypass entropy redaction for known-safe identifiers. |
|
| `AllowlistPatterns` | Defaults (sha256/sha1/sha384/sha512) | Regex patterns that bypass entropy redaction for known-safe identifiers. |
|
||||||
| `AllowlistFile` | — | Optional allowlist file (JSON array or newline-delimited). Paths resolve against the content root. |
|
| `AllowlistFile` | — | Optional allowlist file (JSON array or newline-delimited). Paths resolve against the content root. |
|
||||||
|
|
||||||
Violations surface in the response metadata (`guardrail.violations[*]`) and increment `advisory_ai_guardrail_blocks_total`. Console consumes the same payload for its ribbon state.
|
Violations surface in the response metadata (`guardrail.violations[*]`) and increment `advisory_ai_guardrail_blocks_total`. Console consumes the same payload for its ribbon state.
|
||||||
|
|
||||||
@@ -95,9 +95,9 @@ Each task type (Summary, Conflict, Remediation) inherits the defaults below. Ove
|
|||||||
|
|
||||||
| Task | `StructuredMaxChunks` | `VectorTopK` | `VectorQueries` (default) | `SbomMaxTimelineEntries` | `SbomMaxDependencyPaths` | `IncludeBlastRadius` |
|
| Task | `StructuredMaxChunks` | `VectorTopK` | `VectorQueries` (default) | `SbomMaxTimelineEntries` | `SbomMaxDependencyPaths` | `IncludeBlastRadius` |
|
||||||
| --- | --- | --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- | --- | --- |
|
||||||
| Summary | 25 | 5 | `Summarize key facts`, `What is impacted?` | 10 | 20 | ✔ |
|
| Summary | 25 | 5 | `Summarize key facts`, `What is impacted?` | 10 | 20 | ✔ |
|
||||||
| Conflict | 30 | 6 | `Highlight conflicting statements`, `Where do sources disagree?` | 8 | 15 | ✖ |
|
| Conflict | 30 | 6 | `Highlight conflicting statements`, `Where do sources disagree?` | 8 | 15 | ✖ |
|
||||||
| Remediation | 35 | 6 | `Provide remediation steps`, `Outline mitigations and fixes` | 12 | 25 | ✔ |
|
| Remediation | 35 | 6 | `Provide remediation steps`, `Outline mitigations and fixes` | 12 | 25 | ✔ |
|
||||||
|
|
||||||
These knobs act as weighting levers: lower `VectorTopK` emphasises deterministic evidence; higher values favor breadth. `StructuredMaxChunks` bounds how many CSAF/OSV/VEX chunks reach the prompt, keeping token budgets predictable.
|
These knobs act as weighting levers: lower `VectorTopK` emphasises deterministic evidence; higher values favor breadth. `StructuredMaxChunks` bounds how many CSAF/OSV/VEX chunks reach the prompt, keeping token budgets predictable.
|
||||||
|
|
||||||
@@ -107,17 +107,17 @@ These knobs act as weighting levers: lower `VectorTopK` emphasises deterministic
|
|||||||
|
|
||||||
| Task | Prompt tokens | Completion tokens |
|
| Task | Prompt tokens | Completion tokens |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| Summary | 2 048 | 512 |
|
| Summary | 2 048 | 512 |
|
||||||
| Conflict | 2 048 | 512 |
|
| Conflict | 2 048 | 512 |
|
||||||
| Remediation | 2 048 | 640 |
|
| Remediation | 2 048 | 640 |
|
||||||
|
|
||||||
Overwrite via `AdvisoryAI:Tasks:Summary:Budget:PromptTokens`, etc. The worker records actual consumption in the response metadata (`inference.prompt_tokens`, `inference.completion_tokens`).
|
Overwrite via `AdvisoryAI:Tasks:Summary:Budget:PromptTokens`, etc. The worker records actual consumption in the response metadata (`inference.prompt_tokens`, `inference.completion_tokens`).
|
||||||
|
|
||||||
## 5. Cache TTLs & queue directories
|
## 5. Cache TTLs & queue directories
|
||||||
|
|
||||||
- **Plan cache TTLs** – In-memory and file-system caches honour `AdvisoryAI:PlanCache:DefaultTimeToLive` (default 10 minutes) and `CleanupInterval` (default 5 minutes). Shorten the TTL to reduce stale plans or increase it to favour offline reuse. Both values accept ISO 8601 or `hh:mm:ss` time spans.
|
- **Plan cache TTLs** – In-memory and file-system caches honour `AdvisoryAI:PlanCache:DefaultTimeToLive` (default 10 minutes) and `CleanupInterval` (default 5 minutes). Shorten the TTL to reduce stale plans or increase it to favour offline reuse. Both values accept ISO 8601 or `hh:mm:ss` time spans.
|
||||||
- **Queue & storage paths** – `AdvisoryAI:Queue:DirectoryPath`, `AdvisoryAI:Storage:PlanCacheDirectory`, and `AdvisoryAI:Storage:OutputDirectory` default to `data/advisory-ai/{queue,plans,outputs}` under the content root; override these when mounting RWX volumes in sovereign clusters.
|
- **Queue & storage paths** – `AdvisoryAI:Queue:DirectoryPath`, `AdvisoryAI:Storage:PlanCacheDirectory`, and `AdvisoryAI:Storage:OutputDirectory` default to `data/advisory-ai/{queue,plans,outputs}` under the content root; override these when mounting RWX volumes in sovereign clusters.
|
||||||
- **Output TTLs** – Output artefacts inherit the host file-system retention policies. Combine `DefaultTimeToLive` with a cron or systemd timer to prune `outputs/` periodically when operating in remote-inference-heavy environments.
|
- **Output TTLs** – Output artefacts inherit the host file-system retention policies. Combine `DefaultTimeToLive` with a cron or systemd timer to prune `outputs/` periodically when operating in remote-inference-heavy environments.
|
||||||
|
|
||||||
### Example: raised TTL & custom queue path
|
### Example: raised TTL & custom queue path
|
||||||
|
|
||||||
@@ -138,6 +138,6 @@ Overwrite via `AdvisoryAI:Tasks:Summary:Budget:PromptTokens`, etc. The worker re
|
|||||||
## 6. Operational notes
|
## 6. Operational notes
|
||||||
|
|
||||||
- Updating **guardrail phrases** triggers only on host reload. When distributing blocked-phrase files via Offline Kits, keep filenames stable and version them through Git so QA can diff changes.
|
- Updating **guardrail phrases** triggers only on host reload. When distributing blocked-phrase files via Offline Kits, keep filenames stable and version them through Git so QA can diff changes.
|
||||||
- **Temperature / sampling** remains a remote-provider concern. StellaOps records the provider’s `modelId` and exposes fallback metadata so policy authors can audit when sanitized prompts were returned instead of model output.
|
- **Temperature / sampling** remains a remote-provider concern. StellaOps records the provider’s `modelId` and exposes fallback metadata so policy authors can audit when sanitized prompts were returned instead of model output.
|
||||||
- Always track changes in `docs/implplan/SPRINT_0111_0001_0001_advisoryai.md` (task `DOCS-AIAI-31-006`) when promoting this document so the guild can trace which parameters were added per sprint.
|
- Always track changes in `docs/implplan/SPRINT_0111_0001_0001_advisoryai.md` (task `DOCS-AIAI-31-006`) when promoting this document so the guild can trace which parameters were added per sprint.
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
# component_architecture_scanner.md — **Stella Ops Scanner** (2025Q4)
|
# component_architecture_scanner.md — **Stella Ops Scanner** (2025Q4)
|
||||||
|
|
||||||
> Aligned with Epic 6 – Vulnerability Explorer and Epic 10 – Export Center.
|
> Aligned with Epic 6 – Vulnerability Explorer and Epic 10 – Export Center.
|
||||||
|
|
||||||
> **Scope.** Implementation‑ready architecture for the **Scanner** subsystem: WebService, Workers, analyzers, SBOM assembly (inventory & usage), per‑layer caching, three‑way diffs, artifact catalog (RustFS default + PostgreSQL, S3-compatible fallback), attestation hand‑off, and scale/security posture. This document is the contract between the scanning plane and everything else (Policy, Excititor, Concelier, UI, CLI).
|
> **Scope.** Implementation‑ready architecture for the **Scanner** subsystem: WebService, Workers, analyzers, SBOM assembly (inventory & usage), per‑layer caching, three‑way diffs, artifact catalog (RustFS default + PostgreSQL, S3-compatible fallback), attestation hand‑off, and scale/security posture. This document is the contract between the scanning plane and everything else (Policy, Excititor, Concelier, UI, CLI).
|
||||||
> **Related:** `docs/modules/scanner/operations/ai-code-guard.md`
|
> **Related:** `docs/modules/scanner/operations/ai-code-guard.md`
|
||||||
> **Storage profile:** `docs/modules/scanner/sbom-attestation-hot-lookup-profile.md`
|
> **Storage profile:** `docs/modules/scanner/sbom-attestation-hot-lookup-profile.md`
|
||||||
|
|
||||||
@@ -10,13 +10,13 @@
|
|||||||
|
|
||||||
## 0) Mission & boundaries
|
## 0) Mission & boundaries
|
||||||
|
|
||||||
**Mission.** Produce **deterministic**, **explainable** SBOMs and diffs for container images and filesystems, quickly and repeatedly, without guessing. Emit two views: **Inventory** (everything present) and **Usage** (entrypoint closure + actually linked libs). Attach attestations through **Signer→Attestor→Rekor v2**.
|
**Mission.** Produce **deterministic**, **explainable** SBOMs and diffs for container images and filesystems, quickly and repeatedly, without guessing. Emit two views: **Inventory** (everything present) and **Usage** (entrypoint closure + actually linked libs). Attach attestations through **Signer→Attestor→Rekor v2**.
|
||||||
|
|
||||||
**Boundaries.**
|
**Boundaries.**
|
||||||
|
|
||||||
* Scanner **does not** produce PASS/FAIL. The backend (Policy + Excititor + Concelier) decides presentation and verdicts.
|
* Scanner **does not** produce PASS/FAIL. The backend (Policy + Excititor + Concelier) decides presentation and verdicts.
|
||||||
* Scanner **does not** keep third‑party SBOM warehouses. It may **bind** to existing attestations for exact hashes.
|
* Scanner **does not** keep third‑party SBOM warehouses. It may **bind** to existing attestations for exact hashes.
|
||||||
* Core analyzers are **deterministic** (no fuzzy identity). Optional heuristic plug‑ins (e.g., patch‑presence) run under explicit flags and never contaminate the core SBOM.
|
* Core analyzers are **deterministic** (no fuzzy identity). Optional heuristic plug‑ins (e.g., patch‑presence) run under explicit flags and never contaminate the core SBOM.
|
||||||
|
|
||||||
SBOM dependency reachability inference uses dependency graphs to reduce false positives and
|
SBOM dependency reachability inference uses dependency graphs to reduce false positives and
|
||||||
apply reachability-aware severity adjustments. See `src/Scanner/docs/sbom-reachability-filtering.md`
|
apply reachability-aware severity adjustments. See `src/Scanner/docs/sbom-reachability-filtering.md`
|
||||||
@@ -28,27 +28,27 @@ for policy configuration and reporting expectations.
|
|||||||
|
|
||||||
```
|
```
|
||||||
src/
|
src/
|
||||||
├─ StellaOps.Scanner.WebService/ # REST control plane, catalog, diff, exports
|
├─ StellaOps.Scanner.WebService/ # REST control plane, catalog, diff, exports
|
||||||
├─ StellaOps.Scanner.Worker/ # queue consumer; executes analyzers
|
├─ StellaOps.Scanner.Worker/ # queue consumer; executes analyzers
|
||||||
├─ StellaOps.Scanner.Models/ # DTOs, evidence, graph nodes, CDX/SPDX adapters
|
├─ StellaOps.Scanner.Models/ # DTOs, evidence, graph nodes, CDX/SPDX adapters
|
||||||
├─ StellaOps.Scanner.Storage/ # PostgreSQL repositories; RustFS object client (default) + S3 fallback; ILM/GC
|
├─ StellaOps.Scanner.Storage/ # PostgreSQL repositories; RustFS object client (default) + S3 fallback; ILM/GC
|
||||||
├─ StellaOps.Scanner.Queue/ # queue abstraction (Valkey/NATS/RabbitMQ)
|
├─ StellaOps.Scanner.Queue/ # queue abstraction (Valkey/NATS/RabbitMQ)
|
||||||
├─ StellaOps.Scanner.Cache/ # layer cache; file CAS; bloom/bitmap indexes
|
├─ StellaOps.Scanner.Cache/ # layer cache; file CAS; bloom/bitmap indexes
|
||||||
├─ StellaOps.Scanner.EntryTrace/ # ENTRYPOINT/CMD → terminal program resolver (shell AST)
|
├─ StellaOps.Scanner.EntryTrace/ # ENTRYPOINT/CMD → terminal program resolver (shell AST)
|
||||||
├─ StellaOps.Scanner.Analyzers.OS.[Apk|Dpkg|Rpm]/
|
├─ StellaOps.Scanner.Analyzers.OS.[Apk|Dpkg|Rpm]/
|
||||||
├─ StellaOps.Scanner.Analyzers.Lang.[Java|Node|Bun|Python|Go|DotNet|Rust|Ruby|Php]/
|
├─ StellaOps.Scanner.Analyzers.Lang.[Java|Node|Bun|Python|Go|DotNet|Rust|Ruby|Php]/
|
||||||
├─ StellaOps.Scanner.Analyzers.Native.[ELF|PE|MachO]/ # PE/Mach-O planned (M2)
|
├─ StellaOps.Scanner.Analyzers.Native.[ELF|PE|MachO]/ # PE/Mach-O planned (M2)
|
||||||
├─ StellaOps.Scanner.Analyzers.Secrets/ # Secret leak detection (2026.01)
|
├─ StellaOps.Scanner.Analyzers.Secrets/ # Secret leak detection (2026.01)
|
||||||
├─ StellaOps.Scanner.Symbols.Native/ # NEW – native symbol reader/demangler (Sprint 401)
|
├─ StellaOps.Scanner.Symbols.Native/ # NEW – native symbol reader/demangler (Sprint 401)
|
||||||
├─ StellaOps.Scanner.CallGraph.Native/ # NEW – function/call-edge builder + CAS emitter
|
├─ StellaOps.Scanner.CallGraph.Native/ # NEW – function/call-edge builder + CAS emitter
|
||||||
├─ StellaOps.Scanner.Emit.CDX/ # CycloneDX (JSON + Protobuf)
|
├─ StellaOps.Scanner.Emit.CDX/ # CycloneDX (JSON + Protobuf)
|
||||||
├─ StellaOps.Scanner.Emit.SPDX/ # SPDX 3.0.1 JSON
|
├─ StellaOps.Scanner.Emit.SPDX/ # SPDX 3.0.1 JSON
|
||||||
├─ StellaOps.Scanner.Diff/ # image→layer→component three‑way diff
|
├─ StellaOps.Scanner.Diff/ # image→layer→component three‑way diff
|
||||||
├─ StellaOps.Scanner.Index/ # BOM‑Index sidecar (purls + roaring bitmaps)
|
├─ StellaOps.Scanner.Index/ # BOM‑Index sidecar (purls + roaring bitmaps)
|
||||||
├─ StellaOps.Scanner.Tests.* # unit/integration/e2e fixtures
|
├─ StellaOps.Scanner.Tests.* # unit/integration/e2e fixtures
|
||||||
└─ Tools/
|
└─ Tools/
|
||||||
├─ StellaOps.Scanner.Sbomer.BuildXPlugin/ # BuildKit generator (image referrer SBOMs)
|
├─ StellaOps.Scanner.Sbomer.BuildXPlugin/ # BuildKit generator (image referrer SBOMs)
|
||||||
└─ StellaOps.Scanner.Sbomer.DockerImage/ # CLI‑driven scanner container
|
└─ StellaOps.Scanner.Sbomer.DockerImage/ # CLI‑driven scanner container
|
||||||
```
|
```
|
||||||
|
|
||||||
### 1.0 Cartographer Ownership (Sprint 201)
|
### 1.0 Cartographer Ownership (Sprint 201)
|
||||||
@@ -58,18 +58,18 @@ src/
|
|||||||
- Legacy `src/Cartographer/` paths are retired; operational and build references now resolve through Scanner-owned solution/project paths.
|
- Legacy `src/Cartographer/` paths are retired; operational and build references now resolve through Scanner-owned solution/project paths.
|
||||||
|
|
||||||
Per-analyzer notes (language analyzers):
|
Per-analyzer notes (language analyzers):
|
||||||
- `docs/modules/scanner/analyzers-java.md` — Java/Kotlin (Maven, Gradle, fat archives)
|
- `docs/modules/scanner/analyzers-java.md` — Java/Kotlin (Maven, Gradle, fat archives)
|
||||||
- `docs/modules/scanner/dotnet-analyzer.md` — .NET (deps.json, NuGet, packages.lock.json, declared-only)
|
- `docs/modules/scanner/dotnet-analyzer.md` — .NET (deps.json, NuGet, packages.lock.json, declared-only)
|
||||||
- `docs/modules/scanner/analyzers-python.md` — Python (pip, Poetry, pipenv, conda, editables, vendored)
|
- `docs/modules/scanner/analyzers-python.md` — Python (pip, Poetry, pipenv, conda, editables, vendored)
|
||||||
- `docs/modules/scanner/analyzers-node.md` — Node.js (npm, Yarn, pnpm, multi-version locks)
|
- `docs/modules/scanner/analyzers-node.md` — Node.js (npm, Yarn, pnpm, multi-version locks)
|
||||||
- `docs/modules/scanner/analyzers-bun.md` — Bun (bun.lock v1, dev classification, patches)
|
- `docs/modules/scanner/analyzers-bun.md` — Bun (bun.lock v1, dev classification, patches)
|
||||||
- `docs/modules/scanner/analyzers-go.md` — Go (build info, modules)
|
- `docs/modules/scanner/analyzers-go.md` — Go (build info, modules)
|
||||||
|
|
||||||
Cross-analyzer contract (identity safety, evidence locators, container layout):
|
Cross-analyzer contract (identity safety, evidence locators, container layout):
|
||||||
- `docs/modules/scanner/language-analyzers-contract.md` — PURL vs explicit-key rules, evidence formats, bounded scanning
|
- `docs/modules/scanner/language-analyzers-contract.md` — PURL vs explicit-key rules, evidence formats, bounded scanning
|
||||||
|
|
||||||
Semantic entrypoint analysis (Sprint 0411):
|
Semantic entrypoint analysis (Sprint 0411):
|
||||||
- `docs/modules/scanner/semantic-entrypoint-schema.md` — Schema for intent, capabilities, threat vectors, and data boundaries
|
- `docs/modules/scanner/semantic-entrypoint-schema.md` — Schema for intent, capabilities, threat vectors, and data boundaries
|
||||||
|
|
||||||
Analyzer assemblies and buildx generators are packaged as **restart-time plug-ins** under `plugins/scanner/**` with manifests; services must restart to activate new plug-ins.
|
Analyzer assemblies and buildx generators are packaged as **restart-time plug-ins** under `plugins/scanner/**` with manifests; services must restart to activate new plug-ins.
|
||||||
|
|
||||||
@@ -77,15 +77,15 @@ Analyzer assemblies and buildx generators are packaged as **restart-time plug-in
|
|||||||
|
|
||||||
The **Semantic Entrypoint Engine** enriches scan results with application-level understanding:
|
The **Semantic Entrypoint Engine** enriches scan results with application-level understanding:
|
||||||
|
|
||||||
- **Intent Classification** — Infers application type (WebServer, Worker, CliTool, Serverless, etc.) from framework detection and entrypoint analysis
|
- **Intent Classification** — Infers application type (WebServer, Worker, CliTool, Serverless, etc.) from framework detection and entrypoint analysis
|
||||||
- **Capability Detection** — Identifies system resource access patterns (network, filesystem, database, crypto)
|
- **Capability Detection** — Identifies system resource access patterns (network, filesystem, database, crypto)
|
||||||
- **Threat Vector Inference** — Maps capabilities to potential attack vectors with CWE/OWASP references
|
- **Threat Vector Inference** — Maps capabilities to potential attack vectors with CWE/OWASP references
|
||||||
- **Data Boundary Mapping** — Tracks data flow boundaries with sensitivity classification
|
- **Data Boundary Mapping** — Tracks data flow boundaries with sensitivity classification
|
||||||
|
|
||||||
Components:
|
Components:
|
||||||
- `StellaOps.Scanner.EntryTrace/Semantic/` — Core semantic types and orchestrator
|
- `StellaOps.Scanner.EntryTrace/Semantic/` — Core semantic types and orchestrator
|
||||||
- `StellaOps.Scanner.EntryTrace/Semantic/Adapters/` — Language-specific adapters (Python, Java, Node, .NET, Go)
|
- `StellaOps.Scanner.EntryTrace/Semantic/Adapters/` — Language-specific adapters (Python, Java, Node, .NET, Go)
|
||||||
- `StellaOps.Scanner.EntryTrace/Semantic/Analysis/` — Capability detection, threat inference, boundary mapping
|
- `StellaOps.Scanner.EntryTrace/Semantic/Analysis/` — Capability detection, threat inference, boundary mapping
|
||||||
|
|
||||||
Integration points:
|
Integration points:
|
||||||
- `LanguageComponentRecord` includes semantic fields (`intent`, `capabilities[]`, `threatVectors[]`)
|
- `LanguageComponentRecord` includes semantic fields (`intent`, `capabilities[]`, `threatVectors[]`)
|
||||||
@@ -127,10 +127,10 @@ scanner:
|
|||||||
|
|
||||||
The DI extension (`AddScannerQueue`) wires the transport.
|
The DI extension (`AddScannerQueue`) wires the transport.
|
||||||
|
|
||||||
**Runtime form‑factor:** two deployables
|
**Runtime form‑factor:** two deployables
|
||||||
|
|
||||||
* **Scanner.WebService** (stateless REST)
|
* **Scanner.WebService** (stateless REST)
|
||||||
* **Scanner.Worker** (N replicas; queue‑driven)
|
* **Scanner.Worker** (N replicas; queue‑driven)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -140,26 +140,26 @@ The DI extension (`AddScannerQueue`) wires the transport.
|
|||||||
* **RustFS** (default, offline-first) for SBOM artifacts; S3-compatible interface with **Object Lock** semantics emulated via retention headers; **ILM** for TTL.
|
* **RustFS** (default, offline-first) for SBOM artifacts; S3-compatible interface with **Object Lock** semantics emulated via retention headers; **ILM** for TTL.
|
||||||
* **PostgreSQL** for catalog, job state, diffs, ILM rules.
|
* **PostgreSQL** for catalog, job state, diffs, ILM rules.
|
||||||
* **Queue** (Valkey Streams/NATS/RabbitMQ).
|
* **Queue** (Valkey Streams/NATS/RabbitMQ).
|
||||||
* **Authority** (on‑prem OIDC) for **OpToks** (DPoP/mTLS).
|
* **Authority** (on‑prem OIDC) for **OpToks** (DPoP/mTLS).
|
||||||
* **Signer** + **Attestor** (+ **Fulcio/KMS** + **Rekor v2**) for DSSE + transparency.
|
* **Signer** + **Attestor** (+ **Fulcio/KMS** + **Rekor v2**) for DSSE + transparency.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 3) Contracts & data model
|
## 3) Contracts & data model
|
||||||
|
|
||||||
### 3.1 Evidence‑first component model
|
### 3.1 Evidence‑first component model
|
||||||
|
|
||||||
**Nodes**
|
**Nodes**
|
||||||
|
|
||||||
* `Image`, `Layer`, `File`
|
* `Image`, `Layer`, `File`
|
||||||
* `Component` (`purl?`, `name`, `version?`, `type`, `id` — may be `bin:{sha256}`)
|
* `Component` (`purl?`, `name`, `version?`, `type`, `id` — may be `bin:{sha256}`)
|
||||||
* `Executable` (ELF/PE/Mach‑O), `Library` (native or managed), `EntryScript` (shell/launcher)
|
* `Executable` (ELF/PE/Mach‑O), `Library` (native or managed), `EntryScript` (shell/launcher)
|
||||||
|
|
||||||
**Edges** (all carry **Evidence**)
|
**Edges** (all carry **Evidence**)
|
||||||
|
|
||||||
* `contains(Image|Layer → File)`
|
* `contains(Image|Layer → File)`
|
||||||
* `installs(PackageDB → Component)` (OS database row)
|
* `installs(PackageDB → Component)` (OS database row)
|
||||||
* `declares(InstalledMetadata → Component)` (dist‑info, pom.properties, deps.json…)
|
* `declares(InstalledMetadata → Component)` (dist‑info, pom.properties, deps.json…)
|
||||||
* `links_to(Executable → Library)` (ELF `DT_NEEDED`, PE imports)
|
* `links_to(Executable → Library)` (ELF `DT_NEEDED`, PE imports)
|
||||||
* `calls(EntryScript → Program)` (file:line from shell AST)
|
* `calls(EntryScript → Program)` (file:line from shell AST)
|
||||||
* `attests(Rekor → Component|Image)` (SBOM/predicate binding)
|
* `attests(Rekor → Component|Image)` (SBOM/predicate binding)
|
||||||
@@ -247,7 +247,7 @@ When `scanner.events.enabled = true`, the WebService serialises the signed repor
|
|||||||
|
|
||||||
### 5.1 Acquire & verify
|
### 5.1 Acquire & verify
|
||||||
|
|
||||||
1. **Resolve image** (prefer `repo@sha256:…`).
|
1. **Resolve image** (prefer `repo@sha256:…`).
|
||||||
2. **(Optional) verify image signature** per policy (cosign).
|
2. **(Optional) verify image signature** per policy (cosign).
|
||||||
3. **Pull blobs**, compute layer digests; record metadata.
|
3. **Pull blobs**, compute layer digests; record metadata.
|
||||||
|
|
||||||
@@ -289,19 +289,19 @@ When `scanner.events.enabled = true`, the WebService serialises the signed repor
|
|||||||
**C) Native link graph**
|
**C) Native link graph**
|
||||||
|
|
||||||
* **ELF**: parse `PT_INTERP`, `DT_NEEDED`, RPATH/RUNPATH, **GNU symbol versions**; map **SONAMEs** to file paths; link executables → libs.
|
* **ELF**: parse `PT_INTERP`, `DT_NEEDED`, RPATH/RUNPATH, **GNU symbol versions**; map **SONAMEs** to file paths; link executables → libs.
|
||||||
* **PE/Mach‑O** (planned M2): import table, delay‑imports; version resources; code signatures.
|
* **PE/Mach‑O** (planned M2): import table, delay‑imports; version resources; code signatures.
|
||||||
* Map libs back to **OS packages** if possible (via file lists); else emit `bin:{sha256}` components.
|
* Map libs back to **OS packages** if possible (via file lists); else emit `bin:{sha256}` components.
|
||||||
* The exported metadata (`stellaops.os.*` properties, license list, source package) feeds policy scoring and export pipelines
|
* The exported metadata (`stellaops.os.*` properties, license list, source package) feeds policy scoring and export pipelines
|
||||||
directly – Policy evaluates quiet rules against package provenance while Exporters forward the enriched fields into
|
directly – Policy evaluates quiet rules against package provenance while Exporters forward the enriched fields into
|
||||||
downstream JSON/Trivy payloads.
|
downstream JSON/Trivy payloads.
|
||||||
* **Reachability lattice**: analyzers + runtime probes emit `Evidence`/`Mitigation` records (see `docs/modules/reach-graph/guides/lattice.md`). The lattice engine joins static path evidence, runtime hits (EventPipe/JFR), taint flows, environment gates, and mitigations into `ReachDecision` documents that feed VEX gating and event graph storage.
|
* **Reachability lattice**: analyzers + runtime probes emit `Evidence`/`Mitigation` records (see `docs/modules/reach-graph/guides/lattice.md`). The lattice engine joins static path evidence, runtime hits (EventPipe/JFR), taint flows, environment gates, and mitigations into `ReachDecision` documents that feed VEX gating and event graph storage.
|
||||||
* Sprint 401 introduces `StellaOps.Scanner.Symbols.Native` (DWARF/PDB reader + demangler) and `StellaOps.Scanner.CallGraph.Native`
|
* Sprint 401 introduces `StellaOps.Scanner.Symbols.Native` (DWARF/PDB reader + demangler) and `StellaOps.Scanner.CallGraph.Native`
|
||||||
(function boundary detector + call-edge builder). These libraries feed `FuncNode`/`CallEdge` CAS bundles and enrich reachability
|
(function boundary detector + call-edge builder). These libraries feed `FuncNode`/`CallEdge` CAS bundles and enrich reachability
|
||||||
graphs with `{code_id, confidence, evidence}` so Signals/Policy/UI can cite function-level justifications.
|
graphs with `{code_id, confidence, evidence}` so Signals/Policy/UI can cite function-level justifications.
|
||||||
|
|
||||||
**D) EntryTrace (ENTRYPOINT/CMD → terminal program)**
|
**D) EntryTrace (ENTRYPOINT/CMD → terminal program)**
|
||||||
|
|
||||||
* Read image config; parse shell (POSIX/Bash subset) with AST: `source`/`.` includes; `case/if`; `exec`/`command`; `run‑parts`.
|
* Read image config; parse shell (POSIX/Bash subset) with AST: `source`/`.` includes; `case/if`; `exec`/`command`; `run‑parts`.
|
||||||
* Resolve commands via **PATH** within the **built rootfs**; follow language launchers (Java/Node/Python) to identify the terminal program (ELF/JAR/venv script).
|
* Resolve commands via **PATH** within the **built rootfs**; follow language launchers (Java/Node/Python) to identify the terminal program (ELF/JAR/venv script).
|
||||||
* Record **file:line** and choices for each hop; output chain graph.
|
* Record **file:line** and choices for each hop; output chain graph.
|
||||||
* Unresolvable dynamic constructs are recorded as **unknown** edges with reasons (e.g., `$FOO` unresolved).
|
* Unresolvable dynamic constructs are recorded as **unknown** edges with reasons (e.g., `$FOO` unresolved).
|
||||||
@@ -310,11 +310,11 @@ When `scanner.events.enabled = true`, the WebService serialises the signed repor
|
|||||||
|
|
||||||
Post-resolution, the `SemanticEntrypointOrchestrator` enriches entry trace results with semantic understanding:
|
Post-resolution, the `SemanticEntrypointOrchestrator` enriches entry trace results with semantic understanding:
|
||||||
|
|
||||||
* **Application Intent** — Infers the purpose (WebServer, CliTool, Worker, Serverless, BatchJob, etc.) from framework detection and command patterns.
|
* **Application Intent** — Infers the purpose (WebServer, CliTool, Worker, Serverless, BatchJob, etc.) from framework detection and command patterns.
|
||||||
* **Capability Classes** — Detects capabilities (NetworkListen, DatabaseSql, ProcessSpawn, SecretAccess, etc.) via import/dependency analysis and framework signatures.
|
* **Capability Classes** — Detects capabilities (NetworkListen, DatabaseSql, ProcessSpawn, SecretAccess, etc.) via import/dependency analysis and framework signatures.
|
||||||
* **Attack Surface** — Maps capabilities to potential threat vectors (SqlInjection, Xss, Ssrf, Rce, PathTraversal) with CWE IDs and OWASP Top 10 categories.
|
* **Attack Surface** — Maps capabilities to potential threat vectors (SqlInjection, Xss, Ssrf, Rce, PathTraversal) with CWE IDs and OWASP Top 10 categories.
|
||||||
* **Data Boundaries** — Traces I/O edges (HttpRequest, DatabaseQuery, FileInput, EnvironmentVar) with direction and sensitivity classification.
|
* **Data Boundaries** — Traces I/O edges (HttpRequest, DatabaseQuery, FileInput, EnvironmentVar) with direction and sensitivity classification.
|
||||||
* **Confidence Scoring** — Each inference carries a score (0.0–1.0), tier (Definitive/High/Medium/Low/Unknown), and reasoning chain.
|
* **Confidence Scoring** — Each inference carries a score (0.0–1.0), tier (Definitive/High/Medium/Low/Unknown), and reasoning chain.
|
||||||
|
|
||||||
Language-specific adapters (`PythonSemanticAdapter`, `JavaSemanticAdapter`, `NodeSemanticAdapter`, `DotNetSemanticAdapter`, `GoSemanticAdapter`) recognize framework patterns:
|
Language-specific adapters (`PythonSemanticAdapter`, `JavaSemanticAdapter`, `NodeSemanticAdapter`, `DotNetSemanticAdapter`, `GoSemanticAdapter`) recognize framework patterns:
|
||||||
* **Python**: Django, Flask, FastAPI, Celery, Click/Typer, Lambda handlers
|
* **Python**: Django, Flask, FastAPI, Celery, Click/Typer, Lambda handlers
|
||||||
@@ -379,11 +379,11 @@ public sealed record BinaryFindingEvidence
|
|||||||
### 5.5 SBOM assembly & emit
|
### 5.5 SBOM assembly & emit
|
||||||
|
|
||||||
* **Per-layer SBOM fragments**: components introduced by the layer (+ relationships).
|
* **Per-layer SBOM fragments**: components introduced by the layer (+ relationships).
|
||||||
* **Image SBOMs**: merge fragments; refer back to them via **CycloneDX BOM‑Link** (or SPDX ExternalRef).
|
* **Image SBOMs**: merge fragments; refer back to them via **CycloneDX BOM‑Link** (or SPDX ExternalRef).
|
||||||
* Emit both **Inventory** & **Usage** views.
|
* Emit both **Inventory** & **Usage** views.
|
||||||
* When the native analyzer reports an ELF `buildId`, attach it to component metadata and surface it as `stellaops:buildId` in CycloneDX properties (and diff metadata). This keeps SBOM/diff output in lockstep with runtime events and the debug-store manifest.
|
* When the native analyzer reports an ELF `buildId`, attach it to component metadata and surface it as `stellaops:buildId` in CycloneDX properties (and diff metadata). This keeps SBOM/diff output in lockstep with runtime events and the debug-store manifest.
|
||||||
* Serialize **CycloneDX 1.7 JSON** and **CycloneDX 1.7 Protobuf**; optionally **SPDX 3.0.1 JSON-LD** (`application/spdx+json; version=3.0.1`) with legacy tag-value output (`text/spdx`) when enabled (1.6 accepted for ingest compatibility).
|
* Serialize **CycloneDX 1.7 JSON** and **CycloneDX 1.7 Protobuf**; optionally **SPDX 3.0.1 JSON-LD** (`application/spdx+json; version=3.0.1`) with legacy tag-value output (`text/spdx`) when enabled (1.6 accepted for ingest compatibility).
|
||||||
* Build **BOM‑Index** sidecar: purl table + roaring bitmap; flag `usedByEntrypoint` components for fast backend joins.
|
* Build **BOM‑Index** sidecar: purl table + roaring bitmap; flag `usedByEntrypoint` components for fast backend joins.
|
||||||
|
|
||||||
The emitted `buildId` metadata is preserved in component hashes, diff payloads, and `/policy/runtime` responses so operators can pivot from SBOM entries → runtime events → `debug/.build-id/<aa>/<rest>.debug` within the Offline Kit or release bundle.
|
The emitted `buildId` metadata is preserved in component hashes, diff payloads, and `/policy/runtime` responses so operators can pivot from SBOM entries → runtime events → `debug/.build-id/<aa>/<rest>.debug` within the Offline Kit or release bundle.
|
||||||
|
|
||||||
@@ -475,7 +475,7 @@ Scanner API flows that operate on tenant-partitioned tables now require tenant a
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 6) Three‑way diff (image → layer → component)
|
## 6) Three‑way diff (image → layer → component)
|
||||||
|
|
||||||
### 6.1 Keys & classification
|
### 6.1 Keys & classification
|
||||||
|
|
||||||
@@ -503,13 +503,13 @@ Diffs are stored as artifacts and feed **UI** and **CLI**.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 7) Build‑time SBOMs (fast CI path)
|
## 7) Build‑time SBOMs (fast CI path)
|
||||||
|
|
||||||
**Scanner.Sbomer.BuildXPlugin** can act as a BuildKit **generator**:
|
**Scanner.Sbomer.BuildXPlugin** can act as a BuildKit **generator**:
|
||||||
|
|
||||||
* During `docker buildx build --attest=type=sbom,generator=stellaops/sbom-indexer`, run analyzers on the build context/output; attach SBOMs as OCI **referrers** to the built image.
|
* During `docker buildx build --attest=type=sbom,generator=stellaops/sbom-indexer`, run analyzers on the build context/output; attach SBOMs as OCI **referrers** to the built image.
|
||||||
* Optionally request **Signer/Attestor** to produce **Stella Ops‑verified** attestation immediately; else, Scanner.WebService can verify and re‑attest post‑push.
|
* Optionally request **Signer/Attestor** to produce **Stella Ops‑verified** attestation immediately; else, Scanner.WebService can verify and re‑attest post‑push.
|
||||||
* Scanner.WebService trusts build‑time SBOMs per policy, enabling **no‑rescan** for unchanged bases.
|
* Scanner.WebService trusts build‑time SBOMs per policy, enabling **no‑rescan** for unchanged bases.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -551,26 +551,26 @@ scanner:
|
|||||||
|
|
||||||
## 9) Scale & performance
|
## 9) Scale & performance
|
||||||
|
|
||||||
* **Parallelism**: per‑analyzer concurrency; bounded directory walkers; file CAS dedupe by sha256.
|
* **Parallelism**: per‑analyzer concurrency; bounded directory walkers; file CAS dedupe by sha256.
|
||||||
* **Distributed locks** per **layer digest** to prevent duplicate work across Workers.
|
* **Distributed locks** per **layer digest** to prevent duplicate work across Workers.
|
||||||
* **Registry throttles**: per‑host concurrency budgets; exponential backoff on 429/5xx.
|
* **Registry throttles**: per‑host concurrency budgets; exponential backoff on 429/5xx.
|
||||||
* **Targets**:
|
* **Targets**:
|
||||||
|
|
||||||
* **Build‑time**: P95 ≤ 3–5 s on warmed bases (CI generator).
|
* **Build‑time**: P95 ≤ 3–5 s on warmed bases (CI generator).
|
||||||
* **Post‑build delta**: P95 ≤ 10 s for 200 MB images with cache hit.
|
* **Post‑build delta**: P95 ≤ 10 s for 200 MB images with cache hit.
|
||||||
* **Emit**: CycloneDX Protobuf ≤ 150 ms for 5k components; JSON ≤ 500 ms.
|
* **Emit**: CycloneDX Protobuf ≤ 150 ms for 5k components; JSON ≤ 500 ms.
|
||||||
* **Diff**: ≤ 200 ms for 5k vs 5k components.
|
* **Diff**: ≤ 200 ms for 5k vs 5k components.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 10) Security posture
|
## 10) Security posture
|
||||||
|
|
||||||
* **AuthN**: Authority‑issued short OpToks (DPoP/mTLS).
|
* **AuthN**: Authority‑issued short OpToks (DPoP/mTLS).
|
||||||
* **AuthZ**: scopes (`scanner.scan`, `scanner.export`, `scanner.catalog.read`).
|
* **AuthZ**: scopes (`scanner.scan`, `scanner.export`, `scanner.catalog.read`).
|
||||||
* **mTLS** to **Signer**/**Attestor**; only **Signer** can sign.
|
* **mTLS** to **Signer**/**Attestor**; only **Signer** can sign.
|
||||||
* **No network fetches** during analysis (except registry pulls and optional Rekor index reads).
|
* **No network fetches** during analysis (except registry pulls and optional Rekor index reads).
|
||||||
* **Sandboxing**: non‑root containers; read‑only FS; seccomp profiles; disable execution of scanned content.
|
* **Sandboxing**: non‑root containers; read‑only FS; seccomp profiles; disable execution of scanned content.
|
||||||
* **Release integrity**: all first‑party images are **cosign‑signed**; Workers/WebService self‑verify at startup.
|
* **Release integrity**: all first‑party images are **cosign‑signed**; Workers/WebService self‑verify at startup.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -582,7 +582,7 @@ scanner:
|
|||||||
* `scanner.layer_cache_hits_total`, `scanner.file_cas_hits_total`
|
* `scanner.layer_cache_hits_total`, `scanner.file_cas_hits_total`
|
||||||
* `scanner.artifact_bytes_total{format}`
|
* `scanner.artifact_bytes_total{format}`
|
||||||
* `scanner.attestation_latency_seconds`, `scanner.rekor_failures_total`
|
* `scanner.attestation_latency_seconds`, `scanner.rekor_failures_total`
|
||||||
* `scanner_analyzer_golang_heuristic_total{indicator,version_hint}` — increments whenever the Go analyzer falls back to heuristics (build-id or runtime markers). Grafana panel: `sum by (indicator) (rate(scanner_analyzer_golang_heuristic_total[5m]))`; alert when the rate is ≥ 1 for 15 minutes to highlight unexpected stripped binaries.
|
* `scanner_analyzer_golang_heuristic_total{indicator,version_hint}` — increments whenever the Go analyzer falls back to heuristics (build-id or runtime markers). Grafana panel: `sum by (indicator) (rate(scanner_analyzer_golang_heuristic_total[5m]))`; alert when the rate is ≥ 1 for 15 minutes to highlight unexpected stripped binaries.
|
||||||
* **Tracing**: spans for acquire→union→analyzers→compose→emit→sign→log.
|
* **Tracing**: spans for acquire→union→analyzers→compose→emit→sign→log.
|
||||||
* **Audit logs**: DSSE requests log `license_id`, `image_digest`, `artifactSha256`, `policy_digest?`, Rekor UUID on success.
|
* **Audit logs**: DSSE requests log `license_id`, `image_digest`, `artifactSha256`, `policy_digest?`, Rekor UUID on success.
|
||||||
|
|
||||||
@@ -592,12 +592,12 @@ scanner:
|
|||||||
|
|
||||||
* **Analyzer contracts:** see `language-analyzers-contract.md` for cross-analyzer identity safety, evidence locators, and container layout rules. Per-analyzer docs: `analyzers-java.md`, `dotnet-analyzer.md`, `analyzers-python.md`, `analyzers-node.md`, `analyzers-bun.md`, `analyzers-go.md`. Implementation: `docs/implplan/SPRINT_0408_0001_0001_scanner_language_detection_gaps_program.md`.
|
* **Analyzer contracts:** see `language-analyzers-contract.md` for cross-analyzer identity safety, evidence locators, and container layout rules. Per-analyzer docs: `analyzers-java.md`, `dotnet-analyzer.md`, `analyzers-python.md`, `analyzers-node.md`, `analyzers-bun.md`, `analyzers-go.md`. Implementation: `docs/implplan/SPRINT_0408_0001_0001_scanner_language_detection_gaps_program.md`.
|
||||||
|
|
||||||
* **Determinism:** given same image + analyzers → byte‑identical **CDX Protobuf**; JSON normalized.
|
* **Determinism:** given same image + analyzers → byte‑identical **CDX Protobuf**; JSON normalized.
|
||||||
* **OS packages:** ground‑truth images per distro; compare to package DB.
|
* **OS packages:** ground‑truth images per distro; compare to package DB.
|
||||||
* **Lang ecosystems:** sample images per ecosystem (Java/Node/Python/Go/.NET/Rust) with installed metadata; negative tests w/ lockfile‑only.
|
* **Lang ecosystems:** sample images per ecosystem (Java/Node/Python/Go/.NET/Rust) with installed metadata; negative tests w/ lockfile‑only.
|
||||||
* **Native & EntryTrace:** ELF graph correctness; shell AST cases (includes, run‑parts, exec, case/if).
|
* **Native & EntryTrace:** ELF graph correctness; shell AST cases (includes, run‑parts, exec, case/if).
|
||||||
* **Diff:** layer attribution against synthetic two‑image sequences.
|
* **Diff:** layer attribution against synthetic two‑image sequences.
|
||||||
* **Performance:** cold vs warm cache; large `node_modules` and `site‑packages`.
|
* **Performance:** cold vs warm cache; large `node_modules` and `site‑packages`.
|
||||||
* **Security:** ensure no code execution from image; fuzz parser inputs; path traversal resistance on layer extract.
|
* **Security:** ensure no code execution from image; fuzz parser inputs; path traversal resistance on layer extract.
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -605,16 +605,16 @@ scanner:
|
|||||||
## 13) Failure modes & degradations
|
## 13) Failure modes & degradations
|
||||||
|
|
||||||
* **Missing OS DB** (files exist, DB removed): record **files**; do **not** fabricate package components; emit `bin:{sha256}` where unavoidable; flag in evidence.
|
* **Missing OS DB** (files exist, DB removed): record **files**; do **not** fabricate package components; emit `bin:{sha256}` where unavoidable; flag in evidence.
|
||||||
* **Unreadable metadata** (corrupt dist‑info): record file evidence; skip component creation; annotate.
|
* **Unreadable metadata** (corrupt dist‑info): record file evidence; skip component creation; annotate.
|
||||||
* **Dynamic shell constructs**: mark unresolved edges with reasons (env var unknown) and continue; **Usage** view may be partial.
|
* **Dynamic shell constructs**: mark unresolved edges with reasons (env var unknown) and continue; **Usage** view may be partial.
|
||||||
* **Registry rate limits**: honor backoff; queue job retries with jitter.
|
* **Registry rate limits**: honor backoff; queue job retries with jitter.
|
||||||
* **Signer refusal** (license/plan/version): scan completes; artifact produced; **no attestation**; WebService marks result as **unverified**.
|
* **Signer refusal** (license/plan/version): scan completes; artifact produced; **no attestation**; WebService marks result as **unverified**.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 14) Optional plug‑ins (off by default)
|
## 14) Optional plug‑ins (off by default)
|
||||||
|
|
||||||
* **Patch‑presence detector** (signature‑based backport checks). Reads curated function‑level signatures from advisories; inspects binaries for patched code snippets to lower false‑positives for backported fixes. Runs as a sidecar analyzer that **annotates** components; never overrides core identities.
|
* **Patch‑presence detector** (signature‑based backport checks). Reads curated function‑level signatures from advisories; inspects binaries for patched code snippets to lower false‑positives for backported fixes. Runs as a sidecar analyzer that **annotates** components; never overrides core identities.
|
||||||
* **Runtime probes** (with Zastava): when allowed, compare **/proc/<pid>/maps** (DSOs actually loaded) with static **Usage** view for precision.
|
* **Runtime probes** (with Zastava): when allowed, compare **/proc/<pid>/maps** (DSOs actually loaded) with static **Usage** view for precision.
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -637,14 +637,14 @@ scanner:
|
|||||||
|
|
||||||
## 17) Roadmap (Scanner)
|
## 17) Roadmap (Scanner)
|
||||||
|
|
||||||
* **M2**: Windows containers (MSI/SxS/GAC analyzers), PE/Mach‑O native analyzer, deeper Rust metadata.
|
* **M2**: Windows containers (MSI/SxS/GAC analyzers), PE/Mach‑O native analyzer, deeper Rust metadata.
|
||||||
* **M2**: Buildx generator GA (certified external registries), cross‑registry trust policies.
|
* **M2**: Buildx generator GA (certified external registries), cross‑registry trust policies.
|
||||||
* **M3**: Patch‑presence plug‑in GA (opt‑in), cross‑image corpus clustering (evidence‑only; not identity).
|
* **M3**: Patch‑presence plug‑in GA (opt‑in), cross‑image corpus clustering (evidence‑only; not identity).
|
||||||
* **M3**: Advanced EntryTrace (POSIX shell features breadth, busybox detection).
|
* **M3**: Advanced EntryTrace (POSIX shell features breadth, busybox detection).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Appendix A — EntryTrace resolution (pseudo)
|
### Appendix A — EntryTrace resolution (pseudo)
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
ResolveEntrypoint(ImageConfig cfg, RootFs fs):
|
ResolveEntrypoint(ImageConfig cfg, RootFs fs):
|
||||||
@@ -675,9 +675,9 @@ ResolveEntrypoint(ImageConfig cfg, RootFs fs):
|
|||||||
return Unknown(reason)
|
return Unknown(reason)
|
||||||
```
|
```
|
||||||
|
|
||||||
### Appendix A.1 — EntryTrace Explainability
|
### Appendix A.1 — EntryTrace Explainability
|
||||||
|
|
||||||
### Appendix A.0 — Replay / Record mode
|
### Appendix A.0 — Replay / Record mode
|
||||||
|
|
||||||
- WebService ships a **RecordModeService** that assembles replay manifests (schema v1) with policy/feed/tool pins and reachability references, then writes deterministic input/output bundles to the configured object store (RustFS default, S3/Minio fallback) under `replay/<head>/<digest>.tar.zst`.
|
- WebService ships a **RecordModeService** that assembles replay manifests (schema v1) with policy/feed/tool pins and reachability references, then writes deterministic input/output bundles to the configured object store (RustFS default, S3/Minio fallback) under `replay/<head>/<digest>.tar.zst`.
|
||||||
- Bundles contain canonical manifest JSON plus inputs (policy/feed/tool/analyzer digests) and outputs (SBOM, findings, optional VEX/logs); CAS URIs follow `cas://replay/...` and are attached to scan snapshots as `ReplayArtifacts`.
|
- Bundles contain canonical manifest JSON plus inputs (policy/feed/tool/analyzer digests) and outputs (SBOM, findings, optional VEX/logs); CAS URIs follow `cas://replay/...` and are attached to scan snapshots as `ReplayArtifacts`.
|
||||||
@@ -698,8 +698,8 @@ EntryTrace emits structured diagnostics and metrics so operators can quickly und
|
|||||||
|
|
||||||
Diagnostics drive two metrics published by `EntryTraceMetrics`:
|
Diagnostics drive two metrics published by `EntryTraceMetrics`:
|
||||||
|
|
||||||
- `entrytrace_resolutions_total{outcome}` — resolution attempts segmented by outcome (`resolved`, `partiallyresolved`, `unresolved`).
|
- `entrytrace_resolutions_total{outcome}` — resolution attempts segmented by outcome (`resolved`, `partiallyresolved`, `unresolved`).
|
||||||
- `entrytrace_unresolved_total{reason}` — diagnostic counts keyed by reason.
|
- `entrytrace_unresolved_total{reason}` — diagnostic counts keyed by reason.
|
||||||
|
|
||||||
Structured logs include `entrytrace.path`, `entrytrace.command`, `entrytrace.reason`, and `entrytrace.depth`, all correlated with scan/job IDs. Timestamps are normalized to UTC (microsecond precision) to keep DSSE attestations and UI traces explainable.
|
Structured logs include `entrytrace.path`, `entrytrace.command`, `entrytrace.reason`, and `entrytrace.depth`, all correlated with scan/job IDs. Timestamps are normalized to UTC (microsecond precision) to keep DSSE attestations and UI traces explainable.
|
||||||
|
|
||||||
|
|||||||
@@ -1,81 +1,143 @@
|
|||||||
# S00 Nav Rendering Policy
|
# S00 Nav Rendering Policy
|
||||||
|
|
||||||
Status: Frozen
|
Status: Frozen
|
||||||
Date: 2026-02-18
|
Date: 2026-03-29
|
||||||
Working directory: `docs/modules/ui/v2-rewire`
|
Working directory: `docs/modules/ui/v2-rewire`
|
||||||
Sprint: `20260218_005`, task `R0-03`
|
Sprint: `20260218_005`, task `R0-03` (updated 2026-03-29 for 6-group restructure)
|
||||||
|
|
||||||
## Policy statement
|
## Policy statement
|
||||||
|
|
||||||
Release Control-owned capabilities may be rendered as direct shortcuts in the sidebar if and only if:
|
Capabilities may be rendered as direct shortcuts in the sidebar if and only if:
|
||||||
1. Ownership is labeled as **Release Control** in breadcrumbs and page headers.
|
1. Ownership is labeled with the correct **group name** in breadcrumbs and page headers.
|
||||||
2. The canonical routes for those capabilities live under `/release-control/*`.
|
2. The canonical routes for those capabilities live under the group's route prefix.
|
||||||
3. The sidebar shortcut links to the canonical route, not an alias.
|
3. The sidebar shortcut links to the canonical route, not an alias.
|
||||||
|
|
||||||
This policy prevents mixed rendering where the same screen appears to be owned by two domains.
|
This policy prevents mixed rendering where the same screen appears to be owned by two domains.
|
||||||
|
|
||||||
|
## Canonical sidebar groups (6 groups)
|
||||||
|
|
||||||
|
The sidebar is organized into exactly 6 menu groups identified by `menuGroupId`:
|
||||||
|
|
||||||
|
| # | menuGroupId | Rendered label | Purpose |
|
||||||
|
|---|-------------|----------------|---------|
|
||||||
|
| 1 | `home` | *(none)* | Dashboard entry point |
|
||||||
|
| 2 | `release-control` | Release Control | Deployments, Releases, Environments, Readiness |
|
||||||
|
| 3 | `security` | Security | Vulnerabilities, Posture, Scan, VEX & Exceptions, Risk & Governance (incl. Simulation, Audit) |
|
||||||
|
| 4 | `evidence` | Evidence | Evidence Overview, Decision Capsules, Audit Log, Export Center |
|
||||||
|
| 5 | `operations` | Operations | Operations Hub, Policy Packs, Scheduled Jobs, Feeds & Airgap, Agent Fleet, Signals, Scripts, Diagnostics |
|
||||||
|
| 6 | `setup-admin` | Settings | Integrations, Identity & Access, Certificates & Trust, Theme & Branding, User Preferences |
|
||||||
|
|
||||||
|
### Policy dissolution
|
||||||
|
|
||||||
|
The former `policy` group was dissolved in the 7-to-6 restructure. Policy is a toolset, not a persona -- its items were distributed by audience:
|
||||||
|
|
||||||
|
- **Security** absorbed: VEX & Exceptions, Risk & Governance (including Simulation and Policy Audit). These are consumed by security practitioners during triage and risk assessment.
|
||||||
|
- **Operations** absorbed: Policy Packs. Pack authoring and management is an operational/admin workflow.
|
||||||
|
|
||||||
|
There is no standalone "Policy" group in the sidebar. The `/ops/policy/*` route prefix is retained for backward compatibility but items are surfaced under their new parent groups.
|
||||||
|
|
||||||
|
### New items surfaced (2026-03-29)
|
||||||
|
|
||||||
|
- **Readiness** (`/releases/readiness`) -- added to Release Control. Surfaces gate status and release readiness checks before promotion.
|
||||||
|
- **Findings Explorer** (`/security/findings`) -- added as a child of Security Posture. Provides a filterable view of all security findings across the fleet.
|
||||||
|
|
||||||
|
### Items removed from direct navigation
|
||||||
|
|
||||||
|
The following items are no longer direct sidebar entries but remain routable for deep links and contextual navigation:
|
||||||
|
|
||||||
|
- Runtime Drift, Notifications, Watchlist -- accessible from Operations Hub landing page
|
||||||
|
- Replay & Verify, Bundles, Trust -- accessible from Evidence Overview and Decision Capsules detail
|
||||||
|
|
||||||
## Allowed rendering model
|
## Allowed rendering model
|
||||||
|
|
||||||
### Desktop (expanded sidebar)
|
### Desktop (expanded sidebar)
|
||||||
|
|
||||||
```
|
```
|
||||||
Dashboard
|
[Home]
|
||||||
|
Dashboard
|
||||||
Release Control
|
Release Control
|
||||||
├── Releases [shortcut direct nav allowed]
|
Deployments [badge: failed runs + pending approvals]
|
||||||
├── Approvals [shortcut direct nav allowed]
|
Releases [badge: blocked gates]
|
||||||
├── Bundles [nested only — no direct shortcut]
|
Environments
|
||||||
├── Deployments [nested only — no direct shortcut]
|
Readiness
|
||||||
└── Regions & Environments [nested only — no direct shortcut]
|
Security
|
||||||
Security & Risk
|
Vulnerabilities [badge: critical findings]
|
||||||
Evidence & Audit
|
Security Posture [sparkline: security trend]
|
||||||
Integrations
|
Supply-Chain Data
|
||||||
Platform Ops
|
Findings Explorer
|
||||||
Administration
|
Reachability
|
||||||
|
Unknowns
|
||||||
|
Scan Image
|
||||||
|
VEX & Exceptions
|
||||||
|
Risk & Governance
|
||||||
|
Simulation
|
||||||
|
Policy Audit
|
||||||
|
Evidence
|
||||||
|
Evidence Overview
|
||||||
|
Decision Capsules
|
||||||
|
Audit Log
|
||||||
|
Export Center
|
||||||
|
Operations
|
||||||
|
Operations Hub [sparkline: platform trend]
|
||||||
|
Policy Packs
|
||||||
|
Scheduled Jobs
|
||||||
|
Feeds & Airgap
|
||||||
|
Agent Fleet
|
||||||
|
Signals
|
||||||
|
Scripts
|
||||||
|
Diagnostics
|
||||||
|
Settings
|
||||||
|
Integrations
|
||||||
|
Identity & Access
|
||||||
|
Certificates & Trust
|
||||||
|
Theme & Branding
|
||||||
|
User Preferences
|
||||||
```
|
```
|
||||||
|
|
||||||
`Releases` and `Approvals` may appear as direct children under `Release Control` in the sidebar
|
### Desktop (collapsed sidebar -- icons only)
|
||||||
(rather than requiring expand → click).
|
|
||||||
`Bundles`, `Deployments`, and `Regions & Environments` remain nested and require expand.
|
|
||||||
|
|
||||||
### Desktop (collapsed sidebar — icons only)
|
- Show icon for each group root only.
|
||||||
|
- Tooltip on hover shows the group label.
|
||||||
- Show icon for Release Control root only.
|
- Click navigates to the first item in the group or last active child.
|
||||||
- Tooltip on hover shows "Release Control".
|
- No separate child icons in collapsed mode.
|
||||||
- Click navigates to Release Control overview or last active child.
|
|
||||||
- No separate Releases / Approvals icons in collapsed mode.
|
|
||||||
|
|
||||||
### Mobile (navigation drawer)
|
### Mobile (navigation drawer)
|
||||||
|
|
||||||
- All root domains appear as top-level items in the drawer.
|
- All 6 groups appear as top-level items in the drawer.
|
||||||
- Release Control expands in-place to show child nav items.
|
- Groups expand in-place to show child nav items.
|
||||||
- `Releases` and `Approvals` may appear as drawer children with Release Control as visible parent.
|
- No capabilities may appear as top-level drawer items separate from their group.
|
||||||
- No Release Control capabilities may appear as top-level drawer items separate from the Release Control group.
|
|
||||||
|
|
||||||
## Breadcrumb rules
|
## Breadcrumb rules
|
||||||
|
|
||||||
Canonical format: `Root Domain > Capability > [Sub-page]`
|
Canonical format: `Group > Capability > [Sub-page]`
|
||||||
|
|
||||||
| Scenario | Breadcrumb | Notes |
|
| Scenario | Breadcrumb | Notes |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| Releases list | `Release Control > Releases` | No shortcut bypasses ownership label |
|
| Deployments list | `Release Control > Deployments` | |
|
||||||
| Release detail | `Release Control > Releases > RCB-1234` | ID or name appended |
|
| Release detail | `Release Control > Releases > RCB-1234` | ID or name appended |
|
||||||
| Approvals queue | `Release Control > Approvals` | |
|
| Readiness | `Release Control > Readiness` | New item |
|
||||||
| Approval detail | `Release Control > Approvals > APR-5678` | |
|
| Vulnerabilities | `Security > Vulnerabilities` | |
|
||||||
| Bundle catalog | `Release Control > Bundles` | |
|
| Findings Explorer | `Security > Security Posture > Findings Explorer` | Nested under posture |
|
||||||
| Bundle detail | `Release Control > Bundles > my-bundle` | |
|
| VEX & Exceptions | `Security > VEX & Exceptions` | Absorbed from Policy |
|
||||||
| Bundle version detail | `Release Control > Bundles > my-bundle > v1.3.0` | |
|
| Risk & Governance | `Security > Risk & Governance` | Absorbed from Policy |
|
||||||
| Deployments | `Release Control > Deployments` | |
|
| Policy Simulation | `Security > Risk & Governance > Simulation` | Nested child |
|
||||||
| Environments list | `Release Control > Regions & Environments` | |
|
| Evidence Overview | `Evidence > Evidence Overview` | |
|
||||||
| Environment detail | `Release Control > Regions & Environments > staging-eu` | |
|
| Decision Capsules | `Evidence > Decision Capsules` | |
|
||||||
|
| Audit Log | `Evidence > Audit Log` | |
|
||||||
|
| Operations Hub | `Operations > Operations Hub` | |
|
||||||
|
| Policy Packs | `Operations > Policy Packs` | Absorbed from Policy |
|
||||||
|
| Integrations | `Settings > Integrations` | |
|
||||||
|
| Certificates & Trust | `Settings > Certificates & Trust` | Renamed from "Certificates" |
|
||||||
|
|
||||||
### Concrete counter-examples (forbidden)
|
### Concrete counter-examples (forbidden)
|
||||||
|
|
||||||
| Forbidden breadcrumb | Reason |
|
| Forbidden breadcrumb | Reason |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `Approvals > APR-5678` | Missing Release Control ownership prefix |
|
| `Policy > VEX & Exceptions` | Policy group no longer exists; VEX is under Security |
|
||||||
| `Releases` (no parent) | Same — no domain context |
|
| `Policy > Packs` | Policy group dissolved; Packs is under Operations |
|
||||||
| `Settings > Policy Governance` | Policy Governance owner is Administration, not Settings |
|
| `Approvals > APR-5678` | Missing group ownership prefix |
|
||||||
| `Evidence & Audit > Trust & Signing` | Trust & Signing owner is Administration; Evidence may only show a consumer link |
|
| `Releases` (no parent) | No domain context |
|
||||||
|
| `Evidence > Trust` | Trust item removed from Evidence nav |
|
||||||
|
|
||||||
## Legacy label transition behavior
|
## Legacy label transition behavior
|
||||||
|
|
||||||
@@ -83,7 +145,7 @@ Where users know a surface by an old label, show a compact transition label duri
|
|||||||
|
|
||||||
Rules:
|
Rules:
|
||||||
- Transition labels appear only in page headers and sidebar items, not in breadcrumbs.
|
- Transition labels appear only in page headers and sidebar items, not in breadcrumbs.
|
||||||
- Format: canonical label is primary; old label appears parenthetically — e.g., `Policy Governance (formerly Policy Studio)`.
|
- Format: canonical label is primary; old label appears parenthetically -- e.g., `Certificates & Trust (formerly Certificates)`.
|
||||||
- Transition labels are removed at sprint 016 cutover unless traffic evidence requires extension.
|
- Transition labels are removed at sprint 016 cutover unless traffic evidence requires extension.
|
||||||
- Canonical labels are always primary; old labels never replace canonical ones.
|
- Canonical labels are always primary; old labels never replace canonical ones.
|
||||||
|
|
||||||
@@ -91,26 +153,26 @@ Planned transition labels:
|
|||||||
|
|
||||||
| Canonical label | Transition label (migration window only) | Remove at |
|
| Canonical label | Transition label (migration window only) | Remove at |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `Security & Risk` | `Security & Risk (formerly Security)` | Sprint 016 |
|
| `Security` | `Security (formerly Security & Risk)` | Sprint 016 |
|
||||||
| `Platform Ops` | `Platform Ops (formerly Operations)` | Sprint 016 |
|
| `Operations` | `Operations (formerly Platform Ops)` | Sprint 016 |
|
||||||
| `Evidence & Audit` | `Evidence & Audit (formerly Evidence)` | Sprint 016 |
|
| `Evidence` | `Evidence (formerly Evidence & Audit)` | Sprint 016 |
|
||||||
| `Policy Governance` | `Policy Governance (formerly Policy Studio / Policy)` | Sprint 016 |
|
| `Certificates & Trust` | `Certificates & Trust (formerly Certificates)` | Sprint 016 |
|
||||||
|
|
||||||
## Explicit do-not list
|
## Explicit do-not list
|
||||||
|
|
||||||
The following rendering patterns are forbidden in any sprint implementation:
|
The following rendering patterns are forbidden in any sprint implementation:
|
||||||
|
|
||||||
1. **Do not** place Release Control capability screens (`Releases`, `Approvals`, `Bundles`, `Deployments`, `Environments`) as root-level sidebar items independent from the `Release Control` group.
|
1. **Do not** place any capability as a root-level sidebar item independent from its canonical group.
|
||||||
2. **Do not** display a breadcrumb that omits the canonical root domain prefix.
|
2. **Do not** display a breadcrumb that omits the canonical group prefix.
|
||||||
3. **Do not** show different ownership labels on desktop vs. mobile for the same screen.
|
3. **Do not** show different ownership labels on desktop vs. mobile for the same screen.
|
||||||
4. **Do not** use legacy root-level nav paths (e.g., `/approvals`, `/releases`) as the canonical nav target — they must redirect to `/release-control/*` canonical targets.
|
4. **Do not** use legacy root-level nav paths (e.g., `/approvals`, `/releases` at root) as the canonical nav target -- they must redirect to canonical targets.
|
||||||
5. **Do not** label `Trust & Signing` as owned by Evidence & Audit or Security in any nav or header.
|
5. **Do not** reintroduce a `policy` group -- Policy items live under Security and Operations.
|
||||||
6. **Do not** label `Policy Governance` as owned by Release Control in any nav or header.
|
6. **Do not** label Policy Packs as owned by Security -- Packs authoring is an Operations concern.
|
||||||
7. **Do not** introduce a new root domain that is not in the canonical 7: Dashboard, Release Control, Security & Risk, Evidence & Audit, Integrations, Platform Ops, Administration.
|
7. **Do not** introduce a new root domain that is not in the canonical 6: Home, Release Control, Security, Evidence, Operations, Settings.
|
||||||
|
|
||||||
## Route alias requirements for migration
|
## Route alias requirements for migration
|
||||||
|
|
||||||
During the alias window, current root-level paths (`/releases`, `/approvals`) must:
|
During the alias window, legacy paths must:
|
||||||
- Resolve to the canonical `/release-control/releases` and `/release-control/approvals` routes.
|
- Resolve to the canonical routes under the new group structure.
|
||||||
- Render the canonical breadcrumb (e.g., `Release Control > Releases`) — not an alias-derived breadcrumb.
|
- Render the canonical breadcrumb (e.g., `Security > VEX & Exceptions`) -- not an alias-derived breadcrumb.
|
||||||
- Not appear as primary nav items in the sidebar; the sidebar must link to canonical paths only.
|
- Not appear as primary nav items in the sidebar; the sidebar must link to canonical paths only.
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
# Automated Test-Suite Overview
|
# Automated Test-Suite Overview
|
||||||
|
|
||||||
This document enumerates **every automated check** executed by the Stella Ops
|
This document enumerates **every automated check** executed by the Stella Ops
|
||||||
CI pipeline, from unit level to chaos experiments. It is intended for
|
CI pipeline, from unit level to chaos experiments. It is intended for
|
||||||
contributors who need to extend coverage or diagnose failures.
|
contributors who need to extend coverage or diagnose failures.
|
||||||
|
|
||||||
> **Build parameters** – values such as `{{ dotnet }}` (runtime) and
|
> **Build parameters** – values such as `{{ dotnet }}` (runtime) and
|
||||||
> `{{ angular }}` (UI framework) are injected at build time.
|
> `{{ angular }}` (UI framework) are injected at build time.
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -13,7 +13,7 @@ contributors who need to extend coverage or diagnose failures.
|
|||||||
|
|
||||||
### Core Principles
|
### Core Principles
|
||||||
|
|
||||||
1. **Determinism as Contract**: Scan verdicts must be reproducible. Same inputs → byte-identical outputs.
|
1. **Determinism as Contract**: Scan verdicts must be reproducible. Same inputs → byte-identical outputs.
|
||||||
2. **Offline by Default**: Every test (except explicitly tagged "online") runs without network access.
|
2. **Offline by Default**: Every test (except explicitly tagged "online") runs without network access.
|
||||||
3. **Evidence-First Validation**: Assertions verify the complete evidence chain, not just pass/fail.
|
3. **Evidence-First Validation**: Assertions verify the complete evidence chain, not just pass/fail.
|
||||||
4. **Interop is Required**: Compatibility with ecosystem tools (Syft, Grype, Trivy, cosign) blocks releases.
|
4. **Interop is Required**: Compatibility with ecosystem tools (Syft, Grype, Trivy, cosign) blocks releases.
|
||||||
@@ -78,16 +78,16 @@ the required test types per project model and the module-to-model mapping.
|
|||||||
|
|
||||||
| Metric | Budget | Gate |
|
| Metric | Budget | Gate |
|
||||||
|--------|--------|------|
|
|--------|--------|------|
|
||||||
| API unit coverage | ≥ 85% lines | PR merge |
|
| API unit coverage | ≥ 85% lines | PR merge |
|
||||||
| API response P95 | ≤ 120 ms | nightly alert |
|
| API response P95 | ≤ 120 ms | nightly alert |
|
||||||
| Δ-SBOM warm scan P95 (4 vCPU) | ≤ 5 s | nightly alert |
|
| Δ-SBOM warm scan P95 (4 vCPU) | ≤ 5 s | nightly alert |
|
||||||
| Lighthouse performance score | ≥ 90 | nightly alert |
|
| Lighthouse performance score | ≥ 90 | nightly alert |
|
||||||
| Lighthouse accessibility score | ≥ 95 | nightly alert |
|
| Lighthouse accessibility score | ≥ 95 | nightly alert |
|
||||||
| k6 sustained RPS drop | < 5% vs baseline | nightly alert |
|
| k6 sustained RPS drop | < 5% vs baseline | nightly alert |
|
||||||
| **Replay determinism** | 0 byte diff | **Release** |
|
| **Replay determinism** | 0 byte diff | **Release** |
|
||||||
| **Interop findings parity** | ≥ 95% | **Release** |
|
| **Interop findings parity** | ≥ 95% | **Release** |
|
||||||
| **Offline E2E** | All pass with no network | **Release** |
|
| **Offline E2E** | All pass with no network | **Release** |
|
||||||
| **Unknowns budget (prod)** | ≤ configured limit | **Release** |
|
| **Unknowns budget (prod)** | ≤ configured limit | **Release** |
|
||||||
| **Router Retry-After compliance** | 100% | Nightly |
|
| **Router Retry-After compliance** | 100% | Nightly |
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -109,7 +109,7 @@ dotnet test --filter "Category=Interop"
|
|||||||
|
|
||||||
The script spins up PostgreSQL/Valkey via Testcontainers and requires:
|
The script spins up PostgreSQL/Valkey via Testcontainers and requires:
|
||||||
|
|
||||||
* Docker ≥ 25
|
* Docker ≥ 25
|
||||||
* Node 20 (for Jest/Playwright)
|
* Node 20 (for Jest/Playwright)
|
||||||
|
|
||||||
### PostgreSQL Testcontainers
|
### PostgreSQL Testcontainers
|
||||||
@@ -158,7 +158,7 @@ stella replay verify --manifest run-manifest.json
|
|||||||
### Evidence Index
|
### Evidence Index
|
||||||
|
|
||||||
The **Evidence Index** links verdicts to their supporting evidence chain:
|
The **Evidence Index** links verdicts to their supporting evidence chain:
|
||||||
- Verdict → SBOM digests → Attestation IDs → Tool versions
|
- Verdict → SBOM digests → Attestation IDs → Tool versions
|
||||||
|
|
||||||
### Golden Corpus
|
### Golden Corpus
|
||||||
|
|
||||||
@@ -191,7 +191,7 @@ public class OfflineTests : NetworkIsolatedTestBase
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Concelier OSV↔GHSA Parity Fixtures
|
## Concelier OSV↔GHSA Parity Fixtures
|
||||||
|
|
||||||
The Concelier connector suite includes a regression test (`OsvGhsaParityRegressionTests`)
|
The Concelier connector suite includes a regression test (`OsvGhsaParityRegressionTests`)
|
||||||
that checks a curated set of GHSA identifiers against OSV responses. The fixture
|
that checks a curated set of GHSA identifiers against OSV responses. The fixture
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# 01. Requirements And Principles
|
# 01. Requirements And Principles
|
||||||
|
|
||||||
## 1. Product Goal
|
## 1. Product Goal
|
||||||
|
|
||||||
@@ -239,7 +239,7 @@ They are related, but they are not the same data structure.
|
|||||||
|
|
||||||
### 5.3 Run To Wait
|
### 5.3 Run To Wait
|
||||||
|
|
||||||
The engine should never keep a workflow instance “hot†in memory for correctness.
|
The engine should never keep a workflow instance “hot” in memory for correctness.
|
||||||
|
|
||||||
Execution should run until:
|
Execution should run until:
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
# Tutorial 1: Hello World
|
# Tutorial 1: Hello World
|
||||||
|
|
||||||
The simplest possible workflow: initialize state from a start request, activate a single human task, and complete the workflow when the task is done.
|
The simplest possible workflow: initialize state from a start request, activate a single human task, and complete the workflow when the task is done.
|
||||||
|
|
||||||
## Concepts Introduced
|
## Concepts Introduced
|
||||||
|
|
||||||
- `IDeclarativeWorkflow<T>` — the contract every workflow implements
|
- `IDeclarativeWorkflow<T>` — the contract every workflow implements
|
||||||
- `WorkflowSpec.For<T>()` — the builder entry point
|
- `WorkflowSpec.For<T>()` — the builder entry point
|
||||||
- `.InitializeState()` — transforms the start request into workflow state
|
- `.InitializeState()` — transforms the start request into workflow state
|
||||||
- `.StartWith(task)` — sets the first task to activate
|
- `.StartWith(task)` — sets the first task to activate
|
||||||
- `WorkflowHumanTask.For<T>()` — defines a human task
|
- `WorkflowHumanTask.For<T>()` — defines a human task
|
||||||
- `.OnComplete(flow => flow.Complete())` — terminal step
|
- `.OnComplete(flow => flow.Complete())` — terminal step
|
||||||
|
|
||||||
## What Happens at Runtime
|
## What Happens at Runtime
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@ The simplest possible workflow: initialize state from a start request, activate
|
|||||||
2. State initializes to `{ "customerName": "John" }`
|
2. State initializes to `{ "customerName": "John" }`
|
||||||
3. Task "Greet Customer" is created with status "Pending"
|
3. Task "Greet Customer" is created with status "Pending"
|
||||||
4. A user assigns the task to themselves, then completes it
|
4. A user assigns the task to themselves, then completes it
|
||||||
5. `OnComplete` executes `.Complete()` — the workflow finishes
|
5. `OnComplete` executes `.Complete()` — the workflow finishes
|
||||||
|
|
||||||
## Variants
|
## Variants
|
||||||
|
|
||||||
@@ -26,5 +26,5 @@ The simplest possible workflow: initialize state from a start request, activate
|
|||||||
|
|
||||||
## Next
|
## Next
|
||||||
|
|
||||||
[Tutorial 2: Service Tasks](../02-service-tasks/) — call external services before or after human tasks.
|
[Tutorial 2: Service Tasks](../02-service-tasks/) — call external services before or after human tasks.
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
# Tutorial 2: Service Tasks
|
# Tutorial 2: Service Tasks
|
||||||
|
|
||||||
Call external services (microservices, HTTP APIs, GraphQL, RabbitMQ) from within a workflow. Handle failures and timeouts gracefully.
|
Call external services (microservices, HTTP APIs, GraphQL, RabbitMQ) from within a workflow. Handle failures and timeouts gracefully.
|
||||||
|
|
||||||
## Concepts Introduced
|
## Concepts Introduced
|
||||||
|
|
||||||
- `.Call()` — invoke a transport with payload and optional response capture
|
- `.Call()` — invoke a transport with payload and optional response capture
|
||||||
- Address types — `LegacyRabbit`, `Microservice`, `Http`, `Graphql`, `Rabbit`
|
- Address types — `LegacyRabbit`, `Microservice`, `Http`, `Graphql`, `Rabbit`
|
||||||
- `resultKey` — store the service response in workflow state
|
- `resultKey` — store the service response in workflow state
|
||||||
- `whenFailure` / `whenTimeout` — recovery branches
|
- `whenFailure` / `whenTimeout` — recovery branches
|
||||||
- `WorkflowHandledBranchAction.Complete` — shorthand for "complete on error"
|
- `WorkflowHandledBranchAction.Complete` — shorthand for "complete on error"
|
||||||
- `timeoutSeconds` — per-step timeout override (default: 1 hour)
|
- `timeoutSeconds` — per-step timeout override (default: 1 hour)
|
||||||
|
|
||||||
## Key Points
|
## Key Points
|
||||||
|
|
||||||
@@ -25,5 +25,5 @@ Call external services (microservices, HTTP APIs, GraphQL, RabbitMQ) from within
|
|||||||
|
|
||||||
## Next
|
## Next
|
||||||
|
|
||||||
[Tutorial 3: Decisions](../03-decisions/) — branch workflow logic based on conditions.
|
[Tutorial 3: Decisions](../03-decisions/) — branch workflow logic based on conditions.
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
# Tutorial 3: Decisions
|
# Tutorial 3: Decisions
|
||||||
|
|
||||||
Branch workflow logic based on conditions — state values, payload answers, or complex expressions.
|
Branch workflow logic based on conditions — state values, payload answers, or complex expressions.
|
||||||
|
|
||||||
## Concepts Introduced
|
## Concepts Introduced
|
||||||
|
|
||||||
- `.WhenExpression()` — branch on any boolean expression
|
- `.WhenExpression()` — branch on any boolean expression
|
||||||
- `.WhenStateFlag()` — shorthand for checking a boolean state value
|
- `.WhenStateFlag()` — shorthand for checking a boolean state value
|
||||||
- `.WhenPayloadEquals()` — shorthand for checking a task completion payload value
|
- `.WhenPayloadEquals()` — shorthand for checking a task completion payload value
|
||||||
- Nested decisions — decisions inside decisions for complex routing
|
- Nested decisions — decisions inside decisions for complex routing
|
||||||
|
|
||||||
## Decision Types
|
## Decision Types
|
||||||
|
|
||||||
@@ -24,5 +24,5 @@ Branch workflow logic based on conditions — state values, payload answers
|
|||||||
|
|
||||||
## Next
|
## Next
|
||||||
|
|
||||||
[Tutorial 4: Human Tasks](../04-human-tasks/) — approve/reject patterns with OnComplete flows.
|
[Tutorial 4: Human Tasks](../04-human-tasks/) — approve/reject patterns with OnComplete flows.
|
||||||
|
|
||||||
|
|||||||
@@ -1,26 +1,26 @@
|
|||||||
# Tutorial 4: Human Tasks with OnComplete Flows
|
# Tutorial 4: Human Tasks with OnComplete Flows
|
||||||
|
|
||||||
The approve/reject pattern — the most common human task flow in insurance workflows.
|
The approve/reject pattern — the most common human task flow in insurance workflows.
|
||||||
|
|
||||||
## Concepts Introduced
|
## Concepts Introduced
|
||||||
|
|
||||||
- `WorkflowHumanTask.For<T>()` — define a task with name, type, route, and roles
|
- `WorkflowHumanTask.For<T>()` — define a task with name, type, route, and roles
|
||||||
- `.WithPayload()` — data sent to the UI when the task is displayed
|
- `.WithPayload()` — data sent to the UI when the task is displayed
|
||||||
- `.WithTimeout(seconds)` — optional deadline for the task
|
- `.WithTimeout(seconds)` — optional deadline for the task
|
||||||
- `.WithRoles()` — restrict which roles can interact with this task
|
- `.WithRoles()` — restrict which roles can interact with this task
|
||||||
- `.OnComplete(flow => ...)` — sequence executed after user completes the task
|
- `.OnComplete(flow => ...)` — sequence executed after user completes the task
|
||||||
- `.ActivateTask()` — pause workflow and wait for user action
|
- `.ActivateTask()` — pause workflow and wait for user action
|
||||||
- `.AddTask()` — register a task in the workflow spec (separate from activation)
|
- `.AddTask()` — register a task in the workflow spec (separate from activation)
|
||||||
- Re-activation — send the user back to the same task on validation failure
|
- Re-activation — send the user back to the same task on validation failure
|
||||||
|
|
||||||
## Approve/Reject Pattern
|
## Approve/Reject Pattern
|
||||||
|
|
||||||
1. Workflow starts, runs some service tasks
|
1. Workflow starts, runs some service tasks
|
||||||
2. `.ActivateTask("Approve")` — workflow pauses
|
2. `.ActivateTask("Approve")` — workflow pauses
|
||||||
3. User sees the task in their inbox, assigns it, submits an answer
|
3. User sees the task in their inbox, assigns it, submits an answer
|
||||||
4. `.OnComplete` checks `payload.answer`:
|
4. `.OnComplete` checks `payload.answer`:
|
||||||
- `"approve"` — run confirmation operations, convert to policy
|
- `"approve"` — run confirmation operations, convert to policy
|
||||||
- `"reject"` — cancel the application
|
- `"reject"` — cancel the application
|
||||||
5. If operations fail, re-activate the same task for correction
|
5. If operations fail, re-activate the same task for correction
|
||||||
|
|
||||||
## Variants
|
## Variants
|
||||||
@@ -30,5 +30,5 @@ The approve/reject pattern — the most common human task flow in insurance
|
|||||||
|
|
||||||
## Next
|
## Next
|
||||||
|
|
||||||
[Tutorial 5: Sub-Workflows](../05-sub-workflows/) — inline vs fire-and-forget child workflows.
|
[Tutorial 5: Sub-Workflows](../05-sub-workflows/) — inline vs fire-and-forget child workflows.
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
# Tutorial 5: Sub-Workflows & Continuations
|
# Tutorial 5: Sub-Workflows & Continuations
|
||||||
|
|
||||||
Compose workflows by invoking child workflows — either inline (SubWorkflow) or fire-and-forget (ContinueWith).
|
Compose workflows by invoking child workflows — either inline (SubWorkflow) or fire-and-forget (ContinueWith).
|
||||||
|
|
||||||
## SubWorkflow vs ContinueWith
|
## SubWorkflow vs ContinueWith
|
||||||
|
|
||||||
| Feature | `.SubWorkflow()` | `.ContinueWith()` |
|
| Feature | `.SubWorkflow()` | `.ContinueWith()` |
|
||||||
|---------|-----------------|-------------------|
|
|---------|-----------------|-------------------|
|
||||||
| Parent waits | Yes — resumes after child completes | No — parent completes immediately |
|
| Parent waits | Yes — resumes after child completes | No — parent completes immediately |
|
||||||
| State flows back | Yes — child state merges into parent | No — child is independent |
|
| State flows back | Yes — child state merges into parent | No — child is independent |
|
||||||
| Same instance | Yes — tasks appear under parent instance | No — new workflow instance |
|
| Same instance | Yes — tasks appear under parent instance | No — new workflow instance |
|
||||||
| Use when | Steps must complete before parent continues | Fire-and-forget, scheduled work |
|
| Use when | Steps must complete before parent continues | Fire-and-forget, scheduled work |
|
||||||
|
|
||||||
## Variants
|
## Variants
|
||||||
@@ -18,5 +18,5 @@ Compose workflows by invoking child workflows — either inline (SubWorkflo
|
|||||||
|
|
||||||
## Next
|
## Next
|
||||||
|
|
||||||
[Tutorial 6: Advanced Patterns](../06-advanced-patterns/) — Fork, Repeat, Timer, External Signal.
|
[Tutorial 6: Advanced Patterns](../06-advanced-patterns/) — Fork, Repeat, Timer, External Signal.
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Tutorial 6: Advanced Patterns
|
# Tutorial 6: Advanced Patterns
|
||||||
|
|
||||||
Fork (parallel branches), Repeat (retry loops), Timer (delays), and External Signal (wait for events).
|
Fork (parallel branches), Repeat (retry loops), Timer (delays), and External Signal (wait for events).
|
||||||
|
|
||||||
@@ -18,5 +18,5 @@ Fork (parallel branches), Repeat (retry loops), Timer (delays), and External Sig
|
|||||||
|
|
||||||
## Next
|
## Next
|
||||||
|
|
||||||
[Tutorial 7: Shared Helpers](../07-shared-helpers/) — organizing reusable workflow components.
|
[Tutorial 7: Shared Helpers](../07-shared-helpers/) — organizing reusable workflow components.
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Tutorial 7: Shared Support Helpers
|
# Tutorial 7: Shared Support Helpers
|
||||||
|
|
||||||
When building many workflows for the same domain (e.g., 50+ policy change workflows), extract reusable components into a support helper class.
|
When building many workflows for the same domain (e.g., 50+ policy change workflows), extract reusable components into a support helper class.
|
||||||
|
|
||||||
@@ -6,19 +6,19 @@ When building many workflows for the same domain (e.g., 50+ policy change workfl
|
|||||||
|
|
||||||
| Component | Example |
|
| Component | Example |
|
||||||
|-----------|---------|
|
|-----------|---------|
|
||||||
| **Address constants** | `LegacyRabbitAddress`, `HttpAddress` — centralized routing |
|
| **Address constants** | `LegacyRabbitAddress`, `HttpAddress` — centralized routing |
|
||||||
| **Workflow references** | `WorkflowReference` — for SubWorkflow/ContinueWith targets |
|
| **Workflow references** | `WorkflowReference` — for SubWorkflow/ContinueWith targets |
|
||||||
| **Payload builders** | Static methods returning `WorkflowExpressionDefinition` |
|
| **Payload builders** | Static methods returning `WorkflowExpressionDefinition` |
|
||||||
| **State initializers** | Base state + override pattern |
|
| **State initializers** | Base state + override pattern |
|
||||||
| **Flow extensions** | Extension methods on `WorkflowFlowBuilder<T>` for common sequences |
|
| **Flow extensions** | Extension methods on `WorkflowFlowBuilder<T>` for common sequences |
|
||||||
|
|
||||||
## C#-Only Tutorial
|
## C#-Only Tutorial
|
||||||
|
|
||||||
This tutorial has no JSON equivalent — it covers C# code organization patterns.
|
This tutorial has no JSON equivalent — it covers C# code organization patterns.
|
||||||
|
|
||||||
- [C# Example](csharp/)
|
- [C# Example](csharp/)
|
||||||
|
|
||||||
## Next
|
## Next
|
||||||
|
|
||||||
[Tutorial 8: Expressions](../08-expressions/) — path navigation, functions, and operators.
|
[Tutorial 8: Expressions](../08-expressions/) — path navigation, functions, and operators.
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Tutorial 8: Expressions
|
# Tutorial 8: Expressions
|
||||||
|
|
||||||
The expression system enables declarative logic that compiles to portable canonical JSON. All expressions are evaluable at runtime without recompilation.
|
The expression system enables declarative logic that compiles to portable canonical JSON. All expressions are evaluable at runtime without recompilation.
|
||||||
|
|
||||||
@@ -32,5 +32,5 @@ The expression system enables declarative logic that compiles to portable canoni
|
|||||||
|
|
||||||
## Next
|
## Next
|
||||||
|
|
||||||
[Tutorial 9: Testing](../09-testing/) — unit test setup with recording transports.
|
[Tutorial 9: Testing](../09-testing/) — unit test setup with recording transports.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user