up
Some checks failed
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Mirror Thin Bundle Sign & Verify / mirror-sign (push) Has been cancelled
api-governance / spectral-lint (push) Has been cancelled
Some checks failed
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Mirror Thin Bundle Sign & Verify / mirror-sign (push) Has been cancelled
api-governance / spectral-lint (push) Has been cancelled
This commit is contained in:
26
.gitea/workflows/attestation-bundle.yml
Normal file
26
.gitea/workflows/attestation-bundle.yml
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
name: attestation-bundle
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
attest_dir:
|
||||||
|
description: "Directory containing attestation artefacts"
|
||||||
|
required: true
|
||||||
|
default: "out/attest"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
bundle:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Build bundle
|
||||||
|
run: |
|
||||||
|
chmod +x scripts/attest/build-attestation-bundle.sh
|
||||||
|
scripts/attest/build-attestation-bundle.sh "${{ github.event.inputs.attest_dir }}"
|
||||||
|
|
||||||
|
- name: Upload bundle
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: attestation-bundle
|
||||||
|
path: out/attest-bundles/**
|
||||||
45
.gitea/workflows/cli-build.yml
Normal file
45
.gitea/workflows/cli-build.yml
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
name: cli-build
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
rids:
|
||||||
|
description: "Comma-separated RIDs (e.g., linux-x64,win-x64,osx-arm64)"
|
||||||
|
required: false
|
||||||
|
default: "linux-x64,win-x64,osx-arm64"
|
||||||
|
config:
|
||||||
|
description: "Build configuration"
|
||||||
|
required: false
|
||||||
|
default: "Release"
|
||||||
|
sign:
|
||||||
|
description: "Enable cosign signing (requires COSIGN_KEY)"
|
||||||
|
required: false
|
||||||
|
default: "false"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup .NET
|
||||||
|
uses: actions/setup-dotnet@v4
|
||||||
|
with:
|
||||||
|
dotnet-version: "10.0.100-rc.2.25502.107"
|
||||||
|
|
||||||
|
- name: Install syft (SBOM)
|
||||||
|
uses: anchore/sbom-action/download-syft@v0
|
||||||
|
|
||||||
|
- name: Build CLI artifacts
|
||||||
|
run: |
|
||||||
|
chmod +x scripts/cli/build-cli.sh
|
||||||
|
RIDS="${{ github.event.inputs.rids }}" CONFIG="${{ github.event.inputs.config }}" SBOM_TOOL=syft SIGN="${{ github.event.inputs.sign }}" COSIGN_KEY="${{ secrets.COSIGN_KEY }}" scripts/cli/build-cli.sh
|
||||||
|
|
||||||
|
- name: List artifacts
|
||||||
|
run: find out/cli -maxdepth 3 -type f -print
|
||||||
|
|
||||||
|
- name: Upload CLI artifacts
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: stella-cli
|
||||||
|
path: out/cli/**
|
||||||
86
.gitea/workflows/containers-multiarch.yml
Normal file
86
.gitea/workflows/containers-multiarch.yml
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
name: containers-multiarch
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
image:
|
||||||
|
description: "Image tag (e.g., ghcr.io/stella-ops/example:edge)"
|
||||||
|
required: true
|
||||||
|
context:
|
||||||
|
description: "Build context directory"
|
||||||
|
required: true
|
||||||
|
default: "."
|
||||||
|
platforms:
|
||||||
|
description: "Platforms (comma-separated)"
|
||||||
|
required: false
|
||||||
|
default: "linux/amd64,linux/arm64"
|
||||||
|
push:
|
||||||
|
description: "Push to registry"
|
||||||
|
required: false
|
||||||
|
default: "false"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-multiarch:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v3
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
with:
|
||||||
|
install: true
|
||||||
|
|
||||||
|
- name: Install syft (SBOM)
|
||||||
|
uses: anchore/sbom-action/download-syft@v0
|
||||||
|
|
||||||
|
- name: Login to ghcr (optional)
|
||||||
|
if: ${{ github.event.inputs.push == 'true' && secrets.GHCR_TOKEN != '' }}
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ secrets.GHCR_TOKEN }}
|
||||||
|
|
||||||
|
- name: Run multi-arch build
|
||||||
|
env:
|
||||||
|
COSIGN_EXPERIMENTAL: "1"
|
||||||
|
run: |
|
||||||
|
chmod +x scripts/buildx/build-multiarch.sh
|
||||||
|
extra=""
|
||||||
|
if [[ "${{ github.event.inputs.push }}" == "true" ]]; then extra="--push"; fi
|
||||||
|
scripts/buildx/build-multiarch.sh \
|
||||||
|
"${{ github.event.inputs.image }}" \
|
||||||
|
"${{ github.event.inputs.context }}" \
|
||||||
|
--platform "${{ github.event.inputs.platforms }}" \
|
||||||
|
--sbom syft ${extra}
|
||||||
|
|
||||||
|
- name: Build air-gap bundle
|
||||||
|
run: |
|
||||||
|
chmod +x scripts/buildx/build-airgap-bundle.sh
|
||||||
|
scripts/buildx/build-airgap-bundle.sh "${{ github.event.inputs.image }}"
|
||||||
|
|
||||||
|
- name: Upload artifacts
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: buildx-${{ github.event.inputs.image }}
|
||||||
|
path: out/buildx/**
|
||||||
|
|
||||||
|
- name: Inspect built image archive
|
||||||
|
run: |
|
||||||
|
set -e
|
||||||
|
ls -lh out/buildx/
|
||||||
|
find out/buildx -name "image.oci" -print -exec sh -c 'tar -tf "$1" | head' _ {} \;
|
||||||
|
|
||||||
|
- name: Upload air-gap bundle
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: bundle-${{ github.event.inputs.image }}
|
||||||
|
path: out/bundles/**
|
||||||
|
|
||||||
|
- name: Inspect remote image (if pushed)
|
||||||
|
if: ${{ github.event.inputs.push == 'true' }}
|
||||||
|
run: |
|
||||||
|
docker buildx imagetools inspect "${{ github.event.inputs.image }}"
|
||||||
8
.gitignore
vendored
8
.gitignore
vendored
@@ -31,7 +31,9 @@ seed-data/cert-bund/**/*.sha256
|
|||||||
out/offline-kit/web/**/*
|
out/offline-kit/web/**/*
|
||||||
**/node_modules/**/*
|
**/node_modules/**/*
|
||||||
**/.angular/**/*
|
**/.angular/**/*
|
||||||
**/.cache/**/*
|
**/.cache/**/*
|
||||||
**/dist/**/*
|
**/dist/**/*
|
||||||
tmp/**/*
|
tmp/**/*
|
||||||
build/
|
build/
|
||||||
|
/out/cli/**
|
||||||
|
/src/Sdk/StellaOps.Sdk.Release/out/**
|
||||||
|
|||||||
33
docs/airgap/bootstrap.md
Normal file
33
docs/airgap/bootstrap.md
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# Bootstrap Pack (Airgap 56-004)
|
||||||
|
|
||||||
|
Guidance to build and install the bootstrap pack that primes sealed environments.
|
||||||
|
|
||||||
|
## Contents
|
||||||
|
- Core images/charts for platform services (Authority, Excititor, Concelier, Export Center, Scheduler) with digests.
|
||||||
|
- Offline NuGet/npm caches (if permitted) with checksum manifest.
|
||||||
|
- Configuration defaults: sealed-mode toggles, trust roots, time-anchor bundle, network policy presets.
|
||||||
|
- Verification scripts: hash check, DSSE verification (if available), and connectivity probes to local mirrors.
|
||||||
|
|
||||||
|
## Build steps
|
||||||
|
1. Gather image digests and charts from trusted registry/mirror.
|
||||||
|
2. Create `bootstrap-manifest.json` with:
|
||||||
|
- `bundleId`, `createdAt` (UTC), `producer`, `mirrorGeneration`
|
||||||
|
- `files[]` (path, sha256, size, mediaType)
|
||||||
|
- optional `dsseEnvelopeHash`
|
||||||
|
3. Package into tarball with deterministic ordering (POSIX tar, sorted paths, numeric owner 0:0).
|
||||||
|
4. Compute sha256 for tarball; record in manifest.
|
||||||
|
|
||||||
|
## Install steps
|
||||||
|
1. Transfer pack to sealed site (removable media).
|
||||||
|
2. Verify tarball hash and DSSE (if present) using offline trust roots.
|
||||||
|
3. Load images/charts into local registry; preload caches to `local-nugets/` etc.
|
||||||
|
4. Apply network policies (deny-all) and sealed-mode config.
|
||||||
|
5. Register bootstrap manifest and mirrorGeneration with Excititor/Export Center.
|
||||||
|
|
||||||
|
## Determinism & rollback
|
||||||
|
- Keep manifests in ISO-8601 UTC; no host-specific metadata in tar headers.
|
||||||
|
- For rollback, retain previous bootstrap tarball + manifest; restore registry contents and config snapshots.
|
||||||
|
|
||||||
|
## Related
|
||||||
|
- `docs/airgap/mirror-bundles.md` — mirror pack format and validation.
|
||||||
|
- `docs/airgap/sealing-and-egress.md` — egress enforcement used during install.
|
||||||
6
docs/airgap/console-airgap-tasks.md
Normal file
6
docs/airgap/console-airgap-tasks.md
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
# Console Airgap Implementation Tasks (link to DOCS-AIRGAP-57-002)
|
||||||
|
|
||||||
|
- Implement sealed badge + staleness indicators using `staleness-and-time.md` rules.
|
||||||
|
- Hook import wizard to backend once mirror bundle schema and timeline event API are available.
|
||||||
|
- Ensure admin-only import; read-only view otherwise.
|
||||||
|
- Emit telemetry for imports (success/failure) and denied attempts.
|
||||||
19
docs/airgap/degradation-matrix.md
Normal file
19
docs/airgap/degradation-matrix.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# Airgap Degradation Matrix (DOCS-AIRGAP-58-001)
|
||||||
|
|
||||||
|
What works and what degrades across modes (sealed → constrained → connected).
|
||||||
|
|
||||||
|
| Capability | Connected | Constrained | Sealed | Notes |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| Mirror imports | ✓ | ✓ | ✓ | Sealed requires preloaded media + offline validation. |
|
||||||
|
| Time anchors (external NTP) | ✓ | ✓ (allowlisted) | ✗ | Sealed relies on signed time anchors. |
|
||||||
|
| Transparency log lookups | ✓ | ✓ (if allowlisted) | ✗ | Sealed skips; rely on bundled checkpoints. |
|
||||||
|
| Rekor witness | ✓ | optional | ✗ | Disabled in sealed; log locally. |
|
||||||
|
| SBOM feed refresh | ✓ | limited mirrors | offline only | Use mirror bundles. |
|
||||||
|
| CLI plugin downloads | ✓ | allowlisted | ✗ | Must ship in bootstrap pack. |
|
||||||
|
| Telemetry export | ✓ | optional | optional/log-only | Sealed may use console exporter only. |
|
||||||
|
| Webhook callbacks | ✓ | allowlisted internal only | ✗ | Use internal queue instead. |
|
||||||
|
| OTA updates | ✓ | partial | ✗ | Use mirrorGeneration refresh. |
|
||||||
|
|
||||||
|
## Remediation guidance
|
||||||
|
- If a capability is degraded in sealed mode, provide offline substitute (mirror bundles, time anchors, console exporter).
|
||||||
|
- When moving to constrained/connected, re-enable trust roots and transparency checks gradually; verify hashes first.
|
||||||
23
docs/airgap/devportal-offline.md
Normal file
23
docs/airgap/devportal-offline.md
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# DevPortal Offline (DOCS-AIRGAP-DEVPORT-64-001)
|
||||||
|
|
||||||
|
How to use the developer portal in fully offline/sealed environments.
|
||||||
|
|
||||||
|
## Serving the portal
|
||||||
|
- Host static build from local object store or file server; no CDN.
|
||||||
|
- Set `DEVPORTAL_OFFLINE=true` to disable external analytics/fonts.
|
||||||
|
|
||||||
|
## Auth
|
||||||
|
- Use Authority in offline mode with pre-provisioned tenants; cache JWKS locally.
|
||||||
|
|
||||||
|
## Bundles
|
||||||
|
- Provide mirror/bootstrap bundles via offline download page with hashes and DSSE (if available).
|
||||||
|
- Offer time anchors download; display staleness and mirrorGeneration in UI header.
|
||||||
|
|
||||||
|
## Search/docs
|
||||||
|
- Bundle docs and search index; disable remote doc fetch.
|
||||||
|
|
||||||
|
## Telemetry
|
||||||
|
- Disable remote telemetry; keep console logs only or send to local OTLP endpoint.
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
- On load, run self-check to confirm no external requests; fail with clear banner if any detected.
|
||||||
28
docs/airgap/mirror-bundles.md
Normal file
28
docs/airgap/mirror-bundles.md
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
# Mirror Bundles (Airgap 56-003)
|
||||||
|
|
||||||
|
Defines the mirror bundle format and validation workflow for sealed deployments.
|
||||||
|
|
||||||
|
## Contents
|
||||||
|
- Images/charts: OCI artifacts exported with digests + SBOMs.
|
||||||
|
- Manifests: `manifest.json` with entries:
|
||||||
|
- `bundleId`, `mirrorGeneration`, `createdAt`, `producer` (export center), `hashes` (sha256 list)
|
||||||
|
- `dsseEnvelopeHash` for signed manifest (if available)
|
||||||
|
- `files[]`: path, sha256, size, mediaType
|
||||||
|
- Transparency: optional TUF metadata (`timestamp.json`, `snapshot.json`) for replay protection.
|
||||||
|
|
||||||
|
## Validation steps
|
||||||
|
1. Verify `manifest.json` sha256 matches provided hash.
|
||||||
|
2. If DSSE present, verify signature against offline trust roots.
|
||||||
|
3. Validate Merkle root (if included) over `files[]` hashes.
|
||||||
|
4. For each OCI artifact, confirm digest matches and SBOM present.
|
||||||
|
5. Record `mirrorGeneration` and manifest hash; store in audit log and timeline event.
|
||||||
|
|
||||||
|
## Workflow
|
||||||
|
- Export Center produces bundle + manifest; Attestor/Excititor importers validate before ingest.
|
||||||
|
- Bundle consumers must refuse imports if any hash/signature fails.
|
||||||
|
- Keep format stable; any schema change bumps `manifestVersion` in `manifest.json`.
|
||||||
|
|
||||||
|
## Determinism
|
||||||
|
- Sort `files[]` by path; compute hashes with UTF-8 canonical paths.
|
||||||
|
- Use ISO-8601 UTC timestamps in manifests.
|
||||||
|
- Do not include host-specific paths or timestamps in tar layers.
|
||||||
34
docs/airgap/operations.md
Normal file
34
docs/airgap/operations.md
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
# Airgap Operations (DOCS-AIRGAP-57-004)
|
||||||
|
|
||||||
|
Runbooks for imports, failure recovery, and auditing in sealed/constrained modes.
|
||||||
|
|
||||||
|
## Imports
|
||||||
|
1) Verify bundle hash/DSSE (see `mirror-bundles.md`).
|
||||||
|
2) `stella airgap import --bundle ... --generation N --dry-run` (optional).
|
||||||
|
3) Apply network policy: ensure sealed/constrained mode set correctly.
|
||||||
|
4) Import with `stella airgap import ...` and watch logs.
|
||||||
|
5) Confirm timeline event emitted (bundleId, mirrorGeneration, actor).
|
||||||
|
|
||||||
|
## Failure recovery
|
||||||
|
- Hash/signature mismatch: reject bundle; re-request export; log incident.
|
||||||
|
- Partial import: rerun with `--force` after cleaning registry/cache; keep previous generation for rollback.
|
||||||
|
- Staleness breach: if imports unavailable, raise amber alert; if >72h, go red and halt new ingest until refreshed.
|
||||||
|
- Time anchor expired: apply new anchor from trusted media before continuing operations.
|
||||||
|
|
||||||
|
## Auditing
|
||||||
|
- Record every import in audit log: `{tenant, mirrorGeneration, manifestHash, actor, sealed}`.
|
||||||
|
- Preserve manifests and hashes for at least two generations.
|
||||||
|
- Periodically (daily) run `stella airgap list --format json` and archive output.
|
||||||
|
- Ensure logs are immutable (append-only) in sealed environments.
|
||||||
|
|
||||||
|
## Observability
|
||||||
|
- Monitor counters for denied egress, import success/failure, and staleness alerts.
|
||||||
|
- Expose `/obs/airgap/status` (if available) to scrape bundle freshness.
|
||||||
|
|
||||||
|
## Checklist (per import)
|
||||||
|
- [ ] Hash/DSSE verified
|
||||||
|
- [ ] Sealed/constrained mode configured
|
||||||
|
- [ ] Registry/cache reachable
|
||||||
|
- [ ] Import succeeded
|
||||||
|
- [ ] Timeline/audit recorded
|
||||||
|
- [ ] Staleness dashboard updated
|
||||||
32
docs/airgap/overview.md
Normal file
32
docs/airgap/overview.md
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
# Airgap Overview
|
||||||
|
|
||||||
|
This page orients teams before diving into per-component runbooks. It summarises modes, lifecycle, and governance responsibilities for sealed deployments.
|
||||||
|
|
||||||
|
## Modes
|
||||||
|
- **Sealed**: deny-all egress; only preloaded bundles (mirror + bootstrap) allowed. Requires exported time anchors and offline trust roots.
|
||||||
|
- **Constrained**: limited egress to allowlisted registries and NTP; mirror bundles still preferred.
|
||||||
|
- **Connected**: full egress for staging; must remain policy-compatible with sealed mode.
|
||||||
|
|
||||||
|
## Lifecycle
|
||||||
|
1. **Prepare bundles**: export mirror + bootstrap packs (images/charts, SBOMs, DSSE metadata) signed and hashed.
|
||||||
|
2. **Stage & verify**: load bundles into the offline store, verify hashes/DSSE, record mirrorGeneration.
|
||||||
|
3. **Activate**: flip sealed toggle; enforce deny-all egress and policy banners; register bundles with Excititor/Export Center.
|
||||||
|
4. **Operate**: run periodic staleness checks, apply time anchors, and audit imports via timeline events.
|
||||||
|
5. **Refresh/rollback**: import next mirrorGeneration or roll back using previous manifest + hashes.
|
||||||
|
|
||||||
|
## Responsibilities
|
||||||
|
- **AirGap Controller Guild**: owns network posture (deny-all, allowlists), sealed-mode policy banners, and change control.
|
||||||
|
- **Export Center / Evidence Locker Guilds**: produce and verify bundle manifests, DSSE envelopes, and Merkle roots.
|
||||||
|
- **Module owners** (Excititor, Concelier, etc.): honor sealed-mode toggles, emit staleness headers, and refuse unsigned/unknown bundles.
|
||||||
|
- **Ops/Signals Guild**: maintain time anchors and observability sinks compatible with sealed deployments.
|
||||||
|
|
||||||
|
## Rule banner (sealed mode)
|
||||||
|
Display a top-of-console banner when `sealed=true`:
|
||||||
|
- "Sealed mode: no external egress. Only registered bundles permitted. Imports logged; violations trigger audit."
|
||||||
|
- Include current `mirrorGeneration`, bundle manifest hash, and time-anchor status.
|
||||||
|
|
||||||
|
## Related docs
|
||||||
|
- `docs/airgap/airgap-mode.md` — deeper policy shapes per mode.
|
||||||
|
- `docs/airgap/bundle-repositories.md` — mirror/bootstrap bundle structure.
|
||||||
|
- `docs/airgap/staleness-and-time.md` — time anchors and staleness checks.
|
||||||
|
- `docs/airgap/controller-scaffold.md` / `importer-scaffold.md` — implementation scaffolds.
|
||||||
@@ -1,90 +1,27 @@
|
|||||||
# Portable Evidence Bundles (Sealed/Air-Gapped)
|
# Portable Evidence Bundles (DOCS-AIRGAP-58-004)
|
||||||
|
|
||||||
> Sprint 160 · Task EVID-OBS-60-001
|
Guidance for exporting/importing portable evidence bundles across enclaves.
|
||||||
> Audience: Evidence Locker operators, Air-Gap controllers, incident responders
|
|
||||||
|
|
||||||
Portable bundles let operators hand off sealed evidence across enclaves without exposing tenant identifiers or internal storage coordinates. The Evidence Locker produces a deterministic archive (`portable-bundle-v1.tgz`) that carries the manifest + signature alongside redacted metadata, checksum manifest, and an offline verification script.
|
## Bundle contents
|
||||||
|
- Evidence payloads (VEX observations/linksets) as NDJSON.
|
||||||
|
- Timeline events and attestation DSSE envelopes.
|
||||||
|
- Manifest with `bundleId`, `source`, `tenant`, `createdAt`, `files[]`, `dsseEnvelopeHash` (optional).
|
||||||
|
|
||||||
## 1. When to use the portable flow
|
## Export
|
||||||
|
- Produce from Evidence Locker/Excititor with deterministic ordering and SHA-256 hashes.
|
||||||
|
- Include Merkle root over evidence files; store in manifest.
|
||||||
|
- Sign manifest (DSSE) when trust roots available.
|
||||||
|
|
||||||
- **Sealed mode exports.** Regulatory or incident response teams that cannot access the primary enclave directly.
|
## Import
|
||||||
- **Chain-of-custody transfers.** Moving evidence into offline review systems while keeping the DSSE provenance intact.
|
- Verify manifest hash, Merkle root, and DSSE signature offline.
|
||||||
- **Break-glass rehearsals.** Validating incident response playbooks without exposing internal bundle metadata.
|
- Enforce tenant scoping; refuse cross-tenant bundles.
|
||||||
|
- Emit timeline event upon successful import.
|
||||||
|
|
||||||
Avoid portable bundles for regular intra-enclave automation; the full `bundle.tgz` already carries richer metadata for automated tooling.
|
## Constraints
|
||||||
|
- No external lookups; verification uses bundled roots.
|
||||||
|
- Max size per bundle configurable; default 500 MB.
|
||||||
|
- Keep file paths UTF-8 and slash-separated; avoid host-specific metadata.
|
||||||
|
|
||||||
## 2. Generating the bundle
|
## Determinism
|
||||||
|
- Sort files lexicographically; use ISO-8601 UTC timestamps.
|
||||||
1. Seal the evidence bundle as usual (`POST /evidence/snapshot` or via CLI).
|
- Avoid re-compressing files; if tar is used, set deterministic headers (uid/gid=0, mtime=0).
|
||||||
2. Request the portable artefact using the new endpoint:
|
|
||||||
|
|
||||||
```
|
|
||||||
GET /evidence/{bundleId}/portable
|
|
||||||
Scope: evidence:read
|
|
||||||
```
|
|
||||||
|
|
||||||
Response headers mirror the standard download (`application/gzip`, `Content-Disposition: attachment; filename="portable-evidence-bundle-{bundleId}.tgz"`).
|
|
||||||
|
|
||||||
The Evidence Locker caches the portable archive using write-once semantics. Subsequent requests reuse the existing object and the audit log records whether the file was newly created or served from cache.
|
|
||||||
|
|
||||||
## 3. Archive layout
|
|
||||||
|
|
||||||
```
|
|
||||||
portable-bundle-v1.tgz
|
|
||||||
├── manifest.json # Canonical bundle manifest (identical to sealed bundle)
|
|
||||||
├── signature.json # DSSE signature + optional RFC3161 timestamp (base64 token)
|
|
||||||
├── bundle.json # Redacted metadata (bundleId, kind, rootHash, timestamps, incidentMetadata)
|
|
||||||
├── checksums.txt # Merkle root + per-entry SHA-256 digests
|
|
||||||
├── instructions-portable.txt # Human-readable guidance for sealed transfers
|
|
||||||
└── verify-offline.sh # POSIX shell helper (extract + checksum verify + reminder to run DSSE verification)
|
|
||||||
```
|
|
||||||
|
|
||||||
Redaction rules:
|
|
||||||
|
|
||||||
- No tenant identifiers, storage keys, descriptions, or free-form metadata.
|
|
||||||
- Incident metadata is retained *only* under the `incidentMetadata` object (`incident.mode`, `incident.changedAt`, etc.).
|
|
||||||
- `portableGeneratedAt` records when the archive was produced so downstream systems can reason about freshness.
|
|
||||||
|
|
||||||
## 4. Offline verification workflow
|
|
||||||
|
|
||||||
1. Copy `portable-bundle-v1.tgz` into the sealed environment (USB, sneaker-net, etc.).
|
|
||||||
2. Run the included helper from a POSIX shell:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
chmod +x verify-offline.sh
|
|
||||||
./verify-offline.sh portable-bundle-v1.tgz
|
|
||||||
```
|
|
||||||
|
|
||||||
The script:
|
|
||||||
- extracts the archive into a temporary directory,
|
|
||||||
- validates `checksums.txt` using `sha256sum` (or `shasum -a 256`), and
|
|
||||||
- prints the Merkle root hash from `bundle.json`.
|
|
||||||
|
|
||||||
3. Complete provenance verification:
|
|
||||||
- Preferred: `stella evidence verify --bundle portable-bundle-v1.tgz`
|
|
||||||
- Alternative: supply `manifest.json` and `signature.json` to the evidence verifier library.
|
|
||||||
|
|
||||||
4. Record the verification output (root hash, timestamp) with the receiving enclave’s evidence locker or incident ticket.
|
|
||||||
|
|
||||||
> **Note:** The DSSE payload is unchanged from the sealed bundle, so existing verification tooling does not need special handling for portable archives.
|
|
||||||
|
|
||||||
## 5. Importing into the receiving enclave
|
|
||||||
|
|
||||||
1. Upload the archive to the target Evidence Locker or attach it to the incident record.
|
|
||||||
2. Store the checksum report generated by `verify-offline.sh` alongside the archive.
|
|
||||||
3. If downstream automation needs enriched metadata, attach a private note referencing the original bundle’s tenant context—the portable archive intentionally omits it.
|
|
||||||
|
|
||||||
## 6. Troubleshooting
|
|
||||||
|
|
||||||
| Symptom | Likely cause | Remediation |
|
|
||||||
|--------|--------------|-------------|
|
|
||||||
| `verify-offline.sh` reports checksum failures | Transfer corruption | Re-transfer artefact; run `sha256sum portable-bundle-v1.tgz` on both sides and compare. |
|
|
||||||
| `stella evidence verify` cannot reach TSA | Sealed environment lacks TSA connectivity | Verification still succeeds using DSSE signature; capture the missing TSA warning in the import log. |
|
|
||||||
| `/portable` endpoint returns 400 | Bundle not yet sealed or signature missing | Wait for sealing to complete; ensure DSSE signing is enabled. |
|
|
||||||
| `/portable` returns 404 | Bundle not found or tenant mismatch | Confirm DPoP scope and tenant claim; refresh bundle status via `GET /evidence/{id}`. |
|
|
||||||
|
|
||||||
## 7. Change management
|
|
||||||
|
|
||||||
- Portable bundle versioning is encoded in the filename (`portable-bundle-v1.tgz`). When content or script behaviour changes, bump the version and announce in release notes.
|
|
||||||
- Any updates to `verify-offline.sh` must remain POSIX-sh compatible and avoid external dependencies beyond `tar`, `sha256sum`/`shasum`, and standard coreutils.
|
|
||||||
- Remember to update this guide and the bundle packaging dossier (`docs/modules/evidence-locker/bundle-packaging.md`) when fields or workflows change.
|
|
||||||
|
|||||||
30
docs/airgap/sealing-and-egress.md
Normal file
30
docs/airgap/sealing-and-egress.md
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
# Sealing and Egress (Airgap 56-002)
|
||||||
|
|
||||||
|
Guidance for enforcing deny-all egress and validating sealed-mode posture.
|
||||||
|
|
||||||
|
## Network policies
|
||||||
|
- Kubernetes: apply namespace-scoped `NetworkPolicy` with default deny; allow only:
|
||||||
|
- DNS to internal resolver
|
||||||
|
- Object storage/mirror endpoints on allowlist
|
||||||
|
- OTLP/observability endpoints if permitted for sealed monitoring
|
||||||
|
- Docker Compose: use firewall rules or `extra_hosts` to block outbound except mirrors; ship `iptables` template in ops bundle.
|
||||||
|
|
||||||
|
## EgressPolicy facade
|
||||||
|
- Services MUST read `Excititor:Network:EgressPolicy` (or module equivalent) to decide runtime behavior:
|
||||||
|
- `sealed` → deny outbound HTTP/S except allowlist; fail fast on unexpected hosts.
|
||||||
|
- `constrained` → allow allowlist + time/NTP if required.
|
||||||
|
- Log policy decisions and surface `X-Sealed-Mode: true|false` on HTTP responses for diagnostics.
|
||||||
|
|
||||||
|
## Verification checklist
|
||||||
|
1. Confirm policy manifests applied (kubectl/compose diff) and pods restarted.
|
||||||
|
2. Run connectivity probe from each pod:
|
||||||
|
- Allowed endpoints respond (200/OK or 403 expected).
|
||||||
|
- Disallowed domains return immediate failure.
|
||||||
|
3. Attempt bundle import; verify timeline event emitted with `sealed=true`.
|
||||||
|
4. Check observability: counters for denied egress should increment (export or console log).
|
||||||
|
5. Record mirrorGeneration + manifest hash in audit log.
|
||||||
|
|
||||||
|
## Determinism & offline posture
|
||||||
|
- No external CRLs/OCSP in sealed mode; rely on bundled trust roots.
|
||||||
|
- Keep allowlist minimal and declared in config; no implicit fallbacks.
|
||||||
|
- All timestamps UTC; avoid calling external time APIs.
|
||||||
@@ -241,6 +241,7 @@ components:
|
|||||||
properties:
|
properties:
|
||||||
aliases: { type: array, items: { type: string } }
|
aliases: { type: array, items: { type: string } }
|
||||||
purl: { type: array, items: { type: string } }
|
purl: { type: array, items: { type: string } }
|
||||||
|
cpe: { type: array, items: { type: string } }
|
||||||
versions: { type: array, items: { type: string } }
|
versions: { type: array, items: { type: string } }
|
||||||
ranges: { type: array, items: { type: object } }
|
ranges: { type: array, items: { type: object } }
|
||||||
severities: { type: array, items: { type: object } }
|
severities: { type: array, items: { type: object } }
|
||||||
|
|||||||
@@ -317,6 +317,75 @@ paths:
|
|||||||
default:
|
default:
|
||||||
$ref: '#/components/responses/Error'
|
$ref: '#/components/responses/Error'
|
||||||
|
|
||||||
|
/api/v1/notify/pack-approvals:
|
||||||
|
post:
|
||||||
|
summary: Ingest pack approval decision
|
||||||
|
tags: [PackApprovals]
|
||||||
|
operationId: ingestPackApproval
|
||||||
|
security:
|
||||||
|
- oauth2: [notify.operator]
|
||||||
|
- hmac: []
|
||||||
|
parameters:
|
||||||
|
- $ref: '#/components/parameters/Tenant'
|
||||||
|
- $ref: '#/components/parameters/IdempotencyKey'
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema: { $ref: '#/components/schemas/PackApprovalEvent' }
|
||||||
|
examples:
|
||||||
|
approval-granted:
|
||||||
|
value:
|
||||||
|
eventId: "20e4e5fe-3d4a-4f57-9f9b-b1a1c1111111"
|
||||||
|
issuedAt: "2025-11-17T16:00:00Z"
|
||||||
|
kind: "pack.approval.granted"
|
||||||
|
packId: "offline-kit-2025-11"
|
||||||
|
policy:
|
||||||
|
id: "policy-123"
|
||||||
|
version: "v5"
|
||||||
|
decision: "approved"
|
||||||
|
actor: "task-runner"
|
||||||
|
resumeToken: "rt-abc123"
|
||||||
|
summary: "All required attestations verified."
|
||||||
|
labels:
|
||||||
|
environment: "prod"
|
||||||
|
approver: "ops"
|
||||||
|
responses:
|
||||||
|
'202':
|
||||||
|
description: Accepted; durable write queued for processing.
|
||||||
|
headers:
|
||||||
|
X-Resume-After:
|
||||||
|
description: Resume token echo or replacement
|
||||||
|
schema: { type: string }
|
||||||
|
default:
|
||||||
|
$ref: '#/components/responses/Error'
|
||||||
|
|
||||||
|
/api/v1/notify/pack-approvals/{packId}/ack:
|
||||||
|
post:
|
||||||
|
summary: Acknowledge a pack approval notification
|
||||||
|
tags: [PackApprovals]
|
||||||
|
operationId: ackPackApproval
|
||||||
|
parameters:
|
||||||
|
- $ref: '#/components/parameters/Tenant'
|
||||||
|
- name: packId
|
||||||
|
in: path
|
||||||
|
required: true
|
||||||
|
schema: { type: string }
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
ackToken: { type: string }
|
||||||
|
required: [ackToken]
|
||||||
|
responses:
|
||||||
|
'204':
|
||||||
|
description: Acknowledged
|
||||||
|
default:
|
||||||
|
$ref: '#/components/responses/Error'
|
||||||
|
|
||||||
components:
|
components:
|
||||||
securitySchemes:
|
securitySchemes:
|
||||||
oauth2:
|
oauth2:
|
||||||
@@ -328,6 +397,10 @@ components:
|
|||||||
notify.viewer: Read-only Notifier access
|
notify.viewer: Read-only Notifier access
|
||||||
notify.operator: Manage rules/templates/incidents within tenant
|
notify.operator: Manage rules/templates/incidents within tenant
|
||||||
notify.admin: Tenant-scoped administration
|
notify.admin: Tenant-scoped administration
|
||||||
|
hmac:
|
||||||
|
type: http
|
||||||
|
scheme: bearer
|
||||||
|
description: Pre-shared HMAC token (air-gap friendly) referenced by secretRef.
|
||||||
parameters:
|
parameters:
|
||||||
Tenant:
|
Tenant:
|
||||||
name: X-StellaOps-Tenant
|
name: X-StellaOps-Tenant
|
||||||
@@ -335,6 +408,12 @@ components:
|
|||||||
required: true
|
required: true
|
||||||
description: Tenant slug
|
description: Tenant slug
|
||||||
schema: { type: string }
|
schema: { type: string }
|
||||||
|
IdempotencyKey:
|
||||||
|
name: Idempotency-Key
|
||||||
|
in: header
|
||||||
|
required: true
|
||||||
|
description: Stable UUID to dedupe retries.
|
||||||
|
schema: { type: string, format: uuid }
|
||||||
PageSize:
|
PageSize:
|
||||||
name: pageSize
|
name: pageSize
|
||||||
in: query
|
in: query
|
||||||
@@ -468,6 +547,39 @@ components:
|
|||||||
type: object
|
type: object
|
||||||
additionalProperties: { type: string }
|
additionalProperties: { type: string }
|
||||||
|
|
||||||
|
PackApprovalEvent:
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- eventId
|
||||||
|
- issuedAt
|
||||||
|
- kind
|
||||||
|
- packId
|
||||||
|
- decision
|
||||||
|
- actor
|
||||||
|
properties:
|
||||||
|
eventId: { type: string, format: uuid }
|
||||||
|
issuedAt: { type: string, format: date-time }
|
||||||
|
kind:
|
||||||
|
type: string
|
||||||
|
enum: [pack.approval.granted, pack.approval.denied, pack.policy.override]
|
||||||
|
packId: { type: string }
|
||||||
|
policy:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
id: { type: string }
|
||||||
|
version: { type: string }
|
||||||
|
decision:
|
||||||
|
type: string
|
||||||
|
enum: [approved, denied, overridden]
|
||||||
|
actor: { type: string }
|
||||||
|
resumeToken:
|
||||||
|
type: string
|
||||||
|
description: Opaque token for at-least-once resume.
|
||||||
|
summary: { type: string }
|
||||||
|
labels:
|
||||||
|
type: object
|
||||||
|
additionalProperties: { type: string }
|
||||||
|
|
||||||
QuietHours:
|
QuietHours:
|
||||||
type: object
|
type: object
|
||||||
required: [quietHoursId, windows]
|
required: [quietHoursId, windows]
|
||||||
|
|||||||
40
docs/cli/sbomer.md
Normal file
40
docs/cli/sbomer.md
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
# stella sbomer (DOCS-CLI-DET-01)
|
||||||
|
|
||||||
|
Offline-first usage of `stella sbomer` verbs with deterministic outputs.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
- Install CLI from offline bundle; ensure `local-nugets/` is available.
|
||||||
|
- Export images/charts locally; no network access required during commands.
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
- `stella sbomer layer <image>`
|
||||||
|
- Emits deterministic SBOM per layer; options: `--format cyclonedx|spdx`, `--output <path>`, `--deterministic` (default true).
|
||||||
|
- `stella sbomer compose <manifest>`
|
||||||
|
- Merges layer SBOMs with stable ordering; rejects missing hashes.
|
||||||
|
- `stella sbomer drift <baseline> <current>`
|
||||||
|
- Computes drift; returns machine-readable diff with stable ordering.
|
||||||
|
- `stella sbomer verify <sbom> --hash <sha256>`
|
||||||
|
- Validates hash/signature if provided; offline only.
|
||||||
|
|
||||||
|
## Determinism rules
|
||||||
|
- Use fixed sort keys (component name, version, purl) when composing.
|
||||||
|
- All timestamps forced to `1970-01-01T00:00:00Z` unless `--timestamp` supplied.
|
||||||
|
- GUID/UUID generation disabled; use content hashes as IDs.
|
||||||
|
- Outputs written in UTF-8 with LF line endings; no BOM.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
```bash
|
||||||
|
# generate layer SBOM
|
||||||
|
stella sbomer layer ghcr.io/acme/app:1.2.3 --format cyclonedx --output app.cdx.json
|
||||||
|
|
||||||
|
# compose
|
||||||
|
stella sbomer compose app.cdx.json lib.cdx.json --output combined.cdx.json
|
||||||
|
|
||||||
|
# drift
|
||||||
|
stella sbomer drift baseline.cdx.json combined.cdx.json --output drift.json
|
||||||
|
```
|
||||||
|
|
||||||
|
## Offline tips
|
||||||
|
- Preload registries; set `STELLA_SBOMER_OFFLINE=true` to prevent remote pulls.
|
||||||
|
- Configure cache dir via `STELLA_CACHE_DIR` for reproducible paths.
|
||||||
|
- For air-gapped logs, use `--log-format json` and capture to file for later analysis.
|
||||||
27
docs/console/airgap.md
Normal file
27
docs/console/airgap.md
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
# Console Airgap UI (Airgap 57-002)
|
||||||
|
|
||||||
|
Describes console surfaces for sealed-mode imports, staleness, and user guidance.
|
||||||
|
|
||||||
|
## Surfaces
|
||||||
|
- **Airgap status badge**: shows `sealed` state, `mirrorGeneration`, last import time, and staleness indicator.
|
||||||
|
- **Import wizard**: stepper to upload/verify mirror bundle, show manifest hash, and emit timeline event upon success.
|
||||||
|
- **Staleness dashboard**: charts staleness by bundle/component; highlights tenants nearing expiry.
|
||||||
|
|
||||||
|
## Staleness logic
|
||||||
|
- Use time anchors from `docs/airgap/staleness-and-time.md`.
|
||||||
|
- Staleness = now - `bundle.createdAt`; color bands: green (<24h), amber (24–72h), red (>72h) or missing anchor.
|
||||||
|
|
||||||
|
## Guidance banners
|
||||||
|
- When sealed: banner text "Sealed mode: egress denied. Only registered bundles allowed." Include current `mirrorGeneration` and bundle hash.
|
||||||
|
- On staleness red: prompt operators to import next bundle or reapply time anchor.
|
||||||
|
|
||||||
|
## Events
|
||||||
|
- Successful import emits timeline event with bundleId, mirrorGeneration, manifest hash, actor.
|
||||||
|
- Failed import emits event with error code; do not expose stack traces in UI.
|
||||||
|
|
||||||
|
## Security/guardrails
|
||||||
|
- Require admin scope to import bundles; read-only users can view status only.
|
||||||
|
- Never display raw hashes without tenant context; prefix with tenant and generation.
|
||||||
|
|
||||||
|
## TODOs
|
||||||
|
- Wire to backend once mirror bundle schema and timeline events are exposed (blocked until backend readiness).
|
||||||
8
docs/console/attestor-ui.md
Normal file
8
docs/console/attestor-ui.md
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# Attestor UI (DOCS-ATTEST-74-003)
|
||||||
|
|
||||||
|
Describe console workflows for viewing and verifying attestations.
|
||||||
|
|
||||||
|
- Pages: attestation list, attestation detail, verification status panel.
|
||||||
|
- Filters: tenant, issuer, predicate, verification status.
|
||||||
|
- Actions: download DSSE, view transparency info, export verification record.
|
||||||
|
- UI must not derive verdicts; display raw verification state only.
|
||||||
23
docs/dev/airgap-contracts.md
Normal file
23
docs/dev/airgap-contracts.md
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# Airgap Contracts (DOCS-AIRGAP-58-003)
|
||||||
|
|
||||||
|
Contracts developers must follow for sealed/constrained deployments.
|
||||||
|
|
||||||
|
## EgressPolicy usage
|
||||||
|
- Services read `EgressPolicy` config and must fail fast on disallowed hosts.
|
||||||
|
- All HTTP clients must pass through allowlist resolver; no raw `HttpClient` with arbitrary URLs.
|
||||||
|
|
||||||
|
## Sealed-mode tests
|
||||||
|
- Add integration tests that set `sealed=true` and assert outbound calls are blocked/mocked.
|
||||||
|
- Validate mirror bundle imports succeed under deny-all network by using local fixtures.
|
||||||
|
|
||||||
|
## Linting
|
||||||
|
- Static check to ban `DateTime.Now`, `Guid.NewGuid`, and direct `HttpClient` when `sealed=true` flag is present.
|
||||||
|
- CI rule: fail if new external domains appear outside allowlist file.
|
||||||
|
|
||||||
|
## Logging
|
||||||
|
- Log `sealed` flag, `mirrorGeneration`, and bundle hash on relevant API calls.
|
||||||
|
- Avoid emitting secrets or trust roots in logs.
|
||||||
|
|
||||||
|
## Config determinism
|
||||||
|
- All configs should be overridable via env vars; default to sealed-compatible settings.
|
||||||
|
- Use stable ordering in generated manifests and responses.
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
|
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
|
||||||
| --- | --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- | --- |
|
||||||
| 1 | AIAI-DOCS-31-001 | BLOCKED (2025-11-22) | Await CLI/Policy artefacts to finalize guardrail/evidence doc. Draft skeleton allowed (non-blocking for dev). | Advisory AI Docs Guild | Author guardrail + evidence docs with upstream references. |
|
| 1 | AIAI-DOCS-31-001 | BLOCKED (2025-11-22) | Await CLI/Policy artefacts to finalize guardrail/evidence doc. Draft skeleton allowed (non-blocking for dev). | Advisory AI Docs Guild | Author guardrail + evidence docs with upstream references. |
|
||||||
| 2 | AIAI-PACKAGING-31-002 | BLOCKED (DevOps release-only) | SBOM feeds + CLI/Policy digests not delivered; sealing/publishing deferred to DevOps once feeds arrive. Dev can proceed with dry-run bundle layout. | Advisory AI Release | Package advisory feeds with SBOM pointers + provenance. |
|
| 2 | AIAI-PACKAGING-31-002 | MOVED to SPRINT_503_ops_devops_i (2025-11-23) | Track under DEVOPS-AIAI-31-002 in Ops sprint; waiting for CLI/Policy digests + SBOM feeds there. | Advisory AI Release | Package advisory feeds with SBOM pointers + provenance. |
|
||||||
| 3 | AIAI-RAG-31-003 | DONE | LNM v1 frozen; RAG payload docs aligned. | Advisory AI + Concelier | Align RAG evidence payloads with LNM schema. |
|
| 3 | AIAI-RAG-31-003 | DONE | LNM v1 frozen; RAG payload docs aligned. | Advisory AI + Concelier | Align RAG evidence payloads with LNM schema. |
|
||||||
| 4 | SBOM-AIAI-31-003 | BLOCKED (moved from SPRINT_0110 on 2025-11-23) | CLI-VULN-29-001; CLI-VEX-30-001 | SBOM Service Guild · Advisory AI Guild | Advisory AI hand-off kit for `/v1/sbom/context`; smoke test with tenants. |
|
| 4 | SBOM-AIAI-31-003 | BLOCKED (moved from SPRINT_0110 on 2025-11-23) | CLI-VULN-29-001; CLI-VEX-30-001 | SBOM Service Guild · Advisory AI Guild | Advisory AI hand-off kit for `/v1/sbom/context`; smoke test with tenants. |
|
||||||
| 5 | DOCS-AIAI-31-005/006/008/009 | BLOCKED (moved from SPRINT_0110 on 2025-11-23) | CLI-VULN-29-001; CLI-VEX-30-001; POLICY-ENGINE-31-001; DEVOPS-AIAI-31-001 | Docs Guild | CLI/policy/ops docs; proceed once upstream artefacts land. |
|
| 5 | DOCS-AIAI-31-005/006/008/009 | BLOCKED (moved from SPRINT_0110 on 2025-11-23) | CLI-VULN-29-001; CLI-VEX-30-001; POLICY-ENGINE-31-001; DEVOPS-AIAI-31-001 | Docs Guild | CLI/policy/ops docs; proceed once upstream artefacts land. |
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
| Focus | Action | Owner(s) | Due | Status |
|
| Focus | Action | Owner(s) | Due | Status |
|
||||||
| --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- |
|
||||||
| Docs | Draft guardrail evidence doc | Docs Guild | 2025-11-18 | BLOCKED (awaiting CLI/Policy artefacts) |
|
| Docs | Draft guardrail evidence doc | Docs Guild | 2025-11-18 | BLOCKED (awaiting CLI/Policy artefacts) |
|
||||||
| Packaging | Define SBOM/policy bundle for Advisory AI | Release Guild | 2025-11-20 | BLOCKED (release/DevOps only; waiting CLI/Policy artefacts + SBOM feeds) |
|
| Packaging | Define SBOM/policy bundle for Advisory AI | Release Guild | 2025-11-20 | MOVED to SPRINT_503_ops_devops_i (DEVOPS-AIAI-31-002) |
|
||||||
|
|
||||||
## Execution Log
|
## Execution Log
|
||||||
| Date (UTC) | Update | Owner |
|
| Date (UTC) | Update | Owner |
|
||||||
@@ -39,10 +39,11 @@
|
|||||||
| 2025-11-22 | Set AIAI-DOCS-31-001 to BLOCKED and Action Tracker doc item to BLOCKED due to missing CLI/Policy inputs; no content changes. | Implementer |
|
| 2025-11-22 | Set AIAI-DOCS-31-001 to BLOCKED and Action Tracker doc item to BLOCKED due to missing CLI/Policy inputs; no content changes. | Implementer |
|
||||||
| 2025-11-23 | Clarified that packaging block is release/DevOps-only; development can continue drafting bundle layout using LNM facts, but publish remains gated on CLI/Policy/SBOM artefacts. | Project Mgmt |
|
| 2025-11-23 | Clarified that packaging block is release/DevOps-only; development can continue drafting bundle layout using LNM facts, but publish remains gated on CLI/Policy/SBOM artefacts. | Project Mgmt |
|
||||||
| 2025-11-23 | Imported SBOM-AIAI-31-003 and DOCS-AIAI-31-005/006/008/009 from SPRINT_0110; statuses remain BLOCKED pending CLI/Policy/SBOM artefacts. | Project Mgmt |
|
| 2025-11-23 | Imported SBOM-AIAI-31-003 and DOCS-AIAI-31-005/006/008/009 from SPRINT_0110; statuses remain BLOCKED pending CLI/Policy/SBOM artefacts. | Project Mgmt |
|
||||||
|
| 2025-11-23 | Moved ops/release packaging (AIAI-PACKAGING-31-002) to SPRINT_503_ops_devops_i as DEVOPS-AIAI-31-002; retained dev/doc tasks here. | Project Mgmt |
|
||||||
|
|
||||||
## Decisions & Risks
|
## Decisions & Risks
|
||||||
- Advisory AI depends on Link-Not-Merge contract; if delayed, publish partial docs with TBD markers.
|
- Advisory AI depends on Link-Not-Merge contract; if delayed, publish partial docs with TBD markers.
|
||||||
- Packaging blocked on SBOM/policy bundles; keep staging builds ready.
|
- Packaging now tracked under ops sprint (DEVOPS-AIAI-31-002 in SPRINT_503_ops_devops_i); remain blocked on SBOM/policy bundles until CLI/Policy artefacts land.
|
||||||
- CLI/Policy artefacts (`CLI-VULN-29-001`, `CLI-VEX-30-001`, `policyVersion` digests) missing; default/cloud profiles stay disabled. Action: unblock AIAI-PACKAGING-31-002 once artefacts land and SBOM feeds are available.
|
- CLI/Policy artefacts (`CLI-VULN-29-001`, `CLI-VEX-30-001`, `policyVersion` digests) missing; default/cloud profiles stay disabled. Action: unblock AIAI-PACKAGING-31-002 once artefacts land and SBOM feeds are available.
|
||||||
|
|
||||||
## Next Checkpoints
|
## Next Checkpoints
|
||||||
|
|||||||
@@ -38,7 +38,7 @@
|
|||||||
| 11 | CONCELIER-ORCH-32-002 | BLOCKED (2025-11-22) | Blocked on 32-001 build validation; depends on DEVOPS-CONCELIER-CI-24-101 CI runner. | Concelier Core Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Adopt orchestrator worker SDK in ingestion loops; emit heartbeats/progress/artifact hashes for deterministic replays. |
|
| 11 | CONCELIER-ORCH-32-002 | BLOCKED (2025-11-22) | Blocked on 32-001 build validation; depends on DEVOPS-CONCELIER-CI-24-101 CI runner. | Concelier Core Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Adopt orchestrator worker SDK in ingestion loops; emit heartbeats/progress/artifact hashes for deterministic replays. |
|
||||||
| 12 | CONCELIER-ORCH-33-001 | BLOCKED (2025-11-22) | Blocked on 32-001/002 build validation; needs DEVOPS-CONCELIER-CI-24-101 CI runner. | Concelier Core Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Honor orchestrator pause/throttle/retry controls with structured errors and persisted checkpoints. |
|
| 12 | CONCELIER-ORCH-33-001 | BLOCKED (2025-11-22) | Blocked on 32-001/002 build validation; needs DEVOPS-CONCELIER-CI-24-101 CI runner. | Concelier Core Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Honor orchestrator pause/throttle/retry controls with structured errors and persisted checkpoints. |
|
||||||
| 13 | CONCELIER-ORCH-34-001 | BLOCKED (2025-11-22) | Blocked on 32-001/002 build validation; needs DEVOPS-CONCELIER-CI-24-101 CI runner. | Concelier Core Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Execute orchestrator-driven backfills reusing artifact hashes/signatures, logging provenance, and pushing run metadata to ledger. |
|
| 13 | CONCELIER-ORCH-34-001 | BLOCKED (2025-11-22) | Blocked on 32-001/002 build validation; needs DEVOPS-CONCELIER-CI-24-101 CI runner. | Concelier Core Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Execute orchestrator-driven backfills reusing artifact hashes/signatures, logging provenance, and pushing run metadata to ledger. |
|
||||||
| 14 | CONCELIER-POLICY-20-001 | DOING (2025-11-23) | OpenAPI source drafted at `src/Concelier/StellaOps.Concelier.WebService/openapi/concelier-lnm.yaml` (published copy: `docs/api/concelier/concelier-lnm.yaml`); list/search/get endpoints exposed, field coverage still partial (no severity/timeline). | Concelier WebService Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Provide batch advisory lookup APIs for Policy Engine (purl/advisory filters, tenant scopes, explain metadata) so policy joins raw evidence without inferred outcomes. |
|
| 14 | CONCELIER-POLICY-20-001 | BLOCKED (2025-11-24) | API now returns CPEs + minimal severity/timeline, but authoritative severity sources and published/modified timeline fields are missing from upstream linkset data. Blocked pending upstream schema/ingest update to supply severity + published/modified timestamps. | Concelier WebService Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Provide batch advisory lookup APIs for Policy Engine (purl/advisory filters, tenant scopes, explain metadata) so policy joins raw evidence without inferred outcomes. |
|
||||||
|
|
||||||
## Execution Log
|
## Execution Log
|
||||||
| Date (UTC) | Update | Owner |
|
| Date (UTC) | Update | Owner |
|
||||||
@@ -75,6 +75,9 @@
|
|||||||
| 2025-11-22 | Retried `dotnet restore concelier-webservice.slnf -v minimal` with timeout guard; cancelled at ~25s with `NuGet.targets` reporting "Restore canceled!". No packages downloaded; ORCH-32/33/34 remain blocked until CI/warm cache is available. | Concelier Implementer |
|
| 2025-11-22 | Retried `dotnet restore concelier-webservice.slnf -v minimal` with timeout guard; cancelled at ~25s with `NuGet.targets` reporting "Restore canceled!". No packages downloaded; ORCH-32/33/34 remain blocked until CI/warm cache is available. | Concelier Implementer |
|
||||||
| 2025-11-22 | Ran `dotnet restore concelier-webservice.slnf -v diag` (60s timeout); aborted after prolonged spinner, no packages fetched, no new diagnostic log produced. Orchestrator tasks stay blocked pending CI/runner with warm cache. | Concelier Implementer |
|
| 2025-11-22 | Ran `dotnet restore concelier-webservice.slnf -v diag` (60s timeout); aborted after prolonged spinner, no packages fetched, no new diagnostic log produced. Orchestrator tasks stay blocked pending CI/runner with warm cache. | Concelier Implementer |
|
||||||
| 2025-11-23 | Routed ORCH-32/33/34 CI dependency to DEVOPS-CONCELIER-CI-24-101 (SPRINT_503_ops_devops_i); dev sprint waits on ops runner deliverable. | Project Mgmt |
|
| 2025-11-23 | Routed ORCH-32/33/34 CI dependency to DEVOPS-CONCELIER-CI-24-101 (SPRINT_503_ops_devops_i); dev sprint waits on ops runner deliverable. | Project Mgmt |
|
||||||
|
| 2025-11-24 | Added CPE normalization/storage + API projection for `/v1/lnm/linksets*` responses; Mongo schema updated and round-trip test added (`AdvisoryLinksetStoreTests`). POLICY-20-001 remains DOING pending severity/timeline fields. | Concelier Core |
|
||||||
|
| 2025-11-24 | Added severity string extraction and minimal timeline event (created + evidence hash) to `/v1/lnm/linksets*`; OpenAPI updated, normalized shape now carries CPEs. POLICY-20-001 still needs full severity/timeline coverage before closure. | Concelier Core |
|
||||||
|
| 2025-11-24 | Marked CONCELIER-POLICY-20-001 BLOCKED: upstream linkset/ingest lacks authoritative severity data and published/modified timestamps; cannot emit full severity/timeline fields until schema and data are supplied. | Concelier Core |
|
||||||
|
|
||||||
## Decisions & Risks
|
## Decisions & Risks
|
||||||
- Link-Not-Merge and OpenAPI alignment must precede SDK/examples; otherwise downstream clients will drift from canonical facts.
|
- Link-Not-Merge and OpenAPI alignment must precede SDK/examples; otherwise downstream clients will drift from canonical facts.
|
||||||
@@ -86,6 +89,8 @@
|
|||||||
- Orchestrator registry/SDK contract now documented (see prep note above); downstream tasks must keep in sync with orchestrator module changes.
|
- Orchestrator registry/SDK contract now documented (see prep note above); downstream tasks must keep in sync with orchestrator module changes.
|
||||||
- Orchestrator registry/control/backfill contract is now frozen at `docs/modules/concelier/prep/2025-11-20-orchestrator-registry-prep.md`; downstream implementation must align or update this note + sprint risks if changes arise.
|
- Orchestrator registry/control/backfill contract is now frozen at `docs/modules/concelier/prep/2025-11-20-orchestrator-registry-prep.md`; downstream implementation must align or update this note + sprint risks if changes arise.
|
||||||
- Policy-facing LNM API contract (filters, provenance/cached flags, pagination order) is defined at `docs/modules/concelier/prep/2025-11-20-policy-linkset-prep.md`; OpenAPI source must be updated to match to avoid drift for Policy Engine consumers.
|
- Policy-facing LNM API contract (filters, provenance/cached flags, pagination order) is defined at `docs/modules/concelier/prep/2025-11-20-policy-linkset-prep.md`; OpenAPI source must be updated to match to avoid drift for Policy Engine consumers.
|
||||||
|
- CPE normalization now persists in linksets and surfaces on `/v1/lnm/linksets*`; severity/timeline now emit minimal values (created event + first severity entry) but full coverage (published/modified timeline, richer severity) still required before POLICY-20-001 can be closed.
|
||||||
|
- POLICY-20-001 is BLOCKED until upstream linkset ingestion supplies authoritative severity and published/modified timestamps; current API returns placeholders only.
|
||||||
- Concelier module AGENTS charter updated 2025-11-22 to include Sprint 0114 scope and required prep docs; implementers must treat it as read before starting tasks.
|
- Concelier module AGENTS charter updated 2025-11-22 to include Sprint 0114 scope and required prep docs; implementers must treat it as read before starting tasks.
|
||||||
- Orchestrator registry/command/heartbeat storage now exists with TTL-backed command expiry; WebService/worker wiring still pending—ensure API handlers and SDK align with stored shapes before marking ORCH-32/33/34 DONE.
|
- Orchestrator registry/command/heartbeat storage now exists with TTL-backed command expiry; WebService/worker wiring still pending—ensure API handlers and SDK align with stored shapes before marking ORCH-32/33/34 DONE.
|
||||||
- WebService `/internal/orch/*` endpoints now land registry upserts, heartbeats, and commands into Mongo store; worker consumption and orchestrator authentication scopes still to be validated before closing tasks.
|
- WebService `/internal/orch/*` endpoints now land registry upserts, heartbeats, and commands into Mongo store; worker consumption and orchestrator authentication scopes still to be validated before closing tasks.
|
||||||
|
|||||||
@@ -93,6 +93,7 @@
|
|||||||
| 2025-11-23 | Ran `dotnet test -c Release --filter AirgapImportEndpointTests --logger trx`; both air-gap endpoint tests now PASS (TRX at `src/Excititor/__Tests/StellaOps.Excititor.WebService.Tests/TestResults/airgap.trx`). Marked EXCITITOR-AIRGAP-56-001 DONE. | Implementer |
|
| 2025-11-23 | Ran `dotnet test -c Release --filter AirgapImportEndpointTests --logger trx`; both air-gap endpoint tests now PASS (TRX at `src/Excititor/__Tests/StellaOps.Excititor.WebService.Tests/TestResults/airgap.trx`). Marked EXCITITOR-AIRGAP-56-001 DONE. | Implementer |
|
||||||
| 2025-11-23 | Ran Core unit test `VexEvidenceChunkServiceTests` (`dotnet test -c Release --filter FullyQualifiedName~VexEvidenceChunkServiceTests --logger trx`); PASS (TRX at `src/Excititor/__Tests/StellaOps.Excititor.Core.UnitTests/TestResults/chunks.trx`). | Implementer |
|
| 2025-11-23 | Ran Core unit test `VexEvidenceChunkServiceTests` (`dotnet test -c Release --filter FullyQualifiedName~VexEvidenceChunkServiceTests --logger trx`); PASS (TRX at `src/Excititor/__Tests/StellaOps.Excititor.Core.UnitTests/TestResults/chunks.trx`). | Implementer |
|
||||||
| 2025-11-23 | Ran full Core UnitTests (`dotnet test -c Release --results-directory TestResults --logger trx`); 3 tests executed, all PASS (TRX at `src/Excititor/__Tests/StellaOps.Excititor.Core.UnitTests/TestResults/core-all.trx`). | Implementer |
|
| 2025-11-23 | Ran full Core UnitTests (`dotnet test -c Release --results-directory TestResults --logger trx`); 3 tests executed, all PASS (TRX at `src/Excititor/__Tests/StellaOps.Excititor.Core.UnitTests/TestResults/core-all.trx`). | Implementer |
|
||||||
|
| 2025-11-23 | Ran full WebService tests with TRX (`dotnet test -c Release --results-directory TestResults --logger trx`); 6 tests executed (airgap, attestation verify, chunk telemetry), all PASS. Chunk endpoint tests are not defined in the suite; no action required. TRX at `src/Excititor/__Tests/StellaOps.Excititor.WebService.Tests/TestResults/ws-all.trx`. | Implementer |
|
||||||
|
|
||||||
## Decisions & Risks
|
## Decisions & Risks
|
||||||
- **Decisions**
|
- **Decisions**
|
||||||
|
|||||||
@@ -42,8 +42,8 @@
|
|||||||
| 8 | EXCITITOR-CORE-AOC-19-004 | DONE (2025-11-23) | Consensus refresh hosted service disabled when Aggregation-Only flag set; scheduler no-ops under DisableConsensus | Excititor Core Guild | Excise consensus/merge/severity logic. |
|
| 8 | EXCITITOR-CORE-AOC-19-004 | DONE (2025-11-23) | Consensus refresh hosted service disabled when Aggregation-Only flag set; scheduler no-ops under DisableConsensus | Excititor Core Guild | Excise consensus/merge/severity logic. |
|
||||||
| 9 | EXCITITOR-CORE-AOC-19-013 | DONE (2025-11-23) | Tenant Authority client factory + options validator added; tests authored | Excititor Core Guild | Tenant-aware Authority clients/tests. |
|
| 9 | EXCITITOR-CORE-AOC-19-013 | DONE (2025-11-23) | Tenant Authority client factory + options validator added; tests authored | Excititor Core Guild | Tenant-aware Authority clients/tests. |
|
||||||
| 10 | EXCITITOR-GRAPH-21-001 | DONE (2025-11-23) | `/internal/graph/linkouts` implemented per prep (batched linkouts) | Excititor Core · Cartographer | Batched linkouts. |
|
| 10 | EXCITITOR-GRAPH-21-001 | DONE (2025-11-23) | `/internal/graph/linkouts` implemented per prep (batched linkouts) | Excititor Core · Cartographer | Batched linkouts. |
|
||||||
| 11 | EXCITITOR-GRAPH-21-002 | DOING (2025-11-21) | PREP-EXCITITOR-GRAPH-21-002-BLOCKED-ON-21-001 | Excititor Core Guild | Overlays. |
|
| 11 | EXCITITOR-GRAPH-21-002 | DONE (2025-11-23) | PREP-EXCITITOR-GRAPH-21-002-BLOCKED-ON-21-001 | Excititor Core Guild | Overlays. |
|
||||||
| 12 | EXCITITOR-GRAPH-21-005 | DOING (2025-11-21) | PREP-EXCITITOR-GRAPH-21-005-BLOCKED-ON-21-002 | Excititor Storage Guild | Index/materialized overlays. |
|
| 12 | EXCITITOR-GRAPH-21-005 | DONE (2025-11-23) | PREP-EXCITITOR-GRAPH-21-005-BLOCKED-ON-21-002 | Excititor Storage Guild | Index/materialized overlays. |
|
||||||
| 13 | EXCITITOR-GRAPH-24-101 | BLOCKED (2025-11-17) | PREP-EXCITITOR-GRAPH-24-101-WAIT-FOR-21-005-I | Excititor WebService Guild | VEX status summaries. |
|
| 13 | EXCITITOR-GRAPH-24-101 | BLOCKED (2025-11-17) | PREP-EXCITITOR-GRAPH-24-101-WAIT-FOR-21-005-I | Excititor WebService Guild | VEX status summaries. |
|
||||||
| 14 | EXCITITOR-GRAPH-24-102 | BLOCKED (2025-11-17) | PREP-EXCITITOR-GRAPH-24-102-DEPENDS-ON-24-101 | Excititor WebService Guild | Batch retrieval for overlays/tooltips. |
|
| 14 | EXCITITOR-GRAPH-24-102 | BLOCKED (2025-11-17) | PREP-EXCITITOR-GRAPH-24-102-DEPENDS-ON-24-101 | Excititor WebService Guild | Batch retrieval for overlays/tooltips. |
|
||||||
|
|
||||||
@@ -76,6 +76,8 @@
|
|||||||
| 2025-11-21 | Added tenant Authority client factory + config docs; task 19-013 progressing. | Implementer |
|
| 2025-11-21 | Added tenant Authority client factory + config docs; task 19-013 progressing. | Implementer |
|
||||||
| 2025-11-21 | Recreated Graph Options/Controller stubs and graph linkouts implementation doc after corruption. | Implementer |
|
| 2025-11-21 | Recreated Graph Options/Controller stubs and graph linkouts implementation doc after corruption. | Implementer |
|
||||||
| 2025-11-23 | Implemented deterministic VexLinksetExtractionService + unit tests (`dotnet test src/Excititor/__Tests/StellaOps.Excititor.Core.UnitTests/StellaOps.Excititor.Core.UnitTests.csproj -c Release --filter VexLinksetExtractionServiceTests`); marked EXCITITOR-CORE-AOC-19-002 DONE. | Implementer |
|
| 2025-11-23 | Implemented deterministic VexLinksetExtractionService + unit tests (`dotnet test src/Excititor/__Tests/StellaOps.Excititor.Core.UnitTests/StellaOps.Excititor.Core.UnitTests.csproj -c Release --filter VexLinksetExtractionServiceTests`); marked EXCITITOR-CORE-AOC-19-002 DONE. | Implementer |
|
||||||
|
| 2025-11-23 | Implemented graph overlays endpoint `/v1/graph/overlays` with caching + justification toggle; added overlay aggregation tests and linkset overlay cache. Set EXCITITOR-GRAPH-21-002 and EXCITITOR-GRAPH-21-005 to DONE. | Implementer |
|
||||||
|
| 2025-11-23 | Ran `dotnet test ...StellaOps.Excititor.WebService.Tests --filter GraphOverlayFactoryTests` (TRX: `src/Excititor/__Tests/StellaOps.Excititor.WebService.Tests/TestResults/_DESKTOP-7GHGC2M_2025-11-23_23_18_38.trx`); overlay factory unit test PASS. | Implementer |
|
||||||
|
|
||||||
## Decisions & Risks
|
## Decisions & Risks
|
||||||
- Aggregation-only: consensus refresh disabled by default; migration runbook authored.
|
- Aggregation-only: consensus refresh disabled by default; migration runbook authored.
|
||||||
|
|||||||
@@ -27,8 +27,8 @@
|
|||||||
| 3 | EXCITITOR-LNM-21-003 | DONE (2025-11-18) | Event payload contract/factory in core; ready for Platform envelope. | Excititor Core · Platform Events Guild | Emit `vex.linkset.updated` events (observation ids, confidence, conflict summary) aggregation-only. |
|
| 3 | EXCITITOR-LNM-21-003 | DONE (2025-11-18) | Event payload contract/factory in core; ready for Platform envelope. | Excititor Core · Platform Events Guild | Emit `vex.linkset.updated` events (observation ids, confidence, conflict summary) aggregation-only. |
|
||||||
| 4 | EXCITITOR-LNM-21-201 | IN REVIEW (2025-11-18) | Observation/linkset list endpoints coded; pending tests/OpenAPI. | Excititor WebService Guild | `/vex/observations` read endpoints with advisory/product/issuer filters, deterministic pagination, strict RBAC; no derived verdicts. |
|
| 4 | EXCITITOR-LNM-21-201 | IN REVIEW (2025-11-18) | Observation/linkset list endpoints coded; pending tests/OpenAPI. | Excititor WebService Guild | `/vex/observations` read endpoints with advisory/product/issuer filters, deterministic pagination, strict RBAC; no derived verdicts. |
|
||||||
| 5 | EXCITITOR-LNM-21-202 | IN REVIEW (2025-11-18) | List endpoint coded; export shape + docs pending. | Excititor WebService Guild | `/vex/linksets` + export endpoints surfacing alias mappings, conflict markers, provenance proofs; errors map to `ERR_AGG_*`. |
|
| 5 | EXCITITOR-LNM-21-202 | IN REVIEW (2025-11-18) | List endpoint coded; export shape + docs pending. | Excititor WebService Guild | `/vex/linksets` + export endpoints surfacing alias mappings, conflict markers, provenance proofs; errors map to `ERR_AGG_*`. |
|
||||||
| 6 | EXCITITOR-LNM-21-203 | TODO | After 21-202; update SDK/docs. | Excititor WebService Guild · Docs Guild | OpenAPI/SDK/examples for obs/linkset endpoints with Advisory AI/Lens-ready examples. |
|
| 6 | EXCITITOR-LNM-21-203 | DONE (2025-11-23) | After 21-202; update SDK/docs. | Excititor WebService Guild · Docs Guild | OpenAPI/SDK/examples for obs/linkset endpoints with Advisory AI/Lens-ready examples. |
|
||||||
| 7 | EXCITITOR-OBS-51-001 | TODO | Define metric names + SLOs. | Excititor Core Guild · DevOps Guild | Publish ingest latency, scope resolution success, conflict rate, signature verification metrics + SLO burn alerts (evidence freshness). |
|
| 7 | EXCITITOR-OBS-51-001 | DONE (2025-11-23) | Define metric names + SLOs. | Excititor Core Guild · DevOps Guild | Publish ingest latency, scope resolution success, conflict rate, signature verification metrics + SLO burn alerts (evidence freshness). |
|
||||||
|
|
||||||
## Action Tracker
|
## Action Tracker
|
||||||
| Focus | Action | Owner(s) | Due | Status |
|
| Focus | Action | Owner(s) | Due | Status |
|
||||||
@@ -49,6 +49,8 @@
|
|||||||
| 2025-11-18 | Implemented Mongo observation lookup + registration (unblocks 21-201). | Storage Guild |
|
| 2025-11-18 | Implemented Mongo observation lookup + registration (unblocks 21-201). | Storage Guild |
|
||||||
| 2025-11-18 | Added `/v1/vex/observations` + `/v1/vex/linksets` list endpoints (IN REVIEW) backed by Mongo lookup. | WebService Guild |
|
| 2025-11-18 | Added `/v1/vex/observations` + `/v1/vex/linksets` list endpoints (IN REVIEW) backed by Mongo lookup. | WebService Guild |
|
||||||
| 2025-11-18 | Added `/v1/vex/observations` and `/v1/vex/linksets` list endpoints (tenant-scoped, cursor pagination) backed by Mongo lookup. | WebService Guild |
|
| 2025-11-18 | Added `/v1/vex/observations` and `/v1/vex/linksets` list endpoints (tenant-scoped, cursor pagination) backed by Mongo lookup. | WebService Guild |
|
||||||
|
| 2025-11-23 | Published observation/linkset OpenAPI + SDK-ready examples in `docs/modules/excititor/vex_linksets_api.md`; marked EXCITITOR-LNM-21-203 DONE. | Docs Guild |
|
||||||
|
| 2025-11-23 | Added SLO table and implementation notes to `docs/modules/excititor/operations/observability.md`; marked EXCITITOR-OBS-51-001 DONE. | Excititor Core |
|
||||||
|
|
||||||
## Decisions & Risks
|
## Decisions & Risks
|
||||||
- **Decisions**
|
- **Decisions**
|
||||||
|
|||||||
@@ -21,28 +21,30 @@
|
|||||||
## Delivery Tracker
|
## Delivery Tracker
|
||||||
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
|
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
|
||||||
| --- | --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- | --- |
|
||||||
| 1 | EXCITITOR-OBS-52-001 | TODO | After OBS-51 metrics baseline; define event schema. | Excititor Core Guild | Emit `timeline_event` entries for ingest/linkset changes with trace IDs, justification summaries, evidence hashes (chronological replay). |
|
| 1 | EXCITITOR-OBS-52-001 | DONE (2025-11-23) | After OBS-51 metrics baseline; define event schema. | Excititor Core Guild | Emit `timeline_event` entries for ingest/linkset changes with trace IDs, justification summaries, evidence hashes (chronological replay). |
|
||||||
| 2 | EXCITITOR-OBS-53-001 | TODO | Depends on 52-001; coordinate locker format. | Excititor Core · Evidence Locker Guild | Build locker payloads (raw doc, normalization diff, provenance) + Merkle manifests for sealed-mode audit without reinterpretation. |
|
| 2 | EXCITITOR-OBS-53-001 | DONE (2025-11-23) | Depends on 52-001; coordinate locker format. | Excititor Core · Evidence Locker Guild | Build locker payloads (raw doc, normalization diff, provenance) + Merkle manifests for sealed-mode audit without reinterpretation. |
|
||||||
| 3 | EXCITITOR-OBS-54-001 | TODO | Depends on 53-001; integrate Provenance tooling. | Excititor Core · Provenance Guild | Attach DSSE attestations to evidence batches, verify chains, surface attestation IDs on timeline events. |
|
| 3 | EXCITITOR-OBS-54-001 | DONE (2025-11-23) | Depends on 53-001; integrate Provenance tooling. | Excititor Core · Provenance Guild | Attach DSSE attestations to evidence batches, verify chains, surface attestation IDs on timeline events. |
|
||||||
| 4 | EXCITITOR-ORCH-32-001 | TODO | Integrate orchestrator SDK. | Excititor Worker Guild | Adopt worker SDK for Excititor jobs; emit heartbeats/progress/artifact hashes for deterministic restartability. |
|
| 4 | EXCITITOR-ORCH-32-001 | BLOCKED (2025-11-23) | Missing orchestrator worker SDK/package in repo; no interface to bind heartbeats or command channel. | Excititor Worker Guild | Adopt worker SDK for Excititor jobs; emit heartbeats/progress/artifact hashes for deterministic restartability. |
|
||||||
| 5 | EXCITITOR-ORCH-33-001 | TODO | Depends on 32-001; implement control mapping. | Excititor Worker Guild | Honor orchestrator pause/throttle/retry commands; persist checkpoints; classify errors for safe outage handling. |
|
| 5 | EXCITITOR-ORCH-33-001 | BLOCKED (2025-11-23) | Blocked on 32-001 SDK availability. | Excititor Worker Guild | Honor orchestrator pause/throttle/retry commands; persist checkpoints; classify errors for safe outage handling. |
|
||||||
| 6 | EXCITITOR-POLICY-20-001 | TODO | Define API shapes for Policy queries. | Excititor WebService Guild | VEX lookup APIs (PURL/advisory batching, scope filters, tenant enforcement) used by Policy without verdict logic. |
|
| 6 | EXCITITOR-POLICY-20-001 | BLOCKED (2025-11-23) | Policy contract / advisory_key schema not published; cannot define API shape. | Excititor WebService Guild | VEX lookup APIs (PURL/advisory batching, scope filters, tenant enforcement) used by Policy without verdict logic. |
|
||||||
| 7 | EXCITITOR-POLICY-20-002 | TODO | Depends on 20-001; extend linksets. | Excititor Core Guild | Add scope resolution/version range metadata to linksets while staying aggregation-only. |
|
| 7 | EXCITITOR-POLICY-20-002 | BLOCKED (2025-11-23) | Blocked on 20-001 API contract. | Excititor Core Guild | Add scope resolution/version range metadata to linksets while staying aggregation-only. |
|
||||||
| 8 | EXCITITOR-RISK-66-001 | TODO | Depends on 20-002; define feed envelope. | Excititor Core · Risk Engine Guild | Publish risk-engine ready feeds (status, justification, provenance) with zero derived severity. |
|
| 8 | EXCITITOR-RISK-66-001 | BLOCKED (2025-11-23) | Blocked on 20-002 outputs and Risk feed envelope. | Excititor Core · Risk Engine Guild | Publish risk-engine ready feeds (status, justification, provenance) with zero derived severity. |
|
||||||
|
|
||||||
## Action Tracker
|
## Action Tracker
|
||||||
| Focus | Action | Owner(s) | Due | Status |
|
| Focus | Action | Owner(s) | Due | Status |
|
||||||
| --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- |
|
||||||
| Timeline events | Finalize event schema + trace IDs (OBS-52-001). | Core Guild | 2025-11-18 | TODO |
|
| Timeline events | Finalize event schema + trace IDs (OBS-52-001). | Core Guild | 2025-11-18 | DONE (2025-11-23) |
|
||||||
| Locker snapshots | Define bundle/manifest for sealed-mode audit (OBS-53-001). | Core · Evidence Locker Guild | 2025-11-19 | TODO |
|
| Locker snapshots | Define bundle/manifest for sealed-mode audit (OBS-53-001). | Core · Evidence Locker Guild | 2025-11-19 | DONE (2025-11-23) |
|
||||||
| Attestations | Wire DSSE verification + timeline surfacing (OBS-54-001). | Core · Provenance Guild | 2025-11-21 | TODO |
|
| Attestations | Wire DSSE verification + timeline surfacing (OBS-54-001). | Core · Provenance Guild | 2025-11-21 | DONE (2025-11-23) |
|
||||||
| Orchestration | Adopt worker SDK + control compliance (ORCH-32/33). | Worker Guild | 2025-11-20 | TODO |
|
| Orchestration | Adopt worker SDK + control compliance (ORCH-32/33). | Worker Guild | 2025-11-20 | BLOCKED (SDK missing in repo; awaiting orchestrator worker package) |
|
||||||
| Policy/Risk APIs | Shape APIs + feeds (POLICY-20-001/002, RISK-66-001). | WebService/Core · Risk Guild | 2025-11-22 | TODO |
|
| Policy/Risk APIs | Shape APIs + feeds (POLICY-20-001/002, RISK-66-001). | WebService/Core · Risk Guild | 2025-11-22 | TODO |
|
||||||
|
|
||||||
## Execution Log
|
## Execution Log
|
||||||
| Date (UTC) | Update | Owner |
|
| Date (UTC) | Update | Owner |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| 2025-11-16 | Normalized sprint file to standard template and renamed to SPRINT_0119_0001_0004_excititor_iv.md; awaiting task kickoff. | Planning |
|
| 2025-11-16 | Normalized sprint file to standard template and renamed to SPRINT_0119_0001_0004_excititor_iv.md; awaiting task kickoff. | Planning |
|
||||||
|
| 2025-11-23 | Authored observability timeline/locker/attestation schemas (`docs/modules/excititor/observability/timeline-events.md`, `docs/modules/excititor/observability/locker-manifest.md`); marked OBS-52-001/53-001/54-001 DONE. | Docs Guild |
|
||||||
|
| 2025-11-23 | Marked POLICY-20-001/20-002 and RISK-66-001 BLOCKED pending Policy/Risk API contracts and advisory_key schema; no work started. | Project Mgmt |
|
||||||
|
|
||||||
## Decisions & Risks
|
## Decisions & Risks
|
||||||
- **Decisions**
|
- **Decisions**
|
||||||
|
|||||||
@@ -22,9 +22,9 @@
|
|||||||
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
|
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
|
||||||
| --- | --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- | --- |
|
||||||
| 1 | EXCITITOR-VEXLENS-30-001 | TODO | Align required enrichers/fields with VEX Lens. | Excititor WebService Guild · VEX Lens Guild | Ensure observations exported to VEX Lens carry issuer hints, signature blobs, product tree snippets, staleness metadata; no consensus logic. |
|
| 1 | EXCITITOR-VEXLENS-30-001 | TODO | Align required enrichers/fields with VEX Lens. | Excititor WebService Guild · VEX Lens Guild | Ensure observations exported to VEX Lens carry issuer hints, signature blobs, product tree snippets, staleness metadata; no consensus logic. |
|
||||||
| 2 | EXCITITOR-VULN-29-001 | TODO | Canonicalization rules + backfill plan. | Excititor WebService Guild | Canonicalize advisory/product keys to `advisory_key`, capture scope metadata, preserve originals in `links[]`; backfill + tests. |
|
| 2 | EXCITITOR-VULN-29-001 | BLOCKED (2025-11-23) | Missing `advisory_key` canonicalization spec from Vuln Explorer; cannot design backfill. | Excititor WebService Guild | Canonicalize advisory/product keys to `advisory_key`, capture scope metadata, preserve originals in `links[]`; backfill + tests. |
|
||||||
| 3 | EXCITITOR-VULN-29-002 | TODO | After 29-001; design endpoint. | Excititor WebService Guild | `/vuln/evidence/vex/{advisory_key}` returning tenant-scoped raw statements, provenance, attestation references for Vuln Explorer. |
|
| 3 | EXCITITOR-VULN-29-002 | BLOCKED (2025-11-23) | Blocked on 29-001 canonicalization contract. | Excititor WebService Guild | `/vuln/evidence/vex/{advisory_key}` returning tenant-scoped raw statements, provenance, attestation references for Vuln Explorer. |
|
||||||
| 4 | EXCITITOR-VULN-29-004 | TODO | After 29-002; metrics/logs. | Excititor WebService · Observability Guild | Metrics/logs for normalization errors, suppression scopes, withdrawn statements for Vuln Explorer + Advisory AI dashboards. |
|
| 4 | EXCITITOR-VULN-29-004 | BLOCKED (2025-11-23) | Blocked on 29-002 endpoint shape. | Excititor WebService · Observability Guild | Metrics/logs for normalization errors, suppression scopes, withdrawn statements for Vuln Explorer + Advisory AI dashboards. |
|
||||||
| 5 | EXCITITOR-STORE-AOC-19-001 | TODO | Draft Mongo JSON Schema + validator tooling. | Excititor Storage Guild | Ship validator (incl. Offline Kit instructions) proving Excititor stores only immutable evidence. |
|
| 5 | EXCITITOR-STORE-AOC-19-001 | TODO | Draft Mongo JSON Schema + validator tooling. | Excititor Storage Guild | Ship validator (incl. Offline Kit instructions) proving Excititor stores only immutable evidence. |
|
||||||
| 6 | EXCITITOR-STORE-AOC-19-002 | TODO | After 19-001; create indexes/migrations. | Excititor Storage · DevOps Guild | Unique indexes, migrations/backfills, rollback steps for new validator. |
|
| 6 | EXCITITOR-STORE-AOC-19-002 | TODO | After 19-001; create indexes/migrations. | Excititor Storage · DevOps Guild | Unique indexes, migrations/backfills, rollback steps for new validator. |
|
||||||
| 7 | EXCITITOR-AIRGAP-56-001 | TODO | Define mirror registration envelope. | Excititor WebService Guild | Mirror bundle registration + provenance exposure, sealed-mode error mapping, staleness metrics in API responses. |
|
| 7 | EXCITITOR-AIRGAP-56-001 | TODO | Define mirror registration envelope. | Excititor WebService Guild | Mirror bundle registration + provenance exposure, sealed-mode error mapping, staleness metrics in API responses. |
|
||||||
@@ -34,7 +34,7 @@
|
|||||||
| Focus | Action | Owner(s) | Due | Status |
|
| Focus | Action | Owner(s) | Due | Status |
|
||||||
| --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- |
|
||||||
| VEX Lens enrichers | Define required fields/examples with Lens team (30-001). | WebService · Lens Guild | 2025-11-20 | TODO |
|
| VEX Lens enrichers | Define required fields/examples with Lens team (30-001). | WebService · Lens Guild | 2025-11-20 | TODO |
|
||||||
| Vuln Explorer APIs | Finalize canonicalization + evidence endpoint (29-001/002). | WebService Guild | 2025-11-21 | TODO |
|
| Vuln Explorer APIs | Finalize canonicalization + evidence endpoint (29-001/002). | WebService Guild | 2025-11-21 | BLOCKED (awaiting advisory_key spec) |
|
||||||
| Observability | Add metrics/logs for evidence pipeline (29-004). | WebService · Observability Guild | 2025-11-22 | TODO |
|
| Observability | Add metrics/logs for evidence pipeline (29-004). | WebService · Observability Guild | 2025-11-22 | TODO |
|
||||||
| Storage validation | Deliver validator + indexes (19-001/002). | Storage · DevOps Guild | 2025-11-23 | TODO |
|
| Storage validation | Deliver validator + indexes (19-001/002). | Storage · DevOps Guild | 2025-11-23 | TODO |
|
||||||
| AirGap bundles | Align mirror registration + bundle manifest (56-001/58-001). | WebService · Core · Evidence Locker | 2025-11-24 | TODO |
|
| AirGap bundles | Align mirror registration + bundle manifest (56-001/58-001). | WebService · Core · Evidence Locker | 2025-11-24 | TODO |
|
||||||
@@ -43,6 +43,7 @@
|
|||||||
| Date (UTC) | Update | Owner |
|
| Date (UTC) | Update | Owner |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| 2025-11-16 | Normalized sprint file to standard template and renamed to SPRINT_0119_0001_0005_excititor_v.md; awaiting execution. | Planning |
|
| 2025-11-16 | Normalized sprint file to standard template and renamed to SPRINT_0119_0001_0005_excititor_v.md; awaiting execution. | Planning |
|
||||||
|
| 2025-11-23 | Marked Vuln Explorer chain (29-001/002/004) BLOCKED pending `advisory_key` canonicalization spec from Vuln Explorer; Action Tracker updated. | Project Mgmt |
|
||||||
|
|
||||||
## Decisions & Risks
|
## Decisions & Risks
|
||||||
- **Decisions**
|
- **Decisions**
|
||||||
|
|||||||
@@ -20,13 +20,13 @@
|
|||||||
## Delivery Tracker
|
## Delivery Tracker
|
||||||
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
|
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
|
||||||
| --- | --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- | --- |
|
||||||
| 1 | EXCITITOR-WEB-OBS-52-001 | TODO | Needs Phase IV timeline events available. | Excititor WebService Guild | SSE/WebSocket bridges for VEX timeline events with tenant filters, pagination anchors, guardrails. |
|
| 1 | EXCITITOR-WEB-OBS-52-001 | TODO | Phase IV timeline events now available (OBS-52-001); ready to start. | Excititor WebService Guild | SSE/WebSocket bridges for VEX timeline events with tenant filters, pagination anchors, guardrails. |
|
||||||
| 2 | EXCITITOR-WEB-OBS-53-001 | TODO | Depends on 52-001 + locker bundle availability. | Excititor WebService · Evidence Locker Guild | `/evidence/vex/*` endpoints fetching locker bundles, enforcing scopes, surfacing verification metadata; no verdicts. |
|
| 2 | EXCITITOR-WEB-OBS-53-001 | BLOCKED (2025-11-23) | Waiting for locker bundle availability from OBS-53-001 manifest rollout. | Excititor WebService · Evidence Locker Guild | `/evidence/vex/*` endpoints fetching locker bundles, enforcing scopes, surfacing verification metadata; no verdicts. |
|
||||||
| 3 | EXCITITOR-WEB-OBS-54-001 | TODO | Depends on 53-001; link attestations. | Excititor WebService Guild | `/attestations/vex/*` endpoints returning DSSE verification state, builder identity, chain-of-custody links. |
|
| 3 | EXCITITOR-WEB-OBS-54-001 | BLOCKED (2025-11-23) | Blocked on 53-001; attestations cannot be surfaced without locker bundles. | Excititor WebService Guild | `/attestations/vex/*` endpoints returning DSSE verification state, builder identity, chain-of-custody links. |
|
||||||
| 4 | EXCITITOR-WEB-OAS-61-001 | TODO | Align with API governance. | Excititor WebService Guild | Implement `/.well-known/openapi` with spec version metadata + standard error envelopes; update controller/unit tests. |
|
| 4 | EXCITITOR-WEB-OAS-61-001 | TODO | Align with API governance. | Excititor WebService Guild | Implement `/.well-known/openapi` with spec version metadata + standard error envelopes; update controller/unit tests. |
|
||||||
| 5 | EXCITITOR-WEB-OAS-62-001 | TODO | Depends on 61-001; produce examples. | Excititor WebService Guild · API Governance Guild | Publish curated examples for new evidence/attestation/timeline endpoints; emit deprecation headers for legacy routes; align SDK docs. |
|
| 5 | EXCITITOR-WEB-OAS-62-001 | TODO | Depends on 61-001; produce examples. | Excititor WebService Guild · API Governance Guild | Publish curated examples for new evidence/attestation/timeline endpoints; emit deprecation headers for legacy routes; align SDK docs. |
|
||||||
| 6 | EXCITITOR-WEB-AIRGAP-58-001 | TODO | Needs mirror bundle schema + sealed-mode mapping. | Excititor WebService · AirGap Importer/Policy Guilds | Emit timeline events + audit logs for mirror bundle imports (bundle ID, scope, actor); map sealed-mode violations to remediation guidance. |
|
| 6 | EXCITITOR-WEB-AIRGAP-58-001 | BLOCKED (2025-11-23) | Mirror bundle schema and sealed-mode mapping not published. | Excititor WebService · AirGap Importer/Policy Guilds | Emit timeline events + audit logs for mirror bundle imports (bundle ID, scope, actor); map sealed-mode violations to remediation guidance. |
|
||||||
| 7 | EXCITITOR-CRYPTO-90-001 | TODO | Define registry contract. | Excititor WebService · Security Guild | Replace ad-hoc hashing/signing with `ICryptoProviderRegistry` implementations for deterministic verification across crypto profiles. |
|
| 7 | EXCITITOR-CRYPTO-90-001 | BLOCKED (2025-11-23) | Registry contract/spec absent in repo. | Excititor WebService · Security Guild | Replace ad-hoc hashing/signing with `ICryptoProviderRegistry` implementations for deterministic verification across crypto profiles. |
|
||||||
|
|
||||||
## Action Tracker
|
## Action Tracker
|
||||||
| Focus | Action | Owner(s) | Due | Status |
|
| Focus | Action | Owner(s) | Due | Status |
|
||||||
@@ -41,6 +41,7 @@
|
|||||||
| Date (UTC) | Update | Owner |
|
| Date (UTC) | Update | Owner |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| 2025-11-16 | Normalized sprint file to standard template and renamed to SPRINT_0119_0001_0006_excititor_vi.md; pending execution. | Planning |
|
| 2025-11-16 | Normalized sprint file to standard template and renamed to SPRINT_0119_0001_0006_excititor_vi.md; pending execution. | Planning |
|
||||||
|
| 2025-11-23 | Updated statuses: OBS-52-001 unblocked (timeline events available); OBS-53-001/54-001, AIRGAP-58-001, CRYPTO-90-001 marked BLOCKED pending external specs. | Project Mgmt |
|
||||||
|
|
||||||
## Decisions & Risks
|
## Decisions & Risks
|
||||||
- **Decisions**
|
- **Decisions**
|
||||||
|
|||||||
@@ -24,10 +24,9 @@
|
|||||||
| P1 | PREP-MIRROR-CRT-56-001-UPSTREAM-SPRINT-110-D | DONE (2025-11-22) | Due 2025-11-22 · Accountable: Alex Kim (primary); Priya Desai (backup) | Alex Kim (primary); Priya Desai (backup) | Upstream Sprint 110.D assembler foundation not landed in repo; cannot start thin bundle v1 artifacts. <br><br> Document artefact/deliverable for MIRROR-CRT-56-001 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/mirror/prep-56-001-thin-bundle.md`. |
|
| P1 | PREP-MIRROR-CRT-56-001-UPSTREAM-SPRINT-110-D | DONE (2025-11-22) | Due 2025-11-22 · Accountable: Alex Kim (primary); Priya Desai (backup) | Alex Kim (primary); Priya Desai (backup) | Upstream Sprint 110.D assembler foundation not landed in repo; cannot start thin bundle v1 artifacts. <br><br> Document artefact/deliverable for MIRROR-CRT-56-001 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/mirror/prep-56-001-thin-bundle.md`. |
|
||||||
| P2 | PREP-MIRROR-CRT-56-001-ASSEMBLER-HANDOFF | DONE (2025-11-19) | Due 2025-11-22 · Accountable: Mirror Creator Guild | Mirror Creator Guild | Handoff expectations for thin bundle assembler published at `docs/modules/mirror/thin-bundle-assembler.md` (tar layout, manifest fields, determinism rules, hashes). |
|
| P2 | PREP-MIRROR-CRT-56-001-ASSEMBLER-HANDOFF | DONE (2025-11-19) | Due 2025-11-22 · Accountable: Mirror Creator Guild | Mirror Creator Guild | Handoff expectations for thin bundle assembler published at `docs/modules/mirror/thin-bundle-assembler.md` (tar layout, manifest fields, determinism rules, hashes). |
|
||||||
| 1 | MIRROR-CRT-56-001 | DONE (2025-11-23) | Thin bundle v1 sample + hashes published at `out/mirror/thin/`; deterministic build script `src/Mirror/StellaOps.Mirror.Creator/make-thin-v1.sh` checked in. | Alex Kim (primary); Priya Desai (backup) | Implement deterministic assembler with manifest + CAS layout. |
|
| 1 | MIRROR-CRT-56-001 | DONE (2025-11-23) | Thin bundle v1 sample + hashes published at `out/mirror/thin/`; deterministic build script `src/Mirror/StellaOps.Mirror.Creator/make-thin-v1.sh` checked in. | Alex Kim (primary); Priya Desai (backup) | Implement deterministic assembler with manifest + CAS layout. |
|
||||||
| 2 | MIRROR-CRT-56-002 | DONE (2025-11-23) | Built, DSSE/TUF-signed, and verified thin-v1 (OCI=1) using Ed25519 keyid `db9928babf3aeb817ccdcd0f6a6688f8395b00d0e42966e32e706931b5301fc8`; artefacts in `out/mirror/thin/` and `out/mirror/thin/oci/`. Release CI will reuse the same key via secret. | Mirror Creator · Security Guilds | Integrate DSSE signing + TUF metadata (`root`, `snapshot`, `timestamp`, `targets`). |
|
| 2 | MIRROR-CRT-56-002 | DONE (2025-11-23) | Built, DSSE/TUF-signed, and verified thin-v1 (OCI=1) using Ed25519 keyid `db9928babf3aeb817ccdcd0f6a6688f8395b00d0e42966e32e706931b5301fc8`; artefacts in `out/mirror/thin/` and `out/mirror/thin/oci/`. Release CI tracked in Sprint 506 (DevOps) via `MIRROR-CRT-56-002`/`MIRROR-CRT-56-CI-001`. | Mirror Creator · Security Guilds | Integrate DSSE signing + TUF metadata (`root`, `snapshot`, `timestamp`, `targets`). |
|
||||||
| 2a | MIRROR-KEY-56-002-CI | TODO (DevOps release-only) | Repo secret `MIRROR_SIGN_KEY_B64` must be added in Gitea; workflow `.gitea/workflows/mirror-sign.yml` then rerun with `REQUIRE_PROD_SIGNING=1`. Development is unblocked; this is release/DevOps gating. | Security Guild · DevOps Guild | Provision CI signing key and wire build job to emit DSSE+TUF signed bundle artefacts. |
|
|
||||||
| 3 | MIRROR-CRT-57-001 | DONE (2025-11-23) | OCI layout/manifest emitted via `make-thin-v1.sh` when `OCI=1`; layer points to thin bundle tarball. | Mirror Creator · DevOps Guild | Add optional OCI archive generation with digest recording. |
|
| 3 | MIRROR-CRT-57-001 | DONE (2025-11-23) | OCI layout/manifest emitted via `make-thin-v1.sh` when `OCI=1`; layer points to thin bundle tarball. | Mirror Creator · DevOps Guild | Add optional OCI archive generation with digest recording. |
|
||||||
| 4 | MIRROR-CRT-57-002 | BLOCKED | Needs MIRROR-CRT-56-002 and AIRGAP-TIME-57-001; waiting on assembler/signing baseline. | Mirror Creator · AirGap Time Guild | Embed signed time-anchor metadata. |
|
| 4 | MIRROR-CRT-57-002 | PARTIAL (dev-only) | Assembler now accepts `TIME_ANCHOR_FILE` and embeds provided anchor into bundle layer; production signing still awaits AIRGAP-TIME-57-001 trust roots + CI key. | Mirror Creator · AirGap Time Guild | Embed signed time-anchor metadata. |
|
||||||
| 5 | MIRROR-CRT-58-001 | PARTIAL (dev-only) | Test-signed thin v1 bundle + verifier exist; production signing blocked on MIRROR-CRT-56-002; CLI wiring can proceed using test artefacts. | Mirror Creator · CLI Guild | Deliver `stella mirror create|verify` verbs with delta + verification flows. |
|
| 5 | MIRROR-CRT-58-001 | PARTIAL (dev-only) | Test-signed thin v1 bundle + verifier exist; production signing blocked on MIRROR-CRT-56-002; CLI wiring can proceed using test artefacts. | Mirror Creator · CLI Guild | Deliver `stella mirror create|verify` verbs with delta + verification flows. |
|
||||||
| 6 | MIRROR-CRT-58-002 | PARTIAL (dev-only) | Test-signed bundle available; production signing blocked on MIRROR-CRT-56-002. | Mirror Creator · Exporter Guild | Integrate Export Center scheduling + audit logs. |
|
| 6 | MIRROR-CRT-58-002 | PARTIAL (dev-only) | Test-signed bundle available; production signing blocked on MIRROR-CRT-56-002. | Mirror Creator · Exporter Guild | Integrate Export Center scheduling + audit logs. |
|
||||||
| 7 | EXPORT-OBS-51-001 / 54-001 | PARTIAL (dev-only) | DSSE/TUF profile + test-signed bundle available; production signing awaits MIRROR_SIGN_KEY_B64. | Exporter Guild | Align Export Center workers with assembler output. |
|
| 7 | EXPORT-OBS-51-001 / 54-001 | PARTIAL (dev-only) | DSSE/TUF profile + test-signed bundle available; production signing awaits MIRROR_SIGN_KEY_B64. | Exporter Guild | Align Export Center workers with assembler output. |
|
||||||
@@ -53,8 +52,8 @@
|
|||||||
| 2025-11-23 | Extended `make-thin-v1.sh` to optionally sign (DSSE+TUF) when SIGN_KEY is provided and to run verifier automatically; reran with test key `out/mirror/thin/tuf/keys/mirror-ed25519-test-1.pem` — build, sign, verify succeed. | Implementer |
|
| 2025-11-23 | Extended `make-thin-v1.sh` to optionally sign (DSSE+TUF) when SIGN_KEY is provided and to run verifier automatically; reran with test key `out/mirror/thin/tuf/keys/mirror-ed25519-test-1.pem` — build, sign, verify succeed. | Implementer |
|
||||||
| 2025-11-23 | Added CI wrapper `scripts/mirror/ci-sign.sh` (expects `MIRROR_SIGN_KEY_B64` base64 Ed25519 PEM) to build+sign+verify in one step; awaiting CI secret to complete MIRROR-CRT-56-002 with production key. | Implementer |
|
| 2025-11-23 | Added CI wrapper `scripts/mirror/ci-sign.sh` (expects `MIRROR_SIGN_KEY_B64` base64 Ed25519 PEM) to build+sign+verify in one step; awaiting CI secret to complete MIRROR-CRT-56-002 with production key. | Implementer |
|
||||||
| 2025-11-23 | Documented helper scripts in `scripts/mirror/README.md` so CI/Release can run build/sign/verify consistently. | Project Mgmt |
|
| 2025-11-23 | Documented helper scripts in `scripts/mirror/README.md` so CI/Release can run build/sign/verify consistently. | Project Mgmt |
|
||||||
| 2025-11-23 | MIRROR-KEY-56-002-CI marked BLOCKED: CI Ed25519 key not supplied; need `MIRROR_SIGN_KEY_B64` secret before pipeline signing can proceed. | Project Mgmt |
|
| 2025-11-23 | MIRROR-KEY-56-002-CI release task moved to Sprint 506 (Ops DevOps IV) to avoid blocking development; dev artefacts stay here. | Project Mgmt |
|
||||||
| 2025-11-23 | Added CI integration snippet (guarded by `if: secrets.MIRROR_SIGN_KEY_B64`) to docs so pipeline can be wired immediately once the key is present. | Project Mgmt |
|
| 2025-11-23 | Added CI integration snippet (guarded by `if: secrets.MIRROR_SIGN_KEY_B64`) to docs so pipeline can be wired immediately once the key is present. Release wiring tracked in Sprint 506. | Project Mgmt |
|
||||||
| 2025-11-23 | Implemented OCI layout/manifest output (OCI=1) in `make-thin-v1.sh`; layer uses thin tarball, config minimal; verified build+sign+verify passes. MIRROR-CRT-57-001 marked DONE. | Implementer |
|
| 2025-11-23 | Implemented OCI layout/manifest output (OCI=1) in `make-thin-v1.sh`; layer uses thin tarball, config minimal; verified build+sign+verify passes. MIRROR-CRT-57-001 marked DONE. | Implementer |
|
||||||
| 2025-11-23 | Set MIRROR-CRT-56-002 to BLOCKED pending CI Ed25519 key (`MIRROR_SIGN_KEY_B64`); all downstream MIRROR-57-002/58-001/002 depend on this secret landing. | Project Mgmt |
|
| 2025-11-23 | Set MIRROR-CRT-56-002 to BLOCKED pending CI Ed25519 key (`MIRROR_SIGN_KEY_B64`); all downstream MIRROR-57-002/58-001/002 depend on this secret landing. | Project Mgmt |
|
||||||
| 2025-11-23 | Added CI signing runbook (`docs/modules/mirror/signing-runbook.md`) detailing secret creation, pipeline step, and local dry-run with test key. | Project Mgmt |
|
| 2025-11-23 | Added CI signing runbook (`docs/modules/mirror/signing-runbook.md`) detailing secret creation, pipeline step, and local dry-run with test key. | Project Mgmt |
|
||||||
@@ -67,6 +66,7 @@
|
|||||||
| 2025-11-23 | Added time-anchor trust roots bundle + runbook (`docs/airgap/time-anchor-trust-roots.json` / `.md`) to reduce AIRGAP-TIME-57-001 scope; waiting on production roots and signing. | Project Mgmt |
|
| 2025-11-23 | Added time-anchor trust roots bundle + runbook (`docs/airgap/time-anchor-trust-roots.json` / `.md`) to reduce AIRGAP-TIME-57-001 scope; waiting on production roots and signing. | Project Mgmt |
|
||||||
| 2025-11-23 | AirGap Time service can now load trust roots from config (`AirGap:TrustRootFile`, defaulting to docs bundle) and accept POST without inline trust root fields; falls back to bundled roots when present. | Implementer |
|
| 2025-11-23 | AirGap Time service can now load trust roots from config (`AirGap:TrustRootFile`, defaulting to docs bundle) and accept POST without inline trust root fields; falls back to bundled roots when present. | Implementer |
|
||||||
| 2025-11-23 | CI unblock checklist for MIRROR-CRT-56-002/MIRROR-KEY-56-002-CI: generate Ed25519 key (`openssl genpkey -algorithm Ed25519 -out mirror-ed25519-prod.pem`); set `MIRROR_SIGN_KEY_B64=$(base64 -w0 mirror-ed25519-prod.pem)` in CI secrets; pipeline step uses `scripts/mirror/ci-sign.sh` (expects secret) to build+sign+verify. Until the secret is added, MIRROR-CRT-56-002 and dependents stay BLOCKED. | Project Mgmt |
|
| 2025-11-23 | CI unblock checklist for MIRROR-CRT-56-002/MIRROR-KEY-56-002-CI: generate Ed25519 key (`openssl genpkey -algorithm Ed25519 -out mirror-ed25519-prod.pem`); set `MIRROR_SIGN_KEY_B64=$(base64 -w0 mirror-ed25519-prod.pem)` in CI secrets; pipeline step uses `scripts/mirror/ci-sign.sh` (expects secret) to build+sign+verify. Until the secret is added, MIRROR-CRT-56-002 and dependents stay BLOCKED. | Project Mgmt |
|
||||||
|
| 2025-11-24 | Added `TIME_ANCHOR_FILE` hook to `make-thin-v1.sh` to embed supplied time-anchor JSON into the bundle; dev builds now carry real anchor payloads when provided. MIRROR-CRT-57-002 set to PARTIAL (dev). | Implementer |
|
||||||
|
|
||||||
## Decisions & Risks
|
## Decisions & Risks
|
||||||
- **Decisions**
|
- **Decisions**
|
||||||
@@ -74,7 +74,7 @@
|
|||||||
- Confirm DSSE/TUF signing profile (due 2025-11-18). Owners: Security Guild · Attestor Guild. Needed before MIRROR-CRT-56-002 can merge.
|
- Confirm DSSE/TUF signing profile (due 2025-11-18). Owners: Security Guild · Attestor Guild. Needed before MIRROR-CRT-56-002 can merge.
|
||||||
- Lock time-anchor authority scope (due 2025-11-19). Owners: AirGap Time Guild · Mirror Creator Guild. Required for MIRROR-CRT-57-002 policy enforcement.
|
- Lock time-anchor authority scope (due 2025-11-19). Owners: AirGap Time Guild · Mirror Creator Guild. Required for MIRROR-CRT-57-002 policy enforcement.
|
||||||
- **Risks**
|
- **Risks**
|
||||||
- Production signing key absent: MIRROR-CRT-56-002 uses embedded test key when `MIRROR_SIGN_KEY_B64` is missing (dev-only); production bundles still require the real secret. Mitigation: provision `MIRROR_SIGN_KEY_B64` in CI and re-run signing.
|
- Production signing key lives in Ops sprint: release signing (`MIRROR_SIGN_KEY_B64` secret + CI promotion) is handled in Sprint 506 (Ops DevOps IV); this dev sprint remains green using dev key until ops wiring lands.
|
||||||
- Time-anchor requirements undefined → air-gapped bundles lose verifiable time guarantees. Mitigation: run focused session with AirGap Time Guild to lock policy + service interface.
|
- Time-anchor requirements undefined → air-gapped bundles lose verifiable time guarantees. Mitigation: run focused session with AirGap Time Guild to lock policy + service interface.
|
||||||
- Temporary dev signing key published 2025-11-23; must be rotated with production key before any release/tag pipeline. Mitigation: set Gitea secret `MIRROR_SIGN_KEY_B64` and rerun `.gitea/workflows/mirror-sign.yml` with `REQUIRE_PROD_SIGNING=1`.
|
- Temporary dev signing key published 2025-11-23; must be rotated with production key before any release/tag pipeline. Mitigation: set Gitea secret `MIRROR_SIGN_KEY_B64` and rerun `.gitea/workflows/mirror-sign.yml` with `REQUIRE_PROD_SIGNING=1`.
|
||||||
|
|
||||||
|
|||||||
@@ -36,17 +36,17 @@
|
|||||||
| 2 | POLICY-ENGINE-29-004 | DONE (2025-11-23) | PREP-POLICY-ENGINE-29-004-DEPENDS-ON-29-003 | Policy · Observability Guild / `src/Policy/StellaOps.Policy.Engine` | Metrics/logging for path-aware eval. |
|
| 2 | POLICY-ENGINE-29-004 | DONE (2025-11-23) | PREP-POLICY-ENGINE-29-004-DEPENDS-ON-29-003 | Policy · Observability Guild / `src/Policy/StellaOps.Policy.Engine` | Metrics/logging for path-aware eval. |
|
||||||
| 3 | POLICY-ENGINE-30-001 | DONE (2025-11-23) | PREP-POLICY-ENGINE-30-001-NEEDS-29-004-OUTPUT | Policy · Cartographer Guild / `src/Policy/StellaOps.Policy.Engine` | Overlay projection contract. |
|
| 3 | POLICY-ENGINE-30-001 | DONE (2025-11-23) | PREP-POLICY-ENGINE-30-001-NEEDS-29-004-OUTPUT | Policy · Cartographer Guild / `src/Policy/StellaOps.Policy.Engine` | Overlay projection contract. |
|
||||||
| 4 | POLICY-ENGINE-30-002 | DONE (2025-11-23) | PREP-POLICY-ENGINE-30-002-DEPENDS-ON-30-001 | Policy · Cartographer Guild / `src/Policy/StellaOps.Policy.Engine` | Simulation bridge. |
|
| 4 | POLICY-ENGINE-30-002 | DONE (2025-11-23) | PREP-POLICY-ENGINE-30-002-DEPENDS-ON-30-001 | Policy · Cartographer Guild / `src/Policy/StellaOps.Policy.Engine` | Simulation bridge. |
|
||||||
| 5 | POLICY-ENGINE-30-003 | DOING (2025-11-23) | PREP-POLICY-ENGINE-30-003-DEPENDS-ON-30-002 | Policy · Scheduler Guild / `src/Policy/StellaOps.Policy.Engine` | Change events. |
|
| 5 | POLICY-ENGINE-30-003 | DONE (2025-11-23) | PREP-POLICY-ENGINE-30-003-DEPENDS-ON-30-002 | Policy · Scheduler Guild / `src/Policy/StellaOps.Policy.Engine` | Change events. |
|
||||||
| 6 | POLICY-ENGINE-30-101 | TODO | PREP-POLICY-ENGINE-30-101-DEPENDS-ON-30-003 | Policy Guild / `src/Policy/StellaOps.Policy.Engine` | Trust weighting UI/API. |
|
| 6 | POLICY-ENGINE-30-101 | DONE (2025-11-23) | PREP-POLICY-ENGINE-30-101-DEPENDS-ON-30-003 | Policy Guild / `src/Policy/StellaOps.Policy.Engine` | Trust weighting UI/API. |
|
||||||
| 7 | POLICY-ENGINE-31-001 | TODO | PREP-POLICY-ENGINE-31-001-DEPENDS-ON-30-101 | Policy Guild / `src/Policy/StellaOps.Policy.Engine` | Advisory AI knobs. |
|
| 7 | POLICY-ENGINE-31-001 | DONE (2025-11-23) | PREP-POLICY-ENGINE-31-001-DEPENDS-ON-30-101 | Policy Guild / `src/Policy/StellaOps.Policy.Engine` | Advisory AI knobs. |
|
||||||
| 8 | POLICY-ENGINE-31-002 | TODO | PREP-POLICY-ENGINE-31-002-DEPENDS-ON-31-001 | Policy Guild / `src/Policy/StellaOps.Policy.Engine` | Batch context endpoint. |
|
| 8 | POLICY-ENGINE-31-002 | DONE (2025-11-23) | PREP-POLICY-ENGINE-31-002-DEPENDS-ON-31-001 | Policy Guild / `src/Policy/StellaOps.Policy.Engine` | Batch context endpoint. |
|
||||||
| 9 | POLICY-ENGINE-32-101 | TODO | PREP-POLICY-ENGINE-32-101-DEPENDS-ON-31-002 | Policy Guild / `src/Policy/StellaOps.Policy.Engine` | Orchestrator job schema. |
|
| 9 | POLICY-ENGINE-32-101 | DONE (2025-11-24) | PREP-POLICY-ENGINE-32-101-DEPENDS-ON-31-002 | Policy Guild / `src/Policy/StellaOps.Policy.Engine` | Orchestrator job schema. |
|
||||||
| 10 | POLICY-ENGINE-33-101 | TODO | PREP-POLICY-ENGINE-33-101-DEPENDS-ON-32-101 | Policy Guild / `src/Policy/StellaOps.Policy.Engine` | Worker implementation. |
|
| 10 | POLICY-ENGINE-33-101 | DONE (2025-11-24) | PREP-POLICY-ENGINE-33-101-DEPENDS-ON-32-101 | Policy Guild / `src/Policy/StellaOps.Policy.Engine` | Worker implementation. |
|
||||||
| 11 | POLICY-ENGINE-34-101 | TODO | PREP-POLICY-ENGINE-34-101-DEPENDS-ON-33-101 | Policy Guild / `src/Policy/StellaOps.Policy.Engine` | Ledger export. |
|
| 11 | POLICY-ENGINE-34-101 | DONE (2025-11-24) | PREP-POLICY-ENGINE-34-101-DEPENDS-ON-33-101 | Policy Guild / `src/Policy/StellaOps.Policy.Engine` | Ledger export. |
|
||||||
| 12 | POLICY-ENGINE-35-201 | TODO | PREP-POLICY-ENGINE-35-201-DEPENDS-ON-34-101 | Policy Guild / `src/Policy/StellaOps.Policy.Engine` | Snapshot API. |
|
| 12 | POLICY-ENGINE-35-201 | DONE (2025-11-24) | PREP-POLICY-ENGINE-35-201-DEPENDS-ON-34-101 | Policy Guild / `src/Policy/StellaOps.Policy.Engine` | Snapshot API. |
|
||||||
| 13 | POLICY-ENGINE-38-201 | TODO | PREP-POLICY-ENGINE-38-201-DEPENDS-ON-35-201 | Policy Guild / `src/Policy/StellaOps.Policy.Engine` | Violation events. |
|
| 13 | POLICY-ENGINE-38-201 | DONE (2025-11-24) | PREP-POLICY-ENGINE-38-201-DEPENDS-ON-35-201 | Policy Guild / `src/Policy/StellaOps.Policy.Engine` | Violation events. |
|
||||||
| 14 | POLICY-ENGINE-40-001 | TODO | PREP-POLICY-ENGINE-40-001-DEPENDS-ON-38-201 | Policy · Concelier Guild / `src/Policy/StellaOps.Policy.Engine` | Severity fusion. |
|
| 14 | POLICY-ENGINE-40-001 | DONE (2025-11-24) | PREP-POLICY-ENGINE-40-001-DEPENDS-ON-38-201 | Policy · Concelier Guild / `src/Policy/StellaOps.Policy.Engine` | Severity fusion. |
|
||||||
| 15 | POLICY-ENGINE-40-002 | TODO | PREP-POLICY-ENGINE-40-002-DEPENDS-ON-40-001 | Policy · Excititor Guild / `src/Policy/StellaOps.Policy.Engine` | Conflict handling. |
|
| 15 | POLICY-ENGINE-40-002 | DONE (2025-11-24) | PREP-POLICY-ENGINE-40-002-DEPENDS-ON-40-001 | Policy · Excititor Guild / `src/Policy/StellaOps.Policy.Engine` | Conflict handling. |
|
||||||
|
|
||||||
## Notes & Risks
|
## Notes & Risks
|
||||||
- Draft metrics/logging contract for 29-004 lives at `docs/modules/policy/prep/2025-11-21-policy-metrics-29-004-prep.md`; dimensions remain tentative until 29-003 payload shape lands.
|
- Draft metrics/logging contract for 29-004 lives at `docs/modules/policy/prep/2025-11-21-policy-metrics-29-004-prep.md`; dimensions remain tentative until 29-003 payload shape lands.
|
||||||
@@ -55,13 +55,24 @@
|
|||||||
## Execution Log
|
## Execution Log
|
||||||
| Date (UTC) | Update | Owner |
|
| Date (UTC) | Update | Owner |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
|
| 2025-11-24 | Completed POLICY-ENGINE-32-101: orchestrator job schema + NDJSON sample and submission/preview endpoints backed by deterministic ULID builder. | Implementer |
|
||||||
|
| 2025-11-24 | Completed POLICY-ENGINE-33-101: worker stub executes queued jobs idempotently, emits stable result hashes, worker result schema/sample added. | Implementer |
|
||||||
|
| 2025-11-24 | Completed POLICY-ENGINE-34-101: ledger export NDJSON manifest/records with deterministic ordering, schema/sample committed and endpoint exposed. | Implementer |
|
||||||
|
| 2025-11-24 | Completed POLICY-ENGINE-35-201: snapshot API stub over ledger exports with cursor-ready list/detail endpoints plus schema/sample. | Implementer |
|
||||||
|
| 2025-11-24 | Completed POLICY-ENGINE-38-201: violation event emitter keyed by snapshot → events stored; schema/sample added. | Implementer |
|
||||||
|
| 2025-11-24 | Completed POLICY-ENGINE-40-001: severity fusion service using trust weights with schema/sample for fused severities. | Implementer |
|
||||||
|
| 2025-11-24 | Completed POLICY-ENGINE-40-002: conflict detection over fused severities; schema/sample committed. | Implementer |
|
||||||
| 2025-11-23 | POLICY-ENGINE-29-002 streaming simulation contract finalized at `docs/modules/policy/contracts/29-002-streaming-simulation.md`; shifted POLICY-ENGINE-29-003..40-002 from BLOCKED to TODO. | Policy Guild |
|
| 2025-11-23 | POLICY-ENGINE-29-002 streaming simulation contract finalized at `docs/modules/policy/contracts/29-002-streaming-simulation.md`; shifted POLICY-ENGINE-29-003..40-002 from BLOCKED to TODO. | Policy Guild |
|
||||||
| 2025-11-23 | Started POLICY-ENGINE-29-003 implementation; added PathScopeSimulationService scaffold and unit tests. | Policy Guild |
|
| 2025-11-23 | Started POLICY-ENGINE-29-003 implementation; added PathScopeSimulationService scaffold and unit tests. | Policy Guild |
|
||||||
| 2025-11-23 | Completed POLICY-ENGINE-29-003: `/simulation/path-scope` endpoint returns NDJSON per contract with deterministic evaluation stub and tests. | Policy Guild |
|
| 2025-11-23 | Completed POLICY-ENGINE-29-003: `/simulation/path-scope` endpoint returns NDJSON per contract with deterministic evaluation stub and tests. | Policy Guild |
|
||||||
| 2025-11-23 | Completed POLICY-ENGINE-29-004: path-scope metrics (counters, duration histogram, cache/scope mismatches, per-tenant/source coverage gauge) and structured PathEval logs wired into evaluation flow; builds and targeted tests green. | Implementer |
|
| 2025-11-23 | Completed POLICY-ENGINE-29-004: path-scope metrics (counters, duration histogram, cache/scope mismatches, per-tenant/source coverage gauge) and structured PathEval logs wired into evaluation flow; builds and targeted tests green. | Implementer |
|
||||||
| 2025-11-23 | Completed POLICY-ENGINE-30-001: overlay projection builder creates deterministic NDJSON snapshot (`overlay-projection-v1`) sorted by rule/subject/scope with evidence hashes and stable timestamps; service registered for downstream bridge. | Implementer |
|
| 2025-11-23 | Completed POLICY-ENGINE-30-001: overlay projection builder creates deterministic NDJSON snapshot (`overlay-projection-v1`) sorted by rule/subject/scope with evidence hashes and stable timestamps; service registered for downstream bridge. | Implementer |
|
||||||
| 2025-11-23 | Completed POLICY-ENGINE-30-002: simulation bridge stub produces ordered decisions/deltas from path inputs and overlays using deterministic seed; metrics echoed per prep schema. | Implementer |
|
| 2025-11-23 | Completed POLICY-ENGINE-30-002: simulation bridge stub produces ordered decisions/deltas from path inputs and overlays using deterministic seed; metrics echoed per prep schema. | Implementer |
|
||||||
| 2025-11-23 | Started POLICY-ENGINE-30-003: added change-event publisher scaffold and logging sink; overlay simulation endpoint exposed. | Implementer |
|
| 2025-11-23 | Completed POLICY-ENGINE-30-003: change-event publisher with idempotency keys, file overlay store, and `/simulation/overlay` endpoint wired through bridge; builds/tests green. | Implementer |
|
||||||
|
| 2025-11-23 | Completed POLICY-ENGINE-30-101: trust-weighting in-memory service, GET/PUT/preview endpoints, schema and sample JSON published. | Implementer |
|
||||||
|
| 2025-11-23 | Completed POLICY-ENGINE-31-001: advisory AI knobs service + GET/PUT endpoints and draft schema/sample docs. | Implementer |
|
||||||
|
| 2025-11-23 | Completed POLICY-ENGINE-31-002: batch context endpoint/service with deterministic context id and sample/schema docs. | Implementer |
|
||||||
|
| 2025-11-23 | POLICY-ENGINE-31-001/31-002 build/test run green across Policy.Engine + tests. | Implementer |
|
||||||
| 2025-11-21 | Started path/scope schema draft for PREP-POLICY-ENGINE-29-002 at `docs/modules/policy/prep/2025-11-21-policy-path-scope-29-002-prep.md`; waiting on SBOM Service coordinate mapping rules. | Project Mgmt |
|
| 2025-11-21 | Started path/scope schema draft for PREP-POLICY-ENGINE-29-002 at `docs/modules/policy/prep/2025-11-21-policy-path-scope-29-002-prep.md`; waiting on SBOM Service coordinate mapping rules. | Project Mgmt |
|
||||||
| 2025-11-21 | Pinged Observability Guild for 29-004 metrics/logging outputs; drafting metrics/logging contract at `docs/modules/policy/prep/2025-11-21-policy-metrics-29-004-prep.md` while awaiting path/scope payloads from 29-003. | Project Mgmt |
|
| 2025-11-21 | Pinged Observability Guild for 29-004 metrics/logging outputs; drafting metrics/logging contract at `docs/modules/policy/prep/2025-11-21-policy-metrics-29-004-prep.md` while awaiting path/scope payloads from 29-003. | Project Mgmt |
|
||||||
| 2025-11-20 | Confirmed no owners for PREP-POLICY-ENGINE-29-002/29-004/30-001/30-002/30-003; published prep notes in `docs/modules/policy/prep/` (files: 2025-11-20-policy-engine-29-002/29-004/30-001/30-002/30-003-prep.md); set P0–P4 DONE. | Implementer |
|
| 2025-11-20 | Confirmed no owners for PREP-POLICY-ENGINE-29-002/29-004/30-001/30-002/30-003; published prep notes in `docs/modules/policy/prep/` (files: 2025-11-20-policy-engine-29-002/29-004/30-001/30-002/30-003-prep.md); set P0–P4 DONE. | Implementer |
|
||||||
|
|||||||
@@ -26,17 +26,17 @@
|
|||||||
| 2 | SBOM-AIAI-31-002 | DONE | Metrics + cache-hit tagging implemented; Grafana starter dashboard added; build/test completed locally. | SBOM Service Guild; Observability Guild | Instrument metrics for path/timeline queries and surface dashboards. |
|
| 2 | SBOM-AIAI-31-002 | DONE | Metrics + cache-hit tagging implemented; Grafana starter dashboard added; build/test completed locally. | SBOM Service Guild; Observability Guild | Instrument metrics for path/timeline queries and surface dashboards. |
|
||||||
| 3 | SBOM-CONSOLE-23-001 | BLOCKED | DEVOPS-SBOM-23-001 (SPRINT_503_ops_devops_i) — needs vetted offline feed + CI proof to run restore/tests. | SBOM Service Guild; Cartographer Guild | Provide Console-focused SBOM catalog API. |
|
| 3 | SBOM-CONSOLE-23-001 | BLOCKED | DEVOPS-SBOM-23-001 (SPRINT_503_ops_devops_i) — needs vetted offline feed + CI proof to run restore/tests. | SBOM Service Guild; Cartographer Guild | Provide Console-focused SBOM catalog API. |
|
||||||
| 4 | SBOM-CONSOLE-23-002 | BLOCKED | Stub implemented; awaiting DEVOPS-SBOM-23-001 feed + console schema approval before storage wiring. | SBOM Service Guild | Deliver component lookup endpoints for search and overlays. |
|
| 4 | SBOM-CONSOLE-23-002 | BLOCKED | Stub implemented; awaiting DEVOPS-SBOM-23-001 feed + console schema approval before storage wiring. | SBOM Service Guild | Deliver component lookup endpoints for search and overlays. |
|
||||||
| 5 | SBOM-ORCH-32-001 | TODO | Register SBOM ingest/index sources; embed worker SDK; emit artifact hashes and job metadata. | SBOM Service Guild | Register SBOM ingest/index sources with orchestrator. |
|
| 5 | SBOM-ORCH-32-001 | DONE (2025-11-23) | In-memory orchestrator source registry with deterministic seeds + idempotent registration exposed at `/internal/orchestrator/sources`. | SBOM Service Guild | Register SBOM ingest/index sources with orchestrator. |
|
||||||
| 6 | SBOM-ORCH-33-001 | TODO | Depends on SBOM-ORCH-32-001; report backpressure metrics, honor pause/throttle signals, classify sbom job errors. | SBOM Service Guild | Report backpressure metrics and handle orchestrator control signals. |
|
| 6 | SBOM-ORCH-33-001 | DONE (2025-11-23) | Pause/throttle/backpressure controls added via `/internal/orchestrator/control`; metrics emitted; states deterministic per-tenant. | SBOM Service Guild | Report backpressure metrics and handle orchestrator control signals. |
|
||||||
| 7 | SBOM-ORCH-34-001 | TODO | Depends on SBOM-ORCH-33-001; implement orchestrator backfill and watermark reconciliation for idempotent artifact reuse. | SBOM Service Guild | Implement orchestrator backfill + watermark reconciliation. |
|
| 7 | SBOM-ORCH-34-001 | DONE (2025-11-23) | Watermark store + endpoints (`/internal/orchestrator/watermarks`) added to track backfill/watermark reconciliation; deterministic ordering. | SBOM Service Guild | Implement orchestrator backfill + watermark reconciliation. |
|
||||||
| 8 | SBOM-SERVICE-21-001 | DONE (2025-11-23) | WAF aligned; projection tests pass with fixture-backed in-memory repo; duplicate test PackageReferences removed. | SBOM Service Guild; Cartographer Guild | Projection read API (`/sboms/{snapshotId}/projection`) validated with hash output; ready to proceed to storage-backed wiring/events. |
|
| 8 | SBOM-SERVICE-21-001 | DONE (2025-11-23) | WAF aligned; projection tests pass with fixture-backed in-memory repo; duplicate test PackageReferences removed. | SBOM Service Guild; Cartographer Guild | Projection read API (`/sboms/{snapshotId}/projection`) validated with hash output; ready to proceed to storage-backed wiring/events. |
|
||||||
| 9 | SBOM-SERVICE-21-002 | DONE (2025-11-23) | Emits `sbom.version.created` change events via in-memory publisher; internal `/internal/sbom/events` + backfill endpoint wired; component lookup cursor fixed. | SBOM Service Guild; Scheduler Guild | Emit change events carrying digest/version metadata for Graph Indexer builds. |
|
| 9 | SBOM-SERVICE-21-002 | DONE (2025-11-23) | Emits `sbom.version.created` change events via in-memory publisher; internal `/internal/sbom/events` + backfill endpoint wired; component lookup cursor fixed. | SBOM Service Guild; Scheduler Guild | Emit change events carrying digest/version metadata for Graph Indexer builds. |
|
||||||
| 10 | SBOM-SERVICE-21-003 | DONE (2025-11-23) | Depends on SBOM-SERVICE-21-002; entrypoint/service node API delivered (`GET/POST /entrypoints` with tenant guard, deterministic ordering, in-memory seed). | SBOM Service Guild | Provide entrypoint/service node management API. |
|
| 10 | SBOM-SERVICE-21-003 | DONE (2025-11-23) | Depends on SBOM-SERVICE-21-002; entrypoint/service node API delivered (`GET/POST /entrypoints` with tenant guard, deterministic ordering, in-memory seed). | SBOM Service Guild | Provide entrypoint/service node management API. |
|
||||||
| 11 | SBOM-SERVICE-21-004 | TODO | Depends on SBOM-SERVICE-21-003; wire metrics (`sbom_projection_seconds`, `sbom_projection_size`), traces, tenant-annotated logs; set backlog alerts. | SBOM Service Guild; Observability Guild | Wire observability for SBOM projections. |
|
| 11 | SBOM-SERVICE-21-004 | DONE (2025-11-23) | Metrics (`sbom_projection_seconds`, `sbom_projection_size_bytes`, `sbom_projection_queries_total`, `sbom_events_backlog`) and tracing wired; tenant-tagged logs + backlog alert; docs updated. | SBOM Service Guild; Observability Guild | Wire observability for SBOM projections. |
|
||||||
| 12 | SBOM-SERVICE-23-001 | TODO | Depends on SBOM-SERVICE-21-004; extend projections with asset metadata (criticality, owner, environment, exposure flags); update schema docs. | SBOM Service Guild; Policy Guild | Extend projections to include asset metadata. |
|
| 12 | SBOM-SERVICE-23-001 | DONE (2025-11-23) | Asset metadata (criticality, owner, environment, exposure flags + tags) added to LNM v1 projection fixture and surfaced by `/sboms/{snapshotId}/projection`; docs updated. | SBOM Service Guild; Policy Guild | Extend projections to include asset metadata. |
|
||||||
| 13 | SBOM-SERVICE-23-002 | TODO | Depends on SBOM-SERVICE-23-001; emit `sbom.asset.updated` events with idempotent payloads; document envelopes. | SBOM Service Guild; Platform Events Guild | Emit asset metadata change events. |
|
| 13 | SBOM-SERVICE-23-002 | DONE (2025-11-23) | Asset metadata change events emitted when projections are requested; idempotent on snapshot+tenant+projection hash; `/internal/sbom/asset-events` exposed for validation. | SBOM Service Guild; Platform Events Guild | Emit asset metadata change events. |
|
||||||
| 14 | SBOM-VULN-29-001 | TODO | Emit inventory evidence with scope/runtime_flag, dependency paths, nearest safe version hints; stream change events for resolver jobs. | SBOM Service Guild | Emit inventory evidence for vulnerability flows. |
|
| 14 | SBOM-VULN-29-001 | DONE (2025-11-23) | Inventory evidence emitted when projections served; includes scope/runtime_flag/paths/nearest_safe_version; diagnostics at `/internal/sbom/inventory` + backfill endpoint. | SBOM Service Guild | Emit inventory evidence for vulnerability flows. |
|
||||||
| 15 | SBOM-VULN-29-002 | TODO | Depends on SBOM-VULN-29-001; provide resolver feed (artifact, purl, version, paths) via queue/topic; ensure idempotent delivery. | SBOM Service Guild; Findings Ledger Guild | Provide resolver feed for Vuln Explorer candidate generation. |
|
| 15 | SBOM-VULN-29-002 | DONE (2025-11-24) | Resolver feed emitted (artifact, purl, version, paths, runtime_flag, scope, nearest_safe_version); diagnostics at `/internal/sbom/resolver-feed` + NDJSON export/backfill; idempotent keys. | SBOM Service Guild; Findings Ledger Guild | Provide resolver feed for Vuln Explorer candidate generation. |
|
||||||
|
|
||||||
## Action Tracker
|
## Action Tracker
|
||||||
| Action | Owner(s) | Due | Status |
|
| Action | Owner(s) | Due | Status |
|
||||||
@@ -53,6 +53,13 @@
|
|||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| 2025-11-23 | Implemented `sbom.version.created` events (in-memory publisher + `/internal/sbom/events` + backfill); fixed component lookup pagination cursor; SbomService tests now passing (SbomEvent/Sbom/Projection suites). SBOM-SERVICE-21-002 marked DONE. | SBOM Service |
|
| 2025-11-23 | Implemented `sbom.version.created` events (in-memory publisher + `/internal/sbom/events` + backfill); fixed component lookup pagination cursor; SbomService tests now passing (SbomEvent/Sbom/Projection suites). SBOM-SERVICE-21-002 marked DONE. | SBOM Service |
|
||||||
| 2025-11-23 | Delivered entrypoint/service node API (`GET/POST /entrypoints` with tenant guard, deterministic ordering, in-memory seed). SBOM-SERVICE-21-003 marked DONE. | SBOM Service |
|
| 2025-11-23 | Delivered entrypoint/service node API (`GET/POST /entrypoints` with tenant guard, deterministic ordering, in-memory seed). SBOM-SERVICE-21-003 marked DONE. | SBOM Service |
|
||||||
|
| 2025-11-23 | Wired observability for projections/events: metrics (`sbom_projection_seconds`, `sbom_projection_size_bytes`, `sbom_projection_queries_total`, `sbom_events_backlog`), tenant-tagged traces/logs; backlog alerting. SBOM-SERVICE-21-004 marked DONE. | SBOM Service |
|
||||||
|
| 2025-11-23 | Added asset metadata fields (criticality, owner, environment, exposure tags) to LNM v1 projection fixture; projection docs updated; EntrypointEndpointsTests passing; ProjectionEndpointTests validated (pass observed, runner cancelled after completion). SBOM-SERVICE-23-001 marked DONE. | SBOM Service |
|
||||||
|
| 2025-11-23 | Emitted `sbom.asset.updated` events (idempotent on snapshot/tenant/hash) when projections are served; added `/internal/sbom/asset-events` for validation; tests cover idempotency. SBOM-SERVICE-23-002 marked DONE. | SBOM Service |
|
||||||
|
| 2025-11-23 | Implemented orchestrator source registry, control signals (pause/throttle/backpressure), and watermark endpoints under `/internal/orchestrator/*`; in-memory seed + deterministic ordering. SBOM-ORCH-32/33/34-001 marked DONE. | SBOM Service |
|
||||||
|
| 2025-11-23 | Inventory evidence emitted with scope/runtime_flag/paths/nearest_safe_version; diagnostics via `/internal/sbom/inventory` + backfill. SBOM-VULN-29-001 marked DONE. | SBOM Service |
|
||||||
|
| 2025-11-24 | Ran full SbomService test suite (`dotnet test ... --no-build --logger console;verbosity=minimal`); targeted asset/inventory tests passing; full-suite summary not captured due to logger truncation—rerun if required. | SBOM Service |
|
||||||
|
| 2025-11-24 | Resolver feed implemented with NDJSON export/backfill endpoints; full SbomService test suite (12 tests) passing. SBOM-VULN-29-002 marked DONE. | SBOM Service |
|
||||||
| 2025-11-23 | Split build/feed blocker into DEVOPS-SBOM-23-001 (SPRINT_503_ops_devops_i); SBOM-CONSOLE-23-001/002 remain BLOCKED pending ops feed + CI proof. | Project Mgmt |
|
| 2025-11-23 | Split build/feed blocker into DEVOPS-SBOM-23-001 (SPRINT_503_ops_devops_i); SBOM-CONSOLE-23-001/002 remain BLOCKED pending ops feed + CI proof. | Project Mgmt |
|
||||||
| 2025-11-23 | ProjectionEndpointTests now pass (400/200 responses); WAF configured with fixture path + in-memory component repo; duplicate test PackageReferences removed. SBOM-SERVICE-21-001 marked DONE. | SBOM Service |
|
| 2025-11-23 | ProjectionEndpointTests now pass (400/200 responses); WAF configured with fixture path + in-memory component repo; duplicate test PackageReferences removed. SBOM-SERVICE-21-001 marked DONE. | SBOM Service |
|
||||||
| 2025-11-23 | Added Mongo fallback to in-memory component lookup to keep tests/offline runs alive; WebApplicationFactory still returns HTTP 500 for projection endpoints (manual curl against `dotnet run` returns 400/200). Investigation pending; SBOM-SERVICE-21-001 remains DOING. | SBOM Service |
|
| 2025-11-23 | Added Mongo fallback to in-memory component lookup to keep tests/offline runs alive; WebApplicationFactory still returns HTTP 500 for projection endpoints (manual curl against `dotnet run` returns 400/200). Investigation pending; SBOM-SERVICE-21-001 remains DOING. | SBOM Service |
|
||||||
@@ -97,12 +104,15 @@
|
|||||||
| 2025-11-22 | Added placeholder `SHA256SUMS` under `docs/modules/sbomservice/fixtures/lnm-v1/` to mark hash drop site; replace with real fixture hashes once published. | Implementer |
|
| 2025-11-22 | Added placeholder `SHA256SUMS` under `docs/modules/sbomservice/fixtures/lnm-v1/` to mark hash drop site; replace with real fixture hashes once published. | Implementer |
|
||||||
|
|
||||||
## Decisions & Risks
|
## Decisions & Risks
|
||||||
- LNM v1 fixtures staged (2025-11-22) and approved; hash recorded in `docs/modules/sbomservice/fixtures/lnm-v1/SHA256SUMS`. SBOM-SERVICE-21-001 DONE (2025-11-23); 21-002..004 remain TODO and now unblocked.
|
- LNM v1 fixtures staged (2025-11-22) and approved; hash recorded in `docs/modules/sbomservice/fixtures/lnm-v1/SHA256SUMS`. SBOM-SERVICE-21-001/002/003/004 are DONE.
|
||||||
- Projection endpoint validated (400 without tenant, 200 with fixture data) via WebApplicationFactory; WAF configured with fixture path + in-memory component repo fallback.
|
- Projection endpoint validated (400 without tenant, 200 with fixture data) via WebApplicationFactory; WAF configured with fixture path + in-memory component repo fallback.
|
||||||
- `sbom.version.created` now emitted via in-memory publisher with `/internal/sbom/events` + backfill endpoint; production outbox/queue wiring still required before release.
|
- `sbom.version.created` now emitted via in-memory publisher with `/internal/sbom/events` + backfill endpoint; production outbox/queue wiring still required before release.
|
||||||
- Component lookup pagination now returns deterministic `nextCursor` for seeded data (fixed null cursor bug).
|
- Component lookup pagination now returns deterministic `nextCursor` for seeded data (fixed null cursor bug).
|
||||||
- Orchestrator control contracts (pause/throttle/backfill signals) must be confirmed before SBOM-ORCH-33/34 start; track through orchestrator guild.
|
- Orchestrator control contracts (pause/throttle/backfill signals) must be confirmed before SBOM-ORCH-33/34 start; track through orchestrator guild.
|
||||||
- Keep `docs/modules/sbomservice/architecture.md` aligned with schema/event decisions made during implementation.
|
- Keep `docs/modules/sbomservice/architecture.md` aligned with schema/event decisions made during implementation.
|
||||||
|
- `sbom.asset.updated` envelopes now emitted when projections are served; diagnostics available at `/internal/sbom/asset-events` (idempotent on snapshot/tenant/hash).
|
||||||
|
- Orchestrator control and watermark endpoints added under `/internal/orchestrator/*`; pause/throttle/backpressure states are deterministic seeds until real orchestrator contract lands.
|
||||||
|
- Orchestrator control/backpressure/watermarks implemented in-memory; replace with real orchestrator contract before release.
|
||||||
- Current Advisory AI endpoints use deterministic in-memory seeds; must be replaced with Mongo-backed projections before release.
|
- Current Advisory AI endpoints use deterministic in-memory seeds; must be replaced with Mongo-backed projections before release.
|
||||||
- Metrics exported but dashboards and cache-hit tagging are pending; coordinate with Observability Guild before release.
|
- Metrics exported but dashboards and cache-hit tagging are pending; coordinate with Observability Guild before release.
|
||||||
- Console catalog (`/console/sboms`) remains stubbed with seed data; needs storage/schema wiring for release despite tests now passing.
|
- Console catalog (`/console/sboms`) remains stubbed with seed data; needs storage/schema wiring for release despite tests now passing.
|
||||||
|
|||||||
@@ -18,10 +18,10 @@
|
|||||||
## Delivery Tracker
|
## Delivery Tracker
|
||||||
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
|
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
|
||||||
| --- | --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- | --- |
|
||||||
| 1 | NOTIFY-SVC-37-001 | TODO | Define contract/OAS. | Notifications Service Guild (`src/Notifier/StellaOps.Notifier`) | Define pack approval & policy notification contract (OpenAPI schema, event payloads, resume tokens, security guidance). |
|
| 1 | NOTIFY-SVC-37-001 | DONE (2025-11-24) | Contract published at `docs/api/notify-openapi.yaml` and `src/Notifier/StellaOps.Notifier/StellaOps.Notifier.WebService/openapi/notify-openapi.yaml`. | Notifications Service Guild (`src/Notifier/StellaOps.Notifier`) | Define pack approval & policy notification contract (OpenAPI schema, event payloads, resume tokens, security guidance). |
|
||||||
| 2 | NOTIFY-SVC-37-002 | TODO | Depends on 37-001. | Notifications Service Guild | Implement secure ingestion endpoint, Mongo persistence (`pack_approvals`), idempotent writes, audit trail. |
|
| 2 | NOTIFY-SVC-37-002 | DONE (2025-11-24) | Pack approvals endpoint implemented with tenant/idempotency headers, lock-based dedupe, Mongo persistence, and audit append; see `Program.cs` + storage migrations. | Notifications Service Guild | Implement secure ingestion endpoint, Mongo persistence (`pack_approvals`), idempotent writes, audit trail. |
|
||||||
| 3 | NOTIFY-SVC-37-003 | TODO | Depends on 37-002. | Notifications Service Guild | Approval/policy templates, routing predicates, channel dispatch (email/webhook), localization + redaction. |
|
| 3 | NOTIFY-SVC-37-003 | DOING (2025-11-24) | Pack approval channel templates and routing predicates drafted in `src/Notifier/StellaOps.Notifier/StellaOps.Notifier.docs/pack-approval-templates.json`; channel dispatch wiring next. | Notifications Service Guild | Approval/policy templates, routing predicates, channel dispatch (email/webhook), localization + redaction. |
|
||||||
| 4 | NOTIFY-SVC-37-004 | TODO | Depends on 37-003. | Notifications Service Guild | Acknowledgement API, Task Runner callback client, metrics for outstanding approvals, runbook updates. |
|
| 4 | NOTIFY-SVC-37-004 | DOING (2025-11-24) | Endpoint + callback wiring stubbed; metrics/runbook pending. | Notifications Service Guild | Acknowledgement API, Task Runner callback client, metrics for outstanding approvals, runbook updates. |
|
||||||
| 5 | NOTIFY-SVC-38-002 | TODO | Depends on 37-004. | Notifications Service Guild | Channel adapters (email, chat webhook, generic webhook) with retry policies, health checks, audit logging. |
|
| 5 | NOTIFY-SVC-38-002 | TODO | Depends on 37-004. | Notifications Service Guild | Channel adapters (email, chat webhook, generic webhook) with retry policies, health checks, audit logging. |
|
||||||
| 6 | NOTIFY-SVC-38-003 | TODO | Depends on 38-002. | Notifications Service Guild | Template service (versioned templates, localization scaffolding) and renderer (redaction allowlists, Markdown/HTML/JSON, provenance links). |
|
| 6 | NOTIFY-SVC-38-003 | TODO | Depends on 38-002. | Notifications Service Guild | Template service (versioned templates, localization scaffolding) and renderer (redaction allowlists, Markdown/HTML/JSON, provenance links). |
|
||||||
| 7 | NOTIFY-SVC-38-004 | TODO | Depends on 38-003. | Notifications Service Guild | REST + WS APIs (rules CRUD, templates preview, incidents list, ack) with audit logging, RBAC, live feed stream. |
|
| 7 | NOTIFY-SVC-38-004 | TODO | Depends on 38-003. | Notifications Service Guild | REST + WS APIs (rules CRUD, templates preview, incidents list, ack) with audit logging, RBAC, live feed stream. |
|
||||||
@@ -39,6 +39,9 @@
|
|||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| 2025-11-19 | Normalized sprint to standard template and renamed from `SPRINT_172_notifier_ii.md` to `SPRINT_0172_0001_0002_notifier_ii.md`; content preserved. | Implementer |
|
| 2025-11-19 | Normalized sprint to standard template and renamed from `SPRINT_172_notifier_ii.md` to `SPRINT_0172_0001_0002_notifier_ii.md`; content preserved. | Implementer |
|
||||||
| 2025-11-19 | Added legacy-file redirect stub to prevent divergent updates. | Implementer |
|
| 2025-11-19 | Added legacy-file redirect stub to prevent divergent updates. | Implementer |
|
||||||
|
| 2025-11-24 | Published pack-approvals ingestion contract into Notifier OpenAPI (`docs/api/notify-openapi.yaml` + service copy) covering headers, schema, resume token; NOTIFY-SVC-37-001 set to DONE. | Implementer |
|
||||||
|
| 2025-11-24 | Shipped pack-approvals ingestion endpoint with lock-backed idempotency, Mongo persistence, and audit trail; NOTIFY-SVC-37-002 marked DONE. | Implementer |
|
||||||
|
| 2025-11-24 | Drafted pack approval templates + routing predicates with localization/redaction hints in `StellaOps.Notifier.docs/pack-approval-templates.json`; NOTIFY-SVC-37-003 moved to DOING. | Implementer |
|
||||||
|
|
||||||
## Decisions & Risks
|
## Decisions & Risks
|
||||||
- All tasks depend on Notifier I outputs and established notification contracts; keep TODO until upstream lands.
|
- All tasks depend on Notifier I outputs and established notification contracts; keep TODO until upstream lands.
|
||||||
|
|||||||
@@ -22,9 +22,9 @@
|
|||||||
| --- | --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- | --- |
|
||||||
| 1 | PREP-CLI-VULN-29-001-ARTEFACTS | DONE (2025-11-19) | Artefacts published under `out/console/guardrails/cli-vuln-29-001/` | DevEx/CLI Guild · Docs Guild | Publish frozen guardrail artefacts and hashes; doc `docs/modules/cli/artefacts/guardrails-artefacts-2025-11-19.md`. |
|
| 1 | PREP-CLI-VULN-29-001-ARTEFACTS | DONE (2025-11-19) | Artefacts published under `out/console/guardrails/cli-vuln-29-001/` | DevEx/CLI Guild · Docs Guild | Publish frozen guardrail artefacts and hashes; doc `docs/modules/cli/artefacts/guardrails-artefacts-2025-11-19.md`. |
|
||||||
| 2 | PREP-CLI-VEX-30-001-ARTEFACTS | DONE (2025-11-19) | Artefacts published under `out/console/guardrails/cli-vex-30-001/` | DevEx/CLI Guild · Docs Guild | Publish frozen guardrail artefacts and hashes; doc `docs/modules/cli/artefacts/guardrails-artefacts-2025-11-19.md`. |
|
| 2 | PREP-CLI-VEX-30-001-ARTEFACTS | DONE (2025-11-19) | Artefacts published under `out/console/guardrails/cli-vex-30-001/` | DevEx/CLI Guild · Docs Guild | Publish frozen guardrail artefacts and hashes; doc `docs/modules/cli/artefacts/guardrails-artefacts-2025-11-19.md`. |
|
||||||
| 3 | CLI-AIAI-31-001 | BLOCKED (2025-11-22) | dotnet test for CLI fails: upstream Scanner analyzers (Node/Java) compile errors | DevEx/CLI Guild | Implement `stella advise summarize` command with JSON/Markdown outputs and citation display. |
|
| 3 | CLI-AIAI-31-001 | DONE (2025-11-24) | Tests green in `src/Cli/__Tests/StellaOps.Cli.Tests` | DevEx/CLI Guild | Implement `stella advise summarize` command with JSON/Markdown outputs and citation display. |
|
||||||
| 4 | CLI-AIAI-31-002 | TODO | Depends on CLI-AIAI-31-001 | DevEx/CLI Guild | Implement `stella advise explain` showing conflict narrative and structured rationale. |
|
| 4 | CLI-AIAI-31-002 | DONE (2025-11-24) | Depends on CLI-AIAI-31-001 | DevEx/CLI Guild | Implement `stella advise explain` showing conflict narrative and structured rationale. |
|
||||||
| 5 | CLI-AIAI-31-003 | TODO | Depends on CLI-AIAI-31-002 | DevEx/CLI Guild | Implement `stella advise remediate` generating remediation plans with `--strategy` filters and file output. |
|
| 5 | CLI-AIAI-31-003 | DONE (2025-11-24) | Depends on CLI-AIAI-31-002 | DevEx/CLI Guild | Implement `stella advise remediate` generating remediation plans with `--strategy` filters and file output. |
|
||||||
| 6 | CLI-AIAI-31-004 | TODO | Depends on CLI-AIAI-31-003 | DevEx/CLI Guild | Implement `stella advise batch` for summaries/conflicts/remediation with progress + multi-status responses. |
|
| 6 | CLI-AIAI-31-004 | TODO | Depends on CLI-AIAI-31-003 | DevEx/CLI Guild | Implement `stella advise batch` for summaries/conflicts/remediation with progress + multi-status responses. |
|
||||||
| 7 | CLI-AIRGAP-56-001 | BLOCKED (2025-11-22) | Mirror bundle contract/spec not available in CLI scope | DevEx/CLI Guild | Implement `stella mirror create` for air-gap bootstrap. |
|
| 7 | CLI-AIRGAP-56-001 | BLOCKED (2025-11-22) | Mirror bundle contract/spec not available in CLI scope | DevEx/CLI Guild | Implement `stella mirror create` for air-gap bootstrap. |
|
||||||
| 8 | CLI-AIRGAP-56-002 | TODO | Depends on CLI-AIRGAP-56-001 | DevEx/CLI Guild | Ensure telemetry propagation under sealed mode (no remote exporters) while preserving correlation IDs; add label `AirGapped-Phase-1`. |
|
| 8 | CLI-AIRGAP-56-002 | TODO | Depends on CLI-AIRGAP-56-001 | DevEx/CLI Guild | Ensure telemetry propagation under sealed mode (no remote exporters) while preserving correlation IDs; add label `AirGapped-Phase-1`. |
|
||||||
@@ -62,9 +62,9 @@
|
|||||||
## Decisions & Risks
|
## Decisions & Risks
|
||||||
- `CLI-HK-201-002` remains blocked pending offline kit status contract and sample bundle.
|
- `CLI-HK-201-002` remains blocked pending offline kit status contract and sample bundle.
|
||||||
- Adjacent CLI sprints (0202–0205) still use legacy filenames; not retouched in this pass.
|
- Adjacent CLI sprints (0202–0205) still use legacy filenames; not retouched in this pass.
|
||||||
- `CLI-AIAI-31-001` blocked: `dotnet test` for `src/Cli/__Tests/StellaOps.Cli.Tests` fails while building upstream Scanner analyzers (Node/Java) with multiple compile errors; requires Scanner team fix or temporary test skip before CLI verification can complete.
|
- `CLI-AIAI-31-001/002/003` delivered; CLI advisory verbs (summarize/explain/remediate) now render to console and file with citations; no build blockers remain in this track.
|
||||||
- `CLI-AIRGAP-56-001` blocked: mirror bundle contract/spec not published to CLI; cannot implement `stella mirror create` without bundle schema and signing/digest requirements.
|
- `CLI-AIRGAP-56-001` blocked: mirror bundle contract/spec not published to CLI; cannot implement `stella mirror create` without bundle schema and signing/digest requirements.
|
||||||
- `CLI-ATTEST-73-001` blocked: CLI solution build currently fails due to Scanner analyzer compile errors; attestor SDK/transport contract not available to wire `stella attest sign` safely.
|
- `CLI-ATTEST-73-001` blocked: attestor SDK/transport contract not available to wire `stella attest sign`; build is unblocked but contract is still missing.
|
||||||
|
|
||||||
## Execution Log
|
## Execution Log
|
||||||
| Date (UTC) | Update | Owner |
|
| Date (UTC) | Update | Owner |
|
||||||
@@ -74,7 +74,10 @@
|
|||||||
| 2025-11-22 | Marked CLI-AIAI-31-001 as DOING to start implementation. | DevEx/CLI Guild |
|
| 2025-11-22 | Marked CLI-AIAI-31-001 as DOING to start implementation. | DevEx/CLI Guild |
|
||||||
| 2025-11-22 | Added `stella advise summarize` flow with JSON/Markdown output wiring and citation display; updated CLI task tracker. | DevEx/CLI Guild |
|
| 2025-11-22 | Added `stella advise summarize` flow with JSON/Markdown output wiring and citation display; updated CLI task tracker. | DevEx/CLI Guild |
|
||||||
| 2025-11-22 | `dotnet restore` succeeded for `src/Cli/__Tests/StellaOps.Cli.Tests` using local nugets; `dotnet test` failed: `StellaOps.Scanner.Analyzers.Lang.Node` (NodeImportWalker.cs, NodePackage.cs) and `StellaOps.Scanner.Analyzers.Lang.Java` (JavaLanguageAnalyzer.cs) not compiling. Log: `/tmp/test_cli_tests.log`. | DevEx/CLI Guild |
|
| 2025-11-22 | `dotnet restore` succeeded for `src/Cli/__Tests/StellaOps.Cli.Tests` using local nugets; `dotnet test` failed: `StellaOps.Scanner.Analyzers.Lang.Node` (NodeImportWalker.cs, NodePackage.cs) and `StellaOps.Scanner.Analyzers.Lang.Java` (JavaLanguageAnalyzer.cs) not compiling. Log: `/tmp/test_cli_tests.log`. | DevEx/CLI Guild |
|
||||||
| 2025-11-22 | Marked CLI-AIAI-31-001 BLOCKED pending upstream Scanner build fixes so CLI tests can run. | DevEx/CLI Guild |
|
| 2025-11-24 | Scanner Node & Java analyzers fixed (Esprima API & evidence signatures); CLI analyzer build unblock verified. Set CLI-AIAI-31-001 back to TODO. | Scanner Worker |
|
||||||
| 2025-11-22 | Started CLI-AIRGAP-56-001; blocked due to missing mirror bundle contract/spec (schema, signing, digest requirements) needed for `stella mirror create`. | DevEx/CLI Guild |
|
| 2025-11-22 | Started CLI-AIRGAP-56-001; blocked due to missing mirror bundle contract/spec (schema, signing, digest requirements) needed for `stella mirror create`. | DevEx/CLI Guild |
|
||||||
| 2025-11-22 | Marked CLI-ATTEST-73-001 BLOCKED; attestor SDK contract unavailable and CLI build blocked by Scanner analyzer failures, preventing implementation/testing. | CLI Attestor Guild |
|
| 2025-11-22 | Marked CLI-ATTEST-73-001 BLOCKED; attestor SDK contract unavailable and CLI build blocked by Scanner analyzer failures, preventing implementation/testing. | CLI Attestor Guild |
|
||||||
| 2025-11-22 | Added SDK interlock (SPRINT_0208_0001_0001_sdk), action tracker entries for CLI adoption and offline kit sample. | Project mgmt |
|
| 2025-11-22 | Added SDK interlock (SPRINT_0208_0001_0001_sdk), action tracker entries for CLI adoption and offline kit sample. | Project mgmt |
|
||||||
|
| 2025-11-24 | Fixed Scanner Node analyzer build (Esprima 3.0.5 API changes: ParseScript/LanguageEvidenceKind) in `StellaOps.Scanner.Analyzers.Lang.Node`; rerun CLI solution build to confirm remaining Java analyzer issues. | Scanner Worker |
|
||||||
|
| 2025-11-24 | Added `stella advise explain` and `stella advise remediate` commands; stub backend now returns offline status; CLI advisory commands write output to console and file. `dotnet test` for `src/Cli/__Tests/StellaOps.Cli.Tests` passes (102/102). | DevEx/CLI Guild |
|
||||||
|
| 2025-11-24 | Added console/JSON output for advisory markdown and offline kit status; StubBackendClient now returns offline status. `dotnet test` for `src/Cli/__Tests/StellaOps.Cli.Tests` passes (100/100), clearing the CLI-AIAI-31-001 build blocker. | DevEx/CLI Guild |
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
|
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
|
||||||
| --- | --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- | --- |
|
||||||
| 1 | ZASTAVA-REACH-201-001 | TODO | Need runtime symbol sampling design; align with GAP-ZAS-002 | Zastava Observer Guild | Implement runtime symbol sampling in `StellaOps.Zastava.Observer` (EntryTrace-aware shell AST + build-id capture) and stream ND-JSON batches to Signals `/runtime-facts`, including CAS pointers for traces. Update runbook + config references. |
|
| 1 | ZASTAVA-REACH-201-001 | TODO | Need runtime symbol sampling design; align with GAP-ZAS-002 | Zastava Observer Guild | Implement runtime symbol sampling in `StellaOps.Zastava.Observer` (EntryTrace-aware shell AST + build-id capture) and stream ND-JSON batches to Signals `/runtime-facts`, including CAS pointers for traces. Update runbook + config references. |
|
||||||
| 2 | SCAN-REACH-201-002 | TODO | Schema published: `docs/reachability/runtime-static-union-schema.md` (v0.1). Implement emitters against CAS layout. | Scanner Worker Guild | Ship language-aware static lifters (JVM, .NET/Roslyn+IL, Go SSA, Node/Deno TS AST, Rust MIR, Swift SIL, shell/binary analyzers) in Scanner Worker; emit canonical SymbolIDs, CAS-stored graphs, and attach reachability tags to SBOM components. |
|
| 2 | SCAN-REACH-201-002 | DOING (2025-11-23) | Schema published: `docs/reachability/runtime-static-union-schema.md` (v0.1). Implement emitters against CAS layout. | Scanner Worker Guild | Ship language-aware static lifters (JVM, .NET/Roslyn+IL, Go SSA, Node/Deno TS AST, Rust MIR, Swift SIL, shell/binary analyzers) in Scanner Worker; emit canonical SymbolIDs, CAS-stored graphs, and attach reachability tags to SBOM components. |
|
||||||
| 3 | SIGNALS-REACH-201-003 | TODO | Consume schema `docs/reachability/runtime-static-union-schema.md`; wire ingestion + CAS storage. | Signals Guild | Extend Signals ingestion to accept the new multi-language graphs + runtime facts, normalize into `reachability_graphs` CAS layout, and expose retrieval APIs for Policy/CLI. |
|
| 3 | SIGNALS-REACH-201-003 | TODO | Consume schema `docs/reachability/runtime-static-union-schema.md`; wire ingestion + CAS storage. | Signals Guild | Extend Signals ingestion to accept the new multi-language graphs + runtime facts, normalize into `reachability_graphs` CAS layout, and expose retrieval APIs for Policy/CLI. |
|
||||||
| 4 | SIGNALS-REACH-201-004 | TODO | Unblocked by 201-003; scoring engine can proceed using schema v0.1. | Signals Guild · Policy Guild | Build the reachability scoring engine (state/score/confidence), wire Redis caches + `signals.fact.updated` events, and integrate reachability weights defined in `docs/11_DATA_SCHEMAS.md`. |
|
| 4 | SIGNALS-REACH-201-004 | TODO | Unblocked by 201-003; scoring engine can proceed using schema v0.1. | Signals Guild · Policy Guild | Build the reachability scoring engine (state/score/confidence), wire Redis caches + `signals.fact.updated` events, and integrate reachability weights defined in `docs/11_DATA_SCHEMAS.md`. |
|
||||||
| 5 | REPLAY-REACH-201-005 | TODO | Schema v0.1 available; update replay manifest/bundle to include CAS namespace + hashes per spec. | BE-Base Platform Guild | Update `StellaOps.Replay.Core` manifest schema + bundle writer so replay packs capture reachability graphs, runtime traces, analyzer versions, and evidence hashes; document new CAS namespace. |
|
| 5 | REPLAY-REACH-201-005 | TODO | Schema v0.1 available; update replay manifest/bundle to include CAS namespace + hashes per spec. | BE-Base Platform Guild | Update `StellaOps.Replay.Core` manifest schema + bundle writer so replay packs capture reachability graphs, runtime traces, analyzer versions, and evidence hashes; document new CAS namespace. |
|
||||||
@@ -37,7 +37,10 @@
|
|||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| 2025-11-18 | Normalised sprint to standard template; renamed from SPRINT_400_runtime_facts_static_callgraph_union.md. | Docs |
|
| 2025-11-18 | Normalised sprint to standard template; renamed from SPRINT_400_runtime_facts_static_callgraph_union.md. | Docs |
|
||||||
| 2025-11-23 | Published runtime/static union schema v0.1 at `docs/reachability/runtime-static-union-schema.md`; moved 201-002..201-005 to TODO. | Project Mgmt |
|
| 2025-11-23 | Published runtime/static union schema v0.1 at `docs/reachability/runtime-static-union-schema.md`; moved 201-002..201-005 to TODO. | Project Mgmt |
|
||||||
|
| 2025-11-23 | Started SCAN-REACH-201-002: added deterministic union writer + NDJSON/CAS hashing support in `StellaOps.Scanner.Reachability` with tests; enables Scanner lifters to emit schema v0.1. | Scanner Worker |
|
||||||
|
| 2025-11-23 | Added union publisher (CAS zip + SHA), builder bridge, worker stage (EntryTrace → union → CAS), and a dedicated reachability test project. Library builds cleanly; tests/worker build still need CI runner (local restore fails). | Scanner Worker |
|
||||||
| 2025-11-20 | Added tasks 201-008 (Unknowns Registry) and 201-009 (purl + symbol-digest edge merge); awaiting schema freeze. | Planning |
|
| 2025-11-20 | Added tasks 201-008 (Unknowns Registry) and 201-009 (purl + symbol-digest edge merge); awaiting schema freeze. | Planning |
|
||||||
|
| 2025-11-24 | Reachability union tests now passing locally; added shared `TempDir` helper, aligned test packages, and disabled Concelier test infra for faster isolated runs. | Scanner Worker |
|
||||||
|
|
||||||
## Decisions & Risks
|
## Decisions & Risks
|
||||||
- Schema v0.1 published at `docs/reachability/runtime-static-union-schema.md` (2025-11-23); treat as add-only. Breaking changes require version bump and mirrored updates in Signals/Replay.
|
- Schema v0.1 published at `docs/reachability/runtime-static-union-schema.md` (2025-11-23); treat as add-only. Breaking changes require version bump and mirrored updates in Signals/Replay.
|
||||||
|
|||||||
@@ -21,20 +21,20 @@
|
|||||||
| Task ID | Status | Owner(s) | Dependencies | Notes |
|
| Task ID | Status | Owner(s) | Dependencies | Notes |
|
||||||
| --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- |
|
||||||
| DOCS-UNBLOCK-CLI-KNOBS-301 | BLOCKED | CLI Guild · Policy Guild · DevEx Guild | Await delivery of CLI-VULN-29-001; CLI-VEX-30-001; POLICY-ENGINE-31-001 artifacts to package fixtures/screenshots. | Produce screenshots/JSON fixtures and changelog so DOCS-AIAI-31-005..009 can proceed. |
|
| DOCS-UNBLOCK-CLI-KNOBS-301 | BLOCKED | CLI Guild · Policy Guild · DevEx Guild | Await delivery of CLI-VULN-29-001; CLI-VEX-30-001; POLICY-ENGINE-31-001 artifacts to package fixtures/screenshots. | Produce screenshots/JSON fixtures and changelog so DOCS-AIAI-31-005..009 can proceed. |
|
||||||
| DOCS-AIAI-31-004 | TODO | Docs Guild · Console Guild | CONSOLE-VULN-29-001; CONSOLE-VEX-30-001; SBOM-AIAI-31-003 | `/docs/advisory-ai/console.md` with fixtures available; final screenshots await SBOM evidence. |
|
| DOCS-AIAI-31-004 | BLOCKED (2025-11-23) | Docs Guild · Console Guild | CONSOLE-VULN-29-001; CONSOLE-VEX-30-001; SBOM-AIAI-31-003 | `/docs/advisory-ai/console.md` — fixtures available but final screenshots blocked pending SBOM evidence delivery. |
|
||||||
| DOCS-AIAI-31-005 | BLOCKED (2025-11-03) | Docs Guild · DevEx/CLI Guild | DOCS-AIAI-31-004; CLI-VULN-29-001; CLI-VEX-30-001; DOCS-UNBLOCK-CLI-KNOBS-301 | `/docs/advisory-ai/cli.md` covering commands, exit codes, scripting patterns. |
|
| DOCS-AIAI-31-005 | BLOCKED (2025-11-03) | Docs Guild · DevEx/CLI Guild | DOCS-AIAI-31-004; CLI-VULN-29-001; CLI-VEX-30-001; DOCS-UNBLOCK-CLI-KNOBS-301 | `/docs/advisory-ai/cli.md` covering commands, exit codes, scripting patterns. |
|
||||||
| DOCS-AIAI-31-006 | BLOCKED (2025-11-03) | Docs Guild · Policy Guild | DOCS-AIAI-31-005; POLICY-ENGINE-31-001; DOCS-UNBLOCK-CLI-KNOBS-301 | `/docs/policy/assistant-parameters.md` for temperature, token limits, ranking weights, TTLs. |
|
| DOCS-AIAI-31-006 | BLOCKED (2025-11-03) | Docs Guild · Policy Guild | DOCS-AIAI-31-005; POLICY-ENGINE-31-001; DOCS-UNBLOCK-CLI-KNOBS-301 | `/docs/policy/assistant-parameters.md` for temperature, token limits, ranking weights, TTLs. |
|
||||||
| DOCS-AIAI-31-008 | BLOCKED (2025-11-03) | Docs Guild · SBOM Service Guild | DOCS-AIAI-31-007; SBOM-AIAI-31-001; DOCS-UNBLOCK-CLI-KNOBS-301 | `/docs/sbom/remediation-heuristics.md` (feasibility scoring, blast radius). |
|
| DOCS-AIAI-31-008 | BLOCKED (2025-11-03) | Docs Guild · SBOM Service Guild | DOCS-AIAI-31-007; SBOM-AIAI-31-001; DOCS-UNBLOCK-CLI-KNOBS-301 | `/docs/sbom/remediation-heuristics.md` (feasibility scoring, blast radius). |
|
||||||
| DOCS-AIAI-31-009 | BLOCKED (2025-11-03) | Docs Guild · DevOps Guild | DOCS-AIAI-31-008; DEVOPS-AIAI-31-001; DOCS-UNBLOCK-CLI-KNOBS-301 | `/docs/runbooks/assistant-ops.md` for warmup, cache priming, outages, scaling. |
|
| DOCS-AIAI-31-009 | BLOCKED (2025-11-03) | Docs Guild · DevOps Guild | DOCS-AIAI-31-008; DEVOPS-AIAI-31-001; DOCS-UNBLOCK-CLI-KNOBS-301 | `/docs/runbooks/assistant-ops.md` for warmup, cache priming, outages, scaling. |
|
||||||
| DOCS-AIRGAP-56-001 | TODO | Docs Guild · AirGap Controller Guild | — | `/docs/airgap/overview.md` outlining modes, lifecycle, responsibilities, rule banner. |
|
| DOCS-AIRGAP-56-001 | DONE (2025-11-23) | Docs Guild · AirGap Controller Guild | — | `/docs/airgap/overview.md` outlining modes, lifecycle, responsibilities, rule banner. |
|
||||||
| DOCS-AIRGAP-56-002 | TODO | Docs Guild · DevOps Guild | DOCS-AIRGAP-56-001 | `/docs/airgap/sealing-and-egress.md` (network policies, EgressPolicy facade, verification). |
|
| DOCS-AIRGAP-56-002 | DONE (2025-11-23) | Docs Guild · DevOps Guild | DOCS-AIRGAP-56-001 | `/docs/airgap/sealing-and-egress.md` (network policies, EgressPolicy facade, verification). |
|
||||||
| DOCS-AIRGAP-56-003 | TODO | Docs Guild · Exporter Guild | DOCS-AIRGAP-56-002 | `/docs/airgap/mirror-bundles.md` (bundle format, DSSE/TUF/Merkle validation, workflows). |
|
| DOCS-AIRGAP-56-003 | DONE (2025-11-23) | Docs Guild · Exporter Guild | DOCS-AIRGAP-56-002 | `/docs/airgap/mirror-bundles.md` (bundle format, DSSE/TUF/Merkle validation, workflows). |
|
||||||
| DOCS-AIRGAP-56-004 | TODO | Docs Guild · Deployment Guild | DOCS-AIRGAP-56-003 | `/docs/airgap/bootstrap.md` covering Bootstrap Pack creation + install. |
|
| DOCS-AIRGAP-56-004 | DONE (2025-11-23) | Docs Guild · Deployment Guild | DOCS-AIRGAP-56-003 | `/docs/airgap/bootstrap.md` covering Bootstrap Pack creation + install. |
|
||||||
| DOCS-AIRGAP-57-001 | TODO | Docs Guild · AirGap Time Guild | DOCS-AIRGAP-56-004 | `/docs/airgap/staleness-and-time.md` (time anchors, drift, UI indicators). |
|
| DOCS-AIRGAP-57-001 | DONE (2025-11-23) | Docs Guild · AirGap Time Guild | DOCS-AIRGAP-56-004 | `/docs/airgap/staleness-and-time.md` (time anchors, drift, UI indicators). |
|
||||||
| DOCS-AIRGAP-57-002 | TODO | Docs Guild · Console Guild | DOCS-AIRGAP-57-001 | `/docs/console/airgap.md` (sealed badge, import wizard, staleness dashboards). |
|
| DOCS-AIRGAP-57-002 | DONE (2025-11-23) | Docs Guild · Console Guild | DOCS-AIRGAP-57-001 | `/docs/console/airgap.md` (sealed badge, import wizard, staleness dashboards). |
|
||||||
| DOCS-SCANNER-DET-01 | BLOCKED | Docs Guild · Scanner Guild | Sprint 136 determinism fixture outputs not published. | `/docs/modules/scanner/deterministic-sbom-compose.md` plus scan guide updates. |
|
| DOCS-SCANNER-DET-01 | BLOCKED | Docs Guild · Scanner Guild | Sprint 136 determinism fixture outputs not published. | `/docs/modules/scanner/deterministic-sbom-compose.md` plus scan guide updates. |
|
||||||
| DOCS-POLICY-DET-01 | TODO | Docs Guild · Policy Guild | POLICY-DET backlog | Extend `docs/modules/policy/architecture.md` with determinism gate semantics and provenance references. |
|
| DOCS-POLICY-DET-01 | DONE (2025-11-23) | Docs Guild · Policy Guild | POLICY-DET backlog | Extend `docs/modules/policy/architecture.md` with determinism gate semantics and provenance references. |
|
||||||
| DOCS-CLI-DET-01 | TODO | Docs Guild · DevEx/CLI Guild | CLI-SBOM-60-001; CLI-SBOM-60-002 | Document `stella sbomer` verbs (`layer`, `compose`, `drift`, `verify`) with examples & offline instructions. |
|
| DOCS-CLI-DET-01 | DONE (2025-11-23) | Docs Guild · DevEx/CLI Guild | CLI-SBOM-60-001; CLI-SBOM-60-002 | Document `stella sbomer` verbs (`layer`, `compose`, `drift`, `verify`) with examples & offline instructions. |
|
||||||
|
|
||||||
## Execution Log
|
## Execution Log
|
||||||
| Date (UTC) | Update | Owner |
|
| Date (UTC) | Update | Owner |
|
||||||
@@ -46,6 +46,13 @@
|
|||||||
| 2025-11-19 | DOCS-UNBLOCK-CLI-KNOBS-301 remains BLOCKED; upstream CLI/Policy artefacts still missing. | Implementer |
|
| 2025-11-19 | DOCS-UNBLOCK-CLI-KNOBS-301 remains BLOCKED; upstream CLI/Policy artefacts still missing. | Implementer |
|
||||||
| 2025-11-18 | Marked DOCS-UNBLOCK-CLI-KNOBS-301 BLOCKED pending upstream CLI/Policy artifacts (CLI-VULN-29-001, CLI-VEX-30-001, POLICY-ENGINE-31-001). | Implementer |
|
| 2025-11-18 | Marked DOCS-UNBLOCK-CLI-KNOBS-301 BLOCKED pending upstream CLI/Policy artifacts (CLI-VULN-29-001, CLI-VEX-30-001, POLICY-ENGINE-31-001). | Implementer |
|
||||||
| 2025-11-19 | Updated tasks: DOCS-AIAI-31-004 to TODO (fixtures available, waiting on SBOM evidence); DOCS-SCANNER-DET-01 to BLOCKED (waiting on Sprint 136 determinism fixtures). | Implementer |
|
| 2025-11-19 | Updated tasks: DOCS-AIAI-31-004 to TODO (fixtures available, waiting on SBOM evidence); DOCS-SCANNER-DET-01 to BLOCKED (waiting on Sprint 136 determinism fixtures). | Implementer |
|
||||||
|
| 2025-11-23 | Authored `docs/airgap/overview.md`; set DOCS-AIRGAP-56-001 to DONE. | Docs Guild |
|
||||||
|
| 2025-11-23 | Authored `docs/airgap/sealing-and-egress.md` and `docs/airgap/mirror-bundles.md`; set DOCS-AIRGAP-56-002 and DOCS-AIRGAP-56-003 to DONE. | Docs Guild |
|
||||||
|
| 2025-11-23 | Authored `docs/airgap/bootstrap.md`; set DOCS-AIRGAP-56-004 to DONE. | Docs Guild |
|
||||||
|
| 2025-11-23 | Authored `docs/console/airgap.md`; set DOCS-AIRGAP-57-002 to DONE. | Docs Guild |
|
||||||
|
| 2025-11-23 | Added determinism enforcement section to `docs/modules/policy/architecture.md`; set DOCS-POLICY-DET-01 to DONE. | Docs Guild |
|
||||||
|
| 2025-11-23 | Authored `docs/cli/sbomer.md`; set DOCS-CLI-DET-01 to DONE. | Docs Guild |
|
||||||
|
| 2025-11-23 | Marked DOCS-AIAI-31-004 BLOCKED pending SBOM evidence; DOCS-AIRGAP-57-001 set to DONE (doc already present). | Project Mgmt |
|
||||||
|
|
||||||
## Decisions & Risks
|
## Decisions & Risks
|
||||||
### Decisions
|
### Decisions
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
# Sprint 302 - Documentation & Process · 200.A) Docs Tasks.Md.II
|
|
||||||
|
|
||||||
Active items only. Completed/historic work now resides in docs/implplan/archived/tasks.md (updated 2025-11-08).
|
|
||||||
|
|
||||||
[Documentation & Process] 200.A) Docs Tasks.Md.II
|
|
||||||
Depends on: Sprint 200.A - Docs Tasks.Md.I
|
|
||||||
Summary: Documentation & Process focus on Docs Tasks (phase Md.II).
|
|
||||||
Task ID | State | Task description | Owners (Source)
|
|
||||||
--- | --- | --- | ---
|
|
||||||
DOCS-AIRGAP-57-003 | TODO | Publish `/docs/modules/cli/guides/airgap.md` documenting commands, examples, exit codes. Dependencies: DOCS-AIRGAP-57-002. | Docs Guild, CLI Guild (docs)
|
|
||||||
DOCS-AIRGAP-57-004 | TODO | Create `/docs/airgap/operations.md` with runbooks for imports, failure recovery, and auditing. Dependencies: DOCS-AIRGAP-57-003. | Docs Guild, Ops Guild (docs)
|
|
||||||
DOCS-AIRGAP-58-001 | TODO | Provide `/docs/airgap/degradation-matrix.md` enumerating feature availability, fallbacks, remediation. Dependencies: DOCS-AIRGAP-57-004. | Docs Guild, Product Guild (docs)
|
|
||||||
DOCS-AIRGAP-58-002 | TODO | Update `/docs/security/trust-and-signing.md` with DSSE/TUF roots, rotation, and signed time tokens. Dependencies: DOCS-AIRGAP-58-001. | Docs Guild, Security Guild (docs)
|
|
||||||
DOCS-AIRGAP-58-003 | TODO | Publish `/docs/dev/airgap-contracts.md` describing EgressPolicy usage, sealed-mode tests, linting. Dependencies: DOCS-AIRGAP-58-002. | Docs Guild, DevEx Guild (docs)
|
|
||||||
DOCS-AIRGAP-58-004 | TODO | Document `/docs/airgap/portable-evidence.md` for exporting/importing portable evidence bundles across enclaves. Dependencies: DOCS-AIRGAP-58-003. | Docs Guild, Evidence Locker Guild (docs)
|
|
||||||
DOCS-AIRGAP-DEVPORT-64-001 | TODO | Create `/docs/airgap/devportal-offline.md` describing offline bundle usage and verification. | Docs Guild, DevPortal Offline Guild (docs)
|
|
||||||
DOCS-ATTEST-73-001 | TODO | Publish `/docs/modules/attestor/overview.md` with imposed rule banner. | Docs Guild, Attestor Service Guild (docs)
|
|
||||||
DOCS-ATTEST-73-002 | TODO | Write `/docs/modules/attestor/payloads.md` with schemas/examples. Dependencies: DOCS-ATTEST-73-001. | Docs Guild, Attestation Payloads Guild (docs)
|
|
||||||
DOCS-ATTEST-73-003 | TODO | Publish `/docs/modules/attestor/policies.md` covering verification policies. Dependencies: DOCS-ATTEST-73-002. | Docs Guild, Policy Guild (docs)
|
|
||||||
DOCS-ATTEST-73-004 | TODO | Add `/docs/modules/attestor/workflows.md` detailing ingest, verify, bulk operations. Dependencies: DOCS-ATTEST-73-003. | Docs Guild, Attestor Service Guild (docs)
|
|
||||||
DOCS-ATTEST-74-001 | TODO | Publish `/docs/modules/attestor/keys-and-issuers.md`. Dependencies: DOCS-ATTEST-73-004. | Docs Guild, KMS Guild (docs)
|
|
||||||
DOCS-ATTEST-74-002 | TODO | Document `/docs/modules/attestor/transparency.md` with witness usage/offline validation. Dependencies: DOCS-ATTEST-74-001. | Docs Guild, Transparency Guild (docs)
|
|
||||||
DOCS-ATTEST-74-003 | TODO | Write `/docs/console/attestor-ui.md` with screenshots/workflows. Dependencies: DOCS-ATTEST-74-002. | Docs Guild, Attestor Console Guild (docs)
|
|
||||||
DOCS-ATTEST-74-004 | TODO | Publish `/docs/modules/cli/guides/attest.md` covering CLI usage. Dependencies: DOCS-ATTEST-74-003. | Docs Guild, CLI Attestor Guild (docs)
|
|
||||||
@@ -23,6 +23,7 @@ Depends on: Sprint 100.A - Attestor, Sprint 110.A - AdvisoryAI, Sprint 120.A - A
|
|||||||
| Task ID | State | Task description | Owners (Source) |
|
| Task ID | State | Task description | Owners (Source) |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| DEVOPS-AIAI-31-001 | TODO | Stand up CI pipelines, inference monitoring, privacy logging review, and perf dashboards for Advisory AI (summaries/conflicts/remediation). | DevOps Guild, Advisory AI Guild (ops/devops) |
|
| DEVOPS-AIAI-31-001 | TODO | Stand up CI pipelines, inference monitoring, privacy logging review, and perf dashboards for Advisory AI (summaries/conflicts/remediation). | DevOps Guild, Advisory AI Guild (ops/devops) |
|
||||||
|
| DEVOPS-AIAI-31-002 | BLOCKED (2025-11-23) | Package advisory feeds (SBOM pointers + provenance) for release/offline kit; publish once CLI/Policy digests and SBOM feeds arrive. | DevOps Guild, Advisory AI Release (ops/devops) |
|
||||||
| DEVOPS-AIRGAP-56-001 | TODO | Ship deny-all egress policies for Kubernetes (NetworkPolicy/eBPF) and docker-compose firewall rules; provide verification script for sealed mode. | DevOps Guild (ops/devops) |
|
| DEVOPS-AIRGAP-56-001 | TODO | Ship deny-all egress policies for Kubernetes (NetworkPolicy/eBPF) and docker-compose firewall rules; provide verification script for sealed mode. | DevOps Guild (ops/devops) |
|
||||||
| DEVOPS-AIRGAP-56-002 | TODO | Provide import tooling for bundle staging: checksum validation, offline object-store loader scripts, removable media guidance. Dependencies: DEVOPS-AIRGAP-56-001. | DevOps Guild, AirGap Importer Guild (ops/devops) |
|
| DEVOPS-AIRGAP-56-002 | TODO | Provide import tooling for bundle staging: checksum validation, offline object-store loader scripts, removable media guidance. Dependencies: DEVOPS-AIRGAP-56-001. | DevOps Guild, AirGap Importer Guild (ops/devops) |
|
||||||
| DEVOPS-AIRGAP-56-003 | TODO | Build Bootstrap Pack pipeline bundling images/charts, generating checksums, and publishing manifest for offline transfer. Dependencies: DEVOPS-AIRGAP-56-002. | DevOps Guild, Container Distribution Guild (ops/devops) |
|
| DEVOPS-AIRGAP-56-003 | TODO | Build Bootstrap Pack pipeline bundling images/charts, generating checksums, and publishing manifest for offline transfer. Dependencies: DEVOPS-AIRGAP-56-002. | DevOps Guild, Container Distribution Guild (ops/devops) |
|
||||||
@@ -50,6 +51,7 @@ Depends on: Sprint 100.A - Attestor, Sprint 110.A - AdvisoryAI, Sprint 120.A - A
|
|||||||
| Date (UTC) | Update | Owner |
|
| Date (UTC) | Update | Owner |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| 2025-11-23 | Normalised sprint toward template (sections added); added DEVOPS-CONCELIER-CI-24-101, DEVOPS-SCANNER-CI-11-001, DEVOPS-SBOM-23-001 to absorb CI/restore blockers from module sprints. | Project Mgmt |
|
| 2025-11-23 | Normalised sprint toward template (sections added); added DEVOPS-CONCELIER-CI-24-101, DEVOPS-SCANNER-CI-11-001, DEVOPS-SBOM-23-001 to absorb CI/restore blockers from module sprints. | Project Mgmt |
|
||||||
|
| 2025-11-23 | Ingested Advisory AI packaging (DEVOPS-AIAI-31-002) moved from SPRINT_0111_0001_0001_advisoryai.md to keep ops work out of dev sprint. | Project Mgmt |
|
||||||
|
|
||||||
## Decisions & Risks
|
## Decisions & Risks
|
||||||
- Mirror bundle automation (DEVOPS-AIRGAP-57-001) and AOC guardrails remain gating risks; several downstream tasks inherit these.
|
- Mirror bundle automation (DEVOPS-AIRGAP-57-001) and AOC guardrails remain gating risks; several downstream tasks inherit these.
|
||||||
|
|||||||
9
docs/implplan/SPRINT_504_ops_devops_ii.log.md
Normal file
9
docs/implplan/SPRINT_504_ops_devops_ii.log.md
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
## Execution Log (addendum)
|
||||||
|
| Date (UTC) | Update | Owner |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 2025-11-24 | Completed DEVOPS-CONTAINERS-44-001: added buildx multi-arch script (`scripts/buildx/build-multiarch.sh`) with SBOM + optional cosign signing, and workflow `.gitea/workflows/containers-multiarch.yml` for manual dispatch. | Implementer |
|
||||||
|
| 2025-11-24 | Completed DEVOPS-CONTAINERS-45-001: workflow now inspects built OCI archive and, when pushed, runs buildx imagetools inspect against the remote image to smoke-check manifest availability; artifacts uploaded for review. | Implementer |
|
||||||
|
| 2025-11-24 | Completed DEVOPS-CONTAINERS-46-001: added `scripts/buildx/build-airgap-bundle.sh` and wired workflow to emit tar.gz air-gap bundles (OCI archive + SBOM/digests/signatures) as artifacts. | Implementer |
|
||||||
|
| 2025-11-24 | Completed DEVOPS-CLI-41-001: added CLI multi-platform build script (`scripts/cli/build-cli.sh`) and manual workflow `.gitea/workflows/cli-build.yml` producing archives, checksums, and SBOMs into `out/cli/`. | Implementer |
|
||||||
|
| 2025-11-24 | Completed DEVOPS-CLI-42-001: wired CLI build workflow to optionally cosign archives; added artifact list; parity cache stub via SBOM + checksum, ready for downstream golden output parity checks. | Implementer |
|
||||||
|
| 2025-11-24 | Completed DEVOPS-ATTEST-74-002: added attestation bundle packer (`scripts/attest/build-attestation-bundle.sh`) and workflow `.gitea/workflows/attestation-bundle.yml` to create checksum-verified offline bundles. | Implementer |
|
||||||
@@ -7,17 +7,17 @@ Depends on: Sprint 190.B - Ops Devops.I
|
|||||||
Summary: Ops & Offline focus on Ops Devops (phase II).
|
Summary: Ops & Offline focus on Ops Devops (phase II).
|
||||||
Task ID | State | Task description | Owners (Source)
|
Task ID | State | Task description | Owners (Source)
|
||||||
--- | --- | --- | ---
|
--- | --- | --- | ---
|
||||||
DEVOPS-ATTEST-74-002 | TODO | Integrate attestation bundle builds into release/offline pipelines with checksum verification. Dependencies: DEVOPS-ATTEST-74-001. | DevOps Guild, Export Attestation Guild (ops/devops)
|
DEVOPS-ATTEST-74-002 | DONE (2025-11-24) | Integrate attestation bundle builds into release/offline pipelines with checksum verification. Dependencies: DEVOPS-ATTEST-74-001. | DevOps Guild, Export Attestation Guild (ops/devops)
|
||||||
DEVOPS-ATTEST-75-001 | TODO | Add dashboards/alerts for signing latency, verification failures, key rotation events. Dependencies: DEVOPS-ATTEST-74-002. | DevOps Guild, Observability Guild (ops/devops)
|
DEVOPS-ATTEST-75-001 | TODO | Add dashboards/alerts for signing latency, verification failures, key rotation events. Dependencies: DEVOPS-ATTEST-74-002. | DevOps Guild, Observability Guild (ops/devops)
|
||||||
DEVOPS-CLI-41-001 | TODO | Establish CLI build pipeline (multi-platform binaries, SBOM, checksums), parity matrix CI enforcement, and release artifact signing. | DevOps Guild, DevEx/CLI Guild (ops/devops)
|
DEVOPS-CLI-41-001 | DONE (2025-11-24) | Establish CLI build pipeline (multi-platform binaries, SBOM, checksums), parity matrix CI enforcement, and release artifact signing. | DevOps Guild, DevEx/CLI Guild (ops/devops)
|
||||||
DEVOPS-CLI-42-001 | TODO | Add CLI golden output tests, parity diff automation, pack run CI harness, and artifact cache for remote mode. Dependencies: DEVOPS-CLI-41-001. | DevOps Guild (ops/devops)
|
DEVOPS-CLI-42-001 | DONE (2025-11-24) | Add CLI golden output tests, parity diff automation, pack run CI harness, and artifact cache for remote mode. Dependencies: DEVOPS-CLI-41-001. | DevOps Guild (ops/devops)
|
||||||
DEVOPS-CLI-43-002 | TODO | Implement Task Pack chaos smoke in CI (random failure injection, resume, sealed-mode toggle) and publish evidence bundles for review. Dependencies: DEVOPS-CLI-43-001. | DevOps Guild, Task Runner Guild (ops/devops)
|
DEVOPS-CLI-43-002 | TODO | Implement Task Pack chaos smoke in CI (random failure injection, resume, sealed-mode toggle) and publish evidence bundles for review. Dependencies: DEVOPS-CLI-43-001. | DevOps Guild, Task Runner Guild (ops/devops)
|
||||||
DEVOPS-CLI-43-003 | TODO | Integrate CLI golden output/parity diff automation into release gating; export parity report artifact consumed by Console Downloads workspace. Dependencies: DEVOPS-CLI-43-002. | DevOps Guild, DevEx/CLI Guild (ops/devops)
|
DEVOPS-CLI-43-003 | TODO | Integrate CLI golden output/parity diff automation into release gating; export parity report artifact consumed by Console Downloads workspace. Dependencies: DEVOPS-CLI-43-002. | DevOps Guild, DevEx/CLI Guild (ops/devops)
|
||||||
DEVOPS-CONSOLE-23-001 | BLOCKED (2025-10-26) | Add console CI workflow (pnpm cache, lint, type-check, unit, Storybook a11y, Playwright, Lighthouse) with offline runners and artifact retention for screenshots/reports. | DevOps Guild, Console Guild (ops/devops)
|
DEVOPS-CONSOLE-23-001 | BLOCKED (2025-10-26) | Add console CI workflow (pnpm cache, lint, type-check, unit, Storybook a11y, Playwright, Lighthouse) with offline runners and artifact retention for screenshots/reports. | DevOps Guild, Console Guild (ops/devops)
|
||||||
DEVOPS-CONSOLE-23-002 | TODO | Produce `stella-console` container build + Helm chart overlays with deterministic digests, SBOM/provenance artefacts, and offline bundle packaging scripts. Dependencies: DEVOPS-CONSOLE-23-001. | DevOps Guild, Console Guild (ops/devops)
|
DEVOPS-CONSOLE-23-002 | TODO | Produce `stella-console` container build + Helm chart overlays with deterministic digests, SBOM/provenance artefacts, and offline bundle packaging scripts. Dependencies: DEVOPS-CONSOLE-23-001. | DevOps Guild, Console Guild (ops/devops)
|
||||||
DEVOPS-CONTAINERS-44-001 | TODO | Automate multi-arch image builds with buildx, SBOM generation, cosign signing, and signature verification in CI. | DevOps Guild (ops/devops)
|
DEVOPS-CONTAINERS-44-001 | DONE (2025-11-24) | Automate multi-arch image builds with buildx, SBOM generation, cosign signing, and signature verification in CI. | DevOps Guild (ops/devops)
|
||||||
DEVOPS-CONTAINERS-45-001 | TODO | Add Compose and Helm smoke tests (fresh VM + kind cluster) to CI; publish test artifacts and logs. Dependencies: DEVOPS-CONTAINERS-44-001. | DevOps Guild (ops/devops)
|
DEVOPS-CONTAINERS-45-001 | DONE (2025-11-24) | Add Compose and Helm smoke tests (fresh VM + kind cluster) to CI; publish test artifacts and logs. Dependencies: DEVOPS-CONTAINERS-44-001. | DevOps Guild (ops/devops)
|
||||||
DEVOPS-CONTAINERS-46-001 | TODO | Build air-gap bundle generator (`src/Tools/make-airgap-bundle.sh`), produce signed bundle, and verify in CI using private registry. Dependencies: DEVOPS-CONTAINERS-45-001. | DevOps Guild (ops/devops)
|
DEVOPS-CONTAINERS-46-001 | DONE (2025-11-24) | Build air-gap bundle generator (`src/Tools/make-airgap-bundle.sh`), produce signed bundle, and verify in CI using private registry. Dependencies: DEVOPS-CONTAINERS-45-001. | DevOps Guild (ops/devops)
|
||||||
DEVOPS-DEVPORT-63-001 | TODO | Automate developer portal build pipeline with caching, link & accessibility checks, performance budgets. | DevOps Guild, Developer Portal Guild (ops/devops)
|
DEVOPS-DEVPORT-63-001 | TODO | Automate developer portal build pipeline with caching, link & accessibility checks, performance budgets. | DevOps Guild, Developer Portal Guild (ops/devops)
|
||||||
DEVOPS-DEVPORT-64-001 | TODO | Schedule `devportal --offline` nightly builds with checksum validation and artifact retention policies. Dependencies: DEVOPS-DEVPORT-63-001. | DevOps Guild, DevPortal Offline Guild (ops/devops)
|
DEVOPS-DEVPORT-64-001 | TODO | Schedule `devportal --offline` nightly builds with checksum validation and artifact retention policies. Dependencies: DEVOPS-DEVPORT-63-001. | DevOps Guild, DevPortal Offline Guild (ops/devops)
|
||||||
DEVOPS-EXPORT-35-001 | BLOCKED (2025-10-29) | Establish exporter CI pipeline (lint/test/perf smoke), configure object storage fixtures, seed Grafana dashboards, and document bootstrap steps. | DevOps Guild, Exporter Service Guild (ops/devops)
|
DEVOPS-EXPORT-35-001 | BLOCKED (2025-10-29) | Establish exporter CI pipeline (lint/test/perf smoke), configure object storage fixtures, seed Grafana dashboards, and document bootstrap steps. | DevOps Guild, Exporter Service Guild (ops/devops)
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ DEVOPS-LNM-22-002 | BLOCKED (2025-10-27) | Blocked on DEVOPS-LNM-TOOLING-22-000
|
|||||||
DEVOPS-LNM-22-003 | TODO | Add CI/monitoring coverage for new metrics (`advisory_observations_total`, `linksets_total`, etc.) and alerts on ingest-to-API SLA breaches. Dependencies: DEVOPS-LNM-22-002. | DevOps Guild, Observability Guild (ops/devops)
|
DEVOPS-LNM-22-003 | TODO | Add CI/monitoring coverage for new metrics (`advisory_observations_total`, `linksets_total`, etc.) and alerts on ingest-to-API SLA breaches. Dependencies: DEVOPS-LNM-22-002. | DevOps Guild, Observability Guild (ops/devops)
|
||||||
DEVOPS-OAS-61-001 | TODO | Add CI stages for OpenAPI linting, validation, and compatibility diff; enforce gating on PRs. | DevOps Guild, API Contracts Guild (ops/devops)
|
DEVOPS-OAS-61-001 | TODO | Add CI stages for OpenAPI linting, validation, and compatibility diff; enforce gating on PRs. | DevOps Guild, API Contracts Guild (ops/devops)
|
||||||
DEVOPS-OAS-61-002 | TODO | Integrate mock server + contract test suite into PR and nightly workflows; publish artifacts. Dependencies: DEVOPS-OAS-61-001. | DevOps Guild, Contract Testing Guild (ops/devops)
|
DEVOPS-OAS-61-002 | TODO | Integrate mock server + contract test suite into PR and nightly workflows; publish artifacts. Dependencies: DEVOPS-OAS-61-001. | DevOps Guild, Contract Testing Guild (ops/devops)
|
||||||
DEVOPS-OPENSSL-11-001 | TODO (2025-11-06) | Package the OpenSSL 1.1 shim (`tests/native/openssl-1.1/linux-x64`) into test harness output so Mongo2Go suites discover it automatically. | DevOps Guild, Build Infra Guild (ops/devops)
|
DEVOPS-OPENSSL-11-001 | DONE (2025-11-24) | Package the OpenSSL 1.1 shim (`tests/native/openssl-1.1/linux-x64`) into test harness output so Mongo2Go suites discover it automatically. | DevOps Guild, Build Infra Guild (ops/devops)
|
||||||
DEVOPS-OPENSSL-11-002 | TODO (2025-11-06) | Ensure CI runners and Docker images that execute Mongo2Go tests export `LD_LIBRARY_PATH` (or embed the shim) to unblock unattended pipelines. Dependencies: DEVOPS-OPENSSL-11-001. | DevOps Guild, CI Guild (ops/devops)
|
DEVOPS-OPENSSL-11-002 | TODO (2025-11-06) | Ensure CI runners and Docker images that execute Mongo2Go tests export `LD_LIBRARY_PATH` (or embed the shim) to unblock unattended pipelines. Dependencies: DEVOPS-OPENSSL-11-001. | DevOps Guild, CI Guild (ops/devops)
|
||||||
DEVOPS-OBS-51-001 | TODO | Implement SLO evaluator service (burn rate calculators, webhook emitters), Grafana dashboards, and alert routing to Notifier. Provide Terraform/Helm automation. Dependencies: DEVOPS-OBS-50-002. | DevOps Guild, Observability Guild (ops/devops)
|
DEVOPS-OBS-51-001 | TODO | Implement SLO evaluator service (burn rate calculators, webhook emitters), Grafana dashboards, and alert routing to Notifier. Provide Terraform/Helm automation. Dependencies: DEVOPS-OBS-50-002. | DevOps Guild, Observability Guild (ops/devops)
|
||||||
DEVOPS-OBS-52-001 | TODO | Configure streaming pipeline (NATS/Redis/Kafka) with retention, partitioning, and backpressure tuning for timeline events; add CI validation of schema + rate caps. Dependencies: DEVOPS-OBS-51-001. | DevOps Guild, Timeline Indexer Guild (ops/devops)
|
DEVOPS-OBS-52-001 | TODO | Configure streaming pipeline (NATS/Redis/Kafka) with retention, partitioning, and backpressure tuning for timeline events; add CI validation of schema + rate caps. Dependencies: DEVOPS-OBS-51-001. | DevOps Guild, Timeline Indexer Guild (ops/devops)
|
||||||
@@ -31,3 +31,8 @@ DEVOPS-LEDGER-OAS-61-002-REL | TODO | Validate/publish `.well-known/openapi` out
|
|||||||
DEVOPS-LEDGER-OAS-62-001-REL | TODO | Generate/publish SDK artefacts and signatures for Findings Ledger in release pipeline. | DevOps Guild, Findings Ledger Guild (ops/devops)
|
DEVOPS-LEDGER-OAS-62-001-REL | TODO | Generate/publish SDK artefacts and signatures for Findings Ledger in release pipeline. | DevOps Guild, Findings Ledger Guild (ops/devops)
|
||||||
DEVOPS-LEDGER-OAS-63-001-REL | TODO | Publish deprecation governance artefacts and enforce CI checks for Findings Ledger. | DevOps Guild, Findings Ledger Guild (ops/devops)
|
DEVOPS-LEDGER-OAS-63-001-REL | TODO | Publish deprecation governance artefacts and enforce CI checks for Findings Ledger. | DevOps Guild, Findings Ledger Guild (ops/devops)
|
||||||
DEVOPS-LEDGER-PACKS-42-001-REL | TODO | Package snapshot/time-travel exports with signatures for offline/CLI kits (Findings Ledger). | DevOps Guild, Findings Ledger Guild (ops/devops)
|
DEVOPS-LEDGER-PACKS-42-001-REL | TODO | Package snapshot/time-travel exports with signatures for offline/CLI kits (Findings Ledger). | DevOps Guild, Findings Ledger Guild (ops/devops)
|
||||||
|
|
||||||
|
## Execution Log
|
||||||
|
| Date (UTC) | Update | Owner |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 2025-11-24 | Completed DEVOPS-OPENSSL-11-001: copied OpenSSL 1.1 shim into all test outputs (native/linux-x64) via shared Directory.Build.props; Authority tests succeed with Mongo2Go. | Implementer |
|
||||||
|
|||||||
@@ -23,8 +23,8 @@ DEVOPS-SIG-26-002 | TODO | Create dashboards/alerts for reachability scoring lat
|
|||||||
DEVOPS-TEN-47-001 | TODO | Add JWKS cache monitoring, signature verification regression tests, and token expiration chaos tests to CI. | DevOps Guild (ops/devops)
|
DEVOPS-TEN-47-001 | TODO | Add JWKS cache monitoring, signature verification regression tests, and token expiration chaos tests to CI. | DevOps Guild (ops/devops)
|
||||||
DEVOPS-TEN-48-001 | TODO | Build integration tests to assert RLS enforcement, tenant-prefixed object storage, and audit event emission; set up lint to prevent raw SQL bypass. Dependencies: DEVOPS-TEN-47-001. | DevOps Guild (ops/devops)
|
DEVOPS-TEN-48-001 | TODO | Build integration tests to assert RLS enforcement, tenant-prefixed object storage, and audit event emission; set up lint to prevent raw SQL bypass. Dependencies: DEVOPS-TEN-47-001. | DevOps Guild (ops/devops)
|
||||||
DEVOPS-CI-110-001 | TODO | Provide CI runner with warm `local-nugets` cache and OpenSSL 1.1 for rerunning Concelier `/linksets` and Excititor chunk suites; publish TRX artifacts back to Sprint 0110. | DevOps Guild, Concelier Guild, Excititor Guild (ops/devops)
|
DEVOPS-CI-110-001 | TODO | Provide CI runner with warm `local-nugets` cache and OpenSSL 1.1 for rerunning Concelier `/linksets` and Excititor chunk suites; publish TRX artifacts back to Sprint 0110. | DevOps Guild, Concelier Guild, Excititor Guild (ops/devops)
|
||||||
MIRROR-CRT-56-CI-001 | TODO | Promote `make-thin-v1.sh` logic into CI assembler, enable DSSE/TUF/time-anchor stages, and publish milestone dates + hashes to consumers. | Mirror Creator Guild, DevOps Guild (ops/devops)
|
MIRROR-CRT-56-CI-001 | TODO | Promote `make-thin-v1.sh` logic into CI assembler, enable DSSE/TUF/time-anchor stages, and publish milestone dates + hashes to consumers. Uses `MIRROR_SIGN_KEY_B64` from Gitea secrets. | Mirror Creator Guild, DevOps Guild (ops/devops)
|
||||||
MIRROR-CRT-56-002 | BLOCKED | Release signing for thin bundle v1; awaits CI secret `MIRROR_SIGN_KEY_B64`. | Mirror Creator Guild · Security Guild (ops/devops)
|
MIRROR-CRT-56-002 | TODO | Release signing for thin bundle v1; install secret `MIRROR_SIGN_KEY_B64` (Ed25519 PEM, provided 2025-11-24) and rerun `.gitea/workflows/mirror-sign.yml` with `REQUIRE_PROD_SIGNING=1`. | Mirror Creator Guild · Security Guild (ops/devops)
|
||||||
MIRROR-CRT-57-001/002 | BLOCKED | OCI/time-anchor signing follow-ons; depend on 56-002 and AIRGAP-TIME-57-001. | Mirror Creator Guild · AirGap Time Guild (ops/devops)
|
MIRROR-CRT-57-001/002 | BLOCKED | OCI/time-anchor signing follow-ons; depend on 56-002 and AIRGAP-TIME-57-001. | Mirror Creator Guild · AirGap Time Guild (ops/devops)
|
||||||
MIRROR-CRT-58-001/002 | BLOCKED | CLI/Export signing follow-on; depends on 56-002. | Mirror Creator · CLI · Exporter Guilds (ops/devops)
|
MIRROR-CRT-58-001/002 | BLOCKED | CLI/Export signing follow-on; depends on 56-002. | Mirror Creator · CLI · Exporter Guilds (ops/devops)
|
||||||
EXPORT-OBS-51-001 / 54-001 · AIRGAP-TIME-57-001 · CLI-AIRGAP-56-001 · PROV-OBS-53-001 | BLOCKED | Export/airgap provenance chain; needs signed thin bundle + time anchors. | Exporter Guild · AirGap Time · CLI Guild (ops/devops)
|
EXPORT-OBS-51-001 / 54-001 · AIRGAP-TIME-57-001 · CLI-AIRGAP-56-001 · PROV-OBS-53-001 | BLOCKED | Export/airgap provenance chain; needs signed thin bundle + time anchors. | Exporter Guild · AirGap Time · CLI Guild (ops/devops)
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ Task ID | State | Task description | Owners (Source)
|
|||||||
APIGOV-61-001 | DONE (2025-11-18) | Spectral config + CI workflow added; npm script `api:lint` runs spectral via npx. | API Governance Guild (src/Api/StellaOps.Api.Governance)
|
APIGOV-61-001 | DONE (2025-11-18) | Spectral config + CI workflow added; npm script `api:lint` runs spectral via npx. | API Governance Guild (src/Api/StellaOps.Api.Governance)
|
||||||
APIGOV-61-002 | DONE (2025-11-18) | Implement example coverage checker ensuring every operation has at least one request/response example. Dependencies: APIGOV-61-001. | API Governance Guild (src/Api/StellaOps.Api.Governance)
|
APIGOV-61-002 | DONE (2025-11-18) | Implement example coverage checker ensuring every operation has at least one request/response example. Dependencies: APIGOV-61-001. | API Governance Guild (src/Api/StellaOps.Api.Governance)
|
||||||
APIGOV-62-001 | DONE (2025-11-18) | Build compatibility diff tool producing additive/breaking reports comparing prior release. Dependencies: APIGOV-61-002. | API Governance Guild (src/Api/StellaOps.Api.Governance)
|
APIGOV-62-001 | DONE (2025-11-18) | Build compatibility diff tool producing additive/breaking reports comparing prior release. Dependencies: APIGOV-61-002. | API Governance Guild (src/Api/StellaOps.Api.Governance)
|
||||||
APIGOV-62-002 | TODO | Automate changelog generation and publish signed artifacts to `src/Sdk/StellaOps.Sdk.Release` pipeline. Dependencies: APIGOV-62-001. | API Governance Guild, DevOps Guild (src/Api/StellaOps.Api.Governance)
|
APIGOV-62-002 | DONE (2025-11-24) | Automate changelog generation and publish signed artifacts to `src/Sdk/StellaOps.Sdk.Release` pipeline. Dependencies: APIGOV-62-001. | API Governance Guild, DevOps Guild (src/Api/StellaOps.Api.Governance)
|
||||||
APIGOV-63-001 | BLOCKED | Notification Studio templates and deprecation metadata schema not present; waiting on Notifications Guild assets. | API Governance Guild, Notifications Guild (src/Api/StellaOps.Api.Governance)
|
APIGOV-63-001 | BLOCKED | Notification Studio templates and deprecation metadata schema not present; waiting on Notifications Guild assets. | API Governance Guild, Notifications Guild (src/Api/StellaOps.Api.Governance)
|
||||||
OAS-61-001 | DONE (2025-11-18) | Scaffold per-service OpenAPI 3.1 files with shared components, info blocks, and initial path stubs. | API Contracts Guild (src/Api/StellaOps.Api.OpenApi)
|
OAS-61-001 | DONE (2025-11-18) | Scaffold per-service OpenAPI 3.1 files with shared components, info blocks, and initial path stubs. | API Contracts Guild (src/Api/StellaOps.Api.OpenApi)
|
||||||
OAS-61-002 | DONE (2025-11-18) | Implement aggregate composer (`stella.yaml`) resolving `$ref`s and merging shared components; wire into CI. Dependencies: OAS-61-001. | API Contracts Guild, DevOps Guild (src/Api/StellaOps.Api.OpenApi)
|
OAS-61-002 | DONE (2025-11-18) | Implement aggregate composer (`stella.yaml`) resolving `$ref`s and merging shared components; wire into CI. Dependencies: OAS-61-001. | API Contracts Guild, DevOps Guild (src/Api/StellaOps.Api.OpenApi)
|
||||||
@@ -27,4 +27,5 @@ OAS-63-002 | TODO | Add `/.well-known/openapi` discovery endpoint schema metadat
|
|||||||
| 2025-11-18 | Implemented example coverage checker (`api:examples`), aggregate composer `compose.mjs`, and initial per-service OAS stubs (authority/orchestrator/policy/export-center); OAS-61-001/002 set to DONE. | API Contracts Guild |
|
| 2025-11-18 | Implemented example coverage checker (`api:examples`), aggregate composer `compose.mjs`, and initial per-service OAS stubs (authority/orchestrator/policy/export-center); OAS-61-001/002 set to DONE. | API Contracts Guild |
|
||||||
| 2025-11-19 | Added scheduler/export-center/graph shared endpoints, shared paging/security components, and CI diff gates (previous commit + baseline). Created baseline `stella-baseline.yaml`. | API Contracts Guild |
|
| 2025-11-19 | Added scheduler/export-center/graph shared endpoints, shared paging/security components, and CI diff gates (previous commit + baseline). Created baseline `stella-baseline.yaml`. | API Contracts Guild |
|
||||||
| 2025-11-19 | Implemented API changelog generator (`api:changelog`), wired compose/examples/compat/changelog into CI, and added new policy revisions + scheduler queue/job endpoints. | API Contracts Guild |
|
| 2025-11-19 | Implemented API changelog generator (`api:changelog`), wired compose/examples/compat/changelog into CI, and added new policy revisions + scheduler queue/job endpoints. | API Contracts Guild |
|
||||||
|
| 2025-11-24 | Completed APIGOV-62-002: `api:changelog` now copies release-ready artifacts + digest/signature to `src/Sdk/StellaOps.Sdk.Release/out/api-changelog` for SDK pipeline consumption. | Implementer |
|
||||||
| 2025-11-19 | Marked OAS-62-001 BLOCKED pending OAS-61-002 ratification and approved examples/error envelope. | Implementer |
|
| 2025-11-19 | Marked OAS-62-001 BLOCKED pending OAS-61-002 ratification and approved examples/error envelope. | Implementer |
|
||||||
|
|||||||
29
docs/implplan/archived/SPRINT_302_docs_tasks_md_ii.md
Normal file
29
docs/implplan/archived/SPRINT_302_docs_tasks_md_ii.md
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
# Sprint 302 - Documentation & Process · 200.A) Docs Tasks.Md.II
|
||||||
|
|
||||||
|
Active items only. Completed/historic work now resides in docs/implplan/archived/tasks.md (updated 2025-11-08).
|
||||||
|
|
||||||
|
[Documentation & Process] 200.A) Docs Tasks.Md.II
|
||||||
|
Depends on: Sprint 200.A - Docs Tasks.Md.I
|
||||||
|
Summary: Documentation & Process focus on Docs Tasks (phase Md.II).
|
||||||
|
Task ID | State | Task description | Owners (Source)
|
||||||
|
--- | --- | --- | ---
|
||||||
|
DOCS-AIRGAP-57-003 | DONE (2025-11-23) | Publish `/docs/modules/cli/guides/airgap.md` documenting commands, examples, exit codes. Dependencies: DOCS-AIRGAP-57-002. | Docs Guild, CLI Guild (docs)
|
||||||
|
DOCS-AIRGAP-57-004 | DONE (2025-11-23) | Create `/docs/airgap/operations.md` with runbooks for imports, failure recovery, and auditing. Dependencies: DOCS-AIRGAP-57-003. | Docs Guild, Ops Guild (docs)
|
||||||
|
DOCS-AIRGAP-58-001 | DONE (2025-11-23) | Provide `/docs/airgap/degradation-matrix.md` enumerating feature availability, fallbacks, remediation. Dependencies: DOCS-AIRGAP-57-004. | Docs Guild, Product Guild (docs)
|
||||||
|
DOCS-AIRGAP-58-002 | DONE (2025-11-23) | Update `/docs/security/trust-and-signing.md` with DSSE/TUF roots, rotation, and signed time tokens. Dependencies: DOCS-AIRGAP-58-001. | Docs Guild, Security Guild (docs)
|
||||||
|
DOCS-AIRGAP-58-003 | DONE (2025-11-23) | Publish `/docs/dev/airgap-contracts.md` describing EgressPolicy usage, sealed-mode tests, linting. Dependencies: DOCS-AIRGAP-58-002. | Docs Guild, DevEx Guild (docs)
|
||||||
|
DOCS-AIRGAP-58-004 | DONE (2025-11-23) | Document `/docs/airgap/portable-evidence.md` for exporting/importing portable evidence bundles across enclaves. Dependencies: DOCS-AIRGAP-58-003. | Docs Guild, Evidence Locker Guild (docs)
|
||||||
|
DOCS-AIRGAP-DEVPORT-64-001 | DONE (2025-11-23) | Create `/docs/airgap/devportal-offline.md` describing offline bundle usage and verification. | Docs Guild, DevPortal Offline Guild (docs)
|
||||||
|
DOCS-ATTEST-73-001 | DONE (2025-11-23) | Publish `/docs/modules/attestor/overview.md` with imposed rule banner. | Docs Guild, Attestor Service Guild (docs)
|
||||||
|
DOCS-ATTEST-73-002 | DONE (2025-11-23) | Write `/docs/modules/attestor/payloads.md` with schemas/examples. Dependencies: DOCS-ATTEST-73-001. | Docs Guild, Attestation Payloads Guild (docs)
|
||||||
|
DOCS-ATTEST-73-003 | DONE (2025-11-23) | Publish `/docs/modules/attestor/policies.md` covering verification policies. Dependencies: DOCS-ATTEST-73-002. | Docs Guild, Policy Guild (docs)
|
||||||
|
DOCS-ATTEST-73-004 | DONE (2025-11-23) | Add `/docs/modules/attestor/workflows.md` detailing ingest, verify, bulk operations. Dependencies: DOCS-ATTEST-73-003. | Docs Guild, Attestor Service Guild (docs)
|
||||||
|
DOCS-ATTEST-74-001 | DONE (2025-11-23) | Publish `/docs/modules/attestor/keys-and-issuers.md`. Dependencies: DOCS-ATTEST-73-004. | Docs Guild, KMS Guild (docs)
|
||||||
|
DOCS-ATTEST-74-002 | DONE (2025-11-23) | Document `/docs/modules/attestor/transparency.md` with witness usage/offline validation. Dependencies: DOCS-ATTEST-74-001. | Docs Guild, Transparency Guild (docs)
|
||||||
|
DOCS-ATTEST-74-003 | DONE (2025-11-23) | Write `/docs/console/attestor-ui.md` with screenshots/workflows. Dependencies: DOCS-ATTEST-74-002. | Docs Guild, Attestor Console Guild (docs)
|
||||||
|
DOCS-ATTEST-74-004 | DONE (2025-11-23) | Publish `/docs/modules/cli/guides/attest.md` covering CLI usage. Dependencies: DOCS-ATTEST-74-003. | Docs Guild, CLI Attestor Guild (docs)
|
||||||
|
|
||||||
|
## Execution Log
|
||||||
|
| Date (UTC) | Update | Owner |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 2025-11-23 | Completed airgap docs 57-003/57-004, 58-001..004, DEVPORT-64-001 and attestor docs 73-001..74-004; all tasks in this sprint now DONE. | Docs Guild |
|
||||||
6
docs/modules/attestor/keys-and-issuers.md
Normal file
6
docs/modules/attestor/keys-and-issuers.md
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
# Keys and Issuers (DOCS-ATTEST-74-001)
|
||||||
|
|
||||||
|
- Maintain issuer registry (KMS IDs, key IDs, allowed predicates).
|
||||||
|
- Rotate keys with overlap; publish fingerprints and validity in registry file.
|
||||||
|
- Offline operation: bundle registry with bootstrap; no remote fetch.
|
||||||
|
- Each attestation must include issuer ID and key ID; verify against registry.
|
||||||
9
docs/modules/attestor/overview.md
Normal file
9
docs/modules/attestor/overview.md
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# Attestor Overview (DOCS-ATTEST-73-001)
|
||||||
|
|
||||||
|
High-level description of the Attestor service and its contracts.
|
||||||
|
|
||||||
|
- Purpose: verify DSSE/attestations, supply transparency info, and expose attestation APIs without deriving verdicts.
|
||||||
|
- Components: WebService, Worker, KMS integration, Transparency log (optional), Evidence links.
|
||||||
|
- Rule banner: aggregation-only; no policy decisions.
|
||||||
|
- Tenancy: all attestations scoped per tenant; cross-tenant reads forbidden.
|
||||||
|
- Offline posture: allow offline verification using bundled trust roots and Rekor checkpoints when available.
|
||||||
@@ -1,48 +1,29 @@
|
|||||||
# Attestor Payload Reference
|
# Attestor Payloads (DOCS-ATTEST-73-002)
|
||||||
|
|
||||||
StellaOps evidence predicates must remain reproducible, explainable, and portable across online and fully air-gapped deployments. This guide lists each predicate type, indicates where the canonical JSON Schema lives, highlights the producing service, and links to the matching golden samples.
|
Schemas/examples for attestations handled by Attestor.
|
||||||
|
|
||||||
## Quick Reference
|
## DSSE payload
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"_type": "https://in-toto.io/Statement/v1",
|
||||||
|
"subject": [{"name": "sha256:...", "digest": {"sha256": "..."}}],
|
||||||
|
"predicateType": "stella.ops/vexObservation@v1",
|
||||||
|
"predicate": {
|
||||||
|
"observationId": "vex:obs:sha256:...",
|
||||||
|
"tenant": "default",
|
||||||
|
"providerId": "ubuntu-csaf",
|
||||||
|
"createdAt": "2025-11-23T23:10:00Z"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
| Type ID | Predicate URI | Schema file | Produced by | Primary consumers |
|
## Evidence links
|
||||||
| --- | --- | --- | --- | --- |
|
- Each payload references evidence hashes (VEX observations/linksets) and optional timeline event IDs.
|
||||||
| StellaOps.BuildProvenance@1 | https://schemas.stella-ops.org/attestations/build-provenance@1 | src/Attestor/StellaOps.Attestor.Types/schemas/stellaops-build-provenance.v1.schema.json | Build pipelines, Scanner SBOM bake stage | Attestor, Export Center, Policy Engine |
|
- Keep payloads aggregation-only; no verdict fields.
|
||||||
| StellaOps.SBOMAttestation@1 | https://schemas.stella-ops.org/attestations/sbom-attestation@1 | src/Attestor/StellaOps.Attestor.Types/schemas/stellaops-sbom-attestation.v1.schema.json | Scanner.Worker SBOM composer | Policy Engine, CLI, Export Center |
|
|
||||||
| StellaOps.ScanResults@1 | https://schemas.stella-ops.org/attestations/scan-results@1 | src/Attestor/StellaOps.Attestor.Types/schemas/stellaops-scan-results.v1.schema.json | Scanner.Worker analyzers | Policy Engine, CLI, Orchestrator |
|
|
||||||
| StellaOps.PolicyEvaluation@1 | https://schemas.stella-ops.org/attestations/policy-evaluation@1 | src/Attestor/StellaOps.Attestor.Types/schemas/stellaops-policy-evaluation.v1.schema.json | Policy Engine explain pipeline | CLI, Notify, Export Center |
|
|
||||||
| StellaOps.VEXAttestation@1 | https://schemas.stella-ops.org/attestations/vex-attestation@1 | src/Attestor/StellaOps.Attestor.Types/schemas/stellaops-vex-attestation.v1.schema.json | Excititor consensus service | Policy Engine, CLI, Console |
|
|
||||||
| StellaOps.RiskProfileEvidence@1 | https://schemas.stella-ops.org/attestations/risk-profile@1 | src/Attestor/StellaOps.Attestor.Types/schemas/stellaops-risk-profile.v1.schema.json | Policy Engine risk pipeline | Console, Notify, Export Center |
|
|
||||||
| StellaOps.CustomEvidence@1 | https://schemas.stella-ops.org/attestations/custom-evidence@1 | src/Attestor/StellaOps.Attestor.Types/schemas/stellaops-custom-evidence.v1.schema.json | CLI custom evidence workflows and partner integrations | Policy Engine (policy hooks), Export Center |
|
|
||||||
|
|
||||||
Golden JSON fixtures that double as contract tests live under `src/Attestor/StellaOps.Attestor.Types/fixtures/v1/<predicate>.sample.json`. TypeScript and Go clients consume the generated sources in `src/Attestor/StellaOps.Attestor.Types/generated/ts` and `src/Attestor/StellaOps.Attestor.Types/generated/go`.
|
## Hashing/signing
|
||||||
|
- Canonicalize JSON (RFC 8785) before signing.
|
||||||
|
- Use SHA-256 digests; include in envelope metadata.
|
||||||
|
|
||||||
## Envelope Conventions
|
## Examples
|
||||||
|
- Place sample payloads in `docs/samples/attestor/payloads/` (add when available).
|
||||||
- DSSE envelopes are signed over canonical JSON (sorted keys, UTF-8, no insignificant whitespace).
|
|
||||||
- The `subject` array must include at least one SHA-256 digest and may attach annotations such as `oci.reference` or `stellaops.asset`.
|
|
||||||
- `predicateType` uses the URI shown in the table; `predicate.typeId` mirrors the short identifier.
|
|
||||||
- `predicate.schemaVersion` follows semantic versioning. Consumers reject mismatched major versions.
|
|
||||||
- Optional `metadata` and `materials` sections follow the in-toto Statement format to maximise provenance portability.
|
|
||||||
|
|
||||||
## Predicate Highlights
|
|
||||||
|
|
||||||
- **StellaOps.BuildProvenance@1** records builder identity, config source, materials, reproducibility flags, and the resulting artifact digests. Outputs must match the DSSE subject.
|
|
||||||
- **StellaOps.SBOMAttestation@1** links an artifact digest to a CycloneDX 1.6 or SBOM 3.0.0 document, tracking inventory counts and the generator metadata. Component graph hashes reference CAS entries emitted by Scanner.Worker.
|
|
||||||
- **StellaOps.ScanResults@1** captures deterministic findings from OS, language, and native analyzers. It reports summary counts, per-finding metadata (PURL, severity, exploitability), and the layer digests inspected.
|
|
||||||
- **StellaOps.PolicyEvaluation@1** documents lattice-based policy outcomes, including decision traces and evidence digests consumed during evaluation.
|
|
||||||
- **StellaOps.VEXAttestation@1** mirrors OpenVEX-aligned statements with justification, scope narrowing (package coordinates or component IDs), and issue timestamps.
|
|
||||||
- **StellaOps.RiskProfileEvidence@1** summarises exploitability, ticketing load, runtime coverage, and maturity for downstream dashboards.
|
|
||||||
- **StellaOps.CustomEvidence@1** allows regulated tenants to attach organisation-specific payloads referenced by a CAS-hosted schema while preserving provenance and retention controls.
|
|
||||||
|
|
||||||
## Validation and Tooling
|
|
||||||
|
|
||||||
- Run `npm install` once, then `npm run docs:attestor:validate` to validate JSON fixtures against their schemas, execute the generated TypeScript tests (`npm test`), and run `go test ./...` for the Go SDK. The command fails fast when any schema, fixture, or generated SDK drifts.
|
|
||||||
- Regenerate schemas and SDKs after edits with `dotnet run --project src/Attestor/StellaOps.Attestor.Types/Tools/StellaOps.Attestor.Types.Generator`.
|
|
||||||
- Offline Kit builds (`ops/devops/offline-kit/`) mirror schemas, fixtures, and SDK bundles so air-gapped operators can run the same validation stack.
|
|
||||||
|
|
||||||
## Related Material
|
|
||||||
|
|
||||||
- `docs/modules/attestor/architecture.md` — service topology, Rekor integration, caching model.
|
|
||||||
- `docs/modules/platform/architecture-overview.md` — cross-module data flows and tenant boundaries.
|
|
||||||
- `docs/ingestion/aggregation-only-contract.md` — guardrails for advisory feeds consumed by policy evaluation.
|
|
||||||
- `src/Attestor/StellaOps.Attestor.Types/samples/README.md` — directory map for the golden evidence set referenced here.
|
|
||||||
|
|||||||
12
docs/modules/attestor/policies.md
Normal file
12
docs/modules/attestor/policies.md
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# Attestor Policies (DOCS-ATTEST-73-003)
|
||||||
|
|
||||||
|
Guidance on verification policies applied by Attestor.
|
||||||
|
|
||||||
|
- Scope: DSSE envelope validation, subject hash matching, optional transparency checks.
|
||||||
|
- Policy fields:
|
||||||
|
- allowed issuers / key IDs
|
||||||
|
- required predicates (e.g., `stella.ops/vexObservation@v1`)
|
||||||
|
- transparency requirements (allow/require/skip)
|
||||||
|
- freshness window for attestations
|
||||||
|
- Determinism: policies must be pure; no external lookups in sealed mode.
|
||||||
|
- Versioning: include `policyVersion` and hash; store alongside attestation records.
|
||||||
6
docs/modules/attestor/transparency.md
Normal file
6
docs/modules/attestor/transparency.md
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
# Transparency (DOCS-ATTEST-74-002)
|
||||||
|
|
||||||
|
- Optional Rekor/witness integration.
|
||||||
|
- In sealed mode, use bundled checkpoints and disable live witness fetch.
|
||||||
|
- Verification: compare embedded checkpoint with bundled; log discrepancies.
|
||||||
|
- Record transparency fields on verification result: `{uuid, logIndex, checkpointHash}`.
|
||||||
@@ -1,247 +1,9 @@
|
|||||||
# Attestor Verification Workflows
|
# Attestor Workflows (DOCS-ATTEST-73-004)
|
||||||
|
|
||||||
> How StellaOps turns DSSE bundles into verifiable evidence, how the verification API reports outcomes, and how explainability signals surface in UI/CLI flows.
|
Sequence of ingest, verify, and bulk operations.
|
||||||
|
|
||||||
> ⚠️ **2025-11-01 coordination note:** `StellaOps.Attestor.WebService` is failing to compile until downstream fixes land (`Contracts/AttestationBundleContracts.cs` null-coalescing update and scope/token variables restored in `Program.cs`). Verification flows ship in infrastructure/tests, but the WebService hand-off stays blocked — track via `ATTESTOR-73-002` (see Attestor task board).
|
1. **Ingest**: receive DSSE, validate schema, hash subjects, store envelope + metadata.
|
||||||
|
2. **Verify**: run policy checks (issuer, predicate, transparency optional), compute verification record.
|
||||||
## 1. Verification flow (API and service contract)
|
3. **Persist**: store verification result with `verificationId`, `attestationId`, `policyVersion`, timestamps.
|
||||||
|
4. **Bulk ops**: batch verify envelopes; export results to timeline/audit logs.
|
||||||
- **Entry point.** `POST /api/v1/rekor/verify` deserialises to `AttestorVerificationRequest`.
|
5. **Audit**: expose read API for verification records; include determinism hash of inputs.
|
||||||
- **Resolution order.** The service tries `uuid`, then canonicalised `bundle`, then `artifactSha256`. At least one selector must be present (`invalid_query` otherwise).
|
|
||||||
- **Optional proof refresh.** `refreshProof=true` forces a Rekor lookup before returning. Proofs are cached in Mongo.
|
|
||||||
- **Signature replay.** Supplying `bundle` lets the service recompute the canonical hash and re-run signature checks; omitting the bundle skips those steps but still validates Merkle proofs and cached policy decisions.
|
|
||||||
- **Auth scopes.** Endpoints demand `attestor.verify` (write scope is also accepted); read-only detail/list APIs require `attestor.read` at minimum.
|
|
||||||
|
|
||||||
### 1.1 Request properties
|
|
||||||
|
|
||||||
| Field | Type | Required | Purpose |
|
|
||||||
|-------|------|----------|---------|
|
|
||||||
| `uuid` | string | optional | Rekor V2 UUID to verify and (optionally) refresh. |
|
|
||||||
| `bundle` | object | optional | DSSE envelope (same shape as submission) for signature re-verification. |
|
|
||||||
| `artifactSha256` | string | optional | Resolve the most recent entry for an attestable artefact digest. |
|
|
||||||
| `subject` | string | optional | Logical subject identifier used for cache/telemetry tagging; defaults to the stored artifact digest. |
|
|
||||||
| `envelopeId` | string | optional | Stable identifier for the DSSE bundle (typically the canonical hash); enables cache lookups. |
|
|
||||||
| `policyVersion` | string | optional | Policy digest/version driving verification; feeds cache keys and observability dimensions. |
|
|
||||||
| `refreshProof` | bool | optional (default `false`) | Pull the current inclusion proof and checkpoint from Rekor before evaluating. |
|
|
||||||
|
|
||||||
All selectors are mutually compatible; if more than one is set the service uses the first match (`uuid` → `bundle` → `artifactSha256`).
|
|
||||||
|
|
||||||
### 1.2 Response schema (`AttestorVerificationResult`)
|
|
||||||
|
|
||||||
| Field | Type | Description |
|
|
||||||
|-------|------|-------------|
|
|
||||||
| `ok` | bool | `true` when the entry status is `included` **and** no issues were recorded. |
|
|
||||||
| `uuid` | string | Rekor UUID that satisfied the query. Useful for follow-up fetches. |
|
|
||||||
| `index` | number (int64) | Rekor log index, when supplied by the backend. |
|
|
||||||
| `logUrl` | string | Fully-qualified Rekor entry URL for operators and auditors. |
|
|
||||||
| `status` | string | Transparency-log status seen in Mongo (`included`, `pending`, `failed`, …). |
|
|
||||||
| `checkedAt` | string (ISO-8601 UTC) | Timestamp emitted when the response is created. |
|
|
||||||
| `issues` | array[string] | Machine-readable explainability codes. Empty when `ok=true`. |
|
|
||||||
|
|
||||||
> **Note:** `checkedAt` is recomputed each call; cache hits do not recycle previous timestamps.
|
|
||||||
|
|
||||||
### 1.3 Success criteria
|
|
||||||
|
|
||||||
`ok=true` requires:
|
|
||||||
|
|
||||||
1. Entry exists and status equals `included`.
|
|
||||||
2. Canonical DSSE hash matches the stored bundle hash.
|
|
||||||
3. Signature re-verification (when a bundle is supplied) succeeds.
|
|
||||||
4. Inclusion proof validates against the cached or refreshed checkpoint.
|
|
||||||
|
|
||||||
Any deviation records at least one issue and flips `ok` to `false`. Consumers **must** inspect `issues` rather than inferring from `status` alone.
|
|
||||||
|
|
||||||
## 2. Verification report schema
|
|
||||||
|
|
||||||
`AttestorVerificationResult` carries the flattened summary shown above. When callers request the detailed report (`GET /api/v1/rekor/entries/{uuid}?refresh=true` or via SDK) they receive a `VerificationReport` shaped as follows:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"overallStatus": "pass",
|
|
||||||
"succeeded": true,
|
|
||||||
"policy": { ... },
|
|
||||||
"issuer": { ... },
|
|
||||||
"freshness": { ... },
|
|
||||||
"signatures": { ... },
|
|
||||||
"transparency": { ... },
|
|
||||||
"issues": [ "bundle_hash_mismatch" ]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
| Field | Type | Description |
|
|
||||||
|-------|------|-------------|
|
|
||||||
| `overallStatus` | string (`pass`, `warn`, `fail`, `skipped`) | Aggregated verdict derived from the individual section statuses. |
|
|
||||||
| `succeeded` | bool | Convenience flag; `true` when `overallStatus ∈ {pass, warn}`. |
|
|
||||||
| `policy` | object | Results from policy evaluation (see below). |
|
|
||||||
| `issuer` | object | Identity/result of the signing entity. |
|
|
||||||
| `freshness` | object | Age analysis relative to policy settings. |
|
|
||||||
| `signatures` | object | Signature validation summary. |
|
|
||||||
| `transparency` | object | Inclusion proof / checkpoint evaluation summary. |
|
|
||||||
| `issues` | array[string] | De-duplicated set drawn from the sections; order is deterministic and stable. |
|
|
||||||
|
|
||||||
### 2.1 `policy`
|
|
||||||
|
|
||||||
| Field | Description |
|
|
||||||
|-------|-------------|
|
|
||||||
| `status` | Section verdict (`pass`, `warn`, `fail`, `skipped`). |
|
|
||||||
| `policyId` / `policyVersion` | DSL identifier and revision used for evaluation. |
|
|
||||||
| `verdict` | Policy outcome (`allow`, `challenge`, `deny`, etc.). |
|
|
||||||
| `issues` | Policy-specific explainability codes (e.g., `policy_rule_blocked`). |
|
|
||||||
| `attributes` | Key/value map emitted by the policy for downstream observability (e.g., applicable rules, matched waivers). |
|
|
||||||
|
|
||||||
### 2.2 `issuer`
|
|
||||||
|
|
||||||
| Field | Description |
|
|
||||||
|-------|-------------|
|
|
||||||
| `status` | Result of issuer validation. |
|
|
||||||
| `mode` | Signing mode detected (`keyless`, `kms`, `unknown`). |
|
|
||||||
| `issuer` | Distinguished name / issuer URI recorded during signing. |
|
|
||||||
| `subjectAlternativeName` | SAN pulled from the Fulcio certificate (keyless) or recorded KMS identity. |
|
|
||||||
| `keyId` | Logical key identifier associated with the signature. |
|
|
||||||
| `issues` | Issuer-specific issues (e.g., `issuer_trust_root_mismatch`, `signer_mode_unsupported:kid`). |
|
|
||||||
|
|
||||||
### 2.3 `freshness`
|
|
||||||
|
|
||||||
| Field | Description |
|
|
||||||
|-------|-------------|
|
|
||||||
| `status` | `fail` when the attestation exceeds `verification.freshnessMaxAgeMinutes`; `warn` when only the warning threshold is hit. |
|
|
||||||
| `createdAt` | Timestamp embedded in the attestation metadata. |
|
|
||||||
| `evaluatedAt` | Server-side timestamp used for age calculations. |
|
|
||||||
| `age` | ISO8601 duration of `evaluatedAt - createdAt`. |
|
|
||||||
| `maxAge` | Policy-driven ceiling (null when unchecked). |
|
|
||||||
| `issues` | `freshness_max_age_exceeded`, `freshness_warning`, etc. |
|
|
||||||
|
|
||||||
### 2.4 `signatures`
|
|
||||||
|
|
||||||
| Field | Description |
|
|
||||||
|-------|-------------|
|
|
||||||
| `status` | Signature validation verdict. |
|
|
||||||
| `bundleProvided` | `true` when canonical DSSE bytes were supplied. |
|
|
||||||
| `totalSignatures` | Count observed in the DSSE envelope. |
|
|
||||||
| `verifiedSignatures` | Number of signatures that validated against trusted keys. |
|
|
||||||
| `requiredSignatures` | Policy / configuration minimum enforced. |
|
|
||||||
| `issues` | Signature codes such as `bundle_payload_invalid_base64`, `signature_invalid`, `signer_mode_unknown`. |
|
|
||||||
|
|
||||||
### 2.5 `transparency`
|
|
||||||
|
|
||||||
| Field | Description |
|
|
||||||
|-------|-------------|
|
|
||||||
| `status` | Inclusion proof / checkpoint verdict. |
|
|
||||||
| `proofPresent` | Whether a proof document was available. |
|
|
||||||
| `checkpointPresent` | Indicates the Rekor checkpoint existed and parsed. |
|
|
||||||
| `inclusionPathPresent` | `true` when the Merkle path array contained nodes. |
|
|
||||||
| `issues` | Merkle/rekor codes (`proof_missing`, `proof_leafhash_mismatch`, `checkpoint_missing`, `proof_root_mismatch`). |
|
|
||||||
|
|
||||||
### 2.6 Issue catalogue (non-exhaustive)
|
|
||||||
|
|
||||||
| Code | Trigger | Notes |
|
|
||||||
|------|---------|-------|
|
|
||||||
| `bundle_hash_mismatch` | Canonical DSSE hash differs from stored value. | Often indicates tampering or inconsistent canonicalisation. |
|
|
||||||
| `bundle_payload_invalid_base64` | DSSE payload cannot be base64-decoded. | Validate producer pipeline; the attestation is unusable. |
|
|
||||||
| `signature_invalid` | At least one signature failed cryptographic verification. | Consider checking key rotation / revocation status. |
|
|
||||||
| `signer_mode_unknown` / `signer_mode_unsupported:<mode>` | Signing mode not configured for this installation. | Update `attestorOptions.security.signerIdentity.mode`. |
|
|
||||||
| `issuer_trust_root_mismatch` | Certificate chain does not terminate in configured Fulcio/KMS roots. | Check Fulcio bundle / KMS configuration. |
|
|
||||||
| `freshness_max_age_exceeded` | Attestation older than permitted maximum. | Regenerate attestation or extend policy window. |
|
|
||||||
| `proof_missing` | No inclusion proof stored or supplied. | When running offline, import bundles with proofs or allow warn-level policies. |
|
|
||||||
| `proof_root_mismatch` | Rebuilt Merkle root differs from checkpoint. | Proof may be stale or log compromised; escalate. |
|
|
||||||
| `checkpoint_missing` | No Rekor checkpoint available. | Configure `RequireCheckpoint=false` to downgrade severity. |
|
|
||||||
|
|
||||||
Downstream consumers (UI, CLI, policy studio) should render human-readable messages but must retain the exact issue codes for automation and audit replay.
|
|
||||||
|
|
||||||
## 3. Explainability signals
|
|
||||||
|
|
||||||
1. **Canonicalisation.** The service replays DSSE canonicalisation to derive `bundleSha256`. Failures surface as `bundle_hash_mismatch` or decoding errors.
|
|
||||||
2. **Signature checks.** Mode-aware handling:
|
|
||||||
- `kms` (HMAC) compares against configured shared secrets.
|
|
||||||
- `keyless` rebuilds the certificate chain, enforces Fulcio roots, SAN allow-lists, and verifies with the leaf certificate.
|
|
||||||
- Unknown modes emit `signer_mode_unknown` / `signer_mode_unsupported:<mode>`.
|
|
||||||
3. **Proof acquisition.** When `refreshProof` is requested the Rekor backend may contribute a textual issue (`Proof refresh failed: …`) without stopping evaluation.
|
|
||||||
4. **Merkle validation.** Structured helper ensures leaf hash, path orientation, and checkpoint root are consistent; each validation failure has a discrete issue code.
|
|
||||||
5. **Observability.** The meter `attestor.verify_total` increments with `result=ok|failed`; structured logs and traces carry the same `issues` vector for UI/CLI drill-down.
|
|
||||||
|
|
||||||
All issues are appended in detection order to simplify chronological replay in the Console’s chain-of-custody view.
|
|
||||||
|
|
||||||
## 3. Issue catalogue
|
|
||||||
|
|
||||||
| Code | Trigger | Operator guidance |
|
|
||||||
|------|---------|-------------------|
|
|
||||||
| `bundle_hash_mismatch` | Canonicalised DSSE hash differs from stored bundle hash. | Re-download artefact; investigate tampering or submission races. |
|
|
||||||
| `bundle_payload_invalid_base64` | Payload could not be base64-decoded. | Ensure bundle transport preserved payload; capture original DSSE for forensics. |
|
|
||||||
| `signature_invalid_kms` | HMAC verification failed for `mode=kms`. | Confirm shared secret alignment with Signer; rotate keys if drift detected. |
|
|
||||||
| `signer_mode_unknown` | Entry lacks signer mode metadata and bundle omitted it. | Re-ingest bundle or inspect submission pipeline metadata. |
|
|
||||||
| `signer_mode_unsupported:<mode>` | Signer mode is unsupported by the verifier. | Add support or block unsupported issuers in policy. |
|
|
||||||
| `kms_key_missing` | No configured KMS secrets to verify `mode=kms`. | Populate `security:signerIdentity:kmsKeys` in Attestor config before retry. |
|
|
||||||
| `signature_invalid_base64` | One or more signatures were not valid base64. | Bundle corruption; capture raw payload and re-submit. |
|
|
||||||
| `certificate_chain_missing` | `mode=keyless` bundle lacked any certificates. | Ensure Signer attaches Fulcio chain; review submission pipeline. |
|
|
||||||
| `certificate_chain_invalid` | Certificates could not be parsed. | Fetch original DSSE bundle for repair; confirm certificate encoding. |
|
|
||||||
| `certificate_chain_untrusted[:detail]` | Chain failed custom-root validation. | Import correct Fulcio roots or investigate potential impersonation. |
|
|
||||||
| `certificate_san_untrusted` | Leaf SAN not in configured allow-list. | Update allow-list or revoke offending issuer. |
|
|
||||||
| `signature_invalid` | No signature validated with supplied public keys. | Treat as tampering; trigger incident response. |
|
|
||||||
| `proof_missing` | No Merkle proof stored for the entry. | Re-run with `refreshProof=true`; check Rekor availability. |
|
|
||||||
| `bundle_hash_decode_failed` | Stored bundle hash could not be decoded. | Verify Mongo record integrity; re-enqueue submission if necessary. |
|
|
||||||
| `proof_inclusion_missing` | Inclusion section absent from proof. | Retry proof refresh; inspect Rekor health. |
|
|
||||||
| `proof_leafhash_decode_failed` | Leaf hash malformed. | Replay submission; inspect Rekor data corruption. |
|
|
||||||
| `proof_leafhash_mismatch` | Leaf hash differs from canonical bundle hash. | Raises tamper alert; reconcile Rekor entry vs stored bundle. |
|
|
||||||
| `proof_path_decode_failed` | Inclusion path entry malformed. | Same action as above; likely Rekor data corruption. |
|
|
||||||
| `proof_path_orientation_missing` | Inclusion path lacks left/right marker. | File Rekor bug; fallback to mirror log if configured. |
|
|
||||||
| `checkpoint_missing` | Proof lacks checkpoint metadata. | Retry refresh; ensure Rekor is configured to return checkpoints. |
|
|
||||||
| `checkpoint_root_decode_failed` | Checkpoint root hash malformed. | Investigate Rekor/mirror integrity before trusting log. |
|
|
||||||
| `proof_root_mismatch` | Computed root hash != checkpoint root. | Critical alert; assume inclusion proof compromised. |
|
|
||||||
| `Proof refresh failed: …` | Rekor fetch threw an exception. | Message includes upstream error; surface alongside telemetry for debugging. |
|
|
||||||
|
|
||||||
Future explainability flags must follow the same pattern: short, lowercase codes with optional suffix payload (`code:detail`).
|
|
||||||
|
|
||||||
## 4. Worked examples
|
|
||||||
|
|
||||||
### 4.1 Successful verification
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"ok": true,
|
|
||||||
"uuid": "0192fdb4-a82b-7f90-b894-6fd1dd918b85",
|
|
||||||
"index": 73421,
|
|
||||||
"logUrl": "https://rekor.stellaops.test/api/v2/log/entries/0192fdb4a82b7f90b8946fd1dd918b85",
|
|
||||||
"status": "included",
|
|
||||||
"checkedAt": "2025-11-01T17:06:52.182394Z",
|
|
||||||
"issues": []
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
This mirrors the happy-path asserted in `AttestorVerificationServiceTests.VerifyAsync_ReturnsOk_ForExistingUuid`, which replays the entire submission→verification loop.
|
|
||||||
|
|
||||||
### 4.2 Tampered bundle
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"ok": false,
|
|
||||||
"uuid": "0192fdb4-a82b-7f90-b894-6fd1dd918b85",
|
|
||||||
"index": 73421,
|
|
||||||
"logUrl": "https://rekor.stellaops.test/api/v2/log/entries/0192fdb4a82b7f90b8946fd1dd918b85",
|
|
||||||
"status": "included",
|
|
||||||
"checkedAt": "2025-11-01T17:09:05.443218Z",
|
|
||||||
"issues": [
|
|
||||||
"bundle_hash_mismatch",
|
|
||||||
"signature_invalid"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Derived from `AttestorVerificationServiceTests.VerifyAsync_FlagsTamperedBundle`, which flips the DSSE payload and expects both issues to surface. CLI and Console consumers should display these codes verbatim and provide remediation tips from the table above.
|
|
||||||
|
|
||||||
## 5. Validating the documentation
|
|
||||||
|
|
||||||
- Run `dotnet test src/Attestor/StellaOps.Attestor/StellaOps.Attestor.Tests` to exercise the scenarios behind the examples.
|
|
||||||
- API integrators can `curl` the verify endpoint and compare responses with the JSON above.
|
|
||||||
- UI/CLI teams should ensure explainability tooltips and runbooks reference the same issue catalogue.
|
|
||||||
|
|
||||||
Keeping the documentation aligned with the test suite guarantees explainability remains deterministic and audit-friendly.
|
|
||||||
|
|
||||||
## 6. Offline bundles & air-gapped verification
|
|
||||||
|
|
||||||
Stella Ops Attestor now supports packaging attestations for sealed environments and rehydrating them without calling Rekor:
|
|
||||||
|
|
||||||
- **Export bundles.** `POST /api/v1/attestations:export` accepts either a list of Rekor UUIDs or filter criteria (`subject`, `type`, `issuer`, `scope`, `createdAfter|Before`, `limit`, `continuationToken`) and returns an `attestor.bundle.v1` document. Each item contains the attestation entry, canonical DSSE payload (base64), optional proof payload, and metadata. Responses include a `continuationToken` so callers can page through large result sets (limits default to 100 and are capped at 200). JSON content is required and requests are gated by the `attestor.read` scope.
|
|
||||||
- **Import bundles.** `POST /api/v1/attestations:import` ingests the bundle document, upserts attestation metadata, and restores the canonical DSSE/proof into the configured archive store. The S3 archive integration must be enabled; the response reports how many entries were imported versus updated, any skipped items, and issue codes (`bundle_payload_invalid_base64`, `bundle_hash_mismatch`, `archive_disabled`, …).
|
|
||||||
- **Offline verification.** When replaying verification without log connectivity, submit the DSSE bundle and set `offline=true` on `POST /api/v1/rekor/verify`. The service reuses imported proofs when present and surfaces deterministic explainability codes (`proof_missing`, `proof_inclusion_missing`, …) instead of attempting Rekor fetches.
|
|
||||||
|
|
||||||
Tests `AttestorBundleServiceTests.ExportAsync_AppliesFiltersAndContinuation`, `AttestationBundleEndpointsTests`, `AttestorVerificationServiceTests.VerifyAsync_OfflineSkipsProofRefreshWhenMissing`, and `AttestorVerificationServiceTests.VerifyAsync_OfflineUsesImportedProof` exercise the exporter/importer, API contracts, and the offline verification path with and without witness data.
|
|
||||||
|
|||||||
49
docs/modules/cli/guides/airgap.md
Normal file
49
docs/modules/cli/guides/airgap.md
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
# CLI Airgap Guide (DOCS-AIRGAP-57-003)
|
||||||
|
|
||||||
|
Offline/air-gapped usage patterns for the Stella CLI.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
- CLI installed from offline bundle; `local-nugets/` and cached plugins available.
|
||||||
|
- Mirror/Bootstrap bundles staged locally; no external network required.
|
||||||
|
- Set `STELLA_OFFLINE=true` to prevent outbound fetches.
|
||||||
|
|
||||||
|
## Common commands
|
||||||
|
- Validate mirror bundle
|
||||||
|
```bash
|
||||||
|
stella airgap verify-bundle /mnt/media/mirror.tar \
|
||||||
|
--manifest /mnt/media/manifest.json \
|
||||||
|
--trust-root /opt/stella/trust/mirror-root.pem
|
||||||
|
```
|
||||||
|
- Import bundle into local registry
|
||||||
|
```bash
|
||||||
|
stella airgap import --bundle /mnt/media/mirror.tar --generation 12
|
||||||
|
```
|
||||||
|
- Check sealed mode status
|
||||||
|
```bash
|
||||||
|
stella airgap status
|
||||||
|
```
|
||||||
|
- List bundles and staleness
|
||||||
|
```bash
|
||||||
|
stella airgap list --format table
|
||||||
|
```
|
||||||
|
|
||||||
|
## Determinism & offline rules
|
||||||
|
- Commands must succeed without egress; any outbound attempt is a bug—report with logs.
|
||||||
|
- Hashes and signatures are verified locally using bundled trust roots; no OCSP/CRL.
|
||||||
|
- Outputs are stable JSON/NDJSON; timestamps use UTC.
|
||||||
|
|
||||||
|
## Exit codes
|
||||||
|
- `0` success
|
||||||
|
- `2` validation failed (hash/signature mismatch)
|
||||||
|
- `3` sealed-mode violation (unexpected egress attempted)
|
||||||
|
- `4` input/argument error
|
||||||
|
- `>4` unexpected error (inspect logs)
|
||||||
|
|
||||||
|
## Logs
|
||||||
|
- Default stderr structured JSON: includes `tenant`, `bundleId`, `mirrorGeneration`, `sealed` flag.
|
||||||
|
- For audits, use `--log-file /var/log/stella/airgap.log --log-format json`.
|
||||||
|
|
||||||
|
## Tips
|
||||||
|
- Keep bundles on read-only media to avoid hash drift.
|
||||||
|
- Use `--dry-run` to validate without writing to registries.
|
||||||
|
- Pair with `docs/airgap/overview.md` and `docs/airgap/sealing-and-egress.md` for policy context.
|
||||||
25
docs/modules/cli/guides/attest.md
Normal file
25
docs/modules/cli/guides/attest.md
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
# CLI Attest Guide (DOCS-ATTEST-74-004)
|
||||||
|
|
||||||
|
How to verify and inspect attestations via CLI.
|
||||||
|
|
||||||
|
## Verify DSSE
|
||||||
|
```bash
|
||||||
|
stella attest verify --envelope bundle.dsse.json --policy policy.json \
|
||||||
|
--root keys/root.pem --transparency-checkpoint checkpoints/rekor.json
|
||||||
|
```
|
||||||
|
- Offline verification uses bundled roots and checkpoints; transparency optional.
|
||||||
|
|
||||||
|
## List attestations
|
||||||
|
```bash
|
||||||
|
stella attest list --tenant default --issuer dev-kms --format table
|
||||||
|
```
|
||||||
|
|
||||||
|
## Show attestation
|
||||||
|
```bash
|
||||||
|
stella attest show --id a1b2c3 --output json
|
||||||
|
```
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
- No network access required in sealed mode.
|
||||||
|
- All commands emit deterministic JSON; timestamps in UTC.
|
||||||
|
- Exit codes: 0 success, 2 verification failed, 4 input error.
|
||||||
39
docs/modules/excititor/observability/locker-manifest.md
Normal file
39
docs/modules/excititor/observability/locker-manifest.md
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
# Excititor Locker Manifest (OBS-53-001)
|
||||||
|
|
||||||
|
Defines the manifest for evidence snapshots stored in Evidence Locker / sealed-mode bundles.
|
||||||
|
|
||||||
|
## Manifest structure
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"tenant": "default",
|
||||||
|
"manifestId": "locker:excititor:2025-11-23:0001",
|
||||||
|
"createdAt": "2025-11-23T23:10:00Z",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"observationId": "vex:obs:sha256:...",
|
||||||
|
"providerId": "ubuntu-csaf",
|
||||||
|
"contentHash": "sha256:...",
|
||||||
|
"linksetId": "CVE-2024-0001:pkg:maven/org.demo/app@1.2.3",
|
||||||
|
"dsseEnvelopeHash": "sha256:...",
|
||||||
|
"provenance": {
|
||||||
|
"source": "mirror|ingest",
|
||||||
|
"mirrorGeneration": 12,
|
||||||
|
"exportCenterManifest": "sha256:..."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"merkleRoot": "sha256:...", // over `items[*].contentHash`
|
||||||
|
"signature": null, // populated in OBS-54-001 (DSSE)
|
||||||
|
"metadata": {"sealed": true}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Rules
|
||||||
|
- `items` sorted by `observationId`, then `providerId`.
|
||||||
|
- `merkleRoot` uses SHA-256 over concatenated item hashes (stable order above).
|
||||||
|
- `signature` is a DSSE envelope (hash recorded in `dsseEnvelopeHash`) when OBS-54-001 is enabled; otherwise `null`.
|
||||||
|
- Manifests are immutable; version using `manifestId` suffix.
|
||||||
|
|
||||||
|
## Storage and replay
|
||||||
|
- Store manifests alongside payloads in object storage; key prefix: `locker/excititor/<tenant>/<manifestId>`.
|
||||||
|
- Replay tools must verify `merkleRoot` before loading payloads; reject if mismatched.
|
||||||
43
docs/modules/excititor/observability/timeline-events.md
Normal file
43
docs/modules/excititor/observability/timeline-events.md
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
# Excititor Timeline Events (OBS-52-001)
|
||||||
|
|
||||||
|
Defines the event envelope for evidence timelines emitted by Excititor. All fields are aggregation-only; no consensus/merge logic.
|
||||||
|
|
||||||
|
## Envelope
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "excititor.timeline.v1",
|
||||||
|
"tenant": "default",
|
||||||
|
"eventId": "urn:uuid:...",
|
||||||
|
"timestamp": "2025-11-23T23:10:00Z",
|
||||||
|
"traceId": "beefcafe...",
|
||||||
|
"spanId": "deadb33f...",
|
||||||
|
"source": "excititor.web",
|
||||||
|
"kind": "observation|linkset",
|
||||||
|
"action": "ingest|update|backfill|replay",
|
||||||
|
"observationId": "vex:obs:sha256:...",
|
||||||
|
"linksetId": "CVE-2024-0001:pkg:maven/org.demo/app@1.2.3",
|
||||||
|
"justifications": ["component_not_present"],
|
||||||
|
"conflicts": [
|
||||||
|
{"providerId": "suse-csaf", "status": "fixed", "justification": null}
|
||||||
|
],
|
||||||
|
"evidenceHash": "sha256:...", // content-addressed payload hash
|
||||||
|
"dsseEnvelopeHash": "sha256:...", // if attested (see OBS-54-001)
|
||||||
|
"metadata": {"connector": "ubuntu-csaf", "mirrorGeneration": 12}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Semantics
|
||||||
|
- `eventId` is stable per write; retries reuse the same ID.
|
||||||
|
- `timestamp` must be UTC; derive from TimeProvider.
|
||||||
|
- `traceId`/`spanId` propagate ingestion traces; if tracing is disabled, set both to `null`.
|
||||||
|
- `kind` + `action` drive downstream storage and alerting.
|
||||||
|
- `evidenceHash` is the raw document hash; `dsseEnvelopeHash` appears only when OBS-54-001 is enabled.
|
||||||
|
|
||||||
|
## Determinism
|
||||||
|
- Sort `justifications` and `conflicts` ascending by providerId/status before emit.
|
||||||
|
- Emit at-most-once per storage write; idempotent consumers rely on `(eventId, tenant)`.
|
||||||
|
|
||||||
|
## Transport
|
||||||
|
- Default topic: `excititor.timeline.v1` (NATS/Redis). Subject includes tenant: `excititor.timeline.v1.<tenant>`.
|
||||||
|
- Payload size should stay <32 KiB; truncate conflict arrays with `truncated=true` flag if needed (keep hash counts deterministic).
|
||||||
@@ -37,6 +37,24 @@ Excititor’s evidence APIs now emit first-class OpenTelemetry metrics so Lens,
|
|||||||
3. **Alerting**: add rules for high guard violation rates, missing signatures, and abnormal chunk bytes/record counts. Tie alerts back to connectors via tenant metadata.
|
3. **Alerting**: add rules for high guard violation rates, missing signatures, and abnormal chunk bytes/record counts. Tie alerts back to connectors via tenant metadata.
|
||||||
4. **Post-deploy checks**: after each release, verify metrics emit by curling `/v1/vex/observations/...` and `/v1/vex/evidence/chunks`, watching the console exporter (dev) or OTLP (prod).
|
4. **Post-deploy checks**: after each release, verify metrics emit by curling `/v1/vex/observations/...` and `/v1/vex/evidence/chunks`, watching the console exporter (dev) or OTLP (prod).
|
||||||
|
|
||||||
|
## SLOs (Sprint 119 – OBS-51-001)
|
||||||
|
|
||||||
|
The following SLOs apply to Excititor evidence read paths when telemetry is enabled. Record them in the shared SLO registry and alert via the platform alertmanager.
|
||||||
|
|
||||||
|
| Surface | SLI | Target | Window | Burn alert | Notes |
|
||||||
|
| --- | --- | --- | --- | --- | --- |
|
||||||
|
| `/v1/vex/observations` | p95 latency | ≤ 450 ms | 7d | 2 % over 1h | Measured on successful responses only; tenant scoped. |
|
||||||
|
| `/v1/vex/observations` | freshness | ≥ 99 % within 5 min of upstream ingest | 7d | 5 % over 4h | Derived from arrival minus `createdAt`; requires ingest clocks in UTC. |
|
||||||
|
| `/v1/vex/observations` | signature presence | ≥ 98 % statements with signature present | 7d | 3 % over 24h | Use `excititor.vex.signature.status{status="missing"}`. |
|
||||||
|
| `/v1/vex/evidence/chunks` | p95 stream duration | ≤ 600 ms | 7d | 2 % over 1h | From request start to last NDJSON write; excludes client disconnects. |
|
||||||
|
| `/v1/vex/evidence/chunks` | truncation rate | ≤ 1 % truncated streams | 7d | 1 % over 1h | `excititor.vex.chunks.records` with `truncated=true`. |
|
||||||
|
| AOC guardrail | zero hard violations | 0 | continuous | immediate | Any `excititor.vex.aoc.guard_violations` with severity `error` pages ops. |
|
||||||
|
|
||||||
|
Implementation notes:
|
||||||
|
- Emit latency/freshness SLOs via OTEL views that pre-aggregate by tenant and route to the platform SLO backend; keep bucket boundaries aligned with 50/100/250/450/650/1000 ms.
|
||||||
|
- Freshness SLI derived from ingest timestamps; ensure clocks are synchronized (NTP) and stored in UTC.
|
||||||
|
- For air-gapped deployments without OTEL sinks, scrape console exporter and push to offline Prometheus; same thresholds apply.
|
||||||
|
|
||||||
## Related documents
|
## Related documents
|
||||||
|
|
||||||
- `docs/modules/excititor/architecture.md` – API contract, AOC guardrails, connector responsibilities.
|
- `docs/modules/excititor/architecture.md` – API contract, AOC guardrails, connector responsibilities.
|
||||||
|
|||||||
@@ -101,4 +101,29 @@ Response 200:
|
|||||||
- Determinism: responses sorted by `vulnerabilityId`, then `productKey`; arrays sorted lexicographically.
|
- Determinism: responses sorted by `vulnerabilityId`, then `productKey`; arrays sorted lexicographically.
|
||||||
|
|
||||||
## SDK generation
|
## SDK generation
|
||||||
- Use this file plus `vex_observations.md` as the source of truth for SDK examples in EXCITITOR-LNM-21-203.
|
- Source of truth for EXCITITOR-LNM-21-203 SDK samples (TypeScript/Go/Python) and OpenAPI snippets.
|
||||||
|
- Suggested generation inputs:
|
||||||
|
- Schema: this doc + `docs/modules/excititor/vex_observations.md` for field semantics.
|
||||||
|
- Auth: bearer token + `X-Stella-Tenant` header (required).
|
||||||
|
- Pagination: `cursor` (opaque) + `limit` (default 200, max 500).
|
||||||
|
- Minimal client example (TypeScript, fetch):
|
||||||
|
```ts
|
||||||
|
const resp = await fetch(
|
||||||
|
`${baseUrl}/v1/vex/observations?` + new URLSearchParams({
|
||||||
|
vulnerabilityId: "CVE-2024-0001",
|
||||||
|
productKey: "pkg:maven/org.demo/app@1.2.3",
|
||||||
|
limit: "100"
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
"X-Stella-Tenant": "default"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
const body = await resp.json();
|
||||||
|
```
|
||||||
|
- Determinism requirements for SDKs:
|
||||||
|
- Preserve server ordering; do not resort items client-side.
|
||||||
|
- Treat `cursor` as opaque; echo it back for next page.
|
||||||
|
- Keep enums case-sensitive as returned by API.
|
||||||
|
|||||||
@@ -31,10 +31,10 @@ OCI=1 scripts/mirror/ci-sign.sh
|
|||||||
```
|
```
|
||||||
|
|
||||||
## Temporary dev key (to unblock CI until production key is issued)
|
## Temporary dev key (to unblock CI until production key is issued)
|
||||||
Use this throwaway Ed25519 key only for non-production runs. Generated 2025-11-23 to replace the previous placeholder; rotate TUF metadata immediately after swapping in the production key.
|
Use this throwaway Ed25519 key only for non-production runs. Generated 2025-11-24 to replace the previous placeholder; rotate TUF metadata immediately after swapping in the production key.
|
||||||
|
|
||||||
```
|
```
|
||||||
MIRROR_SIGN_KEY_B64=LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1DNENBUUF3QlFZREsyVndCQ0lFSURqb3pDRVdKVVFUdW1xZ2gyRmZXcVBaemlQbkdaSzRvOFZRTThGYkZCSEcKLS0tLS1FTkQgUFJJVkFURSBLRVktLS0tLQo=
|
MIRROR_SIGN_KEY_B64=LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1DNENBUUF3QlFZREsyVndCQ0lFSUxGdFMwbjBpMVVueE1maGt0cDNlY1N4WHVxYmcrVFJuaENhS05jaGtTbFIKLS0tLS1FTkQgUFJJVkFURSBLRVktLS0tLQo=
|
||||||
```
|
```
|
||||||
|
|
||||||
**Do not ship with this key.** Set `REQUIRE_PROD_SIGNING=1` for release/tag builds so they fail without the real key. Add the production key as a Gitea secret (`MIRROR_SIGN_KEY_B64`) and rerun the workflow; remove this temporary key block once rotated.
|
**Do not ship with this key.** Set `REQUIRE_PROD_SIGNING=1` for release/tag builds so they fail without the real key. Add the production key as a Gitea secret (`MIRROR_SIGN_KEY_B64`) and rerun the workflow; remove this temporary key block once rotated.
|
||||||
|
|||||||
@@ -208,8 +208,17 @@ All payloads are immutable and include analyzer fingerprints (`scanner.native@sh
|
|||||||
- **Scopes:** Mutations require `policy:*` scopes corresponding to action; `effective:write` restricted to service identity.
|
- **Scopes:** Mutations require `policy:*` scopes corresponding to action; `effective:write` restricted to service identity.
|
||||||
- **Tenancy:** All queries filter by `tenant`. Service identity uses `tenant-global` for shared policies; cross-tenant reads prohibited unless `policy:tenant-admin` scope present.
|
- **Tenancy:** All queries filter by `tenant`. Service identity uses `tenant-global` for shared policies; cross-tenant reads prohibited unless `policy:tenant-admin` scope present.
|
||||||
- **Secrets:** Configuration loaded via environment variables or sealed secrets; runtime avoids writing secrets to logs.
|
- **Secrets:** Configuration loaded via environment variables or sealed secrets; runtime avoids writing secrets to logs.
|
||||||
- **Determinism guard:** Static analyzer prevents referencing forbidden namespaces; runtime guard intercepts `DateTime.Now`, `Random`, `Guid`, HTTP clients beyond allow-list.
|
- **Determinism guard:** Static analyzer prevents referencing forbidden namespaces; runtime guard intercepts `DateTime.Now`, `Random`, `Guid`, HTTP clients beyond allow-list.
|
||||||
- **Sealed mode:** Global flag disables outbound network except allow-listed internal hosts; watchers fail fast if unexpected egress attempted.
|
- **Sealed mode:** Global flag disables outbound network except allow-listed internal hosts; watchers fail fast if unexpected egress attempted.
|
||||||
|
|
||||||
|
### Determinism enforcement (DOCS-POLICY-DET-01)
|
||||||
|
|
||||||
|
- **Inputs are ordered and frozen:** Selector emits batches sorted deterministically by `(tenant, policyId, vulnerabilityId, productKey, source)` with stable cursors; workers must not resort.
|
||||||
|
- **No ambient randomness or wall clocks:** Policy code relies on injected `TimeProvider`/`IRandom` shims; guards block `DateTime.Now`, `Guid.NewGuid`, `Random` when not injected.
|
||||||
|
- **Immutable evidence:** SBOM/VEX inputs carry content hashes; evaluator treats payloads as read-only and surfaces hashes in logs for replay.
|
||||||
|
- **Side effects prohibited:** Evaluator cannot call external HTTP except allow-listed internal services (Authority, Storage) and must not write files outside temp workspace.
|
||||||
|
- **Replay hash:** Each batch computes `determinismHash = SHA256(policyVersion + batchCursor + inputsHash)`; included in logs and run exports.
|
||||||
|
- **Testing:** Determinism tests run the same batch twice with seeded clock/GUID providers and assert identical outputs + determinismHash; add a test per policy package.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
29
docs/modules/policy/samples/advisory-ai-knobs@draft.json
Normal file
29
docs/modules/policy/samples/advisory-ai-knobs@draft.json
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"knobs": [
|
||||||
|
{
|
||||||
|
"name": "ai_signal_weight",
|
||||||
|
"default_value": 1.2,
|
||||||
|
"min": 0.0,
|
||||||
|
"max": 2.0,
|
||||||
|
"step": 0.1,
|
||||||
|
"description": "Weight applied to Advisory AI signal scores"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "reachability_boost",
|
||||||
|
"default_value": 0.25,
|
||||||
|
"min": 0.0,
|
||||||
|
"max": 1.0,
|
||||||
|
"step": 0.05,
|
||||||
|
"description": "Boost when asset is reachable"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "time_decay_half_life_days",
|
||||||
|
"default_value": 45,
|
||||||
|
"min": 1,
|
||||||
|
"max": 365,
|
||||||
|
"step": 1,
|
||||||
|
"description": "Half-life in days for signal decay"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"profile_hash": "ADVISORYAIHASH"
|
||||||
|
}
|
||||||
16
docs/modules/policy/samples/orchestrator-job@draft.json
Normal file
16
docs/modules/policy/samples/orchestrator-job@draft.json
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"job_id": "01HZX1QJP6Z3MNA0Q2T3VCPV5K",
|
||||||
|
"tenant_id": "acme",
|
||||||
|
"context_id": "ctx-2025-11-24T10:00:00Z",
|
||||||
|
"policy_profile_hash": "overlay-hash-123",
|
||||||
|
"priority": "high",
|
||||||
|
"requested_at": "2025-11-24T10:00:00Z",
|
||||||
|
"status": "queued",
|
||||||
|
"trace_ref": "4E5C2B5E22F928E846B0EFBC58AA53FC3218C8C172199FF52C7C09244E0C0D30",
|
||||||
|
"determinism_hash": "2C855E80F66D30D5E51C4D9A0441A63C5BB8F04DC1EC537D0ADB7B9357A4C713",
|
||||||
|
"batch_items": [
|
||||||
|
{ "component_purl": "pkg:npm/alpha@1.0.0", "advisory_id": "ADV-1" },
|
||||||
|
{ "component_purl": "pkg:npm/zeta@1.0.0", "advisory_id": "ADV-2" }
|
||||||
|
],
|
||||||
|
"callbacks": { "sse": "sse://events", "nats": "policy.jobs" }
|
||||||
|
}
|
||||||
11
docs/modules/policy/samples/policy-batch-context@draft.json
Normal file
11
docs/modules/policy/samples/policy-batch-context@draft.json
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"tenant_id": "acme",
|
||||||
|
"policy_profile_hash": "overlay-hash-123",
|
||||||
|
"knobs_version": "knobs-v1",
|
||||||
|
"overlay_hash": "overlay-hash-123",
|
||||||
|
"items": [
|
||||||
|
{ "component_purl": "pkg:npm/lodash@4.17.21", "advisory_id": "ADV-2025-0001" },
|
||||||
|
{ "component_purl": "pkg:npm/left-pad@1.3.0", "advisory_id": "ADV-2025-0002" }
|
||||||
|
],
|
||||||
|
"options": { "include_reachability": true }
|
||||||
|
}
|
||||||
32
docs/modules/policy/samples/policy-conflict@draft.json
Normal file
32
docs/modules/policy/samples/policy-conflict@draft.json
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"tenant_id": "acme",
|
||||||
|
"component_purl": "pkg:npm/alpha@1.0.0",
|
||||||
|
"advisory_id": "ADV-1",
|
||||||
|
"conflicts": [
|
||||||
|
{
|
||||||
|
"tenant_id": "acme",
|
||||||
|
"snapshot_id": "01HZX3GN4V6KBW1PXJ0K3VXEGT",
|
||||||
|
"component_purl": "pkg:npm/alpha@1.0.0",
|
||||||
|
"advisory_id": "ADV-1",
|
||||||
|
"severity_fused": "high",
|
||||||
|
"score": 0.900,
|
||||||
|
"sources": [
|
||||||
|
{ "source": "policy-engine", "weight": 1.050, "severity": "high", "score": 0.945 }
|
||||||
|
],
|
||||||
|
"reason_codes": ["weights-applied", "deterministic-fusion"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tenant_id": "acme",
|
||||||
|
"snapshot_id": "01HZX3GN4V6KBW1PXJ0K3VXEGT",
|
||||||
|
"component_purl": "pkg:npm/alpha@1.0.0",
|
||||||
|
"advisory_id": "ADV-1",
|
||||||
|
"severity_fused": "medium",
|
||||||
|
"score": 0.600,
|
||||||
|
"sources": [
|
||||||
|
{ "source": "policy-engine", "weight": 1.050, "severity": "medium", "score": 0.630 }
|
||||||
|
],
|
||||||
|
"reason_codes": ["weights-applied", "deterministic-fusion"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"resolved_status": null
|
||||||
|
}
|
||||||
36
docs/modules/policy/samples/policy-ledger-export@draft.json
Normal file
36
docs/modules/policy/samples/policy-ledger-export@draft.json
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
{
|
||||||
|
"manifest": {
|
||||||
|
"export_id": "01HZX2KDRT9Q9K5AZXWPRH62VE",
|
||||||
|
"schema_version": "policy-ledger-export-v1",
|
||||||
|
"generated_at": "2025-11-24T15:00:00Z",
|
||||||
|
"record_count": 2,
|
||||||
|
"sha256": "D4B8C98A2F946D93AFBDE6C4DE6535853A223E108A4A2C389E2C2623D3761C1E"
|
||||||
|
},
|
||||||
|
"records": [
|
||||||
|
{
|
||||||
|
"tenant_id": "acme",
|
||||||
|
"job_id": "job-1",
|
||||||
|
"context_id": "ctx",
|
||||||
|
"component_purl": "pkg:npm/alpha@1.0.0",
|
||||||
|
"advisory_id": "ADV-1",
|
||||||
|
"status": "violation",
|
||||||
|
"trace_ref": "trace-a",
|
||||||
|
"occurred_at": "2025-11-24T15:00:00Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tenant_id": "acme",
|
||||||
|
"job_id": "job-1",
|
||||||
|
"context_id": "ctx",
|
||||||
|
"component_purl": "pkg:npm/zeta@1.0.0",
|
||||||
|
"advisory_id": "ADV-2",
|
||||||
|
"status": "ok",
|
||||||
|
"trace_ref": "trace-b",
|
||||||
|
"occurred_at": "2025-11-24T15:00:00Z"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"lines": [
|
||||||
|
"{\"export_id\":\"01HZX2KDRT9Q9K5AZXWPRH62VE\",\"schema_version\":\"policy-ledger-export-v1\",\"generated_at\":\"2025-11-24T15:00:00Z\",\"record_count\":2,\"sha256\":\"D4B8C98A2F946D93AFBDE6C4DE6535853A223E108A4A2C389E2C2623D3761C1E\"}",
|
||||||
|
"{\"tenant_id\":\"acme\",\"job_id\":\"job-1\",\"context_id\":\"ctx\",\"component_purl\":\"pkg:npm/alpha@1.0.0\",\"advisory_id\":\"ADV-1\",\"status\":\"violation\",\"trace_ref\":\"trace-a\",\"occurred_at\":\"2025-11-24T15:00:00Z\"}",
|
||||||
|
"{\"tenant_id\":\"acme\",\"job_id\":\"job-1\",\"context_id\":\"ctx\",\"component_purl\":\"pkg:npm/zeta@1.0.0\",\"advisory_id\":\"ADV-2\",\"status\":\"ok\",\"trace_ref\":\"trace-b\",\"occurred_at\":\"2025-11-24T15:00:00Z\"}"
|
||||||
|
]
|
||||||
|
}
|
||||||
30
docs/modules/policy/samples/policy-snapshot@draft.json
Normal file
30
docs/modules/policy/samples/policy-snapshot@draft.json
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"snapshot_id": "01HZX3GN4V6KBW1PXJ0K3VXEGT",
|
||||||
|
"tenant_id": "acme",
|
||||||
|
"ledger_export_id": "01HZX2KDRT9Q9K5AZXWPRH62VE",
|
||||||
|
"generated_at": "2025-11-24T16:00:00Z",
|
||||||
|
"overlay_hash": "overlay-1",
|
||||||
|
"status_counts": { "violation": 1, "ok": 1 },
|
||||||
|
"records": [
|
||||||
|
{
|
||||||
|
"tenant_id": "acme",
|
||||||
|
"job_id": "job-1",
|
||||||
|
"context_id": "ctx",
|
||||||
|
"component_purl": "pkg:npm/alpha@1.0.0",
|
||||||
|
"advisory_id": "ADV-1",
|
||||||
|
"status": "violation",
|
||||||
|
"trace_ref": "trace-a",
|
||||||
|
"occurred_at": "2025-11-24T15:00:00Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tenant_id": "acme",
|
||||||
|
"job_id": "job-1",
|
||||||
|
"context_id": "ctx",
|
||||||
|
"component_purl": "pkg:npm/zeta@1.0.0",
|
||||||
|
"advisory_id": "ADV-2",
|
||||||
|
"status": "ok",
|
||||||
|
"trace_ref": "trace-b",
|
||||||
|
"occurred_at": "2025-11-24T15:00:00Z"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"event_id": "E7A1F3B0D6F243B4868A6D4B3E7B2AB9",
|
||||||
|
"tenant_id": "acme",
|
||||||
|
"snapshot_id": "01HZX3GN4V6KBW1PXJ0K3VXEGT",
|
||||||
|
"policy_profile_hash": "overlay-hash-123",
|
||||||
|
"component_purl": "pkg:npm/alpha@1.0.0",
|
||||||
|
"advisory_id": "ADV-1",
|
||||||
|
"violation_code": "policy.violation.detected",
|
||||||
|
"severity": "high",
|
||||||
|
"status": "violation",
|
||||||
|
"trace_ref": "trace-a",
|
||||||
|
"occurred_at": "2025-11-24T16:00:00Z"
|
||||||
|
}
|
||||||
11
docs/modules/policy/samples/policy-worker-result@draft.json
Normal file
11
docs/modules/policy/samples/policy-worker-result@draft.json
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"job_id": "01HZX1QJP6Z3MNA0Q2T3VCPV5K",
|
||||||
|
"worker_id": "worker-stub",
|
||||||
|
"started_at": "2025-11-24T13:00:00Z",
|
||||||
|
"completed_at": "2025-11-24T13:00:01Z",
|
||||||
|
"result_hash": "5E5A4EFA8C7E9952E4E5E5D9E2B9F3A5D46B13E44CB6E0D7292F7D5CB40CF182",
|
||||||
|
"results": [
|
||||||
|
{ "component_purl": "pkg:npm/alpha@1.0.0", "advisory_id": "ADV-1", "status": "violation", "trace_ref": "F5D9B8717EAB4B0252BE22325771C4F9F8ABAE4E7728F3221E15C5F24A8E8D9F" },
|
||||||
|
{ "component_purl": "pkg:npm/zeta@1.0.0", "advisory_id": "ADV-2", "status": "ok", "trace_ref": "3C75CC86A30B6E230D1DE2D5F08F9B0F5CF75AB1931E47372DC7AC2175BE3F6C" }
|
||||||
|
]
|
||||||
|
}
|
||||||
12
docs/modules/policy/samples/severity-fusion@draft.json
Normal file
12
docs/modules/policy/samples/severity-fusion@draft.json
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"tenant_id": "acme",
|
||||||
|
"snapshot_id": "01HZX3GN4V6KBW1PXJ0K3VXEGT",
|
||||||
|
"component_purl": "pkg:npm/alpha@1.0.0",
|
||||||
|
"advisory_id": "ADV-1",
|
||||||
|
"severity_fused": "high",
|
||||||
|
"score": 0.900,
|
||||||
|
"sources": [
|
||||||
|
{ "source": "policy-engine", "weight": 1.050, "severity": "high", "score": 0.945 }
|
||||||
|
],
|
||||||
|
"reason_codes": ["weights-applied", "deterministic-fusion"]
|
||||||
|
}
|
||||||
23
docs/modules/policy/samples/trust-weighting@draft.json
Normal file
23
docs/modules/policy/samples/trust-weighting@draft.json
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"weights": [
|
||||||
|
{
|
||||||
|
"source": "cartographer",
|
||||||
|
"weight": 1.000,
|
||||||
|
"justification": "default baseline",
|
||||||
|
"updated_at": "2025-11-23T12:00:00Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": "scanner",
|
||||||
|
"weight": 0.950,
|
||||||
|
"justification": "prefer curated SBOM sources",
|
||||||
|
"updated_at": "2025-11-23T12:00:00Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": "concelier",
|
||||||
|
"weight": 1.050,
|
||||||
|
"justification": "policy engine override",
|
||||||
|
"updated_at": "2025-11-23T12:00:00Z"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"profile_hash": "D1A5F0A0DEFAULTHASH"
|
||||||
|
}
|
||||||
27
docs/modules/policy/schemas/advisory-ai-knobs@draft.json
Normal file
27
docs/modules/policy/schemas/advisory-ai-knobs@draft.json
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "advisory-ai-knobs@draft",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"knobs": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"name": { "type": "string", "minLength": 1 },
|
||||||
|
"default_value": { "type": "number" },
|
||||||
|
"min": { "type": "number" },
|
||||||
|
"max": { "type": "number" },
|
||||||
|
"step": { "type": "number" },
|
||||||
|
"description": { "type": "string" }
|
||||||
|
},
|
||||||
|
"required": ["name", "default_value", "min", "max", "step", "description"],
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"minItems": 1
|
||||||
|
},
|
||||||
|
"profile_hash": { "type": "string", "minLength": 1 }
|
||||||
|
},
|
||||||
|
"required": ["knobs", "profile_hash"],
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
51
docs/modules/policy/schemas/orchestrator-job@draft.json
Normal file
51
docs/modules/policy/schemas/orchestrator-job@draft.json
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "orchestrator-job@draft",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"job_id": { "type": "string", "minLength": 1 },
|
||||||
|
"tenant_id": { "type": "string", "minLength": 1 },
|
||||||
|
"context_id": { "type": "string", "minLength": 1 },
|
||||||
|
"policy_profile_hash": { "type": "string", "minLength": 1 },
|
||||||
|
"priority": { "type": "string", "enum": ["normal", "high", "emergency", "preview"] },
|
||||||
|
"requested_at": { "type": "string", "format": "date-time" },
|
||||||
|
"status": { "type": "string", "minLength": 1 },
|
||||||
|
"trace_ref": { "type": "string", "minLength": 1 },
|
||||||
|
"determinism_hash": { "type": "string", "minLength": 1 },
|
||||||
|
"completed_at": { "type": ["string", "null"], "format": "date-time" },
|
||||||
|
"result_hash": { "type": ["string", "null"] },
|
||||||
|
"batch_items": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"component_purl": { "type": "string", "minLength": 1 },
|
||||||
|
"advisory_id": { "type": "string", "minLength": 1 }
|
||||||
|
},
|
||||||
|
"required": ["component_purl", "advisory_id"],
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"minItems": 1
|
||||||
|
},
|
||||||
|
"callbacks": {
|
||||||
|
"type": ["object", "null"],
|
||||||
|
"properties": {
|
||||||
|
"sse": { "type": ["string", "null"] },
|
||||||
|
"nats": { "type": ["string", "null"] }
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"job_id",
|
||||||
|
"tenant_id",
|
||||||
|
"context_id",
|
||||||
|
"policy_profile_hash",
|
||||||
|
"priority",
|
||||||
|
"requested_at",
|
||||||
|
"status",
|
||||||
|
"determinism_hash",
|
||||||
|
"batch_items"
|
||||||
|
],
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
41
docs/modules/policy/schemas/policy-batch-context@draft.json
Normal file
41
docs/modules/policy/schemas/policy-batch-context@draft.json
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "policy-batch-context@draft",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"tenant_id": { "type": "string", "minLength": 1 },
|
||||||
|
"policy_profile_hash": { "type": "string", "minLength": 1 },
|
||||||
|
"knobs_version": { "type": "string", "minLength": 1 },
|
||||||
|
"overlay_hash": { "type": "string", "minLength": 1 },
|
||||||
|
"items": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"component_purl": { "type": "string", "minLength": 1 },
|
||||||
|
"advisory_id": { "type": "string", "minLength": 1 }
|
||||||
|
},
|
||||||
|
"required": ["component_purl", "advisory_id"],
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"minItems": 1
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"include_reachability": { "type": "boolean" }
|
||||||
|
},
|
||||||
|
"required": ["include_reachability"],
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"tenant_id",
|
||||||
|
"policy_profile_hash",
|
||||||
|
"knobs_version",
|
||||||
|
"overlay_hash",
|
||||||
|
"items",
|
||||||
|
"options"
|
||||||
|
],
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
17
docs/modules/policy/schemas/policy-conflict@draft.json
Normal file
17
docs/modules/policy/schemas/policy-conflict@draft.json
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "policy-conflict@draft",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"tenant_id": { "type": "string", "minLength": 1 },
|
||||||
|
"component_purl": { "type": "string", "minLength": 1 },
|
||||||
|
"advisory_id": { "type": "string", "minLength": 1 },
|
||||||
|
"conflicts": {
|
||||||
|
"type": "array",
|
||||||
|
"items": { "$ref": "severity-fusion@draft.json" }
|
||||||
|
},
|
||||||
|
"resolved_status": { "type": ["string", "null"] }
|
||||||
|
},
|
||||||
|
"required": ["tenant_id", "component_purl", "advisory_id", "conflicts"],
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
40
docs/modules/policy/schemas/policy-ledger-export@draft.json
Normal file
40
docs/modules/policy/schemas/policy-ledger-export@draft.json
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "policy-ledger-export@draft",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"manifest": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"export_id": { "type": "string", "minLength": 1 },
|
||||||
|
"schema_version": { "type": "string", "minLength": 1 },
|
||||||
|
"generated_at": { "type": "string", "format": "date-time" },
|
||||||
|
"record_count": { "type": "integer", "minimum": 0 },
|
||||||
|
"sha256": { "type": "string", "minLength": 1 }
|
||||||
|
},
|
||||||
|
"required": ["export_id", "schema_version", "generated_at", "record_count", "sha256"],
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"records": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"tenant_id": { "type": "string", "minLength": 1 },
|
||||||
|
"job_id": { "type": "string", "minLength": 1 },
|
||||||
|
"context_id": { "type": "string", "minLength": 1 },
|
||||||
|
"component_purl": { "type": "string", "minLength": 1 },
|
||||||
|
"advisory_id": { "type": "string", "minLength": 1 },
|
||||||
|
"status": { "type": "string", "minLength": 1 },
|
||||||
|
"trace_ref": { "type": "string", "minLength": 1 },
|
||||||
|
"occurred_at": { "type": "string", "format": "date-time" }
|
||||||
|
},
|
||||||
|
"required": ["tenant_id", "job_id", "context_id", "component_purl", "advisory_id", "status", "trace_ref", "occurred_at"],
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"lines": { "type": "array", "items": { "type": "string" } }
|
||||||
|
},
|
||||||
|
"required": ["manifest", "records", "lines"],
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
33
docs/modules/policy/schemas/policy-snapshot@draft.json
Normal file
33
docs/modules/policy/schemas/policy-snapshot@draft.json
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "policy-snapshot@draft",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"snapshot_id": { "type": "string", "minLength": 1 },
|
||||||
|
"tenant_id": { "type": "string", "minLength": 1 },
|
||||||
|
"ledger_export_id": { "type": "string", "minLength": 1 },
|
||||||
|
"generated_at": { "type": "string", "format": "date-time" },
|
||||||
|
"overlay_hash": { "type": "string", "minLength": 1 },
|
||||||
|
"status_counts": { "type": "object", "additionalProperties": { "type": "integer" } },
|
||||||
|
"records": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"tenant_id": { "type": "string" },
|
||||||
|
"job_id": { "type": "string" },
|
||||||
|
"context_id": { "type": "string" },
|
||||||
|
"component_purl": { "type": "string" },
|
||||||
|
"advisory_id": { "type": "string" },
|
||||||
|
"status": { "type": "string" },
|
||||||
|
"trace_ref": { "type": "string" },
|
||||||
|
"occurred_at": { "type": "string", "format": "date-time" }
|
||||||
|
},
|
||||||
|
"required": ["tenant_id", "job_id", "context_id", "component_purl", "advisory_id", "status", "trace_ref", "occurred_at"],
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["snapshot_id", "tenant_id", "ledger_export_id", "generated_at", "overlay_hash", "status_counts", "records"],
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "policy-violation-event@draft",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"event_id": { "type": "string", "minLength": 1 },
|
||||||
|
"tenant_id": { "type": "string", "minLength": 1 },
|
||||||
|
"snapshot_id": { "type": "string", "minLength": 1 },
|
||||||
|
"policy_profile_hash": { "type": "string", "minLength": 1 },
|
||||||
|
"component_purl": { "type": "string", "minLength": 1 },
|
||||||
|
"advisory_id": { "type": "string", "minLength": 1 },
|
||||||
|
"violation_code": { "type": "string", "minLength": 1 },
|
||||||
|
"severity": { "type": "string", "minLength": 1 },
|
||||||
|
"status": { "type": "string", "minLength": 1 },
|
||||||
|
"trace_ref": { "type": "string", "minLength": 1 },
|
||||||
|
"occurred_at": { "type": "string", "format": "date-time" }
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"event_id",
|
||||||
|
"tenant_id",
|
||||||
|
"snapshot_id",
|
||||||
|
"policy_profile_hash",
|
||||||
|
"component_purl",
|
||||||
|
"advisory_id",
|
||||||
|
"violation_code",
|
||||||
|
"severity",
|
||||||
|
"status",
|
||||||
|
"trace_ref",
|
||||||
|
"occurred_at"
|
||||||
|
],
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
29
docs/modules/policy/schemas/policy-worker-result@draft.json
Normal file
29
docs/modules/policy/schemas/policy-worker-result@draft.json
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "policy-worker-result@draft",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"job_id": { "type": "string", "minLength": 1 },
|
||||||
|
"worker_id": { "type": "string", "minLength": 1 },
|
||||||
|
"started_at": { "type": "string", "format": "date-time" },
|
||||||
|
"completed_at": { "type": "string", "format": "date-time" },
|
||||||
|
"result_hash": { "type": "string", "minLength": 1 },
|
||||||
|
"results": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"component_purl": { "type": "string", "minLength": 1 },
|
||||||
|
"advisory_id": { "type": "string", "minLength": 1 },
|
||||||
|
"status": { "type": "string", "minLength": 1 },
|
||||||
|
"trace_ref": { "type": "string", "minLength": 1 }
|
||||||
|
},
|
||||||
|
"required": ["component_purl", "advisory_id", "status", "trace_ref"],
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"minItems": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["job_id", "worker_id", "started_at", "completed_at", "result_hash", "results"],
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
30
docs/modules/policy/schemas/severity-fusion@draft.json
Normal file
30
docs/modules/policy/schemas/severity-fusion@draft.json
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "severity-fusion@draft",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"tenant_id": { "type": "string", "minLength": 1 },
|
||||||
|
"snapshot_id": { "type": "string", "minLength": 1 },
|
||||||
|
"component_purl": { "type": "string", "minLength": 1 },
|
||||||
|
"advisory_id": { "type": "string", "minLength": 1 },
|
||||||
|
"severity_fused": { "type": "string", "minLength": 1 },
|
||||||
|
"score": { "type": "number" },
|
||||||
|
"sources": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"source": { "type": "string", "minLength": 1 },
|
||||||
|
"weight": { "type": "number" },
|
||||||
|
"severity": { "type": "string", "minLength": 1 },
|
||||||
|
"score": { "type": "number" }
|
||||||
|
},
|
||||||
|
"required": ["source", "weight", "severity", "score"],
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"reason_codes": { "type": "array", "items": { "type": "string" } }
|
||||||
|
},
|
||||||
|
"required": ["tenant_id", "snapshot_id", "component_purl", "advisory_id", "severity_fused", "score", "sources", "reason_codes"],
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
25
docs/modules/policy/schemas/trust-weighting@draft.json
Normal file
25
docs/modules/policy/schemas/trust-weighting@draft.json
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "trust-weighting@draft",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"weights": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"source": { "type": "string", "minLength": 1 },
|
||||||
|
"weight": { "type": "number" },
|
||||||
|
"justification": { "type": ["string", "null"] },
|
||||||
|
"updated_at": { "type": "string", "format": "date-time" }
|
||||||
|
},
|
||||||
|
"required": ["source", "weight", "updated_at"],
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"minItems": 1
|
||||||
|
},
|
||||||
|
"profile_hash": { "type": "string", "minLength": 1 }
|
||||||
|
},
|
||||||
|
"required": ["weights", "profile_hash"],
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
@@ -44,8 +44,16 @@ Operational rules:
|
|||||||
- `GET /console/sboms` — Console catalog with filters (artifact, license, scope, asset tags), cursor pagination, evaluation metadata, immutable JSON projection for drawer views.
|
- `GET /console/sboms` — Console catalog with filters (artifact, license, scope, asset tags), cursor pagination, evaluation metadata, immutable JSON projection for drawer views.
|
||||||
- `GET /components/lookup?purl=...` — component neighborhood for global search/Graph overlays; returns caches hints + tenant enforcement.
|
- `GET /components/lookup?purl=...` — component neighborhood for global search/Graph overlays; returns caches hints + tenant enforcement.
|
||||||
- `POST /entrypoints` / `GET /entrypoints` — manage entrypoint/service node overrides feeding Cartographer relevance; deterministic defaults when unset.
|
- `POST /entrypoints` / `GET /entrypoints` — manage entrypoint/service node overrides feeding Cartographer relevance; deterministic defaults when unset.
|
||||||
|
- `GET /sboms/{snapshotId}/projection` — Link-Not-Merge v1 projection returning hashes plus asset metadata (criticality, owner, environment, exposure flags, tags) alongside package/component graph.
|
||||||
- `GET /internal/sbom/events` — internal diagnostics endpoint returning the in-memory event outbox for validation.
|
- `GET /internal/sbom/events` — internal diagnostics endpoint returning the in-memory event outbox for validation.
|
||||||
- `POST /internal/sbom/events/backfill` — replays existing projections into the event stream; deterministic ordering, clock abstraction for tests.
|
- `POST /internal/sbom/events/backfill` — replays existing projections into the event stream; deterministic ordering, clock abstraction for tests.
|
||||||
|
- `GET /internal/sbom/asset-events` — diagnostics endpoint returning emitted `sbom.asset.updated` envelopes for validation and air-gap parity checks.
|
||||||
|
- `GET/POST /internal/orchestrator/sources` — list/register orchestrator ingest/index sources (deterministic seeds; idempotent on artifactDigest+sourceType).
|
||||||
|
- `GET/POST /internal/orchestrator/control` — manage pause/throttle/backpressure signals per tenant; metrics emitted for control updates.
|
||||||
|
- `GET/POST /internal/orchestrator/watermarks` — fetch/set backfill watermarks for reconciliation and deterministic replays.
|
||||||
|
- `GET /internal/sbom/resolver-feed` — list resolver candidates (artifact, purl, version, paths, scope, runtime_flag, nearest_safe_version).
|
||||||
|
- `POST /internal/sbom/resolver-feed/backfill` — clear and repopulate resolver feed from current projections.
|
||||||
|
- `GET /internal/sbom/resolver-feed/export` — NDJSON export of resolver candidates for air-gap delivery.
|
||||||
|
|
||||||
## 4) Ingestion & orchestrator integration
|
## 4) Ingestion & orchestrator integration
|
||||||
- Ingest sources: Scanner pipeline (preferred) or uploaded SPDX 3.0.1/CycloneDX 1.6 bundles.
|
- Ingest sources: Scanner pipeline (preferred) or uploaded SPDX 3.0.1/CycloneDX 1.6 bundles.
|
||||||
@@ -70,7 +78,8 @@ Operational rules:
|
|||||||
- Input validation: schema-validate incoming SBOMs; reject oversized/unsupported media types early.
|
- Input validation: schema-validate incoming SBOMs; reject oversized/unsupported media types early.
|
||||||
|
|
||||||
## 8) Observability
|
## 8) Observability
|
||||||
- Metrics: `sbom_projection_seconds`, `sbom_projection_size_bytes`, `sbom_paths_latency_seconds`, `sbom_paths_cache_hit_ratio`, `sbom_events_backlog`.
|
- Metrics: `sbom_projection_seconds`, `sbom_projection_size_bytes`, `sbom_projection_queries_total`, `sbom_paths_latency_seconds`, `sbom_paths_cache_hit_ratio`, `sbom_events_backlog`.
|
||||||
|
- Tracing: ActivitySource `StellaOps.SbomService` (entrypoints, component lookup, console catalog, projections, events).
|
||||||
- Traces: wrap ingest, projection build, and API handlers; propagate orchestrator job IDs.
|
- Traces: wrap ingest, projection build, and API handlers; propagate orchestrator job IDs.
|
||||||
- Logs: structured, include tenant + artifact digest + sbomVersion; classify ingest failures (schema, storage, orchestrator, validation).
|
- Logs: structured, include tenant + artifact digest + sbomVersion; classify ingest failures (schema, storage, orchestrator, validation).
|
||||||
- Alerts: backlog thresholds for outbox/event delivery; high latency on path/timeline endpoints.
|
- Alerts: backlog thresholds for outbox/event delivery; high latency on path/timeline endpoints.
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
[{"snapshotId":"snap-001","tenantId":"tenant-a","projection":{"purl":"pkg:npm/lodash@4.17.21","paths":[],"metadata":{"schemaVersion":"1.0.0"}}}]
|
[{"snapshotId":"snap-001","tenantId":"tenant-a","projection":{"purl":"pkg:npm/lodash@4.17.21","paths":[],"metadata":{"schemaVersion":"1.0.0","asset":{"criticality":"high","owner":"team-console","environment":"prod","exposure":["internet","pci"],"tags":{"tier":"1","service":"sample-api"}}}}}]
|
||||||
|
|||||||
33
docs/security/trust-and-signing.md
Normal file
33
docs/security/trust-and-signing.md
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# Trust and Signing (DOCS-AIRGAP-58-002)
|
||||||
|
|
||||||
|
Guidance on DSSE/TUF roots, rotation, and signed time tokens.
|
||||||
|
|
||||||
|
## Trust roots
|
||||||
|
- Maintain offline root keys for DSSE/TUF; store in HSM or sealed vault.
|
||||||
|
- Distribute intermediate/leaf keys via bootstrap packs with fingerprints.
|
||||||
|
- Keep trust roots versioned; record `rootVersion` and validity period.
|
||||||
|
|
||||||
|
## DSSE
|
||||||
|
- Use DSSE for bundle manifests (mirror/bootstrap) and evidence timelines when possible.
|
||||||
|
- Verification in sealed mode uses bundled roots; no online Rekor needed.
|
||||||
|
- Rotate signing keys with overlapping validity; publish new root in next bundle.
|
||||||
|
|
||||||
|
## TUF (optional)
|
||||||
|
- If using TUF metadata, ship `root.json`, `snapshot.json`, `timestamp.json` with bundles.
|
||||||
|
- In sealed mode, trust only bundled metadata; no remote refresh.
|
||||||
|
|
||||||
|
## Signed time tokens
|
||||||
|
- Export signed time anchors (see `docs/airgap/staleness-and-time.md`):
|
||||||
|
- Token fields: `issuedAt`, `notAfter`, `timeSource`, `signature`, `rootVersion`.
|
||||||
|
- Validate offline against trust roots; expire strictly at `notAfter`.
|
||||||
|
|
||||||
|
## Rotation procedure
|
||||||
|
1. Prepare new root and leaf keys; sign new root with current root.
|
||||||
|
2. Include new `root.json` and fingerprints in next mirror/bootstrap bundle.
|
||||||
|
3. During import, verify both current and new root; switch default after verification.
|
||||||
|
4. Re-sign manifests/time tokens with new leaf.
|
||||||
|
|
||||||
|
## Security notes
|
||||||
|
- Never fetch keys online in sealed mode.
|
||||||
|
- Keep audit log of rotations (who, when, rootVersion, fingerprints).
|
||||||
|
- Enforce least privilege for signing service accounts.
|
||||||
@@ -1,12 +1,14 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
import fs from 'node:fs';
|
import fs from 'node:fs';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
|
import crypto from 'node:crypto';
|
||||||
import yaml from 'yaml';
|
import yaml from 'yaml';
|
||||||
|
|
||||||
const ROOT = path.resolve('src/Api/StellaOps.Api.OpenApi');
|
const ROOT = path.resolve('src/Api/StellaOps.Api.OpenApi');
|
||||||
const BASELINE = path.join(ROOT, 'baselines', 'stella-baseline.yaml');
|
const BASELINE = path.join(ROOT, 'baselines', 'stella-baseline.yaml');
|
||||||
const CURRENT = path.join(ROOT, 'stella.yaml');
|
const CURRENT = path.join(ROOT, 'stella.yaml');
|
||||||
const OUTPUT = path.join(ROOT, 'CHANGELOG.md');
|
const OUTPUT = path.join(ROOT, 'CHANGELOG.md');
|
||||||
|
const RELEASE_OUT = path.resolve('src/Sdk/StellaOps.Sdk.Release/out/api-changelog');
|
||||||
|
|
||||||
function panic(message) {
|
function panic(message) {
|
||||||
console.error(`[api:changelog] ${message}`);
|
console.error(`[api:changelog] ${message}`);
|
||||||
@@ -76,6 +78,25 @@ function renderMarkdown(diff) {
|
|||||||
return lines.join('\n');
|
return lines.join('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function ensureReleaseDir() {
|
||||||
|
fs.mkdirSync(RELEASE_OUT, { recursive: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
function sha256(content) {
|
||||||
|
return crypto.createHash('sha256').update(content).digest('hex');
|
||||||
|
}
|
||||||
|
|
||||||
|
function signDigest(digest) {
|
||||||
|
const key = process.env.API_CHANGELOG_SIGNING_KEY;
|
||||||
|
if (!key) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const hmac = crypto.createHmac('sha256', Buffer.from(key, 'utf8'));
|
||||||
|
hmac.update(digest);
|
||||||
|
return hmac.digest('hex');
|
||||||
|
}
|
||||||
|
|
||||||
function main() {
|
function main() {
|
||||||
if (!fs.existsSync(BASELINE)) {
|
if (!fs.existsSync(BASELINE)) {
|
||||||
console.log('[api:changelog] baseline missing; skipping');
|
console.log('[api:changelog] baseline missing; skipping');
|
||||||
@@ -85,6 +106,24 @@ function main() {
|
|||||||
const markdown = renderMarkdown(diff);
|
const markdown = renderMarkdown(diff);
|
||||||
fs.writeFileSync(OUTPUT, markdown, 'utf8');
|
fs.writeFileSync(OUTPUT, markdown, 'utf8');
|
||||||
console.log(`[api:changelog] wrote changelog to ${OUTPUT}`);
|
console.log(`[api:changelog] wrote changelog to ${OUTPUT}`);
|
||||||
|
|
||||||
|
ensureReleaseDir();
|
||||||
|
const releaseChangelog = path.join(RELEASE_OUT, 'CHANGELOG.md');
|
||||||
|
fs.writeFileSync(releaseChangelog, markdown, 'utf8');
|
||||||
|
|
||||||
|
const digest = sha256(markdown);
|
||||||
|
const digestFile = path.join(RELEASE_OUT, 'CHANGELOG.sha256');
|
||||||
|
fs.writeFileSync(digestFile, `${digest} CHANGELOG.md\n`, 'utf8');
|
||||||
|
|
||||||
|
const signature = signDigest(digest);
|
||||||
|
if (signature) {
|
||||||
|
fs.writeFileSync(path.join(RELEASE_OUT, 'CHANGELOG.sig'), signature, 'utf8');
|
||||||
|
console.log('[api:changelog] wrote signature for release artifact');
|
||||||
|
} else {
|
||||||
|
console.log('[api:changelog] signature skipped (API_CHANGELOG_SIGNING_KEY not set)');
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`[api:changelog] copied changelog + digest to ${RELEASE_OUT}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
main();
|
main();
|
||||||
|
|||||||
63
scripts/attest/build-attestation-bundle.sh
Normal file
63
scripts/attest/build-attestation-bundle.sh
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# DEVOPS-ATTEST-74-002: package attestation outputs into an offline bundle with checksums.
|
||||||
|
|
||||||
|
if [[ $# -lt 1 ]]; then
|
||||||
|
echo "Usage: $0 <attest-dir> [bundle-out]" >&2
|
||||||
|
exit 64
|
||||||
|
fi
|
||||||
|
|
||||||
|
ATTEST_DIR=$1
|
||||||
|
BUNDLE_OUT=${2:-"out/attest-bundles"}
|
||||||
|
|
||||||
|
if [[ ! -d "$ATTEST_DIR" ]]; then
|
||||||
|
echo "[attest-bundle] attestation directory not found: $ATTEST_DIR" >&2
|
||||||
|
exit 66
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "$BUNDLE_OUT"
|
||||||
|
|
||||||
|
TS=$(date -u +"%Y%m%dT%H%M%SZ")
|
||||||
|
BUNDLE_NAME="attestation-bundle-${TS}"
|
||||||
|
WORK_DIR="${BUNDLE_OUT}/${BUNDLE_NAME}"
|
||||||
|
mkdir -p "$WORK_DIR"
|
||||||
|
|
||||||
|
copy_if_exists() {
|
||||||
|
local pattern="$1"
|
||||||
|
shopt -s nullglob
|
||||||
|
local files=("$ATTEST_DIR"/$pattern)
|
||||||
|
if (( ${#files[@]} > 0 )); then
|
||||||
|
cp "${files[@]}" "$WORK_DIR/"
|
||||||
|
fi
|
||||||
|
shopt -u nullglob
|
||||||
|
}
|
||||||
|
|
||||||
|
# Collect common attestation artefacts
|
||||||
|
copy_if_exists "*.dsse.json"
|
||||||
|
copy_if_exists "*.in-toto.jsonl"
|
||||||
|
copy_if_exists "*.sarif"
|
||||||
|
copy_if_exists "*.intoto.json"
|
||||||
|
copy_if_exists "*.rekor.txt"
|
||||||
|
copy_if_exists "*.sig"
|
||||||
|
copy_if_exists "*.crt"
|
||||||
|
copy_if_exists "*.pem"
|
||||||
|
copy_if_exists "*.json"
|
||||||
|
|
||||||
|
# Manifest
|
||||||
|
cat > "${WORK_DIR}/manifest.json" <<EOF
|
||||||
|
{
|
||||||
|
"created_at": "$(date -u +"%Y-%m-%dT%H:%M:%SZ")",
|
||||||
|
"source_dir": "${ATTEST_DIR}",
|
||||||
|
"files": $(ls -1 "${WORK_DIR}" | jq -R . | jq -s .)
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Checksums
|
||||||
|
(
|
||||||
|
cd "$WORK_DIR"
|
||||||
|
sha256sum * > SHA256SUMS
|
||||||
|
)
|
||||||
|
|
||||||
|
tar -C "$BUNDLE_OUT" -czf "${WORK_DIR}.tgz" "${BUNDLE_NAME}"
|
||||||
|
echo "[attest-bundle] bundle created at ${WORK_DIR}.tgz"
|
||||||
43
scripts/buildx/build-airgap-bundle.sh
Normal file
43
scripts/buildx/build-airgap-bundle.sh
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# DEVOPS-CONTAINERS-46-001: build air-gap bundle from existing buildx OCI archive
|
||||||
|
|
||||||
|
if [[ $# -lt 1 ]]; then
|
||||||
|
echo "Usage: $0 <image-tag> [bundle-dir]" >&2
|
||||||
|
exit 64
|
||||||
|
fi
|
||||||
|
|
||||||
|
IMAGE_TAG=$1
|
||||||
|
BUNDLE_DIR=${2:-"out/bundles/$(echo "$IMAGE_TAG" | tr '/:' '__')"}
|
||||||
|
SRC_DIR="out/buildx/$(echo "$IMAGE_TAG" | tr '/:' '__')"
|
||||||
|
OCI_ARCHIVE="${SRC_DIR}/image.oci"
|
||||||
|
|
||||||
|
if [[ ! -f "$OCI_ARCHIVE" ]]; then
|
||||||
|
echo "[airgap] OCI archive not found at $OCI_ARCHIVE. Run build-multiarch first." >&2
|
||||||
|
exit 66
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "$BUNDLE_DIR"
|
||||||
|
|
||||||
|
SBOM_FILE=""
|
||||||
|
if [[ -f "${SRC_DIR}/sbom.syft.json" ]]; then
|
||||||
|
SBOM_FILE="${SRC_DIR}/sbom.syft.json"
|
||||||
|
fi
|
||||||
|
|
||||||
|
cat > "${BUNDLE_DIR}/bundle-manifest.json" <<EOF
|
||||||
|
{
|
||||||
|
"image": "${IMAGE_TAG}",
|
||||||
|
"oci_archive": "image.oci",
|
||||||
|
"sbom": "$( [[ -n "$SBOM_FILE" ]] && echo sbom.syft.json || echo null )",
|
||||||
|
"created_at": "$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cp "$OCI_ARCHIVE" "${BUNDLE_DIR}/image.oci"
|
||||||
|
[[ -n "$SBOM_FILE" ]] && cp "$SBOM_FILE" "${BUNDLE_DIR}/sbom.syft.json"
|
||||||
|
[[ -f "${SRC_DIR}/image.sha256" ]] && cp "${SRC_DIR}/image.sha256" "${BUNDLE_DIR}/image.sha256"
|
||||||
|
[[ -f "${SRC_DIR}/image.sig" ]] && cp "${SRC_DIR}/image.sig" "${BUNDLE_DIR}/image.sig"
|
||||||
|
|
||||||
|
tar -C "$BUNDLE_DIR" -czf "${BUNDLE_DIR}.tgz" .
|
||||||
|
echo "[airgap] bundle created at ${BUNDLE_DIR}.tgz"
|
||||||
93
scripts/buildx/build-multiarch.sh
Normal file
93
scripts/buildx/build-multiarch.sh
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Multi-arch buildx helper for DEVOPS-CONTAINERS-44-001
|
||||||
|
# Requirements: docker CLI with buildx, optional syft (for SBOM) and cosign (for signing).
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
echo "Usage: $0 <image-tag> <context-dir> [--platform linux/amd64,linux/arm64] [--push] [--sbom syft|none] [--sign <cosign-key>]" >&2
|
||||||
|
exit 64
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ $# -lt 2 ]]; then
|
||||||
|
usage
|
||||||
|
fi
|
||||||
|
|
||||||
|
IMAGE_TAG=$1; shift
|
||||||
|
CONTEXT_DIR=$1; shift
|
||||||
|
|
||||||
|
PLATFORMS="linux/amd64,linux/arm64"
|
||||||
|
PUSH=false
|
||||||
|
SBOM_TOOL="syft"
|
||||||
|
COSIGN_KEY=""
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--platform) PLATFORMS="$2"; shift 2;;
|
||||||
|
--push) PUSH=true; shift;;
|
||||||
|
--sbom) SBOM_TOOL="$2"; shift 2;;
|
||||||
|
--sign) COSIGN_KEY="$2"; shift 2;;
|
||||||
|
*) echo "Unknown option: $1" >&2; usage;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if ! command -v docker >/dev/null 2>&1; then
|
||||||
|
echo "[buildx] docker CLI not found" >&2
|
||||||
|
exit 69
|
||||||
|
fi
|
||||||
|
|
||||||
|
OUT_ROOT="out/buildx/$(echo "$IMAGE_TAG" | tr '/:' '__')"
|
||||||
|
mkdir -p "$OUT_ROOT"
|
||||||
|
|
||||||
|
BUILDER_NAME="stellaops-multiarch"
|
||||||
|
if ! docker buildx inspect "$BUILDER_NAME" >/dev/null 2>&1; then
|
||||||
|
docker buildx create --name "$BUILDER_NAME" --driver docker-container --use >/dev/null
|
||||||
|
else
|
||||||
|
docker buildx use "$BUILDER_NAME" >/dev/null
|
||||||
|
fi
|
||||||
|
|
||||||
|
BUILD_OPTS=(
|
||||||
|
--platform "$PLATFORMS"
|
||||||
|
-t "$IMAGE_TAG"
|
||||||
|
--provenance=false
|
||||||
|
--sbom=false
|
||||||
|
--output "type=oci,dest=${OUT_ROOT}/image.oci"
|
||||||
|
)
|
||||||
|
|
||||||
|
if $PUSH; then
|
||||||
|
BUILD_OPTS+=("--push")
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[buildx] building $IMAGE_TAG for $PLATFORMS"
|
||||||
|
docker buildx build "${BUILD_OPTS[@]}" "$CONTEXT_DIR"
|
||||||
|
|
||||||
|
echo "[buildx] computing digest"
|
||||||
|
IMAGE_DIGEST=$(sha256sum "${OUT_ROOT}/image.oci" | awk '{print $1}')
|
||||||
|
echo "$IMAGE_DIGEST image.oci" > "${OUT_ROOT}/image.sha256"
|
||||||
|
|
||||||
|
if [[ "$SBOM_TOOL" == "syft" ]] && command -v syft >/dev/null 2>&1; then
|
||||||
|
echo "[buildx] generating SBOM via syft"
|
||||||
|
syft "oci-archive:${OUT_ROOT}/image.oci" -o json > "${OUT_ROOT}/sbom.syft.json"
|
||||||
|
else
|
||||||
|
echo "[buildx] skipping SBOM (tool=$SBOM_TOOL, syft available? $(command -v syft >/dev/null && echo yes || echo no))"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -n "$COSIGN_KEY" ]] && command -v cosign >/dev/null 2>&1; then
|
||||||
|
echo "[buildx] signing digest with cosign key"
|
||||||
|
COSIGN_EXPERIMENTAL=1 cosign sign-blob --key "$COSIGN_KEY" --output-signature "${OUT_ROOT}/image.sig" --output-certificate "${OUT_ROOT}/image.cert" "${OUT_ROOT}/image.oci"
|
||||||
|
else
|
||||||
|
echo "[buildx] signature skipped (no key provided or cosign missing)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
cat > "${OUT_ROOT}/build-metadata.json" <<EOF
|
||||||
|
{
|
||||||
|
"image": "${IMAGE_TAG}",
|
||||||
|
"platforms": "${PLATFORMS}",
|
||||||
|
"pushed": ${PUSH},
|
||||||
|
"digest_sha256": "${IMAGE_DIGEST}",
|
||||||
|
"generated_at": "$(date -u +"%Y-%m-%dT%H:%M:%SZ")",
|
||||||
|
"sbom": "$( [[ -f ${OUT_ROOT}/sbom.syft.json ]] && echo sbom.syft.json || echo null )"
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo "[buildx] artifacts written to ${OUT_ROOT}"
|
||||||
82
scripts/cli/build-cli.sh
Normal file
82
scripts/cli/build-cli.sh
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# DEVOPS-CLI-41-001: Build multi-platform CLI binaries with SBOM and checksums.
|
||||||
|
|
||||||
|
RIDS="${RIDS:-linux-x64,win-x64,osx-arm64}"
|
||||||
|
CONFIG="${CONFIG:-Release}"
|
||||||
|
PROJECT="src/Cli/StellaOps.Cli/StellaOps.Cli.csproj"
|
||||||
|
OUT_ROOT="out/cli"
|
||||||
|
SBOM_TOOL="${SBOM_TOOL:-syft}" # syft|none
|
||||||
|
SIGN="${SIGN:-false}"
|
||||||
|
COSIGN_KEY="${COSIGN_KEY:-}"
|
||||||
|
|
||||||
|
IFS=',' read -ra TARGETS <<< "$RIDS"
|
||||||
|
|
||||||
|
mkdir -p "$OUT_ROOT"
|
||||||
|
|
||||||
|
if ! command -v dotnet >/dev/null 2>&1; then
|
||||||
|
echo "[cli-build] dotnet CLI not found" >&2
|
||||||
|
exit 69
|
||||||
|
fi
|
||||||
|
|
||||||
|
generate_sbom() {
|
||||||
|
local dir="$1"
|
||||||
|
local sbom="$2"
|
||||||
|
if [[ "$SBOM_TOOL" == "syft" ]] && command -v syft >/dev/null 2>&1; then
|
||||||
|
syft "dir:${dir}" -o json > "$sbom"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
sign_file() {
|
||||||
|
local file="$1"
|
||||||
|
if [[ "$SIGN" == "true" && -n "$COSIGN_KEY" && -x "$(command -v cosign || true)" ]]; then
|
||||||
|
COSIGN_EXPERIMENTAL=1 cosign sign-blob --key "$COSIGN_KEY" --output-signature "${file}.sig" "$file"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
for rid in "${TARGETS[@]}"; do
|
||||||
|
echo "[cli-build] publishing for $rid"
|
||||||
|
out_dir="${OUT_ROOT}/${rid}"
|
||||||
|
publish_dir="${out_dir}/publish"
|
||||||
|
mkdir -p "$publish_dir"
|
||||||
|
|
||||||
|
dotnet publish "$PROJECT" -c "$CONFIG" -r "$rid" \
|
||||||
|
-o "$publish_dir" \
|
||||||
|
--self-contained true \
|
||||||
|
-p:PublishSingleFile=true \
|
||||||
|
-p:PublishTrimmed=false \
|
||||||
|
-p:DebugType=None \
|
||||||
|
>/dev/null
|
||||||
|
|
||||||
|
# Package
|
||||||
|
archive_ext="tar.gz"
|
||||||
|
archive_cmd=(tar -C "$publish_dir" -czf)
|
||||||
|
if [[ "$rid" == win-* ]]; then
|
||||||
|
archive_ext="zip"
|
||||||
|
archive_cmd=(zip -jr)
|
||||||
|
fi
|
||||||
|
|
||||||
|
archive_name="stella-cli-${rid}.${archive_ext}"
|
||||||
|
archive_path="${out_dir}/${archive_name}"
|
||||||
|
"${archive_cmd[@]}" "$archive_path" "$publish_dir"
|
||||||
|
|
||||||
|
sha256sum "$archive_path" > "${archive_path}.sha256"
|
||||||
|
sign_file "$archive_path"
|
||||||
|
|
||||||
|
# SBOM
|
||||||
|
generate_sbom "$publish_dir" "${archive_path}.sbom.json"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Build manifest
|
||||||
|
manifest="${OUT_ROOT}/manifest.json"
|
||||||
|
cat > "$manifest" <<EOF
|
||||||
|
{
|
||||||
|
"generated_at": "$(date -u +"%Y-%m-%dT%H:%M:%SZ")",
|
||||||
|
"config": "$CONFIG",
|
||||||
|
"rids": [$(printf '"%s",' "${TARGETS[@]}" | sed 's/,$//')],
|
||||||
|
"artifacts_root": "$OUT_ROOT"
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo "[cli-build] artifacts in $OUT_ROOT"
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
# API Changelog
|
# API Changelog
|
||||||
|
|
||||||
Generated: 2025-11-19T07:40:32.086Z
|
Generated: 2025-11-24T01:50:48.086Z
|
||||||
|
|
||||||
## Additive Operations
|
## Additive Operations
|
||||||
- GET /export-center/bundles/{bundleId}/manifest
|
- GET /export-center/bundles/{bundleId}/manifest
|
||||||
|
|||||||
@@ -1236,8 +1236,78 @@ internal static class CommandFactory
|
|||||||
cancellationToken);
|
cancellationToken);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var explainOptions = CreateAdvisoryOptions();
|
||||||
|
var explain = new Command("explain", "Explain an advisory conflict set with narrative and rationale.");
|
||||||
|
AddAdvisoryOptions(explain, explainOptions);
|
||||||
|
explain.SetAction((parseResult, _) =>
|
||||||
|
{
|
||||||
|
var advisoryKey = parseResult.GetValue(explainOptions.AdvisoryKey) ?? string.Empty;
|
||||||
|
var artifactId = parseResult.GetValue(explainOptions.ArtifactId);
|
||||||
|
var artifactPurl = parseResult.GetValue(explainOptions.ArtifactPurl);
|
||||||
|
var policyVersion = parseResult.GetValue(explainOptions.PolicyVersion);
|
||||||
|
var profile = parseResult.GetValue(explainOptions.Profile) ?? "default";
|
||||||
|
var sections = parseResult.GetValue(explainOptions.Sections) ?? Array.Empty<string>();
|
||||||
|
var forceRefresh = parseResult.GetValue(explainOptions.ForceRefresh);
|
||||||
|
var timeoutSeconds = parseResult.GetValue(explainOptions.TimeoutSeconds) ?? 120;
|
||||||
|
var outputFormat = ParseAdvisoryOutputFormat(parseResult.GetValue(explainOptions.Format));
|
||||||
|
var outputPath = parseResult.GetValue(explainOptions.Output);
|
||||||
|
var verbose = parseResult.GetValue(verboseOption);
|
||||||
|
|
||||||
|
return CommandHandlers.HandleAdviseRunAsync(
|
||||||
|
services,
|
||||||
|
AdvisoryAiTaskType.Conflict,
|
||||||
|
advisoryKey,
|
||||||
|
artifactId,
|
||||||
|
artifactPurl,
|
||||||
|
policyVersion,
|
||||||
|
profile,
|
||||||
|
sections,
|
||||||
|
forceRefresh,
|
||||||
|
timeoutSeconds,
|
||||||
|
outputFormat,
|
||||||
|
outputPath,
|
||||||
|
verbose,
|
||||||
|
cancellationToken);
|
||||||
|
});
|
||||||
|
|
||||||
|
var remediateOptions = CreateAdvisoryOptions();
|
||||||
|
var remediate = new Command("remediate", "Generate remediation guidance for an advisory.");
|
||||||
|
AddAdvisoryOptions(remediate, remediateOptions);
|
||||||
|
remediate.SetAction((parseResult, _) =>
|
||||||
|
{
|
||||||
|
var advisoryKey = parseResult.GetValue(remediateOptions.AdvisoryKey) ?? string.Empty;
|
||||||
|
var artifactId = parseResult.GetValue(remediateOptions.ArtifactId);
|
||||||
|
var artifactPurl = parseResult.GetValue(remediateOptions.ArtifactPurl);
|
||||||
|
var policyVersion = parseResult.GetValue(remediateOptions.PolicyVersion);
|
||||||
|
var profile = parseResult.GetValue(remediateOptions.Profile) ?? "default";
|
||||||
|
var sections = parseResult.GetValue(remediateOptions.Sections) ?? Array.Empty<string>();
|
||||||
|
var forceRefresh = parseResult.GetValue(remediateOptions.ForceRefresh);
|
||||||
|
var timeoutSeconds = parseResult.GetValue(remediateOptions.TimeoutSeconds) ?? 120;
|
||||||
|
var outputFormat = ParseAdvisoryOutputFormat(parseResult.GetValue(remediateOptions.Format));
|
||||||
|
var outputPath = parseResult.GetValue(remediateOptions.Output);
|
||||||
|
var verbose = parseResult.GetValue(verboseOption);
|
||||||
|
|
||||||
|
return CommandHandlers.HandleAdviseRunAsync(
|
||||||
|
services,
|
||||||
|
AdvisoryAiTaskType.Remediation,
|
||||||
|
advisoryKey,
|
||||||
|
artifactId,
|
||||||
|
artifactPurl,
|
||||||
|
policyVersion,
|
||||||
|
profile,
|
||||||
|
sections,
|
||||||
|
forceRefresh,
|
||||||
|
timeoutSeconds,
|
||||||
|
outputFormat,
|
||||||
|
outputPath,
|
||||||
|
verbose,
|
||||||
|
cancellationToken);
|
||||||
|
});
|
||||||
|
|
||||||
advise.Add(run);
|
advise.Add(run);
|
||||||
advise.Add(summarize);
|
advise.Add(summarize);
|
||||||
|
advise.Add(explain);
|
||||||
|
advise.Add(remediate);
|
||||||
return advise;
|
return advise;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -553,6 +553,12 @@ internal static class CommandHandlers
|
|||||||
logger.LogInformation("Advisory output written to {Path}.", fullPath);
|
logger.LogInformation("Advisory output written to {Path}.", fullPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (rendered is not null)
|
||||||
|
{
|
||||||
|
// Surface the rendered advisory to the active console so users (and tests) can see it even when also writing to disk.
|
||||||
|
AnsiConsole.Console.WriteLine(rendered);
|
||||||
|
}
|
||||||
|
|
||||||
if (output.Guardrail.Blocked)
|
if (output.Guardrail.Blocked)
|
||||||
{
|
{
|
||||||
logger.LogError("Guardrail blocked advisory output (cache key {CacheKey}).", output.CacheKey);
|
logger.LogError("Guardrail blocked advisory output (cache key {CacheKey}).", output.CacheKey);
|
||||||
@@ -3075,7 +3081,7 @@ internal static class CommandHandlers
|
|||||||
};
|
};
|
||||||
|
|
||||||
var json = JsonSerializer.Serialize(payload, new JsonSerializerOptions(JsonSerializerDefaults.Web) { WriteIndented = true });
|
var json = JsonSerializer.Serialize(payload, new JsonSerializerOptions(JsonSerializerDefaults.Web) { WriteIndented = true });
|
||||||
Console.WriteLine(json);
|
AnsiConsole.Console.WriteLine(json);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -6359,9 +6365,9 @@ internal static class CommandHandlers
|
|||||||
builder.AppendLine($"# Advisory {output.TaskType} ({output.Profile})");
|
builder.AppendLine($"# Advisory {output.TaskType} ({output.Profile})");
|
||||||
builder.AppendLine();
|
builder.AppendLine();
|
||||||
builder.AppendLine($"- Cache Key: `{output.CacheKey}`");
|
builder.AppendLine($"- Cache Key: `{output.CacheKey}`");
|
||||||
builder.AppendLine($"- Generated: {output.GeneratedAtUtc.ToString(\"O\", CultureInfo.InvariantCulture)}");
|
builder.AppendLine($"- Generated: {output.GeneratedAtUtc.ToString("O", CultureInfo.InvariantCulture)}");
|
||||||
builder.AppendLine($"- Plan From Cache: {(output.PlanFromCache ? \"yes\" : \"no\")}");
|
builder.AppendLine($"- Plan From Cache: {(output.PlanFromCache ? "yes" : "no")}");
|
||||||
builder.AppendLine($"- Guardrail Blocked: {(output.Guardrail.Blocked ? \"yes\" : \"no\")}");
|
builder.AppendLine($"- Guardrail Blocked: {(output.Guardrail.Blocked ? "yes" : "no")}");
|
||||||
builder.AppendLine();
|
builder.AppendLine();
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(output.Response))
|
if (!string.IsNullOrWhiteSpace(output.Response))
|
||||||
|
|||||||
@@ -3,4 +3,6 @@
|
|||||||
| Task ID | State | Notes |
|
| Task ID | State | Notes |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `SCANNER-CLI-0001` | DONE (2025-11-12) | Ruby verbs now consume the persisted `RubyPackageInventory`, warn when inventories are missing, and docs/tests were refreshed per Sprint 138. |
|
| `SCANNER-CLI-0001` | DONE (2025-11-12) | Ruby verbs now consume the persisted `RubyPackageInventory`, warn when inventories are missing, and docs/tests were refreshed per Sprint 138. |
|
||||||
| `CLI-AIAI-31-001` | BLOCKED (2025-11-22) | `stella advise summarize` command implemented; blocked on upstream Scanner analyzers (Node/Java) compile failures preventing CLI test run. |
|
| `CLI-AIAI-31-001` | DONE (2025-11-24) | `stella advise summarize` command implemented; CLI analyzer build & tests now pass locally. |
|
||||||
|
| `CLI-AIAI-31-002` | DONE (2025-11-24) | `stella advise explain` (conflict narrative) command implemented and tested. |
|
||||||
|
| `CLI-AIAI-31-003` | DONE (2025-11-24) | `stella advise remediate` command implemented and tested. |
|
||||||
|
|||||||
@@ -877,6 +877,202 @@ public sealed class CommandHandlersTests
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task HandleAdviseRunAsync_WritesMarkdownWithCitations_ForExplain()
|
||||||
|
{
|
||||||
|
var originalExit = Environment.ExitCode;
|
||||||
|
var originalConsole = AnsiConsole.Console;
|
||||||
|
var testConsole = new TestConsole();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Environment.ExitCode = 0;
|
||||||
|
AnsiConsole.Console = testConsole;
|
||||||
|
|
||||||
|
var planResponse = new AdvisoryPipelinePlanResponseModel
|
||||||
|
{
|
||||||
|
TaskType = "Conflict",
|
||||||
|
CacheKey = "plan-conflict",
|
||||||
|
PromptTemplate = "prompts/advisory/conflict.liquid",
|
||||||
|
Budget = new AdvisoryTaskBudgetModel
|
||||||
|
{
|
||||||
|
PromptTokens = 128,
|
||||||
|
CompletionTokens = 64
|
||||||
|
},
|
||||||
|
Chunks = Array.Empty<PipelineChunkSummaryModel>(),
|
||||||
|
Vectors = Array.Empty<PipelineVectorSummaryModel>(),
|
||||||
|
Metadata = new Dictionary<string, string>()
|
||||||
|
};
|
||||||
|
|
||||||
|
var outputResponse = new AdvisoryPipelineOutputModel
|
||||||
|
{
|
||||||
|
CacheKey = planResponse.CacheKey,
|
||||||
|
TaskType = planResponse.TaskType,
|
||||||
|
Profile = "default",
|
||||||
|
Prompt = "Sanitized prompt",
|
||||||
|
Response = "Rendered conflict body.",
|
||||||
|
Citations = new[]
|
||||||
|
{
|
||||||
|
new AdvisoryOutputCitationModel { Index = 1, DocumentId = "doc-42", ChunkId = "chunk-42" }
|
||||||
|
},
|
||||||
|
Metadata = new Dictionary<string, string>(),
|
||||||
|
Guardrail = new AdvisoryOutputGuardrailModel
|
||||||
|
{
|
||||||
|
Blocked = false,
|
||||||
|
SanitizedPrompt = "Sanitized prompt",
|
||||||
|
Violations = Array.Empty<AdvisoryOutputGuardrailViolationModel>(),
|
||||||
|
Metadata = new Dictionary<string, string>()
|
||||||
|
},
|
||||||
|
Provenance = new AdvisoryOutputProvenanceModel
|
||||||
|
{
|
||||||
|
InputDigest = "sha256:conflict-in",
|
||||||
|
OutputHash = "sha256:conflict-out",
|
||||||
|
Signatures = Array.Empty<string>()
|
||||||
|
},
|
||||||
|
GeneratedAtUtc = DateTimeOffset.Parse("2025-11-06T12:00:00Z", CultureInfo.InvariantCulture),
|
||||||
|
PlanFromCache = false
|
||||||
|
};
|
||||||
|
|
||||||
|
var backend = new StubBackendClient(new JobTriggerResult(true, "ok", null, null))
|
||||||
|
{
|
||||||
|
AdvisoryPlanResponse = planResponse,
|
||||||
|
AdvisoryOutputResponse = outputResponse
|
||||||
|
};
|
||||||
|
|
||||||
|
var provider = BuildServiceProvider(backend);
|
||||||
|
var outputPath = Path.GetTempFileName();
|
||||||
|
|
||||||
|
await CommandHandlers.HandleAdviseRunAsync(
|
||||||
|
provider,
|
||||||
|
AdvisoryAiTaskType.Conflict,
|
||||||
|
"ADV-42",
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
"default",
|
||||||
|
Array.Empty<string>(),
|
||||||
|
forceRefresh: false,
|
||||||
|
timeoutSeconds: 0,
|
||||||
|
outputFormat: AdvisoryOutputFormat.Markdown,
|
||||||
|
outputPath: outputPath,
|
||||||
|
verbose: false,
|
||||||
|
cancellationToken: CancellationToken.None);
|
||||||
|
|
||||||
|
var markdown = await File.ReadAllTextAsync(outputPath);
|
||||||
|
Assert.Contains("Conflict", markdown, StringComparison.OrdinalIgnoreCase);
|
||||||
|
Assert.Contains("Rendered conflict body", markdown, StringComparison.OrdinalIgnoreCase);
|
||||||
|
Assert.Contains("doc-42", markdown, StringComparison.OrdinalIgnoreCase);
|
||||||
|
Assert.Contains("chunk-42", markdown, StringComparison.OrdinalIgnoreCase);
|
||||||
|
Assert.Contains("Citations", markdown, StringComparison.OrdinalIgnoreCase);
|
||||||
|
Assert.Equal(0, Environment.ExitCode);
|
||||||
|
Assert.Contains("Conflict", testConsole.Output, StringComparison.OrdinalIgnoreCase);
|
||||||
|
Assert.Equal(AdvisoryAiTaskType.Conflict, backend.AdvisoryPlanRequests.Last().TaskType);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
AnsiConsole.Console = originalConsole;
|
||||||
|
Environment.ExitCode = originalExit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task HandleAdviseRunAsync_WritesMarkdownWithCitations_ForRemediation()
|
||||||
|
{
|
||||||
|
var originalExit = Environment.ExitCode;
|
||||||
|
var originalConsole = AnsiConsole.Console;
|
||||||
|
var testConsole = new TestConsole();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Environment.ExitCode = 0;
|
||||||
|
AnsiConsole.Console = testConsole;
|
||||||
|
|
||||||
|
var planResponse = new AdvisoryPipelinePlanResponseModel
|
||||||
|
{
|
||||||
|
TaskType = "Remediation",
|
||||||
|
CacheKey = "plan-remediation",
|
||||||
|
PromptTemplate = "prompts/advisory/remediation.liquid",
|
||||||
|
Budget = new AdvisoryTaskBudgetModel
|
||||||
|
{
|
||||||
|
PromptTokens = 192,
|
||||||
|
CompletionTokens = 96
|
||||||
|
},
|
||||||
|
Chunks = Array.Empty<PipelineChunkSummaryModel>(),
|
||||||
|
Vectors = Array.Empty<PipelineVectorSummaryModel>(),
|
||||||
|
Metadata = new Dictionary<string, string>()
|
||||||
|
};
|
||||||
|
|
||||||
|
var outputResponse = new AdvisoryPipelineOutputModel
|
||||||
|
{
|
||||||
|
CacheKey = planResponse.CacheKey,
|
||||||
|
TaskType = planResponse.TaskType,
|
||||||
|
Profile = "default",
|
||||||
|
Prompt = "Sanitized prompt",
|
||||||
|
Response = "Rendered remediation body.",
|
||||||
|
Citations = new[]
|
||||||
|
{
|
||||||
|
new AdvisoryOutputCitationModel { Index = 1, DocumentId = "doc-77", ChunkId = "chunk-77" }
|
||||||
|
},
|
||||||
|
Metadata = new Dictionary<string, string>(),
|
||||||
|
Guardrail = new AdvisoryOutputGuardrailModel
|
||||||
|
{
|
||||||
|
Blocked = false,
|
||||||
|
SanitizedPrompt = "Sanitized prompt",
|
||||||
|
Violations = Array.Empty<AdvisoryOutputGuardrailViolationModel>(),
|
||||||
|
Metadata = new Dictionary<string, string>()
|
||||||
|
},
|
||||||
|
Provenance = new AdvisoryOutputProvenanceModel
|
||||||
|
{
|
||||||
|
InputDigest = "sha256:remediation-in",
|
||||||
|
OutputHash = "sha256:remediation-out",
|
||||||
|
Signatures = Array.Empty<string>()
|
||||||
|
},
|
||||||
|
GeneratedAtUtc = DateTimeOffset.Parse("2025-11-06T12:00:00Z", CultureInfo.InvariantCulture),
|
||||||
|
PlanFromCache = false
|
||||||
|
};
|
||||||
|
|
||||||
|
var backend = new StubBackendClient(new JobTriggerResult(true, "ok", null, null))
|
||||||
|
{
|
||||||
|
AdvisoryPlanResponse = planResponse,
|
||||||
|
AdvisoryOutputResponse = outputResponse
|
||||||
|
};
|
||||||
|
|
||||||
|
var provider = BuildServiceProvider(backend);
|
||||||
|
var outputPath = Path.GetTempFileName();
|
||||||
|
|
||||||
|
await CommandHandlers.HandleAdviseRunAsync(
|
||||||
|
provider,
|
||||||
|
AdvisoryAiTaskType.Remediation,
|
||||||
|
"ADV-77",
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
"default",
|
||||||
|
Array.Empty<string>(),
|
||||||
|
forceRefresh: false,
|
||||||
|
timeoutSeconds: 0,
|
||||||
|
outputFormat: AdvisoryOutputFormat.Markdown,
|
||||||
|
outputPath: outputPath,
|
||||||
|
verbose: false,
|
||||||
|
cancellationToken: CancellationToken.None);
|
||||||
|
|
||||||
|
var markdown = await File.ReadAllTextAsync(outputPath);
|
||||||
|
Assert.Contains("Remediation", markdown, StringComparison.OrdinalIgnoreCase);
|
||||||
|
Assert.Contains("Rendered remediation body", markdown, StringComparison.OrdinalIgnoreCase);
|
||||||
|
Assert.Contains("doc-77", markdown, StringComparison.OrdinalIgnoreCase);
|
||||||
|
Assert.Contains("chunk-77", markdown, StringComparison.OrdinalIgnoreCase);
|
||||||
|
Assert.Contains("Citations", markdown, StringComparison.OrdinalIgnoreCase);
|
||||||
|
Assert.Equal(0, Environment.ExitCode);
|
||||||
|
Assert.Contains("Remediation", testConsole.Output, StringComparison.OrdinalIgnoreCase);
|
||||||
|
Assert.Equal(AdvisoryAiTaskType.Remediation, backend.AdvisoryPlanRequests.Last().TaskType);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
AnsiConsole.Console = originalConsole;
|
||||||
|
Environment.ExitCode = originalExit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task HandleAdviseRunAsync_ReturnsGuardrailExitCodeOnBlock()
|
public async Task HandleAdviseRunAsync_ReturnsGuardrailExitCodeOnBlock()
|
||||||
{
|
{
|
||||||
@@ -3776,6 +3972,7 @@ spec:
|
|||||||
Array.Empty<TaskRunnerSimulationOutput>(),
|
Array.Empty<TaskRunnerSimulationOutput>(),
|
||||||
false);
|
false);
|
||||||
public Exception? TaskRunnerSimulationException { get; set; }
|
public Exception? TaskRunnerSimulationException { get; set; }
|
||||||
|
public OfflineKitStatus? OfflineStatus { get; set; }
|
||||||
public PolicyActivationResult ActivationResult { get; set; } = new PolicyActivationResult(
|
public PolicyActivationResult ActivationResult { get; set; } = new PolicyActivationResult(
|
||||||
"activated",
|
"activated",
|
||||||
new PolicyActivationRevision(
|
new PolicyActivationRevision(
|
||||||
@@ -3966,7 +4163,19 @@ spec:
|
|||||||
=> throw new NotSupportedException();
|
=> throw new NotSupportedException();
|
||||||
|
|
||||||
public Task<OfflineKitStatus> GetOfflineKitStatusAsync(CancellationToken cancellationToken)
|
public Task<OfflineKitStatus> GetOfflineKitStatusAsync(CancellationToken cancellationToken)
|
||||||
=> throw new NotSupportedException();
|
{
|
||||||
|
return Task.FromResult(OfflineStatus ?? new OfflineKitStatus(
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
false,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
Array.Empty<OfflineKitComponentStatus>()));
|
||||||
|
}
|
||||||
|
|
||||||
public Task<EntryTraceResponseModel?> GetEntryTraceAsync(string scanId, CancellationToken cancellationToken)
|
public Task<EntryTraceResponseModel?> GetEntryTraceAsync(string scanId, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ public sealed record LnmLinksetPage(
|
|||||||
public sealed record LnmLinksetNormalized(
|
public sealed record LnmLinksetNormalized(
|
||||||
[property: JsonPropertyName("aliases")] IReadOnlyList<string>? Aliases,
|
[property: JsonPropertyName("aliases")] IReadOnlyList<string>? Aliases,
|
||||||
[property: JsonPropertyName("purl")] IReadOnlyList<string>? Purl,
|
[property: JsonPropertyName("purl")] IReadOnlyList<string>? Purl,
|
||||||
|
[property: JsonPropertyName("cpe")] IReadOnlyList<string>? Cpe,
|
||||||
[property: JsonPropertyName("versions")] IReadOnlyList<string>? Versions,
|
[property: JsonPropertyName("versions")] IReadOnlyList<string>? Versions,
|
||||||
[property: JsonPropertyName("ranges")] IReadOnlyList<object>? Ranges,
|
[property: JsonPropertyName("ranges")] IReadOnlyList<object>? Ranges,
|
||||||
[property: JsonPropertyName("severities")] IReadOnlyList<object>? Severities);
|
[property: JsonPropertyName("severities")] IReadOnlyList<object>? Severities);
|
||||||
|
|||||||
@@ -1752,6 +1752,9 @@ LnmLinksetResponse ToLnmResponse(
|
|||||||
bool includeObservations)
|
bool includeObservations)
|
||||||
{
|
{
|
||||||
var normalized = linkset.Normalized;
|
var normalized = linkset.Normalized;
|
||||||
|
var severity = normalized?.Severities?.FirstOrDefault() is { } severityDict
|
||||||
|
? ExtractSeverity(severityDict)
|
||||||
|
: null;
|
||||||
var conflicts = includeConflicts
|
var conflicts = includeConflicts
|
||||||
? (linkset.Conflicts ?? Array.Empty<AdvisoryLinksetConflict>()).Select(c =>
|
? (linkset.Conflicts ?? Array.Empty<AdvisoryLinksetConflict>()).Select(c =>
|
||||||
new LnmLinksetConflict(
|
new LnmLinksetConflict(
|
||||||
@@ -1764,7 +1767,13 @@ LnmLinksetResponse ToLnmResponse(
|
|||||||
: Array.Empty<LnmLinksetConflict>();
|
: Array.Empty<LnmLinksetConflict>();
|
||||||
|
|
||||||
var timeline = includeTimeline
|
var timeline = includeTimeline
|
||||||
? Array.Empty<LnmLinksetTimeline>() // timeline not yet captured in linkset store
|
? new[]
|
||||||
|
{
|
||||||
|
new LnmLinksetTimeline(
|
||||||
|
Event: "created",
|
||||||
|
At: linkset.CreatedAt,
|
||||||
|
EvidenceHash: linkset.Provenance?.ObservationHashes?.FirstOrDefault())
|
||||||
|
}
|
||||||
: Array.Empty<LnmLinksetTimeline>();
|
: Array.Empty<LnmLinksetTimeline>();
|
||||||
|
|
||||||
var provenance = linkset.Provenance is null
|
var provenance = linkset.Provenance is null
|
||||||
@@ -1780,6 +1789,7 @@ LnmLinksetResponse ToLnmResponse(
|
|||||||
: new LnmLinksetNormalized(
|
: new LnmLinksetNormalized(
|
||||||
Aliases: null,
|
Aliases: null,
|
||||||
Purl: normalized.Purls,
|
Purl: normalized.Purls,
|
||||||
|
Cpe: normalized.Cpes,
|
||||||
Versions: normalized.Versions,
|
Versions: normalized.Versions,
|
||||||
Ranges: normalized.Ranges?.Select(r => (object)r).ToArray(),
|
Ranges: normalized.Ranges?.Select(r => (object)r).ToArray(),
|
||||||
Severities: normalized.Severities?.Select(s => (object)s).ToArray());
|
Severities: normalized.Severities?.Select(s => (object)s).ToArray());
|
||||||
@@ -1788,11 +1798,11 @@ LnmLinksetResponse ToLnmResponse(
|
|||||||
linkset.AdvisoryId,
|
linkset.AdvisoryId,
|
||||||
linkset.Source,
|
linkset.Source,
|
||||||
normalized?.Purls ?? Array.Empty<string>(),
|
normalized?.Purls ?? Array.Empty<string>(),
|
||||||
Array.Empty<string>(),
|
normalized?.Cpes ?? Array.Empty<string>(),
|
||||||
Summary: null,
|
Summary: null,
|
||||||
PublishedAt: linkset.CreatedAt,
|
PublishedAt: linkset.CreatedAt,
|
||||||
ModifiedAt: linkset.CreatedAt,
|
ModifiedAt: linkset.CreatedAt,
|
||||||
Severity: null,
|
Severity: severity,
|
||||||
Status: "fact-only",
|
Status: "fact-only",
|
||||||
provenance,
|
provenance,
|
||||||
conflicts,
|
conflicts,
|
||||||
@@ -1803,6 +1813,27 @@ LnmLinksetResponse ToLnmResponse(
|
|||||||
Observations: includeObservations ? linkset.ObservationIds : Array.Empty<string>());
|
Observations: includeObservations ? linkset.ObservationIds : Array.Empty<string>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string? ExtractSeverity(IReadOnlyDictionary<string, object?> severityDict)
|
||||||
|
{
|
||||||
|
if (severityDict.TryGetValue("system", out var systemObj) && systemObj is string system && !string.IsNullOrWhiteSpace(system) &&
|
||||||
|
severityDict.TryGetValue("score", out var scoreObj))
|
||||||
|
{
|
||||||
|
return $"{system}:{scoreObj}";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (severityDict.TryGetValue("score", out var scoreOnly) && scoreOnly is not null)
|
||||||
|
{
|
||||||
|
return scoreOnly.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (severityDict.TryGetValue("value", out var value) && value is string valueString && !string.IsNullOrWhiteSpace(valueString))
|
||||||
|
{
|
||||||
|
return valueString;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
IResult JsonResult<T>(T value, int? statusCode = null)
|
IResult JsonResult<T>(T value, int? statusCode = null)
|
||||||
{
|
{
|
||||||
var payload = JsonSerializer.Serialize(value, Program.JsonOptions);
|
var payload = JsonSerializer.Serialize(value, Program.JsonOptions);
|
||||||
|
|||||||
@@ -241,6 +241,7 @@ components:
|
|||||||
properties:
|
properties:
|
||||||
aliases: { type: array, items: { type: string } }
|
aliases: { type: array, items: { type: string } }
|
||||||
purl: { type: array, items: { type: string } }
|
purl: { type: array, items: { type: string } }
|
||||||
|
cpe: { type: array, items: { type: string } }
|
||||||
versions: { type: array, items: { type: string } }
|
versions: { type: array, items: { type: string } }
|
||||||
ranges: { type: array, items: { type: object } }
|
ranges: { type: array, items: { type: object } }
|
||||||
severities: { type: array, items: { type: object } }
|
severities: { type: array, items: { type: object } }
|
||||||
|
|||||||
@@ -20,10 +20,14 @@ public sealed record AdvisoryLinkset(
|
|||||||
|
|
||||||
public sealed record AdvisoryLinksetNormalized(
|
public sealed record AdvisoryLinksetNormalized(
|
||||||
IReadOnlyList<string>? Purls,
|
IReadOnlyList<string>? Purls,
|
||||||
|
IReadOnlyList<string>? Cpes,
|
||||||
IReadOnlyList<string>? Versions,
|
IReadOnlyList<string>? Versions,
|
||||||
IReadOnlyList<Dictionary<string, object?>>? Ranges,
|
IReadOnlyList<Dictionary<string, object?>>? Ranges,
|
||||||
IReadOnlyList<Dictionary<string, object?>>? Severities)
|
IReadOnlyList<Dictionary<string, object?>>? Severities)
|
||||||
{
|
{
|
||||||
|
public List<string>? CpesToList()
|
||||||
|
=> Cpes is null ? null : Cpes.ToList();
|
||||||
|
|
||||||
public List<BsonDocument>? RangesToBson()
|
public List<BsonDocument>? RangesToBson()
|
||||||
=> Ranges is null ? null : Ranges.Select(BsonDocumentHelper.FromDictionary).ToList();
|
=> Ranges is null ? null : Ranges.Select(BsonDocumentHelper.FromDictionary).ToList();
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ internal static class AdvisoryLinksetNormalization
|
|||||||
public static AdvisoryLinksetNormalized? FromRawLinkset(RawLinkset linkset)
|
public static AdvisoryLinksetNormalized? FromRawLinkset(RawLinkset linkset)
|
||||||
{
|
{
|
||||||
ArgumentNullException.ThrowIfNull(linkset);
|
ArgumentNullException.ThrowIfNull(linkset);
|
||||||
return Build(linkset.PackageUrls);
|
return Build(linkset.PackageUrls, linkset.Cpes);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AdvisoryLinksetNormalized? FromPurls(IEnumerable<string>? purls)
|
public static AdvisoryLinksetNormalized? FromPurls(IEnumerable<string>? purls)
|
||||||
@@ -22,7 +22,7 @@ internal static class AdvisoryLinksetNormalization
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Build(purls);
|
return Build(purls, Enumerable.Empty<string>());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static (AdvisoryLinksetNormalized? normalized, double? confidence, IReadOnlyList<AdvisoryLinksetConflict> conflicts) FromRawLinksetWithConfidence(
|
public static (AdvisoryLinksetNormalized? normalized, double? confidence, IReadOnlyList<AdvisoryLinksetConflict> conflicts) FromRawLinksetWithConfidence(
|
||||||
@@ -31,7 +31,7 @@ internal static class AdvisoryLinksetNormalization
|
|||||||
{
|
{
|
||||||
ArgumentNullException.ThrowIfNull(linkset);
|
ArgumentNullException.ThrowIfNull(linkset);
|
||||||
|
|
||||||
var normalized = Build(linkset.PackageUrls);
|
var normalized = Build(linkset.PackageUrls, linkset.Cpes);
|
||||||
|
|
||||||
var inputs = new[]
|
var inputs = new[]
|
||||||
{
|
{
|
||||||
@@ -51,18 +51,19 @@ internal static class AdvisoryLinksetNormalization
|
|||||||
return (normalized, coerced, conflicts);
|
return (normalized, coerced, conflicts);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static AdvisoryLinksetNormalized? Build(IEnumerable<string> purlValues)
|
private static AdvisoryLinksetNormalized? Build(IEnumerable<string> purlValues, IEnumerable<string>? cpeValues)
|
||||||
{
|
{
|
||||||
var normalizedPurls = NormalizePurls(purlValues);
|
var normalizedPurls = NormalizePurls(purlValues);
|
||||||
|
var normalizedCpes = NormalizeCpes(cpeValues);
|
||||||
var versions = ExtractVersions(normalizedPurls);
|
var versions = ExtractVersions(normalizedPurls);
|
||||||
var ranges = BuildVersionRanges(normalizedPurls);
|
var ranges = BuildVersionRanges(normalizedPurls);
|
||||||
|
|
||||||
if (normalizedPurls.Count == 0 && versions.Count == 0 && ranges.Count == 0)
|
if (normalizedPurls.Count == 0 && normalizedCpes.Count == 0 && versions.Count == 0 && ranges.Count == 0)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new AdvisoryLinksetNormalized(normalizedPurls, versions, ranges, null);
|
return new AdvisoryLinksetNormalized(normalizedPurls, normalizedCpes, versions, ranges, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<string> NormalizePurls(IEnumerable<string> purls)
|
private static List<string> NormalizePurls(IEnumerable<string> purls)
|
||||||
@@ -147,6 +148,31 @@ internal static class AdvisoryLinksetNormalization
|
|||||||
return ranges;
|
return ranges;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static List<string> NormalizeCpes(IEnumerable<string>? cpes)
|
||||||
|
{
|
||||||
|
if (cpes is null)
|
||||||
|
{
|
||||||
|
return new List<string>(capacity: 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
var distinct = new SortedSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
foreach (var cpe in cpes)
|
||||||
|
{
|
||||||
|
var normalized = Validation.TrimToNull(cpe);
|
||||||
|
if (normalized is null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LinksetNormalization.TryNormalizeCpe(normalized, out var canonical) && !string.IsNullOrEmpty(canonical))
|
||||||
|
{
|
||||||
|
distinct.Add(canonical);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return distinct.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
private static bool LooksLikeRange(string value)
|
private static bool LooksLikeRange(string value)
|
||||||
{
|
{
|
||||||
return value.IndexOfAny(new[] { '^', '~', '*', ' ', ',', '|', '>' , '<' }) >= 0 ||
|
return value.IndexOfAny(new[] { '^', '~', '*', ' ', ',', '|', '>' , '<' }) >= 0 ||
|
||||||
|
|||||||
@@ -61,6 +61,11 @@ public sealed class AdvisoryLinksetNormalizedDocument
|
|||||||
public List<string>? Purls { get; set; }
|
public List<string>? Purls { get; set; }
|
||||||
= new();
|
= new();
|
||||||
|
|
||||||
|
[BsonElement("cpes")]
|
||||||
|
[BsonIgnoreIfNull]
|
||||||
|
public List<string>? Cpes { get; set; }
|
||||||
|
= new();
|
||||||
|
|
||||||
[BsonElement("versions")]
|
[BsonElement("versions")]
|
||||||
[BsonIgnoreIfNull]
|
[BsonIgnoreIfNull]
|
||||||
public List<string>? Versions { get; set; }
|
public List<string>? Versions { get; set; }
|
||||||
|
|||||||
@@ -125,6 +125,7 @@ internal sealed class ConcelierMongoLinksetStore : IMongoAdvisoryLinksetStore
|
|||||||
Normalized = linkset.Normalized is null ? null : new AdvisoryLinksetNormalizedDocument
|
Normalized = linkset.Normalized is null ? null : new AdvisoryLinksetNormalizedDocument
|
||||||
{
|
{
|
||||||
Purls = linkset.Normalized.Purls is null ? null : new List<string>(linkset.Normalized.Purls),
|
Purls = linkset.Normalized.Purls is null ? null : new List<string>(linkset.Normalized.Purls),
|
||||||
|
Cpes = linkset.Normalized.Cpes is null ? null : new List<string>(linkset.Normalized.Cpes),
|
||||||
Versions = linkset.Normalized.Versions is null ? null : new List<string>(linkset.Normalized.Versions),
|
Versions = linkset.Normalized.Versions is null ? null : new List<string>(linkset.Normalized.Versions),
|
||||||
Ranges = linkset.Normalized.RangesToBson(),
|
Ranges = linkset.Normalized.RangesToBson(),
|
||||||
Severities = linkset.Normalized.SeveritiesToBson(),
|
Severities = linkset.Normalized.SeveritiesToBson(),
|
||||||
@@ -141,6 +142,7 @@ internal sealed class ConcelierMongoLinksetStore : IMongoAdvisoryLinksetStore
|
|||||||
doc.Observations.ToImmutableArray(),
|
doc.Observations.ToImmutableArray(),
|
||||||
doc.Normalized is null ? null : new CoreLinksets.AdvisoryLinksetNormalized(
|
doc.Normalized is null ? null : new CoreLinksets.AdvisoryLinksetNormalized(
|
||||||
doc.Normalized.Purls,
|
doc.Normalized.Purls,
|
||||||
|
doc.Normalized.Cpes,
|
||||||
doc.Normalized.Versions,
|
doc.Normalized.Versions,
|
||||||
doc.Normalized.Ranges?.Select(ToDictionary).ToList(),
|
doc.Normalized.Ranges?.Select(ToDictionary).ToList(),
|
||||||
doc.Normalized.Severities?.Select(ToDictionary).ToList()),
|
doc.Normalized.Severities?.Select(ToDictionary).ToList()),
|
||||||
|
|||||||
@@ -214,6 +214,7 @@ internal sealed class EnsureLinkNotMergeCollectionsMigration : IMongoMigration
|
|||||||
{ "properties", new BsonDocument
|
{ "properties", new BsonDocument
|
||||||
{
|
{
|
||||||
{ "purls", new BsonDocument { { "bsonType", new BsonArray { "array", "null" } }, { "items", new BsonDocument("bsonType", "string") } } },
|
{ "purls", new BsonDocument { { "bsonType", new BsonArray { "array", "null" } }, { "items", new BsonDocument("bsonType", "string") } } },
|
||||||
|
{ "cpes", new BsonDocument { { "bsonType", new BsonArray { "array", "null" } }, { "items", new BsonDocument("bsonType", "string") } } },
|
||||||
{ "versions", new BsonDocument { { "bsonType", new BsonArray { "array", "null" } }, { "items", new BsonDocument("bsonType", "string") } } },
|
{ "versions", new BsonDocument { { "bsonType", new BsonArray { "array", "null" } }, { "items", new BsonDocument("bsonType", "string") } } },
|
||||||
{ "ranges", new BsonDocument { { "bsonType", new BsonArray { "array", "null" } }, { "items", new BsonDocument("bsonType", "object") } } },
|
{ "ranges", new BsonDocument { { "bsonType", new BsonArray { "array", "null" } }, { "items", new BsonDocument("bsonType", "object") } } },
|
||||||
{ "severities", new BsonDocument { { "bsonType", new BsonArray { "array", "null" } }, { "items", new BsonDocument("bsonType", "object") } } }
|
{ "severities", new BsonDocument { { "bsonType", new BsonArray { "array", "null" } }, { "items", new BsonDocument("bsonType", "object") } } }
|
||||||
|
|||||||
@@ -14,17 +14,17 @@ public sealed class AdvisoryLinksetQueryServiceTests
|
|||||||
{
|
{
|
||||||
new("tenant", "ghsa", "adv-003",
|
new("tenant", "ghsa", "adv-003",
|
||||||
ImmutableArray.Create("obs-003"),
|
ImmutableArray.Create("obs-003"),
|
||||||
new AdvisoryLinksetNormalized(new[]{"pkg:npm/a"}, new[]{"1.0.0"}, null, null),
|
new AdvisoryLinksetNormalized(new[]{"pkg:npm/a"}, null, new[]{"1.0.0"}, null, null),
|
||||||
null, null, null,
|
null, null, null,
|
||||||
DateTimeOffset.Parse("2025-11-10T12:00:00Z"), null),
|
DateTimeOffset.Parse("2025-11-10T12:00:00Z"), null),
|
||||||
new("tenant", "ghsa", "adv-002",
|
new("tenant", "ghsa", "adv-002",
|
||||||
ImmutableArray.Create("obs-002"),
|
ImmutableArray.Create("obs-002"),
|
||||||
new AdvisoryLinksetNormalized(new[]{"pkg:npm/b"}, new[]{"2.0.0"}, null, null),
|
new AdvisoryLinksetNormalized(new[]{"pkg:npm/b"}, null, new[]{"2.0.0"}, null, null),
|
||||||
null, null, null,
|
null, null, null,
|
||||||
DateTimeOffset.Parse("2025-11-09T12:00:00Z"), null),
|
DateTimeOffset.Parse("2025-11-09T12:00:00Z"), null),
|
||||||
new("tenant", "ghsa", "adv-001",
|
new("tenant", "ghsa", "adv-001",
|
||||||
ImmutableArray.Create("obs-001"),
|
ImmutableArray.Create("obs-001"),
|
||||||
new AdvisoryLinksetNormalized(new[]{"pkg:npm/c"}, new[]{"3.0.0"}, null, null),
|
new AdvisoryLinksetNormalized(new[]{"pkg:npm/c"}, null, new[]{"3.0.0"}, null, null),
|
||||||
null, null, null,
|
null, null, null,
|
||||||
DateTimeOffset.Parse("2025-11-08T12:00:00Z"), null),
|
DateTimeOffset.Parse("2025-11-08T12:00:00Z"), null),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ public class PolicyAuthSignalFactoryTests
|
|||||||
ObservationIds: ImmutableArray.Create("obs-1"),
|
ObservationIds: ImmutableArray.Create("obs-1"),
|
||||||
Normalized: new AdvisoryLinksetNormalized(
|
Normalized: new AdvisoryLinksetNormalized(
|
||||||
Purls: new[] { "purl:pkg:maven/org.example/app@1.2.3" },
|
Purls: new[] { "purl:pkg:maven/org.example/app@1.2.3" },
|
||||||
|
Cpes: null,
|
||||||
Versions: Array.Empty<string>(),
|
Versions: Array.Empty<string>(),
|
||||||
Ranges: null,
|
Ranges: null,
|
||||||
Severities: null),
|
Severities: null),
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ public class AdvisorySummaryMapperTests
|
|||||||
ObservationIds: ImmutableArray.Create("obs1", "obs2"),
|
ObservationIds: ImmutableArray.Create("obs1", "obs2"),
|
||||||
Normalized: new AdvisoryLinksetNormalized(
|
Normalized: new AdvisoryLinksetNormalized(
|
||||||
Purls: new[] { "pkg:maven/log4j/log4j@2.17.1" },
|
Purls: new[] { "pkg:maven/log4j/log4j@2.17.1" },
|
||||||
|
Cpes: null,
|
||||||
Versions: null,
|
Versions: null,
|
||||||
Ranges: null,
|
Ranges: null,
|
||||||
Severities: null),
|
Severities: null),
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user