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:
File diff suppressed because it is too large
Load Diff
@@ -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.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,40 +1,40 @@
|
|||||||
# 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
|
||||||
|
|
||||||
- **Nodes:**
|
- **Nodes:**
|
||||||
- `Artifact` (application/image digest) with metadata (tenant, environment, labels).
|
- `Artifact` (application/image digest) with metadata (tenant, environment, labels).
|
||||||
- `SBOM` (sbom digest, format, version/sequence, chain id).
|
- `SBOM` (sbom digest, format, version/sequence, chain id).
|
||||||
- `Component` (package/version, purl, ecosystem).
|
- `Component` (package/version, purl, ecosystem).
|
||||||
- `File`/`Path` (source files, binary paths) with hash/time metadata.
|
- `File`/`Path` (source files, binary paths) with hash/time metadata.
|
||||||
- `License` nodes linked to components and SBOM attestations.
|
- `License` nodes linked to components and SBOM attestations.
|
||||||
- `Advisory` and `VEXStatement` nodes linking to Concelier/Excititor records via digests.
|
- `Advisory` and `VEXStatement` nodes linking to Concelier/Excititor records via digests.
|
||||||
- `PolicyVersion` nodes representing signed policy packs.
|
- `PolicyVersion` nodes representing signed policy packs.
|
||||||
- **Edges:** directed, timestamped relationships such as `DEPENDS_ON`, `BUILT_FROM`, `DECLARED_IN`, `AFFECTED_BY`, `VEX_EXEMPTS`, `GOVERNS_WITH`, `OBSERVED_RUNTIME`, `SBOM_VERSION_OF`, and `SBOM_LINEAGE_*`. Each edge carries provenance (SRM hash, SBOM digest, policy run ID).
|
- **Edges:** directed, timestamped relationships such as `DEPENDS_ON`, `BUILT_FROM`, `DECLARED_IN`, `AFFECTED_BY`, `VEX_EXEMPTS`, `GOVERNS_WITH`, `OBSERVED_RUNTIME`, `SBOM_VERSION_OF`, and `SBOM_LINEAGE_*`. Each edge carries provenance (SRM hash, SBOM digest, policy run ID).
|
||||||
- **Overlays:** computed index tables providing fast access to reachability, blast radius, and differential views (e.g., `graph_overlay/vuln/{tenant}/{advisoryKey}`). Runtime endpoints emit overlays inline (`policy.overlay.v1`, `openvex.v1`) with deterministic overlay IDs (`sha256(tenant|nodeId|overlayKind)`) and sampled explain traces on policy overlays.
|
- **Overlays:** computed index tables providing fast access to reachability, blast radius, and differential views (e.g., `graph_overlay/vuln/{tenant}/{advisoryKey}`). Runtime endpoints emit overlays inline (`policy.overlay.v1`, `openvex.v1`) with deterministic overlay IDs (`sha256(tenant|nodeId|overlayKind)`) and sampled explain traces on policy overlays.
|
||||||
|
|
||||||
## 2) Pipelines
|
## 2) Pipelines
|
||||||
|
|
||||||
1. **Ingestion:** Cartographer/SBOM Service emit SBOM snapshots (`sbom_snapshot` events) captured by the Graph Indexer. Ledger lineage references become `SBOM_VERSION_OF` + `SBOM_LINEAGE_*` edges. Advisories/VEX from Concelier/Excititor generate edge updates, policy runs attach overlay metadata.
|
1. **Ingestion:** Cartographer/SBOM Service emit SBOM snapshots (`sbom_snapshot` events) captured by the Graph Indexer. Ledger lineage references become `SBOM_VERSION_OF` + `SBOM_LINEAGE_*` edges. Advisories/VEX from Concelier/Excititor generate edge updates, policy runs attach overlay metadata.
|
||||||
2. **ETL:** Normalises nodes/edges into canonical IDs, deduplicates, enforces tenant partitions, and writes to the graph store (planned: Neo4j-compatible or PostgreSQL adjacency lists).
|
2. **ETL:** Normalises nodes/edges into canonical IDs, deduplicates, enforces tenant partitions, and writes to the graph store (planned: Neo4j-compatible or PostgreSQL adjacency lists).
|
||||||
3. **Overlay computation:** Batch workers build materialised views for frequently used queries (impact lists, saved queries, policy overlays) and store as immutable blobs for Offline Kit exports.
|
3. **Overlay computation:** Batch workers build materialised views for frequently used queries (impact lists, saved queries, policy overlays) and store as immutable blobs for Offline Kit exports.
|
||||||
4. **Diffing:** `graph_diff` jobs compare two snapshots (e.g., pre/post deploy) and generate signed diff manifests for UI/CLI consumption.
|
4. **Diffing:** `graph_diff` jobs compare two snapshots (e.g., pre/post deploy) and generate signed diff manifests for UI/CLI consumption.
|
||||||
5. **Analytics (Runtime & Signals 140.A):** background workers run Louvain-style clustering + degree/betweenness approximations on ingested graphs, emitting overlays per tenant/snapshot and writing cluster ids back to nodes when enabled.
|
5. **Analytics (Runtime & Signals 140.A):** background workers run Louvain-style clustering + degree/betweenness approximations on ingested graphs, emitting overlays per tenant/snapshot and writing cluster ids back to nodes when enabled.
|
||||||
|
|
||||||
## 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.
|
||||||
- `GET /graph/edges/{edgeId}/metadata` — single edge metadata with explanation, via, provenance, and evidence references.
|
- `GET /graph/edges/{edgeId}/metadata` — single edge metadata with explanation, via, provenance, and evidence references.
|
||||||
- `GET /graph/edges/path/{sourceNodeId}/{targetNodeId}` — returns all edges on the shortest path between two nodes, each with metadata.
|
- `GET /graph/edges/path/{sourceNodeId}/{targetNodeId}` — returns all edges on the shortest path between two nodes, each with metadata.
|
||||||
- `GET /graph/edges/by-reason/{reason}` — query edges by `EdgeReason` enum (e.g., `SbomDependency`, `AdvisoryAffects`, `VexStatement`, `RuntimeTrace`).
|
- `GET /graph/edges/by-reason/{reason}` — query edges by `EdgeReason` enum (e.g., `SbomDependency`, `AdvisoryAffects`, `VexStatement`, `RuntimeTrace`).
|
||||||
- `GET /graph/edges/by-evidence?evidenceType=&evidenceRef=` — query edges by evidence reference.
|
- `GET /graph/edges/by-evidence?evidenceType=&evidenceRef=` — query edges by evidence reference.
|
||||||
- Legacy: `GET /graph/nodes/{id}`, `POST /graph/query/saved`, `GET /graph/impact/{advisoryKey}`, `POST /graph/overlay/policy` remain in spec but should align to the NDJSON surfaces above as they are brought forward.
|
- Legacy: `GET /graph/nodes/{id}`, `POST /graph/query/saved`, `GET /graph/impact/{advisoryKey}`, `POST /graph/overlay/policy` remain in spec but should align to the NDJSON surfaces above as they are brought forward.
|
||||||
@@ -54,11 +54,11 @@
|
|||||||
- Rate limiting and audit logging use the resolved tenant context; authenticated flows no longer collapse to ambiguous `"unknown"` tenant keys.
|
- Rate limiting and audit logging use the resolved tenant context; authenticated flows no longer collapse to ambiguous `"unknown"` tenant keys.
|
||||||
|
|
||||||
### 3.2) Edge Metadata Contracts
|
### 3.2) Edge Metadata Contracts
|
||||||
|
|
||||||
The edge metadata system provides explainability for graph relationships:
|
The edge metadata system provides explainability for graph relationships:
|
||||||
|
|
||||||
- **EdgeReason** enum: `Unknown`, `SbomDependency`, `StaticSymbol`, `RuntimeTrace`, `PackageManifest`, `Lockfile`, `BuildArtifact`, `ImageLayer`, `AdvisoryAffects`, `VexStatement`, `PolicyOverlay`, `AttestationRef`, `OperatorAnnotation`, `TransitiveInference`, `Provenance`.
|
- **EdgeReason** enum: `Unknown`, `SbomDependency`, `StaticSymbol`, `RuntimeTrace`, `PackageManifest`, `Lockfile`, `BuildArtifact`, `ImageLayer`, `AdvisoryAffects`, `VexStatement`, `PolicyOverlay`, `AttestationRef`, `OperatorAnnotation`, `TransitiveInference`, `Provenance`.
|
||||||
- **EdgeVia** record: Describes how the edge was discovered (method, version, timestamp, confidence in basis points, evidence reference).
|
- **EdgeVia** record: Describes how the edge was discovered (method, version, timestamp, confidence in basis points, evidence reference).
|
||||||
- **EdgeExplanationPayload** record: Full explanation including reason, via, human-readable summary, evidence list, provenance reference, and tags.
|
- **EdgeExplanationPayload** record: Full explanation including reason, via, human-readable summary, evidence list, provenance reference, and tags.
|
||||||
- **EdgeProvenanceRef** record: Source system, collection timestamp, SBOM digest, scan digest, attestation ID, event offset.
|
- **EdgeProvenanceRef** record: Source system, collection timestamp, SBOM digest, scan digest, attestation ID, event offset.
|
||||||
- **EdgeTileWithMetadata** record: Extends `EdgeTile` with `Explanation` property containing the full metadata.
|
- **EdgeTileWithMetadata** record: Extends `EdgeTile` with `Explanation` property containing the full metadata.
|
||||||
@@ -72,34 +72,34 @@ The edge metadata system provides explainability for graph relationships:
|
|||||||
- This rollout localizes selected error paths (for example, edge/export not found, invalid reason, and tenant/auth validation text) for `en-US` and `de-DE`.
|
- This rollout localizes selected error paths (for example, edge/export not found, invalid reason, and tenant/auth validation text) for `en-US` and `de-DE`.
|
||||||
|
|
||||||
## 4) Storage considerations
|
## 4) Storage considerations
|
||||||
|
|
||||||
- Backed by either:
|
- Backed by either:
|
||||||
- **Relational + adjacency** (PostgreSQL tables `graph_nodes`, `graph_edges`, `graph_overlays`) with deterministic ordering and streaming exports.
|
- **Relational + adjacency** (PostgreSQL tables `graph_nodes`, `graph_edges`, `graph_overlays`) with deterministic ordering and streaming exports.
|
||||||
- Or **Graph DB** (e.g., Neo4j/Cosmos Gremlin) behind an abstraction layer; choice depends on deployment footprint.
|
- Or **Graph DB** (e.g., Neo4j/Cosmos Gremlin) behind an abstraction layer; choice depends on deployment footprint.
|
||||||
- All storages require tenant partitioning, append-only change logs, and export manifests for Offline Kits.
|
- All storages require tenant partitioning, append-only change logs, and export manifests for Offline Kits.
|
||||||
|
|
||||||
## 5) Offline & export
|
## 5) Offline & export
|
||||||
|
|
||||||
- Each snapshot packages `nodes.jsonl`, `edges.jsonl`, `overlays/` plus manifest with hash, counts, and provenance. Export Center consumes these artefacts for graph-specific bundles.
|
- Each snapshot packages `nodes.jsonl`, `edges.jsonl`, `overlays/` plus manifest with hash, counts, and provenance. Export Center consumes these artefacts for graph-specific bundles.
|
||||||
- Saved queries and overlays include deterministic IDs so Offline Kit consumers can import and replay results.
|
- Saved queries and overlays include deterministic IDs so Offline Kit consumers can import and replay results.
|
||||||
- Runtime hosts register the SBOM ingest pipeline via `services.AddSbomIngestPipeline(...)`. Snapshot exports default to `./artifacts/graph-snapshots` but can be redirected with `STELLAOPS_GRAPH_SNAPSHOT_DIR` or the `SbomIngestOptions.SnapshotRootDirectory` callback.
|
- Runtime hosts register the SBOM ingest pipeline via `services.AddSbomIngestPipeline(...)`. Snapshot exports default to `./artifacts/graph-snapshots` but can be redirected with `STELLAOPS_GRAPH_SNAPSHOT_DIR` or the `SbomIngestOptions.SnapshotRootDirectory` callback.
|
||||||
- Analytics overlays are exported as NDJSON (`overlays/clusters.ndjson`, `overlays/centrality.ndjson`) ordered by node id; `overlays/manifest.json` mirrors snapshot id and counts for offline parity.
|
- Analytics overlays are exported as NDJSON (`overlays/clusters.ndjson`, `overlays/centrality.ndjson`) ordered by node id; `overlays/manifest.json` mirrors snapshot id and counts for offline parity.
|
||||||
|
|
||||||
## 6) Observability
|
## 6) Observability
|
||||||
|
|
||||||
- Metrics: ingestion lag (`graph_ingest_lag_seconds`), node/edge counts, query latency per saved query, overlay generation duration.
|
- Metrics: ingestion lag (`graph_ingest_lag_seconds`), node/edge counts, query latency per saved query, overlay generation duration.
|
||||||
- New analytics metrics: `graph_analytics_runs_total`, `graph_analytics_failures_total`, `graph_analytics_clusters_total`, `graph_analytics_centrality_total`, plus change-stream/backfill counters (`graph_changes_total`, `graph_backfill_total`, `graph_change_failures_total`, `graph_change_lag_seconds`).
|
- New analytics metrics: `graph_analytics_runs_total`, `graph_analytics_failures_total`, `graph_analytics_clusters_total`, `graph_analytics_centrality_total`, plus change-stream/backfill counters (`graph_changes_total`, `graph_backfill_total`, `graph_change_failures_total`, `graph_change_lag_seconds`).
|
||||||
- Logs: structured events for ETL stages and query execution (with trace IDs).
|
- Logs: structured events for ETL stages and query execution (with trace IDs).
|
||||||
- Traces: ETL pipeline spans, query engine spans.
|
- Traces: ETL pipeline spans, query engine spans.
|
||||||
|
|
||||||
## 7) Rollout notes
|
## 7) Rollout notes
|
||||||
|
|
||||||
- Phase 1: ingest SBOM + advisories, deliver impact queries.
|
- Phase 1: ingest SBOM + advisories, deliver impact queries.
|
||||||
- Phase 2: add VEX overlays, policy overlays, diff tooling.
|
- Phase 2: add VEX overlays, policy overlays, diff tooling.
|
||||||
- Phase 3: expose runtime/Zastava edges and AI-assisted recommendations (future).
|
- Phase 3: expose runtime/Zastava edges and AI-assisted recommendations (future).
|
||||||
|
|
||||||
### Local testing note
|
### Local testing note
|
||||||
|
|
||||||
Set `STELLAOPS_TEST_POSTGRES_CONNECTION` to a reachable PostgreSQL instance before running `tests/Graph/StellaOps.Graph.Indexer.Tests`. The test harness falls back to `Host=127.0.0.1;Port=5432;Database=stellaops_test`, then Testcontainers for PostgreSQL, but the CI workflow requires the environment variable to be present to ensure upsert coverage runs against a managed database. Use `STELLAOPS_GRAPH_SNAPSHOT_DIR` (or the `AddSbomIngestPipeline` options callback) to control where graph snapshot artefacts land during local runs.
|
Set `STELLAOPS_TEST_POSTGRES_CONNECTION` to a reachable PostgreSQL instance before running `tests/Graph/StellaOps.Graph.Indexer.Tests`. The test harness falls back to `Host=127.0.0.1;Port=5432;Database=stellaops_test`, then Testcontainers for PostgreSQL, but the CI workflow requires the environment variable to be present to ensure upsert coverage runs against a managed database. Use `STELLAOPS_GRAPH_SNAPSHOT_DIR` (or the `AddSbomIngestPipeline` options callback) to control where graph snapshot artefacts land during local runs.
|
||||||
|
|
||||||
Refer to the module README and implementation plan for immediate context, and update this document once component boundaries and data flows are finalised.
|
Refer to the module README and implementation plan for immediate context, and update this document once component boundaries and data flows are finalised.
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -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