Restructure solution layout by module
This commit is contained in:
2
.gitattributes
vendored
2
.gitattributes
vendored
@@ -1,2 +1,2 @@
|
|||||||
# Ensure analyzer fixture assets keep LF endings for deterministic hashes
|
# Ensure analyzer fixture assets keep LF endings for deterministic hashes
|
||||||
src/StellaOps.Scanner.Analyzers.Lang.Python.Tests/Fixtures/** text eol=lf
|
src/Scanner/__Tests/StellaOps.Scanner.Analyzers.Lang.Python.Tests/Fixtures/** text eol=lf
|
||||||
|
|||||||
@@ -19,11 +19,11 @@ jobs:
|
|||||||
dotnet-version: 10.0.100-rc.1.25451.107
|
dotnet-version: 10.0.100-rc.1.25451.107
|
||||||
include-prerelease: true
|
include-prerelease: true
|
||||||
|
|
||||||
- name: Restore dependencies
|
- name: Restore dependencies
|
||||||
run: dotnet restore src/StellaOps.Feedser/StellaOps.Feedser.sln
|
run: dotnet restore src/Concelier/StellaOps.Concelier.sln
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: dotnet build src/StellaOps.Feedser/StellaOps.Feedser.sln --configuration Release --no-restore -warnaserror
|
run: dotnet build src/Concelier/StellaOps.Concelier.sln --configuration Release --no-restore -warnaserror
|
||||||
|
|
||||||
- name: Test
|
- name: Test
|
||||||
run: dotnet test src/StellaOps.Feedser/StellaOps.Feedser.Tests/StellaOps.Feedser.Tests.csproj --configuration Release --no-restore --logger "trx;LogFileName=feedser-tests.trx"
|
run: dotnet test src/Concelier/StellaOps.Concelier.sln --configuration Release --no-restore --logger "trx;LogFileName=concelier-tests.trx"
|
||||||
|
|||||||
@@ -77,15 +77,15 @@ jobs:
|
|||||||
include-prerelease: true
|
include-prerelease: true
|
||||||
|
|
||||||
- name: Restore Concelier solution
|
- name: Restore Concelier solution
|
||||||
run: dotnet restore src/StellaOps.Concelier.sln
|
run: dotnet restore src/Concelier/StellaOps.Concelier.sln
|
||||||
|
|
||||||
- name: Build Concelier solution (warnings as errors)
|
- name: Build Concelier solution (warnings as errors)
|
||||||
run: dotnet build src/StellaOps.Concelier.sln --configuration $BUILD_CONFIGURATION --no-restore -warnaserror
|
run: dotnet build src/Concelier/StellaOps.Concelier.sln --configuration $BUILD_CONFIGURATION --no-restore -warnaserror
|
||||||
|
|
||||||
- name: Run Concelier unit and integration tests
|
- name: Run Concelier unit and integration tests
|
||||||
run: |
|
run: |
|
||||||
mkdir -p "$TEST_RESULTS_DIR"
|
mkdir -p "$TEST_RESULTS_DIR"
|
||||||
dotnet test src/StellaOps.Concelier.sln \
|
dotnet test src/Concelier/StellaOps.Concelier.sln \
|
||||||
--configuration $BUILD_CONFIGURATION \
|
--configuration $BUILD_CONFIGURATION \
|
||||||
--no-build \
|
--no-build \
|
||||||
--logger "trx;LogFileName=stellaops-concelier-tests.trx" \
|
--logger "trx;LogFileName=stellaops-concelier-tests.trx" \
|
||||||
@@ -202,20 +202,20 @@ PY
|
|||||||
run: |
|
run: |
|
||||||
dotnet restore src/StellaOps.sln
|
dotnet restore src/StellaOps.sln
|
||||||
for project in \
|
for project in \
|
||||||
src/StellaOps.Scanner.Analyzers.Lang/StellaOps.Scanner.Analyzers.Lang.csproj \
|
src/Scanner/__Libraries/StellaOps.Scanner.Analyzers.Lang/StellaOps.Scanner.Analyzers.Lang.csproj \
|
||||||
src/StellaOps.Scanner.Analyzers.Lang.Java/StellaOps.Scanner.Analyzers.Lang.Java.csproj \
|
src/Scanner/__Libraries/StellaOps.Scanner.Analyzers.Lang.Java/StellaOps.Scanner.Analyzers.Lang.Java.csproj \
|
||||||
src/StellaOps.Scanner.Analyzers.Lang.Node/StellaOps.Scanner.Analyzers.Lang.Node.csproj \
|
src/Scanner/__Libraries/StellaOps.Scanner.Analyzers.Lang.Node/StellaOps.Scanner.Analyzers.Lang.Node.csproj \
|
||||||
src/StellaOps.Scanner.Analyzers.Lang.Python/StellaOps.Scanner.Analyzers.Lang.Python.csproj \
|
src/Scanner/__Libraries/StellaOps.Scanner.Analyzers.Lang.Python/StellaOps.Scanner.Analyzers.Lang.Python.csproj \
|
||||||
src/StellaOps.Scanner.Analyzers.Lang.Go/StellaOps.Scanner.Analyzers.Lang.Go.csproj \
|
src/Scanner/__Libraries/StellaOps.Scanner.Analyzers.Lang.Go/StellaOps.Scanner.Analyzers.Lang.Go.csproj \
|
||||||
src/StellaOps.Scanner.Analyzers.Lang.DotNet/StellaOps.Scanner.Analyzers.Lang.DotNet.csproj \
|
src/Scanner/__Libraries/StellaOps.Scanner.Analyzers.Lang.DotNet/StellaOps.Scanner.Analyzers.Lang.DotNet.csproj \
|
||||||
src/StellaOps.Scanner.Analyzers.Lang.Rust/StellaOps.Scanner.Analyzers.Lang.Rust.csproj
|
src/Scanner/__Libraries/StellaOps.Scanner.Analyzers.Lang.Rust/StellaOps.Scanner.Analyzers.Lang.Rust.csproj
|
||||||
do
|
do
|
||||||
dotnet build "$project" --configuration $BUILD_CONFIGURATION --no-restore -warnaserror
|
dotnet build "$project" --configuration $BUILD_CONFIGURATION --no-restore -warnaserror
|
||||||
done
|
done
|
||||||
|
|
||||||
- name: Run scanner language analyzer tests
|
- name: Run scanner language analyzer tests
|
||||||
run: |
|
run: |
|
||||||
dotnet test src/StellaOps.Scanner.Analyzers.Lang.Tests/StellaOps.Scanner.Analyzers.Lang.Tests.csproj \
|
dotnet test src/Scanner/__Tests/StellaOps.Scanner.Analyzers.Lang.Tests/StellaOps.Scanner.Analyzers.Lang.Tests.csproj \
|
||||||
--configuration $BUILD_CONFIGURATION \
|
--configuration $BUILD_CONFIGURATION \
|
||||||
--no-build \
|
--no-build \
|
||||||
--logger "trx;LogFileName=stellaops-scanner-lang-tests.trx" \
|
--logger "trx;LogFileName=stellaops-scanner-lang-tests.trx" \
|
||||||
@@ -231,11 +231,11 @@ PY
|
|||||||
CAPTURED_AT="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
|
CAPTURED_AT="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
|
||||||
|
|
||||||
dotnet run \
|
dotnet run \
|
||||||
--project src/StellaOps.Bench/Scanner.Analyzers/StellaOps.Bench.ScannerAnalyzers/StellaOps.Bench.ScannerAnalyzers.csproj \
|
--project src/Bench/StellaOps.Bench/Scanner.Analyzers/StellaOps.Bench.ScannerAnalyzers/StellaOps.Bench.ScannerAnalyzers.csproj \
|
||||||
--configuration $BUILD_CONFIGURATION \
|
--configuration $BUILD_CONFIGURATION \
|
||||||
-- \
|
-- \
|
||||||
--repo-root . \
|
--repo-root . \
|
||||||
--baseline src/StellaOps.Bench/Scanner.Analyzers/baseline.csv \
|
--baseline src/Bench/StellaOps.Bench/Scanner.Analyzers/baseline.csv \
|
||||||
--out "$PERF_OUTPUT_DIR/latest.csv" \
|
--out "$PERF_OUTPUT_DIR/latest.csv" \
|
||||||
--json "$PERF_OUTPUT_DIR/report.json" \
|
--json "$PERF_OUTPUT_DIR/report.json" \
|
||||||
--prom "$PERF_OUTPUT_DIR/metrics.prom" \
|
--prom "$PERF_OUTPUT_DIR/metrics.prom" \
|
||||||
@@ -253,7 +253,7 @@ PY
|
|||||||
|
|
||||||
- name: Publish BuildX SBOM generator
|
- name: Publish BuildX SBOM generator
|
||||||
run: |
|
run: |
|
||||||
dotnet publish src/StellaOps.Scanner.Sbomer.BuildXPlugin/StellaOps.Scanner.Sbomer.BuildXPlugin.csproj \
|
dotnet publish src/Scanner/StellaOps.Scanner.Sbomer.BuildXPlugin/StellaOps.Scanner.Sbomer.BuildXPlugin.csproj \
|
||||||
--configuration $BUILD_CONFIGURATION \
|
--configuration $BUILD_CONFIGURATION \
|
||||||
--output out/buildx
|
--output out/buildx
|
||||||
|
|
||||||
@@ -337,10 +337,10 @@ PY
|
|||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
retention-days: 7
|
retention-days: 7
|
||||||
|
|
||||||
- name: Publish Feedser web service
|
- name: Publish Concelier web service
|
||||||
run: |
|
run: |
|
||||||
mkdir -p "$PUBLISH_DIR"
|
mkdir -p "$PUBLISH_DIR"
|
||||||
dotnet publish src/StellaOps.Feedser.WebService/StellaOps.Feedser.WebService.csproj \
|
dotnet publish src/Concelier/StellaOps.Concelier.WebService/StellaOps.Concelier.WebService.csproj \
|
||||||
--configuration $BUILD_CONFIGURATION \
|
--configuration $BUILD_CONFIGURATION \
|
||||||
--no-build \
|
--no-build \
|
||||||
--output "$PUBLISH_DIR"
|
--output "$PUBLISH_DIR"
|
||||||
@@ -348,20 +348,20 @@ PY
|
|||||||
- name: Upload published artifacts
|
- name: Upload published artifacts
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: feedser-publish
|
name: concelier-publish
|
||||||
path: ${{ env.PUBLISH_DIR }}
|
path: ${{ env.PUBLISH_DIR }}
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
retention-days: 7
|
retention-days: 7
|
||||||
|
|
||||||
- name: Restore Authority solution
|
- name: Restore Authority solution
|
||||||
run: dotnet restore src/StellaOps.Authority/StellaOps.Authority.sln
|
run: dotnet restore src/Authority/StellaOps.Authority/StellaOps.Authority.sln
|
||||||
|
|
||||||
- name: Build Authority solution
|
- name: Build Authority solution
|
||||||
run: dotnet build src/StellaOps.Authority/StellaOps.Authority.sln --configuration $BUILD_CONFIGURATION --no-restore -warnaserror
|
run: dotnet build src/Authority/StellaOps.Authority/StellaOps.Authority.sln --configuration $BUILD_CONFIGURATION --no-restore -warnaserror
|
||||||
|
|
||||||
- name: Run Authority tests
|
- name: Run Authority tests
|
||||||
run: |
|
run: |
|
||||||
dotnet test src/StellaOps.Configuration.Tests/StellaOps.Configuration.Tests.csproj \
|
dotnet test src/__Libraries/__Tests/StellaOps.Configuration.Tests/StellaOps.Configuration.Tests.csproj \
|
||||||
--configuration $BUILD_CONFIGURATION \
|
--configuration $BUILD_CONFIGURATION \
|
||||||
--no-build \
|
--no-build \
|
||||||
--logger "trx;LogFileName=stellaops-authority-tests.trx" \
|
--logger "trx;LogFileName=stellaops-authority-tests.trx" \
|
||||||
@@ -370,7 +370,7 @@ PY
|
|||||||
- name: Publish Authority web service
|
- name: Publish Authority web service
|
||||||
run: |
|
run: |
|
||||||
mkdir -p "$AUTHORITY_PUBLISH_DIR"
|
mkdir -p "$AUTHORITY_PUBLISH_DIR"
|
||||||
dotnet publish src/StellaOps.Authority/StellaOps.Authority/StellaOps.Authority.csproj \
|
dotnet publish src/Authority/StellaOps.Authority/StellaOps.Authority/StellaOps.Authority.csproj \
|
||||||
--configuration $BUILD_CONFIGURATION \
|
--configuration $BUILD_CONFIGURATION \
|
||||||
--no-build \
|
--no-build \
|
||||||
--output "$AUTHORITY_PUBLISH_DIR"
|
--output "$AUTHORITY_PUBLISH_DIR"
|
||||||
@@ -439,7 +439,7 @@ PY
|
|||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
needs: build-test
|
needs: build-test
|
||||||
env:
|
env:
|
||||||
BENCH_DIR: src/StellaOps.Bench/Scanner.Analyzers
|
BENCH_DIR: src/Bench/StellaOps.Bench/Scanner.Analyzers
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|||||||
@@ -1,39 +1,39 @@
|
|||||||
# .gitea/workflows/docs.yml
|
# .gitea/workflows/docs.yml
|
||||||
# Documentation quality checks and preview artefacts
|
# Documentation quality checks and preview artefacts
|
||||||
|
|
||||||
name: Docs CI
|
name: Docs CI
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
paths:
|
paths:
|
||||||
- 'docs/**'
|
- 'docs/**'
|
||||||
- 'scripts/render_docs.py'
|
- 'scripts/render_docs.py'
|
||||||
- '.gitea/workflows/docs.yml'
|
- '.gitea/workflows/docs.yml'
|
||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
paths:
|
||||||
- 'docs/**'
|
- 'docs/**'
|
||||||
- 'scripts/render_docs.py'
|
- 'scripts/render_docs.py'
|
||||||
- '.gitea/workflows/docs.yml'
|
- '.gitea/workflows/docs.yml'
|
||||||
workflow_dispatch: {}
|
workflow_dispatch: {}
|
||||||
|
|
||||||
env:
|
env:
|
||||||
NODE_VERSION: '20'
|
NODE_VERSION: '20'
|
||||||
PYTHON_VERSION: '3.11'
|
PYTHON_VERSION: '3.11'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
lint-and-preview:
|
lint-and-preview:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
env:
|
env:
|
||||||
DOCS_OUTPUT_DIR: ${{ github.workspace }}/artifacts/docs-preview
|
DOCS_OUTPUT_DIR: ${{ github.workspace }}/artifacts/docs-preview
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: ${{ env.NODE_VERSION }}
|
node-version: ${{ env.NODE_VERSION }}
|
||||||
|
|
||||||
- name: Install documentation toolchain
|
- name: Install documentation toolchain
|
||||||
run: |
|
run: |
|
||||||
npm install --no-save markdown-link-check remark-cli remark-preset-lint-recommended ajv ajv-cli ajv-formats
|
npm install --no-save markdown-link-check remark-cli remark-preset-lint-recommended ajv ajv-cli ajv-formats
|
||||||
@@ -43,11 +43,11 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
dotnet-version: '10.0.100-rc.2.25502.107'
|
dotnet-version: '10.0.100-rc.2.25502.107'
|
||||||
|
|
||||||
- name: Link check
|
- name: Link check
|
||||||
run: |
|
run: |
|
||||||
find docs -name '*.md' -print0 | \
|
find docs -name '*.md' -print0 | \
|
||||||
xargs -0 -n1 -I{} npx markdown-link-check --quiet '{}'
|
xargs -0 -n1 -I{} npx markdown-link-check --quiet '{}'
|
||||||
|
|
||||||
- name: Remark lint
|
- name: Remark lint
|
||||||
run: |
|
run: |
|
||||||
npx remark docs -qf
|
npx remark docs -qf
|
||||||
@@ -70,26 +70,26 @@ jobs:
|
|||||||
|
|
||||||
- name: Run Notify schema validation tests
|
- name: Run Notify schema validation tests
|
||||||
run: |
|
run: |
|
||||||
dotnet test src/StellaOps.Notify.Models.Tests/StellaOps.Notify.Models.Tests.csproj --configuration Release --nologo
|
dotnet test src/Notify/__Tests/StellaOps.Notify.Models.Tests/StellaOps.Notify.Models.Tests.csproj --configuration Release --nologo
|
||||||
|
|
||||||
- name: Setup Python
|
- name: Setup Python
|
||||||
uses: actions/setup-python@v5
|
uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: ${{ env.PYTHON_VERSION }}
|
python-version: ${{ env.PYTHON_VERSION }}
|
||||||
|
|
||||||
- name: Install documentation dependencies
|
- name: Install documentation dependencies
|
||||||
run: |
|
run: |
|
||||||
python -m pip install --upgrade pip
|
python -m pip install --upgrade pip
|
||||||
python -m pip install markdown pygments
|
python -m pip install markdown pygments
|
||||||
|
|
||||||
- name: Render documentation preview bundle
|
- name: Render documentation preview bundle
|
||||||
run: |
|
run: |
|
||||||
python scripts/render_docs.py --source docs --output "$DOCS_OUTPUT_DIR" --clean
|
python scripts/render_docs.py --source docs --output "$DOCS_OUTPUT_DIR" --clean
|
||||||
|
|
||||||
- name: Upload documentation preview
|
- name: Upload documentation preview
|
||||||
if: always()
|
if: always()
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: feedser-docs-preview
|
name: feedser-docs-preview
|
||||||
path: ${{ env.DOCS_OUTPUT_DIR }}
|
path: ${{ env.DOCS_OUTPUT_DIR }}
|
||||||
retention-days: 7
|
retention-days: 7
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ jobs:
|
|||||||
- name: Publish Python analyzer plug-in
|
- name: Publish Python analyzer plug-in
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
dotnet publish src/StellaOps.Scanner.Analyzers.Lang.Python/StellaOps.Scanner.Analyzers.Lang.Python.csproj \
|
dotnet publish src/Scanner/__Libraries/StellaOps.Scanner.Analyzers.Lang.Python/StellaOps.Scanner.Analyzers.Lang.Python.csproj \
|
||||||
--configuration Release \
|
--configuration Release \
|
||||||
--output out/analyzers/python \
|
--output out/analyzers/python \
|
||||||
--no-self-contained
|
--no-self-contained
|
||||||
|
|||||||
68
.gitignore
vendored
68
.gitignore
vendored
@@ -1,34 +1,34 @@
|
|||||||
# Build outputs
|
# Build outputs
|
||||||
bin/
|
bin/
|
||||||
obj/
|
obj/
|
||||||
*.pdb
|
*.pdb
|
||||||
*.dll
|
*.dll
|
||||||
|
|
||||||
# IDE state
|
# IDE state
|
||||||
.vs/
|
.vs/
|
||||||
*.user
|
*.user
|
||||||
*.suo
|
*.suo
|
||||||
*.userprefs
|
*.userprefs
|
||||||
|
|
||||||
# Rider/VSCode
|
# Rider/VSCode
|
||||||
.idea/
|
.idea/
|
||||||
.vscode/
|
.vscode/
|
||||||
|
|
||||||
# Packages and logs
|
# Packages and logs
|
||||||
*.log
|
*.log
|
||||||
TestResults/
|
TestResults/
|
||||||
|
|
||||||
.dotnet
|
.dotnet
|
||||||
.DS_Store
|
.DS_Store
|
||||||
seed-data/ics-cisa/*.csv
|
seed-data/ics-cisa/*.csv
|
||||||
seed-data/ics-cisa/*.xlsx
|
seed-data/ics-cisa/*.xlsx
|
||||||
seed-data/ics-cisa/*.sha256
|
seed-data/ics-cisa/*.sha256
|
||||||
seed-data/cert-bund/**/*.json
|
seed-data/cert-bund/**/*.json
|
||||||
seed-data/cert-bund/**/*.sha256
|
seed-data/cert-bund/**/*.sha256
|
||||||
|
|
||||||
out/offline-kit/web/**/*
|
out/offline-kit/web/**/*
|
||||||
src/StellaOps.Web/node_modules/**/*
|
src/Web/StellaOps.Web/node_modules/**/*
|
||||||
src/StellaOps.Web/.angular/**/*
|
src/Web/StellaOps.Web/.angular/**/*
|
||||||
**/node_modules/**/*
|
**/node_modules/**/*
|
||||||
node_modules
|
node_modules
|
||||||
tmp/**/*
|
tmp/**/*
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
home = /usr/bin
|
home = /usr/bin
|
||||||
include-system-site-packages = false
|
include-system-site-packages = false
|
||||||
version = 3.12.3
|
version = 3.12.3
|
||||||
executable = /usr/bin/python3.12
|
executable = /usr/bin/python3.12
|
||||||
command = /usr/bin/python3 -m venv /mnt/e/dev/git.stella-ops.org/.venv
|
command = /usr/bin/python3 -m venv /mnt/e/dev/git.stella-ops.org/.venv
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
<Project>
|
<Project>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<StellaOpsRepoRoot Condition="'$(StellaOpsRepoRoot)' == ''">$([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)'))</StellaOpsRepoRoot>
|
<StellaOpsRepoRoot Condition="'$(StellaOpsRepoRoot)' == ''">$([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)'))</StellaOpsRepoRoot>
|
||||||
<StellaOpsLocalNuGetSource Condition="'$(StellaOpsLocalNuGetSource)' == ''">$([System.IO.Path]::GetFullPath('$(StellaOpsRepoRoot)local-nuget/'))</StellaOpsLocalNuGetSource>
|
<StellaOpsLocalNuGetSource Condition="'$(StellaOpsLocalNuGetSource)' == ''">$([System.IO.Path]::GetFullPath('$(StellaOpsRepoRoot)local-nuget/'))</StellaOpsLocalNuGetSource>
|
||||||
<StellaOpsDotNetPublicSource Condition="'$(StellaOpsDotNetPublicSource)' == ''">https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public/nuget/v3/index.json</StellaOpsDotNetPublicSource>
|
<StellaOpsDotNetPublicSource Condition="'$(StellaOpsDotNetPublicSource)' == ''">https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public/nuget/v3/index.json</StellaOpsDotNetPublicSource>
|
||||||
<StellaOpsNuGetOrgSource Condition="'$(StellaOpsNuGetOrgSource)' == ''">https://api.nuget.org/v3/index.json</StellaOpsNuGetOrgSource>
|
<StellaOpsNuGetOrgSource Condition="'$(StellaOpsNuGetOrgSource)' == ''">https://api.nuget.org/v3/index.json</StellaOpsNuGetOrgSource>
|
||||||
<_StellaOpsDefaultRestoreSources>$(StellaOpsLocalNuGetSource);$(StellaOpsDotNetPublicSource);$(StellaOpsNuGetOrgSource)</_StellaOpsDefaultRestoreSources>
|
<_StellaOpsDefaultRestoreSources>$(StellaOpsLocalNuGetSource);$(StellaOpsDotNetPublicSource);$(StellaOpsNuGetOrgSource)</_StellaOpsDefaultRestoreSources>
|
||||||
<_StellaOpsOriginalRestoreSources Condition="'$(_StellaOpsOriginalRestoreSources)' == ''">$(RestoreSources)</_StellaOpsOriginalRestoreSources>
|
<_StellaOpsOriginalRestoreSources Condition="'$(_StellaOpsOriginalRestoreSources)' == ''">$(RestoreSources)</_StellaOpsOriginalRestoreSources>
|
||||||
<RestoreSources Condition="'$(_StellaOpsOriginalRestoreSources)' == ''">$(_StellaOpsDefaultRestoreSources)</RestoreSources>
|
<RestoreSources Condition="'$(_StellaOpsOriginalRestoreSources)' == ''">$(_StellaOpsDefaultRestoreSources)</RestoreSources>
|
||||||
<RestoreSources Condition="'$(_StellaOpsOriginalRestoreSources)' != ''">$(_StellaOpsDefaultRestoreSources);$(_StellaOpsOriginalRestoreSources)</RestoreSources>
|
<RestoreSources Condition="'$(_StellaOpsOriginalRestoreSources)' != ''">$(_StellaOpsDefaultRestoreSources);$(_StellaOpsOriginalRestoreSources)</RestoreSources>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -1,93 +1,93 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>net472;netstandard2.1</TargetFrameworks>
|
<TargetFrameworks>net472;netstandard2.1</TargetFrameworks>
|
||||||
<Authors>Johannes Hoppe and many contributors</Authors>
|
<Authors>Johannes Hoppe and many contributors</Authors>
|
||||||
<Description>Mongo2Go is a managed wrapper around MongoDB binaries. It targets .NET Framework 4.7.2 and .NET Standard 2.1.
|
<Description>Mongo2Go is a managed wrapper around MongoDB binaries. It targets .NET Framework 4.7.2 and .NET Standard 2.1.
|
||||||
This Nuget package contains the executables of mongod, mongoimport and mongoexport v4.4.4 for Windows, Linux and macOS.
|
This Nuget package contains the executables of mongod, mongoimport and mongoexport v4.4.4 for Windows, Linux and macOS.
|
||||||
|
|
||||||
|
|
||||||
Mongo2Go has two use cases:
|
Mongo2Go has two use cases:
|
||||||
|
|
||||||
1. Providing multiple, temporary and isolated MongoDB databases for integration tests
|
1. Providing multiple, temporary and isolated MongoDB databases for integration tests
|
||||||
2. Providing a quick to set up MongoDB database for a local developer environment</Description>
|
2. Providing a quick to set up MongoDB database for a local developer environment</Description>
|
||||||
<Company>HAUS HOPPE - ITS</Company>
|
<Company>HAUS HOPPE - ITS</Company>
|
||||||
<Copyright>Copyright © 2012-2025 Johannes Hoppe and many ❤️ contributors</Copyright>
|
<Copyright>Copyright © 2012-2025 Johannes Hoppe and many ❤️ contributors</Copyright>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
<PackageIcon>icon.png</PackageIcon>
|
<PackageIcon>icon.png</PackageIcon>
|
||||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||||
<PackageProjectUrl>https://github.com/Mongo2Go/Mongo2Go</PackageProjectUrl>
|
<PackageProjectUrl>https://github.com/Mongo2Go/Mongo2Go</PackageProjectUrl>
|
||||||
<PackageReleaseNotes>https://github.com/Mongo2Go/Mongo2Go/releases</PackageReleaseNotes>
|
<PackageReleaseNotes>https://github.com/Mongo2Go/Mongo2Go/releases</PackageReleaseNotes>
|
||||||
<PackageTags>MongoDB Mongo unit test integration runner</PackageTags>
|
<PackageTags>MongoDB Mongo unit test integration runner</PackageTags>
|
||||||
<RepositoryUrl>https://github.com/Mongo2Go/Mongo2Go</RepositoryUrl>
|
<RepositoryUrl>https://github.com/Mongo2Go/Mongo2Go</RepositoryUrl>
|
||||||
<RepositoryType>git</RepositoryType>
|
<RepositoryType>git</RepositoryType>
|
||||||
<AssemblyTitle>Mongo2Go</AssemblyTitle>
|
<AssemblyTitle>Mongo2Go</AssemblyTitle>
|
||||||
<AssemblyDescription>Mongo2Go is a managed wrapper around MongoDB binaries.</AssemblyDescription>
|
<AssemblyDescription>Mongo2Go is a managed wrapper around MongoDB binaries.</AssemblyDescription>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|netstandard2.1|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|netstandard2.1|AnyCPU'">
|
||||||
<WarningLevel>4</WarningLevel>
|
<WarningLevel>4</WarningLevel>
|
||||||
<NoWarn>1701;1702;1591;1573</NoWarn>
|
<NoWarn>1701;1702;1591;1573</NoWarn>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|netstandard2.1|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|netstandard2.1|AnyCPU'">
|
||||||
<WarningLevel>4</WarningLevel>
|
<WarningLevel>4</WarningLevel>
|
||||||
<NoWarn>1701;1702;1591;1573</NoWarn>
|
<NoWarn>1701;1702;1591;1573</NoWarn>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net48|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net48|AnyCPU'">
|
||||||
<NoWarn>1701;1702;1591;1573</NoWarn>
|
<NoWarn>1701;1702;1591;1573</NoWarn>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net48|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net48|AnyCPU'">
|
||||||
<NoWarn>1701;1702;1591;1573</NoWarn>
|
<NoWarn>1701;1702;1591;1573</NoWarn>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Label="Restoring">
|
<PropertyGroup Label="Restoring">
|
||||||
<DisableImplicitNuGetFallbackFolder>true</DisableImplicitNuGetFallbackFolder>
|
<DisableImplicitNuGetFallbackFolder>true</DisableImplicitNuGetFallbackFolder>
|
||||||
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
|
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
|
||||||
<RestoreLockedMode Condition="$(ContinuousIntegrationBuild) == 'true'">true</RestoreLockedMode>
|
<RestoreLockedMode Condition="$(ContinuousIntegrationBuild) == 'true'">true</RestoreLockedMode>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Label="SourceLink">
|
<PropertyGroup Label="SourceLink">
|
||||||
<DebugType>embedded</DebugType>
|
<DebugType>embedded</DebugType>
|
||||||
<EmbedUntrackedSources>true</EmbedUntrackedSources>
|
<EmbedUntrackedSources>true</EmbedUntrackedSources>
|
||||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Label="MinVer">
|
<PropertyGroup Label="MinVer">
|
||||||
<MinVerTagPrefix>v</MinVerTagPrefix>
|
<MinVerTagPrefix>v</MinVerTagPrefix>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Update="packages.lock.json" Visible="false" />
|
<None Update="packages.lock.json" Visible="false" />
|
||||||
<None Include="../mongo2go_200_200.png" Visible="false">
|
<None Include="../mongo2go_200_200.png" Visible="false">
|
||||||
<Pack>true</Pack>
|
<Pack>true</Pack>
|
||||||
<PackagePath>icon.png</PackagePath>
|
<PackagePath>icon.png</PackagePath>
|
||||||
</None>
|
</None>
|
||||||
<None Include="../../tools/mongodb*/**" Visible="false">
|
<None Include="../../tools/mongodb*/**" Visible="false">
|
||||||
<Pack>true</Pack>
|
<Pack>true</Pack>
|
||||||
<PackagePath>tools</PackagePath>
|
<PackagePath>tools</PackagePath>
|
||||||
</None>
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.0-rc.2.25502.107" />
|
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.0-rc.2.25502.107" />
|
||||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="all" />
|
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="all" />
|
||||||
<PackageReference Include="MinVer" Version="2.5.0" PrivateAssets="all" />
|
<PackageReference Include="MinVer" Version="2.5.0" PrivateAssets="all" />
|
||||||
<PackageReference Include="MongoDB.Driver" Version="3.5.0" />
|
<PackageReference Include="MongoDB.Driver" Version="3.5.0" />
|
||||||
<PackageReference Include="SharpCompress" Version="0.41.0" />
|
<PackageReference Include="SharpCompress" Version="0.41.0" />
|
||||||
<PackageReference Include="System.Text.Json" Version="6.0.10" />
|
<PackageReference Include="System.Text.Json" Version="6.0.10" />
|
||||||
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.3" PrivateAssets="all" />
|
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.3" PrivateAssets="all" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<InternalsVisibleTo Include="Mongo2GoTests" />
|
<InternalsVisibleTo Include="Mongo2GoTests" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<Target Name="PrintPackageVersionForGitHubActions" AfterTargets="Pack">
|
<Target Name="PrintPackageVersionForGitHubActions" AfterTargets="Pack">
|
||||||
<Message Importance="high" Text="version=$(PackageVersion)" />
|
<Message Importance="high" Text="version=$(PackageVersion)" />
|
||||||
<Message Importance="high" Text="nupkg-filename=$(PackageId).$(PackageVersion).nupkg" />
|
<Message Importance="high" Text="nupkg-filename=$(PackageId).$(PackageVersion).nupkg" />
|
||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<IsPackable>false</IsPackable>
|
<IsPackable>false</IsPackable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Mongo2Go\Mongo2Go.csproj" />
|
<ProjectReference Include="..\Mongo2Go\Mongo2Go.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="FluentAssertions" Version="5.10.3" />
|
<PackageReference Include="FluentAssertions" Version="5.10.3" />
|
||||||
<PackageReference Include="Machine.Specifications" Version="1.0.0" />
|
<PackageReference Include="Machine.Specifications" Version="1.0.0" />
|
||||||
<PackageReference Include="Machine.Specifications.Runner.VisualStudio" Version="2.10.1" />
|
<PackageReference Include="Machine.Specifications.Runner.VisualStudio" Version="2.10.1" />
|
||||||
<PackageReference Include="MELT" Version="0.7.0" />
|
<PackageReference Include="MELT" Version="0.7.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.1" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.1" />
|
||||||
<PackageReference Include="Moq" Version="4.16.1" />
|
<PackageReference Include="Moq" Version="4.16.1" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
<PackageReference Include="System.Net.Http" Version="4.3.4" />
|
<PackageReference Include="System.Net.Http" Version="4.3.4" />
|
||||||
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" />
|
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
88
NuGet.config
88
NuGet.config
@@ -1,44 +1,44 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<configuration>
|
<configuration>
|
||||||
<config>
|
<config>
|
||||||
<add key="restoreIgnoreFailedSources" value="true" />
|
<add key="restoreIgnoreFailedSources" value="true" />
|
||||||
</config>
|
</config>
|
||||||
<packageSources>
|
<packageSources>
|
||||||
<clear />
|
<clear />
|
||||||
<add key="local" value="local-nuget" />
|
<add key="local" value="local-nuget" />
|
||||||
<add key="dotnet-public" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public/nuget/v3/index.json" />
|
<add key="dotnet-public" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public/nuget/v3/index.json" />
|
||||||
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
|
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
|
||||||
</packageSources>
|
</packageSources>
|
||||||
<packageSourceMapping>
|
<packageSourceMapping>
|
||||||
<packageSource key="local">
|
<packageSource key="local">
|
||||||
<package pattern="Mongo2Go" />
|
<package pattern="Mongo2Go" />
|
||||||
<package pattern="Microsoft.IdentityModel.Tokens" />
|
<package pattern="Microsoft.IdentityModel.Tokens" />
|
||||||
<package pattern="Microsoft.Extensions.Http.Polly" />
|
<package pattern="Microsoft.Extensions.Http.Polly" />
|
||||||
<package pattern="Microsoft.Extensions.Caching.Memory" />
|
<package pattern="Microsoft.Extensions.Caching.Memory" />
|
||||||
<package pattern="Microsoft.Extensions.Configuration" />
|
<package pattern="Microsoft.Extensions.Configuration" />
|
||||||
<package pattern="Microsoft.Extensions.Configuration.Binder" />
|
<package pattern="Microsoft.Extensions.Configuration.Binder" />
|
||||||
<package pattern="Microsoft.Extensions.DependencyInjection.Abstractions" />
|
<package pattern="Microsoft.Extensions.DependencyInjection.Abstractions" />
|
||||||
<package pattern="Microsoft.Extensions.Hosting" />
|
<package pattern="Microsoft.Extensions.Hosting" />
|
||||||
<package pattern="Microsoft.Extensions.Hosting.Abstractions" />
|
<package pattern="Microsoft.Extensions.Hosting.Abstractions" />
|
||||||
<package pattern="Microsoft.Extensions.Http" />
|
<package pattern="Microsoft.Extensions.Http" />
|
||||||
<package pattern="Microsoft.Extensions.Logging.Abstractions" />
|
<package pattern="Microsoft.Extensions.Logging.Abstractions" />
|
||||||
<package pattern="Microsoft.Extensions.Options" />
|
<package pattern="Microsoft.Extensions.Options" />
|
||||||
<package pattern="Microsoft.Extensions.Options.ConfigurationExtensions" />
|
<package pattern="Microsoft.Extensions.Options.ConfigurationExtensions" />
|
||||||
<package pattern="Microsoft.Data.Sqlite" />
|
<package pattern="Microsoft.Data.Sqlite" />
|
||||||
<package pattern="Microsoft.AspNetCore.Authentication.JwtBearer" />
|
<package pattern="Microsoft.AspNetCore.Authentication.JwtBearer" />
|
||||||
<package pattern="Google.Protobuf" />
|
<package pattern="Google.Protobuf" />
|
||||||
<package pattern="Grpc.*" />
|
<package pattern="Grpc.*" />
|
||||||
<package pattern="Microsoft.Bcl.AsyncInterfaces" />
|
<package pattern="Microsoft.Bcl.AsyncInterfaces" />
|
||||||
<package pattern="System.Memory" />
|
<package pattern="System.Memory" />
|
||||||
<package pattern="System.Runtime.CompilerServices.Unsafe" />
|
<package pattern="System.Runtime.CompilerServices.Unsafe" />
|
||||||
</packageSource>
|
</packageSource>
|
||||||
<packageSource key="dotnet-public">
|
<packageSource key="dotnet-public">
|
||||||
<package pattern="Microsoft.Extensions.*" />
|
<package pattern="Microsoft.Extensions.*" />
|
||||||
<package pattern="Microsoft.AspNetCore.*" />
|
<package pattern="Microsoft.AspNetCore.*" />
|
||||||
<package pattern="Microsoft.Data.Sqlite" />
|
<package pattern="Microsoft.Data.Sqlite" />
|
||||||
</packageSource>
|
</packageSource>
|
||||||
<packageSource key="nuget.org">
|
<packageSource key="nuget.org">
|
||||||
<package pattern="*" />
|
<package pattern="*" />
|
||||||
</packageSource>
|
</packageSource>
|
||||||
</packageSourceMapping>
|
</packageSourceMapping>
|
||||||
</configuration>
|
</configuration>
|
||||||
|
|||||||
@@ -14,9 +14,9 @@ control against the Concelier API.
|
|||||||
3. Copy `etc/authority.yaml.sample` to `etc/authority.yaml`, review the issuer, token
|
3. Copy `etc/authority.yaml.sample` to `etc/authority.yaml`, review the issuer, token
|
||||||
lifetimes, and plug-in descriptors, then edit the companion manifests under
|
lifetimes, and plug-in descriptors, then edit the companion manifests under
|
||||||
`etc/authority.plugins/*.yaml` to match your deployment.
|
`etc/authority.plugins/*.yaml` to match your deployment.
|
||||||
4. Start the web service with `dotnet run --project src/StellaOps.Concelier.WebService`.
|
4. Start the web service with `dotnet run --project src/Concelier/StellaOps.Concelier.WebService`.
|
||||||
5. Configure the CLI via environment variables (e.g. `STELLAOPS_BACKEND_URL`) and trigger
|
5. Configure the CLI via environment variables (e.g. `STELLAOPS_BACKEND_URL`) and trigger
|
||||||
jobs with `dotnet run --project src/StellaOps.Cli -- db merge`.
|
jobs with `dotnet run --project src/Cli/StellaOps.Cli -- db merge`.
|
||||||
|
|
||||||
Detailed operator guidance is available in `docs/10_CONCELIER_CLI_QUICKSTART.md`. API and
|
Detailed operator guidance is available in `docs/10_CONCELIER_CLI_QUICKSTART.md`. API and
|
||||||
command reference material lives in `docs/09_API_CLI_REFERENCE.md`.
|
command reference material lives in `docs/09_API_CLI_REFERENCE.md`.
|
||||||
@@ -31,4 +31,4 @@ for integration steps once available.
|
|||||||
- `docs/README.md` now consolidates the platform index and points to the updated high-level architecture.
|
- `docs/README.md` now consolidates the platform index and points to the updated high-level architecture.
|
||||||
- Module architecture dossiers live under `docs/ARCHITECTURE_*.md`; the most relevant here are `docs/ARCHITECTURE_CONCELIER.md` (service layout, merge engine, exports) and `docs/ARCHITECTURE_CLI.md` (command surface, AOT packaging, auth flows). Related services such as the Signer, Attestor, Authority, Scanner, UI, Excititor, Zastava, and DevOps pipeline each have their own dossier.
|
- Module architecture dossiers live under `docs/ARCHITECTURE_*.md`; the most relevant here are `docs/ARCHITECTURE_CONCELIER.md` (service layout, merge engine, exports) and `docs/ARCHITECTURE_CLI.md` (command surface, AOT packaging, auth flows). Related services such as the Signer, Attestor, Authority, Scanner, UI, Excititor, Zastava, and DevOps pipeline each have their own dossier.
|
||||||
- Offline operation guidance moved to `docs/24_OFFLINE_KIT.md`, which details bundle composition, verification, and delta workflows. Concelier-specific connector operations stay in `docs/ops/concelier-certbund-operations.md` and companion runbooks under `docs/ops/`.
|
- Offline operation guidance moved to `docs/24_OFFLINE_KIT.md`, which details bundle composition, verification, and delta workflows. Concelier-specific connector operations stay in `docs/ops/concelier-certbund-operations.md` and companion runbooks under `docs/ops/`.
|
||||||
|
|
||||||
|
|||||||
1119
SPRINTS.md
1119
SPRINTS.md
File diff suppressed because it is too large
Load Diff
@@ -1,208 +0,0 @@
|
|||||||
Closed sprint tasks archived from SPRINTS.md on 2025-10-19.
|
|
||||||
|
|
||||||
| Sprint | Theme | Tasks File Path | Status | Type of Specialist | Task ID | Task Description |
|
|
||||||
| --- | --- | --- | --- | --- | --- | --- |
|
|
||||||
| Sprint 1 | Stabilize In-Progress Foundations | src/StellaOps.Concelier.Models/TASKS.md | DONE (2025-10-12) | Team Models & Merge Leads | FEEDMODELS-SCHEMA-01-001 | SemVer primitive range-style metadata<br>Instructions to work:<br>DONE Read ./AGENTS.md and src/StellaOps.Concelier.Models/AGENTS.md. This task lays the groundwork—complete the SemVer helper updates before teammates pick up FEEDMODELS-SCHEMA-01-002/003 and FEEDMODELS-SCHEMA-02-900. Use ./src/FASTER_MODELING_AND_NORMALIZATION.md for the target rule structure. |
|
|
||||||
| Sprint 1 | Stabilize In-Progress Foundations | src/StellaOps.Concelier.Models/TASKS.md | DONE (2025-10-11) | Team Models & Merge Leads | FEEDMODELS-SCHEMA-01-002 | Provenance decision rationale field<br>Instructions to work:<br>AdvisoryProvenance now carries `decisionReason` and docs/tests were updated. Connectors and merge tasks should populate the field when applying precedence/freshness/tie-breaker logic; see src/StellaOps.Concelier.Models/PROVENANCE_GUIDELINES.md for usage guidance. |
|
|
||||||
| Sprint 1 | Stabilize In-Progress Foundations | src/StellaOps.Concelier.Models/TASKS.md | DONE (2025-10-11) | Team Models & Merge Leads | FEEDMODELS-SCHEMA-01-003 | Normalized version rules collection<br>Instructions to work:<br>`AffectedPackage.NormalizedVersions` and supporting comparer/docs/tests shipped. Connector owners must emit rule arrays per ./src/FASTER_MODELING_AND_NORMALIZATION.md and report progress via FEEDMERGE-COORD-02-900 so merge/storage backfills can proceed. |
|
|
||||||
| Sprint 1 | Stabilize In-Progress Foundations | src/StellaOps.Concelier.Models/TASKS.md | DONE (2025-10-12) | Team Models & Merge Leads | FEEDMODELS-SCHEMA-02-900 | Range primitives for SemVer/EVR/NEVRA metadata<br>Instructions to work:<br>DONE Read ./AGENTS.md and src/StellaOps.Concelier.Models/AGENTS.md before resuming this stalled effort. Confirm helpers align with the new `NormalizedVersions` representation so connectors finishing in Sprint 2 can emit consistent metadata. |
|
|
||||||
| Sprint 1 | Stabilize In-Progress Foundations | src/StellaOps.Concelier.Normalization/TASKS.md | DONE (2025-10-11) | Team Normalization & Storage Backbone | FEEDNORM-NORM-02-001 | SemVer normalized rule emitter<br>Shared `SemVerRangeRuleBuilder` now outputs primitives + normalized rules per `FASTER_MODELING_AND_NORMALIZATION.md`; CVE/GHSA connectors consuming the API have verified fixtures. |
|
|
||||||
| Sprint 1 | Stabilize In-Progress Foundations | src/StellaOps.Concelier.Storage.Mongo/TASKS.md | DONE (2025-10-11) | Team Normalization & Storage Backbone | FEEDSTORAGE-DATA-02-001 | Normalized range dual-write + backfill<br>AdvisoryStore dual-writes flattened `normalizedVersions` when `concelier.storage.enableSemVerStyle` is set; migration `20251011-semver-style-backfill` updates historical records and docs outline the rollout. |
|
|
||||||
| Sprint 1 | Stabilize In-Progress Foundations | src/StellaOps.Concelier.Storage.Mongo/TASKS.md | DONE (2025-10-11) | Team Normalization & Storage Backbone | FEEDSTORAGE-DATA-02-002 | Provenance decision reason persistence<br>Storage now persists `provenance.decisionReason` for advisories and merge events; tests cover round-trips. |
|
|
||||||
| Sprint 1 | Stabilize In-Progress Foundations | src/StellaOps.Concelier.Storage.Mongo/TASKS.md | DONE (2025-10-11) | Team Normalization & Storage Backbone | FEEDSTORAGE-DATA-02-003 | Normalized versions indexing<br>Bootstrapper seeds compound/sparse indexes for flattened normalized rules and `docs/dev/mongo_indices.md` documents query guidance. |
|
|
||||||
| Sprint 1 | Stabilize In-Progress Foundations | src/StellaOps.Concelier.Storage.Mongo/TASKS.md | DONE (2025-10-11) | Team Normalization & Storage Backbone | FEEDSTORAGE-TESTS-02-004 | Restore AdvisoryStore build after normalized versions refactor<br>Updated constructors/tests keep storage suites passing with the new feature flag defaults. |
|
|
||||||
| Sprint 1 | Stabilize In-Progress Foundations | src/StellaOps.Concelier.WebService/TASKS.md | DONE (2025-10-12) | Team WebService & Authority | FEEDWEB-ENGINE-01-002 | Plumb Authority client resilience options<br>WebService wires `authority.resilience.*` into `AddStellaOpsAuthClient` and adds binding coverage via `AuthorityClientResilienceOptionsAreBound`. |
|
|
||||||
| Sprint 1 | Stabilize In-Progress Foundations | src/StellaOps.Concelier.WebService/TASKS.md | DONE (2025-10-12) | Team WebService & Authority | FEEDWEB-DOCS-01-003 | Author ops guidance for resilience tuning<br>Install/runbooks document connected vs air-gapped resilience profiles and monitoring hooks. |
|
|
||||||
| Sprint 1 | Stabilize In-Progress Foundations | src/StellaOps.Concelier.WebService/TASKS.md | DONE (2025-10-12) | Team WebService & Authority | FEEDWEB-DOCS-01-004 | Document authority bypass logging patterns<br>Operator guides now call out `route/status/subject/clientId/scopes/bypass/remote` audit fields and SIEM triggers. |
|
|
||||||
| Sprint 1 | Stabilize In-Progress Foundations | src/StellaOps.Concelier.WebService/TASKS.md | DONE (2025-10-12) | Team WebService & Authority | FEEDWEB-DOCS-01-005 | Update Concelier operator guide for enforcement cutoff<br>Install guide reiterates the 2025-12-31 cutoff and links audit signals to the rollout checklist. |
|
|
||||||
| Sprint 1 | Stabilize In-Progress Foundations | src/StellaOps.Authority/TASKS.md | DONE (2025-10-11) | Team WebService & Authority | SEC3.HOST | Rate limiter policy binding<br>Authority host now applies configuration-driven fixed windows to `/token`, `/authorize`, and `/internal/*`; integration tests assert 429 + `Retry-After` headers; docs/config samples refreshed for Docs guild diagrams. |
|
|
||||||
| Sprint 1 | Stabilize In-Progress Foundations | src/StellaOps.Authority/TASKS.md | DONE (2025-10-11) | Team WebService & Authority | SEC3.BUILD | Authority rate-limiter follow-through<br>`Security.RateLimiting` now fronts token/authorize/internal limiters; Authority + Configuration matrices (`dotnet test src/StellaOps.Authority/StellaOps.Authority.sln`, `dotnet test src/StellaOps.Configuration.Tests/StellaOps.Configuration.Tests.csproj`) passed on 2025-10-11; awaiting #authority-core broadcast. |
|
|
||||||
| Sprint 1 | Stabilize In-Progress Foundations | src/StellaOps.Authority/TASKS.md | DONE (2025-10-14) | Team Authority Platform & Security Guild | AUTHCORE-BUILD-OPENIDDICT / AUTHCORE-STORAGE-DEVICE-TOKENS / AUTHCORE-BOOTSTRAP-INVITES | Address remaining Authority compile blockers (OpenIddict transaction shim, token device document, bootstrap invite cleanup) so `dotnet build src/StellaOps.Authority.sln` returns success. |
|
|
||||||
| Sprint 1 | Stabilize In-Progress Foundations | src/StellaOps.Authority/StellaOps.Authority.Plugin.Standard/TASKS.md | DONE (2025-10-11) | Team WebService & Authority | PLG6.DOC | Plugin developer guide polish<br>Section 9 now documents rate limiter metadata, config keys, and lockout interplay; YAML samples updated alongside Authority config templates. |
|
|
||||||
| Sprint 1 | Stabilize In-Progress Foundations | src/StellaOps.Concelier.Connector.CertCc/TASKS.md | DONE (2025-10-11) | Team Connector Resumption – CERT/RedHat | FEEDCONN-CERTCC-02-001 | Fetch pipeline & state tracking<br>Summary planner now drives monthly/yearly VINCE fetches, persists pending summaries/notes, and hydrates VINCE detail queue with telemetry.<br>Team instructions: Read ./AGENTS.md and src/StellaOps.Concelier.Connector.CertCc/AGENTS.md. Coordinate daily with Models/Merge leads so new normalizedVersions output and provenance tags stay aligned with ./src/FASTER_MODELING_AND_NORMALIZATION.md. |
|
|
||||||
| Sprint 1 | Stabilize In-Progress Foundations | src/StellaOps.Concelier.Connector.CertCc/TASKS.md | DONE (2025-10-11) | Team Connector Resumption – CERT/RedHat | FEEDCONN-CERTCC-02-002 | VINCE note detail fetcher<br>Summary planner queues VINCE note detail endpoints, persists raw JSON with SHA/ETag metadata, and records retry/backoff metrics. |
|
|
||||||
| Sprint 1 | Stabilize In-Progress Foundations | src/StellaOps.Concelier.Connector.CertCc/TASKS.md | DONE (2025-10-11) | Team Connector Resumption – CERT/RedHat | FEEDCONN-CERTCC-02-003 | DTO & parser implementation<br>Added VINCE DTO aggregate, Markdown→text sanitizer, vendor/status/vulnerability parsers, and parser regression fixture. |
|
|
||||||
| Sprint 1 | Stabilize In-Progress Foundations | src/StellaOps.Concelier.Connector.CertCc/TASKS.md | DONE (2025-10-11) | Team Connector Resumption – CERT/RedHat | FEEDCONN-CERTCC-02-004 | Canonical mapping & range primitives<br>VINCE DTO aggregate flows through `CertCcMapper`, emitting vendor range primitives + normalized version rules that persist via `_advisoryStore`. |
|
|
||||||
| Sprint 1 | Stabilize In-Progress Foundations | src/StellaOps.Concelier.Connector.CertCc/TASKS.md | DONE (2025-10-12) | Team Connector Resumption – CERT/RedHat | FEEDCONN-CERTCC-02-005 | Deterministic fixtures/tests<br>Snapshot harness refreshed 2025-10-12; `certcc-*.snapshot.json` regenerated and regression suite green without UPDATE flag drift. |
|
|
||||||
| Sprint 1 | Stabilize In-Progress Foundations | src/StellaOps.Concelier.Connector.CertCc/TASKS.md | DONE (2025-10-12) | Team Connector Resumption – CERT/RedHat | FEEDCONN-CERTCC-02-006 | Telemetry & documentation<br>`CertCcDiagnostics` publishes summary/detail/parse/map metrics (meter `StellaOps.Concelier.Connector.CertCc`), README documents instruments, and log guidance captured for Ops on 2025-10-12. |
|
|
||||||
| Sprint 1 | Stabilize In-Progress Foundations | src/StellaOps.Concelier.Connector.CertCc/TASKS.md | DONE (2025-10-12) | Team Connector Resumption – CERT/RedHat | FEEDCONN-CERTCC-02-007 | Connector test harness remediation<br>Harness now wires `AddSourceCommon`, resets `FakeTimeProvider`, and passes canned-response regression run dated 2025-10-12. |
|
|
||||||
| Sprint 1 | Stabilize In-Progress Foundations | src/StellaOps.Concelier.Connector.CertCc/TASKS.md | DONE (2025-10-11) | Team Connector Resumption – CERT/RedHat | FEEDCONN-CERTCC-02-008 | Snapshot coverage handoff<br>Fixtures regenerated with normalized ranges + provenance fields on 2025-10-11; QA handoff notes published and merge backfill unblocked. |
|
|
||||||
| Sprint 1 | Stabilize In-Progress Foundations | src/StellaOps.Concelier.Connector.CertCc/TASKS.md | DONE (2025-10-12) | Team Connector Resumption – CERT/RedHat | FEEDCONN-CERTCC-02-012 | Schema sync & snapshot regen follow-up<br>Fixtures regenerated with normalizedVersions + provenance decision reasons; handoff notes updated for Merge backfill 2025-10-12. |
|
|
||||||
| Sprint 1 | Stabilize In-Progress Foundations | src/StellaOps.Concelier.Connector.CertCc/TASKS.md | DONE (2025-10-11) | Team Connector Resumption – CERT/RedHat | FEEDCONN-CERTCC-02-009 | Detail/map reintegration plan<br>Staged reintegration plan published in `src/StellaOps.Concelier.Connector.CertCc/FEEDCONN-CERTCC-02-009_PLAN.md`; coordinates enablement with FEEDCONN-CERTCC-02-004. |
|
|
||||||
| Sprint 1 | Stabilize In-Progress Foundations | src/StellaOps.Concelier.Connector.CertCc/TASKS.md | DONE (2025-10-12) | Team Connector Resumption – CERT/RedHat | FEEDCONN-CERTCC-02-010 | Partial-detail graceful degradation<br>Detail fetch now tolerates 404/403/410 responses and regression tests cover mixed endpoint availability. |
|
|
||||||
| Sprint 1 | Stabilize In-Progress Foundations | src/StellaOps.Concelier.Connector.Distro.RedHat/TASKS.md | DONE (2025-10-11) | Team Connector Resumption – CERT/RedHat | FEEDCONN-REDHAT-02-001 | Fixture validation sweep<br>Instructions to work:<br>Fixtures regenerated post-model-helper rollout; provenance ordering and normalizedVersions scaffolding verified via tests. Conflict resolver deltas logged in src/StellaOps.Concelier.Connector.Distro.RedHat/CONFLICT_RESOLVER_NOTES.md for Sprint 3 consumers. |
|
|
||||||
| Sprint 1 | Stabilize In-Progress Foundations | src/StellaOps.Concelier.Connector.Vndr.Apple/TASKS.md | DONE (2025-10-12) | Team Vendor Apple Specialists | FEEDCONN-APPLE-02-001 | Canonical mapping & range primitives<br>Mapper emits SemVer rules (`scheme=apple:*`); fixtures regenerated with trimmed references + new RSR coverage, update tooling finalized. |
|
|
||||||
| Sprint 1 | Stabilize In-Progress Foundations | src/StellaOps.Concelier.Connector.Vndr.Apple/TASKS.md | DONE (2025-10-11) | Team Vendor Apple Specialists | FEEDCONN-APPLE-02-002 | Deterministic fixtures/tests<br>Sanitized live fixtures + regression snapshots wired into tests; normalized rule coverage asserted. |
|
|
||||||
| Sprint 1 | Stabilize In-Progress Foundations | src/StellaOps.Concelier.Connector.Vndr.Apple/TASKS.md | DONE (2025-10-11) | Team Vendor Apple Specialists | FEEDCONN-APPLE-02-003 | Telemetry & documentation<br>Apple meter metrics wired into Concelier WebService OpenTelemetry configuration; README and fixtures document normalizedVersions coverage. |
|
|
||||||
| Sprint 1 | Stabilize In-Progress Foundations | src/StellaOps.Concelier.Connector.Vndr.Apple/TASKS.md | DONE (2025-10-12) | Team Vendor Apple Specialists | FEEDCONN-APPLE-02-004 | Live HTML regression sweep<br>Sanitised HT125326/HT125328/HT106355/HT214108/HT215500 fixtures recorded and regression tests green on 2025-10-12. |
|
|
||||||
| Sprint 1 | Stabilize In-Progress Foundations | src/StellaOps.Concelier.Connector.Vndr.Apple/TASKS.md | DONE (2025-10-11) | Team Vendor Apple Specialists | FEEDCONN-APPLE-02-005 | Fixture regeneration tooling<br>`UPDATE_APPLE_FIXTURES=1` flow fetches & rewrites fixtures; README documents usage.<br>Instructions to work:<br>DONE Read ./AGENTS.md and src/StellaOps.Concelier.Connector.Vndr.Apple/AGENTS.md. Resume stalled tasks, ensuring normalizedVersions output and fixtures align with ./src/FASTER_MODELING_AND_NORMALIZATION.md before handing data to the conflict sprint. |
|
|
||||||
| Sprint 1 | Stabilize In-Progress Foundations | src/StellaOps.Concelier.Connector.Ghsa/TASKS.md | DONE (2025-10-12) | Team Connector Normalized Versions Rollout | FEEDCONN-GHSA-02-001 | GHSA normalized versions & provenance<br>Team instructions: Read ./AGENTS.md and each module's AGENTS file. Adopt the `NormalizedVersions` array emitted by the models sprint, wiring provenance `decisionReason` where merge overrides occur. Follow ./src/FASTER_MODELING_AND_NORMALIZATION.md; report via src/StellaOps.Concelier.Merge/TASKS.md (FEEDMERGE-COORD-02-900). Progress 2025-10-11: GHSA/OSV emit normalized arrays with refreshed fixtures; CVE mapper now surfaces SemVer normalized ranges; NVD/KEV adoption pending; outstanding follow-ups include FEEDSTORAGE-DATA-02-001, FEEDMERGE-ENGINE-02-002, and rolling `tools/FixtureUpdater` updates across connectors. |
|
|
||||||
| Sprint 1 | Stabilize In-Progress Foundations | src/StellaOps.Concelier.Connector.Osv/TASKS.md | DONE (2025-10-12) | Team Connector Normalized Versions Rollout | FEEDCONN-OSV-02-003 | OSV normalized versions & freshness |
|
|
||||||
| Sprint 1 | Stabilize In-Progress Foundations | src/StellaOps.Concelier.Connector.Nvd/TASKS.md | DONE (2025-10-12) | Team Connector Normalized Versions Rollout | FEEDCONN-NVD-02-002 | NVD normalized versions & timestamps |
|
|
||||||
| Sprint 1 | Stabilize In-Progress Foundations | src/StellaOps.Concelier.Connector.Cve/TASKS.md | DONE (2025-10-12) | Team Connector Normalized Versions Rollout | FEEDCONN-CVE-02-003 | CVE normalized versions uplift |
|
|
||||||
| Sprint 1 | Stabilize In-Progress Foundations | src/StellaOps.Concelier.Connector.Kev/TASKS.md | DONE (2025-10-12) | Team Connector Normalized Versions Rollout | FEEDCONN-KEV-02-003 | KEV normalized versions propagation |
|
|
||||||
| Sprint 1 | Stabilize In-Progress Foundations | src/StellaOps.Concelier.Connector.Osv/TASKS.md | DONE (2025-10-12) | Team Connector Normalized Versions Rollout | FEEDCONN-OSV-04-003 | OSV parity fixture refresh |
|
|
||||||
| Sprint 1 | Stabilize In-Progress Foundations | src/StellaOps.Concelier.WebService/TASKS.md | DONE (2025-10-10) | Team WebService & Authority | FEEDWEB-DOCS-01-001 | Document authority toggle & scope requirements<br>Quickstart carries toggle/scope guidance pending docs guild review (no change this sprint). |
|
|
||||||
| Sprint 1 | Stabilize In-Progress Foundations | src/StellaOps.Concelier.WebService/TASKS.md | DONE (2025-10-12) | Team WebService & Authority | FEEDWEB-DOCS-01-003 | Author ops guidance for resilience tuning<br>Operator docs now outline connected vs air-gapped resilience profiles and monitoring cues. |
|
|
||||||
| Sprint 1 | Stabilize In-Progress Foundations | src/StellaOps.Concelier.WebService/TASKS.md | DONE (2025-10-12) | Team WebService & Authority | FEEDWEB-DOCS-01-004 | Document authority bypass logging patterns<br>Audit logging guidance highlights `route/status/subject/clientId/scopes/bypass/remote` fields and SIEM alerts. |
|
|
||||||
| Sprint 1 | Stabilize In-Progress Foundations | src/StellaOps.Concelier.WebService/TASKS.md | DONE (2025-10-12) | Team WebService & Authority | FEEDWEB-DOCS-01-005 | Update Concelier operator guide for enforcement cutoff<br>Install guide reiterates the 2025-12-31 cutoff and ties audit signals to rollout checks. |
|
|
||||||
| Sprint 1 | Stabilize In-Progress Foundations | src/StellaOps.Concelier.WebService/TASKS.md | DONE (2025-10-11) | Team WebService & Authority | FEEDWEB-OPS-01-006 | Rename plugin drop directory to namespaced path<br>Build outputs, tests, and docs now target `StellaOps.Concelier.PluginBinaries`/`StellaOps.Authority.PluginBinaries`. |
|
|
||||||
| Sprint 1 | Stabilize In-Progress Foundations | src/StellaOps.Concelier.WebService/TASKS.md | DONE (2025-10-11) | Team WebService & Authority | FEEDWEB-OPS-01-007 | Authority resilience adoption<br>Deployment docs and CLI notes explain the LIB5 resilience knobs for rollout.<br>Instructions to work:<br>DONE Read ./AGENTS.md and src/StellaOps.Concelier.WebService/AGENTS.md. These items were mid-flight; resume implementation ensuring docs/operators receive timely updates. |
|
|
||||||
| Sprint 1 | Stabilize In-Progress Foundations | src/StellaOps.Authority/TASKS.md | DONE (2025-10-11) | Team Authority Platform & Security Guild | AUTHCORE-ENGINE-01-001 | CORE8.RL — Rate limiter plumbing validated; integration tests green and docs handoff recorded for middleware ordering + Retry-After headers (see `docs/dev/authority-rate-limit-tuning-outline.md` for continuing guidance). |
|
|
||||||
| Sprint 1 | Stabilize In-Progress Foundations | src/StellaOps.Cryptography/TASKS.md | DONE (2025-10-11) | Team Authority Platform & Security Guild | AUTHCRYPTO-ENGINE-01-001 | SEC3.A — Shared metadata resolver confirmed via host test run; SEC3.B now unblocked for tuning guidance (outline captured in `docs/dev/authority-rate-limit-tuning-outline.md`). |
|
|
||||||
| Sprint 1 | Stabilize In-Progress Foundations | src/StellaOps.Cryptography/TASKS.md | DONE (2025-10-13) | Team Authority Platform & Security Guild | AUTHSEC-DOCS-01-002 | SEC3.B — Published `docs/security/rate-limits.md` with tuning matrix, alert thresholds, and lockout interplay guidance; Docs guild can lift copy into plugin guide. |
|
|
||||||
| Sprint 1 | Stabilize In-Progress Foundations | src/StellaOps.Cryptography/TASKS.md | DONE (2025-10-14) | Team Authority Platform & Security Guild | AUTHSEC-CRYPTO-02-001 | SEC5.B1 — Introduce libsodium signing provider and parity tests to unblock CLI verification enhancements. |
|
|
||||||
| Sprint 1 | Bootstrap & Replay Hardening | src/StellaOps.Cryptography/TASKS.md | DONE (2025-10-14) | Security Guild | AUTHSEC-CRYPTO-02-004 | SEC5.D/E — Finish bootstrap invite lifecycle (API/store/cleanup) and token device heuristics; build currently red due to pending handler integration. |
|
|
||||||
| Sprint 1 | Developer Tooling | src/StellaOps.Cli/TASKS.md | DONE (2025-10-15) | DevEx/CLI | AUTHCLI-DIAG-01-001 | Surface password policy diagnostics in CLI startup/output so operators see weakened overrides immediately.<br>CLI now loads Authority plug-ins at startup, logs weakened password policies (length/complexity), and regression coverage lives in `StellaOps.Cli.Tests/Services/AuthorityDiagnosticsReporterTests`. |
|
|
||||||
| Sprint 1 | Stabilize In-Progress Foundations | src/StellaOps.Authority/StellaOps.Authority.Plugin.Standard/TASKS.md | DONE (2025-10-11) | Team Authority Platform & Security Guild | AUTHPLUG-DOCS-01-001 | PLG6.DOC — Developer guide copy + diagrams merged 2025-10-11; limiter guidance incorporated and handed to Docs guild for asset export. |
|
|
||||||
| Sprint 2 | Connector & Data Implementation Wave | src/StellaOps.Concelier.Normalization/TASKS.md | DONE (2025-10-12) | Team Normalization & Storage Backbone | FEEDNORM-NORM-02-001 | SemVer normalized rule emitter<br>`SemVerRangeRuleBuilder` shipped 2025-10-12 with comparator/`||` support and fixtures aligning to `FASTER_MODELING_AND_NORMALIZATION.md`. |
|
|
||||||
| Sprint 2 | Connector & Data Implementation Wave | src/StellaOps.Concelier.Storage.Mongo/TASKS.md | DONE (2025-10-11) | Team Normalization & Storage Backbone | FEEDSTORAGE-DATA-02-001 | Normalized range dual-write + backfill |
|
|
||||||
| Sprint 2 | Connector & Data Implementation Wave | src/StellaOps.Concelier.Storage.Mongo/TASKS.md | DONE (2025-10-11) | Team Normalization & Storage Backbone | FEEDSTORAGE-DATA-02-002 | Provenance decision reason persistence |
|
|
||||||
| Sprint 2 | Connector & Data Implementation Wave | src/StellaOps.Concelier.Storage.Mongo/TASKS.md | DONE (2025-10-11) | Team Normalization & Storage Backbone | FEEDSTORAGE-DATA-02-003 | Normalized versions indexing<br>Indexes seeded + docs updated 2025-10-11 to cover flattened normalized rules for connector adoption. |
|
|
||||||
| Sprint 2 | Connector & Data Implementation Wave | src/StellaOps.Concelier.Merge/TASKS.md | DONE (2025-10-11) | Team Normalization & Storage Backbone | FEEDMERGE-ENGINE-02-002 | Normalized versions union & dedupe<br>Affected package resolver unions/dedupes normalized rules, stamps merge provenance with `decisionReason`, and tests cover the rollout. |
|
|
||||||
| Sprint 2 | Connector & Data Implementation Wave | src/StellaOps.Concelier.Connector.Ghsa/TASKS.md | DONE (2025-10-11) | Team Connector Expansion – GHSA/NVD/OSV | FEEDCONN-GHSA-02-001 | GHSA normalized versions & provenance |
|
|
||||||
| Sprint 2 | Connector & Data Implementation Wave | src/StellaOps.Concelier.Connector.Ghsa/TASKS.md | DONE (2025-10-11) | Team Connector Expansion – GHSA/NVD/OSV | FEEDCONN-GHSA-02-004 | GHSA credits & ecosystem severity mapping |
|
|
||||||
| Sprint 2 | Connector & Data Implementation Wave | src/StellaOps.Concelier.Connector.Ghsa/TASKS.md | DONE (2025-10-12) | Team Connector Expansion – GHSA/NVD/OSV | FEEDCONN-GHSA-02-005 | GitHub quota monitoring & retries |
|
|
||||||
| Sprint 2 | Connector & Data Implementation Wave | src/StellaOps.Concelier.Connector.Ghsa/TASKS.md | DONE (2025-10-12) | Team Connector Expansion – GHSA/NVD/OSV | FEEDCONN-GHSA-02-006 | Production credential & scheduler rollout |
|
|
||||||
| Sprint 2 | Connector & Data Implementation Wave | src/StellaOps.Concelier.Connector.Ghsa/TASKS.md | DONE (2025-10-12) | Team Connector Expansion – GHSA/NVD/OSV | FEEDCONN-GHSA-02-007 | Credit parity regression fixtures |
|
|
||||||
| Sprint 2 | Connector & Data Implementation Wave | src/StellaOps.Concelier.Connector.Nvd/TASKS.md | DONE (2025-10-11) | Team Connector Expansion – GHSA/NVD/OSV | FEEDCONN-NVD-02-002 | NVD normalized versions & timestamps |
|
|
||||||
| Sprint 2 | Connector & Data Implementation Wave | src/StellaOps.Concelier.Connector.Nvd/TASKS.md | DONE (2025-10-11) | Team Connector Expansion – GHSA/NVD/OSV | FEEDCONN-NVD-02-004 | NVD CVSS & CWE precedence payloads |
|
|
||||||
| Sprint 2 | Connector & Data Implementation Wave | src/StellaOps.Concelier.Connector.Nvd/TASKS.md | DONE (2025-10-12) | Team Connector Expansion – GHSA/NVD/OSV | FEEDCONN-NVD-02-005 | NVD merge/export parity regression |
|
|
||||||
| Sprint 2 | Connector & Data Implementation Wave | src/StellaOps.Concelier.Connector.Osv/TASKS.md | DONE (2025-10-11) | Team Connector Expansion – GHSA/NVD/OSV | FEEDCONN-OSV-02-003 | OSV normalized versions & freshness |
|
|
||||||
| Sprint 2 | Connector & Data Implementation Wave | src/StellaOps.Concelier.Connector.Osv/TASKS.md | DONE (2025-10-11) | Team Connector Expansion – GHSA/NVD/OSV | FEEDCONN-OSV-02-004 | OSV references & credits alignment |
|
|
||||||
| Sprint 2 | Connector & Data Implementation Wave | src/StellaOps.Concelier.Connector.Osv/TASKS.md | DONE (2025-10-12) | Team Connector Expansion – GHSA/NVD/OSV | FEEDCONN-OSV-02-005 | Fixture updater workflow<br>Resolved 2025-10-12: OSV mapper now derives canonical PURLs for Go + scoped npm packages when raw payloads omit `purl`; conflict fixtures unchanged for invalid npm names. Verified via `dotnet test src/StellaOps.Concelier.Connector.Osv.Tests`, `src/StellaOps.Concelier.Connector.Ghsa.Tests`, `src/StellaOps.Concelier.Connector.Nvd.Tests`, and backbone normalization/storage suites. |
|
|
||||||
| Sprint 2 | Connector & Data Implementation Wave | src/StellaOps.Concelier.Connector.Acsc/TASKS.md | DONE (2025-10-12) | Team Connector Expansion – Regional & Vendor Feeds | FEEDCONN-ACSC-02-001 … 02-008 | Fetch→parse→map pipeline, fixtures, diagnostics, and README finished 2025-10-12; downstream export parity captured via FEEDEXPORT-JSON-04-001 / FEEDEXPORT-TRIVY-04-001 (completed). |
|
|
||||||
| Sprint 2 | Connector & Data Implementation Wave | src/StellaOps.Concelier.Connector.Cccs/TASKS.md | DONE (2025-10-16) | Team Connector Expansion – Regional & Vendor Feeds | FEEDCONN-CCCS-02-001 … 02-008 | Observability meter, historical harvest plan, and DOM sanitizer refinements wrapped; ops notes live under `docs/ops/concelier-cccs-operations.md` with fixtures validating EN/FR list handling. |
|
|
||||||
| Sprint 2 | Connector & Data Implementation Wave | src/StellaOps.Concelier.Connector.CertBund/TASKS.md | DONE (2025-10-15) | Team Connector Expansion – Regional & Vendor Feeds | FEEDCONN-CERTBUND-02-001 … 02-008 | Telemetry/docs (02-006) and history/locale sweep (02-007) completed alongside pipeline; runbook `docs/ops/concelier-certbund-operations.md` captures locale guidance and offline packaging. |
|
|
||||||
| Sprint 2 | Connector & Data Implementation Wave | src/StellaOps.Concelier.Connector.Kisa/TASKS.md | DONE (2025-10-14) | Team Connector Expansion – Regional & Vendor Feeds | FEEDCONN-KISA-02-001 … 02-007 | Connector, tests, and telemetry/docs (02-006) finalized; localisation notes in `docs/dev/kisa_connector_notes.md` complete rollout. |
|
|
||||||
| Sprint 2 | Connector & Data Implementation Wave | src/StellaOps.Concelier.Connector.Ru.Bdu/TASKS.md | DONE (2025-10-14) | Team Connector Expansion – Regional & Vendor Feeds | FEEDCONN-RUBDU-02-001 … 02-008 | Fetch/parser/mapper refinements, regression fixtures, telemetry/docs, access options, and trusted root packaging all landed; README documents offline access strategy. |
|
|
||||||
| Sprint 2 | Connector & Data Implementation Wave | src/StellaOps.Concelier.Connector.Ru.Nkcki/TASKS.md | DONE (2025-10-13) | Team Connector Expansion – Regional & Vendor Feeds | FEEDCONN-NKCKI-02-001 … 02-008 | Listing fetch, parser, mapper, fixtures, telemetry/docs, and archive plan finished; Mongo2Go/libcrypto dependency resolved via bundled OpenSSL noted in ops guide. |
|
|
||||||
| Sprint 2 | Connector & Data Implementation Wave | src/StellaOps.Concelier.Connector.Ics.Cisa/TASKS.md | DONE (2025-10-16) | Team Connector Expansion – Regional & Vendor Feeds | FEEDCONN-ICSCISA-02-001 … 02-011 | Feed parser attachment fixes, SemVer exact values, regression suites, telemetry/docs updates, and handover complete; ops runbook now details attachment verification + proxy usage. |
|
|
||||||
| Sprint 2 | Connector & Data Implementation Wave | src/StellaOps.Concelier.Connector.Vndr.Cisco/TASKS.md | DONE (2025-10-14) | Team Connector Expansion – Regional & Vendor Feeds | FEEDCONN-CISCO-02-001 … 02-007 | OAuth fetch pipeline, DTO/mapping, tests, and telemetry/docs shipped; monitoring/export integration follow-ups recorded in Ops docs and exporter backlog (completed). |
|
|
||||||
| Sprint 2 | Connector & Data Implementation Wave | src/StellaOps.Concelier.Connector.Vndr.Msrc/TASKS.md | DONE (2025-10-15) | Team Connector Expansion – Regional & Vendor Feeds | FEEDCONN-MSRC-02-001 … 02-008 | Azure AD onboarding (02-008) unblocked fetch/parse/map pipeline; fixtures, telemetry/docs, and Offline Kit guidance published in `docs/ops/concelier-msrc-operations.md`. |
|
|
||||||
| Sprint 2 | Connector & Data Implementation Wave | src/StellaOps.Concelier.Connector.Cve/TASKS.md | DONE (2025-10-15) | Team Connector Support & Monitoring | FEEDCONN-CVE-02-001 … 02-002 | CVE data-source selection, fetch pipeline, and docs landed 2025-10-10. 2025-10-15: smoke verified using the seeded mirror fallback; connector now logs a warning and pulls from `seed-data/cve/` until live CVE Services credentials arrive. |
|
|
||||||
| Sprint 2 | Connector & Data Implementation Wave | src/StellaOps.Concelier.Connector.Kev/TASKS.md | DONE (2025-10-12) | Team Connector Support & Monitoring | FEEDCONN-KEV-02-001 … 02-002 | KEV catalog ingestion, fixtures, telemetry, and schema validation completed 2025-10-12; ops dashboard published. |
|
|
||||||
| Sprint 2 | Connector & Data Implementation Wave | docs/TASKS.md | DONE (2025-10-11) | Team Docs & Knowledge Base | FEEDDOCS-DOCS-01-001 | Canonical schema docs refresh<br>Updated canonical schema + provenance guides with SemVer style, normalized version rules, decision reason change log, and migration notes. |
|
|
||||||
| Sprint 2 | Connector & Data Implementation Wave | docs/TASKS.md | DONE (2025-10-11) | Team Docs & Knowledge Base | FEEDDOCS-DOCS-02-001 | Concelier-SemVer Playbook<br>Published merge playbook covering mapper patterns, dedupe flow, indexes, and rollout checklist. |
|
|
||||||
| Sprint 2 | Connector & Data Implementation Wave | docs/TASKS.md | DONE (2025-10-11) | Team Docs & Knowledge Base | FEEDDOCS-DOCS-02-002 | Normalized versions query guide<br>Delivered Mongo index/query addendum with `$unwind` recipes, dedupe checks, and operational checklist.<br>Instructions to work:<br>DONE Read ./AGENTS.md and docs/AGENTS.md. Document every schema/index/query change produced in Sprint 1-2 leveraging ./src/FASTER_MODELING_AND_NORMALIZATION.md. |
|
|
||||||
| Sprint 3 | Conflict Resolution Integration & Communications | src/StellaOps.Concelier.Core/TASKS.md | DONE (2025-10-11) | Team Core Engine & Storage Analytics | FEEDCORE-ENGINE-03-001 | Canonical merger implementation<br>`CanonicalMerger` ships with freshness/tie-breaker logic, provenance, and unit coverage feeding Merge. |
|
|
||||||
| Sprint 3 | Conflict Resolution Integration & Communications | src/StellaOps.Concelier.Core/TASKS.md | DONE (2025-10-11) | Team Core Engine & Storage Analytics | FEEDCORE-ENGINE-03-002 | Field precedence and tie-breaker map<br>Field precedence tables and tie-breaker metrics wired into the canonical merge flow; docs/tests updated.<br>Instructions to work:<br>Read ./AGENTS.md and core AGENTS. Implement the conflict resolver exactly as specified in ./src/DEDUP_CONFLICTS_RESOLUTION_ALGO.md, coordinating with Merge and Storage teammates. |
|
|
||||||
| Sprint 3 | Conflict Resolution Integration & Communications | src/StellaOps.Concelier.Storage.Mongo/TASKS.md | DONE (2025-10-11) | Team Core Engine & Storage Analytics | FEEDSTORAGE-DATA-03-001 | Merge event provenance audit prep<br>Merge events now persist `fieldDecisions` and analytics-ready provenance snapshots. |
|
|
||||||
| Sprint 3 | Conflict Resolution Integration & Communications | src/StellaOps.Concelier.Storage.Mongo/TASKS.md | DONE (2025-10-11) | Team Core Engine & Storage Analytics | FEEDSTORAGE-DATA-02-001 | Normalized range dual-write + backfill<br>Dual-write/backfill flag delivered; migration + options validated in tests. |
|
|
||||||
| Sprint 3 | Conflict Resolution Integration & Communications | src/StellaOps.Concelier.Storage.Mongo/TASKS.md | DONE (2025-10-11) | Team Core Engine & Storage Analytics | FEEDSTORAGE-TESTS-02-004 | Restore AdvisoryStore build after normalized versions refactor<br>Storage tests adjusted for normalized versions/decision reasons.<br>Instructions to work:<br>Read ./AGENTS.md and storage AGENTS. Extend merge events with decision reasons and analytics views to support the conflict rules, and deliver the dual-write/backfill for `NormalizedVersions` + `decisionReason` so connectors can roll out safely. |
|
|
||||||
| Sprint 3 | Conflict Resolution Integration & Communications | src/StellaOps.Concelier.Merge/TASKS.md | DONE (2025-10-11) | Team Merge & QA Enforcement | FEEDMERGE-ENGINE-04-001 | GHSA/NVD/OSV conflict rules<br>Merge pipeline consumes `CanonicalMerger` output prior to precedence merge. |
|
|
||||||
| Sprint 3 | Conflict Resolution Integration & Communications | src/StellaOps.Concelier.Merge/TASKS.md | DONE (2025-10-11) | Team Merge & QA Enforcement | FEEDMERGE-ENGINE-04-002 | Override metrics instrumentation<br>Merge events capture per-field decisions; counters/logs align with conflict rules. |
|
|
||||||
| Sprint 3 | Conflict Resolution Integration & Communications | src/StellaOps.Concelier.Merge/TASKS.md | DONE (2025-10-11) | Team Merge & QA Enforcement | FEEDMERGE-ENGINE-04-003 | Reference & credit union pipeline<br>Canonical merge preserves unions with updated tests. |
|
|
||||||
| Sprint 3 | Conflict Resolution Integration & Communications | src/StellaOps.Concelier.Merge/TASKS.md | DONE (2025-10-11) | Team Merge & QA Enforcement | FEEDMERGE-QA-04-001 | End-to-end conflict regression suite<br>Added regression tests (`AdvisoryMergeServiceTests`) covering canonical + precedence flow.<br>Instructions to work:<br>Read ./AGENTS.md and merge AGENTS. Integrate the canonical merger, instrument metrics, and deliver comprehensive regression tests following ./src/DEDUP_CONFLICTS_RESOLUTION_ALGO.md. |
|
|
||||||
| Sprint 3 | Conflict Resolution Integration & Communications | src/StellaOps.Concelier.Connector.Ghsa/TASKS.md | DONE (2025-10-12) | Team Connector Regression Fixtures | FEEDCONN-GHSA-04-002 | GHSA conflict regression fixtures |
|
|
||||||
| Sprint 3 | Conflict Resolution Integration & Communications | src/StellaOps.Concelier.Connector.Nvd/TASKS.md | DONE (2025-10-12) | Team Connector Regression Fixtures | FEEDCONN-NVD-04-002 | NVD conflict regression fixtures |
|
|
||||||
| Sprint 3 | Conflict Resolution Integration & Communications | src/StellaOps.Concelier.Connector.Osv/TASKS.md | DONE (2025-10-12) | Team Connector Regression Fixtures | FEEDCONN-OSV-04-002 | OSV conflict regression fixtures<br>Instructions to work:<br>Read ./AGENTS.md and module AGENTS. Produce fixture triples supporting the precedence/tie-breaker paths defined in ./src/DEDUP_CONFLICTS_RESOLUTION_ALGO.md and hand them to Merge QA. |
|
|
||||||
| Sprint 3 | Conflict Resolution Integration & Communications | docs/TASKS.md | DONE (2025-10-11) | Team Documentation Guild – Conflict Guidance | FEEDDOCS-DOCS-05-001 | Concelier Conflict Rules<br>Runbook published at `docs/ops/concelier-conflict-resolution.md`; metrics/log guidance aligned with Sprint 3 merge counters. |
|
|
||||||
| Sprint 3 | Conflict Resolution Integration & Communications | docs/TASKS.md | DONE (2025-10-16) | Team Documentation Guild – Conflict Guidance | FEEDDOCS-DOCS-05-002 | Conflict runbook ops rollout<br>Ops review completed, alert thresholds applied, and change log appended in `docs/ops/concelier-conflict-resolution.md`; task closed after connector signals verified. |
|
|
||||||
| Sprint 4 | Schema Parity & Freshness Alignment | src/StellaOps.Concelier.Models/TASKS.md | DONE (2025-10-15) | Team Models & Merge Leads | FEEDMODELS-SCHEMA-04-001 | Advisory schema parity (description/CWE/canonical metric)<br>Extend `Advisory` and related records with description text, CWE collection, and canonical metric pointer; refresh validation + serializer determinism tests. |
|
|
||||||
| Sprint 4 | Schema Parity & Freshness Alignment | src/StellaOps.Concelier.Core/TASKS.md | DONE (2025-10-15) | Team Core Engine & Storage Analytics | FEEDCORE-ENGINE-04-003 | Canonical merger parity for new fields<br>Teach `CanonicalMerger` to populate description, CWEResults, and canonical metric pointer with provenance + regression coverage. |
|
|
||||||
| Sprint 4 | Schema Parity & Freshness Alignment | src/StellaOps.Concelier.Core/TASKS.md | DONE (2025-10-15) | Team Core Engine & Storage Analytics | FEEDCORE-ENGINE-04-004 | Reference normalization & freshness instrumentation cleanup<br>Implement URL normalization for reference dedupe, align freshness-sensitive instrumentation, and add analytics tests. |
|
|
||||||
| Sprint 4 | Schema Parity & Freshness Alignment | src/StellaOps.Concelier.Merge/TASKS.md | DONE (2025-10-15) | Team Merge & QA Enforcement | FEEDMERGE-ENGINE-04-004 | Merge pipeline parity for new advisory fields<br>Ensure merge service + merge events surface description/CWE/canonical metric decisions with updated metrics/tests. |
|
|
||||||
| Sprint 4 | Schema Parity & Freshness Alignment | src/StellaOps.Concelier.Merge/TASKS.md | DONE (2025-10-15) | Team Merge & QA Enforcement | FEEDMERGE-ENGINE-04-005 | Connector coordination for new advisory fields<br>GHSA/NVD/OSV connectors now ship description, CWE, and canonical metric data with refreshed fixtures; merge coordination log updated and exporters notified. |
|
|
||||||
| Sprint 4 | Schema Parity & Freshness Alignment | src/StellaOps.Concelier.Exporter.Json/TASKS.md | DONE (2025-10-15) | Team Exporters – JSON | FEEDEXPORT-JSON-04-001 | Surface new advisory fields in JSON exporter<br>Update schemas/offline bundle + fixtures once model/core parity lands.<br>2025-10-15: `dotnet test src/StellaOps.Concelier.Exporter.Json.Tests` validated canonical metric/CWE emission. |
|
|
||||||
| Sprint 4 | Schema Parity & Freshness Alignment | src/StellaOps.Concelier.Exporter.TrivyDb/TASKS.md | DONE (2025-10-15) | Team Exporters – Trivy DB | FEEDEXPORT-TRIVY-04-001 | Propagate new advisory fields into Trivy DB package<br>Extend Bolt builder, metadata, and regression tests for the expanded schema.<br>2025-10-15: `dotnet test src/StellaOps.Concelier.Exporter.TrivyDb.Tests` confirmed canonical metric/CWE propagation. |
|
|
||||||
| Sprint 4 | Schema Parity & Freshness Alignment | src/StellaOps.Concelier.Connector.Ghsa/TASKS.md | DONE (2025-10-16) | Team Connector Regression Fixtures | FEEDCONN-GHSA-04-004 | Harden CVSS fallback so canonical metric ids persist when GitHub omits vectors; extend fixtures and document severity precedence hand-off to Merge. |
|
|
||||||
| Sprint 4 | Schema Parity & Freshness Alignment | src/StellaOps.Concelier.Connector.Osv/TASKS.md | DONE (2025-10-16) | Team Connector Expansion – GHSA/NVD/OSV | FEEDCONN-OSV-04-005 | Map OSV advisories lacking CVSS vectors to canonical metric ids/notes and document CWE provenance quirks; schedule parity fixture updates. |
|
|
||||||
| Sprint 5 | Excititor Core Foundations | src/StellaOps.Excititor.Core/TASKS.md | DONE (2025-10-15) | Team Excititor Core & Policy | EXCITITOR-CORE-01-001 | Stand up canonical VEX claim/consensus records with deterministic serializers so Storage/Exports share a stable contract. |
|
|
||||||
| Sprint 5 | Excititor Core Foundations | src/StellaOps.Excititor.Core/TASKS.md | DONE (2025-10-15) | Team Excititor Core & Policy | EXCITITOR-CORE-01-002 | Implement trust-weighted consensus resolver with baseline policy weights, justification gates, telemetry output, and majority/tie handling. |
|
|
||||||
| Sprint 5 | Excititor Core Foundations | src/StellaOps.Excititor.Core/TASKS.md | DONE (2025-10-15) | Team Excititor Core & Policy | EXCITITOR-CORE-01-003 | Publish shared connector/exporter/attestation abstractions and deterministic query signature utilities for cache/attestation workflows. |
|
|
||||||
| Sprint 5 | Excititor Core Foundations | src/StellaOps.Excititor.Policy/TASKS.md | DONE (2025-10-15) | Team Excititor Policy | EXCITITOR-POLICY-01-001 | Established policy options & snapshot provider covering baseline weights/overrides. |
|
|
||||||
| Sprint 5 | Excititor Core Foundations | src/StellaOps.Excititor.Policy/TASKS.md | DONE (2025-10-15) | Team Excititor Policy | EXCITITOR-POLICY-01-002 | Policy evaluator now feeds consensus resolver with immutable snapshots. |
|
|
||||||
| Sprint 5 | Excititor Core Foundations | src/StellaOps.Excititor.Policy/TASKS.md | DONE (2025-10-16) | Team Excititor Policy | EXCITITOR-POLICY-01-003 | Author policy diagnostics, CLI/WebService surfacing, and documentation updates. |
|
|
||||||
| Sprint 5 | Excititor Core Foundations | src/StellaOps.Excititor.Policy/TASKS.md | DONE (2025-10-16) | Team Excititor Policy | EXCITITOR-POLICY-01-004 | Implement YAML/JSON schema validation and deterministic diagnostics for operator bundles. |
|
|
||||||
| Sprint 5 | Excititor Core Foundations | src/StellaOps.Excititor.Policy/TASKS.md | DONE (2025-10-16) | Team Excititor Policy | EXCITITOR-POLICY-01-005 | Add policy change tracking, snapshot digests, and telemetry/logging hooks. |
|
|
||||||
| Sprint 5 | Excititor Core Foundations | src/StellaOps.Excititor.Storage.Mongo/TASKS.md | DONE (2025-10-15) | Team Excititor Storage | EXCITITOR-STORAGE-01-001 | Mongo mapping registry plus raw/export entities and DI extensions in place. |
|
|
||||||
| Sprint 5 | Excititor Core Foundations | src/StellaOps.Excititor.Storage.Mongo/TASKS.md | DONE (2025-10-16) | Team Excititor Storage | EXCITITOR-STORAGE-01-004 | Build provider/consensus/cache class maps and related collections. |
|
|
||||||
| Sprint 5 | Excititor Core Foundations | src/StellaOps.Excititor.Export/TASKS.md | DONE (2025-10-15) | Team Excititor Export | EXCITITOR-EXPORT-01-001 | Export engine delivers cache lookup, manifest creation, and policy integration. |
|
|
||||||
| Sprint 5 | Excititor Core Foundations | src/StellaOps.Excititor.Export/TASKS.md | DONE (2025-10-17) | Team Excititor Export | EXCITITOR-EXPORT-01-004 | Connect export engine to attestation client and persist Rekor metadata. |
|
|
||||||
| Sprint 5 | Excititor Core Foundations | src/StellaOps.Excititor.Attestation/TASKS.md | DONE (2025-10-16) | Team Excititor Attestation | EXCITITOR-ATTEST-01-001 | Implement in-toto predicate + DSSE builder providing envelopes for export attestation. |
|
|
||||||
| Sprint 5 | Excititor Core Foundations | src/StellaOps.Excititor.Connectors.Abstractions/TASKS.md | DONE (2025-10-17) | Team Excititor Connectors | EXCITITOR-CONN-ABS-01-001 | Deliver shared connector context/base classes so provider plug-ins can be activated via WebService/Worker. |
|
|
||||||
| Sprint 5 | Excititor Core Foundations | src/StellaOps.Excititor.WebService/TASKS.md | DONE (2025-10-17) | Team Excititor WebService | EXCITITOR-WEB-01-001 | Scaffold minimal API host, DI, and `/excititor/status` endpoint integrating policy, storage, export, and attestation services. |
|
|
||||||
| Sprint 6 | Excititor Ingest & Formats | src/StellaOps.Excititor.Worker/TASKS.md | DONE (2025-10-17) | Team Excititor Worker | EXCITITOR-WORKER-01-001 | Create Worker host with provider scheduling and logging to drive recurring pulls/reconciliation. |
|
|
||||||
| Sprint 6 | Excititor Ingest & Formats | src/StellaOps.Excititor.Formats.CSAF/TASKS.md | DONE (2025-10-17) | Team Excititor Formats | EXCITITOR-FMT-CSAF-01-001 | Implement CSAF normalizer foundation translating provider documents into `VexClaim` entries. |
|
|
||||||
| Sprint 6 | Excititor Ingest & Formats | src/StellaOps.Excititor.Formats.CycloneDX/TASKS.md | DONE (2025-10-17) | Team Excititor Formats | EXCITITOR-FMT-CYCLONE-01-001 | Implement CycloneDX VEX normalizer capturing `analysis` state and component references. |
|
|
||||||
| Sprint 6 | Excititor Ingest & Formats | src/StellaOps.Excititor.Formats.OpenVEX/TASKS.md | DONE (2025-10-17) | Team Excititor Formats | EXCITITOR-FMT-OPENVEX-01-001 | Implement OpenVEX normalizer to ingest attestations into canonical claims with provenance. |
|
|
||||||
| Sprint 6 | Excititor Ingest & Formats | src/StellaOps.Excititor.Connectors.RedHat.CSAF/TASKS.md | DONE (2025-10-17) | Team Excititor Connectors – Red Hat | EXCITITOR-CONN-RH-01-001 | Ship Red Hat CSAF provider metadata discovery enabling incremental pulls. |
|
|
||||||
| Sprint 6 | Excititor Ingest & Formats | src/StellaOps.Excititor.Connectors.RedHat.CSAF/TASKS.md | DONE (2025-10-17) | Team Excititor Connectors – Red Hat | EXCITITOR-CONN-RH-01-002 | Fetch CSAF windows with ETag handling, resume tokens, quarantine on schema errors, and persist raw docs. |
|
|
||||||
| Sprint 6 | Excititor Ingest & Formats | src/StellaOps.Excititor.Connectors.RedHat.CSAF/TASKS.md | DONE (2025-10-17) | Team Excititor Connectors – Red Hat | EXCITITOR-CONN-RH-01-003 | Populate provider trust overrides (cosign issuer, identity regex) and provenance hints for policy evaluation/logging. |
|
|
||||||
| Sprint 6 | Excititor Ingest & Formats | src/StellaOps.Excititor.Connectors.RedHat.CSAF/TASKS.md | DONE (2025-10-17) | Team Excititor Connectors – Red Hat | EXCITITOR-CONN-RH-01-004 | Persist resume cursors (last updated timestamp/document hashes) in storage and reload during fetch to avoid duplicates. |
|
|
||||||
| Sprint 6 | Excititor Ingest & Formats | src/StellaOps.Excititor.Connectors.RedHat.CSAF/TASKS.md | DONE (2025-10-17) | Team Excititor Connectors – Red Hat | EXCITITOR-CONN-RH-01-005 | Register connector in Worker/WebService DI, add scheduled jobs, and document CLI triggers for Red Hat CSAF pulls. |
|
|
||||||
| Sprint 6 | Excititor Ingest & Formats | src/StellaOps.Excititor.Connectors.RedHat.CSAF/TASKS.md | DONE (2025-10-17) | Team Excititor Connectors – Red Hat | EXCITITOR-CONN-RH-01-006 | Add CSAF normalization parity fixtures ensuring RHSA-specific metadata is preserved. |
|
|
||||||
| Sprint 6 | Excititor Ingest & Formats | src/StellaOps.Excititor.Connectors.Cisco.CSAF/TASKS.md | DONE (2025-10-17) | Team Excititor Connectors – Cisco | EXCITITOR-CONN-CISCO-01-001 | Implement Cisco CSAF endpoint discovery/auth to unlock paginated pulls. |
|
|
||||||
| Sprint 6 | Excititor Ingest & Formats | src/StellaOps.Excititor.Connectors.Cisco.CSAF/TASKS.md | DONE (2025-10-17) | Team Excititor Connectors – Cisco | EXCITITOR-CONN-CISCO-01-002 | Implement Cisco CSAF paginated fetch loop with dedupe and raw persistence support. |
|
|
||||||
| Sprint 6 | Excititor Ingest & Formats | src/StellaOps.Excititor.Connectors.SUSE.RancherVEXHub/TASKS.md | DONE (2025-10-17) | Team Excititor Connectors – SUSE | EXCITITOR-CONN-SUSE-01-001 | Build Rancher VEX Hub discovery/subscription path with offline snapshot support. |
|
|
||||||
| Sprint 6 | Excititor Ingest & Formats | src/StellaOps.Excititor.Connectors.MSRC.CSAF/TASKS.md | DONE (2025-10-17) | Team Excititor Connectors – MSRC | EXCITITOR-CONN-MS-01-001 | Deliver AAD onboarding/token cache for MSRC CSAF ingestion. |
|
|
||||||
| Sprint 6 | Excititor Ingest & Formats | src/StellaOps.Excititor.Connectors.Oracle.CSAF/TASKS.md | DONE (2025-10-17) | Team Excititor Connectors – Oracle | EXCITITOR-CONN-ORACLE-01-001 | Implement Oracle CSAF catalogue discovery with CPU calendar awareness. |
|
|
||||||
| Sprint 6 | Excititor Ingest & Formats | src/StellaOps.Excititor.Connectors.Ubuntu.CSAF/TASKS.md | DONE (2025-10-17) | Team Excititor Connectors – Ubuntu | EXCITITOR-CONN-UBUNTU-01-001 | Implement Ubuntu CSAF discovery and channel selection for USN ingestion. |
|
|
||||||
| Sprint 6 | Excititor Ingest & Formats | src/StellaOps.Excititor.Connectors.OCI.OpenVEX.Attest/TASKS.md | DONE (2025-10-18) | Team Excititor Connectors – OCI | EXCITITOR-CONN-OCI-01-001 | Wire OCI discovery/auth to fetch OpenVEX attestations for configured images. |
|
|
||||||
| Sprint 6 | Excititor Ingest & Formats | src/StellaOps.Excititor.Connectors.OCI.OpenVEX.Attest/TASKS.md | DONE (2025-10-18) | Team Excititor Connectors – OCI | EXCITITOR-CONN-OCI-01-002 | Attestation fetch & verify loop – download DSSE attestations, trigger verification, handle retries/backoff, persist raw statements. |
|
|
||||||
| Sprint 6 | Excititor Ingest & Formats | src/StellaOps.Excititor.Connectors.OCI.OpenVEX.Attest/TASKS.md | DONE (2025-10-18) | Team Excititor Connectors – OCI | EXCITITOR-CONN-OCI-01-003 | Provenance metadata & policy hooks – emit image, subject digest, issuer, and trust metadata for policy weighting/logging. |
|
|
||||||
| Sprint 6 | Excititor Ingest & Formats | src/StellaOps.Cli/TASKS.md | DONE (2025-10-18) | DevEx/CLI | EXCITITOR-CLI-01-001 | Add `excititor` CLI verbs bridging to WebService with consistent auth and offline UX. |
|
|
||||||
| Sprint 7 | Contextual Truth Foundations | src/StellaOps.Excititor.Core/TASKS.md | DONE (2025-10-19) | Team Excititor Core & Policy | EXCITITOR-CORE-02-001 | Context signal schema prep – extend consensus models with severity/KEV/EPSS fields and update canonical serializers. |
|
|
||||||
| Sprint 7 | Contextual Truth Foundations | src/StellaOps.Excititor.Policy/TASKS.md | DONE (2025-10-19) | Team Excititor Policy | EXCITITOR-POLICY-02-001 | Scoring coefficients & weight ceilings – add α/β options, weight boosts, and validation guidance. |
|
|
||||||
| Sprint 7 | Contextual Truth Foundations | src/StellaOps.Excititor.Attestation/TASKS.md | DONE (2025-10-16) | Team Excititor Attestation | EXCITITOR-ATTEST-01-002 | Rekor v2 client integration – ship transparency log client with retries and offline queue. |
|
|
||||||
| Sprint 9 | Scanner Core Foundations | src/StellaOps.Scanner.Core/TASKS.md | DONE (2025-10-18) | Team Scanner Core | SCANNER-CORE-09-501 | Define shared DTOs (ScanJob, ProgressEvent), error taxonomy, and deterministic ID/timestamp helpers aligning with `ARCHITECTURE_SCANNER.md` §3–§4. |
|
|
||||||
| Sprint 9 | Scanner Core Foundations | src/StellaOps.Scanner.Core/TASKS.md | DONE (2025-10-18) | Team Scanner Core | SCANNER-CORE-09-502 | Observability helpers (correlation IDs, logging scopes, metric namespacing, deterministic hashes) consumed by WebService/Worker. |
|
|
||||||
| Sprint 9 | Scanner Core Foundations | src/StellaOps.Scanner.Core/TASKS.md | DONE (2025-10-18) | Team Scanner Core | SCANNER-CORE-09-503 | Security utilities: Authority client factory, OpTok caching, DPoP verifier, restart-time plug-in guardrails for scanner components. |
|
|
||||||
| Sprint 9 | Scanner Build-time | src/StellaOps.Scanner.Sbomer.BuildXPlugin/TASKS.md | DONE (2025-10-19) | BuildX Guild | SP9-BLDX-09-001 | Buildx driver scaffold + handshake with Scanner.Emit (local CAS). |
|
|
||||||
| Sprint 9 | Scanner Build-time | src/StellaOps.Scanner.Sbomer.BuildXPlugin/TASKS.md | DONE (2025-10-19) | BuildX Guild | SP9-BLDX-09-002 | OCI annotations + provenance hand-off to Attestor. |
|
|
||||||
| Sprint 9 | Scanner Build-time | src/StellaOps.Scanner.Sbomer.BuildXPlugin/TASKS.md | DONE (2025-10-19) | BuildX Guild | SP9-BLDX-09-003 | CI demo: minimal SBOM push & backend report wiring. |
|
|
||||||
| Sprint 9 | Scanner Build-time | src/StellaOps.Scanner.Sbomer.BuildXPlugin/TASKS.md | DONE (2025-10-19) | BuildX Guild | SP9-BLDX-09-004 | Stabilize descriptor nonce derivation so repeated builds emit deterministic placeholders. |
|
|
||||||
| Sprint 9 | Scanner Build-time | src/StellaOps.Scanner.Sbomer.BuildXPlugin/TASKS.md | DONE (2025-10-19) | BuildX Guild | SP9-BLDX-09-005 | Integrate determinism guard into GitHub/Gitea workflows and archive proof artifacts. |
|
|
||||||
| Sprint 9 | Scanner Core Foundations | src/StellaOps.Scanner.WebService/TASKS.md | DONE (2025-10-18) | Team Scanner WebService | SCANNER-WEB-09-101 | Minimal API host with Authority enforcement, health/ready endpoints, and restart-time plug-in loader per architecture §1, §4. |
|
|
||||||
| Sprint 9 | Scanner Core Foundations | src/StellaOps.Scanner.WebService/TASKS.md | DONE (2025-10-18) | Team Scanner WebService | SCANNER-WEB-09-102 | `/api/v1/scans` submission/status endpoints with deterministic IDs, validation, and cancellation support. |
|
|
||||||
| Sprint 9 | Scanner Core Foundations | src/StellaOps.Scanner.WebService/TASKS.md | DONE (2025-10-19) | Team Scanner WebService | SCANNER-WEB-09-104 | Configuration binding for Mongo, MinIO, queue, feature flags; startup diagnostics and fail-fast policy. |
|
|
||||||
| Sprint 9 | Scanner Core Foundations | src/StellaOps.Scanner.Worker/TASKS.md | DONE (2025-10-19) | Team Scanner Worker | SCANNER-WORKER-09-201 | Worker host bootstrap with Authority auth, hosted services, and graceful shutdown semantics. |
|
|
||||||
| Sprint 9 | Scanner Core Foundations | src/StellaOps.Scanner.Worker/TASKS.md | DONE (2025-10-19) | Team Scanner Worker | SCANNER-WORKER-09-202 | Lease/heartbeat loop with retry+jitter, poison-job quarantine, structured logging. |
|
|
||||||
| Sprint 9 | Scanner Core Foundations | src/StellaOps.Scanner.Worker/TASKS.md | DONE (2025-10-19) | Team Scanner Worker | SCANNER-WORKER-09-203 | Analyzer dispatch skeleton emitting deterministic stage progress and honoring cancellation tokens. |
|
|
||||||
| Sprint 9 | Scanner Core Foundations | src/StellaOps.Scanner.Worker/TASKS.md | DONE (2025-10-19) | Team Scanner Worker | SCANNER-WORKER-09-204 | Worker metrics (queue latency, stage duration, failure counts) with OpenTelemetry resource wiring. |
|
|
||||||
| Sprint 9 | Scanner Core Foundations | src/StellaOps.Scanner.Worker/TASKS.md | DONE (2025-10-19) | Team Scanner Worker | SCANNER-WORKER-09-205 | Harden heartbeat jitter so lease safety margin stays ≥3× and cover with regression tests + optional live queue smoke run. |
|
|
||||||
| Sprint 9 | Policy Foundations | src/StellaOps.Policy/TASKS.md | DONE | Policy Guild | POLICY-CORE-09-001 | Policy schema + binder + diagnostics. |
|
|
||||||
| Sprint 9 | Policy Foundations | src/StellaOps.Policy/TASKS.md | DONE | Policy Guild | POLICY-CORE-09-002 | Policy snapshot store + revision digests. |
|
|
||||||
| Sprint 9 | Policy Foundations | src/StellaOps.Policy/TASKS.md | DONE | Policy Guild | POLICY-CORE-09-003 | `/policy/preview` API (image digest → projected verdict diff). |
|
|
||||||
| Sprint 9 | DevOps Foundations | ops/devops/TASKS.md | DONE (2025-10-19) | DevOps Guild | DEVOPS-HELM-09-001 | Helm/Compose environment profiles (dev/staging/airgap) with deterministic digests. |
|
|
||||||
| Sprint 9 | Docs & Governance | docs/TASKS.md | DONE (2025-10-19) | Docs Guild, DevEx | DOCS-ADR-09-001 | Establish ADR process and template. |
|
|
||||||
| Sprint 9 | Docs & Governance | docs/TASKS.md | DONE (2025-10-19) | Docs Guild, Platform Events | DOCS-EVENTS-09-002 | Publish event schema catalog (`docs/events/`) for critical envelopes. |
|
|
||||||
| Sprint 9 | Scanner Core Foundations | src/StellaOps.Scanner.Storage/TASKS.md | DONE (2025-10-19) | Team Scanner Storage | SCANNER-STORAGE-09-301 | Mongo catalog schemas/indexes for images, layers, artifacts, jobs, lifecycle rules plus migrations. |
|
|
||||||
| Sprint 9 | Scanner Core Foundations | src/StellaOps.Scanner.Storage/TASKS.md | DONE (2025-10-19) | Team Scanner Storage | SCANNER-STORAGE-09-302 | MinIO layout, immutability policies, client abstraction, and configuration binding. |
|
|
||||||
| Sprint 9 | Scanner Core Foundations | src/StellaOps.Scanner.Storage/TASKS.md | DONE (2025-10-19) | Team Scanner Storage | SCANNER-STORAGE-09-303 | Repositories/services with dual-write feature flag, deterministic digests, TTL enforcement tests. |
|
|
||||||
| Sprint 9 | Scanner Core Foundations | src/StellaOps.Scanner.Queue/TASKS.md | DONE (2025-10-19) | Team Scanner Queue | SCANNER-QUEUE-09-401 | Queue abstraction + Redis Streams adapter with ack/claim APIs and idempotency tokens. |
|
|
||||||
| Sprint 9 | Scanner Core Foundations | src/StellaOps.Scanner.Queue/TASKS.md | DONE (2025-10-19) | Team Scanner Queue | SCANNER-QUEUE-09-402 | Pluggable backend support (Redis, NATS) with configuration binding, health probes, failover docs. |
|
|
||||||
| Sprint 9 | Scanner Core Foundations | src/StellaOps.Scanner.Queue/TASKS.md | DONE (2025-10-19) | Team Scanner Queue | SCANNER-QUEUE-09-403 | Retry + dead-letter strategy with structured logs/metrics for offline deployments. |
|
|
||||||
| Sprint 1 | Stabilize In-Progress Foundations | src/StellaOps.Concelier.Connector.Ghsa/TASKS.md | DONE (2025-10-12) | Team Connector Normalized Versions Rollout | FEEDCONN-GHSA-02-001 | GHSA normalized versions & provenance<br>Team instructions: Read ./AGENTS.md and each module's AGENTS file. Adopt the `NormalizedVersions` array emitted by the models sprint, wiring provenance `decisionReason` where merge overrides occur. Follow ./src/FASTER_MODELING_AND_NORMALIZATION.md; report via src/StellaOps.Concelier.Merge/TASKS.md (FEEDMERGE-COORD-02-900). Progress 2025-10-11: GHSA/OSV emit normalized arrays with refreshed fixtures; CVE mapper now surfaces SemVer normalized ranges; NVD/KEV adoption pending; outstanding follow-ups include FEEDSTORAGE-DATA-02-001, FEEDMERGE-ENGINE-02-002, and rolling `tools/FixtureUpdater` updates across connectors.<br>Progress 2025-10-20: Coordination matrix + rollout dashboard refreshed; upcoming deadlines tracked (Cccs/Cisco 2025-10-21, CertBund 2025-10-22, ICS-CISA 2025-10-23, KISA 2025-10-24) with escalation path documented in FEEDMERGE-COORD-02-900.|
|
|
||||||
| Sprint 1 | Stabilize In-Progress Foundations | src/StellaOps.Concelier.WebService/TASKS.md | DONE (2025-10-19) | Team WebService & Authority | FEEDWEB-OPS-01-006 | Rename plugin drop directory to namespaced path<br>Build outputs now point at `StellaOps.Concelier.PluginBinaries`/`StellaOps.Authority.PluginBinaries`; defaults/docs/tests updated to reflect the new layout. |
|
|
||||||
| Sprint 7 | Contextual Truth Foundations | src/StellaOps.Excititor.Storage.Mongo/TASKS.md | DONE (2025-10-19) | Team Excititor Storage | EXCITITOR-STORAGE-02-001 | Statement events & scoring signals – immutable VEX statements store, consensus signal fields, and migration `20251019-consensus-signals-statements` with tests (`dotnet test src/StellaOps.Excititor.Core.Tests/StellaOps.Excititor.Core.Tests.csproj`, `dotnet test src/StellaOps.Excititor.Storage.Mongo.Tests/StellaOps.Excititor.Storage.Mongo.Tests.csproj`). |
|
|
||||||
| Sprint 7 | Contextual Truth Foundations | src/StellaOps.Concelier.Core/TASKS.md | DONE (2025-10-19) | Team Core Engine & Storage Analytics | FEEDCORE-ENGINE-07-001 | Advisory event log & asOf queries – surface immutable statements and replay capability. |
|
|
||||||
| Sprint 7 | Contextual Truth Foundations | src/StellaOps.Concelier.WebService/TASKS.md | DONE (2025-10-19) | Concelier WebService Guild | FEEDWEB-EVENTS-07-001 | Advisory event replay API – expose `/concelier/advisories/{key}/replay` with `asOf` filter, hex hashes, and conflict data. |
|
|
||||||
| Sprint 7 | Contextual Truth Foundations | src/StellaOps.Concelier.Merge/TASKS.md | DONE (2025-10-20) | BE-Merge | FEEDMERGE-ENGINE-07-001 | Conflict sets & explainers – persist conflict materialization and replay hashes for merge decisions. |
|
|
||||||
| Sprint 8 | Mongo strengthening | src/StellaOps.Concelier.Storage.Mongo/TASKS.md | DONE (2025-10-19) | Team Normalization & Storage Backbone | FEEDSTORAGE-MONGO-08-001 | Causal-consistent Concelier storage sessions<br>Scoped session facilitator registered, repositories accept optional session handles, and replica-set failover tests verify read-your-write + monotonic reads. |
|
|
||||||
| Sprint 8 | Mongo strengthening | src/StellaOps.Authority/TASKS.md | DONE (2025-10-19) | Authority Core & Storage Guild | AUTHSTORAGE-MONGO-08-001 | Harden Authority Mongo usage<br>Scoped Mongo sessions with majority read/write concerns wired through stores and GraphQL/HTTP pipelines; replica-set election regression validated. |
|
|
||||||
| Sprint 8 | Mongo strengthening | src/StellaOps.Excititor.Storage.Mongo/TASKS.md | DONE (2025-10-19) | Team Excititor Storage | EXCITITOR-STORAGE-MONGO-08-001 | Causal consistency for Excititor repositories<br>Session-scoped repositories shipped with new Mongo records, orchestrators/workers now share scoped sessions, and replica-set failover coverage added via `dotnet test src/StellaOps.Excititor.Storage.Mongo.Tests/StellaOps.Excititor.Storage.Mongo.Tests.csproj`. |
|
|
||||||
| Sprint 8 | Platform Maintenance | src/StellaOps.Excititor.Storage.Mongo/TASKS.md | DONE (2025-10-19) | Team Excititor Storage | EXCITITOR-STORAGE-03-001 | Statement backfill tooling – shipped admin backfill endpoint, CLI hook (`stellaops excititor backfill-statements`), integration tests, and operator runbook (`docs/dev/EXCITITOR_STATEMENT_BACKFILL.md`). |
|
|
||||||
| Sprint 8 | Mirror Distribution | src/StellaOps.Concelier.Exporter.Json/TASKS.md | DONE (2025-10-19) | Concelier Export Guild | CONCELIER-EXPORT-08-201 | Mirror bundle + domain manifest – produce signed JSON aggregates for `*.stella-ops.org` mirrors. |
|
|
||||||
| Sprint 8 | Mirror Distribution | src/StellaOps.Concelier.Exporter.TrivyDb/TASKS.md | DONE (2025-10-19) | Concelier Export Guild | CONCELIER-EXPORT-08-202 | Mirror-ready Trivy DB bundles – mirror options emit per-domain manifests/metadata/db archives with deterministic digests for downstream sync. |
|
|
||||||
| Sprint 8 | Mirror Distribution | src/StellaOps.Concelier.WebService/TASKS.md | DONE (2025-10-20) | Concelier WebService Guild | CONCELIER-WEB-08-201 | Mirror distribution endpoints – expose domain-scoped index/download APIs with auth/quota. |
|
|
||||||
| Sprint 8 | Mirror Distribution | ops/devops/TASKS.md | DONE (2025-10-19) | DevOps Guild | DEVOPS-MIRROR-08-001 | Managed mirror deployments for `*.stella-ops.org` – Helm/Compose overlays, CDN, runbooks. |
|
|
||||||
| Sprint 8 | Plugin Infrastructure | src/StellaOps.Plugin/TASKS.md | DONE (2025-10-20) | Plugin Platform Guild, Authority Core | PLUGIN-DI-08-003 | Refactor Authority identity-provider registry to resolve scoped plugin services on-demand.<br>Introduce factory pattern aligned with scoped lifetimes decided in coordination workshop. |
|
|
||||||
| Sprint 8 | Plugin Infrastructure | src/StellaOps.Plugin/TASKS.md | DONE (2025-10-20) | Plugin Platform Guild, Authority Core | PLUGIN-DI-08-004 | Update Authority plugin loader to activate registrars with DI support and scoped service awareness.<br>Add two-phase initialization allowing scoped dependencies post-container build. |
|
|
||||||
| Sprint 8 | Plugin Infrastructure | src/StellaOps.Plugin/TASKS.md | DONE (2025-10-20) | Plugin Platform Guild, Authority Core | PLUGIN-DI-08-005 | Provide scoped-safe bootstrap execution for Authority plugins.<br>Implement scope-per-run pattern for hosted bootstrap tasks and document migration guidance. |
|
|
||||||
| Sprint 10 | DevOps Security | ops/devops/TASKS.md | DONE (2025-10-20) | DevOps Guild | DEVOPS-SEC-10-301 | Address NU1902/NU1903 advisories for `MongoDB.Driver` 2.12.0 and `SharpCompress` 0.23.0; Wave 0A prerequisites confirmed complete before remediation work. |
|
|
||||||
| Sprint 11 | Signing Chain Bring-up | src/StellaOps.Authority/TASKS.md | DONE (2025-10-20) | Authority Core & Security Guild | AUTH-DPOP-11-001 | Implement DPoP proof validation + nonce handling for high-value audiences per architecture. |
|
|
||||||
| Sprint 15 | Notify Foundations | src/StellaOps.Notify.WebService/TASKS.md | DONE (2025-10-19) | Notify WebService Guild | NOTIFY-WEB-15-103 | Delivery history & test-send endpoints. |
|
|
||||||
| Sprint 15 | Notify Foundations | src/StellaOps.Notify.Connectors.Slack/TASKS.md | DONE (2025-10-20) | Notify Connectors Guild | NOTIFY-CONN-SLACK-15-502 | Slack health/test-send support. |
|
|
||||||
| Sprint 15 | Notify Foundations | src/StellaOps.Notify.Connectors.Teams/TASKS.md | DONE (2025-10-20) | Notify Connectors Guild | NOTIFY-CONN-TEAMS-15-602 | Teams health/test-send support. |
|
|
||||||
| Sprint 15 | Notify Foundations | src/StellaOps.Notify.Connectors.Teams/TASKS.md | DONE (2025-10-20) | Notify Connectors Guild | NOTIFY-CONN-TEAMS-15-604 | Teams health endpoint metadata alignment. |
|
|
||||||
| Sprint 15 | Notify Foundations | src/StellaOps.Notify.Connectors.Slack/TASKS.md | DONE (2025-10-20) | Notify Connectors Guild | NOTIFY-CONN-SLACK-15-503 | Package Slack connector as restart-time plug-in (manifest + host registration). |
|
|
||||||
| Sprint 15 | Notify Foundations | src/StellaOps.Notify.Connectors.Teams/TASKS.md | DONE (2025-10-20) | Notify Connectors Guild | NOTIFY-CONN-TEAMS-15-603 | Package Teams connector as restart-time plug-in (manifest + host registration). |
|
|
||||||
| Sprint 15 | Notify Foundations | src/StellaOps.Notify.Connectors.Email/TASKS.md | DONE (2025-10-20) | Notify Connectors Guild | NOTIFY-CONN-EMAIL-15-703 | Package Email connector as restart-time plug-in (manifest + host registration). |
|
|
||||||
| Sprint 15 | Notify Foundations | src/StellaOps.Scanner.WebService/TASKS.md | DONE (2025-10-20) | Scanner WebService Guild | SCANNER-EVENTS-15-201 | Emit `scanner.report.ready` + `scanner.scan.completed` events. |
|
|
||||||
| Sprint 15 | Notify Foundations | src/StellaOps.Notify.Connectors.Webhook/TASKS.md | DONE (2025-10-20) | Notify Connectors Guild | NOTIFY-CONN-WEBHOOK-15-803 | Package Webhook connector as restart-time plug-in (manifest + host registration). |
|
|
||||||
| Sprint 16 | Scheduler Intelligence | src/StellaOps.Scheduler.Models/TASKS.md | DONE (2025-10-20) | Scheduler Models Guild | SCHED-MODELS-16-103 | Versioning/migration helpers for schedules/runs. |
|
|
||||||
| Sprint 16 | Scheduler Intelligence | src/StellaOps.Scheduler.Queue/TASKS.md | DONE (2025-10-20) | Scheduler Queue Guild | SCHED-QUEUE-16-401 | Queue abstraction + Redis Streams adapter. |
|
|
||||||
| Sprint 16 | Scheduler Intelligence | src/StellaOps.Scheduler.Queue/TASKS.md | DONE (2025-10-20) | Scheduler Queue Guild | SCHED-QUEUE-16-402 | NATS JetStream adapter with health probes. |
|
|
||||||
| Sprint 16 | Scheduler Intelligence | src/StellaOps.Scheduler.ImpactIndex/TASKS.md | DONE (2025-10-20) | Scheduler ImpactIndex Guild | SCHED-IMPACT-16-300 | **STUB** ImpactIndex ingest/query using fixtures (to be removed by SP16 completion). |
|
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
This file describe implementation of Stella Ops (docs/README.md). Implementation must respect rules from AGENTS.md (read if you have not).
|
|
||||||
|
|
||||||
| Sprint | Theme | Tasks File Path | Status | Type of Specialist | Task ID | Task Description |
|
|
||||||
| --- | --- | --- | --- | --- | --- | --- |
|
|
||||||
| Sprint 7 | Contextual Truth Foundations | docs/TASKS.md | DONE (2025-10-22) | Docs Guild, Concelier WebService | DOCS-CONCELIER-07-201 | Final editorial review and publish pass for Concelier authority toggle documentation (Quickstart + operator guide). |
|
|
||||||
| Sprint 7 | Contextual Truth Foundations | src/StellaOps.Excititor.WebService/TASKS.md | DONE (2025-10-20) | Team Excititor WebService | EXCITITOR-WEB-01-002 | Ingest & reconcile endpoints – scope-enforced `/excititor/init`, `/excititor/ingest/run`, `/excititor/ingest/resume`, `/excititor/reconcile`; regression via `dotnet test … --filter FullyQualifiedName~IngestEndpointsTests`. |
|
|
||||||
| Sprint 7 | Contextual Truth Foundations | src/StellaOps.Excititor.WebService/TASKS.md | DONE (2025-10-20) | Team Excititor WebService | EXCITITOR-WEB-01-004 | Resolve API & signed responses – expose `/excititor/resolve`, return signed consensus/score envelopes, document auth. |
|
|
||||||
| Sprint 7 | Contextual Truth Foundations | src/StellaOps.Excititor.Worker/TASKS.md | DONE (2025-10-21) | Team Excititor Worker | EXCITITOR-WORKER-01-004 | TTL refresh & stability damper – schedule re-resolve loops and guard against status flapping. |
|
|
||||||
| Sprint 7 | Contextual Truth Foundations | src/StellaOps.Concelier.Core/TASKS.md | DONE (2025-10-21) | Team Core Engine & Data Science | FEEDCORE-ENGINE-07-002 | Noise prior computation service – learn false-positive priors and expose deterministic summaries. |
|
|
||||||
| Sprint 7 | Contextual Truth Foundations | src/StellaOps.Concelier.Core/TASKS.md | DONE (2025-10-21) | Team Core Engine & Storage Analytics | FEEDCORE-ENGINE-07-003 | Unknown state ledger & confidence seeding – persist unknown flags, seed confidence bands, expose query surface. |
|
|
||||||
| Sprint 7 | Contextual Truth Foundations | src/StellaOps.Excititor.WebService/TASKS.md | DONE (2025-10-19) | Team Excititor WebService | EXCITITOR-WEB-01-005 | Mirror distribution endpoints – expose download APIs for downstream Excititor instances. |
|
|
||||||
| Sprint 7 | Contextual Truth Foundations | src/StellaOps.Excititor.Export/TASKS.md | DONE (2025-10-21) | Team Excititor Export | EXCITITOR-EXPORT-01-005 | Score & resolve envelope surfaces – include signed consensus/score artifacts in exports. |
|
|
||||||
| Sprint 7 | Contextual Truth Foundations | src/StellaOps.Excititor.Export/TASKS.md | DONE (2025-10-21) | Team Excititor Export | EXCITITOR-EXPORT-01-006 | Quiet provenance packaging – attach quieted-by statement IDs, signers, justification codes to exports and attestations. |
|
|
||||||
| Sprint 7 | Contextual Truth Foundations | src/StellaOps.Excititor.Export/TASKS.md | DONE (2025-10-21) | Team Excititor Export | EXCITITOR-EXPORT-01-007 | Mirror bundle + domain manifest – publish signed consensus bundles for mirrors. |
|
|
||||||
| Sprint 7 | Contextual Truth Foundations | src/StellaOps.Excititor.Connectors.StellaOpsMirror/TASKS.md | DONE (2025-10-21) | Excititor Connectors – Stella | EXCITITOR-CONN-STELLA-07-001 | Excititor mirror connector – ingest signed mirror bundles and map to VexClaims with resume handling. |
|
|
||||||
| Sprint 7 | Contextual Truth Foundations | src/StellaOps.Concelier.Storage.Mongo/TASKS.md | DONE (2025-10-19) | Team Normalization & Storage Backbone | FEEDSTORAGE-DATA-07-001 | Advisory statement & conflict collections – provision Mongo schema/indexes for event-sourced merge. |
|
|
||||||
| Sprint 7 | Contextual Truth Foundations | src/StellaOps.Web/TASKS.md | DONE (2025-10-21) | UX Specialist, Angular Eng | WEB1.TRIVY-SETTINGS-TESTS | Add headless UI test run (`ng test --watch=false`) and document prerequisites once Angular tooling is chained up. |
|
|
||||||
| Sprint 8 | Mirror Distribution | src/StellaOps.Concelier.Connector.StellaOpsMirror/TASKS.md | DONE (2025-10-20) | BE-Conn-Stella | FEEDCONN-STELLA-08-001 | Concelier mirror connector – fetch mirror manifest, verify signatures, and hydrate canonical DTOs with resume support. |
|
|
||||||
| Sprint 8 | Mirror Distribution | src/StellaOps.Concelier.Connector.StellaOpsMirror/TASKS.md | DONE (2025-10-20) | BE-Conn-Stella | FEEDCONN-STELLA-08-002 | Map mirror payloads into canonical advisory DTOs with provenance referencing mirror domain + original source metadata. |
|
|
||||||
| Sprint 8 | Mirror Distribution | src/StellaOps.Concelier.Connector.StellaOpsMirror/TASKS.md | DONE (2025-10-20) | BE-Conn-Stella | FEEDCONN-STELLA-08-003 | Add incremental cursor + resume support (per-export fingerprint) and document configuration for downstream Concelier instances. |
|
|
||||||
| Sprint 8 | Plugin Infrastructure | src/StellaOps.Plugin/TASKS.md | DONE (2025-10-21) | Plugin Platform Guild | PLUGIN-DI-08-001 | Scoped service support in plugin bootstrap – added dynamic plugin tests ensuring `[ServiceBinding]` metadata flows through plugin hosts and remains idempotent. |
|
|
||||||
| Sprint 8 | Plugin Infrastructure | src/StellaOps.Plugin/TASKS.md | DONE (2025-10-20) | Plugin Platform Guild, Authority Core | PLUGIN-DI-08-002.COORD | Authority scoped-service integration handshake<br>Workshop concluded 2025-10-20 15:00–16:05 UTC; decisions + follow-ups recorded in `docs/dev/authority-plugin-di-coordination.md`. |
|
|
||||||
| Sprint 8 | Plugin Infrastructure | src/StellaOps.Plugin/TASKS.md | DONE (2025-10-20) | Plugin Platform Guild, Authority Core | PLUGIN-DI-08-002 | Authority plugin integration updates – scoped identity-provider services with registry handles; regression coverage via scoped registrar/unit tests. |
|
|
||||||
| Sprint 8 | Plugin Infrastructure | src/StellaOps.Authority/TASKS.md | DONE (2025-10-20) | Authority Core, Plugin Platform Guild | AUTH-PLUGIN-COORD-08-002 | Coordinate scoped-service adoption for Authority plug-in registrars<br>Workshop notes and follow-up backlog captured 2025-10-20 in `docs/dev/authority-plugin-di-coordination.md`. |
|
|
||||||
| Sprint 9 | Scanner Core Foundations | src/StellaOps.Scanner.WebService/TASKS.md | DONE (2025-10-19) | Team Scanner WebService | SCANNER-WEB-09-103 | Progress streaming (SSE/JSONL) with correlation IDs and ISO-8601 UTC timestamps, documented in API reference. |
|
|
||||||
| Sprint 9 | Scanner Core Foundations | src/StellaOps.Scanner.WebService/TASKS.md | DONE (2025-10-19) | Team Scanner WebService | SCANNER-POLICY-09-105 | Policy snapshot loader + schema + OpenAPI (YAML ignore rules, VEX include/exclude, vendor precedence). |
|
|
||||||
| Sprint 9 | Scanner Core Foundations | src/StellaOps.Scanner.WebService/TASKS.md | DONE (2025-10-19) | Team Scanner WebService | SCANNER-POLICY-09-106 | `/reports` verdict assembly (Feedser+Vexer+Policy) + signed response envelope. |
|
|
||||||
| Sprint 9 | Scanner Core Foundations | src/StellaOps.Scanner.WebService/TASKS.md | DONE (2025-10-19) | Team Scanner WebService | SCANNER-POLICY-09-107 | Expose score inputs, config version, and quiet provenance in `/reports` JSON and signed payload. |
|
|
||||||
| Sprint 9 | DevOps Foundations | ops/devops/TASKS.md | DONE (2025-10-21) | DevOps Guild, Scanner WebService Guild | DEVOPS-SCANNER-09-204 | Surface `SCANNER__EVENTS__*` env config across Compose/Helm and document overrides. |
|
|
||||||
| Sprint 9 | DevOps Foundations | ops/devops/TASKS.md | DONE (2025-10-21) | DevOps Guild, Notify Guild | DEVOPS-SCANNER-09-205 | Notify smoke job validates Redis stream + Notify deliveries after staging deploys. |
|
|
||||||
| Sprint 9 | Policy Foundations | src/StellaOps.Policy/TASKS.md | DONE (2025-10-19) | Policy Guild | POLICY-CORE-09-004 | Versioned scoring config with schema validation, trust table, and golden fixtures. |
|
|
||||||
| Sprint 9 | Policy Foundations | src/StellaOps.Policy/TASKS.md | DONE (2025-10-19) | Policy Guild | POLICY-CORE-09-005 | Scoring/quiet engine – compute score, enforce VEX-only quiet rules, emit inputs and provenance. |
|
|
||||||
| Sprint 9 | Policy Foundations | src/StellaOps.Policy/TASKS.md | DONE (2025-10-19) | Policy Guild | POLICY-CORE-09-006 | Unknown state & confidence decay – deterministic bands surfaced in policy outputs. |
|
|
||||||
| Sprint 9 | Docs & Governance | docs/TASKS.md | DONE (2025-10-21) | Platform Events Guild | PLATFORM-EVENTS-09-401 | Embed canonical event samples into contract/integration tests and ensure CI validates payloads against published schemas. |
|
|
||||||
| Sprint 10 | Benchmarks | src/StellaOps.Bench/TASKS.md | DONE (2025-10-21) | Bench Guild, Language Analyzer Guild | BENCH-SCANNER-10-002 | Wire real language analyzers into bench harness & refresh baselines post-implementation. |
|
|
||||||
| Sprint 10 | Scanner Analyzers & SBOM | src/StellaOps.Scanner.Analyzers.Lang/TASKS.md | DONE (2025-10-21) | Language Analyzer Guild | SCANNER-ANALYZERS-LANG-10-302 | Node analyzer handling workspaces/symlinks emitting `pkg:npm`. |
|
|
||||||
| Sprint 10 | Scanner Analyzers & SBOM | src/StellaOps.Scanner.Analyzers.Lang/TASKS.md | DONE (2025-10-21) | Language Analyzer Guild | SCANNER-ANALYZERS-LANG-10-303 | Python analyzer reading `*.dist-info`, RECORD hashes, entry points. |
|
|
||||||
| Sprint 10 | Scanner Analyzers & SBOM | src/StellaOps.Scanner.Analyzers.Lang/TASKS.md | DONE (2025-10-22) | Language Analyzer Guild | SCANNER-ANALYZERS-LANG-10-304 | Go analyzer leveraging buildinfo for `pkg:golang` components. |
|
|
||||||
| Sprint 10 | Scanner Analyzers & SBOM | src/StellaOps.Scanner.Analyzers.Lang.Go/TASKS.md | DONE (2025-10-22) | Language Analyzer Guild | SCANNER-ANALYZERS-LANG-10-304E | Plumb Go heuristic counter into Scanner metrics pipeline and alerting. |
|
|
||||||
| Sprint 10 | Scanner Analyzers & SBOM | src/StellaOps.Scanner.Analyzers.Lang/TASKS.md | DONE (2025-10-22) | Language Analyzer Guild | SCANNER-ANALYZERS-LANG-10-305 | .NET analyzer parsing `*.deps.json`, assembly metadata, RID variants. |
|
|
||||||
| Sprint 10 | Scanner Analyzers & SBOM | src/StellaOps.Scanner.Analyzers.Lang/TASKS.md | DONE (2025-10-22) | Language Analyzer Guild | SCANNER-ANALYZERS-LANG-10-306 | Rust analyzer detecting crates or falling back to `bin:{sha256}`. |
|
|
||||||
| Sprint 10 | Scanner Analyzers & SBOM | src/StellaOps.Scanner.Analyzers.Lang/TASKS.md | DONE (2025-10-19) | Language Analyzer Guild | SCANNER-ANALYZERS-LANG-10-307 | Shared language evidence helpers + usage flag propagation. |
|
|
||||||
| Sprint 10 | Scanner Analyzers & SBOM | src/StellaOps.Scanner.Analyzers.Lang/TASKS.md | DONE (2025-10-19) | Language Analyzer Guild | SCANNER-ANALYZERS-LANG-10-308 | Determinism + fixture harness for language analyzers. |
|
|
||||||
| Sprint 10 | Scanner Analyzers & SBOM | src/StellaOps.Scanner.Analyzers.Lang/TASKS.md | DONE (2025-10-21) | Language Analyzer Guild | SCANNER-ANALYZERS-LANG-10-309 | Package language analyzers as restart-time plug-ins (manifest + host registration). |
|
|
||||||
| Sprint 10 | Scanner Analyzers & SBOM | src/StellaOps.Scanner.Emit/TASKS.md | DONE (2025-10-22) | Emit Guild | SCANNER-EMIT-10-601 | Compose inventory SBOM (CycloneDX JSON/Protobuf) from layer fragments. |
|
|
||||||
| Sprint 10 | Scanner Analyzers & SBOM | src/StellaOps.Scanner.Emit/TASKS.md | DONE (2025-10-22) | Emit Guild | SCANNER-EMIT-10-602 | Compose usage SBOM leveraging EntryTrace to flag actual usage. |
|
|
||||||
| Sprint 10 | Scanner Analyzers & SBOM | src/StellaOps.Scanner.Emit/TASKS.md | DONE (2025-10-22) | Emit Guild | SCANNER-EMIT-10-603 | Generate BOM index sidecar (purl table + roaring bitmap + usage flag). |
|
|
||||||
| Sprint 10 | Scanner Analyzers & SBOM | src/StellaOps.Scanner.Emit/TASKS.md | DONE (2025-10-22) | Emit Guild | SCANNER-EMIT-10-604 | Package artifacts for export + attestation with deterministic manifests. |
|
|
||||||
| Sprint 10 | Scanner Analyzers & SBOM | src/StellaOps.Scanner.Emit/TASKS.md | DONE (2025-10-22) | Emit Guild | SCANNER-EMIT-10-605 | Emit BOM-Index sidecar schema/fixtures (CRITICAL PATH for SP16). |
|
|
||||||
| Sprint 10 | Scanner Analyzers & SBOM | src/StellaOps.Scanner.Emit/TASKS.md | DONE (2025-10-22) | Emit Guild | SCANNER-EMIT-10-606 | Usage view bit flags integrated with EntryTrace. |
|
|
||||||
| Sprint 10 | Scanner Analyzers & SBOM | src/StellaOps.Scanner.Emit/TASKS.md | DONE (2025-10-22) | Emit Guild | SCANNER-EMIT-10-607 | Embed scoring inputs, confidence band, and quiet provenance in CycloneDX/DSSE artifacts. |
|
|
||||||
| Sprint 10 | Scanner Analyzers & SBOM | src/StellaOps.Scanner.Cache/TASKS.md | DONE (2025-10-19) | Scanner Cache Guild | SCANNER-CACHE-10-101 | Implement layer cache store keyed by layer digest with metadata retention per architecture §3.3. |
|
|
||||||
| Sprint 10 | Scanner Analyzers & SBOM | src/StellaOps.Scanner.Cache/TASKS.md | DONE (2025-10-19) | Scanner Cache Guild | SCANNER-CACHE-10-102 | Build file CAS with dedupe, TTL enforcement, and offline import/export hooks. |
|
|
||||||
| Sprint 10 | Scanner Analyzers & SBOM | src/StellaOps.Scanner.Cache/TASKS.md | DONE (2025-10-19) | Scanner Cache Guild | SCANNER-CACHE-10-103 | Expose cache metrics/logging and configuration toggles for warm/cold thresholds. |
|
|
||||||
| Sprint 10 | Scanner Analyzers & SBOM | src/StellaOps.Scanner.Cache/TASKS.md | DONE (2025-10-19) | Scanner Cache Guild | SCANNER-CACHE-10-104 | Implement cache invalidation workflows (layer delete, TTL expiry, diff invalidation). |
|
|
||||||
| Sprint 10 | Scanner Analyzers & SBOM | src/StellaOps.Scanner.Analyzers.OS/TASKS.md | DONE (2025-10-19) | OS Analyzer Guild | SCANNER-ANALYZERS-OS-10-201 | Alpine/apk analyzer emitting deterministic components with provenance. |
|
|
||||||
| Sprint 10 | Scanner Analyzers & SBOM | src/StellaOps.Scanner.Analyzers.OS/TASKS.md | DONE (2025-10-19) | OS Analyzer Guild | SCANNER-ANALYZERS-OS-10-202 | Debian/dpkg analyzer mapping packages to purl identity with evidence. |
|
|
||||||
| Sprint 10 | Scanner Analyzers & SBOM | src/StellaOps.Scanner.Analyzers.OS/TASKS.md | DONE (2025-10-19) | OS Analyzer Guild | SCANNER-ANALYZERS-OS-10-203 | RPM analyzer capturing EVR, file listings, provenance. |
|
|
||||||
| Sprint 10 | Scanner Analyzers & SBOM | src/StellaOps.Scanner.Analyzers.OS/TASKS.md | DONE (2025-10-19) | OS Analyzer Guild | SCANNER-ANALYZERS-OS-10-204 | Shared OS evidence helpers for package identity + provenance. |
|
|
||||||
| Sprint 10 | Scanner Analyzers & SBOM | src/StellaOps.Scanner.Analyzers.OS/TASKS.md | DONE (2025-10-19) | OS Analyzer Guild | SCANNER-ANALYZERS-OS-10-205 | Vendor metadata enrichment (source packages, license, CVE hints). |
|
|
||||||
| Sprint 10 | Scanner Analyzers & SBOM | src/StellaOps.Scanner.Analyzers.OS/TASKS.md | DONE (2025-10-19) | OS Analyzer Guild | SCANNER-ANALYZERS-OS-10-206 | Determinism harness + fixtures for OS analyzers. |
|
|
||||||
| Sprint 10 | Scanner Analyzers & SBOM | src/StellaOps.Scanner.Analyzers.OS/TASKS.md | DONE (2025-10-19) | OS Analyzer Guild | SCANNER-ANALYZERS-OS-10-207 | Package OS analyzers as restart-time plug-ins (manifest + host registration). |
|
|
||||||
| Sprint 10 | Scanner Analyzers & SBOM | src/StellaOps.Scanner.Analyzers.Lang/TASKS.md | DONE (2025-10-19) | Language Analyzer Guild | SCANNER-ANALYZERS-LANG-10-301 | Java analyzer emitting `pkg:maven` with provenance. |
|
|
||||||
| Sprint 10 | Scanner Analyzers & SBOM | src/StellaOps.Scanner.EntryTrace/TASKS.md | DONE (2025-10-19) | EntryTrace Guild | SCANNER-ENTRYTRACE-10-401 | POSIX shell AST parser with deterministic output. |
|
|
||||||
| Sprint 10 | Scanner Analyzers & SBOM | src/StellaOps.Scanner.EntryTrace/TASKS.md | DONE (2025-10-19) | EntryTrace Guild | SCANNER-ENTRYTRACE-10-402 | Command resolution across layered rootfs with evidence attribution. |
|
|
||||||
| Sprint 10 | Scanner Analyzers & SBOM | src/StellaOps.Scanner.EntryTrace/TASKS.md | DONE (2025-10-19) | EntryTrace Guild | SCANNER-ENTRYTRACE-10-403 | Interpreter tracing for shell wrappers to Python/Node/Java launchers. |
|
|
||||||
| Sprint 10 | Scanner Analyzers & SBOM | src/StellaOps.Scanner.EntryTrace/TASKS.md | DONE (2025-10-19) | EntryTrace Guild | SCANNER-ENTRYTRACE-10-404 | Python entry analyzer (venv shebang, module invocation, usage flag). |
|
|
||||||
| Sprint 10 | Scanner Analyzers & SBOM | src/StellaOps.Scanner.EntryTrace/TASKS.md | DONE (2025-10-19) | EntryTrace Guild | SCANNER-ENTRYTRACE-10-405 | Node/Java launcher analyzer capturing script/jar targets. |
|
|
||||||
| Sprint 10 | Scanner Analyzers & SBOM | src/StellaOps.Scanner.EntryTrace/TASKS.md | DONE (2025-10-19) | EntryTrace Guild | SCANNER-ENTRYTRACE-10-406 | Explainability + diagnostics for unresolved constructs with metrics. |
|
|
||||||
| Sprint 10 | Scanner Analyzers & SBOM | src/StellaOps.Scanner.EntryTrace/TASKS.md | DONE (2025-10-19) | EntryTrace Guild | SCANNER-ENTRYTRACE-10-407 | Package EntryTrace analyzers as restart-time plug-ins (manifest + host registration). |
|
|
||||||
| Sprint 10 | Scanner Analyzers & SBOM | src/StellaOps.Scanner.Diff/TASKS.md | DONE (2025-10-19) | Diff Guild | SCANNER-DIFF-10-501 | Build component differ tracking add/remove/version changes with deterministic ordering. |
|
|
||||||
| Sprint 10 | Scanner Analyzers & SBOM | src/StellaOps.Scanner.Diff/TASKS.md | DONE (2025-10-19) | Diff Guild | SCANNER-DIFF-10-502 | Attribute diffs to introducing/removing layers including provenance evidence. |
|
|
||||||
| Sprint 10 | Scanner Analyzers & SBOM | src/StellaOps.Scanner.Diff/TASKS.md | DONE (2025-10-19) | Diff Guild | SCANNER-DIFF-10-503 | Produce JSON diff output for inventory vs usage views aligned with API contract. |
|
|
||||||
| Sprint 10 | Samples | samples/TASKS.md | DONE (2025-10-20) | Samples Guild, Scanner Team | SAMPLES-10-001 | Sample images with SBOM/BOM-Index sidecars. |
|
|
||||||
| Sprint 10 | DevOps Perf | ops/devops/TASKS.md | DONE (2025-10-22) | DevOps Guild | DEVOPS-PERF-10-001 | Perf smoke job ensuring <5 s SBOM compose. |
|
|
||||||
| Sprint 10 | DevOps Perf | ops/devops/TASKS.md | DONE (2025-10-23) | DevOps Guild | DEVOPS-PERF-10-002 | Publish analyzer bench metrics to Grafana/perf workbook and alarm on ≥20 % regressions. |
|
|
||||||
| Sprint 10 | Policy Samples | samples/TASKS.md | DONE (2025-10-23) | Samples Guild, Policy Guild | SAMPLES-13-004 | Add policy preview/report fixtures showing confidence bands and unknown-age tags. |
|
|
||||||
| Sprint 10 | Policy Samples | src/StellaOps.Web/TASKS.md | DONE (2025-10-23) | UI Guild | WEB-POLICY-FIXTURES-10-001 | Wire policy preview/report doc fixtures into UI harness (test utility or Storybook substitute) with type bindings and validation guard so UI stays aligned with documented payloads. |
|
|
||||||
| Sprint 11 | Signing Chain Bring-up | src/StellaOps.Signer/TASKS.md | DONE (2025-10-21) | Signer Guild | SIGNER-API-11-101 | `/sign/dsse` pipeline with Authority auth, PoE introspection, release verification, DSSE signing. |
|
|
||||||
| Sprint 11 | Signing Chain Bring-up | src/StellaOps.Signer/TASKS.md | DONE (2025-10-21) | Signer Guild | SIGNER-REF-11-102 | `/verify/referrers` endpoint with OCI lookup, caching, and policy enforcement. |
|
|
||||||
| Sprint 11 | Signing Chain Bring-up | src/StellaOps.Signer/TASKS.md | DONE (2025-10-21) | Signer Guild | SIGNER-QUOTA-11-103 | Enforce plan quotas, concurrency/QPS limits, artifact size caps with metrics/audit logs. |
|
|
||||||
| Sprint 11 | Signing Chain Bring-up | src/StellaOps.Authority/TASKS.md | DONE (2025-10-23) | Authority Core & Security Guild | AUTH-MTLS-11-002 | Add OAuth mTLS client credential support with certificate-bound tokens and introspection updates. |
|
|
||||||
| Sprint 12 | Runtime Guardrails | src/StellaOps.Scanner.WebService/TASKS.md | DONE (2025-10-20) | Scanner WebService Guild | SCANNER-RUNTIME-12-301 | `/runtime/events` ingestion endpoint with validation, batching, storage hooks. |
|
|
||||||
| Sprint 13 | UX & CLI Experience | src/StellaOps.Cli/TASKS.md | DONE (2025-10-21) | DevEx/CLI | CLI-OFFLINE-13-006 | Implement offline kit pull/import/status commands with integrity checks. |
|
|
||||||
| Sprint 13 | UX & CLI Experience | src/StellaOps.Cli/TASKS.md | DONE (2025-10-22) | DevEx/CLI | CLI-PLUGIN-13-007 | Package non-core CLI verbs as restart-time plug-ins (manifest + loader tests). |
|
|
||||||
| Sprint 13 | UX & CLI Experience | src/StellaOps.Web/TASKS.md | DONE (2025-10-21) | UX Specialist, Angular Eng, DevEx | WEB1.DEPS-13-001 | Stabilise Angular workspace dependencies for headless CI installs (`npm install`, Chromium handling, docs). |
|
|
||||||
| Sprint 16 | Scheduler Intelligence | src/StellaOps.Scheduler.Queue/TASKS.md | DONE (2025-10-20) | Scheduler Queue Guild | SCHED-QUEUE-16-403 | Dead-letter handling + metrics. |
|
|
||||||
| Sprint 18 | Launch Readiness | ops/offline-kit/TASKS.md | DONE (2025-10-22) | Offline Kit Guild, Scanner Guild | DEVOPS-OFFLINE-18-004 | Rebuild Offline Kit bundle with Go analyzer plug-in and refreshed manifest/signature set. |
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
This file describe implementation of Stella Ops (docs/README.md). Implementation must respect rules from AGENTS.md (read if you have not).
|
|
||||||
|
|
||||||
| Sprint | Theme | Tasks File Path | Status | Type of Specialist | Task ID | Task Description |
|
|
||||||
| --- | --- | --- | --- | --- | --- | --- |
|
|
||||||
| Sprint 11 | Signing Chain Bring-up | src/StellaOps.Attestor/TASKS.md | DONE (2025-10-19) | Attestor Guild | ATTESTOR-API-11-201 | `/rekor/entries` submission pipeline with dedupe, proof acquisition, and persistence. |
|
|
||||||
| Sprint 11 | Signing Chain Bring-up | src/StellaOps.Attestor/TASKS.md | DONE (2025-10-19) | Attestor Guild | ATTESTOR-VERIFY-11-202 | `/rekor/verify` + retrieval endpoints validating signatures and Merkle proofs. |
|
|
||||||
| Sprint 11 | Signing Chain Bring-up | src/StellaOps.Attestor/TASKS.md | DONE (2025-10-19) | Attestor Guild | ATTESTOR-OBS-11-203 | Telemetry, alerting, mTLS hardening, and archive workflow for Attestor. |
|
|
||||||
| Sprint 11 | Storage Platform Hardening | src/StellaOps.Scanner.Storage/TASKS.md | DONE (2025-10-23) | Scanner Storage Guild | SCANNER-STORAGE-11-401 | Migrate scanner object storage integration from MinIO to RustFS with data migration plan. |
|
|
||||||
| Sprint 11 | UI Integration | src/StellaOps.UI/TASKS.md | DONE (2025-10-23) | UI Guild | UI-ATTEST-11-005 | Attestation visibility (Rekor id, status) on Scan Detail. |
|
|
||||||
| Sprint 12 | Runtime Guardrails | src/StellaOps.Zastava.Core/TASKS.md | DONE (2025-10-23) | Zastava Core Guild | ZASTAVA-CORE-12-201 | Define runtime event/admission DTOs, hashing helpers, and versioning strategy. |
|
|
||||||
| Sprint 12 | Runtime Guardrails | src/StellaOps.Zastava.Core/TASKS.md | DONE (2025-10-23) | Zastava Core Guild | ZASTAVA-CORE-12-202 | Provide configuration/logging/metrics utilities shared by Observer/Webhook. |
|
|
||||||
| Sprint 12 | Runtime Guardrails | src/StellaOps.Zastava.Core/TASKS.md | DONE (2025-10-23) | Zastava Core Guild | ZASTAVA-CORE-12-203 | Authority client helpers, OpTok caching, and security guardrails for runtime services. |
|
|
||||||
| Sprint 12 | Runtime Guardrails | src/StellaOps.Zastava.Core/TASKS.md | DONE (2025-10-23) | Zastava Core Guild | ZASTAVA-OPS-12-204 | Operational runbooks, alert rules, and dashboard exports for runtime plane. |
|
|
||||||
| Sprint 12 | Runtime Guardrails | src/StellaOps.Zastava.Observer/TASKS.md | DONE (2025-10-24) | Zastava Observer Guild | ZASTAVA-OBS-12-001 | Container lifecycle watcher emitting deterministic runtime events with buffering. |
|
|
||||||
| Sprint 12 | Runtime Guardrails | src/StellaOps.Zastava.Observer/TASKS.md | DONE (2025-10-24) | Zastava Observer Guild | ZASTAVA-OBS-12-002 | Capture entrypoint traces + loaded libraries, hashing binaries and linking to baseline SBOM. |
|
|
||||||
| Sprint 12 | Runtime Guardrails | src/StellaOps.Zastava.Observer/TASKS.md | DONE (2025-10-24) | Zastava Observer Guild | ZASTAVA-OBS-12-003 | Posture checks for signatures/SBOM/attestation with offline caching. |
|
|
||||||
| Sprint 12 | Runtime Guardrails | src/StellaOps.Zastava.Observer/TASKS.md | DONE (2025-10-24) | Zastava Observer Guild | ZASTAVA-OBS-12-004 | Batch `/runtime/events` submissions with disk-backed buffer and rate limits. |
|
|
||||||
| Sprint 12 | Runtime Guardrails | src/StellaOps.Zastava.Webhook/TASKS.md | DONE (2025-10-24) | Zastava Webhook Guild | ZASTAVA-WEBHOOK-12-101 | Admission controller host with TLS bootstrap and Authority auth. |
|
|
||||||
| Sprint 12 | Runtime Guardrails | src/StellaOps.Zastava.Webhook/TASKS.md | DONE (2025-10-24) | Zastava Webhook Guild | ZASTAVA-WEBHOOK-12-102 | Query Scanner `/policy/runtime`, resolve digests, enforce verdicts. |
|
|
||||||
| Sprint 12 | Runtime Guardrails | src/StellaOps.Zastava.Webhook/TASKS.md | DONE (2025-10-24) | Zastava Webhook Guild | ZASTAVA-WEBHOOK-12-103 | Caching, fail-open/closed toggles, metrics/logging for admission decisions. |
|
|
||||||
| Sprint 12 | Runtime Guardrails | src/StellaOps.Zastava.Webhook/TASKS.md | DONE (2025-10-24) | Zastava Webhook Guild | ZASTAVA-WEBHOOK-12-104 | Wire `/admission` endpoint to runtime policy client and emit allow/deny envelopes. |
|
|
||||||
| Sprint 12 | Runtime Guardrails | src/StellaOps.Scanner.WebService/TASKS.md | DONE (2025-10-24) | Scanner WebService Guild | SCANNER-RUNTIME-12-302 | `/policy/runtime` endpoint joining SBOM baseline + policy verdict, returning admission guidance. |
|
|
||||||
| Sprint 12 | Runtime Guardrails | src/StellaOps.Scanner.WebService/TASKS.md | DONE (2025-10-24) | Scanner WebService Guild | SCANNER-RUNTIME-12-303 | Align `/policy/runtime` verdicts with canonical policy evaluation (Feedser/Vexer). |
|
|
||||||
| Sprint 12 | Runtime Guardrails | src/StellaOps.Scanner.WebService/TASKS.md | DONE (2025-10-24) | Scanner WebService Guild | SCANNER-RUNTIME-12-304 | Integrate attestation verification into runtime policy metadata. |
|
|
||||||
| Sprint 12 | Runtime Guardrails | src/StellaOps.Scanner.WebService/TASKS.md | DONE (2025-10-24) | Scanner WebService Guild | SCANNER-RUNTIME-12-305 | Deliver shared fixtures + e2e validation with Zastava/CLI teams. |
|
|
||||||
| Sprint 13 | UX & CLI Experience | src/StellaOps.UI/TASKS.md | DONE (2025-10-23) | UI Guild | UI-AUTH-13-001 | Integrate Authority OIDC + DPoP flows with session management. |
|
|
||||||
| Sprint 13 | UX & CLI Experience | src/StellaOps.UI/TASKS.md | DONE (2025-10-25) | UI Guild | UI-NOTIFY-13-006 | Notify panel: channels/rules CRUD, deliveries view, test send. |
|
|
||||||
| Sprint 13 | Platform Reliability | ops/devops/TASKS.md | DONE (2025-10-25) | DevOps Guild, Platform Leads | DEVOPS-NUGET-13-001 | Wire up .NET 10 preview feeds/local mirrors so `dotnet restore` succeeds offline; document updated NuGet bootstrap. |
|
|
||||||
| Sprint 15 | Notify Foundations | src/StellaOps.Notify.Queue/TASKS.md | DONE (2025-10-23) | Notify Queue Guild | NOTIFY-QUEUE-15-401 | Bus abstraction + Redis Streams adapter with ordering/idempotency. |
|
|
||||||
| Sprint 15 | Notify Foundations | src/StellaOps.Notify.Queue/TASKS.md | DONE (2025-10-23) | Notify Queue Guild | NOTIFY-QUEUE-15-402 | NATS JetStream adapter with health probes and failover. |
|
|
||||||
| Sprint 15 | Notify Foundations | src/StellaOps.Notify.Queue/TASKS.md | DONE (2025-10-23) | Notify Queue Guild | NOTIFY-QUEUE-15-403 | Delivery queue with retry/dead-letter + metrics. |
|
|
||||||
| Sprint 15 | Notify Foundations | src/StellaOps.Notify.Worker/TASKS.md | DONE (2025-10-23) | Notify Worker Guild | NOTIFY-WORKER-15-201 | Bus subscription + leasing loop with backoff. |
|
|
||||||
| Sprint 17 | Symbol Intelligence & Forensics | src/StellaOps.Zastava.Observer/TASKS.md | DONE (2025-10-25) | Zastava Observer Guild | ZASTAVA-OBS-17-005 | Collect GNU build-id during runtime observation and attach it to emitted events. |
|
|
||||||
| Sprint 17 | Symbol Intelligence & Forensics | src/StellaOps.Scanner.WebService/TASKS.md | DONE (2025-10-25) | Scanner WebService Guild | SCANNER-RUNTIME-17-401 | Persist runtime build-id observations and expose them for debug-symbol correlation. |
|
|
||||||
@@ -1,180 +1,180 @@
|
|||||||
x-release-labels: &release-labels
|
x-release-labels: &release-labels
|
||||||
com.stellaops.release.version: "2025.09.2"
|
com.stellaops.release.version: "2025.09.2"
|
||||||
com.stellaops.release.channel: "stable"
|
com.stellaops.release.channel: "stable"
|
||||||
com.stellaops.profile: "prod"
|
com.stellaops.profile: "prod"
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
stellaops:
|
stellaops:
|
||||||
driver: bridge
|
driver: bridge
|
||||||
frontdoor:
|
frontdoor:
|
||||||
external: true
|
external: true
|
||||||
name: ${FRONTDOOR_NETWORK:-stellaops_frontdoor}
|
name: ${FRONTDOOR_NETWORK:-stellaops_frontdoor}
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
mongo-data:
|
mongo-data:
|
||||||
minio-data:
|
minio-data:
|
||||||
rustfs-data:
|
rustfs-data:
|
||||||
concelier-jobs:
|
concelier-jobs:
|
||||||
nats-data:
|
nats-data:
|
||||||
|
|
||||||
services:
|
services:
|
||||||
mongo:
|
mongo:
|
||||||
image: docker.io/library/mongo@sha256:c258b26dbb7774f97f52aff52231ca5f228273a84329c5f5e451c3739457db49
|
image: docker.io/library/mongo@sha256:c258b26dbb7774f97f52aff52231ca5f228273a84329c5f5e451c3739457db49
|
||||||
command: ["mongod", "--bind_ip_all"]
|
command: ["mongod", "--bind_ip_all"]
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
environment:
|
environment:
|
||||||
MONGO_INITDB_ROOT_USERNAME: "${MONGO_INITDB_ROOT_USERNAME}"
|
MONGO_INITDB_ROOT_USERNAME: "${MONGO_INITDB_ROOT_USERNAME}"
|
||||||
MONGO_INITDB_ROOT_PASSWORD: "${MONGO_INITDB_ROOT_PASSWORD}"
|
MONGO_INITDB_ROOT_PASSWORD: "${MONGO_INITDB_ROOT_PASSWORD}"
|
||||||
volumes:
|
volumes:
|
||||||
- mongo-data:/data/db
|
- mongo-data:/data/db
|
||||||
networks:
|
networks:
|
||||||
- stellaops
|
- stellaops
|
||||||
labels: *release-labels
|
labels: *release-labels
|
||||||
|
|
||||||
minio:
|
minio:
|
||||||
image: docker.io/minio/minio@sha256:14cea493d9a34af32f524e538b8346cf79f3321eff8e708c1e2960462bd8936e
|
image: docker.io/minio/minio@sha256:14cea493d9a34af32f524e538b8346cf79f3321eff8e708c1e2960462bd8936e
|
||||||
command: ["server", "/data", "--console-address", ":9001"]
|
command: ["server", "/data", "--console-address", ":9001"]
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
environment:
|
environment:
|
||||||
MINIO_ROOT_USER: "${MINIO_ROOT_USER}"
|
MINIO_ROOT_USER: "${MINIO_ROOT_USER}"
|
||||||
MINIO_ROOT_PASSWORD: "${MINIO_ROOT_PASSWORD}"
|
MINIO_ROOT_PASSWORD: "${MINIO_ROOT_PASSWORD}"
|
||||||
volumes:
|
volumes:
|
||||||
- minio-data:/data
|
- minio-data:/data
|
||||||
ports:
|
ports:
|
||||||
- "${MINIO_CONSOLE_PORT:-9001}:9001"
|
- "${MINIO_CONSOLE_PORT:-9001}:9001"
|
||||||
networks:
|
networks:
|
||||||
- stellaops
|
- stellaops
|
||||||
labels: *release-labels
|
labels: *release-labels
|
||||||
|
|
||||||
rustfs:
|
rustfs:
|
||||||
image: registry.stella-ops.org/stellaops/rustfs:2025.10.0-edge
|
image: registry.stella-ops.org/stellaops/rustfs:2025.10.0-edge
|
||||||
command: ["serve", "--listen", "0.0.0.0:8080", "--root", "/data"]
|
command: ["serve", "--listen", "0.0.0.0:8080", "--root", "/data"]
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
environment:
|
environment:
|
||||||
RUSTFS__LOG__LEVEL: info
|
RUSTFS__LOG__LEVEL: info
|
||||||
RUSTFS__STORAGE__PATH: /data
|
RUSTFS__STORAGE__PATH: /data
|
||||||
volumes:
|
volumes:
|
||||||
- rustfs-data:/data
|
- rustfs-data:/data
|
||||||
ports:
|
ports:
|
||||||
- "${RUSTFS_HTTP_PORT:-8080}:8080"
|
- "${RUSTFS_HTTP_PORT:-8080}:8080"
|
||||||
networks:
|
networks:
|
||||||
- stellaops
|
- stellaops
|
||||||
labels: *release-labels
|
labels: *release-labels
|
||||||
|
|
||||||
nats:
|
nats:
|
||||||
image: docker.io/library/nats@sha256:c82559e4476289481a8a5196e675ebfe67eea81d95e5161e3e78eccfe766608e
|
image: docker.io/library/nats@sha256:c82559e4476289481a8a5196e675ebfe67eea81d95e5161e3e78eccfe766608e
|
||||||
command:
|
command:
|
||||||
- "-js"
|
- "-js"
|
||||||
- "-sd"
|
- "-sd"
|
||||||
- /data
|
- /data
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
ports:
|
ports:
|
||||||
- "${NATS_CLIENT_PORT:-4222}:4222"
|
- "${NATS_CLIENT_PORT:-4222}:4222"
|
||||||
volumes:
|
volumes:
|
||||||
- nats-data:/data
|
- nats-data:/data
|
||||||
networks:
|
networks:
|
||||||
- stellaops
|
- stellaops
|
||||||
labels: *release-labels
|
labels: *release-labels
|
||||||
|
|
||||||
authority:
|
authority:
|
||||||
image: registry.stella-ops.org/stellaops/authority@sha256:b0348bad1d0b401cc3c71cb40ba034c8043b6c8874546f90d4783c9dbfcc0bf5
|
image: registry.stella-ops.org/stellaops/authority@sha256:b0348bad1d0b401cc3c71cb40ba034c8043b6c8874546f90d4783c9dbfcc0bf5
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
depends_on:
|
depends_on:
|
||||||
- mongo
|
- mongo
|
||||||
environment:
|
environment:
|
||||||
STELLAOPS_AUTHORITY__ISSUER: "${AUTHORITY_ISSUER}"
|
STELLAOPS_AUTHORITY__ISSUER: "${AUTHORITY_ISSUER}"
|
||||||
STELLAOPS_AUTHORITY__MONGO__CONNECTIONSTRING: "mongodb://${MONGO_INITDB_ROOT_USERNAME}:${MONGO_INITDB_ROOT_PASSWORD}@mongo:27017"
|
STELLAOPS_AUTHORITY__MONGO__CONNECTIONSTRING: "mongodb://${MONGO_INITDB_ROOT_USERNAME}:${MONGO_INITDB_ROOT_PASSWORD}@mongo:27017"
|
||||||
STELLAOPS_AUTHORITY__PLUGINDIRECTORIES__0: "/app/plugins"
|
STELLAOPS_AUTHORITY__PLUGINDIRECTORIES__0: "/app/plugins"
|
||||||
STELLAOPS_AUTHORITY__PLUGINS__CONFIGURATIONDIRECTORY: "/app/etc/authority.plugins"
|
STELLAOPS_AUTHORITY__PLUGINS__CONFIGURATIONDIRECTORY: "/app/etc/authority.plugins"
|
||||||
volumes:
|
volumes:
|
||||||
- ../../etc/authority.yaml:/etc/authority.yaml:ro
|
- ../../etc/authority.yaml:/etc/authority.yaml:ro
|
||||||
- ../../etc/authority.plugins:/app/etc/authority.plugins:ro
|
- ../../etc/authority.plugins:/app/etc/authority.plugins:ro
|
||||||
ports:
|
ports:
|
||||||
- "${AUTHORITY_PORT:-8440}:8440"
|
- "${AUTHORITY_PORT:-8440}:8440"
|
||||||
networks:
|
networks:
|
||||||
- stellaops
|
- stellaops
|
||||||
- frontdoor
|
- frontdoor
|
||||||
labels: *release-labels
|
labels: *release-labels
|
||||||
|
|
||||||
signer:
|
signer:
|
||||||
image: registry.stella-ops.org/stellaops/signer@sha256:8ad574e61f3a9e9bda8a58eb2700ae46813284e35a150b1137bc7c2b92ac0f2e
|
image: registry.stella-ops.org/stellaops/signer@sha256:8ad574e61f3a9e9bda8a58eb2700ae46813284e35a150b1137bc7c2b92ac0f2e
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
depends_on:
|
depends_on:
|
||||||
- authority
|
- authority
|
||||||
environment:
|
environment:
|
||||||
SIGNER__AUTHORITY__BASEURL: "https://authority:8440"
|
SIGNER__AUTHORITY__BASEURL: "https://authority:8440"
|
||||||
SIGNER__POE__INTROSPECTURL: "${SIGNER_POE_INTROSPECT_URL}"
|
SIGNER__POE__INTROSPECTURL: "${SIGNER_POE_INTROSPECT_URL}"
|
||||||
SIGNER__STORAGE__MONGO__CONNECTIONSTRING: "mongodb://${MONGO_INITDB_ROOT_USERNAME}:${MONGO_INITDB_ROOT_PASSWORD}@mongo:27017"
|
SIGNER__STORAGE__MONGO__CONNECTIONSTRING: "mongodb://${MONGO_INITDB_ROOT_USERNAME}:${MONGO_INITDB_ROOT_PASSWORD}@mongo:27017"
|
||||||
ports:
|
ports:
|
||||||
- "${SIGNER_PORT:-8441}:8441"
|
- "${SIGNER_PORT:-8441}:8441"
|
||||||
networks:
|
networks:
|
||||||
- stellaops
|
- stellaops
|
||||||
- frontdoor
|
- frontdoor
|
||||||
labels: *release-labels
|
labels: *release-labels
|
||||||
|
|
||||||
attestor:
|
attestor:
|
||||||
image: registry.stella-ops.org/stellaops/attestor@sha256:0534985f978b0b5d220d73c96fddd962cd9135f616811cbe3bff4666c5af568f
|
image: registry.stella-ops.org/stellaops/attestor@sha256:0534985f978b0b5d220d73c96fddd962cd9135f616811cbe3bff4666c5af568f
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
depends_on:
|
depends_on:
|
||||||
- signer
|
- signer
|
||||||
environment:
|
environment:
|
||||||
ATTESTOR__SIGNER__BASEURL: "https://signer:8441"
|
ATTESTOR__SIGNER__BASEURL: "https://signer:8441"
|
||||||
ATTESTOR__MONGO__CONNECTIONSTRING: "mongodb://${MONGO_INITDB_ROOT_USERNAME}:${MONGO_INITDB_ROOT_PASSWORD}@mongo:27017"
|
ATTESTOR__MONGO__CONNECTIONSTRING: "mongodb://${MONGO_INITDB_ROOT_USERNAME}:${MONGO_INITDB_ROOT_PASSWORD}@mongo:27017"
|
||||||
ports:
|
ports:
|
||||||
- "${ATTESTOR_PORT:-8442}:8442"
|
- "${ATTESTOR_PORT:-8442}:8442"
|
||||||
networks:
|
networks:
|
||||||
- stellaops
|
- stellaops
|
||||||
- frontdoor
|
- frontdoor
|
||||||
labels: *release-labels
|
labels: *release-labels
|
||||||
|
|
||||||
concelier:
|
concelier:
|
||||||
image: registry.stella-ops.org/stellaops/concelier@sha256:c58cdcaee1d266d68d498e41110a589dd204b487d37381096bd61ab345a867c5
|
image: registry.stella-ops.org/stellaops/concelier@sha256:c58cdcaee1d266d68d498e41110a589dd204b487d37381096bd61ab345a867c5
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
depends_on:
|
depends_on:
|
||||||
- mongo
|
- mongo
|
||||||
- minio
|
- minio
|
||||||
environment:
|
environment:
|
||||||
CONCELIER__STORAGE__MONGO__CONNECTIONSTRING: "mongodb://${MONGO_INITDB_ROOT_USERNAME}:${MONGO_INITDB_ROOT_PASSWORD}@mongo:27017"
|
CONCELIER__STORAGE__MONGO__CONNECTIONSTRING: "mongodb://${MONGO_INITDB_ROOT_USERNAME}:${MONGO_INITDB_ROOT_PASSWORD}@mongo:27017"
|
||||||
CONCELIER__STORAGE__S3__ENDPOINT: "http://minio:9000"
|
CONCELIER__STORAGE__S3__ENDPOINT: "http://minio:9000"
|
||||||
CONCELIER__STORAGE__S3__ACCESSKEYID: "${MINIO_ROOT_USER}"
|
CONCELIER__STORAGE__S3__ACCESSKEYID: "${MINIO_ROOT_USER}"
|
||||||
CONCELIER__STORAGE__S3__SECRETACCESSKEY: "${MINIO_ROOT_PASSWORD}"
|
CONCELIER__STORAGE__S3__SECRETACCESSKEY: "${MINIO_ROOT_PASSWORD}"
|
||||||
CONCELIER__AUTHORITY__BASEURL: "https://authority:8440"
|
CONCELIER__AUTHORITY__BASEURL: "https://authority:8440"
|
||||||
volumes:
|
volumes:
|
||||||
- concelier-jobs:/var/lib/concelier/jobs
|
- concelier-jobs:/var/lib/concelier/jobs
|
||||||
ports:
|
ports:
|
||||||
- "${CONCELIER_PORT:-8445}:8445"
|
- "${CONCELIER_PORT:-8445}:8445"
|
||||||
networks:
|
networks:
|
||||||
- stellaops
|
- stellaops
|
||||||
- frontdoor
|
- frontdoor
|
||||||
labels: *release-labels
|
labels: *release-labels
|
||||||
|
|
||||||
scanner-web:
|
scanner-web:
|
||||||
image: registry.stella-ops.org/stellaops/scanner-web@sha256:14b23448c3f9586a9156370b3e8c1991b61907efa666ca37dd3aaed1e79fe3b7
|
image: registry.stella-ops.org/stellaops/scanner-web@sha256:14b23448c3f9586a9156370b3e8c1991b61907efa666ca37dd3aaed1e79fe3b7
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
depends_on:
|
depends_on:
|
||||||
- concelier
|
- concelier
|
||||||
- rustfs
|
- rustfs
|
||||||
- nats
|
- nats
|
||||||
environment:
|
environment:
|
||||||
SCANNER__STORAGE__MONGO__CONNECTIONSTRING: "mongodb://${MONGO_INITDB_ROOT_USERNAME}:${MONGO_INITDB_ROOT_PASSWORD}@mongo:27017"
|
SCANNER__STORAGE__MONGO__CONNECTIONSTRING: "mongodb://${MONGO_INITDB_ROOT_USERNAME}:${MONGO_INITDB_ROOT_PASSWORD}@mongo:27017"
|
||||||
SCANNER__ARTIFACTSTORE__DRIVER: "rustfs"
|
SCANNER__ARTIFACTSTORE__DRIVER: "rustfs"
|
||||||
SCANNER__ARTIFACTSTORE__ENDPOINT: "http://rustfs:8080/api/v1"
|
SCANNER__ARTIFACTSTORE__ENDPOINT: "http://rustfs:8080/api/v1"
|
||||||
SCANNER__ARTIFACTSTORE__BUCKET: "scanner-artifacts"
|
SCANNER__ARTIFACTSTORE__BUCKET: "scanner-artifacts"
|
||||||
SCANNER__ARTIFACTSTORE__TIMEOUTSECONDS: "30"
|
SCANNER__ARTIFACTSTORE__TIMEOUTSECONDS: "30"
|
||||||
SCANNER__QUEUE__BROKER: "${SCANNER_QUEUE_BROKER}"
|
SCANNER__QUEUE__BROKER: "${SCANNER_QUEUE_BROKER}"
|
||||||
SCANNER__EVENTS__ENABLED: "${SCANNER_EVENTS_ENABLED:-true}"
|
SCANNER__EVENTS__ENABLED: "${SCANNER_EVENTS_ENABLED:-true}"
|
||||||
SCANNER__EVENTS__DRIVER: "${SCANNER_EVENTS_DRIVER:-redis}"
|
SCANNER__EVENTS__DRIVER: "${SCANNER_EVENTS_DRIVER:-redis}"
|
||||||
SCANNER__EVENTS__DSN: "${SCANNER_EVENTS_DSN:-}"
|
SCANNER__EVENTS__DSN: "${SCANNER_EVENTS_DSN:-}"
|
||||||
SCANNER__EVENTS__STREAM: "${SCANNER_EVENTS_STREAM:-stella.events}"
|
SCANNER__EVENTS__STREAM: "${SCANNER_EVENTS_STREAM:-stella.events}"
|
||||||
SCANNER__EVENTS__PUBLISHTIMEOUTSECONDS: "${SCANNER_EVENTS_PUBLISH_TIMEOUT_SECONDS:-5}"
|
SCANNER__EVENTS__PUBLISHTIMEOUTSECONDS: "${SCANNER_EVENTS_PUBLISH_TIMEOUT_SECONDS:-5}"
|
||||||
SCANNER__EVENTS__MAXSTREAMLENGTH: "${SCANNER_EVENTS_MAX_STREAM_LENGTH:-10000}"
|
SCANNER__EVENTS__MAXSTREAMLENGTH: "${SCANNER_EVENTS_MAX_STREAM_LENGTH:-10000}"
|
||||||
ports:
|
ports:
|
||||||
- "${SCANNER_WEB_PORT:-8444}:8444"
|
- "${SCANNER_WEB_PORT:-8444}:8444"
|
||||||
networks:
|
networks:
|
||||||
- stellaops
|
- stellaops
|
||||||
- frontdoor
|
- frontdoor
|
||||||
labels: *release-labels
|
labels: *release-labels
|
||||||
|
|
||||||
scanner-worker:
|
scanner-worker:
|
||||||
image: registry.stella-ops.org/stellaops/scanner-worker@sha256:32e25e76386eb9ea8bee0a1ad546775db9a2df989fab61ac877e351881960dab
|
image: registry.stella-ops.org/stellaops/scanner-worker@sha256:32e25e76386eb9ea8bee0a1ad546775db9a2df989fab61ac877e351881960dab
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
@@ -212,46 +212,46 @@ services:
|
|||||||
networks:
|
networks:
|
||||||
- stellaops
|
- stellaops
|
||||||
labels: *release-labels
|
labels: *release-labels
|
||||||
|
|
||||||
notify-web:
|
notify-web:
|
||||||
image: ${NOTIFY_WEB_IMAGE:-registry.stella-ops.org/stellaops/notify-web:2025.09.2}
|
image: ${NOTIFY_WEB_IMAGE:-registry.stella-ops.org/stellaops/notify-web:2025.09.2}
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
depends_on:
|
depends_on:
|
||||||
- mongo
|
- mongo
|
||||||
- authority
|
- authority
|
||||||
environment:
|
environment:
|
||||||
DOTNET_ENVIRONMENT: Production
|
DOTNET_ENVIRONMENT: Production
|
||||||
volumes:
|
volumes:
|
||||||
- ../../etc/notify.prod.yaml:/app/etc/notify.yaml:ro
|
- ../../etc/notify.prod.yaml:/app/etc/notify.yaml:ro
|
||||||
ports:
|
ports:
|
||||||
- "${NOTIFY_WEB_PORT:-8446}:8446"
|
- "${NOTIFY_WEB_PORT:-8446}:8446"
|
||||||
networks:
|
networks:
|
||||||
- stellaops
|
- stellaops
|
||||||
- frontdoor
|
- frontdoor
|
||||||
labels: *release-labels
|
labels: *release-labels
|
||||||
|
|
||||||
excititor:
|
excititor:
|
||||||
image: registry.stella-ops.org/stellaops/excititor@sha256:59022e2016aebcef5c856d163ae705755d3f81949d41195256e935ef40a627fa
|
image: registry.stella-ops.org/stellaops/excititor@sha256:59022e2016aebcef5c856d163ae705755d3f81949d41195256e935ef40a627fa
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
depends_on:
|
depends_on:
|
||||||
- concelier
|
- concelier
|
||||||
environment:
|
environment:
|
||||||
EXCITITOR__CONCELIER__BASEURL: "https://concelier:8445"
|
EXCITITOR__CONCELIER__BASEURL: "https://concelier:8445"
|
||||||
EXCITITOR__STORAGE__MONGO__CONNECTIONSTRING: "mongodb://${MONGO_INITDB_ROOT_USERNAME}:${MONGO_INITDB_ROOT_PASSWORD}@mongo:27017"
|
EXCITITOR__STORAGE__MONGO__CONNECTIONSTRING: "mongodb://${MONGO_INITDB_ROOT_USERNAME}:${MONGO_INITDB_ROOT_PASSWORD}@mongo:27017"
|
||||||
networks:
|
networks:
|
||||||
- stellaops
|
- stellaops
|
||||||
labels: *release-labels
|
labels: *release-labels
|
||||||
|
|
||||||
web-ui:
|
web-ui:
|
||||||
image: registry.stella-ops.org/stellaops/web-ui@sha256:10d924808c48e4353e3a241da62eb7aefe727a1d6dc830eb23a8e181013b3a23
|
image: registry.stella-ops.org/stellaops/web-ui@sha256:10d924808c48e4353e3a241da62eb7aefe727a1d6dc830eb23a8e181013b3a23
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
depends_on:
|
depends_on:
|
||||||
- scanner-web
|
- scanner-web
|
||||||
environment:
|
environment:
|
||||||
STELLAOPS_UI__BACKEND__BASEURL: "https://scanner-web:8444"
|
STELLAOPS_UI__BACKEND__BASEURL: "https://scanner-web:8444"
|
||||||
ports:
|
ports:
|
||||||
- "${UI_PORT:-8443}:8443"
|
- "${UI_PORT:-8443}:8443"
|
||||||
networks:
|
networks:
|
||||||
- stellaops
|
- stellaops
|
||||||
- frontdoor
|
- frontdoor
|
||||||
labels: *release-labels
|
labels: *release-labels
|
||||||
|
|||||||
@@ -1,57 +1,57 @@
|
|||||||
version: "3.9"
|
version: "3.9"
|
||||||
|
|
||||||
services:
|
services:
|
||||||
prometheus:
|
prometheus:
|
||||||
image: prom/prometheus:v2.53.0
|
image: prom/prometheus:v2.53.0
|
||||||
container_name: stellaops-prometheus
|
container_name: stellaops-prometheus
|
||||||
command:
|
command:
|
||||||
- "--config.file=/etc/prometheus/prometheus.yaml"
|
- "--config.file=/etc/prometheus/prometheus.yaml"
|
||||||
volumes:
|
volumes:
|
||||||
- ../telemetry/storage/prometheus.yaml:/etc/prometheus/prometheus.yaml:ro
|
- ../telemetry/storage/prometheus.yaml:/etc/prometheus/prometheus.yaml:ro
|
||||||
- prometheus-data:/prometheus
|
- prometheus-data:/prometheus
|
||||||
- ../telemetry/certs:/etc/telemetry/tls:ro
|
- ../telemetry/certs:/etc/telemetry/tls:ro
|
||||||
- ../telemetry/storage/auth:/etc/telemetry/auth:ro
|
- ../telemetry/storage/auth:/etc/telemetry/auth:ro
|
||||||
environment:
|
environment:
|
||||||
PROMETHEUS_COLLECTOR_TARGET: stellaops-otel-collector:9464
|
PROMETHEUS_COLLECTOR_TARGET: stellaops-otel-collector:9464
|
||||||
ports:
|
ports:
|
||||||
- "9090:9090"
|
- "9090:9090"
|
||||||
depends_on:
|
depends_on:
|
||||||
- tempo
|
- tempo
|
||||||
- loki
|
- loki
|
||||||
|
|
||||||
tempo:
|
tempo:
|
||||||
image: grafana/tempo:2.5.0
|
image: grafana/tempo:2.5.0
|
||||||
container_name: stellaops-tempo
|
container_name: stellaops-tempo
|
||||||
command:
|
command:
|
||||||
- "-config.file=/etc/tempo/tempo.yaml"
|
- "-config.file=/etc/tempo/tempo.yaml"
|
||||||
volumes:
|
volumes:
|
||||||
- ../telemetry/storage/tempo.yaml:/etc/tempo/tempo.yaml:ro
|
- ../telemetry/storage/tempo.yaml:/etc/tempo/tempo.yaml:ro
|
||||||
- ../telemetry/storage/tenants/tempo-overrides.yaml:/etc/telemetry/tenants/tempo-overrides.yaml:ro
|
- ../telemetry/storage/tenants/tempo-overrides.yaml:/etc/telemetry/tenants/tempo-overrides.yaml:ro
|
||||||
- ../telemetry/certs:/etc/telemetry/tls:ro
|
- ../telemetry/certs:/etc/telemetry/tls:ro
|
||||||
- tempo-data:/var/tempo
|
- tempo-data:/var/tempo
|
||||||
ports:
|
ports:
|
||||||
- "3200:3200"
|
- "3200:3200"
|
||||||
environment:
|
environment:
|
||||||
TEMPO_ZONE: docker
|
TEMPO_ZONE: docker
|
||||||
|
|
||||||
loki:
|
loki:
|
||||||
image: grafana/loki:3.1.0
|
image: grafana/loki:3.1.0
|
||||||
container_name: stellaops-loki
|
container_name: stellaops-loki
|
||||||
command:
|
command:
|
||||||
- "-config.file=/etc/loki/loki.yaml"
|
- "-config.file=/etc/loki/loki.yaml"
|
||||||
volumes:
|
volumes:
|
||||||
- ../telemetry/storage/loki.yaml:/etc/loki/loki.yaml:ro
|
- ../telemetry/storage/loki.yaml:/etc/loki/loki.yaml:ro
|
||||||
- ../telemetry/storage/tenants/loki-overrides.yaml:/etc/telemetry/tenants/loki-overrides.yaml:ro
|
- ../telemetry/storage/tenants/loki-overrides.yaml:/etc/telemetry/tenants/loki-overrides.yaml:ro
|
||||||
- ../telemetry/certs:/etc/telemetry/tls:ro
|
- ../telemetry/certs:/etc/telemetry/tls:ro
|
||||||
- loki-data:/var/loki
|
- loki-data:/var/loki
|
||||||
ports:
|
ports:
|
||||||
- "3100:3100"
|
- "3100:3100"
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
prometheus-data:
|
prometheus-data:
|
||||||
tempo-data:
|
tempo-data:
|
||||||
loki-data:
|
loki-data:
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
default:
|
default:
|
||||||
name: stellaops-telemetry
|
name: stellaops-telemetry
|
||||||
|
|||||||
@@ -1,34 +1,34 @@
|
|||||||
version: "3.9"
|
version: "3.9"
|
||||||
|
|
||||||
services:
|
services:
|
||||||
otel-collector:
|
otel-collector:
|
||||||
image: otel/opentelemetry-collector:0.105.0
|
image: otel/opentelemetry-collector:0.105.0
|
||||||
container_name: stellaops-otel-collector
|
container_name: stellaops-otel-collector
|
||||||
command:
|
command:
|
||||||
- "--config=/etc/otel-collector/config.yaml"
|
- "--config=/etc/otel-collector/config.yaml"
|
||||||
environment:
|
environment:
|
||||||
STELLAOPS_OTEL_TLS_CERT: /etc/otel-collector/tls/collector.crt
|
STELLAOPS_OTEL_TLS_CERT: /etc/otel-collector/tls/collector.crt
|
||||||
STELLAOPS_OTEL_TLS_KEY: /etc/otel-collector/tls/collector.key
|
STELLAOPS_OTEL_TLS_KEY: /etc/otel-collector/tls/collector.key
|
||||||
STELLAOPS_OTEL_TLS_CA: /etc/otel-collector/tls/ca.crt
|
STELLAOPS_OTEL_TLS_CA: /etc/otel-collector/tls/ca.crt
|
||||||
STELLAOPS_OTEL_PROMETHEUS_ENDPOINT: 0.0.0.0:9464
|
STELLAOPS_OTEL_PROMETHEUS_ENDPOINT: 0.0.0.0:9464
|
||||||
STELLAOPS_OTEL_REQUIRE_CLIENT_CERT: "true"
|
STELLAOPS_OTEL_REQUIRE_CLIENT_CERT: "true"
|
||||||
STELLAOPS_TENANT_ID: dev
|
STELLAOPS_TENANT_ID: dev
|
||||||
volumes:
|
volumes:
|
||||||
- ../telemetry/otel-collector-config.yaml:/etc/otel-collector/config.yaml:ro
|
- ../telemetry/otel-collector-config.yaml:/etc/otel-collector/config.yaml:ro
|
||||||
- ../telemetry/certs:/etc/otel-collector/tls:ro
|
- ../telemetry/certs:/etc/otel-collector/tls:ro
|
||||||
ports:
|
ports:
|
||||||
- "4317:4317" # OTLP gRPC (mTLS)
|
- "4317:4317" # OTLP gRPC (mTLS)
|
||||||
- "4318:4318" # OTLP HTTP (mTLS)
|
- "4318:4318" # OTLP HTTP (mTLS)
|
||||||
- "9464:9464" # Prometheus exporter (mTLS)
|
- "9464:9464" # Prometheus exporter (mTLS)
|
||||||
- "13133:13133" # Health check
|
- "13133:13133" # Health check
|
||||||
- "1777:1777" # pprof
|
- "1777:1777" # pprof
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "curl", "-fsk", "--cert", "/etc/otel-collector/tls/client.crt", "--key", "/etc/otel-collector/tls/client.key", "--cacert", "/etc/otel-collector/tls/ca.crt", "https://localhost:13133/healthz"]
|
test: ["CMD", "curl", "-fsk", "--cert", "/etc/otel-collector/tls/client.crt", "--key", "/etc/otel-collector/tls/client.key", "--cacert", "/etc/otel-collector/tls/ca.crt", "https://localhost:13133/healthz"]
|
||||||
interval: 30s
|
interval: 30s
|
||||||
start_period: 15s
|
start_period: 15s
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
retries: 3
|
retries: 3
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
default:
|
default:
|
||||||
name: stellaops-telemetry
|
name: stellaops-telemetry
|
||||||
|
|||||||
56
deploy/compose/env/prod.env.example
vendored
56
deploy/compose/env/prod.env.example
vendored
@@ -1,33 +1,33 @@
|
|||||||
# Substitutions for docker-compose.prod.yaml
|
# Substitutions for docker-compose.prod.yaml
|
||||||
# ⚠️ Replace all placeholder secrets with values sourced from your secret manager.
|
# ⚠️ Replace all placeholder secrets with values sourced from your secret manager.
|
||||||
MONGO_INITDB_ROOT_USERNAME=stellaops-prod
|
MONGO_INITDB_ROOT_USERNAME=stellaops-prod
|
||||||
MONGO_INITDB_ROOT_PASSWORD=REPLACE_WITH_STRONG_PASSWORD
|
MONGO_INITDB_ROOT_PASSWORD=REPLACE_WITH_STRONG_PASSWORD
|
||||||
MINIO_ROOT_USER=stellaops-prod
|
MINIO_ROOT_USER=stellaops-prod
|
||||||
MINIO_ROOT_PASSWORD=REPLACE_WITH_STRONG_PASSWORD
|
MINIO_ROOT_PASSWORD=REPLACE_WITH_STRONG_PASSWORD
|
||||||
# Expose the MinIO console only to trusted operator networks.
|
# Expose the MinIO console only to trusted operator networks.
|
||||||
MINIO_CONSOLE_PORT=39001
|
MINIO_CONSOLE_PORT=39001
|
||||||
RUSTFS_HTTP_PORT=8080
|
RUSTFS_HTTP_PORT=8080
|
||||||
AUTHORITY_ISSUER=https://authority.prod.stella-ops.org
|
AUTHORITY_ISSUER=https://authority.prod.stella-ops.org
|
||||||
AUTHORITY_PORT=8440
|
AUTHORITY_PORT=8440
|
||||||
SIGNER_POE_INTROSPECT_URL=https://licensing.prod.stella-ops.org/introspect
|
SIGNER_POE_INTROSPECT_URL=https://licensing.prod.stella-ops.org/introspect
|
||||||
SIGNER_PORT=8441
|
SIGNER_PORT=8441
|
||||||
ATTESTOR_PORT=8442
|
ATTESTOR_PORT=8442
|
||||||
CONCELIER_PORT=8445
|
CONCELIER_PORT=8445
|
||||||
SCANNER_WEB_PORT=8444
|
SCANNER_WEB_PORT=8444
|
||||||
UI_PORT=8443
|
UI_PORT=8443
|
||||||
NATS_CLIENT_PORT=4222
|
NATS_CLIENT_PORT=4222
|
||||||
SCANNER_QUEUE_BROKER=nats://nats:4222
|
SCANNER_QUEUE_BROKER=nats://nats:4222
|
||||||
# `true` enables signed scanner events for Notify ingestion.
|
# `true` enables signed scanner events for Notify ingestion.
|
||||||
SCANNER_EVENTS_ENABLED=true
|
SCANNER_EVENTS_ENABLED=true
|
||||||
SCANNER_EVENTS_DRIVER=redis
|
SCANNER_EVENTS_DRIVER=redis
|
||||||
# Leave SCANNER_EVENTS_DSN empty to inherit the Redis queue DSN when SCANNER_QUEUE_BROKER uses redis://.
|
# Leave SCANNER_EVENTS_DSN empty to inherit the Redis queue DSN when SCANNER_QUEUE_BROKER uses redis://.
|
||||||
SCANNER_EVENTS_DSN=
|
SCANNER_EVENTS_DSN=
|
||||||
SCANNER_EVENTS_STREAM=stella.events
|
SCANNER_EVENTS_STREAM=stella.events
|
||||||
SCANNER_EVENTS_PUBLISH_TIMEOUT_SECONDS=5
|
SCANNER_EVENTS_PUBLISH_TIMEOUT_SECONDS=5
|
||||||
SCANNER_EVENTS_MAX_STREAM_LENGTH=10000
|
SCANNER_EVENTS_MAX_STREAM_LENGTH=10000
|
||||||
SCHEDULER_QUEUE_KIND=Nats
|
SCHEDULER_QUEUE_KIND=Nats
|
||||||
SCHEDULER_QUEUE_NATS_URL=nats://nats:4222
|
SCHEDULER_QUEUE_NATS_URL=nats://nats:4222
|
||||||
SCHEDULER_STORAGE_DATABASE=stellaops_scheduler
|
SCHEDULER_STORAGE_DATABASE=stellaops_scheduler
|
||||||
SCHEDULER_SCANNER_BASEADDRESS=http://scanner-web:8444
|
SCHEDULER_SCANNER_BASEADDRESS=http://scanner-web:8444
|
||||||
# External reverse proxy (Traefik, Envoy, etc.) that terminates TLS.
|
# External reverse proxy (Traefik, Envoy, etc.) that terminates TLS.
|
||||||
FRONTDOOR_NETWORK=stellaops_frontdoor
|
FRONTDOOR_NETWORK=stellaops_frontdoor
|
||||||
|
|||||||
@@ -1,64 +1,64 @@
|
|||||||
receivers:
|
receivers:
|
||||||
otlp:
|
otlp:
|
||||||
protocols:
|
protocols:
|
||||||
grpc:
|
grpc:
|
||||||
endpoint: 0.0.0.0:4317
|
endpoint: 0.0.0.0:4317
|
||||||
tls:
|
tls:
|
||||||
cert_file: ${STELLAOPS_OTEL_TLS_CERT:?STELLAOPS_OTEL_TLS_CERT not set}
|
cert_file: ${STELLAOPS_OTEL_TLS_CERT:?STELLAOPS_OTEL_TLS_CERT not set}
|
||||||
key_file: ${STELLAOPS_OTEL_TLS_KEY:?STELLAOPS_OTEL_TLS_KEY not set}
|
key_file: ${STELLAOPS_OTEL_TLS_KEY:?STELLAOPS_OTEL_TLS_KEY not set}
|
||||||
client_ca_file: ${STELLAOPS_OTEL_TLS_CA:?STELLAOPS_OTEL_TLS_CA not set}
|
client_ca_file: ${STELLAOPS_OTEL_TLS_CA:?STELLAOPS_OTEL_TLS_CA not set}
|
||||||
require_client_certificate: ${STELLAOPS_OTEL_REQUIRE_CLIENT_CERT:true}
|
require_client_certificate: ${STELLAOPS_OTEL_REQUIRE_CLIENT_CERT:true}
|
||||||
http:
|
http:
|
||||||
endpoint: 0.0.0.0:4318
|
endpoint: 0.0.0.0:4318
|
||||||
tls:
|
tls:
|
||||||
cert_file: ${STELLAOPS_OTEL_TLS_CERT:?STELLAOPS_OTEL_TLS_CERT not set}
|
cert_file: ${STELLAOPS_OTEL_TLS_CERT:?STELLAOPS_OTEL_TLS_CERT not set}
|
||||||
key_file: ${STELLAOPS_OTEL_TLS_KEY:?STELLAOPS_OTEL_TLS_KEY not set}
|
key_file: ${STELLAOPS_OTEL_TLS_KEY:?STELLAOPS_OTEL_TLS_KEY not set}
|
||||||
client_ca_file: ${STELLAOPS_OTEL_TLS_CA:?STELLAOPS_OTEL_TLS_CA not set}
|
client_ca_file: ${STELLAOPS_OTEL_TLS_CA:?STELLAOPS_OTEL_TLS_CA not set}
|
||||||
require_client_certificate: ${STELLAOPS_OTEL_REQUIRE_CLIENT_CERT:true}
|
require_client_certificate: ${STELLAOPS_OTEL_REQUIRE_CLIENT_CERT:true}
|
||||||
|
|
||||||
processors:
|
processors:
|
||||||
attributes/tenant-tag:
|
attributes/tenant-tag:
|
||||||
actions:
|
actions:
|
||||||
- key: tenant.id
|
- key: tenant.id
|
||||||
action: insert
|
action: insert
|
||||||
value: ${STELLAOPS_TENANT_ID:unknown}
|
value: ${STELLAOPS_TENANT_ID:unknown}
|
||||||
batch:
|
batch:
|
||||||
send_batch_size: 1024
|
send_batch_size: 1024
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
|
|
||||||
exporters:
|
exporters:
|
||||||
logging:
|
logging:
|
||||||
verbosity: normal
|
verbosity: normal
|
||||||
prometheus:
|
prometheus:
|
||||||
endpoint: ${STELLAOPS_OTEL_PROMETHEUS_ENDPOINT:0.0.0.0:9464}
|
endpoint: ${STELLAOPS_OTEL_PROMETHEUS_ENDPOINT:0.0.0.0:9464}
|
||||||
enable_open_metrics: true
|
enable_open_metrics: true
|
||||||
metric_expiration: 5m
|
metric_expiration: 5m
|
||||||
tls:
|
tls:
|
||||||
cert_file: ${STELLAOPS_OTEL_TLS_CERT:?STELLAOPS_OTEL_TLS_CERT not set}
|
cert_file: ${STELLAOPS_OTEL_TLS_CERT:?STELLAOPS_OTEL_TLS_CERT not set}
|
||||||
key_file: ${STELLAOPS_OTEL_TLS_KEY:?STELLAOPS_OTEL_TLS_KEY not set}
|
key_file: ${STELLAOPS_OTEL_TLS_KEY:?STELLAOPS_OTEL_TLS_KEY not set}
|
||||||
client_ca_file: ${STELLAOPS_OTEL_TLS_CA:?STELLAOPS_OTEL_TLS_CA not set}
|
client_ca_file: ${STELLAOPS_OTEL_TLS_CA:?STELLAOPS_OTEL_TLS_CA not set}
|
||||||
|
|
||||||
extensions:
|
extensions:
|
||||||
health_check:
|
health_check:
|
||||||
endpoint: ${STELLAOPS_OTEL_HEALTH_ENDPOINT:0.0.0.0:13133}
|
endpoint: ${STELLAOPS_OTEL_HEALTH_ENDPOINT:0.0.0.0:13133}
|
||||||
pprof:
|
pprof:
|
||||||
endpoint: ${STELLAOPS_OTEL_PPROF_ENDPOINT:0.0.0.0:1777}
|
endpoint: ${STELLAOPS_OTEL_PPROF_ENDPOINT:0.0.0.0:1777}
|
||||||
|
|
||||||
service:
|
service:
|
||||||
telemetry:
|
telemetry:
|
||||||
logs:
|
logs:
|
||||||
level: ${STELLAOPS_OTEL_LOG_LEVEL:info}
|
level: ${STELLAOPS_OTEL_LOG_LEVEL:info}
|
||||||
extensions: [health_check, pprof]
|
extensions: [health_check, pprof]
|
||||||
pipelines:
|
pipelines:
|
||||||
traces:
|
traces:
|
||||||
receivers: [otlp]
|
receivers: [otlp]
|
||||||
processors: [attributes/tenant-tag, batch]
|
processors: [attributes/tenant-tag, batch]
|
||||||
exporters: [logging]
|
exporters: [logging]
|
||||||
metrics:
|
metrics:
|
||||||
receivers: [otlp]
|
receivers: [otlp]
|
||||||
processors: [attributes/tenant-tag, batch]
|
processors: [attributes/tenant-tag, batch]
|
||||||
exporters: [logging, prometheus]
|
exporters: [logging, prometheus]
|
||||||
logs:
|
logs:
|
||||||
receivers: [otlp]
|
receivers: [otlp]
|
||||||
processors: [attributes/tenant-tag, batch]
|
processors: [attributes/tenant-tag, batch]
|
||||||
exporters: [logging]
|
exporters: [logging]
|
||||||
|
|||||||
@@ -1,121 +1,121 @@
|
|||||||
{{- if .Values.telemetry.collector.enabled }}
|
{{- if .Values.telemetry.collector.enabled }}
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: ConfigMap
|
kind: ConfigMap
|
||||||
metadata:
|
metadata:
|
||||||
name: {{ include "stellaops.telemetryCollector.fullname" . }}
|
name: {{ include "stellaops.telemetryCollector.fullname" . }}
|
||||||
labels:
|
labels:
|
||||||
{{- include "stellaops.labels" (dict "root" . "name" "otel-collector" "svc" (dict "class" "telemetry")) | nindent 4 }}
|
{{- include "stellaops.labels" (dict "root" . "name" "otel-collector" "svc" (dict "class" "telemetry")) | nindent 4 }}
|
||||||
data:
|
data:
|
||||||
config.yaml: |
|
config.yaml: |
|
||||||
{{ include "stellaops.telemetryCollector.config" . | indent 4 }}
|
{{ include "stellaops.telemetryCollector.config" . | indent 4 }}
|
||||||
---
|
---
|
||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
name: {{ include "stellaops.telemetryCollector.fullname" . }}
|
name: {{ include "stellaops.telemetryCollector.fullname" . }}
|
||||||
labels:
|
labels:
|
||||||
{{- include "stellaops.labels" (dict "root" . "name" "otel-collector" "svc" (dict "class" "telemetry")) | nindent 4 }}
|
{{- include "stellaops.labels" (dict "root" . "name" "otel-collector" "svc" (dict "class" "telemetry")) | nindent 4 }}
|
||||||
spec:
|
spec:
|
||||||
replicas: {{ .Values.telemetry.collector.replicas | default 1 }}
|
replicas: {{ .Values.telemetry.collector.replicas | default 1 }}
|
||||||
selector:
|
selector:
|
||||||
matchLabels:
|
matchLabels:
|
||||||
app.kubernetes.io/name: {{ include "stellaops.name" . | quote }}
|
app.kubernetes.io/name: {{ include "stellaops.name" . | quote }}
|
||||||
app.kubernetes.io/component: "otel-collector"
|
app.kubernetes.io/component: "otel-collector"
|
||||||
template:
|
template:
|
||||||
metadata:
|
metadata:
|
||||||
labels:
|
labels:
|
||||||
app.kubernetes.io/name: {{ include "stellaops.name" . | quote }}
|
app.kubernetes.io/name: {{ include "stellaops.name" . | quote }}
|
||||||
app.kubernetes.io/component: "otel-collector"
|
app.kubernetes.io/component: "otel-collector"
|
||||||
stellaops.profile: {{ .Values.global.profile | quote }}
|
stellaops.profile: {{ .Values.global.profile | quote }}
|
||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: otel-collector
|
- name: otel-collector
|
||||||
image: {{ .Values.telemetry.collector.image | default "otel/opentelemetry-collector:0.105.0" | quote }}
|
image: {{ .Values.telemetry.collector.image | default "otel/opentelemetry-collector:0.105.0" | quote }}
|
||||||
args:
|
args:
|
||||||
- "--config=/etc/otel/config.yaml"
|
- "--config=/etc/otel/config.yaml"
|
||||||
ports:
|
ports:
|
||||||
- name: otlp-grpc
|
- name: otlp-grpc
|
||||||
containerPort: 4317
|
containerPort: 4317
|
||||||
- name: otlp-http
|
- name: otlp-http
|
||||||
containerPort: 4318
|
containerPort: 4318
|
||||||
- name: metrics
|
- name: metrics
|
||||||
containerPort: 9464
|
containerPort: 9464
|
||||||
- name: health
|
- name: health
|
||||||
containerPort: 13133
|
containerPort: 13133
|
||||||
- name: pprof
|
- name: pprof
|
||||||
containerPort: 1777
|
containerPort: 1777
|
||||||
env:
|
env:
|
||||||
- name: STELLAOPS_OTEL_TLS_CERT
|
- name: STELLAOPS_OTEL_TLS_CERT
|
||||||
value: {{ .Values.telemetry.collector.tls.certPath | default "/etc/otel/tls/tls.crt" | quote }}
|
value: {{ .Values.telemetry.collector.tls.certPath | default "/etc/otel/tls/tls.crt" | quote }}
|
||||||
- name: STELLAOPS_OTEL_TLS_KEY
|
- name: STELLAOPS_OTEL_TLS_KEY
|
||||||
value: {{ .Values.telemetry.collector.tls.keyPath | default "/etc/otel/tls/tls.key" | quote }}
|
value: {{ .Values.telemetry.collector.tls.keyPath | default "/etc/otel/tls/tls.key" | quote }}
|
||||||
- name: STELLAOPS_OTEL_TLS_CA
|
- name: STELLAOPS_OTEL_TLS_CA
|
||||||
value: {{ .Values.telemetry.collector.tls.caPath | default "/etc/otel/tls/ca.crt" | quote }}
|
value: {{ .Values.telemetry.collector.tls.caPath | default "/etc/otel/tls/ca.crt" | quote }}
|
||||||
- name: STELLAOPS_OTEL_PROMETHEUS_ENDPOINT
|
- name: STELLAOPS_OTEL_PROMETHEUS_ENDPOINT
|
||||||
value: {{ .Values.telemetry.collector.prometheusEndpoint | default "0.0.0.0:9464" | quote }}
|
value: {{ .Values.telemetry.collector.prometheusEndpoint | default "0.0.0.0:9464" | quote }}
|
||||||
- name: STELLAOPS_OTEL_REQUIRE_CLIENT_CERT
|
- name: STELLAOPS_OTEL_REQUIRE_CLIENT_CERT
|
||||||
value: {{ .Values.telemetry.collector.requireClientCert | default true | quote }}
|
value: {{ .Values.telemetry.collector.requireClientCert | default true | quote }}
|
||||||
- name: STELLAOPS_TENANT_ID
|
- name: STELLAOPS_TENANT_ID
|
||||||
value: {{ .Values.telemetry.collector.defaultTenant | default "unknown" | quote }}
|
value: {{ .Values.telemetry.collector.defaultTenant | default "unknown" | quote }}
|
||||||
- name: STELLAOPS_OTEL_LOG_LEVEL
|
- name: STELLAOPS_OTEL_LOG_LEVEL
|
||||||
value: {{ .Values.telemetry.collector.logLevel | default "info" | quote }}
|
value: {{ .Values.telemetry.collector.logLevel | default "info" | quote }}
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
- name: config
|
- name: config
|
||||||
mountPath: /etc/otel/config.yaml
|
mountPath: /etc/otel/config.yaml
|
||||||
subPath: config.yaml
|
subPath: config.yaml
|
||||||
readOnly: true
|
readOnly: true
|
||||||
- name: tls
|
- name: tls
|
||||||
mountPath: /etc/otel/tls
|
mountPath: /etc/otel/tls
|
||||||
readOnly: true
|
readOnly: true
|
||||||
livenessProbe:
|
livenessProbe:
|
||||||
httpGet:
|
httpGet:
|
||||||
scheme: HTTPS
|
scheme: HTTPS
|
||||||
port: health
|
port: health
|
||||||
path: /healthz
|
path: /healthz
|
||||||
initialDelaySeconds: 10
|
initialDelaySeconds: 10
|
||||||
periodSeconds: 30
|
periodSeconds: 30
|
||||||
readinessProbe:
|
readinessProbe:
|
||||||
httpGet:
|
httpGet:
|
||||||
scheme: HTTPS
|
scheme: HTTPS
|
||||||
port: health
|
port: health
|
||||||
path: /healthz
|
path: /healthz
|
||||||
initialDelaySeconds: 5
|
initialDelaySeconds: 5
|
||||||
periodSeconds: 15
|
periodSeconds: 15
|
||||||
{{- with .Values.telemetry.collector.resources }}
|
{{- with .Values.telemetry.collector.resources }}
|
||||||
resources:
|
resources:
|
||||||
{{ toYaml . | indent 12 }}
|
{{ toYaml . | indent 12 }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
volumes:
|
volumes:
|
||||||
- name: config
|
- name: config
|
||||||
configMap:
|
configMap:
|
||||||
name: {{ include "stellaops.telemetryCollector.fullname" . }}
|
name: {{ include "stellaops.telemetryCollector.fullname" . }}
|
||||||
- name: tls
|
- name: tls
|
||||||
secret:
|
secret:
|
||||||
secretName: {{ .Values.telemetry.collector.tls.secretName | required "telemetry.collector.tls.secretName is required" }}
|
secretName: {{ .Values.telemetry.collector.tls.secretName | required "telemetry.collector.tls.secretName is required" }}
|
||||||
{{- if .Values.telemetry.collector.tls.items }}
|
{{- if .Values.telemetry.collector.tls.items }}
|
||||||
items:
|
items:
|
||||||
{{ toYaml .Values.telemetry.collector.tls.items | indent 14 }}
|
{{ toYaml .Values.telemetry.collector.tls.items | indent 14 }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Service
|
kind: Service
|
||||||
metadata:
|
metadata:
|
||||||
name: {{ include "stellaops.telemetryCollector.fullname" . }}
|
name: {{ include "stellaops.telemetryCollector.fullname" . }}
|
||||||
labels:
|
labels:
|
||||||
{{- include "stellaops.labels" (dict "root" . "name" "otel-collector" "svc" (dict "class" "telemetry")) | nindent 4 }}
|
{{- include "stellaops.labels" (dict "root" . "name" "otel-collector" "svc" (dict "class" "telemetry")) | nindent 4 }}
|
||||||
spec:
|
spec:
|
||||||
type: ClusterIP
|
type: ClusterIP
|
||||||
selector:
|
selector:
|
||||||
app.kubernetes.io/name: {{ include "stellaops.name" . | quote }}
|
app.kubernetes.io/name: {{ include "stellaops.name" . | quote }}
|
||||||
app.kubernetes.io/component: "otel-collector"
|
app.kubernetes.io/component: "otel-collector"
|
||||||
ports:
|
ports:
|
||||||
- name: otlp-grpc
|
- name: otlp-grpc
|
||||||
port: {{ .Values.telemetry.collector.service.grpcPort | default 4317 }}
|
port: {{ .Values.telemetry.collector.service.grpcPort | default 4317 }}
|
||||||
targetPort: otlp-grpc
|
targetPort: otlp-grpc
|
||||||
- name: otlp-http
|
- name: otlp-http
|
||||||
port: {{ .Values.telemetry.collector.service.httpPort | default 4318 }}
|
port: {{ .Values.telemetry.collector.service.httpPort | default 4318 }}
|
||||||
targetPort: otlp-http
|
targetPort: otlp-http
|
||||||
- name: metrics
|
- name: metrics
|
||||||
port: {{ .Values.telemetry.collector.service.metricsPort | default 9464 }}
|
port: {{ .Values.telemetry.collector.service.metricsPort | default 9464 }}
|
||||||
targetPort: metrics
|
targetPort: metrics
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|||||||
@@ -1,221 +1,221 @@
|
|||||||
global:
|
global:
|
||||||
profile: prod
|
profile: prod
|
||||||
release:
|
release:
|
||||||
version: "2025.09.2"
|
version: "2025.09.2"
|
||||||
channel: stable
|
channel: stable
|
||||||
manifestSha256: "dc3c8fe1ab83941c838ccc5a8a5862f7ddfa38c2078e580b5649db26554565b7"
|
manifestSha256: "dc3c8fe1ab83941c838ccc5a8a5862f7ddfa38c2078e580b5649db26554565b7"
|
||||||
image:
|
image:
|
||||||
pullPolicy: IfNotPresent
|
pullPolicy: IfNotPresent
|
||||||
labels:
|
labels:
|
||||||
stellaops.io/channel: stable
|
stellaops.io/channel: stable
|
||||||
stellaops.io/profile: prod
|
stellaops.io/profile: prod
|
||||||
|
|
||||||
configMaps:
|
configMaps:
|
||||||
notify-config:
|
notify-config:
|
||||||
data:
|
data:
|
||||||
notify.yaml: |
|
notify.yaml: |
|
||||||
storage:
|
storage:
|
||||||
driver: mongo
|
driver: mongo
|
||||||
connectionString: "mongodb://stellaops-mongo:27017"
|
connectionString: "mongodb://stellaops-mongo:27017"
|
||||||
database: "stellaops_notify_prod"
|
database: "stellaops_notify_prod"
|
||||||
commandTimeoutSeconds: 45
|
commandTimeoutSeconds: 45
|
||||||
|
|
||||||
authority:
|
authority:
|
||||||
enabled: true
|
enabled: true
|
||||||
issuer: "https://authority.prod.stella-ops.org"
|
issuer: "https://authority.prod.stella-ops.org"
|
||||||
metadataAddress: "https://authority.prod.stella-ops.org/.well-known/openid-configuration"
|
metadataAddress: "https://authority.prod.stella-ops.org/.well-known/openid-configuration"
|
||||||
requireHttpsMetadata: true
|
requireHttpsMetadata: true
|
||||||
allowAnonymousFallback: false
|
allowAnonymousFallback: false
|
||||||
backchannelTimeoutSeconds: 30
|
backchannelTimeoutSeconds: 30
|
||||||
tokenClockSkewSeconds: 60
|
tokenClockSkewSeconds: 60
|
||||||
audiences:
|
audiences:
|
||||||
- notify
|
- notify
|
||||||
readScope: notify.read
|
readScope: notify.read
|
||||||
adminScope: notify.admin
|
adminScope: notify.admin
|
||||||
|
|
||||||
api:
|
api:
|
||||||
basePath: "/api/v1/notify"
|
basePath: "/api/v1/notify"
|
||||||
internalBasePath: "/internal/notify"
|
internalBasePath: "/internal/notify"
|
||||||
tenantHeader: "X-StellaOps-Tenant"
|
tenantHeader: "X-StellaOps-Tenant"
|
||||||
|
|
||||||
plugins:
|
plugins:
|
||||||
baseDirectory: "/opt/stellaops"
|
baseDirectory: "/opt/stellaops"
|
||||||
directory: "plugins/notify"
|
directory: "plugins/notify"
|
||||||
searchPatterns:
|
searchPatterns:
|
||||||
- "StellaOps.Notify.Connectors.*.dll"
|
- "StellaOps.Notify.Connectors.*.dll"
|
||||||
orderedPlugins:
|
orderedPlugins:
|
||||||
- StellaOps.Notify.Connectors.Slack
|
- StellaOps.Notify.Connectors.Slack
|
||||||
- StellaOps.Notify.Connectors.Teams
|
- StellaOps.Notify.Connectors.Teams
|
||||||
- StellaOps.Notify.Connectors.Email
|
- StellaOps.Notify.Connectors.Email
|
||||||
- StellaOps.Notify.Connectors.Webhook
|
- StellaOps.Notify.Connectors.Webhook
|
||||||
|
|
||||||
telemetry:
|
telemetry:
|
||||||
enableRequestLogging: true
|
enableRequestLogging: true
|
||||||
minimumLogLevel: Information
|
minimumLogLevel: Information
|
||||||
services:
|
services:
|
||||||
authority:
|
authority:
|
||||||
image: registry.stella-ops.org/stellaops/authority@sha256:b0348bad1d0b401cc3c71cb40ba034c8043b6c8874546f90d4783c9dbfcc0bf5
|
image: registry.stella-ops.org/stellaops/authority@sha256:b0348bad1d0b401cc3c71cb40ba034c8043b6c8874546f90d4783c9dbfcc0bf5
|
||||||
service:
|
service:
|
||||||
port: 8440
|
port: 8440
|
||||||
env:
|
env:
|
||||||
STELLAOPS_AUTHORITY__ISSUER: "https://authority.prod.stella-ops.org"
|
STELLAOPS_AUTHORITY__ISSUER: "https://authority.prod.stella-ops.org"
|
||||||
STELLAOPS_AUTHORITY__PLUGINDIRECTORIES__0: "/app/plugins"
|
STELLAOPS_AUTHORITY__PLUGINDIRECTORIES__0: "/app/plugins"
|
||||||
STELLAOPS_AUTHORITY__PLUGINS__CONFIGURATIONDIRECTORY: "/app/etc/authority.plugins"
|
STELLAOPS_AUTHORITY__PLUGINS__CONFIGURATIONDIRECTORY: "/app/etc/authority.plugins"
|
||||||
envFrom:
|
envFrom:
|
||||||
- secretRef:
|
- secretRef:
|
||||||
name: stellaops-prod-core
|
name: stellaops-prod-core
|
||||||
signer:
|
signer:
|
||||||
image: registry.stella-ops.org/stellaops/signer@sha256:8ad574e61f3a9e9bda8a58eb2700ae46813284e35a150b1137bc7c2b92ac0f2e
|
image: registry.stella-ops.org/stellaops/signer@sha256:8ad574e61f3a9e9bda8a58eb2700ae46813284e35a150b1137bc7c2b92ac0f2e
|
||||||
service:
|
service:
|
||||||
port: 8441
|
port: 8441
|
||||||
env:
|
env:
|
||||||
SIGNER__AUTHORITY__BASEURL: "https://stellaops-authority:8440"
|
SIGNER__AUTHORITY__BASEURL: "https://stellaops-authority:8440"
|
||||||
SIGNER__POE__INTROSPECTURL: "https://licensing.prod.stella-ops.org/introspect"
|
SIGNER__POE__INTROSPECTURL: "https://licensing.prod.stella-ops.org/introspect"
|
||||||
envFrom:
|
envFrom:
|
||||||
- secretRef:
|
- secretRef:
|
||||||
name: stellaops-prod-core
|
name: stellaops-prod-core
|
||||||
attestor:
|
attestor:
|
||||||
image: registry.stella-ops.org/stellaops/attestor@sha256:0534985f978b0b5d220d73c96fddd962cd9135f616811cbe3bff4666c5af568f
|
image: registry.stella-ops.org/stellaops/attestor@sha256:0534985f978b0b5d220d73c96fddd962cd9135f616811cbe3bff4666c5af568f
|
||||||
service:
|
service:
|
||||||
port: 8442
|
port: 8442
|
||||||
env:
|
env:
|
||||||
ATTESTOR__SIGNER__BASEURL: "https://stellaops-signer:8441"
|
ATTESTOR__SIGNER__BASEURL: "https://stellaops-signer:8441"
|
||||||
envFrom:
|
envFrom:
|
||||||
- secretRef:
|
- secretRef:
|
||||||
name: stellaops-prod-core
|
name: stellaops-prod-core
|
||||||
concelier:
|
concelier:
|
||||||
image: registry.stella-ops.org/stellaops/concelier@sha256:c58cdcaee1d266d68d498e41110a589dd204b487d37381096bd61ab345a867c5
|
image: registry.stella-ops.org/stellaops/concelier@sha256:c58cdcaee1d266d68d498e41110a589dd204b487d37381096bd61ab345a867c5
|
||||||
service:
|
service:
|
||||||
port: 8445
|
port: 8445
|
||||||
env:
|
env:
|
||||||
CONCELIER__STORAGE__S3__ENDPOINT: "http://stellaops-minio:9000"
|
CONCELIER__STORAGE__S3__ENDPOINT: "http://stellaops-minio:9000"
|
||||||
CONCELIER__AUTHORITY__BASEURL: "https://stellaops-authority:8440"
|
CONCELIER__AUTHORITY__BASEURL: "https://stellaops-authority:8440"
|
||||||
envFrom:
|
envFrom:
|
||||||
- secretRef:
|
- secretRef:
|
||||||
name: stellaops-prod-core
|
name: stellaops-prod-core
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
- name: concelier-jobs
|
- name: concelier-jobs
|
||||||
mountPath: /var/lib/concelier/jobs
|
mountPath: /var/lib/concelier/jobs
|
||||||
volumeClaims:
|
volumeClaims:
|
||||||
- name: concelier-jobs
|
- name: concelier-jobs
|
||||||
claimName: stellaops-concelier-jobs
|
claimName: stellaops-concelier-jobs
|
||||||
scanner-web:
|
scanner-web:
|
||||||
image: registry.stella-ops.org/stellaops/scanner-web@sha256:14b23448c3f9586a9156370b3e8c1991b61907efa666ca37dd3aaed1e79fe3b7
|
image: registry.stella-ops.org/stellaops/scanner-web@sha256:14b23448c3f9586a9156370b3e8c1991b61907efa666ca37dd3aaed1e79fe3b7
|
||||||
service:
|
service:
|
||||||
port: 8444
|
port: 8444
|
||||||
env:
|
env:
|
||||||
SCANNER__ARTIFACTSTORE__DRIVER: "rustfs"
|
SCANNER__ARTIFACTSTORE__DRIVER: "rustfs"
|
||||||
SCANNER__ARTIFACTSTORE__ENDPOINT: "http://stellaops-rustfs:8080/api/v1"
|
SCANNER__ARTIFACTSTORE__ENDPOINT: "http://stellaops-rustfs:8080/api/v1"
|
||||||
SCANNER__ARTIFACTSTORE__BUCKET: "scanner-artifacts"
|
SCANNER__ARTIFACTSTORE__BUCKET: "scanner-artifacts"
|
||||||
SCANNER__ARTIFACTSTORE__TIMEOUTSECONDS: "30"
|
SCANNER__ARTIFACTSTORE__TIMEOUTSECONDS: "30"
|
||||||
SCANNER__QUEUE__BROKER: "nats://stellaops-nats:4222"
|
SCANNER__QUEUE__BROKER: "nats://stellaops-nats:4222"
|
||||||
SCANNER__EVENTS__ENABLED: "true"
|
SCANNER__EVENTS__ENABLED: "true"
|
||||||
SCANNER__EVENTS__DRIVER: "redis"
|
SCANNER__EVENTS__DRIVER: "redis"
|
||||||
SCANNER__EVENTS__DSN: ""
|
SCANNER__EVENTS__DSN: ""
|
||||||
SCANNER__EVENTS__STREAM: "stella.events"
|
SCANNER__EVENTS__STREAM: "stella.events"
|
||||||
SCANNER__EVENTS__PUBLISHTIMEOUTSECONDS: "5"
|
SCANNER__EVENTS__PUBLISHTIMEOUTSECONDS: "5"
|
||||||
SCANNER__EVENTS__MAXSTREAMLENGTH: "10000"
|
SCANNER__EVENTS__MAXSTREAMLENGTH: "10000"
|
||||||
envFrom:
|
envFrom:
|
||||||
- secretRef:
|
- secretRef:
|
||||||
name: stellaops-prod-core
|
name: stellaops-prod-core
|
||||||
scanner-worker:
|
scanner-worker:
|
||||||
image: registry.stella-ops.org/stellaops/scanner-worker@sha256:32e25e76386eb9ea8bee0a1ad546775db9a2df989fab61ac877e351881960dab
|
image: registry.stella-ops.org/stellaops/scanner-worker@sha256:32e25e76386eb9ea8bee0a1ad546775db9a2df989fab61ac877e351881960dab
|
||||||
replicas: 3
|
replicas: 3
|
||||||
env:
|
env:
|
||||||
SCANNER__ARTIFACTSTORE__DRIVER: "rustfs"
|
SCANNER__ARTIFACTSTORE__DRIVER: "rustfs"
|
||||||
SCANNER__ARTIFACTSTORE__ENDPOINT: "http://stellaops-rustfs:8080/api/v1"
|
SCANNER__ARTIFACTSTORE__ENDPOINT: "http://stellaops-rustfs:8080/api/v1"
|
||||||
SCANNER__ARTIFACTSTORE__BUCKET: "scanner-artifacts"
|
SCANNER__ARTIFACTSTORE__BUCKET: "scanner-artifacts"
|
||||||
SCANNER__ARTIFACTSTORE__TIMEOUTSECONDS: "30"
|
SCANNER__ARTIFACTSTORE__TIMEOUTSECONDS: "30"
|
||||||
SCANNER__QUEUE__BROKER: "nats://stellaops-nats:4222"
|
SCANNER__QUEUE__BROKER: "nats://stellaops-nats:4222"
|
||||||
SCANNER__EVENTS__ENABLED: "true"
|
SCANNER__EVENTS__ENABLED: "true"
|
||||||
SCANNER__EVENTS__DRIVER: "redis"
|
SCANNER__EVENTS__DRIVER: "redis"
|
||||||
SCANNER__EVENTS__DSN: ""
|
SCANNER__EVENTS__DSN: ""
|
||||||
SCANNER__EVENTS__STREAM: "stella.events"
|
SCANNER__EVENTS__STREAM: "stella.events"
|
||||||
SCANNER__EVENTS__PUBLISHTIMEOUTSECONDS: "5"
|
SCANNER__EVENTS__PUBLISHTIMEOUTSECONDS: "5"
|
||||||
SCANNER__EVENTS__MAXSTREAMLENGTH: "10000"
|
SCANNER__EVENTS__MAXSTREAMLENGTH: "10000"
|
||||||
envFrom:
|
envFrom:
|
||||||
- secretRef:
|
- secretRef:
|
||||||
name: stellaops-prod-core
|
name: stellaops-prod-core
|
||||||
notify-web:
|
notify-web:
|
||||||
image: registry.stella-ops.org/stellaops/notify-web:2025.09.2
|
image: registry.stella-ops.org/stellaops/notify-web:2025.09.2
|
||||||
service:
|
service:
|
||||||
port: 8446
|
port: 8446
|
||||||
env:
|
env:
|
||||||
DOTNET_ENVIRONMENT: Production
|
DOTNET_ENVIRONMENT: Production
|
||||||
envFrom:
|
envFrom:
|
||||||
- secretRef:
|
- secretRef:
|
||||||
name: stellaops-prod-notify
|
name: stellaops-prod-notify
|
||||||
configMounts:
|
configMounts:
|
||||||
- name: notify-config
|
- name: notify-config
|
||||||
mountPath: /app/etc/notify.yaml
|
mountPath: /app/etc/notify.yaml
|
||||||
subPath: notify.yaml
|
subPath: notify.yaml
|
||||||
configMap: notify-config
|
configMap: notify-config
|
||||||
excititor:
|
excititor:
|
||||||
image: registry.stella-ops.org/stellaops/excititor@sha256:59022e2016aebcef5c856d163ae705755d3f81949d41195256e935ef40a627fa
|
image: registry.stella-ops.org/stellaops/excititor@sha256:59022e2016aebcef5c856d163ae705755d3f81949d41195256e935ef40a627fa
|
||||||
env:
|
env:
|
||||||
EXCITITOR__CONCELIER__BASEURL: "https://stellaops-concelier:8445"
|
EXCITITOR__CONCELIER__BASEURL: "https://stellaops-concelier:8445"
|
||||||
envFrom:
|
envFrom:
|
||||||
- secretRef:
|
- secretRef:
|
||||||
name: stellaops-prod-core
|
name: stellaops-prod-core
|
||||||
web-ui:
|
web-ui:
|
||||||
image: registry.stella-ops.org/stellaops/web-ui@sha256:10d924808c48e4353e3a241da62eb7aefe727a1d6dc830eb23a8e181013b3a23
|
image: registry.stella-ops.org/stellaops/web-ui@sha256:10d924808c48e4353e3a241da62eb7aefe727a1d6dc830eb23a8e181013b3a23
|
||||||
service:
|
service:
|
||||||
port: 8443
|
port: 8443
|
||||||
env:
|
env:
|
||||||
STELLAOPS_UI__BACKEND__BASEURL: "https://stellaops-scanner-web:8444"
|
STELLAOPS_UI__BACKEND__BASEURL: "https://stellaops-scanner-web:8444"
|
||||||
mongo:
|
mongo:
|
||||||
class: infrastructure
|
class: infrastructure
|
||||||
image: docker.io/library/mongo@sha256:c258b26dbb7774f97f52aff52231ca5f228273a84329c5f5e451c3739457db49
|
image: docker.io/library/mongo@sha256:c258b26dbb7774f97f52aff52231ca5f228273a84329c5f5e451c3739457db49
|
||||||
service:
|
service:
|
||||||
port: 27017
|
port: 27017
|
||||||
command:
|
command:
|
||||||
- mongod
|
- mongod
|
||||||
- --bind_ip_all
|
- --bind_ip_all
|
||||||
envFrom:
|
envFrom:
|
||||||
- secretRef:
|
- secretRef:
|
||||||
name: stellaops-prod-mongo
|
name: stellaops-prod-mongo
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
- name: mongo-data
|
- name: mongo-data
|
||||||
mountPath: /data/db
|
mountPath: /data/db
|
||||||
volumeClaims:
|
volumeClaims:
|
||||||
- name: mongo-data
|
- name: mongo-data
|
||||||
claimName: stellaops-mongo-data
|
claimName: stellaops-mongo-data
|
||||||
minio:
|
minio:
|
||||||
class: infrastructure
|
class: infrastructure
|
||||||
image: docker.io/minio/minio@sha256:14cea493d9a34af32f524e538b8346cf79f3321eff8e708c1e2960462bd8936e
|
image: docker.io/minio/minio@sha256:14cea493d9a34af32f524e538b8346cf79f3321eff8e708c1e2960462bd8936e
|
||||||
service:
|
service:
|
||||||
port: 9000
|
port: 9000
|
||||||
command:
|
command:
|
||||||
- server
|
- server
|
||||||
- /data
|
- /data
|
||||||
- --console-address
|
- --console-address
|
||||||
- :9001
|
- :9001
|
||||||
envFrom:
|
envFrom:
|
||||||
- secretRef:
|
- secretRef:
|
||||||
name: stellaops-prod-minio
|
name: stellaops-prod-minio
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
- name: minio-data
|
- name: minio-data
|
||||||
mountPath: /data
|
mountPath: /data
|
||||||
volumeClaims:
|
volumeClaims:
|
||||||
- name: minio-data
|
- name: minio-data
|
||||||
claimName: stellaops-minio-data
|
claimName: stellaops-minio-data
|
||||||
rustfs:
|
rustfs:
|
||||||
class: infrastructure
|
class: infrastructure
|
||||||
image: registry.stella-ops.org/stellaops/rustfs:2025.10.0-edge
|
image: registry.stella-ops.org/stellaops/rustfs:2025.10.0-edge
|
||||||
service:
|
service:
|
||||||
port: 8080
|
port: 8080
|
||||||
command:
|
command:
|
||||||
- serve
|
- serve
|
||||||
- --listen
|
- --listen
|
||||||
- 0.0.0.0:8080
|
- 0.0.0.0:8080
|
||||||
- --root
|
- --root
|
||||||
- /data
|
- /data
|
||||||
env:
|
env:
|
||||||
RUSTFS__LOG__LEVEL: info
|
RUSTFS__LOG__LEVEL: info
|
||||||
RUSTFS__STORAGE__PATH: /data
|
RUSTFS__STORAGE__PATH: /data
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
- name: rustfs-data
|
- name: rustfs-data
|
||||||
mountPath: /data
|
mountPath: /data
|
||||||
volumeClaims:
|
volumeClaims:
|
||||||
- name: rustfs-data
|
- name: rustfs-data
|
||||||
claimName: stellaops-rustfs-data
|
claimName: stellaops-rustfs-data
|
||||||
|
|||||||
@@ -1,39 +1,39 @@
|
|||||||
global:
|
global:
|
||||||
release:
|
release:
|
||||||
version: ""
|
version: ""
|
||||||
channel: ""
|
channel: ""
|
||||||
manifestSha256: ""
|
manifestSha256: ""
|
||||||
profile: ""
|
profile: ""
|
||||||
image:
|
image:
|
||||||
pullPolicy: IfNotPresent
|
pullPolicy: IfNotPresent
|
||||||
labels: {}
|
labels: {}
|
||||||
|
|
||||||
telemetry:
|
telemetry:
|
||||||
collector:
|
collector:
|
||||||
enabled: false
|
enabled: false
|
||||||
replicas: 1
|
replicas: 1
|
||||||
image: otel/opentelemetry-collector:0.105.0
|
image: otel/opentelemetry-collector:0.105.0
|
||||||
requireClientCert: true
|
requireClientCert: true
|
||||||
defaultTenant: unknown
|
defaultTenant: unknown
|
||||||
logLevel: info
|
logLevel: info
|
||||||
tls:
|
tls:
|
||||||
secretName: ""
|
secretName: ""
|
||||||
certPath: /etc/otel/tls/tls.crt
|
certPath: /etc/otel/tls/tls.crt
|
||||||
keyPath: /etc/otel/tls/tls.key
|
keyPath: /etc/otel/tls/tls.key
|
||||||
caPath: /etc/otel/tls/ca.crt
|
caPath: /etc/otel/tls/ca.crt
|
||||||
items:
|
items:
|
||||||
- key: tls.crt
|
- key: tls.crt
|
||||||
path: tls.crt
|
path: tls.crt
|
||||||
- key: tls.key
|
- key: tls.key
|
||||||
path: tls.key
|
path: tls.key
|
||||||
- key: ca.crt
|
- key: ca.crt
|
||||||
path: ca.crt
|
path: ca.crt
|
||||||
service:
|
service:
|
||||||
grpcPort: 4317
|
grpcPort: 4317
|
||||||
httpPort: 4318
|
httpPort: 4318
|
||||||
metricsPort: 9464
|
metricsPort: 9464
|
||||||
resources: {}
|
resources: {}
|
||||||
|
|
||||||
services:
|
services:
|
||||||
scheduler-worker:
|
scheduler-worker:
|
||||||
image: registry.stella-ops.org/stellaops/scheduler-worker:2025.10.0-edge
|
image: registry.stella-ops.org/stellaops/scheduler-worker:2025.10.0-edge
|
||||||
|
|||||||
2
deploy/telemetry/.gitignore
vendored
2
deploy/telemetry/.gitignore
vendored
@@ -1 +1 @@
|
|||||||
certs/
|
certs/
|
||||||
|
|||||||
@@ -1,35 +1,35 @@
|
|||||||
# Telemetry Collector Assets
|
# Telemetry Collector Assets
|
||||||
|
|
||||||
These assets provision the default OpenTelemetry Collector instance required by
|
These assets provision the default OpenTelemetry Collector instance required by
|
||||||
`DEVOPS-OBS-50-001`. The collector acts as the secured ingest point for traces,
|
`DEVOPS-OBS-50-001`. The collector acts as the secured ingest point for traces,
|
||||||
metrics, and logs emitted by Stella Ops services.
|
metrics, and logs emitted by Stella Ops services.
|
||||||
|
|
||||||
## Contents
|
## Contents
|
||||||
|
|
||||||
| File | Purpose |
|
| File | Purpose |
|
||||||
| ---- | ------- |
|
| ---- | ------- |
|
||||||
| `otel-collector-config.yaml` | Baseline collector configuration (mutual TLS, OTLP receivers, Prometheus exporter). |
|
| `otel-collector-config.yaml` | Baseline collector configuration (mutual TLS, OTLP receivers, Prometheus exporter). |
|
||||||
| `storage/prometheus.yaml` | Prometheus scrape configuration tuned for the collector and service tenants. |
|
| `storage/prometheus.yaml` | Prometheus scrape configuration tuned for the collector and service tenants. |
|
||||||
| `storage/tempo.yaml` | Tempo configuration with multitenancy, WAL, and compaction settings. |
|
| `storage/tempo.yaml` | Tempo configuration with multitenancy, WAL, and compaction settings. |
|
||||||
| `storage/loki.yaml` | Loki configuration enabling multitenant log ingestion with retention policies. |
|
| `storage/loki.yaml` | Loki configuration enabling multitenant log ingestion with retention policies. |
|
||||||
| `storage/tenants/*.yaml` | Per-tenant overrides for Tempo and Loki rate/retention controls. |
|
| `storage/tenants/*.yaml` | Per-tenant overrides for Tempo and Loki rate/retention controls. |
|
||||||
|
|
||||||
## Development workflow
|
## Development workflow
|
||||||
|
|
||||||
1. Generate development certificates (collector + client) using
|
1. Generate development certificates (collector + client) using
|
||||||
`ops/devops/telemetry/generate_dev_tls.sh`.
|
`ops/devops/telemetry/generate_dev_tls.sh`.
|
||||||
2. Launch the collector via `docker compose -f docker-compose.telemetry.yaml up`.
|
2. Launch the collector via `docker compose -f docker-compose.telemetry.yaml up`.
|
||||||
3. Launch the storage backends (Prometheus, Tempo, Loki) via
|
3. Launch the storage backends (Prometheus, Tempo, Loki) via
|
||||||
`docker compose -f docker-compose.telemetry-storage.yaml up`.
|
`docker compose -f docker-compose.telemetry-storage.yaml up`.
|
||||||
4. Run the smoke test: `python ops/devops/telemetry/smoke_otel_collector.py`.
|
4. Run the smoke test: `python ops/devops/telemetry/smoke_otel_collector.py`.
|
||||||
5. Explore the storage configuration (`storage/README.md`) to tune retention/limits.
|
5. Explore the storage configuration (`storage/README.md`) to tune retention/limits.
|
||||||
|
|
||||||
The smoke test sends OTLP traffic over TLS and asserts the collector accepted
|
The smoke test sends OTLP traffic over TLS and asserts the collector accepted
|
||||||
traces, metrics, and logs by scraping the Prometheus metrics endpoint.
|
traces, metrics, and logs by scraping the Prometheus metrics endpoint.
|
||||||
|
|
||||||
## Kubernetes
|
## Kubernetes
|
||||||
|
|
||||||
The Helm chart consumes the same configuration (see `values.yaml`). Provide TLS
|
The Helm chart consumes the same configuration (see `values.yaml`). Provide TLS
|
||||||
material via a secret referenced by `telemetry.collector.tls.secretName`,
|
material via a secret referenced by `telemetry.collector.tls.secretName`,
|
||||||
containing `ca.crt`, `tls.crt`, and `tls.key`. Client certificates are required
|
containing `ca.crt`, `tls.crt`, and `tls.key`. Client certificates are required
|
||||||
for ingestion and should be issued by the same CA.
|
for ingestion and should be issued by the same CA.
|
||||||
|
|||||||
@@ -1,67 +1,67 @@
|
|||||||
receivers:
|
receivers:
|
||||||
otlp:
|
otlp:
|
||||||
protocols:
|
protocols:
|
||||||
grpc:
|
grpc:
|
||||||
endpoint: 0.0.0.0:4317
|
endpoint: 0.0.0.0:4317
|
||||||
tls:
|
tls:
|
||||||
cert_file: ${STELLAOPS_OTEL_TLS_CERT:?STELLAOPS_OTEL_TLS_CERT not set}
|
cert_file: ${STELLAOPS_OTEL_TLS_CERT:?STELLAOPS_OTEL_TLS_CERT not set}
|
||||||
key_file: ${STELLAOPS_OTEL_TLS_KEY:?STELLAOPS_OTEL_TLS_KEY not set}
|
key_file: ${STELLAOPS_OTEL_TLS_KEY:?STELLAOPS_OTEL_TLS_KEY not set}
|
||||||
client_ca_file: ${STELLAOPS_OTEL_TLS_CA:?STELLAOPS_OTEL_TLS_CA not set}
|
client_ca_file: ${STELLAOPS_OTEL_TLS_CA:?STELLAOPS_OTEL_TLS_CA not set}
|
||||||
require_client_certificate: ${STELLAOPS_OTEL_REQUIRE_CLIENT_CERT:true}
|
require_client_certificate: ${STELLAOPS_OTEL_REQUIRE_CLIENT_CERT:true}
|
||||||
http:
|
http:
|
||||||
endpoint: 0.0.0.0:4318
|
endpoint: 0.0.0.0:4318
|
||||||
tls:
|
tls:
|
||||||
cert_file: ${STELLAOPS_OTEL_TLS_CERT:?STELLAOPS_OTEL_TLS_CERT not set}
|
cert_file: ${STELLAOPS_OTEL_TLS_CERT:?STELLAOPS_OTEL_TLS_CERT not set}
|
||||||
key_file: ${STELLAOPS_OTEL_TLS_KEY:?STELLAOPS_OTEL_TLS_KEY not set}
|
key_file: ${STELLAOPS_OTEL_TLS_KEY:?STELLAOPS_OTEL_TLS_KEY not set}
|
||||||
client_ca_file: ${STELLAOPS_OTEL_TLS_CA:?STELLAOPS_OTEL_TLS_CA not set}
|
client_ca_file: ${STELLAOPS_OTEL_TLS_CA:?STELLAOPS_OTEL_TLS_CA not set}
|
||||||
require_client_certificate: ${STELLAOPS_OTEL_REQUIRE_CLIENT_CERT:true}
|
require_client_certificate: ${STELLAOPS_OTEL_REQUIRE_CLIENT_CERT:true}
|
||||||
|
|
||||||
processors:
|
processors:
|
||||||
attributes/tenant-tag:
|
attributes/tenant-tag:
|
||||||
actions:
|
actions:
|
||||||
- key: tenant.id
|
- key: tenant.id
|
||||||
action: insert
|
action: insert
|
||||||
value: ${STELLAOPS_TENANT_ID:unknown}
|
value: ${STELLAOPS_TENANT_ID:unknown}
|
||||||
batch:
|
batch:
|
||||||
send_batch_size: 1024
|
send_batch_size: 1024
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
|
|
||||||
exporters:
|
exporters:
|
||||||
logging:
|
logging:
|
||||||
verbosity: normal
|
verbosity: normal
|
||||||
prometheus:
|
prometheus:
|
||||||
endpoint: ${STELLAOPS_OTEL_PROMETHEUS_ENDPOINT:0.0.0.0:9464}
|
endpoint: ${STELLAOPS_OTEL_PROMETHEUS_ENDPOINT:0.0.0.0:9464}
|
||||||
enable_open_metrics: true
|
enable_open_metrics: true
|
||||||
metric_expiration: 5m
|
metric_expiration: 5m
|
||||||
tls:
|
tls:
|
||||||
cert_file: ${STELLAOPS_OTEL_TLS_CERT:?STELLAOPS_OTEL_TLS_CERT not set}
|
cert_file: ${STELLAOPS_OTEL_TLS_CERT:?STELLAOPS_OTEL_TLS_CERT not set}
|
||||||
key_file: ${STELLAOPS_OTEL_TLS_KEY:?STELLAOPS_OTEL_TLS_KEY not set}
|
key_file: ${STELLAOPS_OTEL_TLS_KEY:?STELLAOPS_OTEL_TLS_KEY not set}
|
||||||
client_ca_file: ${STELLAOPS_OTEL_TLS_CA:?STELLAOPS_OTEL_TLS_CA not set}
|
client_ca_file: ${STELLAOPS_OTEL_TLS_CA:?STELLAOPS_OTEL_TLS_CA not set}
|
||||||
# Additional OTLP exporters can be configured by extending this section at runtime.
|
# Additional OTLP exporters can be configured by extending this section at runtime.
|
||||||
# For example, set STELLAOPS_OTEL_UPSTREAM_ENDPOINT and mount certificates, then
|
# For example, set STELLAOPS_OTEL_UPSTREAM_ENDPOINT and mount certificates, then
|
||||||
# add the exporter via a sidecar overlay.
|
# add the exporter via a sidecar overlay.
|
||||||
|
|
||||||
extensions:
|
extensions:
|
||||||
health_check:
|
health_check:
|
||||||
endpoint: ${STELLAOPS_OTEL_HEALTH_ENDPOINT:0.0.0.0:13133}
|
endpoint: ${STELLAOPS_OTEL_HEALTH_ENDPOINT:0.0.0.0:13133}
|
||||||
pprof:
|
pprof:
|
||||||
endpoint: ${STELLAOPS_OTEL_PPROF_ENDPOINT:0.0.0.0:1777}
|
endpoint: ${STELLAOPS_OTEL_PPROF_ENDPOINT:0.0.0.0:1777}
|
||||||
|
|
||||||
service:
|
service:
|
||||||
telemetry:
|
telemetry:
|
||||||
logs:
|
logs:
|
||||||
level: ${STELLAOPS_OTEL_LOG_LEVEL:info}
|
level: ${STELLAOPS_OTEL_LOG_LEVEL:info}
|
||||||
extensions: [health_check, pprof]
|
extensions: [health_check, pprof]
|
||||||
pipelines:
|
pipelines:
|
||||||
traces:
|
traces:
|
||||||
receivers: [otlp]
|
receivers: [otlp]
|
||||||
processors: [attributes/tenant-tag, batch]
|
processors: [attributes/tenant-tag, batch]
|
||||||
exporters: [logging]
|
exporters: [logging]
|
||||||
metrics:
|
metrics:
|
||||||
receivers: [otlp]
|
receivers: [otlp]
|
||||||
processors: [attributes/tenant-tag, batch]
|
processors: [attributes/tenant-tag, batch]
|
||||||
exporters: [logging, prometheus]
|
exporters: [logging, prometheus]
|
||||||
logs:
|
logs:
|
||||||
receivers: [otlp]
|
receivers: [otlp]
|
||||||
processors: [attributes/tenant-tag, batch]
|
processors: [attributes/tenant-tag, batch]
|
||||||
exporters: [logging]
|
exporters: [logging]
|
||||||
|
|||||||
@@ -1,33 +1,33 @@
|
|||||||
# Telemetry Storage Stack
|
# Telemetry Storage Stack
|
||||||
|
|
||||||
Configuration snippets for the default StellaOps observability backends used in
|
Configuration snippets for the default StellaOps observability backends used in
|
||||||
staging and production environments. The stack comprises:
|
staging and production environments. The stack comprises:
|
||||||
|
|
||||||
- **Prometheus** for metrics (scraping the collector's Prometheus exporter)
|
- **Prometheus** for metrics (scraping the collector's Prometheus exporter)
|
||||||
- **Tempo** for traces (OTLP ingest via mTLS)
|
- **Tempo** for traces (OTLP ingest via mTLS)
|
||||||
- **Loki** for logs (HTTP ingest with tenant isolation)
|
- **Loki** for logs (HTTP ingest with tenant isolation)
|
||||||
|
|
||||||
## Files
|
## Files
|
||||||
|
|
||||||
| Path | Description |
|
| Path | Description |
|
||||||
| ---- | ----------- |
|
| ---- | ----------- |
|
||||||
| `prometheus.yaml` | Scrape configuration for the collector (mTLS + bearer token placeholder). |
|
| `prometheus.yaml` | Scrape configuration for the collector (mTLS + bearer token placeholder). |
|
||||||
| `tempo.yaml` | Tempo configuration with multitenancy enabled and local storage paths. |
|
| `tempo.yaml` | Tempo configuration with multitenancy enabled and local storage paths. |
|
||||||
| `loki.yaml` | Loki configuration enabling per-tenant overrides and boltdb-shipper storage. |
|
| `loki.yaml` | Loki configuration enabling per-tenant overrides and boltdb-shipper storage. |
|
||||||
| `tenants/tempo-overrides.yaml` | Example tenant overrides for Tempo (retention, limits). |
|
| `tenants/tempo-overrides.yaml` | Example tenant overrides for Tempo (retention, limits). |
|
||||||
| `tenants/loki-overrides.yaml` | Example tenant overrides for Loki (rate limits, retention). |
|
| `tenants/loki-overrides.yaml` | Example tenant overrides for Loki (rate limits, retention). |
|
||||||
| `auth/` | Placeholder directory for Prometheus bearer token files (e.g., `token`). |
|
| `auth/` | Placeholder directory for Prometheus bearer token files (e.g., `token`). |
|
||||||
|
|
||||||
These configurations are referenced by the Docker Compose overlay
|
These configurations are referenced by the Docker Compose overlay
|
||||||
(`deploy/compose/docker-compose.telemetry-storage.yaml`) and the staging rollout documented in
|
(`deploy/compose/docker-compose.telemetry-storage.yaml`) and the staging rollout documented in
|
||||||
`docs/ops/telemetry-storage.md`. Adjust paths, credentials, and overrides before running in
|
`docs/ops/telemetry-storage.md`. Adjust paths, credentials, and overrides before running in
|
||||||
connected environments. Place the Prometheus bearer token in `auth/token` when using the
|
connected environments. Place the Prometheus bearer token in `auth/token` when using the
|
||||||
Compose overlay (the directory contains a `.gitkeep` placeholder and is gitignored by default).
|
Compose overlay (the directory contains a `.gitkeep` placeholder and is gitignored by default).
|
||||||
|
|
||||||
## Security
|
## Security
|
||||||
|
|
||||||
- Both Tempo and Loki require mutual TLS.
|
- Both Tempo and Loki require mutual TLS.
|
||||||
- Prometheus uses mTLS plus a bearer token that should be minted by Authority.
|
- Prometheus uses mTLS plus a bearer token that should be minted by Authority.
|
||||||
- Update the overrides files to enforce per-tenant retention/ingestion limits.
|
- Update the overrides files to enforce per-tenant retention/ingestion limits.
|
||||||
|
|
||||||
For comprehensive deployment steps see `docs/ops/telemetry-storage.md`.
|
For comprehensive deployment steps see `docs/ops/telemetry-storage.md`.
|
||||||
|
|||||||
@@ -1,48 +1,48 @@
|
|||||||
auth_enabled: true
|
auth_enabled: true
|
||||||
|
|
||||||
server:
|
server:
|
||||||
http_listen_port: 3100
|
http_listen_port: 3100
|
||||||
log_level: info
|
log_level: info
|
||||||
|
|
||||||
common:
|
common:
|
||||||
ring:
|
ring:
|
||||||
instance_addr: 127.0.0.1
|
instance_addr: 127.0.0.1
|
||||||
kvstore:
|
kvstore:
|
||||||
store: inmemory
|
store: inmemory
|
||||||
replication_factor: 1
|
replication_factor: 1
|
||||||
path_prefix: /var/loki
|
path_prefix: /var/loki
|
||||||
|
|
||||||
schema_config:
|
schema_config:
|
||||||
configs:
|
configs:
|
||||||
- from: 2024-01-01
|
- from: 2024-01-01
|
||||||
store: boltdb-shipper
|
store: boltdb-shipper
|
||||||
object_store: filesystem
|
object_store: filesystem
|
||||||
schema: v13
|
schema: v13
|
||||||
index:
|
index:
|
||||||
prefix: loki_index_
|
prefix: loki_index_
|
||||||
period: 24h
|
period: 24h
|
||||||
|
|
||||||
storage_config:
|
storage_config:
|
||||||
filesystem:
|
filesystem:
|
||||||
directory: /var/loki/chunks
|
directory: /var/loki/chunks
|
||||||
boltdb_shipper:
|
boltdb_shipper:
|
||||||
active_index_directory: /var/loki/index
|
active_index_directory: /var/loki/index
|
||||||
cache_location: /var/loki/index_cache
|
cache_location: /var/loki/index_cache
|
||||||
shared_store: filesystem
|
shared_store: filesystem
|
||||||
|
|
||||||
ruler:
|
ruler:
|
||||||
storage:
|
storage:
|
||||||
type: local
|
type: local
|
||||||
local:
|
local:
|
||||||
directory: /var/loki/rules
|
directory: /var/loki/rules
|
||||||
rule_path: /tmp/loki-rules
|
rule_path: /tmp/loki-rules
|
||||||
enable_api: true
|
enable_api: true
|
||||||
|
|
||||||
limits_config:
|
limits_config:
|
||||||
enforce_metric_name: false
|
enforce_metric_name: false
|
||||||
reject_old_samples: true
|
reject_old_samples: true
|
||||||
reject_old_samples_max_age: 168h
|
reject_old_samples_max_age: 168h
|
||||||
max_entries_limit_per_query: 5000
|
max_entries_limit_per_query: 5000
|
||||||
ingestion_rate_mb: 10
|
ingestion_rate_mb: 10
|
||||||
ingestion_burst_size_mb: 20
|
ingestion_burst_size_mb: 20
|
||||||
per_tenant_override_config: /etc/telemetry/tenants/loki-overrides.yaml
|
per_tenant_override_config: /etc/telemetry/tenants/loki-overrides.yaml
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
global:
|
global:
|
||||||
scrape_interval: 15s
|
scrape_interval: 15s
|
||||||
evaluation_interval: 30s
|
evaluation_interval: 30s
|
||||||
|
|
||||||
scrape_configs:
|
scrape_configs:
|
||||||
- job_name: "stellaops-otel-collector"
|
- job_name: "stellaops-otel-collector"
|
||||||
scheme: https
|
scheme: https
|
||||||
metrics_path: /
|
metrics_path: /
|
||||||
tls_config:
|
tls_config:
|
||||||
ca_file: ${PROMETHEUS_TLS_CA_FILE:-/etc/telemetry/tls/ca.crt}
|
ca_file: ${PROMETHEUS_TLS_CA_FILE:-/etc/telemetry/tls/ca.crt}
|
||||||
cert_file: ${PROMETHEUS_TLS_CERT_FILE:-/etc/telemetry/tls/client.crt}
|
cert_file: ${PROMETHEUS_TLS_CERT_FILE:-/etc/telemetry/tls/client.crt}
|
||||||
key_file: ${PROMETHEUS_TLS_KEY_FILE:-/etc/telemetry/tls/client.key}
|
key_file: ${PROMETHEUS_TLS_KEY_FILE:-/etc/telemetry/tls/client.key}
|
||||||
insecure_skip_verify: false
|
insecure_skip_verify: false
|
||||||
authorization:
|
authorization:
|
||||||
type: Bearer
|
type: Bearer
|
||||||
credentials_file: ${PROMETHEUS_BEARER_TOKEN_FILE:-/etc/telemetry/auth/token}
|
credentials_file: ${PROMETHEUS_BEARER_TOKEN_FILE:-/etc/telemetry/auth/token}
|
||||||
static_configs:
|
static_configs:
|
||||||
- targets:
|
- targets:
|
||||||
- ${PROMETHEUS_COLLECTOR_TARGET:-stellaops-otel-collector:9464}
|
- ${PROMETHEUS_COLLECTOR_TARGET:-stellaops-otel-collector:9464}
|
||||||
|
|||||||
@@ -1,56 +1,56 @@
|
|||||||
multitenancy_enabled: true
|
multitenancy_enabled: true
|
||||||
usage_report:
|
usage_report:
|
||||||
reporting_enabled: false
|
reporting_enabled: false
|
||||||
|
|
||||||
server:
|
server:
|
||||||
http_listen_port: 3200
|
http_listen_port: 3200
|
||||||
log_level: info
|
log_level: info
|
||||||
|
|
||||||
distributor:
|
distributor:
|
||||||
receivers:
|
receivers:
|
||||||
otlp:
|
otlp:
|
||||||
protocols:
|
protocols:
|
||||||
grpc:
|
grpc:
|
||||||
tls:
|
tls:
|
||||||
cert_file: ${TEMPO_TLS_CERT_FILE:-/etc/telemetry/tls/server.crt}
|
cert_file: ${TEMPO_TLS_CERT_FILE:-/etc/telemetry/tls/server.crt}
|
||||||
key_file: ${TEMPO_TLS_KEY_FILE:-/etc/telemetry/tls/server.key}
|
key_file: ${TEMPO_TLS_KEY_FILE:-/etc/telemetry/tls/server.key}
|
||||||
client_ca_file: ${TEMPO_TLS_CA_FILE:-/etc/telemetry/tls/ca.crt}
|
client_ca_file: ${TEMPO_TLS_CA_FILE:-/etc/telemetry/tls/ca.crt}
|
||||||
require_client_cert: true
|
require_client_cert: true
|
||||||
http:
|
http:
|
||||||
tls:
|
tls:
|
||||||
cert_file: ${TEMPO_TLS_CERT_FILE:-/etc/telemetry/tls/server.crt}
|
cert_file: ${TEMPO_TLS_CERT_FILE:-/etc/telemetry/tls/server.crt}
|
||||||
key_file: ${TEMPO_TLS_KEY_FILE:-/etc/telemetry/tls/server.key}
|
key_file: ${TEMPO_TLS_KEY_FILE:-/etc/telemetry/tls/server.key}
|
||||||
client_ca_file: ${TEMPO_TLS_CA_FILE:-/etc/telemetry/tls/ca.crt}
|
client_ca_file: ${TEMPO_TLS_CA_FILE:-/etc/telemetry/tls/ca.crt}
|
||||||
require_client_cert: true
|
require_client_cert: true
|
||||||
|
|
||||||
ingester:
|
ingester:
|
||||||
lifecycler:
|
lifecycler:
|
||||||
ring:
|
ring:
|
||||||
instance_availability_zone: ${TEMPO_ZONE:-zone-a}
|
instance_availability_zone: ${TEMPO_ZONE:-zone-a}
|
||||||
trace_idle_period: 10s
|
trace_idle_period: 10s
|
||||||
max_block_bytes: 1_048_576
|
max_block_bytes: 1_048_576
|
||||||
|
|
||||||
compactor:
|
compactor:
|
||||||
compaction:
|
compaction:
|
||||||
block_retention: 168h
|
block_retention: 168h
|
||||||
|
|
||||||
metrics_generator:
|
metrics_generator:
|
||||||
registry:
|
registry:
|
||||||
external_labels:
|
external_labels:
|
||||||
cluster: stellaops
|
cluster: stellaops
|
||||||
|
|
||||||
storage:
|
storage:
|
||||||
trace:
|
trace:
|
||||||
backend: local
|
backend: local
|
||||||
local:
|
local:
|
||||||
path: /var/tempo/traces
|
path: /var/tempo/traces
|
||||||
wal:
|
wal:
|
||||||
path: /var/tempo/wal
|
path: /var/tempo/wal
|
||||||
metrics:
|
metrics:
|
||||||
backend: prometheus
|
backend: prometheus
|
||||||
|
|
||||||
overrides:
|
overrides:
|
||||||
defaults:
|
defaults:
|
||||||
ingestion_rate_limit_bytes: 1048576
|
ingestion_rate_limit_bytes: 1048576
|
||||||
max_traces_per_user: 200000
|
max_traces_per_user: 200000
|
||||||
per_tenant_override_config: /etc/telemetry/tenants/tempo-overrides.yaml
|
per_tenant_override_config: /etc/telemetry/tenants/tempo-overrides.yaml
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
# Example Loki per-tenant overrides
|
# Example Loki per-tenant overrides
|
||||||
# Adjust according to https://grafana.com/docs/loki/latest/configuration/#limits_config
|
# Adjust according to https://grafana.com/docs/loki/latest/configuration/#limits_config
|
||||||
|
|
||||||
stellaops-dev:
|
stellaops-dev:
|
||||||
ingestion_rate_mb: 10
|
ingestion_rate_mb: 10
|
||||||
ingestion_burst_size_mb: 20
|
ingestion_burst_size_mb: 20
|
||||||
max_global_streams_per_user: 5000
|
max_global_streams_per_user: 5000
|
||||||
retention_period: 168h
|
retention_period: 168h
|
||||||
|
|
||||||
stellaops-stage:
|
stellaops-stage:
|
||||||
ingestion_rate_mb: 20
|
ingestion_rate_mb: 20
|
||||||
ingestion_burst_size_mb: 40
|
ingestion_burst_size_mb: 40
|
||||||
max_global_streams_per_user: 10000
|
max_global_streams_per_user: 10000
|
||||||
retention_period: 336h
|
retention_period: 336h
|
||||||
|
|
||||||
__default__:
|
__default__:
|
||||||
ingestion_rate_mb: 5
|
ingestion_rate_mb: 5
|
||||||
ingestion_burst_size_mb: 10
|
ingestion_burst_size_mb: 10
|
||||||
retention_period: 72h
|
retention_period: 72h
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
# Example Tempo per-tenant overrides
|
# Example Tempo per-tenant overrides
|
||||||
# Consult https://grafana.com/docs/tempo/latest/configuration/#limits-configuration
|
# Consult https://grafana.com/docs/tempo/latest/configuration/#limits-configuration
|
||||||
# before applying in production.
|
# before applying in production.
|
||||||
|
|
||||||
stellaops-dev:
|
stellaops-dev:
|
||||||
traces_per_second_limit: 100000
|
traces_per_second_limit: 100000
|
||||||
max_bytes_per_trace: 10485760
|
max_bytes_per_trace: 10485760
|
||||||
max_search_bytes_per_trace: 20971520
|
max_search_bytes_per_trace: 20971520
|
||||||
|
|
||||||
stellaops-stage:
|
stellaops-stage:
|
||||||
traces_per_second_limit: 200000
|
traces_per_second_limit: 200000
|
||||||
max_bytes_per_trace: 20971520
|
max_bytes_per_trace: 20971520
|
||||||
|
|
||||||
__default__:
|
__default__:
|
||||||
traces_per_second_limit: 50000
|
traces_per_second_limit: 50000
|
||||||
max_bytes_per_trace: 5242880
|
max_bytes_per_trace: 5242880
|
||||||
|
|||||||
@@ -1,130 +1,130 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""
|
"""
|
||||||
Ensure deployment bundles reference the images defined in a release manifest.
|
Ensure deployment bundles reference the images defined in a release manifest.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
./deploy/tools/check-channel-alignment.py \
|
./deploy/tools/check-channel-alignment.py \
|
||||||
--release deploy/releases/2025.10-edge.yaml \
|
--release deploy/releases/2025.10-edge.yaml \
|
||||||
--target deploy/helm/stellaops/values-dev.yaml \
|
--target deploy/helm/stellaops/values-dev.yaml \
|
||||||
--target deploy/compose/docker-compose.dev.yaml
|
--target deploy/compose/docker-compose.dev.yaml
|
||||||
|
|
||||||
For every target file, the script scans `image:` declarations and verifies that
|
For every target file, the script scans `image:` declarations and verifies that
|
||||||
any image belonging to a repository listed in the release manifest matches the
|
any image belonging to a repository listed in the release manifest matches the
|
||||||
exact digest or tag recorded there. Images outside of the manifest (for example,
|
exact digest or tag recorded there. Images outside of the manifest (for example,
|
||||||
supporting services such as `nats`) are ignored.
|
supporting services such as `nats`) are ignored.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import pathlib
|
import pathlib
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
from typing import Dict, Iterable, List, Optional, Set
|
from typing import Dict, Iterable, List, Optional, Set
|
||||||
|
|
||||||
IMAGE_LINE = re.compile(r"^\s*image:\s*['\"]?(?P<image>\S+)['\"]?\s*$")
|
IMAGE_LINE = re.compile(r"^\s*image:\s*['\"]?(?P<image>\S+)['\"]?\s*$")
|
||||||
|
|
||||||
|
|
||||||
def extract_images(path: pathlib.Path) -> List[str]:
|
def extract_images(path: pathlib.Path) -> List[str]:
|
||||||
images: List[str] = []
|
images: List[str] = []
|
||||||
for line in path.read_text(encoding="utf-8").splitlines():
|
for line in path.read_text(encoding="utf-8").splitlines():
|
||||||
match = IMAGE_LINE.match(line)
|
match = IMAGE_LINE.match(line)
|
||||||
if match:
|
if match:
|
||||||
images.append(match.group("image"))
|
images.append(match.group("image"))
|
||||||
return images
|
return images
|
||||||
|
|
||||||
|
|
||||||
def image_repo(image: str) -> str:
|
def image_repo(image: str) -> str:
|
||||||
if "@" in image:
|
if "@" in image:
|
||||||
return image.split("@", 1)[0]
|
return image.split("@", 1)[0]
|
||||||
# Split on the last colon to preserve registries with ports (e.g. localhost:5000)
|
# Split on the last colon to preserve registries with ports (e.g. localhost:5000)
|
||||||
if ":" in image:
|
if ":" in image:
|
||||||
prefix, tag = image.rsplit(":", 1)
|
prefix, tag = image.rsplit(":", 1)
|
||||||
if "/" in tag:
|
if "/" in tag:
|
||||||
# handle digestive colon inside path (unlikely)
|
# handle digestive colon inside path (unlikely)
|
||||||
return image
|
return image
|
||||||
return prefix
|
return prefix
|
||||||
return image
|
return image
|
||||||
|
|
||||||
|
|
||||||
def load_release_map(release_path: pathlib.Path) -> Dict[str, str]:
|
def load_release_map(release_path: pathlib.Path) -> Dict[str, str]:
|
||||||
release_map: Dict[str, str] = {}
|
release_map: Dict[str, str] = {}
|
||||||
for image in extract_images(release_path):
|
for image in extract_images(release_path):
|
||||||
repo = image_repo(image)
|
repo = image_repo(image)
|
||||||
release_map[repo] = image
|
release_map[repo] = image
|
||||||
return release_map
|
return release_map
|
||||||
|
|
||||||
|
|
||||||
def check_target(
|
def check_target(
|
||||||
target_path: pathlib.Path,
|
target_path: pathlib.Path,
|
||||||
release_map: Dict[str, str],
|
release_map: Dict[str, str],
|
||||||
ignore_repos: Set[str],
|
ignore_repos: Set[str],
|
||||||
) -> List[str]:
|
) -> List[str]:
|
||||||
errors: List[str] = []
|
errors: List[str] = []
|
||||||
for image in extract_images(target_path):
|
for image in extract_images(target_path):
|
||||||
repo = image_repo(image)
|
repo = image_repo(image)
|
||||||
if repo in ignore_repos:
|
if repo in ignore_repos:
|
||||||
continue
|
continue
|
||||||
if repo not in release_map:
|
if repo not in release_map:
|
||||||
continue
|
continue
|
||||||
expected = release_map[repo]
|
expected = release_map[repo]
|
||||||
if image != expected:
|
if image != expected:
|
||||||
errors.append(
|
errors.append(
|
||||||
f"{target_path}: {image} does not match release value {expected}"
|
f"{target_path}: {image} does not match release value {expected}"
|
||||||
)
|
)
|
||||||
return errors
|
return errors
|
||||||
|
|
||||||
|
|
||||||
def parse_args(argv: Optional[Iterable[str]] = None) -> argparse.Namespace:
|
def parse_args(argv: Optional[Iterable[str]] = None) -> argparse.Namespace:
|
||||||
parser = argparse.ArgumentParser(description=__doc__)
|
parser = argparse.ArgumentParser(description=__doc__)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--release",
|
"--release",
|
||||||
required=True,
|
required=True,
|
||||||
type=pathlib.Path,
|
type=pathlib.Path,
|
||||||
help="Path to the release manifest (YAML)",
|
help="Path to the release manifest (YAML)",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--target",
|
"--target",
|
||||||
action="append",
|
action="append",
|
||||||
required=True,
|
required=True,
|
||||||
type=pathlib.Path,
|
type=pathlib.Path,
|
||||||
help="Deployment profile to validate against the release manifest",
|
help="Deployment profile to validate against the release manifest",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--ignore-repo",
|
"--ignore-repo",
|
||||||
action="append",
|
action="append",
|
||||||
default=[],
|
default=[],
|
||||||
help="Repository prefix to ignore (may be repeated)",
|
help="Repository prefix to ignore (may be repeated)",
|
||||||
)
|
)
|
||||||
return parser.parse_args(argv)
|
return parser.parse_args(argv)
|
||||||
|
|
||||||
|
|
||||||
def main(argv: Optional[Iterable[str]] = None) -> int:
|
def main(argv: Optional[Iterable[str]] = None) -> int:
|
||||||
args = parse_args(argv)
|
args = parse_args(argv)
|
||||||
|
|
||||||
release_map = load_release_map(args.release)
|
release_map = load_release_map(args.release)
|
||||||
ignore_repos = {repo.rstrip("/") for repo in args.ignore_repo}
|
ignore_repos = {repo.rstrip("/") for repo in args.ignore_repo}
|
||||||
|
|
||||||
if not release_map:
|
if not release_map:
|
||||||
print(f"error: no images found in release manifest {args.release}", file=sys.stderr)
|
print(f"error: no images found in release manifest {args.release}", file=sys.stderr)
|
||||||
return 2
|
return 2
|
||||||
|
|
||||||
total_errors: List[str] = []
|
total_errors: List[str] = []
|
||||||
for target in args.target:
|
for target in args.target:
|
||||||
if not target.exists():
|
if not target.exists():
|
||||||
total_errors.append(f"{target}: file not found")
|
total_errors.append(f"{target}: file not found")
|
||||||
continue
|
continue
|
||||||
total_errors.extend(check_target(target, release_map, ignore_repos))
|
total_errors.extend(check_target(target, release_map, ignore_repos))
|
||||||
|
|
||||||
if total_errors:
|
if total_errors:
|
||||||
print("✖ channel alignment check failed:", file=sys.stderr)
|
print("✖ channel alignment check failed:", file=sys.stderr)
|
||||||
for err in total_errors:
|
for err in total_errors:
|
||||||
print(f" - {err}", file=sys.stderr)
|
print(f" - {err}", file=sys.stderr)
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
print("✓ deployment profiles reference release images for the inspected repositories.")
|
print("✓ deployment profiles reference release images for the inspected repositories.")
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
raise SystemExit(main())
|
raise SystemExit(main())
|
||||||
|
|||||||
@@ -1,61 +1,61 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
COMPOSE_DIR="$ROOT_DIR/compose"
|
COMPOSE_DIR="$ROOT_DIR/compose"
|
||||||
HELM_DIR="$ROOT_DIR/helm/stellaops"
|
HELM_DIR="$ROOT_DIR/helm/stellaops"
|
||||||
|
|
||||||
compose_profiles=(
|
compose_profiles=(
|
||||||
"docker-compose.dev.yaml:env/dev.env.example"
|
"docker-compose.dev.yaml:env/dev.env.example"
|
||||||
"docker-compose.stage.yaml:env/stage.env.example"
|
"docker-compose.stage.yaml:env/stage.env.example"
|
||||||
"docker-compose.prod.yaml:env/prod.env.example"
|
"docker-compose.prod.yaml:env/prod.env.example"
|
||||||
"docker-compose.airgap.yaml:env/airgap.env.example"
|
"docker-compose.airgap.yaml:env/airgap.env.example"
|
||||||
"docker-compose.mirror.yaml:env/mirror.env.example"
|
"docker-compose.mirror.yaml:env/mirror.env.example"
|
||||||
"docker-compose.telemetry.yaml:"
|
"docker-compose.telemetry.yaml:"
|
||||||
"docker-compose.telemetry-storage.yaml:"
|
"docker-compose.telemetry-storage.yaml:"
|
||||||
)
|
)
|
||||||
|
|
||||||
docker_ready=false
|
docker_ready=false
|
||||||
if command -v docker >/dev/null 2>&1; then
|
if command -v docker >/dev/null 2>&1; then
|
||||||
if docker compose version >/dev/null 2>&1; then
|
if docker compose version >/dev/null 2>&1; then
|
||||||
docker_ready=true
|
docker_ready=true
|
||||||
else
|
else
|
||||||
echo "⚠️ docker CLI present but Compose plugin unavailable; skipping compose validation" >&2
|
echo "⚠️ docker CLI present but Compose plugin unavailable; skipping compose validation" >&2
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
echo "⚠️ docker CLI not found; skipping compose validation" >&2
|
echo "⚠️ docker CLI not found; skipping compose validation" >&2
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "$docker_ready" == "true" ]]; then
|
if [[ "$docker_ready" == "true" ]]; then
|
||||||
for entry in "${compose_profiles[@]}"; do
|
for entry in "${compose_profiles[@]}"; do
|
||||||
IFS=":" read -r compose_file env_file <<<"$entry"
|
IFS=":" read -r compose_file env_file <<<"$entry"
|
||||||
printf '→ validating %s with %s\n' "$compose_file" "$env_file"
|
printf '→ validating %s with %s\n' "$compose_file" "$env_file"
|
||||||
if [[ -n "$env_file" ]]; then
|
if [[ -n "$env_file" ]]; then
|
||||||
docker compose \
|
docker compose \
|
||||||
--env-file "$COMPOSE_DIR/$env_file" \
|
--env-file "$COMPOSE_DIR/$env_file" \
|
||||||
-f "$COMPOSE_DIR/$compose_file" config >/dev/null
|
-f "$COMPOSE_DIR/$compose_file" config >/dev/null
|
||||||
else
|
else
|
||||||
docker compose -f "$COMPOSE_DIR/$compose_file" config >/dev/null
|
docker compose -f "$COMPOSE_DIR/$compose_file" config >/dev/null
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
helm_values=(
|
helm_values=(
|
||||||
"$HELM_DIR/values-dev.yaml"
|
"$HELM_DIR/values-dev.yaml"
|
||||||
"$HELM_DIR/values-stage.yaml"
|
"$HELM_DIR/values-stage.yaml"
|
||||||
"$HELM_DIR/values-prod.yaml"
|
"$HELM_DIR/values-prod.yaml"
|
||||||
"$HELM_DIR/values-airgap.yaml"
|
"$HELM_DIR/values-airgap.yaml"
|
||||||
"$HELM_DIR/values-mirror.yaml"
|
"$HELM_DIR/values-mirror.yaml"
|
||||||
)
|
)
|
||||||
|
|
||||||
if command -v helm >/dev/null 2>&1; then
|
if command -v helm >/dev/null 2>&1; then
|
||||||
for values in "${helm_values[@]}"; do
|
for values in "${helm_values[@]}"; do
|
||||||
printf '→ linting Helm chart with %s\n' "$(basename "$values")"
|
printf '→ linting Helm chart with %s\n' "$(basename "$values")"
|
||||||
helm lint "$HELM_DIR" -f "$values"
|
helm lint "$HELM_DIR" -f "$values"
|
||||||
helm template test-release "$HELM_DIR" -f "$values" >/dev/null
|
helm template test-release "$HELM_DIR" -f "$values" >/dev/null
|
||||||
done
|
done
|
||||||
else
|
else
|
||||||
echo "⚠️ helm CLI not found; skipping Helm lint/template" >&2
|
echo "⚠️ helm CLI not found; skipping Helm lint/template" >&2
|
||||||
fi
|
fi
|
||||||
|
|
||||||
printf 'Profiles validated (where tooling was available).\n'
|
printf 'Profiles validated (where tooling was available).\n'
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -45,7 +45,7 @@ runtime wiring, CLI usage) and leaves connector/internal customization for later
|
|||||||
4. Start the web service from the repository root:
|
4. Start the web service from the repository root:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
dotnet run --project src/StellaOps.Concelier.WebService
|
dotnet run --project src/Concelier/StellaOps.Concelier.WebService
|
||||||
```
|
```
|
||||||
|
|
||||||
On startup Concelier validates the options, boots MongoDB indexes, loads plug-ins,
|
On startup Concelier validates the options, boots MongoDB indexes, loads plug-ins,
|
||||||
@@ -94,7 +94,7 @@ Rollout checkpoints for the two Authority toggles:
|
|||||||
## 2 · Configure the CLI
|
## 2 · Configure the CLI
|
||||||
|
|
||||||
The CLI reads configuration from JSON/YAML files *and* environment variables. The
|
The CLI reads configuration from JSON/YAML files *and* environment variables. The
|
||||||
defaults live in `src/StellaOps.Cli/appsettings.json` and expect overrides at runtime.
|
defaults live in `src/Cli/StellaOps.Cli/appsettings.json` and expect overrides at runtime.
|
||||||
|
|
||||||
| Setting | Environment variable | Default | Purpose |
|
| Setting | Environment variable | Default | Purpose |
|
||||||
| ------- | -------------------- | ------- | ------- |
|
| ------- | -------------------- | ------- | ------- |
|
||||||
@@ -123,12 +123,12 @@ export STELLAOPS_AUTHORITY_URL="https://authority.local"
|
|||||||
export STELLAOPS_AUTHORITY_CLIENT_ID="concelier-cli"
|
export STELLAOPS_AUTHORITY_CLIENT_ID="concelier-cli"
|
||||||
export STELLAOPS_AUTHORITY_CLIENT_SECRET="s3cr3t"
|
export STELLAOPS_AUTHORITY_CLIENT_SECRET="s3cr3t"
|
||||||
export STELLAOPS_AUTHORITY_SCOPE="concelier.jobs.trigger advisory:ingest advisory:read"
|
export STELLAOPS_AUTHORITY_SCOPE="concelier.jobs.trigger advisory:ingest advisory:read"
|
||||||
dotnet run --project src/StellaOps.Cli -- db merge
|
dotnet run --project src/Cli/StellaOps.Cli -- db merge
|
||||||
|
|
||||||
# Acquire a bearer token and confirm cache state
|
# Acquire a bearer token and confirm cache state
|
||||||
dotnet run --project src/StellaOps.Cli -- auth login
|
dotnet run --project src/Cli/StellaOps.Cli -- auth login
|
||||||
dotnet run --project src/StellaOps.Cli -- auth status
|
dotnet run --project src/Cli/StellaOps.Cli -- auth status
|
||||||
dotnet run --project src/StellaOps.Cli -- auth whoami
|
dotnet run --project src/Cli/StellaOps.Cli -- auth whoami
|
||||||
```
|
```
|
||||||
|
|
||||||
Refer to `docs/dev/32_AUTH_CLIENT_GUIDE.md` for deeper guidance on tuning retry/offline settings and rollout checklists.
|
Refer to `docs/dev/32_AUTH_CLIENT_GUIDE.md` for deeper guidance on tuning retry/offline settings and rollout checklists.
|
||||||
@@ -143,31 +143,31 @@ rely on environment variables for ephemeral runners.
|
|||||||
1. **Trigger connector fetch stages**
|
1. **Trigger connector fetch stages**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
dotnet run --project src/StellaOps.Cli -- db fetch --source osv --stage fetch
|
dotnet run --project src/Cli/StellaOps.Cli -- db fetch --source osv --stage fetch
|
||||||
dotnet run --project src/StellaOps.Cli -- db fetch --source osv --stage parse
|
dotnet run --project src/Cli/StellaOps.Cli -- db fetch --source osv --stage parse
|
||||||
dotnet run --project src/StellaOps.Cli -- db fetch --source osv --stage map
|
dotnet run --project src/Cli/StellaOps.Cli -- db fetch --source osv --stage map
|
||||||
```
|
```
|
||||||
|
|
||||||
Use `--mode resume` when continuing from a previous window:
|
Use `--mode resume` when continuing from a previous window:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
dotnet run --project src/StellaOps.Cli -- db fetch --source redhat --stage fetch --mode resume
|
dotnet run --project src/Cli/StellaOps.Cli -- db fetch --source redhat --stage fetch --mode resume
|
||||||
```
|
```
|
||||||
|
|
||||||
2. **Merge canonical advisories**
|
2. **Merge canonical advisories**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
dotnet run --project src/StellaOps.Cli -- db merge
|
dotnet run --project src/Cli/StellaOps.Cli -- db merge
|
||||||
```
|
```
|
||||||
|
|
||||||
3. **Produce exports**
|
3. **Produce exports**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# JSON tree (vuln-list style)
|
# JSON tree (vuln-list style)
|
||||||
dotnet run --project src/StellaOps.Cli -- db export --format json
|
dotnet run --project src/Cli/StellaOps.Cli -- db export --format json
|
||||||
|
|
||||||
# Trivy DB (delta example)
|
# Trivy DB (delta example)
|
||||||
dotnet run --project src/StellaOps.Cli -- db export --format trivy-db --delta
|
dotnet run --project src/Cli/StellaOps.Cli -- db export --format trivy-db --delta
|
||||||
```
|
```
|
||||||
|
|
||||||
Concelier always produces a deterministic OCI layout. The first run after a clean
|
Concelier always produces a deterministic OCI layout. The first run after a clean
|
||||||
@@ -207,13 +207,13 @@ rely on environment variables for ephemeral runners.
|
|||||||
```bash
|
```bash
|
||||||
export STELLA_TENANT="${STELLA_TENANT:-tenant-a}"
|
export STELLA_TENANT="${STELLA_TENANT:-tenant-a}"
|
||||||
|
|
||||||
dotnet run --project src/StellaOps.Cli -- aoc verify \
|
dotnet run --project src/Cli/StellaOps.Cli -- aoc verify \
|
||||||
--since 24h \
|
--since 24h \
|
||||||
--format table \
|
--format table \
|
||||||
--tenant "$STELLA_TENANT"
|
--tenant "$STELLA_TENANT"
|
||||||
|
|
||||||
# Optional: capture JSON evidence for pipelines/audits
|
# Optional: capture JSON evidence for pipelines/audits
|
||||||
dotnet run --project src/StellaOps.Cli -- aoc verify \
|
dotnet run --project src/Cli/StellaOps.Cli -- aoc verify \
|
||||||
--since 7d \
|
--since 7d \
|
||||||
--limit 100 \
|
--limit 100 \
|
||||||
--format json \
|
--format json \
|
||||||
@@ -244,9 +244,9 @@ rely on environment variables for ephemeral runners.
|
|||||||
6. **Manage scanners (optional)**
|
6. **Manage scanners (optional)**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
dotnet run --project src/StellaOps.Cli -- scanner download --channel stable
|
dotnet run --project src/Cli/StellaOps.Cli -- scanner download --channel stable
|
||||||
dotnet run --project src/StellaOps.Cli -- scan run --entry scanners/latest/Scanner.dll --target ./sboms
|
dotnet run --project src/Cli/StellaOps.Cli -- scan run --entry scanners/latest/Scanner.dll --target ./sboms
|
||||||
dotnet run --project src/StellaOps.Cli -- scan upload --file results/scan-001.json
|
dotnet run --project src/Cli/StellaOps.Cli -- scan upload --file results/scan-001.json
|
||||||
```
|
```
|
||||||
|
|
||||||
Add `--verbose` to any command for structured console logs. All commands honour
|
Add `--verbose` to any command for structured console logs. All commands honour
|
||||||
|
|||||||
@@ -1,380 +1,380 @@
|
|||||||
# StellaOps Authority Service
|
# StellaOps Authority Service
|
||||||
|
|
||||||
> **Status:** Drafted 2025-10-12 (CORE5B.DOC / DOC1.AUTH) – aligns with Authority revocation store, JWKS rotation, and bootstrap endpoints delivered in Sprint 1.
|
> **Status:** Drafted 2025-10-12 (CORE5B.DOC / DOC1.AUTH) – aligns with Authority revocation store, JWKS rotation, and bootstrap endpoints delivered in Sprint 1.
|
||||||
|
|
||||||
## 1. Purpose
|
## 1. Purpose
|
||||||
The **StellaOps Authority** service issues OAuth2/OIDC tokens for every StellaOps module (Concelier, Backend, Agent, Zastava) and exposes the policy controls required in sovereign/offline environments. Authority is built as a minimal ASP.NET host that:
|
The **StellaOps Authority** service issues OAuth2/OIDC tokens for every StellaOps module (Concelier, Backend, Agent, Zastava) and exposes the policy controls required in sovereign/offline environments. Authority is built as a minimal ASP.NET host that:
|
||||||
|
|
||||||
- brokers password, client-credentials, and device-code flows through pluggable identity providers;
|
- brokers password, client-credentials, and device-code flows through pluggable identity providers;
|
||||||
- persists access/refresh/device tokens in MongoDB with deterministic schemas for replay analysis and air-gapped audit copies;
|
- persists access/refresh/device tokens in MongoDB with deterministic schemas for replay analysis and air-gapped audit copies;
|
||||||
- distributes revocation bundles and JWKS material so downstream services can enforce lockouts without direct database access;
|
- distributes revocation bundles and JWKS material so downstream services can enforce lockouts without direct database access;
|
||||||
- offers bootstrap APIs for first-run provisioning and key rotation without redeploying binaries.
|
- offers bootstrap APIs for first-run provisioning and key rotation without redeploying binaries.
|
||||||
|
|
||||||
Authority is deployed alongside Concelier in air-gapped environments and never requires outbound internet access. All trusted metadata (OpenIddict discovery, JWKS, revocation bundles) is cacheable, signed, and reproducible.
|
Authority is deployed alongside Concelier in air-gapped environments and never requires outbound internet access. All trusted metadata (OpenIddict discovery, JWKS, revocation bundles) is cacheable, signed, and reproducible.
|
||||||
|
|
||||||
## 2. Component Architecture
|
## 2. Component Architecture
|
||||||
Authority is composed of five cooperating subsystems:
|
Authority is composed of five cooperating subsystems:
|
||||||
|
|
||||||
1. **Minimal API host** – configures OpenIddict endpoints (`/token`, `/authorize`, `/revoke`, `/jwks`), publishes the OpenAPI contract at `/.well-known/openapi`, and enables structured logging/telemetry. Rate limiting hooks (`AuthorityRateLimiter`) wrap every request.
|
1. **Minimal API host** – configures OpenIddict endpoints (`/token`, `/authorize`, `/revoke`, `/jwks`), publishes the OpenAPI contract at `/.well-known/openapi`, and enables structured logging/telemetry. Rate limiting hooks (`AuthorityRateLimiter`) wrap every request.
|
||||||
2. **Plugin host** – loads `StellaOps.Authority.Plugin.*.dll` assemblies, applies capability metadata, and exposes password/client provisioning surfaces through dependency injection.
|
2. **Plugin host** – loads `StellaOps.Authority.Plugin.*.dll` assemblies, applies capability metadata, and exposes password/client provisioning surfaces through dependency injection.
|
||||||
3. **Mongo storage** – persists tokens, revocations, bootstrap invites, and plugin state in deterministic collections indexed for offline sync (`authority_tokens`, `authority_revocations`, etc.).
|
3. **Mongo storage** – persists tokens, revocations, bootstrap invites, and plugin state in deterministic collections indexed for offline sync (`authority_tokens`, `authority_revocations`, etc.).
|
||||||
4. **Cryptography layer** – `StellaOps.Cryptography` abstractions manage password hashing, signing keys, JWKS export, and detached JWS generation.
|
4. **Cryptography layer** – `StellaOps.Cryptography` abstractions manage password hashing, signing keys, JWKS export, and detached JWS generation.
|
||||||
5. **Offline ops APIs** – internal endpoints under `/internal/*` provide administrative flows (bootstrap users/clients, revocation export) guarded by API keys and deterministic audit events.
|
5. **Offline ops APIs** – internal endpoints under `/internal/*` provide administrative flows (bootstrap users/clients, revocation export) guarded by API keys and deterministic audit events.
|
||||||
|
|
||||||
A high-level sequence for password logins:
|
A high-level sequence for password logins:
|
||||||
|
|
||||||
```
|
```
|
||||||
Client -> /token (password grant)
|
Client -> /token (password grant)
|
||||||
-> Rate limiter & audit hooks
|
-> Rate limiter & audit hooks
|
||||||
-> Plugin credential store (Argon2id verification)
|
-> Plugin credential store (Argon2id verification)
|
||||||
-> Token persistence (Mongo authority_tokens)
|
-> Token persistence (Mongo authority_tokens)
|
||||||
-> Response (access/refresh tokens + deterministic claims)
|
-> Response (access/refresh tokens + deterministic claims)
|
||||||
```
|
```
|
||||||
|
|
||||||
## 3. Token Lifecycle & Persistence
|
## 3. Token Lifecycle & Persistence
|
||||||
Authority persists every issued token in MongoDB so operators can audit or revoke without scanning distributed caches.
|
Authority persists every issued token in MongoDB so operators can audit or revoke without scanning distributed caches.
|
||||||
|
|
||||||
- **Collection:** `authority_tokens`
|
- **Collection:** `authority_tokens`
|
||||||
- **Key fields:**
|
- **Key fields:**
|
||||||
- `tokenId`, `type` (`access_token`, `refresh_token`, `device_code`, `authorization_code`)
|
- `tokenId`, `type` (`access_token`, `refresh_token`, `device_code`, `authorization_code`)
|
||||||
- `subjectId`, `clientId`, ordered `scope` array
|
- `subjectId`, `clientId`, ordered `scope` array
|
||||||
- `tenant` (lower-cased tenant hint from the issuing client, omitted for global clients)
|
- `tenant` (lower-cased tenant hint from the issuing client, omitted for global clients)
|
||||||
|
|
||||||
### Console OIDC client
|
### Console OIDC client
|
||||||
|
|
||||||
- **Client ID**: `console-web`
|
- **Client ID**: `console-web`
|
||||||
- **Grants**: `authorization_code` (PKCE required), `refresh_token`
|
- **Grants**: `authorization_code` (PKCE required), `refresh_token`
|
||||||
- **Audience**: `console`
|
- **Audience**: `console`
|
||||||
- **Scopes**: `openid`, `profile`, `email`, `advisory:read`, `vex:read`, `aoc:verify`, `findings:read`, `orch:read`, `vuln:read`
|
- **Scopes**: `openid`, `profile`, `email`, `advisory:read`, `vex:read`, `aoc:verify`, `findings:read`, `orch:read`, `vuln:read`
|
||||||
- **Redirect URIs** (defaults): `https://console.stella-ops.local/oidc/callback`
|
- **Redirect URIs** (defaults): `https://console.stella-ops.local/oidc/callback`
|
||||||
- **Post-logout redirect**: `https://console.stella-ops.local/`
|
- **Post-logout redirect**: `https://console.stella-ops.local/`
|
||||||
- **Tokens**: Access tokens inherit the global 2 minute lifetime; refresh tokens remain short-lived (30 days) and can be exchanged silently via `/token`.
|
- **Tokens**: Access tokens inherit the global 2 minute lifetime; refresh tokens remain short-lived (30 days) and can be exchanged silently via `/token`.
|
||||||
- **Roles**: Assign Authority role `Orch.Viewer` (exposed to tenants as `role/orch-viewer`) when operators need read-only access to Orchestrator telemetry via Console dashboards. Policy Studio ships dedicated roles (`role/policy-author`, `role/policy-reviewer`, `role/policy-approver`, `role/policy-operator`, `role/policy-auditor`) that align with the new `policy:*` scope family; issue them per tenant so audit trails remain scoped.
|
- **Roles**: Assign Authority role `Orch.Viewer` (exposed to tenants as `role/orch-viewer`) when operators need read-only access to Orchestrator telemetry via Console dashboards. Policy Studio ships dedicated roles (`role/policy-author`, `role/policy-reviewer`, `role/policy-approver`, `role/policy-operator`, `role/policy-auditor`) that align with the new `policy:*` scope family; issue them per tenant so audit trails remain scoped.
|
||||||
|
|
||||||
Configuration sample (`etc/authority.yaml.sample`) seeds the client with a confidential secret so Console can negotiate the code exchange on the backend while browsers execute the PKCE dance.
|
Configuration sample (`etc/authority.yaml.sample`) seeds the client with a confidential secret so Console can negotiate the code exchange on the backend while browsers execute the PKCE dance.
|
||||||
|
|
||||||
### Console Authority endpoints
|
### Console Authority endpoints
|
||||||
|
|
||||||
- `/console/tenants` — Requires `authority:tenants.read`; returns the tenant catalogue for the authenticated principal. Requests lacking the `X-Stella-Tenant` header are rejected (`tenant_header_missing`) and logged.
|
- `/console/tenants` — Requires `authority:tenants.read`; returns the tenant catalogue for the authenticated principal. Requests lacking the `X-Stella-Tenant` header are rejected (`tenant_header_missing`) and logged.
|
||||||
- `/console/profile` — Requires `ui.read`; exposes subject metadata (roles, scopes, audiences) and indicates whether the session is within the five-minute fresh-auth window.
|
- `/console/profile` — Requires `ui.read`; exposes subject metadata (roles, scopes, audiences) and indicates whether the session is within the five-minute fresh-auth window.
|
||||||
- `/console/token/introspect` — Requires `ui.read`; introspects the active access token so the SPA can prompt for re-authentication before privileged actions.
|
- `/console/token/introspect` — Requires `ui.read`; introspects the active access token so the SPA can prompt for re-authentication before privileged actions.
|
||||||
|
|
||||||
All endpoints demand DPoP-bound tokens and propagate structured audit events (`authority.console.*`). Gateways must forward the `X-Stella-Tenant` header derived from the access token; downstream services rely on the same value for isolation. Keep Console access tokens short-lived (default 15 minutes) and enforce the fresh-auth window for admin actions (`ui.admin`, `authority:*`, `policy:activate`, `exceptions:approve`).
|
All endpoints demand DPoP-bound tokens and propagate structured audit events (`authority.console.*`). Gateways must forward the `X-Stella-Tenant` header derived from the access token; downstream services rely on the same value for isolation. Keep Console access tokens short-lived (default 15 minutes) and enforce the fresh-auth window for admin actions (`ui.admin`, `authority:*`, `policy:activate`, `exceptions:approve`).
|
||||||
- `status` (`valid`, `revoked`, `expired`), `createdAt`, optional `expiresAt`
|
- `status` (`valid`, `revoked`, `expired`), `createdAt`, optional `expiresAt`
|
||||||
- `revokedAt`, machine-readable `revokedReason`, optional `revokedReasonDescription`
|
- `revokedAt`, machine-readable `revokedReason`, optional `revokedReasonDescription`
|
||||||
- `revokedMetadata` (string dictionary for plugin-specific context)
|
- `revokedMetadata` (string dictionary for plugin-specific context)
|
||||||
- **Persistence flow:** `PersistTokensHandler` stamps missing JWT IDs, normalises scopes, and stores every principal emitted by OpenIddict.
|
- **Persistence flow:** `PersistTokensHandler` stamps missing JWT IDs, normalises scopes, and stores every principal emitted by OpenIddict.
|
||||||
- **Revocation flow:** `AuthorityTokenStore.UpdateStatusAsync` flips status, records the reason metadata, and is invoked by token revocation handlers and plugin provisioning events (e.g., disabling a user).
|
- **Revocation flow:** `AuthorityTokenStore.UpdateStatusAsync` flips status, records the reason metadata, and is invoked by token revocation handlers and plugin provisioning events (e.g., disabling a user).
|
||||||
- **Expiry maintenance:** `AuthorityTokenStore.DeleteExpiredAsync` prunes non-revoked tokens past their `expiresAt` timestamp. Operators should schedule this in maintenance windows if large volumes of tokens are issued.
|
- **Expiry maintenance:** `AuthorityTokenStore.DeleteExpiredAsync` prunes non-revoked tokens past their `expiresAt` timestamp. Operators should schedule this in maintenance windows if large volumes of tokens are issued.
|
||||||
|
|
||||||
### Expectations for resource servers
|
### Expectations for resource servers
|
||||||
Resource servers (Concelier WebService, Backend, Agent) **must not** assume in-memory caches are authoritative. They should:
|
Resource servers (Concelier WebService, Backend, Agent) **must not** assume in-memory caches are authoritative. They should:
|
||||||
|
|
||||||
- cache `/jwks` and `/revocations/export` responses within configured lifetimes;
|
- cache `/jwks` and `/revocations/export` responses within configured lifetimes;
|
||||||
- honour `revokedReason` metadata when shaping audit trails;
|
- honour `revokedReason` metadata when shaping audit trails;
|
||||||
- treat `status != "valid"` or missing tokens as immediate denial conditions.
|
- treat `status != "valid"` or missing tokens as immediate denial conditions.
|
||||||
- propagate the `tenant` claim (`X-Stella-Tenant` header in REST calls) and reject requests when the tenant supplied by Authority does not match the resource server's scope; Concelier and Excititor guard endpoints refuse cross-tenant tokens.
|
- propagate the `tenant` claim (`X-Stella-Tenant` header in REST calls) and reject requests when the tenant supplied by Authority does not match the resource server's scope; Concelier and Excititor guard endpoints refuse cross-tenant tokens.
|
||||||
|
|
||||||
### Tenant propagation
|
### Tenant propagation
|
||||||
|
|
||||||
- Client provisioning (bootstrap or plug-in) accepts a `tenant` hint. Authority normalises the value (`trim().ToLowerInvariant()`) and persists it alongside the registration. Clients without an explicit tenant remain global.
|
- Client provisioning (bootstrap or plug-in) accepts a `tenant` hint. Authority normalises the value (`trim().ToLowerInvariant()`) and persists it alongside the registration. Clients without an explicit tenant remain global.
|
||||||
- Issued principals include the `stellaops:tenant` claim. `PersistTokensHandler` mirrors this claim into `authority_tokens.tenant`, enabling per-tenant revocation and reporting.
|
- Issued principals include the `stellaops:tenant` claim. `PersistTokensHandler` mirrors this claim into `authority_tokens.tenant`, enabling per-tenant revocation and reporting.
|
||||||
- Rate limiter metadata now tags requests with `authority.tenant`, unlocking per-tenant throughput metrics and diagnostic filters. Audit events (`authority.client_credentials.grant`, `authority.password.grant`, bootstrap flows) surface the tenant and login attempt documents index on `{tenant, occurredAt}` for quick queries.
|
- Rate limiter metadata now tags requests with `authority.tenant`, unlocking per-tenant throughput metrics and diagnostic filters. Audit events (`authority.client_credentials.grant`, `authority.password.grant`, bootstrap flows) surface the tenant and login attempt documents index on `{tenant, occurredAt}` for quick queries.
|
||||||
- Client credentials that request `advisory:ingest`, `advisory:read`, `vex:ingest`, `vex:read`, `signals:read`, `signals:write`, `signals:admin`, or `aoc:verify` now fail fast when the client registration lacks a tenant hint. Issued tokens are re-validated against persisted tenant metadata, and Authority rejects any cross-tenant replay (`invalid_client`/`invalid_token`), ensuring aggregation-only workloads remain tenant-scoped.
|
- Client credentials that request `advisory:ingest`, `advisory:read`, `vex:ingest`, `vex:read`, `signals:read`, `signals:write`, `signals:admin`, or `aoc:verify` now fail fast when the client registration lacks a tenant hint. Issued tokens are re-validated against persisted tenant metadata, and Authority rejects any cross-tenant replay (`invalid_client`/`invalid_token`), ensuring aggregation-only workloads remain tenant-scoped.
|
||||||
- Client credentials that request `export.viewer`, `export.operator`, or `export.admin` must provide a tenant hint. Requests for `export.admin` also need accompanying `export_reason` and `export_ticket` parameters; Authority returns `invalid_request` when either value is missing and records the denial in token audit events.
|
- Client credentials that request `export.viewer`, `export.operator`, or `export.admin` must provide a tenant hint. Requests for `export.admin` also need accompanying `export_reason` and `export_ticket` parameters; Authority returns `invalid_request` when either value is missing and records the denial in token audit events.
|
||||||
- Policy Studio scopes (`policy:author`, `policy:review`, `policy:approve`, `policy:operate`, `policy:audit`, `policy:simulate`, `policy:run`, `policy:activate`) require a tenant assignment; Authority rejects tokens missing the hint with `invalid_client` and records `scope.invalid` metadata for auditing.
|
- Policy Studio scopes (`policy:author`, `policy:review`, `policy:approve`, `policy:operate`, `policy:audit`, `policy:simulate`, `policy:run`, `policy:activate`) require a tenant assignment; Authority rejects tokens missing the hint with `invalid_client` and records `scope.invalid` metadata for auditing.
|
||||||
- **AOC pairing guardrails** – Tokens that request `advisory:read`, `vex:read`, or any `signals:*` scope must also request `aoc:verify`. Authority rejects mismatches with `invalid_scope` (`Scope 'aoc:verify' is required when requesting advisory/vex read scopes.` or `Scope 'aoc:verify' is required when requesting signals scopes.`) so automation surfaces deterministic errors.
|
- **AOC pairing guardrails** – Tokens that request `advisory:read`, `vex:read`, or any `signals:*` scope must also request `aoc:verify`. Authority rejects mismatches with `invalid_scope` (`Scope 'aoc:verify' is required when requesting advisory/vex read scopes.` or `Scope 'aoc:verify' is required when requesting signals scopes.`) so automation surfaces deterministic errors.
|
||||||
- **Signals ingestion guardrails** – Sensors and services requesting `signals:write`/`signals:admin` must also request `aoc:verify`; Authority records the `authority.aoc_scope_violation` tag when the pairing is missing so operators can trace failing sensors immediately.
|
- **Signals ingestion guardrails** – Sensors and services requesting `signals:write`/`signals:admin` must also request `aoc:verify`; Authority records the `authority.aoc_scope_violation` tag when the pairing is missing so operators can trace failing sensors immediately.
|
||||||
- Password grant flows reuse the client registration's tenant and enforce the configured scope allow-list. Requested scopes outside that list (or mismatched tenants) trigger `invalid_scope`/`invalid_client` failures, ensuring cross-tenant access is denied before token issuance.
|
- Password grant flows reuse the client registration's tenant and enforce the configured scope allow-list. Requested scopes outside that list (or mismatched tenants) trigger `invalid_scope`/`invalid_client` failures, ensuring cross-tenant access is denied before token issuance.
|
||||||
|
|
||||||
### Default service scopes
|
### Default service scopes
|
||||||
|
|
||||||
| Client ID | Purpose | Scopes granted | Sender constraint | Tenant |
|
| Client ID | Purpose | Scopes granted | Sender constraint | Tenant |
|
||||||
|----------------------|---------------------------------------|--------------------------------------|-------------------|-----------------|
|
|----------------------|---------------------------------------|--------------------------------------|-------------------|-----------------|
|
||||||
| `concelier-ingest` | Concelier raw advisory ingestion | `advisory:ingest`, `advisory:read` | `dpop` | `tenant-default` |
|
| `concelier-ingest` | Concelier raw advisory ingestion | `advisory:ingest`, `advisory:read` | `dpop` | `tenant-default` |
|
||||||
| `excitor-ingest` | Excititor raw VEX ingestion | `vex:ingest`, `vex:read` | `dpop` | `tenant-default` |
|
| `excitor-ingest` | Excititor raw VEX ingestion | `vex:ingest`, `vex:read` | `dpop` | `tenant-default` |
|
||||||
| `aoc-verifier` | Aggregation-only contract verification | `aoc:verify`, `advisory:read`, `vex:read` | `dpop` | `tenant-default` |
|
| `aoc-verifier` | Aggregation-only contract verification | `aoc:verify`, `advisory:read`, `vex:read` | `dpop` | `tenant-default` |
|
||||||
| `cartographer-service` | Graph snapshot construction | `graph:write`, `graph:read` | `dpop` | `tenant-default` |
|
| `cartographer-service` | Graph snapshot construction | `graph:write`, `graph:read` | `dpop` | `tenant-default` |
|
||||||
| `graph-api` | Graph Explorer gateway/API | `graph:read`, `graph:export`, `graph:simulate` | `dpop` | `tenant-default` |
|
| `graph-api` | Graph Explorer gateway/API | `graph:read`, `graph:export`, `graph:simulate` | `dpop` | `tenant-default` |
|
||||||
| `export-center-operator` | Export Center operator automation | `export.viewer`, `export.operator` | `dpop` | `tenant-default` |
|
| `export-center-operator` | Export Center operator automation | `export.viewer`, `export.operator` | `dpop` | `tenant-default` |
|
||||||
| `export-center-admin` | Export Center administrative automation | `export.viewer`, `export.operator`, `export.admin` | `dpop` | `tenant-default` |
|
| `export-center-admin` | Export Center administrative automation | `export.viewer`, `export.operator`, `export.admin` | `dpop` | `tenant-default` |
|
||||||
| `vuln-explorer-ui` | Vuln Explorer UI/API | `vuln:read` | `dpop` | `tenant-default` |
|
| `vuln-explorer-ui` | Vuln Explorer UI/API | `vuln:read` | `dpop` | `tenant-default` |
|
||||||
| `signals-uploader` | Reachability sensor ingestion | `signals:write`, `signals:read`, `aoc:verify` | `dpop` | `tenant-default` |
|
| `signals-uploader` | Reachability sensor ingestion | `signals:write`, `signals:read`, `aoc:verify` | `dpop` | `tenant-default` |
|
||||||
|
|
||||||
> **Secret hygiene (2025‑10‑27):** The repository includes a convenience `etc/authority.yaml` for compose/helm smoke tests. Every entry’s `secretFile` points to `etc/secrets/*.secret`, which ship with `*-change-me` placeholders—replace them with strong values (and wire them through your vault/secret manager) before issuing tokens in CI, staging, or production.
|
> **Secret hygiene (2025‑10‑27):** The repository includes a convenience `etc/authority.yaml` for compose/helm smoke tests. Every entry’s `secretFile` points to `etc/secrets/*.secret`, which ship with `*-change-me` placeholders—replace them with strong values (and wire them through your vault/secret manager) before issuing tokens in CI, staging, or production.
|
||||||
|
|
||||||
For factory provisioning, issue sensors the **SignalsUploader** role template (`signals:write`, `signals:read`, `aoc:verify`). Authority rejects ingestion tokens that omit `aoc:verify`, preserving aggregation-only contract guarantees for reachability signals.
|
For factory provisioning, issue sensors the **SignalsUploader** role template (`signals:write`, `signals:read`, `aoc:verify`). Authority rejects ingestion tokens that omit `aoc:verify`, preserving aggregation-only contract guarantees for reachability signals.
|
||||||
|
|
||||||
These registrations are provided as examples in `etc/authority.yaml.sample`. Clone them per tenant (for example `concelier-tenant-a`, `concelier-tenant-b`) so tokens remain tenant-scoped by construction.
|
These registrations are provided as examples in `etc/authority.yaml.sample`. Clone them per tenant (for example `concelier-tenant-a`, `concelier-tenant-b`) so tokens remain tenant-scoped by construction.
|
||||||
|
|
||||||
Graph Explorer introduces dedicated scopes: `graph:write` for Cartographer build jobs, `graph:read` for query/read operations, `graph:export` for long-running export downloads, and `graph:simulate` for what-if overlays. Assign only the scopes a client actually needs to preserve least privilege—UI-facing clients should typically request read/export access, while background services (Cartographer, Scheduler) require write privileges.
|
Graph Explorer introduces dedicated scopes: `graph:write` for Cartographer build jobs, `graph:read` for query/read operations, `graph:export` for long-running export downloads, and `graph:simulate` for what-if overlays. Assign only the scopes a client actually needs to preserve least privilege—UI-facing clients should typically request read/export access, while background services (Cartographer, Scheduler) require write privileges.
|
||||||
|
|
||||||
#### Least-privilege guidance for graph clients
|
#### Least-privilege guidance for graph clients
|
||||||
|
|
||||||
- **Service identities** – The Cartographer worker should request `graph:write` and `graph:read` only; grant `graph:simulate` exclusively to pipeline automation that invokes Policy Engine overlays on demand. Keep `graph:export` scoped to API gateway components responsible for streaming GraphML/JSONL artifacts. Authority enforces this by rejecting `graph:write` tokens that lack `properties.serviceIdentity: cartographer`.
|
- **Service identities** – The Cartographer worker should request `graph:write` and `graph:read` only; grant `graph:simulate` exclusively to pipeline automation that invokes Policy Engine overlays on demand. Keep `graph:export` scoped to API gateway components responsible for streaming GraphML/JSONL artifacts. Authority enforces this by rejecting `graph:write` tokens that lack `properties.serviceIdentity: cartographer`.
|
||||||
- **Tenant propagation** – Every client registration must pin a `tenant` hint. Authority normalises the value and stamps it into issued tokens (`stellaops:tenant`) so downstream services (Scheduler, Graph API, Console) can enforce tenant isolation without custom headers. Graph scopes (`graph:read`, `graph:write`, `graph:export`, `graph:simulate`) are denied if the tenant hint is missing.
|
- **Tenant propagation** – Every client registration must pin a `tenant` hint. Authority normalises the value and stamps it into issued tokens (`stellaops:tenant`) so downstream services (Scheduler, Graph API, Console) can enforce tenant isolation without custom headers. Graph scopes (`graph:read`, `graph:write`, `graph:export`, `graph:simulate`) are denied if the tenant hint is missing.
|
||||||
- **SDK alignment** – Use the generated `StellaOpsScopes` constants in service code to request graph scopes. Hard-coded strings risk falling out of sync as additional graph capabilities are added.
|
- **SDK alignment** – Use the generated `StellaOpsScopes` constants in service code to request graph scopes. Hard-coded strings risk falling out of sync as additional graph capabilities are added.
|
||||||
- **DPOP for automation** – Maintain sender-constrained (`dpop`) flows for Cartographer and Scheduler to limit reuse of access tokens if a build host is compromised. For UI-facing tokens, pair `graph:read`/`graph:export` with short lifetimes and enforce refresh-token rotation at the gateway.
|
- **DPOP for automation** – Maintain sender-constrained (`dpop`) flows for Cartographer and Scheduler to limit reuse of access tokens if a build host is compromised. For UI-facing tokens, pair `graph:read`/`graph:export` with short lifetimes and enforce refresh-token rotation at the gateway.
|
||||||
|
|
||||||
#### Export Center scope guardrails
|
#### Export Center scope guardrails
|
||||||
|
|
||||||
- **Viewer vs operator** – `export.viewer` grants read-only access to export profiles, manifests, and bundles. Automation that schedules or reruns exports should request `export.operator` (and typically `export.viewer`). Tenant hints remain mandatory; Authority refuses tokens without them.
|
- **Viewer vs operator** – `export.viewer` grants read-only access to export profiles, manifests, and bundles. Automation that schedules or reruns exports should request `export.operator` (and typically `export.viewer`). Tenant hints remain mandatory; Authority refuses tokens without them.
|
||||||
- **Administrative mutations** – Changes to retention policies, encryption key references, or schedule defaults require `export.admin`. When requesting tokens with this scope, clients must supply `export_reason` and `export_ticket` parameters; Authority persists the values for audit records and rejects missing metadata with `invalid_request`.
|
- **Administrative mutations** – Changes to retention policies, encryption key references, or schedule defaults require `export.admin`. When requesting tokens with this scope, clients must supply `export_reason` and `export_ticket` parameters; Authority persists the values for audit records and rejects missing metadata with `invalid_request`.
|
||||||
- **Operational hygiene** – Rotate `export.admin` credentials infrequently and run them through fresh-auth workflows where possible. Prefer distributing verification tooling with `export.viewer` tokens for day-to-day bundle validation.
|
- **Operational hygiene** – Rotate `export.admin` credentials infrequently and run them through fresh-auth workflows where possible. Prefer distributing verification tooling with `export.viewer` tokens for day-to-day bundle validation.
|
||||||
|
|
||||||
#### Vuln Explorer permalinks
|
#### Vuln Explorer permalinks
|
||||||
|
|
||||||
- **Scope** – `vuln:read` authorises Vuln Explorer to fetch advisory/linkset evidence and issue shareable links. Assign it only to front-end/API clients that must render vulnerability details.
|
- **Scope** – `vuln:read` authorises Vuln Explorer to fetch advisory/linkset evidence and issue shareable links. Assign it only to front-end/API clients that must render vulnerability details.
|
||||||
- **Signed links** – `POST /permalinks/vuln` (requires `vuln:read`) accepts `{ "tenant": "tenant-a", "resourceKind": "vulnerability", "state": { ... }, "expiresInSeconds": 86400 }` and returns a JWT (`token`) plus `issuedAt`/`expiresAt`. The token embeds the tenant, requested state, and `vuln:read` scope and is signed with the same Authority signing keys published via `/jwks`.
|
- **Signed links** – `POST /permalinks/vuln` (requires `vuln:read`) accepts `{ "tenant": "tenant-a", "resourceKind": "vulnerability", "state": { ... }, "expiresInSeconds": 86400 }` and returns a JWT (`token`) plus `issuedAt`/`expiresAt`. The token embeds the tenant, requested state, and `vuln:read` scope and is signed with the same Authority signing keys published via `/jwks`.
|
||||||
- **Validation** – Resource servers verify the permalink using cached JWKS: check signature, ensure the tenant matches the current request context, honour the expiry, and enforce the contained `vuln:read` scope. The payload’s `resource.state` block is opaque JSON so UIs can round-trip filters/search terms without new schema changes.
|
- **Validation** – Resource servers verify the permalink using cached JWKS: check signature, ensure the tenant matches the current request context, honour the expiry, and enforce the contained `vuln:read` scope. The payload’s `resource.state` block is opaque JSON so UIs can round-trip filters/search terms without new schema changes.
|
||||||
|
|
||||||
## 4. Revocation Pipeline
|
## 4. Revocation Pipeline
|
||||||
Authority centralises revocation in `authority_revocations` with deterministic categories:
|
Authority centralises revocation in `authority_revocations` with deterministic categories:
|
||||||
|
|
||||||
| Category | Meaning | Required fields |
|
| Category | Meaning | Required fields |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `token` | Specific OAuth token revoked early. | `revocationId` (token id), `tokenType`, optional `clientId`, `subjectId` |
|
| `token` | Specific OAuth token revoked early. | `revocationId` (token id), `tokenType`, optional `clientId`, `subjectId` |
|
||||||
| `subject` | All tokens for a subject disabled. | `revocationId` (= subject id) |
|
| `subject` | All tokens for a subject disabled. | `revocationId` (= subject id) |
|
||||||
| `client` | OAuth client registration revoked. | `revocationId` (= client id) |
|
| `client` | OAuth client registration revoked. | `revocationId` (= client id) |
|
||||||
| `key` | Signing/JWE key withdrawn. | `revocationId` (= key id) |
|
| `key` | Signing/JWE key withdrawn. | `revocationId` (= key id) |
|
||||||
|
|
||||||
`RevocationBundleBuilder` flattens Mongo documents into canonical JSON, sorts entries by (`category`, `revocationId`, `revokedAt`), and signs exports using detached JWS (RFC 7797) with cosign-compatible headers.
|
`RevocationBundleBuilder` flattens Mongo documents into canonical JSON, sorts entries by (`category`, `revocationId`, `revokedAt`), and signs exports using detached JWS (RFC 7797) with cosign-compatible headers.
|
||||||
|
|
||||||
**Export surfaces** (deterministic output, suitable for Offline Kit):
|
**Export surfaces** (deterministic output, suitable for Offline Kit):
|
||||||
|
|
||||||
- CLI: `stella auth revoke export --output ./out` writes `revocation-bundle.json`, `.jws`, `.sha256`.
|
- CLI: `stella auth revoke export --output ./out` writes `revocation-bundle.json`, `.jws`, `.sha256`.
|
||||||
- Verification: `stella auth revoke verify --bundle <path> --signature <path> --key <path>` validates detached JWS signatures before distribution, selecting the crypto provider advertised in the detached header (see `docs/security/revocation-bundle.md`).
|
- Verification: `stella auth revoke verify --bundle <path> --signature <path> --key <path>` validates detached JWS signatures before distribution, selecting the crypto provider advertised in the detached header (see `docs/security/revocation-bundle.md`).
|
||||||
- API: `GET /internal/revocations/export` (requires bootstrap API key) returns the same payload.
|
- API: `GET /internal/revocations/export` (requires bootstrap API key) returns the same payload.
|
||||||
- Verification: `stella auth revoke verify` validates schema, digest, and detached JWS using cached JWKS or offline keys, automatically preferring the hinted provider (libsodium builds honour `provider=libsodium`; other builds fall back to the managed provider).
|
- Verification: `stella auth revoke verify` validates schema, digest, and detached JWS using cached JWKS or offline keys, automatically preferring the hinted provider (libsodium builds honour `provider=libsodium`; other builds fall back to the managed provider).
|
||||||
|
|
||||||
**Consumer guidance:**
|
**Consumer guidance:**
|
||||||
|
|
||||||
1. Mirror `revocation-bundle.json*` alongside Concelier exports. Offline agents fetch both over the existing update channel.
|
1. Mirror `revocation-bundle.json*` alongside Concelier exports. Offline agents fetch both over the existing update channel.
|
||||||
2. Use bundle `sequence` and `bundleId` to detect replay or monotonicity regressions. Ignore bundles with older sequence numbers unless `bundleId` changes and `issuedAt` advances.
|
2. Use bundle `sequence` and `bundleId` to detect replay or monotonicity regressions. Ignore bundles with older sequence numbers unless `bundleId` changes and `issuedAt` advances.
|
||||||
3. Treat `revokedReason` taxonomy as machine-friendly codes (`compromised`, `rotation`, `policy`, `lifecycle`). Translating to human-readable logs is the consumer’s responsibility.
|
3. Treat `revokedReason` taxonomy as machine-friendly codes (`compromised`, `rotation`, `policy`, `lifecycle`). Translating to human-readable logs is the consumer’s responsibility.
|
||||||
|
|
||||||
## 5. Signing Keys & JWKS Rotation
|
## 5. Signing Keys & JWKS Rotation
|
||||||
Authority signs revocation bundles and publishes JWKS entries via the new signing manager:
|
Authority signs revocation bundles and publishes JWKS entries via the new signing manager:
|
||||||
|
|
||||||
- **Configuration (`authority.yaml`):**
|
- **Configuration (`authority.yaml`):**
|
||||||
```yaml
|
```yaml
|
||||||
signing:
|
signing:
|
||||||
enabled: true
|
enabled: true
|
||||||
algorithm: ES256 # Defaults to ES256
|
algorithm: ES256 # Defaults to ES256
|
||||||
keySource: file # Loader identifier (file, vault, etc.)
|
keySource: file # Loader identifier (file, vault, etc.)
|
||||||
provider: default # Optional preferred crypto provider
|
provider: default # Optional preferred crypto provider
|
||||||
activeKeyId: authority-signing-dev
|
activeKeyId: authority-signing-dev
|
||||||
keyPath: "../certificates/authority-signing-dev.pem"
|
keyPath: "../certificates/authority-signing-dev.pem"
|
||||||
additionalKeys:
|
additionalKeys:
|
||||||
- keyId: authority-signing-dev-2024
|
- keyId: authority-signing-dev-2024
|
||||||
path: "../certificates/authority-signing-dev-2024.pem"
|
path: "../certificates/authority-signing-dev-2024.pem"
|
||||||
source: "file"
|
source: "file"
|
||||||
```
|
```
|
||||||
- **Sources:** The default loader supports PEM files relative to the content root; additional loaders can be registered via `IAuthoritySigningKeySource`.
|
- **Sources:** The default loader supports PEM files relative to the content root; additional loaders can be registered via `IAuthoritySigningKeySource`.
|
||||||
- **Providers:** Keys are registered against the `ICryptoProviderRegistry`, so alternative implementations (HSM, libsodium) can be plugged in without changing host code.
|
- **Providers:** Keys are registered against the `ICryptoProviderRegistry`, so alternative implementations (HSM, libsodium) can be plugged in without changing host code.
|
||||||
- **OpenAPI discovery:** `GET /.well-known/openapi` returns the published authentication contract (JSON by default, YAML when requested). Responses include `X-StellaOps-Service`, `X-StellaOps-Api-Version`, `X-StellaOps-Build-Version`, plus grant and scope headers, and honour conditional requests via `ETag`/`If-None-Match`.
|
- **OpenAPI discovery:** `GET /.well-known/openapi` returns the published authentication contract (JSON by default, YAML when requested). Responses include `X-StellaOps-Service`, `X-StellaOps-Api-Version`, `X-StellaOps-Build-Version`, plus grant and scope headers, and honour conditional requests via `ETag`/`If-None-Match`.
|
||||||
- **JWKS output:** `GET /jwks` lists every signing key with `status` metadata (`active`, `retired`). Old keys remain until operators remove them from configuration, allowing verification of historical bundles/tokens.
|
- **JWKS output:** `GET /jwks` lists every signing key with `status` metadata (`active`, `retired`). Old keys remain until operators remove them from configuration, allowing verification of historical bundles/tokens.
|
||||||
|
|
||||||
### Rotation SOP (no downtime)
|
### Rotation SOP (no downtime)
|
||||||
1. Generate a new P-256 private key (PEM) on an offline workstation and place it where the Authority host can read it (e.g., `../certificates/authority-signing-2025.pem`).
|
1. Generate a new P-256 private key (PEM) on an offline workstation and place it where the Authority host can read it (e.g., `../certificates/authority-signing-2025.pem`).
|
||||||
2. Call the authenticated admin API:
|
2. Call the authenticated admin API:
|
||||||
```bash
|
```bash
|
||||||
curl -sS -X POST https://authority.example.com/internal/signing/rotate \
|
curl -sS -X POST https://authority.example.com/internal/signing/rotate \
|
||||||
-H "x-stellaops-bootstrap-key: ${BOOTSTRAP_KEY}" \
|
-H "x-stellaops-bootstrap-key: ${BOOTSTRAP_KEY}" \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-d '{
|
-d '{
|
||||||
"keyId": "authority-signing-2025",
|
"keyId": "authority-signing-2025",
|
||||||
"location": "../certificates/authority-signing-2025.pem",
|
"location": "../certificates/authority-signing-2025.pem",
|
||||||
"source": "file"
|
"source": "file"
|
||||||
}'
|
}'
|
||||||
```
|
```
|
||||||
3. Verify the response reports the previous key as retired and fetch `/jwks` to confirm the new `kid` appears with `status: "active"`.
|
3. Verify the response reports the previous key as retired and fetch `/jwks` to confirm the new `kid` appears with `status: "active"`.
|
||||||
4. Persist the old key path in `signing.additionalKeys` (the rotation API updates in-memory options; rewrite the YAML to match so restarts remain consistent).
|
4. Persist the old key path in `signing.additionalKeys` (the rotation API updates in-memory options; rewrite the YAML to match so restarts remain consistent).
|
||||||
5. If you prefer automation, trigger the `.gitea/workflows/authority-key-rotation.yml` workflow with the new `keyId`/`keyPath`; it wraps `ops/authority/key-rotation.sh` and reads environment-specific secrets. The older key will be marked `retired` and appended to `signing.additionalKeys`.
|
5. If you prefer automation, trigger the `.gitea/workflows/authority-key-rotation.yml` workflow with the new `keyId`/`keyPath`; it wraps `ops/authority/key-rotation.sh` and reads environment-specific secrets. The older key will be marked `retired` and appended to `signing.additionalKeys`.
|
||||||
6. Re-run `stella auth revoke export` so revocation bundles are signed with the new key. Downstream caches should refresh JWKS within their configured lifetime (`StellaOpsAuthorityOptions.Signing` + client cache tolerance).
|
6. Re-run `stella auth revoke export` so revocation bundles are signed with the new key. Downstream caches should refresh JWKS within their configured lifetime (`StellaOpsAuthorityOptions.Signing` + client cache tolerance).
|
||||||
|
|
||||||
The rotation API leverages the same cryptography abstractions as revocation signing; no restart is required and the previous key is marked `retired` but kept available for verification.
|
The rotation API leverages the same cryptography abstractions as revocation signing; no restart is required and the previous key is marked `retired` but kept available for verification.
|
||||||
|
|
||||||
## 6. Bootstrap & Administrative Endpoints
|
## 6. Bootstrap & Administrative Endpoints
|
||||||
Administrative APIs live under `/internal/*` and require the bootstrap API key plus rate-limiter compliance.
|
Administrative APIs live under `/internal/*` and require the bootstrap API key plus rate-limiter compliance.
|
||||||
|
|
||||||
| Endpoint | Method | Description |
|
| Endpoint | Method | Description |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `/internal/users` | `POST` | Provision initial administrative accounts through the registered password-capable plug-in. Emits structured audit events. |
|
| `/internal/users` | `POST` | Provision initial administrative accounts through the registered password-capable plug-in. Emits structured audit events. |
|
||||||
| `/internal/clients` | `POST` | Provision OAuth clients (client credentials / device code). |
|
| `/internal/clients` | `POST` | Provision OAuth clients (client credentials / device code). |
|
||||||
| `/internal/revocations/export` | `GET` | Export revocation bundle + detached JWS + digest. |
|
| `/internal/revocations/export` | `GET` | Export revocation bundle + detached JWS + digest. |
|
||||||
| `/internal/signing/rotate` | `POST` | Promote a new signing key (see SOP above). Request body accepts `keyId`, `location`, optional `source`, `algorithm`, `provider`, and metadata. |
|
| `/internal/signing/rotate` | `POST` | Promote a new signing key (see SOP above). Request body accepts `keyId`, `location`, optional `source`, `algorithm`, `provider`, and metadata. |
|
||||||
|
|
||||||
All administrative calls emit `AuthEventRecord` entries enriched with correlation IDs, PII tags, and network metadata for offline SOC ingestion.
|
All administrative calls emit `AuthEventRecord` entries enriched with correlation IDs, PII tags, and network metadata for offline SOC ingestion.
|
||||||
|
|
||||||
> **Tenant hint:** include a `tenant` entry inside `properties` when bootstrapping clients. Authority normalises the value, stores it on the registration, and stamps future tokens/audit events with the tenant.
|
> **Tenant hint:** include a `tenant` entry inside `properties` when bootstrapping clients. Authority normalises the value, stores it on the registration, and stamps future tokens/audit events with the tenant.
|
||||||
|
|
||||||
### Bootstrap client example
|
### Bootstrap client example
|
||||||
|
|
||||||
```jsonc
|
```jsonc
|
||||||
POST /internal/clients
|
POST /internal/clients
|
||||||
{
|
{
|
||||||
"clientId": "concelier",
|
"clientId": "concelier",
|
||||||
"confidential": true,
|
"confidential": true,
|
||||||
"displayName": "Concelier Backend",
|
"displayName": "Concelier Backend",
|
||||||
"allowedGrantTypes": ["client_credentials"],
|
"allowedGrantTypes": ["client_credentials"],
|
||||||
"allowedScopes": ["concelier.jobs.trigger", "advisory:ingest", "advisory:read"],
|
"allowedScopes": ["concelier.jobs.trigger", "advisory:ingest", "advisory:read"],
|
||||||
"properties": {
|
"properties": {
|
||||||
"tenant": "tenant-default"
|
"tenant": "tenant-default"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
For environments with multiple tenants, repeat the call per tenant-specific client (e.g. `concelier-tenant-a`, `concelier-tenant-b`) or append suffixes to the client identifier.
|
For environments with multiple tenants, repeat the call per tenant-specific client (e.g. `concelier-tenant-a`, `concelier-tenant-b`) or append suffixes to the client identifier.
|
||||||
|
|
||||||
### Aggregation-only verification tokens
|
### Aggregation-only verification tokens
|
||||||
|
|
||||||
- Issue a dedicated client (e.g. `aoc-verifier`) with the scopes `aoc:verify`, `advisory:read`, and `vex:read` for each tenant that runs guard checks. Authority refuses to mint tokens for these scopes unless the client registration provides a tenant hint.
|
- Issue a dedicated client (e.g. `aoc-verifier`) with the scopes `aoc:verify`, `advisory:read`, and `vex:read` for each tenant that runs guard checks. Authority refuses to mint tokens for these scopes unless the client registration provides a tenant hint.
|
||||||
- The CLI (`stella aoc verify --tenant <tenant>`) and Console verification panel both call `/aoc/verify` on Concelier and Excititor. Tokens that omit the tenant claim or present a tenant that does not match the stored registration are rejected with `invalid_client`/`invalid_token`.
|
- The CLI (`stella aoc verify --tenant <tenant>`) and Console verification panel both call `/aoc/verify` on Concelier and Excititor. Tokens that omit the tenant claim or present a tenant that does not match the stored registration are rejected with `invalid_client`/`invalid_token`.
|
||||||
- Audit: `authority.client_credentials.grant` entries record `scope.invalid="aoc:verify"` when requests are rejected because the tenant hint is missing or mismatched.
|
- Audit: `authority.client_credentials.grant` entries record `scope.invalid="aoc:verify"` when requests are rejected because the tenant hint is missing or mismatched.
|
||||||
|
|
||||||
### Exception approvals & routing
|
### Exception approvals & routing
|
||||||
|
|
||||||
- New scopes `exceptions:read`, `exceptions:write`, and `exceptions:approve` govern access to the exception lifecycle. Map these via tenant roles (`exceptions-service`, `exceptions-approver`) as described in `/docs/security/authority-scopes.md`.
|
- New scopes `exceptions:read`, `exceptions:write`, and `exceptions:approve` govern access to the exception lifecycle. Map these via tenant roles (`exceptions-service`, `exceptions-approver`) as described in `/docs/security/authority-scopes.md`.
|
||||||
- Configure approval routing in `authority.yaml` with declarative templates. Each template exposes an `authorityRouteId` for downstream services (Policy Engine, Console) and an optional `requireMfa` flag:
|
- Configure approval routing in `authority.yaml` with declarative templates. Each template exposes an `authorityRouteId` for downstream services (Policy Engine, Console) and an optional `requireMfa` flag:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
exceptions:
|
exceptions:
|
||||||
routingTemplates:
|
routingTemplates:
|
||||||
- id: "secops"
|
- id: "secops"
|
||||||
authorityRouteId: "approvals/secops"
|
authorityRouteId: "approvals/secops"
|
||||||
requireMfa: true
|
requireMfa: true
|
||||||
description: "Security Operations approval chain"
|
description: "Security Operations approval chain"
|
||||||
- id: "governance"
|
- id: "governance"
|
||||||
authorityRouteId: "approvals/governance"
|
authorityRouteId: "approvals/governance"
|
||||||
requireMfa: false
|
requireMfa: false
|
||||||
description: "Non-production waiver review"
|
description: "Non-production waiver review"
|
||||||
```
|
```
|
||||||
|
|
||||||
- Clients requesting exception scopes must include a tenant assignment. Authority rejects client-credential flows that request `exceptions:*` with `invalid_client` and logs `scope.invalid="exceptions:write"` (or the requested scope) in `authority.client_credentials.grant` audit events when the tenant hint is missing.
|
- Clients requesting exception scopes must include a tenant assignment. Authority rejects client-credential flows that request `exceptions:*` with `invalid_client` and logs `scope.invalid="exceptions:write"` (or the requested scope) in `authority.client_credentials.grant` audit events when the tenant hint is missing.
|
||||||
- When any configured routing template sets `requireMfa: true`, user-facing tokens that contain `exceptions:approve` must be acquired through an MFA-capable identity provider. Password/OIDC flows that lack MFA support are rejected with `authority.password.grant` audit events where `reason="Exception approval scope requires an MFA-capable identity provider."`
|
- When any configured routing template sets `requireMfa: true`, user-facing tokens that contain `exceptions:approve` must be acquired through an MFA-capable identity provider. Password/OIDC flows that lack MFA support are rejected with `authority.password.grant` audit events where `reason="Exception approval scope requires an MFA-capable identity provider."`
|
||||||
- Update interactive clients (Console) to request `exceptions:read` by default and elevate to `exceptions:approve` only inside fresh-auth workflows for approvers. Documented examples live in `etc/authority.yaml.sample`.
|
- Update interactive clients (Console) to request `exceptions:read` by default and elevate to `exceptions:approve` only inside fresh-auth workflows for approvers. Documented examples live in `etc/authority.yaml.sample`.
|
||||||
- Verification responses map guard failures to `ERR_AOC_00x` codes and Authority emits `authority.client_credentials.grant` + `authority.token.validate_access` audit records containing the tenant and scopes so operators can trace who executed a run.
|
- Verification responses map guard failures to `ERR_AOC_00x` codes and Authority emits `authority.client_credentials.grant` + `authority.token.validate_access` audit records containing the tenant and scopes so operators can trace who executed a run.
|
||||||
- For air-gapped or offline replicas, pre-issue verification tokens per tenant and rotate them alongside ingest credentials; the guard endpoints never mutate data and remain safe to expose through the offline kit schedule.
|
- For air-gapped or offline replicas, pre-issue verification tokens per tenant and rotate them alongside ingest credentials; the guard endpoints never mutate data and remain safe to expose through the offline kit schedule.
|
||||||
|
|
||||||
## 7. Configuration Reference
|
## 7. Configuration Reference
|
||||||
|
|
||||||
| Section | Key | Description | Notes |
|
| Section | Key | Description | Notes |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| Root | `issuer` | Absolute HTTPS issuer advertised to clients. | Required. Loopback HTTP allowed only for development. |
|
| Root | `issuer` | Absolute HTTPS issuer advertised to clients. | Required. Loopback HTTP allowed only for development. |
|
||||||
| Tokens | `accessTokenLifetime`, `refreshTokenLifetime`, etc. | Lifetimes for each grant (access, refresh, device, authorization code, identity). | Enforced during issuance; persisted on each token document. |
|
| Tokens | `accessTokenLifetime`, `refreshTokenLifetime`, etc. | Lifetimes for each grant (access, refresh, device, authorization code, identity). | Enforced during issuance; persisted on each token document. |
|
||||||
| Storage | `storage.connectionString` | MongoDB connection string. | Required even for tests; offline kits ship snapshots for seeding. |
|
| Storage | `storage.connectionString` | MongoDB connection string. | Required even for tests; offline kits ship snapshots for seeding. |
|
||||||
| Signing | `signing.enabled` | Enable JWKS/revocation signing. | Disable only for development. |
|
| Signing | `signing.enabled` | Enable JWKS/revocation signing. | Disable only for development. |
|
||||||
| Signing | `signing.algorithm` | Signing algorithm identifier. | Currently ES256; additional curves can be wired through crypto providers. |
|
| Signing | `signing.algorithm` | Signing algorithm identifier. | Currently ES256; additional curves can be wired through crypto providers. |
|
||||||
| Signing | `signing.keySource` | Loader identifier (`file`, `vault`, custom). | Determines which `IAuthoritySigningKeySource` resolves keys. |
|
| Signing | `signing.keySource` | Loader identifier (`file`, `vault`, custom). | Determines which `IAuthoritySigningKeySource` resolves keys. |
|
||||||
| Signing | `signing.keyPath` | Relative/absolute path understood by the loader. | Stored as-is; rotation request should keep it in sync with filesystem layout. |
|
| Signing | `signing.keyPath` | Relative/absolute path understood by the loader. | Stored as-is; rotation request should keep it in sync with filesystem layout. |
|
||||||
| Signing | `signing.activeKeyId` | Active JWKS / revocation signing key id. | Exposed as `kid` in JWKS and bundles. |
|
| Signing | `signing.activeKeyId` | Active JWKS / revocation signing key id. | Exposed as `kid` in JWKS and bundles. |
|
||||||
| Signing | `signing.additionalKeys[].keyId` | Retired key identifier retained for verification. | Manager updates this automatically after rotation; keep YAML aligned. |
|
| Signing | `signing.additionalKeys[].keyId` | Retired key identifier retained for verification. | Manager updates this automatically after rotation; keep YAML aligned. |
|
||||||
| Signing | `signing.additionalKeys[].source` | Loader identifier per retired key. | Defaults to `signing.keySource` if omitted. |
|
| Signing | `signing.additionalKeys[].source` | Loader identifier per retired key. | Defaults to `signing.keySource` if omitted. |
|
||||||
| Security | `security.rateLimiting` | Fixed-window limits for `/token`, `/authorize`, `/internal/*`. | See `docs/security/rate-limits.md` for tuning. |
|
| Security | `security.rateLimiting` | Fixed-window limits for `/token`, `/authorize`, `/internal/*`. | See `docs/security/rate-limits.md` for tuning. |
|
||||||
| Bootstrap | `bootstrap.apiKey` | Shared secret required for `/internal/*`. | Only required when `bootstrap.enabled` is true. |
|
| Bootstrap | `bootstrap.apiKey` | Shared secret required for `/internal/*`. | Only required when `bootstrap.enabled` is true. |
|
||||||
|
|
||||||
### 7.1 Sender-constrained clients (DPoP & mTLS)
|
### 7.1 Sender-constrained clients (DPoP & mTLS)
|
||||||
|
|
||||||
Authority now understands two flavours of sender-constrained OAuth clients:
|
Authority now understands two flavours of sender-constrained OAuth clients:
|
||||||
|
|
||||||
- **DPoP proof-of-possession** – clients sign a `DPoP` header for `/token` requests. Authority validates the JWK thumbprint, HTTP method/URI, and replay window, then stamps the resulting access token with `cnf.jkt` so downstream services can verify the same key is reused.
|
- **DPoP proof-of-possession** – clients sign a `DPoP` header for `/token` requests. Authority validates the JWK thumbprint, HTTP method/URI, and replay window, then stamps the resulting access token with `cnf.jkt` so downstream services can verify the same key is reused.
|
||||||
- Configure under `security.senderConstraints.dpop`. `allowedAlgorithms`, `proofLifetime`, and `replayWindow` are enforced at validation time.
|
- Configure under `security.senderConstraints.dpop`. `allowedAlgorithms`, `proofLifetime`, and `replayWindow` are enforced at validation time.
|
||||||
- `security.senderConstraints.dpop.nonce.enabled` enables nonce challenges for high-value audiences (`requiredAudiences`, normalised to case-insensitive strings). When a nonce is required but missing or expired, `/token` replies with `WWW-Authenticate: DPoP error="use_dpop_nonce"` (and, when available, a fresh `DPoP-Nonce` header). Clients must retry with the issued nonce embedded in the proof.
|
- `security.senderConstraints.dpop.nonce.enabled` enables nonce challenges for high-value audiences (`requiredAudiences`, normalised to case-insensitive strings). When a nonce is required but missing or expired, `/token` replies with `WWW-Authenticate: DPoP error="use_dpop_nonce"` (and, when available, a fresh `DPoP-Nonce` header). Clients must retry with the issued nonce embedded in the proof.
|
||||||
- `security.senderConstraints.dpop.nonce.store` selects `memory` (default) or `redis`. When `redis` is configured, set `security.senderConstraints.dpop.nonce.redisConnectionString` so replicas share nonce issuance and high-value clients avoid replay gaps during failover.
|
- `security.senderConstraints.dpop.nonce.store` selects `memory` (default) or `redis`. When `redis` is configured, set `security.senderConstraints.dpop.nonce.redisConnectionString` so replicas share nonce issuance and high-value clients avoid replay gaps during failover.
|
||||||
- Example (enabling Redis-backed nonces; adjust audiences per deployment):
|
- Example (enabling Redis-backed nonces; adjust audiences per deployment):
|
||||||
```yaml
|
```yaml
|
||||||
security:
|
security:
|
||||||
senderConstraints:
|
senderConstraints:
|
||||||
dpop:
|
dpop:
|
||||||
enabled: true
|
enabled: true
|
||||||
proofLifetime: "00:02:00"
|
proofLifetime: "00:02:00"
|
||||||
replayWindow: "00:05:00"
|
replayWindow: "00:05:00"
|
||||||
allowedAlgorithms: [ "ES256", "ES384" ]
|
allowedAlgorithms: [ "ES256", "ES384" ]
|
||||||
nonce:
|
nonce:
|
||||||
enabled: true
|
enabled: true
|
||||||
ttl: "00:10:00"
|
ttl: "00:10:00"
|
||||||
maxIssuancePerMinute: 120
|
maxIssuancePerMinute: 120
|
||||||
store: "redis"
|
store: "redis"
|
||||||
redisConnectionString: "redis://authority-redis:6379?ssl=false"
|
redisConnectionString: "redis://authority-redis:6379?ssl=false"
|
||||||
requiredAudiences:
|
requiredAudiences:
|
||||||
- "signer"
|
- "signer"
|
||||||
- "attestor"
|
- "attestor"
|
||||||
```
|
```
|
||||||
Operators can override any field via environment variables (e.g. `STELLAOPS_AUTHORITY__SECURITY__SENDERCONSTRAINTS__DPOP__NONCE__STORE=redis`).
|
Operators can override any field via environment variables (e.g. `STELLAOPS_AUTHORITY__SECURITY__SENDERCONSTRAINTS__DPOP__NONCE__STORE=redis`).
|
||||||
- Declare client `audiences` in bootstrap manifests or plug-in provisioning metadata; Authority now defaults the token `aud` claim and `resource` indicator from this list, which is also used to trigger nonce enforcement for audiences such as `signer` and `attestor`.
|
- Declare client `audiences` in bootstrap manifests or plug-in provisioning metadata; Authority now defaults the token `aud` claim and `resource` indicator from this list, which is also used to trigger nonce enforcement for audiences such as `signer` and `attestor`.
|
||||||
- **Mutual TLS clients** – client registrations may declare an mTLS binding (`senderConstraint: mtls`). When enabled via `security.senderConstraints.mtls`, Authority validates the presented client certificate against stored bindings (`certificateBindings[]`), optional chain verification, and timing windows. Successful requests embed `cnf.x5t#S256` into the access token (and introspection output) so resource servers can enforce the certificate thumbprint.
|
- **Mutual TLS clients** – client registrations may declare an mTLS binding (`senderConstraint: mtls`). When enabled via `security.senderConstraints.mtls`, Authority validates the presented client certificate against stored bindings (`certificateBindings[]`), optional chain verification, and timing windows. Successful requests embed `cnf.x5t#S256` into the access token (and introspection output) so resource servers can enforce the certificate thumbprint.
|
||||||
- `security.senderConstraints.mtls.enforceForAudiences` forces mTLS whenever the requested `aud`/`resource` (or the client's configured audiences) intersect the configured allow-list (default includes `signer`). Clients configured for different sender constraints are rejected early so operator policy remains consistent.
|
- `security.senderConstraints.mtls.enforceForAudiences` forces mTLS whenever the requested `aud`/`resource` (or the client's configured audiences) intersect the configured allow-list (default includes `signer`). Clients configured for different sender constraints are rejected early so operator policy remains consistent.
|
||||||
- Certificate bindings now act as an allow-list: Authority verifies thumbprint, subject, issuer, serial number, and any declared SAN values against the presented certificate, with rotation grace windows applied to `notBefore/notAfter`. Operators can enforce subject regexes, SAN type allow-lists (`dns`, `uri`, `ip`), trusted certificate authorities, and rotation grace via `security.senderConstraints.mtls.*`.
|
- Certificate bindings now act as an allow-list: Authority verifies thumbprint, subject, issuer, serial number, and any declared SAN values against the presented certificate, with rotation grace windows applied to `notBefore/notAfter`. Operators can enforce subject regexes, SAN type allow-lists (`dns`, `uri`, `ip`), trusted certificate authorities, and rotation grace via `security.senderConstraints.mtls.*`.
|
||||||
|
|
||||||
Both modes persist additional metadata in `authority_tokens`: `senderConstraint` records the enforced policy, while `senderKeyThumbprint` stores the DPoP JWK thumbprint or mTLS certificate hash captured at issuance. Downstream services can rely on these fields (and the corresponding `cnf` claim) when auditing offline copies of the token store.
|
Both modes persist additional metadata in `authority_tokens`: `senderConstraint` records the enforced policy, while `senderKeyThumbprint` stores the DPoP JWK thumbprint or mTLS certificate hash captured at issuance. Downstream services can rely on these fields (and the corresponding `cnf` claim) when auditing offline copies of the token store.
|
||||||
|
|
||||||
### 7.2 Policy Engine clients & scopes
|
### 7.2 Policy Engine clients & scopes
|
||||||
|
|
||||||
Policy Engine v2 introduces dedicated scopes and a service identity that materialises effective findings. Configure Authority as follows when provisioning policy clients:
|
Policy Engine v2 introduces dedicated scopes and a service identity that materialises effective findings. Configure Authority as follows when provisioning policy clients:
|
||||||
|
|
||||||
| Client | Scopes | Notes |
|
| Client | Scopes | Notes |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `policy-engine` (service) | `policy:run`, `findings:read`, `effective:write` | Must include `properties.serviceIdentity: policy-engine` and a tenant. Authority rejects `effective:write` tokens without the marker or tenant. |
|
| `policy-engine` (service) | `policy:run`, `findings:read`, `effective:write` | Must include `properties.serviceIdentity: policy-engine` and a tenant. Authority rejects `effective:write` tokens without the marker or tenant. |
|
||||||
| `policy-cli` / automation | `policy:read`, `policy:author`, `policy:review`, `policy:simulate`, `findings:read` *(optionally add `policy:approve` / `policy:operate` / `policy:activate` for promotion pipelines)* | Keep scopes minimal; reroll CLI/CI tokens issued before 2025‑10‑27 so they drop legacy scope names and adopt the new set. |
|
| `policy-cli` / automation | `policy:read`, `policy:author`, `policy:review`, `policy:simulate`, `findings:read` *(optionally add `policy:approve` / `policy:operate` / `policy:activate` for promotion pipelines)* | Keep scopes minimal; reroll CLI/CI tokens issued before 2025‑10‑27 so they drop legacy scope names and adopt the new set. |
|
||||||
| UI/editor sessions | `policy:read`, `policy:author`, `policy:simulate` (+ reviewer/approver/operator scopes as appropriate) | Issue tenant-specific clients so audit and rate limits remain scoped. |
|
| UI/editor sessions | `policy:read`, `policy:author`, `policy:simulate` (+ reviewer/approver/operator scopes as appropriate) | Issue tenant-specific clients so audit and rate limits remain scoped. |
|
||||||
|
|
||||||
Sample YAML entry:
|
Sample YAML entry:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- clientId: "policy-engine"
|
- clientId: "policy-engine"
|
||||||
displayName: "Policy Engine Service"
|
displayName: "Policy Engine Service"
|
||||||
grantTypes: [ "client_credentials" ]
|
grantTypes: [ "client_credentials" ]
|
||||||
audiences: [ "api://policy-engine" ]
|
audiences: [ "api://policy-engine" ]
|
||||||
scopes: [ "policy:run", "findings:read", "effective:write" ]
|
scopes: [ "policy:run", "findings:read", "effective:write" ]
|
||||||
tenant: "tenant-default"
|
tenant: "tenant-default"
|
||||||
properties:
|
properties:
|
||||||
serviceIdentity: "policy-engine"
|
serviceIdentity: "policy-engine"
|
||||||
senderConstraint: "dpop"
|
senderConstraint: "dpop"
|
||||||
auth:
|
auth:
|
||||||
type: "client_secret"
|
type: "client_secret"
|
||||||
secretFile: "../secrets/policy-engine.secret"
|
secretFile: "../secrets/policy-engine.secret"
|
||||||
```
|
```
|
||||||
|
|
||||||
Compliance checklist:
|
Compliance checklist:
|
||||||
|
|
||||||
- [ ] `policy-engine` client includes `properties.serviceIdentity: policy-engine` and a tenant hint; logins missing either are rejected.
|
- [ ] `policy-engine` client includes `properties.serviceIdentity: policy-engine` and a tenant hint; logins missing either are rejected.
|
||||||
- [ ] Non-service clients omit `effective:write` and receive only the scopes required for their role (`policy:read`, `policy:author`, `policy:review`, `policy:approve`, `policy:operate`, `policy:simulate`, etc.).
|
- [ ] Non-service clients omit `effective:write` and receive only the scopes required for their role (`policy:read`, `policy:author`, `policy:review`, `policy:approve`, `policy:operate`, `policy:simulate`, etc.).
|
||||||
- [ ] Legacy tokens using `policy:write`/`policy:submit`/`policy:edit` are rotated to the new scope set before Production change freeze (see release migration note below).
|
- [ ] Legacy tokens using `policy:write`/`policy:submit`/`policy:edit` are rotated to the new scope set before Production change freeze (see release migration note below).
|
||||||
- [ ] Approval/activation workflows use identities distinct from authoring identities; tenants are provisioned per client to keep telemetry segregated.
|
- [ ] Approval/activation workflows use identities distinct from authoring identities; tenants are provisioned per client to keep telemetry segregated.
|
||||||
- [ ] Operators document reviewer assignments and incident procedures alongside `/docs/security/policy-governance.md` and archive policy evidence bundles (`stella policy bundle export`) with each release.
|
- [ ] Operators document reviewer assignments and incident procedures alongside `/docs/security/policy-governance.md` and archive policy evidence bundles (`stella policy bundle export`) with each release.
|
||||||
|
|
||||||
### 7.3 Orchestrator roles & scopes
|
### 7.3 Orchestrator roles & scopes
|
||||||
|
|
||||||
| Role / Client | Scopes | Notes |
|
| Role / Client | Scopes | Notes |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `Orch.Viewer` role | `orch:read` | Read-only access to Orchestrator dashboards, queues, and telemetry. |
|
| `Orch.Viewer` role | `orch:read` | Read-only access to Orchestrator dashboards, queues, and telemetry. |
|
||||||
| `Orch.Operator` role | `orch:read`, `orch:operate` | Issue short-lived tokens for control actions (pause/resume, retry, sync). Token requests **must** include `operator_reason` (≤256 chars) and `operator_ticket` (≤128 chars); Authority rejects requests missing either value and records both in audit events. |
|
| `Orch.Operator` role | `orch:read`, `orch:operate` | Issue short-lived tokens for control actions (pause/resume, retry, sync). Token requests **must** include `operator_reason` (≤256 chars) and `operator_ticket` (≤128 chars); Authority rejects requests missing either value and records both in audit events. |
|
||||||
|
|
||||||
Token request example via client credentials:
|
Token request example via client credentials:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -u orch-operator:s3cr3t! \
|
curl -u orch-operator:s3cr3t! \
|
||||||
-d 'grant_type=client_credentials' \
|
-d 'grant_type=client_credentials' \
|
||||||
-d 'scope=orch:operate' \
|
-d 'scope=orch:operate' \
|
||||||
-d 'operator_reason=resume source after maintenance' \
|
-d 'operator_reason=resume source after maintenance' \
|
||||||
-d 'operator_ticket=INC-2045' \
|
-d 'operator_ticket=INC-2045' \
|
||||||
https://authority.example.com/token
|
https://authority.example.com/token
|
||||||
```
|
```
|
||||||
|
|
||||||
Tokens lacking `operator_reason` or `operator_ticket` receive `invalid_request`; audit events (`authority.client_credentials.grant`) surface the supplied values under `request.reason` and `request.ticket` for downstream review.
|
Tokens lacking `operator_reason` or `operator_ticket` receive `invalid_request`; audit events (`authority.client_credentials.grant`) surface the supplied values under `request.reason` and `request.ticket` for downstream review.
|
||||||
CLI clients set these parameters via `Authority.OperatorReason` / `Authority.OperatorTicket` (environment variables `STELLAOPS_ORCH_REASON` and `STELLAOPS_ORCH_TICKET`).
|
CLI clients set these parameters via `Authority.OperatorReason` / `Authority.OperatorTicket` (environment variables `STELLAOPS_ORCH_REASON` and `STELLAOPS_ORCH_TICKET`).
|
||||||
|
|
||||||
## 8. Offline & Sovereign Operation
|
## 8. Offline & Sovereign Operation
|
||||||
- **No outbound dependencies:** Authority only contacts MongoDB and local plugins. Discovery and JWKS are cached by clients with offline tolerances (`AllowOfflineCacheFallback`, `OfflineCacheTolerance`). Operators should mirror these responses for air-gapped use.
|
- **No outbound dependencies:** Authority only contacts MongoDB and local plugins. Discovery and JWKS are cached by clients with offline tolerances (`AllowOfflineCacheFallback`, `OfflineCacheTolerance`). Operators should mirror these responses for air-gapped use.
|
||||||
- **Structured logging:** Every revocation export, signing rotation, bootstrap action, and token issuance emits structured logs with `traceId`, `client_id`, `subjectId`, and `network.remoteIp` where applicable. Mirror logs to your SIEM to retain audit trails without central connectivity.
|
- **Structured logging:** Every revocation export, signing rotation, bootstrap action, and token issuance emits structured logs with `traceId`, `client_id`, `subjectId`, and `network.remoteIp` where applicable. Mirror logs to your SIEM to retain audit trails without central connectivity.
|
||||||
- **Determinism:** Sorting rules in token and revocation exports guarantee byte-for-byte identical artefacts given the same datastore state. Hashes and signatures remain stable across machines.
|
- **Determinism:** Sorting rules in token and revocation exports guarantee byte-for-byte identical artefacts given the same datastore state. Hashes and signatures remain stable across machines.
|
||||||
|
|
||||||
## 9. Operational Checklist
|
## 9. Operational Checklist
|
||||||
- [ ] Protect the bootstrap API key and disable bootstrap endpoints (`bootstrap.enabled: false`) once initial setup is complete.
|
- [ ] Protect the bootstrap API key and disable bootstrap endpoints (`bootstrap.enabled: false`) once initial setup is complete.
|
||||||
- [ ] Schedule `stella auth revoke export` (or `/internal/revocations/export`) at the same cadence as Concelier exports so bundles remain in lockstep.
|
- [ ] Schedule `stella auth revoke export` (or `/internal/revocations/export`) at the same cadence as Concelier exports so bundles remain in lockstep.
|
||||||
- [ ] Rotate signing keys before expiration; keep at least one retired key until all cached bundles/tokens signed with it have expired.
|
- [ ] Rotate signing keys before expiration; keep at least one retired key until all cached bundles/tokens signed with it have expired.
|
||||||
- [ ] Monitor `/health` and `/ready` plus rate-limiter metrics to detect plugin outages early.
|
- [ ] Monitor `/health` and `/ready` plus rate-limiter metrics to detect plugin outages early.
|
||||||
- [ ] Ensure downstream services cache JWKS and revocation bundles within tolerances; stale caches risk accepting revoked tokens.
|
- [ ] Ensure downstream services cache JWKS and revocation bundles within tolerances; stale caches risk accepting revoked tokens.
|
||||||
|
|
||||||
For plug-in specific requirements, refer to **[Authority Plug-in Developer Guide](dev/31_AUTHORITY_PLUGIN_DEVELOPER_GUIDE.md)**. For revocation bundle validation workflow, see **[Authority Revocation Bundle](security/revocation-bundle.md)**.
|
For plug-in specific requirements, refer to **[Authority Plug-in Developer Guide](dev/31_AUTHORITY_PLUGIN_DEVELOPER_GUIDE.md)**. For revocation bundle validation workflow, see **[Authority Revocation Bundle](security/revocation-bundle.md)**.
|
||||||
|
|||||||
@@ -1,91 +1,91 @@
|
|||||||
# Data Schemas & Persistence Contracts
|
# Data Schemas & Persistence Contracts
|
||||||
|
|
||||||
*Audience* – backend developers, plug‑in authors, DB admins.
|
*Audience* – backend developers, plug‑in authors, DB admins.
|
||||||
*Scope* – describes **Redis**, **MongoDB** (optional), and on‑disk blob shapes that power Stella Ops.
|
*Scope* – describes **Redis**, **MongoDB** (optional), and on‑disk blob shapes that power Stella Ops.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 0 Document Conventions
|
## 0 Document Conventions
|
||||||
|
|
||||||
* **CamelCase** for JSON.
|
* **CamelCase** for JSON.
|
||||||
* All timestamps are **RFC 3339 / ISO 8601** with `Z` (UTC).
|
* All timestamps are **RFC 3339 / ISO 8601** with `Z` (UTC).
|
||||||
* `⭑` = planned but *not* shipped yet (kept on Feature Matrix “To Do”).
|
* `⭑` = planned but *not* shipped yet (kept on Feature Matrix “To Do”).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 1 SBOM Wrapper Envelope
|
## 1 SBOM Wrapper Envelope
|
||||||
|
|
||||||
Every SBOM blob (regardless of format) is stored on disk or in object storage with a *sidecar* JSON file that indexes it for the scanners.
|
Every SBOM blob (regardless of format) is stored on disk or in object storage with a *sidecar* JSON file that indexes it for the scanners.
|
||||||
|
|
||||||
#### 1.1 JSON Shape
|
#### 1.1 JSON Shape
|
||||||
|
|
||||||
```jsonc
|
```jsonc
|
||||||
{
|
{
|
||||||
"id": "sha256:417f…", // digest of the SBOM *file* itself
|
"id": "sha256:417f…", // digest of the SBOM *file* itself
|
||||||
"imageDigest": "sha256:e2b9…", // digest of the original container image
|
"imageDigest": "sha256:e2b9…", // digest of the original container image
|
||||||
"created": "2025-07-14T07:02:13Z",
|
"created": "2025-07-14T07:02:13Z",
|
||||||
"format": "trivy-json-v2", // NEW enum: trivy-json-v2 | spdx-json | cyclonedx-json
|
"format": "trivy-json-v2", // NEW enum: trivy-json-v2 | spdx-json | cyclonedx-json
|
||||||
"layers": [
|
"layers": [
|
||||||
"sha256:d38b…", // layer digests (ordered)
|
"sha256:d38b…", // layer digests (ordered)
|
||||||
"sha256:af45…"
|
"sha256:af45…"
|
||||||
],
|
],
|
||||||
"partial": false, // true => delta SBOM (only some layers)
|
"partial": false, // true => delta SBOM (only some layers)
|
||||||
"provenanceId": "prov_0291" // ⭑ link to SLSA attestation (Q1‑2026)
|
"provenanceId": "prov_0291" // ⭑ link to SLSA attestation (Q1‑2026)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
*`format`* **NEW** – added to support **multiple SBOM formats**.
|
*`format`* **NEW** – added to support **multiple SBOM formats**.
|
||||||
*`partial`* **NEW** – true when generated via the **delta SBOM** flow (§1.3).
|
*`partial`* **NEW** – true when generated via the **delta SBOM** flow (§1.3).
|
||||||
|
|
||||||
#### 1.2 File‑system Layout
|
#### 1.2 File‑system Layout
|
||||||
|
|
||||||
```
|
```
|
||||||
blobs/
|
blobs/
|
||||||
├─ 417f… # digest prefix
|
├─ 417f… # digest prefix
|
||||||
│ ├─ sbom.json # payload (any format)
|
│ ├─ sbom.json # payload (any format)
|
||||||
│ └─ sbom.meta.json # wrapper (shape above)
|
│ └─ sbom.meta.json # wrapper (shape above)
|
||||||
```
|
```
|
||||||
|
|
||||||
> **Note** – blob storage can point at S3, MinIO, or plain disk; driver plug‑ins adapt.
|
> **Note** – blob storage can point at S3, MinIO, or plain disk; driver plug‑ins adapt.
|
||||||
|
|
||||||
#### 1.3 Delta SBOM Extension
|
#### 1.3 Delta SBOM Extension
|
||||||
|
|
||||||
When `partial: true`, *only* the missing layers have been scanned.
|
When `partial: true`, *only* the missing layers have been scanned.
|
||||||
Merging logic inside `scanning` module stitches new data onto the cached full SBOM in Redis.
|
Merging logic inside `scanning` module stitches new data onto the cached full SBOM in Redis.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 2 Redis Keyspace
|
## 2 Redis Keyspace
|
||||||
|
|
||||||
| Key pattern | Type | TTL | Purpose |
|
| Key pattern | Type | TTL | Purpose |
|
||||||
|-------------------------------------|---------|------|--------------------------------------------------|
|
|-------------------------------------|---------|------|--------------------------------------------------|
|
||||||
| `scan:<digest>` | string | ∞ | Last scan JSON result (as returned by `/scan`) |
|
| `scan:<digest>` | string | ∞ | Last scan JSON result (as returned by `/scan`) |
|
||||||
| `layers:<digest>` | set | 90d | Layers already possessing SBOMs (delta cache) |
|
| `layers:<digest>` | set | 90d | Layers already possessing SBOMs (delta cache) |
|
||||||
| `policy:active` | string | ∞ | YAML **or** Rego ruleset |
|
| `policy:active` | string | ∞ | YAML **or** Rego ruleset |
|
||||||
| `quota:<token>` | string | *until next UTC midnight* | Per‑token scan counter for Free tier ({{ quota_token }} scans). |
|
| `quota:<token>` | string | *until next UTC midnight* | Per‑token scan counter for Free tier ({{ quota_token }} scans). |
|
||||||
| `policy:history` | list | ∞ | Change audit IDs (see Mongo) |
|
| `policy:history` | list | ∞ | Change audit IDs (see Mongo) |
|
||||||
| `feed:nvd:json` | string | 24h | Normalised feed snapshot |
|
| `feed:nvd:json` | string | 24h | Normalised feed snapshot |
|
||||||
| `locator:<imageDigest>` | string | 30d | Maps image digest → sbomBlobId |
|
| `locator:<imageDigest>` | string | 30d | Maps image digest → sbomBlobId |
|
||||||
| `metrics:…` | various | — | Prom / OTLP runtime metrics |
|
| `metrics:…` | various | — | Prom / OTLP runtime metrics |
|
||||||
|
|
||||||
> **Delta SBOM** uses `layers:*` to skip work in <20 ms.
|
> **Delta SBOM** uses `layers:*` to skip work in <20 ms.
|
||||||
> **Quota enforcement** increments `quota:<token>` atomically; when {{ quota_token }} the API returns **429**.
|
> **Quota enforcement** increments `quota:<token>` atomically; when {{ quota_token }} the API returns **429**.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 3 MongoDB Collections (Optional)
|
## 3 MongoDB Collections (Optional)
|
||||||
|
|
||||||
Only enabled when `MONGO_URI` is supplied (for long‑term audit).
|
Only enabled when `MONGO_URI` is supplied (for long‑term audit).
|
||||||
|
|
||||||
| Collection | Shape (summary) | Indexes |
|
| Collection | Shape (summary) | Indexes |
|
||||||
|--------------------|------------------------------------------------------------|-------------------------------------|
|
|--------------------|------------------------------------------------------------|-------------------------------------|
|
||||||
| `sbom_history` | Wrapper JSON + `replaceTs` on overwrite | `{imageDigest}` `{created}` |
|
| `sbom_history` | Wrapper JSON + `replaceTs` on overwrite | `{imageDigest}` `{created}` |
|
||||||
| `policy_versions` | `{_id, yaml, rego, authorId, created}` | `{created}` |
|
| `policy_versions` | `{_id, yaml, rego, authorId, created}` | `{created}` |
|
||||||
| `attestations` ⭑ | SLSA provenance doc + Rekor log pointer | `{imageDigest}` |
|
| `attestations` ⭑ | SLSA provenance doc + Rekor log pointer | `{imageDigest}` |
|
||||||
| `audit_log` | Fully rendered RFC 5424 entries (UI & CLI actions) | `{userId}` `{ts}` |
|
| `audit_log` | Fully rendered RFC 5424 entries (UI & CLI actions) | `{userId}` `{ts}` |
|
||||||
|
|
||||||
Schema detail for **policy_versions**:
|
Schema detail for **policy_versions**:
|
||||||
|
|
||||||
Samples live under `samples/api/scheduler/` (e.g., `schedule.json`, `run.json`, `impact-set.json`, `audit.json`) and mirror the canonical serializer output shown below.
|
Samples live under `samples/api/scheduler/` (e.g., `schedule.json`, `run.json`, `impact-set.json`, `audit.json`) and mirror the canonical serializer output shown below.
|
||||||
|
|
||||||
```jsonc
|
```jsonc
|
||||||
@@ -327,34 +327,34 @@ Materialized view powering the Scheduler UI dashboards. Stores the latest roll-u
|
|||||||
- Schedulers should call the projection service after every run state change so the cache mirrors planner/runner progress.
|
- Schedulers should call the projection service after every run state change so the cache mirrors planner/runner progress.
|
||||||
|
|
||||||
Sample file: `samples/api/scheduler/run-summary.json`.
|
Sample file: `samples/api/scheduler/run-summary.json`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 4 Policy Schema (YAML v1.0)
|
## 4 Policy Schema (YAML v1.0)
|
||||||
|
|
||||||
Minimal viable grammar (subset of OSV‑SCHEMA ideas).
|
Minimal viable grammar (subset of OSV‑SCHEMA ideas).
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
version: "1.0"
|
version: "1.0"
|
||||||
rules:
|
rules:
|
||||||
- name: Block Critical
|
- name: Block Critical
|
||||||
severity: [Critical]
|
severity: [Critical]
|
||||||
action: block
|
action: block
|
||||||
- name: Ignore Low Dev
|
- name: Ignore Low Dev
|
||||||
severity: [Low, None]
|
severity: [Low, None]
|
||||||
environments: [dev, staging]
|
environments: [dev, staging]
|
||||||
action: ignore
|
action: ignore
|
||||||
expires: "2026-01-01"
|
expires: "2026-01-01"
|
||||||
- name: Escalate RegionalFeed High
|
- name: Escalate RegionalFeed High
|
||||||
sources: [NVD, CNNVD, CNVD, ENISA, JVN, BDU]
|
sources: [NVD, CNNVD, CNVD, ENISA, JVN, BDU]
|
||||||
severity: [High, Critical]
|
severity: [High, Critical]
|
||||||
action: escalate
|
action: escalate
|
||||||
```
|
```
|
||||||
|
|
||||||
Validation is performed by `policy:mapping.yaml` JSON‑Schema embedded in backend.
|
Validation is performed by `policy:mapping.yaml` JSON‑Schema embedded in backend.
|
||||||
|
|
||||||
Canonical schema source: `src/StellaOps.Policy/Schemas/policy-schema@1.json` (embedded into `StellaOps.Policy`).
|
Canonical schema source: `src/Policy/__Libraries/StellaOps.Policy/Schemas/policy-schema@1.json` (embedded into `StellaOps.Policy`).
|
||||||
`PolicyValidationCli` (see `src/StellaOps.Policy/PolicyValidationCli.cs`) provides the reusable command handler that the main CLI wires up; in the interim it can be invoked from a short host like:
|
`PolicyValidationCli` (see `src/Policy/__Libraries/StellaOps.Policy/PolicyValidationCli.cs`) provides the reusable command handler that the main CLI wires up; in the interim it can be invoked from a short host like:
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
await new PolicyValidationCli().RunAsync(new PolicyValidationCliOptions
|
await new PolicyValidationCli().RunAsync(new PolicyValidationCliOptions
|
||||||
@@ -363,7 +363,7 @@ await new PolicyValidationCli().RunAsync(new PolicyValidationCliOptions
|
|||||||
Strict = true,
|
Strict = true,
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
### 4.1 Rego Variant (Advanced – TODO)
|
### 4.1 Rego Variant (Advanced – TODO)
|
||||||
|
|
||||||
*Accepted but stored as‑is in `rego` field.*
|
*Accepted but stored as‑is in `rego` field.*
|
||||||
@@ -372,7 +372,7 @@ Evaluated via internal **OPA** side‑car once feature graduates from TODO list.
|
|||||||
### 4.2 Policy Scoring Config (JSON)
|
### 4.2 Policy Scoring Config (JSON)
|
||||||
|
|
||||||
*Schema id.* `https://schemas.stella-ops.org/policy/policy-scoring-schema@1.json`
|
*Schema id.* `https://schemas.stella-ops.org/policy/policy-scoring-schema@1.json`
|
||||||
*Source.* `src/StellaOps.Policy/Schemas/policy-scoring-schema@1.json` (embedded in `StellaOps.Policy`), default fixture at `src/StellaOps.Policy/Schemas/policy-scoring-default.json`.
|
*Source.* `src/Policy/__Libraries/StellaOps.Policy/Schemas/policy-scoring-schema@1.json` (embedded in `StellaOps.Policy`), default fixture at `src/Policy/__Libraries/StellaOps.Policy/Schemas/policy-scoring-default.json`.
|
||||||
|
|
||||||
```jsonc
|
```jsonc
|
||||||
{
|
{
|
||||||
@@ -426,25 +426,25 @@ npx ajv validate --spec=draft2020 -c ajv-formats \
|
|||||||
Planned for Q1‑2026 (kept here for early plug‑in authors).
|
Planned for Q1‑2026 (kept here for early plug‑in authors).
|
||||||
|
|
||||||
```jsonc
|
```jsonc
|
||||||
{
|
{
|
||||||
"id": "prov_0291",
|
"id": "prov_0291",
|
||||||
"imageDigest": "sha256:e2b9…",
|
"imageDigest": "sha256:e2b9…",
|
||||||
"buildType": "https://slsa.dev/container/v1",
|
"buildType": "https://slsa.dev/container/v1",
|
||||||
"builder": {
|
"builder": {
|
||||||
"id": "https://git.stella-ops.ru/ci/stella-runner@sha256:f7b7…"
|
"id": "https://git.stella-ops.ru/ci/stella-runner@sha256:f7b7…"
|
||||||
},
|
},
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"invocation": {
|
"invocation": {
|
||||||
"parameters": {"GIT_SHA": "f6a1…"},
|
"parameters": {"GIT_SHA": "f6a1…"},
|
||||||
"buildStart": "2025-07-14T06:59:17Z",
|
"buildStart": "2025-07-14T06:59:17Z",
|
||||||
"buildEnd": "2025-07-14T07:01:22Z"
|
"buildEnd": "2025-07-14T07:01:22Z"
|
||||||
},
|
},
|
||||||
"completeness": {"parameters": true}
|
"completeness": {"parameters": true}
|
||||||
},
|
},
|
||||||
"materials": [
|
"materials": [
|
||||||
{"uri": "git+https://git…", "digest": {"sha1": "f6a1…"}}
|
{"uri": "git+https://git…", "digest": {"sha1": "f6a1…"}}
|
||||||
],
|
],
|
||||||
"rekorLogIndex": 99817 // entry in local Rekor mirror
|
"rekorLogIndex": 99817 // entry in local Rekor mirror
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -509,42 +509,42 @@ done
|
|||||||
```
|
```
|
||||||
|
|
||||||
Integration tests can embed the sample fixtures to guarantee deterministic serialisation from the `StellaOps.Notify.Models` DTOs introduced in Sprint 15.
|
Integration tests can embed the sample fixtures to guarantee deterministic serialisation from the `StellaOps.Notify.Models` DTOs introduced in Sprint 15.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 6 Validator Contracts
|
## 6 Validator Contracts
|
||||||
|
|
||||||
* For SBOM wrapper – `ISbomValidator` (DLL plug‑in) must return *typed* error list.
|
* For SBOM wrapper – `ISbomValidator` (DLL plug‑in) must return *typed* error list.
|
||||||
* For YAML policies – JSON‑Schema at `/schemas/policy‑v1.json`.
|
* For YAML policies – JSON‑Schema at `/schemas/policy‑v1.json`.
|
||||||
* For Rego – OPA `opa eval --fail-defined` under the hood.
|
* For Rego – OPA `opa eval --fail-defined` under the hood.
|
||||||
* For **Free‑tier quotas** – `IQuotaService` integration tests ensure `quota:<token>` resets at UTC midnight and produces correct `Retry‑After` headers.
|
* For **Free‑tier quotas** – `IQuotaService` integration tests ensure `quota:<token>` resets at UTC midnight and produces correct `Retry‑After` headers.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 7 Migration Notes
|
## 7 Migration Notes
|
||||||
|
|
||||||
1. **Add `format` column** to existing SBOM wrappers; default to `trivy-json-v2`.
|
1. **Add `format` column** to existing SBOM wrappers; default to `trivy-json-v2`.
|
||||||
2. **Populate `layers` & `partial`** via backfill script (ship with `stellopsctl migrate` wizard).
|
2. **Populate `layers` & `partial`** via backfill script (ship with `stellopsctl migrate` wizard).
|
||||||
3. Policy YAML previously stored in Redis → copy to Mongo if persistence enabled.
|
3. Policy YAML previously stored in Redis → copy to Mongo if persistence enabled.
|
||||||
4. Prepare `attestations` collection (empty) – safe to create in advance.
|
4. Prepare `attestations` collection (empty) – safe to create in advance.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 8 Open Questions / Future Work
|
## 8 Open Questions / Future Work
|
||||||
|
|
||||||
* How to de‑duplicate *identical* Rego policies differing only in whitespace?
|
* How to de‑duplicate *identical* Rego policies differing only in whitespace?
|
||||||
* Embed *GOST 34.11‑2018* digests when users enable Russian crypto suite?
|
* Embed *GOST 34.11‑2018* digests when users enable Russian crypto suite?
|
||||||
* Should enterprise tiers share the same Redis quota keys or switch to JWT claim `tier != Free` bypass?
|
* Should enterprise tiers share the same Redis quota keys or switch to JWT claim `tier != Free` bypass?
|
||||||
* Evaluate sliding‑window quota instead of strict daily reset.
|
* Evaluate sliding‑window quota instead of strict daily reset.
|
||||||
* Consider rate‑limit for `/layers/missing` to avoid brute‑force enumeration.
|
* Consider rate‑limit for `/layers/missing` to avoid brute‑force enumeration.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 9 Change Log
|
## 9 Change Log
|
||||||
|
|
||||||
| Date | Note |
|
| Date | Note |
|
||||||
|------------|--------------------------------------------------------------------------------|
|
|------------|--------------------------------------------------------------------------------|
|
||||||
| 2025‑07‑14 | **Added:** `format`, `partial`, delta cache keys, YAML policy schema v1.0. |
|
| 2025‑07‑14 | **Added:** `format`, `partial`, delta cache keys, YAML policy schema v1.0. |
|
||||||
| 2025‑07‑12 | **Initial public draft** – SBOM wrapper, Redis keyspace, audit collections. |
|
| 2025‑07‑12 | **Initial public draft** – SBOM wrapper, Redis keyspace, audit collections. |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -56,7 +56,7 @@
|
|||||||
## 3 Test Harness
|
## 3 Test Harness
|
||||||
|
|
||||||
* **Runner** – `perf/run.sh`, accepts `--phase` and `--samples`.
|
* **Runner** – `perf/run.sh`, accepts `--phase` and `--samples`.
|
||||||
* **Language analyzers microbench** – `dotnet run --project src/StellaOps.Bench/Scanner.Analyzers/StellaOps.Bench.ScannerAnalyzers/StellaOps.Bench.ScannerAnalyzers.csproj -- --repo-root . --out src/StellaOps.Bench/Scanner.Analyzers/baseline.csv --json out/bench/scanner-analyzers/latest.json --prom out/bench/scanner-analyzers/latest.prom --commit $(git rev-parse HEAD)` produces CSV + JSON + Prometheus gauges for analyzer scenarios. Runs fail if `max_ms` regresses ≥ 20 % against `baseline.csv` or if thresholds are exceeded.
|
* **Language analyzers microbench** – `dotnet run --project src/Bench/StellaOps.Bench/Scanner.Analyzers/StellaOps.Bench.ScannerAnalyzers/StellaOps.Bench.ScannerAnalyzers.csproj -- --repo-root . --out src/Bench/StellaOps.Bench/Scanner.Analyzers/baseline.csv --json out/bench/scanner-analyzers/latest.json --prom out/bench/scanner-analyzers/latest.prom --commit $(git rev-parse HEAD)` produces CSV + JSON + Prometheus gauges for analyzer scenarios. Runs fail if `max_ms` regresses ≥ 20 % against `baseline.csv` or if thresholds are exceeded.
|
||||||
* **Metrics** – Prometheus + `jq` extracts; aggregated via `scripts/aggregate.ts`.
|
* **Metrics** – Prometheus + `jq` extracts; aggregated via `scripts/aggregate.ts`.
|
||||||
* **CI** – GitLab CI job *benchmark* publishes JSON to `bench‑artifacts/`.
|
* **CI** – GitLab CI job *benchmark* publishes JSON to `bench‑artifacts/`.
|
||||||
* **Visualisation** – Grafana dashboard *Stella‑Perf* (provisioned JSON).
|
* **Visualisation** – Grafana dashboard *Stella‑Perf* (provisioned JSON).
|
||||||
|
|||||||
@@ -1,47 +1,47 @@
|
|||||||
# Automated Test‑Suite Overview
|
# Automated Test‑Suite Overview
|
||||||
|
|
||||||
This document enumerates **every automated check** executed by the Stella Ops
|
This document enumerates **every automated check** executed by the Stella Ops
|
||||||
CI pipeline, from unit level to chaos experiments. It is intended for
|
CI pipeline, from unit level to chaos experiments. It is intended for
|
||||||
contributors who need to extend coverage or diagnose failures.
|
contributors who need to extend coverage or diagnose failures.
|
||||||
|
|
||||||
> **Build parameters** – values such as `{{ dotnet }}` (runtime) and
|
> **Build parameters** – values such as `{{ dotnet }}` (runtime) and
|
||||||
> `{{ angular }}` (UI framework) are injected at build time.
|
> `{{ angular }}` (UI framework) are injected at build time.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Layer map
|
## Layer map
|
||||||
|
|
||||||
| Layer | Tooling | Entry‑point | Frequency |
|
| Layer | Tooling | Entry‑point | Frequency |
|
||||||
|-------|---------|-------------|-----------|
|
|-------|---------|-------------|-----------|
|
||||||
| **1. Unit** | `xUnit` (<code>dotnet test</code>) | `*.Tests.csproj` | per PR / push |
|
| **1. Unit** | `xUnit` (<code>dotnet test</code>) | `*.Tests.csproj` | per PR / push |
|
||||||
| **2. Property‑based** | `FsCheck` | `SbomPropertyTests` | per PR |
|
| **2. Property‑based** | `FsCheck` | `SbomPropertyTests` | per PR |
|
||||||
| **3. Integration (API)** | `Testcontainers` suite | `test/Api.Integration` | per PR + nightly |
|
| **3. Integration (API)** | `Testcontainers` suite | `test/Api.Integration` | per PR + nightly |
|
||||||
| **4. Integration (DB-merge)** | in-memory Mongo + Redis | `Concelier.Integration` (vulnerability ingest/merge/export service) | per PR |
|
| **4. Integration (DB-merge)** | in-memory Mongo + Redis | `Concelier.Integration` (vulnerability ingest/merge/export service) | per PR |
|
||||||
| **5. Contract (gRPC)** | `Buf breaking` | `buf.yaml` files | per PR |
|
| **5. Contract (gRPC)** | `Buf breaking` | `buf.yaml` files | per PR |
|
||||||
| **6. Front‑end unit** | `Jest` | `ui/src/**/*.spec.ts` | per PR |
|
| **6. Front‑end unit** | `Jest` | `ui/src/**/*.spec.ts` | per PR |
|
||||||
| **7. Front‑end E2E** | `Playwright` | `ui/e2e/**` | nightly |
|
| **7. Front‑end E2E** | `Playwright` | `ui/e2e/**` | nightly |
|
||||||
| **8. Lighthouse perf / a11y** | `lighthouse-ci` (Chrome headless) | `ui/dist/index.html` | nightly |
|
| **8. Lighthouse perf / a11y** | `lighthouse-ci` (Chrome headless) | `ui/dist/index.html` | nightly |
|
||||||
| **9. Load** | `k6` scripted scenarios | `k6/*.js` | nightly |
|
| **9. Load** | `k6` scripted scenarios | `k6/*.js` | nightly |
|
||||||
| **10. Chaos CPU / OOM** | `pumba` | Docker Compose overlay | weekly |
|
| **10. Chaos CPU / OOM** | `pumba` | Docker Compose overlay | weekly |
|
||||||
| **11. Dependency scanning** | `Trivy fs` + `dotnet list package --vuln` | root | per PR |
|
| **11. Dependency scanning** | `Trivy fs` + `dotnet list package --vuln` | root | per PR |
|
||||||
| **12. License compliance** | `LicenceFinder` | root | per PR |
|
| **12. License compliance** | `LicenceFinder` | root | per PR |
|
||||||
| **13. SBOM reproducibility** | `in‑toto attestation` diff | GitLab job | release tags |
|
| **13. SBOM reproducibility** | `in‑toto attestation` diff | GitLab job | release tags |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Quality gates
|
## Quality gates
|
||||||
|
|
||||||
| Metric | Budget | Gate |
|
| Metric | Budget | Gate |
|
||||||
|--------|--------|------|
|
|--------|--------|------|
|
||||||
| API unit coverage | ≥ 85 % lines | PR merge |
|
| API unit coverage | ≥ 85 % lines | PR merge |
|
||||||
| API response P95 | ≤ 120 ms | nightly alert |
|
| API response P95 | ≤ 120 ms | nightly alert |
|
||||||
| Δ‑SBOM warm scan P95 (4 vCPU) | ≤ 5 s | nightly alert |
|
| Δ‑SBOM warm scan P95 (4 vCPU) | ≤ 5 s | nightly alert |
|
||||||
| Lighthouse performance score | ≥ 90 | nightly alert |
|
| Lighthouse performance score | ≥ 90 | nightly alert |
|
||||||
| Lighthouse accessibility score | ≥ 95 | nightly alert |
|
| Lighthouse accessibility score | ≥ 95 | nightly alert |
|
||||||
| k6 sustained RPS drop | < 5 % vs baseline | nightly alert |
|
| k6 sustained RPS drop | < 5 % vs baseline | nightly alert |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Local runner
|
## Local runner
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -63,13 +63,13 @@ The script spins up MongoDB/Redis via Testcontainers and requires:
|
|||||||
|
|
||||||
The Concelier connector suite includes a regression test (`OsvGhsaParityRegressionTests`)
|
The Concelier connector suite includes a regression test (`OsvGhsaParityRegressionTests`)
|
||||||
that checks a curated set of GHSA identifiers against OSV responses. The fixture
|
that checks a curated set of GHSA identifiers against OSV responses. The fixture
|
||||||
snapshots live in `src/StellaOps.Concelier.Connector.Osv.Tests/Fixtures/` and are kept
|
snapshots live in `src/Concelier/StellaOps.Concelier.PluginBinaries/StellaOps.Concelier.Connector.Osv.Tests/Fixtures/` and are kept
|
||||||
deterministic so the parity report remains reproducible.
|
deterministic so the parity report remains reproducible.
|
||||||
|
|
||||||
To refresh the fixtures when GHSA/OSV payloads change:
|
To refresh the fixtures when GHSA/OSV payloads change:
|
||||||
|
|
||||||
1. Ensure outbound HTTPS access to `https://api.osv.dev` and `https://api.github.com`.
|
1. Ensure outbound HTTPS access to `https://api.osv.dev` and `https://api.github.com`.
|
||||||
2. Run `UPDATE_PARITY_FIXTURES=1 dotnet test src/StellaOps.Concelier.Connector.Osv.Tests/StellaOps.Concelier.Connector.Osv.Tests.csproj`.
|
2. Run `UPDATE_PARITY_FIXTURES=1 dotnet test src/Concelier/StellaOps.Concelier.PluginBinaries/StellaOps.Concelier.Connector.Osv.Tests/StellaOps.Concelier.Connector.Osv.Tests.csproj`.
|
||||||
3. Commit the regenerated `osv-ghsa.*.json` files that the test emits (raw snapshots and canonical advisories).
|
3. Commit the regenerated `osv-ghsa.*.json` files that the test emits (raw snapshots and canonical advisories).
|
||||||
|
|
||||||
The regen flow logs `[Parity]` messages and normalises `recordedAt` timestamps so the
|
The regen flow logs `[Parity]` messages and normalises `recordedAt` timestamps so the
|
||||||
@@ -82,28 +82,28 @@ fixtures stay stable across machines.
|
|||||||
```mermaid
|
```mermaid
|
||||||
flowchart LR
|
flowchart LR
|
||||||
subgraph fast-path
|
subgraph fast-path
|
||||||
U[xUnit] --> P[FsCheck] --> I1[Testcontainer API]
|
U[xUnit] --> P[FsCheck] --> I1[Testcontainer API]
|
||||||
end
|
end
|
||||||
|
|
||||||
I1 --> FE[Jest]
|
I1 --> FE[Jest]
|
||||||
FE --> E2E[Playwright]
|
FE --> E2E[Playwright]
|
||||||
E2E --> Lighthouse
|
E2E --> Lighthouse
|
||||||
Lighthouse --> INTEG2[Concelier]
|
Lighthouse --> INTEG2[Concelier]
|
||||||
INTEG2 --> LOAD[k6]
|
INTEG2 --> LOAD[k6]
|
||||||
LOAD --> CHAOS[pumba]
|
LOAD --> CHAOS[pumba]
|
||||||
CHAOS --> RELEASE[Attestation diff]
|
CHAOS --> RELEASE[Attestation diff]
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Adding a new test layer
|
## Adding a new test layer
|
||||||
|
|
||||||
1. Extend `scripts/dev-test.sh` so local contributors get the layer by default.
|
1. Extend `scripts/dev-test.sh` so local contributors get the layer by default.
|
||||||
2. Add a dedicated GitLab job in `.gitlab-ci.yml` (stage `test` or `nightly`).
|
2. Add a dedicated GitLab job in `.gitlab-ci.yml` (stage `test` or `nightly`).
|
||||||
3. Register the job in `docs/19_TEST_SUITE_OVERVIEW.md` *and* list its metric
|
3. Register the job in `docs/19_TEST_SUITE_OVERVIEW.md` *and* list its metric
|
||||||
in `docs/metrics/README.md`.
|
in `docs/metrics/README.md`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
*Last updated {{ "now" | date: "%Y‑%m‑%d" }}*
|
*Last updated {{ "now" | date: "%Y‑%m‑%d" }}*
|
||||||
|
|
||||||
|
|||||||
@@ -1,190 +1,190 @@
|
|||||||
# Stella Ops — Installation Guide (Docker & Air‑Gap)
|
# Stella Ops — Installation Guide (Docker & Air‑Gap)
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
This file is processed by the Eleventy build.
|
This file is processed by the Eleventy build.
|
||||||
Do **not** hard‑code versions or quota numbers; inherit from
|
Do **not** hard‑code versions or quota numbers; inherit from
|
||||||
docs/_includes/CONSTANTS.md instead.
|
docs/_includes/CONSTANTS.md instead.
|
||||||
{{ dotnet }} → ".NET 10 LTS"
|
{{ dotnet }} → ".NET 10 LTS"
|
||||||
{{ angular }} → "20"
|
{{ angular }} → "20"
|
||||||
-->
|
-->
|
||||||
|
|
||||||
> **Status — public α not yet published.**
|
> **Status — public α not yet published.**
|
||||||
> The commands below will work as soon as the first image is tagged
|
> The commands below will work as soon as the first image is tagged
|
||||||
> `registry.stella-ops.org/stella-ops/stella-ops:0.1.0-alpha`
|
> `registry.stella-ops.org/stella-ops/stella-ops:0.1.0-alpha`
|
||||||
> (target date: **late 2025**). Track progress on the
|
> (target date: **late 2025**). Track progress on the
|
||||||
> [road‑map](/roadmap/).
|
> [road‑map](/roadmap/).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 0 · Prerequisites
|
## 0 · Prerequisites
|
||||||
|
|
||||||
| Item | Minimum | Notes |
|
| Item | Minimum | Notes |
|
||||||
|------|---------|-------|
|
|------|---------|-------|
|
||||||
| Linux | Ubuntu 22.04 LTS / Alma 9 | x86‑64 or arm64 |
|
| Linux | Ubuntu 22.04 LTS / Alma 9 | x86‑64 or arm64 |
|
||||||
| CPU / RAM | 2 vCPU / 2 GiB | Laptop baseline |
|
| CPU / RAM | 2 vCPU / 2 GiB | Laptop baseline |
|
||||||
| Disk | 10 GiB SSD | SBOM + vuln DB cache |
|
| Disk | 10 GiB SSD | SBOM + vuln DB cache |
|
||||||
| Docker | **Engine 25 + Compose v2** | `docker -v` |
|
| Docker | **Engine 25 + Compose v2** | `docker -v` |
|
||||||
| TLS | OpenSSL 1.1 + | Self‑signed cert generated at first run |
|
| TLS | OpenSSL 1.1 + | Self‑signed cert generated at first run |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 1 · Connected‑host install (Docker Compose)
|
## 1 · Connected‑host install (Docker Compose)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 1. Make a working directory
|
# 1. Make a working directory
|
||||||
mkdir stella && cd stella
|
mkdir stella && cd stella
|
||||||
|
|
||||||
# 2. Download the signed Compose bundle + example .env
|
# 2. Download the signed Compose bundle + example .env
|
||||||
curl -LO https://get.stella-ops.org/releases/latest/.env.example
|
curl -LO https://get.stella-ops.org/releases/latest/.env.example
|
||||||
curl -LO https://get.stella-ops.org/releases/latest/.env.example.sig
|
curl -LO https://get.stella-ops.org/releases/latest/.env.example.sig
|
||||||
curl -LO https://get.stella-ops.org/releases/latest/docker-compose.infrastructure.yml
|
curl -LO https://get.stella-ops.org/releases/latest/docker-compose.infrastructure.yml
|
||||||
curl -LO https://get.stella-ops.org/releases/latest/docker-compose.infrastructure.yml.sig
|
curl -LO https://get.stella-ops.org/releases/latest/docker-compose.infrastructure.yml.sig
|
||||||
curl -LO https://get.stella-ops.org/releases/latest/docker-compose.stella-ops.yml
|
curl -LO https://get.stella-ops.org/releases/latest/docker-compose.stella-ops.yml
|
||||||
curl -LO https://get.stella-ops.org/releases/latest/docker-compose.stella-ops.yml.sig
|
curl -LO https://get.stella-ops.org/releases/latest/docker-compose.stella-ops.yml.sig
|
||||||
|
|
||||||
# 3. Verify provenance (Cosign public key is stable)
|
# 3. Verify provenance (Cosign public key is stable)
|
||||||
cosign verify-blob \
|
cosign verify-blob \
|
||||||
--key https://stella-ops.org/keys/cosign.pub \
|
--key https://stella-ops.org/keys/cosign.pub \
|
||||||
--signature .env.example.sig \
|
--signature .env.example.sig \
|
||||||
.env.example
|
.env.example
|
||||||
|
|
||||||
cosign verify-blob \
|
cosign verify-blob \
|
||||||
--key https://stella-ops.org/keys/cosign.pub \
|
--key https://stella-ops.org/keys/cosign.pub \
|
||||||
--signature docker-compose.infrastructure.yml.sig \
|
--signature docker-compose.infrastructure.yml.sig \
|
||||||
docker-compose.infrastructure.yml
|
docker-compose.infrastructure.yml
|
||||||
|
|
||||||
cosign verify-blob \
|
cosign verify-blob \
|
||||||
--key https://stella-ops.org/keys/cosign.pub \
|
--key https://stella-ops.org/keys/cosign.pub \
|
||||||
--signature docker-compose.stella-ops.yml.sig \
|
--signature docker-compose.stella-ops.yml.sig \
|
||||||
docker-compose.stella-ops.yml
|
docker-compose.stella-ops.yml
|
||||||
|
|
||||||
# 4. Copy .env.example → .env and edit secrets
|
# 4. Copy .env.example → .env and edit secrets
|
||||||
cp .env.example .env
|
cp .env.example .env
|
||||||
$EDITOR .env
|
$EDITOR .env
|
||||||
|
|
||||||
# 5. Launch databases (MongoDB + Redis)
|
# 5. Launch databases (MongoDB + Redis)
|
||||||
docker compose --env-file .env -f docker-compose.infrastructure.yml up -d
|
docker compose --env-file .env -f docker-compose.infrastructure.yml up -d
|
||||||
|
|
||||||
# 6. Launch Stella Ops (first run pulls ~50 MB merged vuln DB)
|
# 6. Launch Stella Ops (first run pulls ~50 MB merged vuln DB)
|
||||||
docker compose --env-file .env -f docker-compose.stella-ops.yml up -d
|
docker compose --env-file .env -f docker-compose.stella-ops.yml up -d
|
||||||
````
|
````
|
||||||
|
|
||||||
*Default login:* `admin / changeme`
|
*Default login:* `admin / changeme`
|
||||||
UI: [https://\<host\>:8443](https://<host>:8443) (self‑signed certificate)
|
UI: [https://\<host\>:8443](https://<host>:8443) (self‑signed certificate)
|
||||||
|
|
||||||
> **Pinning best‑practice** – in production environments replace
|
> **Pinning best‑practice** – in production environments replace
|
||||||
> `stella-ops:latest` with the immutable digest printed by
|
> `stella-ops:latest` with the immutable digest printed by
|
||||||
> `docker images --digests`.
|
> `docker images --digests`.
|
||||||
|
|
||||||
> **Repo bundles** – Development, staging, and air‑gapped Compose profiles live
|
> **Repo bundles** – Development, staging, and air‑gapped Compose profiles live
|
||||||
> under `deploy/compose/`, already tied to the release manifests in
|
> under `deploy/compose/`, already tied to the release manifests in
|
||||||
> `deploy/releases/`. Helm users can pull the same channel overlays from
|
> `deploy/releases/`. Helm users can pull the same channel overlays from
|
||||||
> `deploy/helm/stellaops/values-*.yaml` and validate everything with
|
> `deploy/helm/stellaops/values-*.yaml` and validate everything with
|
||||||
> `deploy/tools/validate-profiles.sh`.
|
> `deploy/tools/validate-profiles.sh`.
|
||||||
|
|
||||||
### 1.1 · Concelier authority configuration
|
### 1.1 · Concelier authority configuration
|
||||||
|
|
||||||
The Concelier container reads configuration from `etc/concelier.yaml` plus
|
The Concelier container reads configuration from `etc/concelier.yaml` plus
|
||||||
`CONCELIER_` environment variables. To enable the new Authority integration:
|
`CONCELIER_` environment variables. To enable the new Authority integration:
|
||||||
|
|
||||||
1. Add the following keys to `.env` (replace values for your environment):
|
1. Add the following keys to `.env` (replace values for your environment):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
CONCELIER_AUTHORITY__ENABLED=true
|
CONCELIER_AUTHORITY__ENABLED=true
|
||||||
CONCELIER_AUTHORITY__ALLOWANONYMOUSFALLBACK=true # temporary rollout only
|
CONCELIER_AUTHORITY__ALLOWANONYMOUSFALLBACK=true # temporary rollout only
|
||||||
CONCELIER_AUTHORITY__ISSUER="https://authority.internal"
|
CONCELIER_AUTHORITY__ISSUER="https://authority.internal"
|
||||||
CONCELIER_AUTHORITY__AUDIENCES__0="api://concelier"
|
CONCELIER_AUTHORITY__AUDIENCES__0="api://concelier"
|
||||||
CONCELIER_AUTHORITY__REQUIREDSCOPES__0="concelier.jobs.trigger"
|
CONCELIER_AUTHORITY__REQUIREDSCOPES__0="concelier.jobs.trigger"
|
||||||
CONCELIER_AUTHORITY__REQUIREDSCOPES__1="advisory:read"
|
CONCELIER_AUTHORITY__REQUIREDSCOPES__1="advisory:read"
|
||||||
CONCELIER_AUTHORITY__REQUIREDSCOPES__2="advisory:ingest"
|
CONCELIER_AUTHORITY__REQUIREDSCOPES__2="advisory:ingest"
|
||||||
CONCELIER_AUTHORITY__REQUIREDTENANTS__0="tenant-default"
|
CONCELIER_AUTHORITY__REQUIREDTENANTS__0="tenant-default"
|
||||||
CONCELIER_AUTHORITY__CLIENTID="concelier-jobs"
|
CONCELIER_AUTHORITY__CLIENTID="concelier-jobs"
|
||||||
CONCELIER_AUTHORITY__CLIENTSCOPES__0="concelier.jobs.trigger"
|
CONCELIER_AUTHORITY__CLIENTSCOPES__0="concelier.jobs.trigger"
|
||||||
CONCELIER_AUTHORITY__CLIENTSCOPES__1="advisory:read"
|
CONCELIER_AUTHORITY__CLIENTSCOPES__1="advisory:read"
|
||||||
CONCELIER_AUTHORITY__CLIENTSCOPES__2="advisory:ingest"
|
CONCELIER_AUTHORITY__CLIENTSCOPES__2="advisory:ingest"
|
||||||
CONCELIER_AUTHORITY__CLIENTSECRETFILE="/run/secrets/concelier_authority_client"
|
CONCELIER_AUTHORITY__CLIENTSECRETFILE="/run/secrets/concelier_authority_client"
|
||||||
CONCELIER_AUTHORITY__BYPASSNETWORKS__0="127.0.0.1/32"
|
CONCELIER_AUTHORITY__BYPASSNETWORKS__0="127.0.0.1/32"
|
||||||
CONCELIER_AUTHORITY__BYPASSNETWORKS__1="::1/128"
|
CONCELIER_AUTHORITY__BYPASSNETWORKS__1="::1/128"
|
||||||
CONCELIER_AUTHORITY__RESILIENCE__ENABLERETRIES=true
|
CONCELIER_AUTHORITY__RESILIENCE__ENABLERETRIES=true
|
||||||
CONCELIER_AUTHORITY__RESILIENCE__RETRYDELAYS__0="00:00:01"
|
CONCELIER_AUTHORITY__RESILIENCE__RETRYDELAYS__0="00:00:01"
|
||||||
CONCELIER_AUTHORITY__RESILIENCE__RETRYDELAYS__1="00:00:02"
|
CONCELIER_AUTHORITY__RESILIENCE__RETRYDELAYS__1="00:00:02"
|
||||||
CONCELIER_AUTHORITY__RESILIENCE__RETRYDELAYS__2="00:00:05"
|
CONCELIER_AUTHORITY__RESILIENCE__RETRYDELAYS__2="00:00:05"
|
||||||
CONCELIER_AUTHORITY__RESILIENCE__ALLOWOFFLINECACHEFALLBACK=true
|
CONCELIER_AUTHORITY__RESILIENCE__ALLOWOFFLINECACHEFALLBACK=true
|
||||||
CONCELIER_AUTHORITY__RESILIENCE__OFFLINECACHETOLERANCE="00:10:00"
|
CONCELIER_AUTHORITY__RESILIENCE__OFFLINECACHETOLERANCE="00:10:00"
|
||||||
```
|
```
|
||||||
|
|
||||||
Store the client secret outside source control (Docker secrets, mounted file,
|
Store the client secret outside source control (Docker secrets, mounted file,
|
||||||
or Kubernetes Secret). Concelier loads the secret during post-configuration, so
|
or Kubernetes Secret). Concelier loads the secret during post-configuration, so
|
||||||
the value never needs to appear in the YAML template.
|
the value never needs to appear in the YAML template.
|
||||||
|
|
||||||
Connected sites can keep the retry ladder short (1 s, 2 s, 5 s) so job triggers fail fast when Authority is down. For air‑gapped or intermittently connected deployments, extend `RESILIENCE__OFFLINECACHETOLERANCE` (e.g. `00:30:00`) so cached discovery/JWKS data remains valid while the Offline Kit synchronises upstream changes.
|
Connected sites can keep the retry ladder short (1 s, 2 s, 5 s) so job triggers fail fast when Authority is down. For air‑gapped or intermittently connected deployments, extend `RESILIENCE__OFFLINECACHETOLERANCE` (e.g. `00:30:00`) so cached discovery/JWKS data remains valid while the Offline Kit synchronises upstream changes.
|
||||||
|
|
||||||
2. Redeploy Concelier:
|
2. Redeploy Concelier:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker compose --env-file .env -f docker-compose.stella-ops.yml up -d concelier
|
docker compose --env-file .env -f docker-compose.stella-ops.yml up -d concelier
|
||||||
```
|
```
|
||||||
|
|
||||||
3. Tail the logs: `docker compose logs -f concelier`. Successful `/jobs*` calls now
|
3. Tail the logs: `docker compose logs -f concelier`. Successful `/jobs*` calls now
|
||||||
emit `Concelier.Authorization.Audit` entries with `route`, `status`, `subject`,
|
emit `Concelier.Authorization.Audit` entries with `route`, `status`, `subject`,
|
||||||
`clientId`, `scopes`, `bypass`, and `remote` fields. 401 denials keep the same
|
`clientId`, `scopes`, `bypass`, and `remote` fields. 401 denials keep the same
|
||||||
shape—watch for `bypass=True`, which indicates a bypass CIDR accepted an anonymous
|
shape—watch for `bypass=True`, which indicates a bypass CIDR accepted an anonymous
|
||||||
call. See `docs/ops/concelier-authority-audit-runbook.md` for a full audit/alerting checklist.
|
call. See `docs/ops/concelier-authority-audit-runbook.md` for a full audit/alerting checklist.
|
||||||
|
|
||||||
> **Enforcement deadline** – keep `CONCELIER_AUTHORITY__ALLOWANONYMOUSFALLBACK=true`
|
> **Enforcement deadline** – keep `CONCELIER_AUTHORITY__ALLOWANONYMOUSFALLBACK=true`
|
||||||
> only while validating the rollout. Set it to `false` (and restart Concelier)
|
> only while validating the rollout. Set it to `false` (and restart Concelier)
|
||||||
> before **2025-12-31 UTC** to require tokens in production.
|
> before **2025-12-31 UTC** to require tokens in production.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 2 · Optional: request a free quota token
|
## 2 · Optional: request a free quota token
|
||||||
|
|
||||||
Anonymous installs allow **{{ quota\_anon }} scans per UTC day**.
|
Anonymous installs allow **{{ quota\_anon }} scans per UTC day**.
|
||||||
Email `token@stella-ops.org` to receive a signed JWT that raises the limit to
|
Email `token@stella-ops.org` to receive a signed JWT that raises the limit to
|
||||||
**{{ quota\_token }} scans/day**. Insert it into `.env`:
|
**{{ quota\_token }} scans/day**. Insert it into `.env`:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
STELLA_JWT="paste‑token‑here"
|
STELLA_JWT="paste‑token‑here"
|
||||||
docker compose --env-file .env -f docker-compose.stella-ops.yml \
|
docker compose --env-file .env -f docker-compose.stella-ops.yml \
|
||||||
exec stella-ops stella set-jwt "$STELLA_JWT"
|
exec stella-ops stella set-jwt "$STELLA_JWT"
|
||||||
```
|
```
|
||||||
|
|
||||||
> The UI shows a reminder at 200 scans and throttles above the limit but will
|
> The UI shows a reminder at 200 scans and throttles above the limit but will
|
||||||
> **never block** your pipeline.
|
> **never block** your pipeline.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 3 · Air‑gapped install (Offline Update Kit)
|
## 3 · Air‑gapped install (Offline Update Kit)
|
||||||
|
|
||||||
When running on an isolated network use the **Offline Update Kit (OUK)**:
|
When running on an isolated network use the **Offline Update Kit (OUK)**:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Download & verify on a connected host
|
# Download & verify on a connected host
|
||||||
curl -LO https://get.stella-ops.org/ouk/stella-ops-offline-kit-v0.1a.tgz
|
curl -LO https://get.stella-ops.org/ouk/stella-ops-offline-kit-v0.1a.tgz
|
||||||
curl -LO https://get.stella-ops.org/ouk/stella-ops-offline-kit-v0.1a.tgz.sig
|
curl -LO https://get.stella-ops.org/ouk/stella-ops-offline-kit-v0.1a.tgz.sig
|
||||||
|
|
||||||
cosign verify-blob \
|
cosign verify-blob \
|
||||||
--key https://stella-ops.org/keys/cosign.pub \
|
--key https://stella-ops.org/keys/cosign.pub \
|
||||||
--signature stella-ops-offline-kit-v0.1a.tgz.sig \
|
--signature stella-ops-offline-kit-v0.1a.tgz.sig \
|
||||||
stella-ops-offline-kit-v0.1a.tgz
|
stella-ops-offline-kit-v0.1a.tgz
|
||||||
|
|
||||||
# Transfer → air‑gap → import
|
# Transfer → air‑gap → import
|
||||||
docker compose --env-file .env -f docker-compose.stella-ops.yml \
|
docker compose --env-file .env -f docker-compose.stella-ops.yml \
|
||||||
exec stella admin import-offline-usage-kit stella-ops-offline-kit-v0.1a.tgz
|
exec stella admin import-offline-usage-kit stella-ops-offline-kit-v0.1a.tgz
|
||||||
```
|
```
|
||||||
|
|
||||||
*Import is atomic; no service downtime.*
|
*Import is atomic; no service downtime.*
|
||||||
|
|
||||||
For details see the dedicated [Offline Kit guide](/offline/).
|
For details see the dedicated [Offline Kit guide](/offline/).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 4 · Next steps
|
## 4 · Next steps
|
||||||
|
|
||||||
* **5‑min Quick‑Start:** `/quickstart/`
|
* **5‑min Quick‑Start:** `/quickstart/`
|
||||||
* **CI recipes:** `docs/ci/20_CI_RECIPES.md`
|
* **CI recipes:** `docs/ci/20_CI_RECIPES.md`
|
||||||
* **Plug‑in SDK:** `/plugins/`
|
* **Plug‑in SDK:** `/plugins/`
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
*Generated {{ "now" | date: "%Y‑%m‑%d" }} — build tags inserted at render time.*
|
*Generated {{ "now" | date: "%Y‑%m‑%d" }} — build tags inserted at render time.*
|
||||||
|
|||||||
@@ -1,443 +1,443 @@
|
|||||||
# component_architecture_authority.md — **Stella Ops Authority** (2025Q4)
|
# component_architecture_authority.md — **Stella Ops Authority** (2025Q4)
|
||||||
|
|
||||||
> **Scope.** Implementation‑ready architecture for **Stella Ops Authority**: the on‑prem **OIDC/OAuth2** service that issues **short‑lived, sender‑constrained operational tokens (OpToks)** to first‑party services and tools. Covers protocols (DPoP & mTLS binding), token shapes, endpoints, storage, rotation, HA, RBAC, audit, and testing. This component is the trust anchor for *who* is calling inside a Stella Ops installation. (Entitlement is proven separately by **PoE** from the cloud Licensing Service; Authority does not issue PoE.)
|
> **Scope.** Implementation‑ready architecture for **Stella Ops Authority**: the on‑prem **OIDC/OAuth2** service that issues **short‑lived, sender‑constrained operational tokens (OpToks)** to first‑party services and tools. Covers protocols (DPoP & mTLS binding), token shapes, endpoints, storage, rotation, HA, RBAC, audit, and testing. This component is the trust anchor for *who* is calling inside a Stella Ops installation. (Entitlement is proven separately by **PoE** from the cloud Licensing Service; Authority does not issue PoE.)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 0) Mission & boundaries
|
## 0) Mission & boundaries
|
||||||
|
|
||||||
**Mission.** Provide **fast, local, verifiable** authentication for Stella Ops microservices and tools by minting **very short‑lived** OAuth2/OIDC tokens that are **sender‑constrained** (DPoP or mTLS‑bound). Support RBAC scopes, multi‑tenant claims, and deterministic validation for APIs (Scanner, Signer, Attestor, Excititor, Concelier, UI, CLI, Zastava).
|
**Mission.** Provide **fast, local, verifiable** authentication for Stella Ops microservices and tools by minting **very short‑lived** OAuth2/OIDC tokens that are **sender‑constrained** (DPoP or mTLS‑bound). Support RBAC scopes, multi‑tenant claims, and deterministic validation for APIs (Scanner, Signer, Attestor, Excititor, Concelier, UI, CLI, Zastava).
|
||||||
|
|
||||||
**Boundaries.**
|
**Boundaries.**
|
||||||
|
|
||||||
* Authority **does not** validate entitlements/licensing. That’s enforced by **Signer** using **PoE** with the cloud Licensing Service.
|
* Authority **does not** validate entitlements/licensing. That’s enforced by **Signer** using **PoE** with the cloud Licensing Service.
|
||||||
* Authority tokens are **operational only** (2–5 min TTL) and must not be embedded in long‑lived artifacts or stored in SBOMs.
|
* Authority tokens are **operational only** (2–5 min TTL) and must not be embedded in long‑lived artifacts or stored in SBOMs.
|
||||||
* Authority is **stateless for validation** (JWT) and **optional introspection** for services that prefer online checks.
|
* Authority is **stateless for validation** (JWT) and **optional introspection** for services that prefer online checks.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 1) Protocols & cryptography
|
## 1) Protocols & cryptography
|
||||||
|
|
||||||
* **OIDC Discovery**: `/.well-known/openid-configuration`
|
* **OIDC Discovery**: `/.well-known/openid-configuration`
|
||||||
* **OAuth2** grant types:
|
* **OAuth2** grant types:
|
||||||
|
|
||||||
* **Client Credentials** (service↔service, with mTLS or private_key_jwt)
|
* **Client Credentials** (service↔service, with mTLS or private_key_jwt)
|
||||||
* **Device Code** (CLI login on headless agents; optional)
|
* **Device Code** (CLI login on headless agents; optional)
|
||||||
* **Authorization Code + PKCE** (browser login for UI; optional)
|
* **Authorization Code + PKCE** (browser login for UI; optional)
|
||||||
* **Sender constraint options** (choose per caller or per audience):
|
* **Sender constraint options** (choose per caller or per audience):
|
||||||
|
|
||||||
* **DPoP** (Demonstration of Proof‑of‑Possession): proof JWT on each HTTP request, bound to the access token via `cnf.jkt`.
|
* **DPoP** (Demonstration of Proof‑of‑Possession): proof JWT on each HTTP request, bound to the access token via `cnf.jkt`.
|
||||||
* **OAuth 2.0 mTLS** (certificate‑bound tokens): token bound to client certificate thumbprint via `cnf.x5t#S256`.
|
* **OAuth 2.0 mTLS** (certificate‑bound tokens): token bound to client certificate thumbprint via `cnf.x5t#S256`.
|
||||||
* **Signing algorithms**: **EdDSA (Ed25519)** preferred; fallback **ES256 (P‑256)**. Rotation is supported via **kid** in JWKS.
|
* **Signing algorithms**: **EdDSA (Ed25519)** preferred; fallback **ES256 (P‑256)**. Rotation is supported via **kid** in JWKS.
|
||||||
* **Token format**: **JWT** access tokens (compact), optionally opaque reference tokens for services that insist on introspection.
|
* **Token format**: **JWT** access tokens (compact), optionally opaque reference tokens for services that insist on introspection.
|
||||||
* **Clock skew tolerance**: ±60 s; issue `nbf`, `iat`, `exp` accordingly.
|
* **Clock skew tolerance**: ±60 s; issue `nbf`, `iat`, `exp` accordingly.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 2) Token model
|
## 2) Token model
|
||||||
|
|
||||||
### 2.1 Access token (OpTok) — short‑lived (120–300 s)
|
### 2.1 Access token (OpTok) — short‑lived (120–300 s)
|
||||||
|
|
||||||
**Registered claims**
|
**Registered claims**
|
||||||
|
|
||||||
```
|
```
|
||||||
iss = https://authority.<domain>
|
iss = https://authority.<domain>
|
||||||
sub = <client_id or user_id>
|
sub = <client_id or user_id>
|
||||||
aud = <service audience: signer|scanner|attestor|concelier|excititor|ui|zastava>
|
aud = <service audience: signer|scanner|attestor|concelier|excititor|ui|zastava>
|
||||||
exp = <unix ts> (<= 300 s from iat)
|
exp = <unix ts> (<= 300 s from iat)
|
||||||
iat = <unix ts>
|
iat = <unix ts>
|
||||||
nbf = iat - 30
|
nbf = iat - 30
|
||||||
jti = <uuid>
|
jti = <uuid>
|
||||||
scope = "scanner.scan scanner.export signer.sign ..."
|
scope = "scanner.scan scanner.export signer.sign ..."
|
||||||
```
|
```
|
||||||
|
|
||||||
**Sender‑constraint (`cnf`)**
|
**Sender‑constraint (`cnf`)**
|
||||||
|
|
||||||
* **DPoP**:
|
* **DPoP**:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
"cnf": { "jkt": "<base64url(SHA-256(JWK))>" }
|
"cnf": { "jkt": "<base64url(SHA-256(JWK))>" }
|
||||||
```
|
```
|
||||||
* **mTLS**:
|
* **mTLS**:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
"cnf": { "x5t#S256": "<base64url(SHA-256(client_cert_der))>" }
|
"cnf": { "x5t#S256": "<base64url(SHA-256(client_cert_der))>" }
|
||||||
```
|
```
|
||||||
|
|
||||||
**Install/tenant context (custom claims)**
|
**Install/tenant context (custom claims)**
|
||||||
|
|
||||||
```
|
```
|
||||||
tid = <tenant id> // multi-tenant
|
tid = <tenant id> // multi-tenant
|
||||||
inst = <installation id> // unique installation
|
inst = <installation id> // unique installation
|
||||||
roles = [ "svc.scanner", "svc.signer", "ui.admin", ... ]
|
roles = [ "svc.scanner", "svc.signer", "ui.admin", ... ]
|
||||||
plan? = <plan name> // optional hint for UIs; not used for enforcement
|
plan? = <plan name> // optional hint for UIs; not used for enforcement
|
||||||
```
|
```
|
||||||
|
|
||||||
> **Note**: Do **not** copy PoE claims into OpTok; OpTok ≠ entitlement. Only **Signer** checks PoE.
|
> **Note**: Do **not** copy PoE claims into OpTok; OpTok ≠ entitlement. Only **Signer** checks PoE.
|
||||||
|
|
||||||
### 2.2 Refresh tokens (optional)
|
### 2.2 Refresh tokens (optional)
|
||||||
|
|
||||||
* Default **disabled**. If enabled (for UI interactive logins), pair with **DPoP‑bound** refresh tokens or **mTLS** client sessions; short TTL (≤ 8 h), rotating on use (replay‑safe).
|
* Default **disabled**. If enabled (for UI interactive logins), pair with **DPoP‑bound** refresh tokens or **mTLS** client sessions; short TTL (≤ 8 h), rotating on use (replay‑safe).
|
||||||
|
|
||||||
### 2.3 ID tokens (optional)
|
### 2.3 ID tokens (optional)
|
||||||
|
|
||||||
* Issued for UI/browser OIDC flows (Authorization Code + PKCE); not used for service auth.
|
* Issued for UI/browser OIDC flows (Authorization Code + PKCE); not used for service auth.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 3) Endpoints & flows
|
## 3) Endpoints & flows
|
||||||
|
|
||||||
### 3.1 OIDC discovery & keys
|
### 3.1 OIDC discovery & keys
|
||||||
|
|
||||||
* `GET /.well-known/openid-configuration` → endpoints, algs, jwks_uri
|
* `GET /.well-known/openid-configuration` → endpoints, algs, jwks_uri
|
||||||
* `GET /jwks` → JSON Web Key Set (rotating, at least 2 active keys during transition)
|
* `GET /jwks` → JSON Web Key Set (rotating, at least 2 active keys during transition)
|
||||||
|
|
||||||
### 3.2 Token issuance
|
### 3.2 Token issuance
|
||||||
|
|
||||||
* `POST /oauth/token`
|
* `POST /oauth/token`
|
||||||
|
|
||||||
* **Client Credentials** (service→service):
|
* **Client Credentials** (service→service):
|
||||||
|
|
||||||
* **mTLS**: mutual TLS + `client_id` → bound token (`cnf.x5t#S256`)
|
* **mTLS**: mutual TLS + `client_id` → bound token (`cnf.x5t#S256`)
|
||||||
* `security.senderConstraints.mtls.enforceForAudiences` forces the mTLS path when requested `aud`/`resource` values intersect high-value audiences (defaults include `signer`). Authority rejects clients attempting to use DPoP/basic secrets for these audiences.
|
* `security.senderConstraints.mtls.enforceForAudiences` forces the mTLS path when requested `aud`/`resource` values intersect high-value audiences (defaults include `signer`). Authority rejects clients attempting to use DPoP/basic secrets for these audiences.
|
||||||
* Stored `certificateBindings` are authoritative: thumbprint, subject, issuer, serial number, and SAN values are matched against the presented certificate, with rotation grace applied to activation windows. Failures surface deterministic error codes (e.g. `certificate_binding_subject_mismatch`).
|
* Stored `certificateBindings` are authoritative: thumbprint, subject, issuer, serial number, and SAN values are matched against the presented certificate, with rotation grace applied to activation windows. Failures surface deterministic error codes (e.g. `certificate_binding_subject_mismatch`).
|
||||||
* **private_key_jwt**: JWT‑based client auth + **DPoP** header (preferred for tools and CLI)
|
* **private_key_jwt**: JWT‑based client auth + **DPoP** header (preferred for tools and CLI)
|
||||||
* **Device Code** (CLI): `POST /oauth/device/code` + `POST /oauth/token` poll
|
* **Device Code** (CLI): `POST /oauth/device/code` + `POST /oauth/token` poll
|
||||||
* **Authorization Code + PKCE** (UI): standard
|
* **Authorization Code + PKCE** (UI): standard
|
||||||
|
|
||||||
**DPoP handshake (example)**
|
**DPoP handshake (example)**
|
||||||
|
|
||||||
1. Client prepares **JWK** (ephemeral keypair).
|
1. Client prepares **JWK** (ephemeral keypair).
|
||||||
2. Client sends **DPoP proof** header with fields:
|
2. Client sends **DPoP proof** header with fields:
|
||||||
|
|
||||||
```
|
```
|
||||||
htm=POST
|
htm=POST
|
||||||
htu=https://authority.../oauth/token
|
htu=https://authority.../oauth/token
|
||||||
iat=<now>
|
iat=<now>
|
||||||
jti=<uuid>
|
jti=<uuid>
|
||||||
```
|
```
|
||||||
|
|
||||||
signed with the DPoP private key; header carries JWK.
|
signed with the DPoP private key; header carries JWK.
|
||||||
3. Authority validates proof; issues access token with `cnf.jkt=<thumbprint(JWK)>`.
|
3. Authority validates proof; issues access token with `cnf.jkt=<thumbprint(JWK)>`.
|
||||||
4. Client uses the same DPoP key to sign **every subsequent API request** to services (Signer, Scanner, …).
|
4. Client uses the same DPoP key to sign **every subsequent API request** to services (Signer, Scanner, …).
|
||||||
|
|
||||||
**mTLS flow**
|
**mTLS flow**
|
||||||
|
|
||||||
* Mutual TLS at the connection; Authority extracts client cert, validates chain; token carries `cnf.x5t#S256`.
|
* Mutual TLS at the connection; Authority extracts client cert, validates chain; token carries `cnf.x5t#S256`.
|
||||||
|
|
||||||
### 3.3 Introspection & revocation (optional)
|
### 3.3 Introspection & revocation (optional)
|
||||||
|
|
||||||
* `POST /oauth/introspect` → `{ active, sub, scope, aud, exp, cnf, ... }`
|
* `POST /oauth/introspect` → `{ active, sub, scope, aud, exp, cnf, ... }`
|
||||||
* `POST /oauth/revoke` → revokes refresh tokens or opaque access tokens.
|
* `POST /oauth/revoke` → revokes refresh tokens or opaque access tokens.
|
||||||
* **Replay prevention**: maintain **DPoP `jti` cache** (TTL ≤ 10 min) to reject duplicate proofs when services supply DPoP nonces (Signer requires nonce for high‑value operations).
|
* **Replay prevention**: maintain **DPoP `jti` cache** (TTL ≤ 10 min) to reject duplicate proofs when services supply DPoP nonces (Signer requires nonce for high‑value operations).
|
||||||
|
|
||||||
### 3.4 UserInfo (optional for UI)
|
### 3.4 UserInfo (optional for UI)
|
||||||
|
|
||||||
* `GET /userinfo` (ID token context).
|
* `GET /userinfo` (ID token context).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 4) Audiences, scopes & RBAC
|
## 4) Audiences, scopes & RBAC
|
||||||
|
|
||||||
### 4.1 Audiences
|
### 4.1 Audiences
|
||||||
|
|
||||||
* `signer` — only the **Signer** service should accept tokens with `aud=signer`.
|
* `signer` — only the **Signer** service should accept tokens with `aud=signer`.
|
||||||
* `attestor`, `scanner`, `concelier`, `excititor`, `ui`, `zastava` similarly.
|
* `attestor`, `scanner`, `concelier`, `excititor`, `ui`, `zastava` similarly.
|
||||||
|
|
||||||
Services **must** verify `aud` and **sender constraint** (DPoP/mTLS) per their policy.
|
Services **must** verify `aud` and **sender constraint** (DPoP/mTLS) per their policy.
|
||||||
|
|
||||||
### 4.2 Core scopes
|
### 4.2 Core scopes
|
||||||
|
|
||||||
| Scope | Service | Operation |
|
| Scope | Service | Operation |
|
||||||
| ---------------------------------- | ------------------ | -------------------------- |
|
| ---------------------------------- | ------------------ | -------------------------- |
|
||||||
| `signer.sign` | Signer | Request DSSE signing |
|
| `signer.sign` | Signer | Request DSSE signing |
|
||||||
| `attestor.write` | Attestor | Submit Rekor entries |
|
| `attestor.write` | Attestor | Submit Rekor entries |
|
||||||
| `scanner.scan` | Scanner.WebService | Submit scan jobs |
|
| `scanner.scan` | Scanner.WebService | Submit scan jobs |
|
||||||
| `scanner.export` | Scanner.WebService | Export SBOMs |
|
| `scanner.export` | Scanner.WebService | Export SBOMs |
|
||||||
| `scanner.read` | Scanner.WebService | Read catalog/SBOMs |
|
| `scanner.read` | Scanner.WebService | Read catalog/SBOMs |
|
||||||
| `vex.read` / `vex.admin` | Excititor | Query/operate |
|
| `vex.read` / `vex.admin` | Excititor | Query/operate |
|
||||||
| `concelier.read` / `concelier.export` | Concelier | Query/exports |
|
| `concelier.read` / `concelier.export` | Concelier | Query/exports |
|
||||||
| `ui.read` / `ui.admin` | UI | View/admin |
|
| `ui.read` / `ui.admin` | UI | View/admin |
|
||||||
| `zastava.emit` / `zastava.enforce` | Scanner/Zastava | Runtime events / admission |
|
| `zastava.emit` / `zastava.enforce` | Scanner/Zastava | Runtime events / admission |
|
||||||
|
|
||||||
**Roles → scopes mapping** is configured centrally (Authority policy) and pushed during token issuance.
|
**Roles → scopes mapping** is configured centrally (Authority policy) and pushed during token issuance.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 5) Storage & state
|
## 5) Storage & state
|
||||||
|
|
||||||
* **Configuration DB** (PostgreSQL/MySQL): clients, audiences, role→scope maps, tenant/installation registry, device code grants, persistent consents (if any).
|
* **Configuration DB** (PostgreSQL/MySQL): clients, audiences, role→scope maps, tenant/installation registry, device code grants, persistent consents (if any).
|
||||||
* **Cache** (Redis):
|
* **Cache** (Redis):
|
||||||
|
|
||||||
* DPoP **jti** replay cache (short TTL)
|
* DPoP **jti** replay cache (short TTL)
|
||||||
* **Nonce** store (per resource server, if they demand nonce)
|
* **Nonce** store (per resource server, if they demand nonce)
|
||||||
* Device code pollers, rate limiting buckets
|
* Device code pollers, rate limiting buckets
|
||||||
* **JWKS**: key material in HSM/KMS or encrypted at rest; JWKS served from memory.
|
* **JWKS**: key material in HSM/KMS or encrypted at rest; JWKS served from memory.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 6) Key management & rotation
|
## 6) Key management & rotation
|
||||||
|
|
||||||
* Maintain **at least 2 signing keys** active during rotation; tokens carry `kid`.
|
* Maintain **at least 2 signing keys** active during rotation; tokens carry `kid`.
|
||||||
* Prefer **Ed25519** for compact tokens; maintain **ES256** fallback for FIPS contexts.
|
* Prefer **Ed25519** for compact tokens; maintain **ES256** fallback for FIPS contexts.
|
||||||
* Rotation cadence: 30–90 days; emergency rotation supported.
|
* Rotation cadence: 30–90 days; emergency rotation supported.
|
||||||
* Publish new JWKS **before** issuing tokens with the new `kid` to avoid cold‑start validation misses.
|
* Publish new JWKS **before** issuing tokens with the new `kid` to avoid cold‑start validation misses.
|
||||||
* Keep **old keys** available **at least** for max token TTL + 5 minutes.
|
* Keep **old keys** available **at least** for max token TTL + 5 minutes.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 7) HA & performance
|
## 7) HA & performance
|
||||||
|
|
||||||
* **Stateless issuance** (except device codes/refresh) → scale horizontally behind a load‑balancer.
|
* **Stateless issuance** (except device codes/refresh) → scale horizontally behind a load‑balancer.
|
||||||
* **DB** only for client metadata and optional flows; token checks are JWT‑local; introspection endpoints hit cache/DB minimally.
|
* **DB** only for client metadata and optional flows; token checks are JWT‑local; introspection endpoints hit cache/DB minimally.
|
||||||
* **Targets**:
|
* **Targets**:
|
||||||
|
|
||||||
* Token issuance P95 ≤ **20 ms** under warm cache.
|
* Token issuance P95 ≤ **20 ms** under warm cache.
|
||||||
* DPoP proof validation ≤ **1 ms** extra per request at resource servers (Signer/Scanner).
|
* DPoP proof validation ≤ **1 ms** extra per request at resource servers (Signer/Scanner).
|
||||||
* 99.9% uptime; HPA on CPU/latency.
|
* 99.9% uptime; HPA on CPU/latency.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 8) Security posture
|
## 8) Security posture
|
||||||
|
|
||||||
* **Strict TLS** (1.3 preferred); HSTS; modern cipher suites.
|
* **Strict TLS** (1.3 preferred); HSTS; modern cipher suites.
|
||||||
* **mTLS** enabled where required (Signer/Attestor paths).
|
* **mTLS** enabled where required (Signer/Attestor paths).
|
||||||
* **Replay protection**: DPoP `jti` cache, nonce support for **Signer** (add `DPoP-Nonce` header on 401; clients re‑sign).
|
* **Replay protection**: DPoP `jti` cache, nonce support for **Signer** (add `DPoP-Nonce` header on 401; clients re‑sign).
|
||||||
* **Rate limits** per client & per IP; exponential backoff on failures.
|
* **Rate limits** per client & per IP; exponential backoff on failures.
|
||||||
* **Secrets**: clients use **private_key_jwt** or **mTLS**; never basic secrets over the wire.
|
* **Secrets**: clients use **private_key_jwt** or **mTLS**; never basic secrets over the wire.
|
||||||
* **CSP/CSRF** hardening on UI flows; `SameSite=Lax` cookies; PKCE enforced.
|
* **CSP/CSRF** hardening on UI flows; `SameSite=Lax` cookies; PKCE enforced.
|
||||||
* **Logs** redact `Authorization` and DPoP proofs; store `sub`, `aud`, `scopes`, `inst`, `tid`, `cnf` thumbprints, not full keys.
|
* **Logs** redact `Authorization` and DPoP proofs; store `sub`, `aud`, `scopes`, `inst`, `tid`, `cnf` thumbprints, not full keys.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 9) Multi‑tenancy & installations
|
## 9) Multi‑tenancy & installations
|
||||||
|
|
||||||
* **Tenant (`tid`)** and **Installation (`inst`)** registries define which audiences/scopes a client can request.
|
* **Tenant (`tid`)** and **Installation (`inst`)** registries define which audiences/scopes a client can request.
|
||||||
* Cross‑tenant isolation enforced at issuance (disallow rogue `aud`), and resource servers **must** check that `tid` matches their configured tenant.
|
* Cross‑tenant isolation enforced at issuance (disallow rogue `aud`), and resource servers **must** check that `tid` matches their configured tenant.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 10) Admin & operations APIs
|
## 10) Admin & operations APIs
|
||||||
|
|
||||||
All under `/admin` (mTLS + `authority.admin` scope).
|
All under `/admin` (mTLS + `authority.admin` scope).
|
||||||
|
|
||||||
```
|
```
|
||||||
POST /admin/clients # create/update client (confidential/public)
|
POST /admin/clients # create/update client (confidential/public)
|
||||||
POST /admin/audiences # register audience resource URIs
|
POST /admin/audiences # register audience resource URIs
|
||||||
POST /admin/roles # define role→scope mappings
|
POST /admin/roles # define role→scope mappings
|
||||||
POST /admin/tenants # create tenant/install entries
|
POST /admin/tenants # create tenant/install entries
|
||||||
POST /admin/keys/rotate # rotate signing key (zero-downtime)
|
POST /admin/keys/rotate # rotate signing key (zero-downtime)
|
||||||
GET /admin/metrics # Prometheus exposition (token issue rates, errors)
|
GET /admin/metrics # Prometheus exposition (token issue rates, errors)
|
||||||
GET /admin/healthz|readyz # health/readiness
|
GET /admin/healthz|readyz # health/readiness
|
||||||
```
|
```
|
||||||
|
|
||||||
Declared client `audiences` flow through to the issued JWT `aud` claim and the token request's `resource` indicators. Authority relies on this metadata to enforce DPoP nonce challenges for `signer`, `attestor`, and other high-value services without requiring clients to repeat the audience parameter on every request.
|
Declared client `audiences` flow through to the issued JWT `aud` claim and the token request's `resource` indicators. Authority relies on this metadata to enforce DPoP nonce challenges for `signer`, `attestor`, and other high-value services without requiring clients to repeat the audience parameter on every request.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 11) Integration hard lines (what resource servers must enforce)
|
## 11) Integration hard lines (what resource servers must enforce)
|
||||||
|
|
||||||
Every Stella Ops service that consumes Authority tokens **must**:
|
Every Stella Ops service that consumes Authority tokens **must**:
|
||||||
|
|
||||||
1. Verify JWT signature (`kid` in JWKS), `iss`, `aud`, `exp`, `nbf`.
|
1. Verify JWT signature (`kid` in JWKS), `iss`, `aud`, `exp`, `nbf`.
|
||||||
2. Enforce **sender‑constraint**:
|
2. Enforce **sender‑constraint**:
|
||||||
|
|
||||||
* **DPoP**: validate DPoP proof (`htu`, `htm`, `iat`, `jti`) and match `cnf.jkt`; cache `jti` for replay defense; honor nonce challenges.
|
* **DPoP**: validate DPoP proof (`htu`, `htm`, `iat`, `jti`) and match `cnf.jkt`; cache `jti` for replay defense; honor nonce challenges.
|
||||||
* **mTLS**: match presented client cert thumbprint to token `cnf.x5t#S256`.
|
* **mTLS**: match presented client cert thumbprint to token `cnf.x5t#S256`.
|
||||||
3. Check **scopes**; optionally map to internal roles.
|
3. Check **scopes**; optionally map to internal roles.
|
||||||
4. Check **tenant** (`tid`) and **installation** (`inst`) as appropriate.
|
4. Check **tenant** (`tid`) and **installation** (`inst`) as appropriate.
|
||||||
5. For **Signer** only: require **both** OpTok and **PoE** in the request (enforced by Signer, not Authority).
|
5. For **Signer** only: require **both** OpTok and **PoE** in the request (enforced by Signer, not Authority).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 12) Error surfaces & UX
|
## 12) Error surfaces & UX
|
||||||
|
|
||||||
* Token endpoint errors follow OAuth2 (`invalid_client`, `invalid_grant`, `invalid_scope`, `unauthorized_client`).
|
* Token endpoint errors follow OAuth2 (`invalid_client`, `invalid_grant`, `invalid_scope`, `unauthorized_client`).
|
||||||
* Resource servers use RFC 6750 style (`WWW-Authenticate: DPoP error="invalid_token", error_description="…", dpop_nonce="…" `).
|
* Resource servers use RFC 6750 style (`WWW-Authenticate: DPoP error="invalid_token", error_description="…", dpop_nonce="…" `).
|
||||||
* For DPoP nonce challenges, clients retry with the server‑supplied nonce once.
|
* For DPoP nonce challenges, clients retry with the server‑supplied nonce once.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 13) Observability & audit
|
## 13) Observability & audit
|
||||||
|
|
||||||
* **Metrics**:
|
* **Metrics**:
|
||||||
|
|
||||||
* `authority.tokens_issued_total{grant,aud}`
|
* `authority.tokens_issued_total{grant,aud}`
|
||||||
* `authority.dpop_validations_total{result}`
|
* `authority.dpop_validations_total{result}`
|
||||||
* `authority.mtls_bindings_total{result}`
|
* `authority.mtls_bindings_total{result}`
|
||||||
* `authority.jwks_rotations_total`
|
* `authority.jwks_rotations_total`
|
||||||
* `authority.errors_total{type}`
|
* `authority.errors_total{type}`
|
||||||
* **Audit log** (immutable sink): token issuance (`sub`, `aud`, `scopes`, `tid`, `inst`, `cnf thumbprint`, `jti`), revocations, admin changes.
|
* **Audit log** (immutable sink): token issuance (`sub`, `aud`, `scopes`, `tid`, `inst`, `cnf thumbprint`, `jti`), revocations, admin changes.
|
||||||
* **Tracing**: token flows, DB reads, JWKS cache.
|
* **Tracing**: token flows, DB reads, JWKS cache.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 14) Configuration (YAML)
|
## 14) Configuration (YAML)
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
authority:
|
authority:
|
||||||
issuer: "https://authority.internal"
|
issuer: "https://authority.internal"
|
||||||
signing:
|
signing:
|
||||||
enabled: true
|
enabled: true
|
||||||
activeKeyId: "authority-signing-2025"
|
activeKeyId: "authority-signing-2025"
|
||||||
keyPath: "../certificates/authority-signing-2025.pem"
|
keyPath: "../certificates/authority-signing-2025.pem"
|
||||||
algorithm: "ES256"
|
algorithm: "ES256"
|
||||||
keySource: "file"
|
keySource: "file"
|
||||||
security:
|
security:
|
||||||
rateLimiting:
|
rateLimiting:
|
||||||
token:
|
token:
|
||||||
enabled: true
|
enabled: true
|
||||||
permitLimit: 30
|
permitLimit: 30
|
||||||
window: "00:01:00"
|
window: "00:01:00"
|
||||||
queueLimit: 0
|
queueLimit: 0
|
||||||
authorize:
|
authorize:
|
||||||
enabled: true
|
enabled: true
|
||||||
permitLimit: 60
|
permitLimit: 60
|
||||||
window: "00:01:00"
|
window: "00:01:00"
|
||||||
queueLimit: 10
|
queueLimit: 10
|
||||||
internal:
|
internal:
|
||||||
enabled: false
|
enabled: false
|
||||||
permitLimit: 5
|
permitLimit: 5
|
||||||
window: "00:01:00"
|
window: "00:01:00"
|
||||||
queueLimit: 0
|
queueLimit: 0
|
||||||
senderConstraints:
|
senderConstraints:
|
||||||
dpop:
|
dpop:
|
||||||
enabled: true
|
enabled: true
|
||||||
allowedAlgorithms: [ "ES256", "ES384" ]
|
allowedAlgorithms: [ "ES256", "ES384" ]
|
||||||
proofLifetime: "00:02:00"
|
proofLifetime: "00:02:00"
|
||||||
allowedClockSkew: "00:00:30"
|
allowedClockSkew: "00:00:30"
|
||||||
replayWindow: "00:05:00"
|
replayWindow: "00:05:00"
|
||||||
nonce:
|
nonce:
|
||||||
enabled: true
|
enabled: true
|
||||||
ttl: "00:10:00"
|
ttl: "00:10:00"
|
||||||
maxIssuancePerMinute: 120
|
maxIssuancePerMinute: 120
|
||||||
store: "redis"
|
store: "redis"
|
||||||
redisConnectionString: "redis://authority-redis:6379?ssl=false"
|
redisConnectionString: "redis://authority-redis:6379?ssl=false"
|
||||||
requiredAudiences:
|
requiredAudiences:
|
||||||
- "signer"
|
- "signer"
|
||||||
- "attestor"
|
- "attestor"
|
||||||
mtls:
|
mtls:
|
||||||
enabled: true
|
enabled: true
|
||||||
requireChainValidation: true
|
requireChainValidation: true
|
||||||
rotationGrace: "00:15:00"
|
rotationGrace: "00:15:00"
|
||||||
enforceForAudiences:
|
enforceForAudiences:
|
||||||
- "signer"
|
- "signer"
|
||||||
allowedSanTypes:
|
allowedSanTypes:
|
||||||
- "dns"
|
- "dns"
|
||||||
- "uri"
|
- "uri"
|
||||||
allowedCertificateAuthorities:
|
allowedCertificateAuthorities:
|
||||||
- "/etc/ssl/mtls/clients-ca.pem"
|
- "/etc/ssl/mtls/clients-ca.pem"
|
||||||
clients:
|
clients:
|
||||||
- clientId: scanner-web
|
- clientId: scanner-web
|
||||||
grantTypes: [ "client_credentials" ]
|
grantTypes: [ "client_credentials" ]
|
||||||
audiences: [ "scanner" ]
|
audiences: [ "scanner" ]
|
||||||
auth: { type: "private_key_jwt", jwkFile: "/secrets/scanner-web.jwk" }
|
auth: { type: "private_key_jwt", jwkFile: "/secrets/scanner-web.jwk" }
|
||||||
senderConstraint: "dpop"
|
senderConstraint: "dpop"
|
||||||
scopes: [ "scanner.scan", "scanner.export", "scanner.read" ]
|
scopes: [ "scanner.scan", "scanner.export", "scanner.read" ]
|
||||||
- clientId: signer
|
- clientId: signer
|
||||||
grantTypes: [ "client_credentials" ]
|
grantTypes: [ "client_credentials" ]
|
||||||
audiences: [ "signer" ]
|
audiences: [ "signer" ]
|
||||||
auth: { type: "mtls" }
|
auth: { type: "mtls" }
|
||||||
senderConstraint: "mtls"
|
senderConstraint: "mtls"
|
||||||
scopes: [ "signer.sign" ]
|
scopes: [ "signer.sign" ]
|
||||||
- clientId: notify-web-dev
|
- clientId: notify-web-dev
|
||||||
grantTypes: [ "client_credentials" ]
|
grantTypes: [ "client_credentials" ]
|
||||||
audiences: [ "notify.dev" ]
|
audiences: [ "notify.dev" ]
|
||||||
auth: { type: "client_secret", secretFile: "/secrets/notify-web-dev.secret" }
|
auth: { type: "client_secret", secretFile: "/secrets/notify-web-dev.secret" }
|
||||||
senderConstraint: "dpop"
|
senderConstraint: "dpop"
|
||||||
scopes: [ "notify.read", "notify.admin" ]
|
scopes: [ "notify.read", "notify.admin" ]
|
||||||
- clientId: notify-web
|
- clientId: notify-web
|
||||||
grantTypes: [ "client_credentials" ]
|
grantTypes: [ "client_credentials" ]
|
||||||
audiences: [ "notify" ]
|
audiences: [ "notify" ]
|
||||||
auth: { type: "client_secret", secretFile: "/secrets/notify-web.secret" }
|
auth: { type: "client_secret", secretFile: "/secrets/notify-web.secret" }
|
||||||
senderConstraint: "dpop"
|
senderConstraint: "dpop"
|
||||||
scopes: [ "notify.read", "notify.admin" ]
|
scopes: [ "notify.read", "notify.admin" ]
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 15) Testing matrix
|
## 15) Testing matrix
|
||||||
|
|
||||||
* **JWT validation**: wrong `aud`, expired `exp`, skewed `nbf`, stale `kid`.
|
* **JWT validation**: wrong `aud`, expired `exp`, skewed `nbf`, stale `kid`.
|
||||||
* **DPoP**: invalid `htu`/`htm`, replayed `jti`, stale `iat`, wrong `jkt`, nonce dance.
|
* **DPoP**: invalid `htu`/`htm`, replayed `jti`, stale `iat`, wrong `jkt`, nonce dance.
|
||||||
* **mTLS**: wrong client cert, wrong CA, thumbprint mismatch.
|
* **mTLS**: wrong client cert, wrong CA, thumbprint mismatch.
|
||||||
* **RBAC**: scope enforcement per audience; over‑privileged client denied.
|
* **RBAC**: scope enforcement per audience; over‑privileged client denied.
|
||||||
* **Rotation**: JWKS rotation while load‑testing; zero‑downtime verification.
|
* **Rotation**: JWKS rotation while load‑testing; zero‑downtime verification.
|
||||||
* **HA**: kill one Authority instance; verify issuance continues; JWKS served by peers.
|
* **HA**: kill one Authority instance; verify issuance continues; JWKS served by peers.
|
||||||
* **Performance**: 1k token issuance/sec on 2 cores with Redis enabled for jti caching.
|
* **Performance**: 1k token issuance/sec on 2 cores with Redis enabled for jti caching.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 16) Threat model & mitigations (summary)
|
## 16) Threat model & mitigations (summary)
|
||||||
|
|
||||||
| Threat | Vector | Mitigation |
|
| Threat | Vector | Mitigation |
|
||||||
| ------------------- | ---------------- | ------------------------------------------------------------------------------------------ |
|
| ------------------- | ---------------- | ------------------------------------------------------------------------------------------ |
|
||||||
| Token theft | Copy of JWT | **Short TTL**, **sender‑constraint** (DPoP/mTLS); replay blocked by `jti` cache and nonces |
|
| Token theft | Copy of JWT | **Short TTL**, **sender‑constraint** (DPoP/mTLS); replay blocked by `jti` cache and nonces |
|
||||||
| Replay across hosts | Reuse DPoP proof | Enforce `htu`/`htm`, `iat` freshness, `jti` uniqueness; services may require **nonce** |
|
| Replay across hosts | Reuse DPoP proof | Enforce `htu`/`htm`, `iat` freshness, `jti` uniqueness; services may require **nonce** |
|
||||||
| Impersonation | Fake client | mTLS or `private_key_jwt` with pinned JWK; client registration & rotation |
|
| Impersonation | Fake client | mTLS or `private_key_jwt` with pinned JWK; client registration & rotation |
|
||||||
| Key compromise | Signing key leak | HSM/KMS storage, key rotation, audit; emergency key revoke path; narrow token TTL |
|
| Key compromise | Signing key leak | HSM/KMS storage, key rotation, audit; emergency key revoke path; narrow token TTL |
|
||||||
| Cross‑tenant abuse | Scope elevation | Enforce `aud`, `tid`, `inst` at issuance and resource servers |
|
| Cross‑tenant abuse | Scope elevation | Enforce `aud`, `tid`, `inst` at issuance and resource servers |
|
||||||
| Downgrade to bearer | Strip DPoP | Resource servers require DPoP/mTLS based on `aud`; reject bearer without `cnf` |
|
| Downgrade to bearer | Strip DPoP | Resource servers require DPoP/mTLS based on `aud`; reject bearer without `cnf` |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 17) Deployment & HA
|
## 17) Deployment & HA
|
||||||
|
|
||||||
* **Stateless** microservice, containerized; run ≥ 2 replicas behind LB.
|
* **Stateless** microservice, containerized; run ≥ 2 replicas behind LB.
|
||||||
* **DB**: HA Postgres (or MySQL) for clients/roles; **Redis** for device codes, DPoP nonces/jtis.
|
* **DB**: HA Postgres (or MySQL) for clients/roles; **Redis** for device codes, DPoP nonces/jtis.
|
||||||
* **Secrets**: mount client JWKs via K8s Secrets/HashiCorp Vault; signing keys via KMS.
|
* **Secrets**: mount client JWKs via K8s Secrets/HashiCorp Vault; signing keys via KMS.
|
||||||
* **Backups**: DB daily; Redis not critical (ephemeral).
|
* **Backups**: DB daily; Redis not critical (ephemeral).
|
||||||
* **Disaster recovery**: export/import of client registry; JWKS rehydrate from KMS.
|
* **Disaster recovery**: export/import of client registry; JWKS rehydrate from KMS.
|
||||||
* **Compliance**: TLS audit; penetration testing for OIDC flows.
|
* **Compliance**: TLS audit; penetration testing for OIDC flows.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 18) Implementation notes
|
## 18) Implementation notes
|
||||||
|
|
||||||
* Reference stack: **.NET 10** + **OpenIddict 6** (or IdentityServer if licensed) with custom DPoP validator and mTLS binding middleware.
|
* Reference stack: **.NET 10** + **OpenIddict 6** (or IdentityServer if licensed) with custom DPoP validator and mTLS binding middleware.
|
||||||
* Keep the DPoP/JTI cache pluggable; allow Redis/Memcached.
|
* Keep the DPoP/JTI cache pluggable; allow Redis/Memcached.
|
||||||
* Provide **client SDKs** for C# and Go: DPoP key mgmt, proof generation, nonce handling, token refresh helper.
|
* Provide **client SDKs** for C# and Go: DPoP key mgmt, proof generation, nonce handling, token refresh helper.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 19) Quick reference — wire examples
|
## 19) Quick reference — wire examples
|
||||||
|
|
||||||
**Access token (payload excerpt)**
|
**Access token (payload excerpt)**
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"iss": "https://authority.internal",
|
"iss": "https://authority.internal",
|
||||||
"sub": "scanner-web",
|
"sub": "scanner-web",
|
||||||
"aud": "signer",
|
"aud": "signer",
|
||||||
"exp": 1760668800,
|
"exp": 1760668800,
|
||||||
"iat": 1760668620,
|
"iat": 1760668620,
|
||||||
"nbf": 1760668620,
|
"nbf": 1760668620,
|
||||||
"jti": "9d9c3f01-6e1a-49f1-8f77-9b7e6f7e3c50",
|
"jti": "9d9c3f01-6e1a-49f1-8f77-9b7e6f7e3c50",
|
||||||
"scope": "signer.sign",
|
"scope": "signer.sign",
|
||||||
"tid": "tenant-01",
|
"tid": "tenant-01",
|
||||||
"inst": "install-7A2B",
|
"inst": "install-7A2B",
|
||||||
"cnf": { "jkt": "KcVb2V...base64url..." }
|
"cnf": { "jkt": "KcVb2V...base64url..." }
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**DPoP proof header fields (for POST /sign/dsse)**
|
**DPoP proof header fields (for POST /sign/dsse)**
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"htu": "https://signer.internal/sign/dsse",
|
"htu": "https://signer.internal/sign/dsse",
|
||||||
"htm": "POST",
|
"htm": "POST",
|
||||||
"iat": 1760668620,
|
"iat": 1760668620,
|
||||||
"jti": "4b1c9b3c-8a95-4c58-8a92-9c6cfb4a6a0b"
|
"jti": "4b1c9b3c-8a95-4c58-8a92-9c6cfb4a6a0b"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Signer validates that `hash(JWK)` in the proof matches `cnf.jkt` in the token.
|
Signer validates that `hash(JWK)` in the proof matches `cnf.jkt` in the token.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 20) Rollout plan
|
## 20) Rollout plan
|
||||||
|
|
||||||
1. **MVP**: Client Credentials (private_key_jwt + DPoP), JWKS, short OpToks, per‑audience scopes.
|
1. **MVP**: Client Credentials (private_key_jwt + DPoP), JWKS, short OpToks, per‑audience scopes.
|
||||||
2. **Add**: mTLS‑bound tokens for Signer/Attestor; device code for CLI; optional introspection.
|
2. **Add**: mTLS‑bound tokens for Signer/Attestor; device code for CLI; optional introspection.
|
||||||
3. **Hardening**: DPoP nonce support; full audit pipeline; HA tuning.
|
3. **Hardening**: DPoP nonce support; full audit pipeline; HA tuning.
|
||||||
4. **UX**: Tenant/installation admin UI; role→scope editors; client bootstrap wizards.
|
4. **UX**: Tenant/installation admin UI; role→scope editors; client bootstrap wizards.
|
||||||
|
|||||||
@@ -1,406 +1,406 @@
|
|||||||
# component_architecture_cli.md — **Stella Ops CLI** (2025Q4)
|
# component_architecture_cli.md — **Stella Ops CLI** (2025Q4)
|
||||||
|
|
||||||
> **Scope.** Implementation‑ready architecture for **Stella Ops CLI**: command surface, process model, auth (Authority/DPoP), integration with Scanner/Excititor/Concelier/Signer/Attestor, Buildx plug‑in management, offline kit behavior, packaging, observability, security posture, and CI ergonomics.
|
> **Scope.** Implementation‑ready architecture for **Stella Ops CLI**: command surface, process model, auth (Authority/DPoP), integration with Scanner/Excititor/Concelier/Signer/Attestor, Buildx plug‑in management, offline kit behavior, packaging, observability, security posture, and CI ergonomics.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 0) Mission & boundaries
|
## 0) Mission & boundaries
|
||||||
|
|
||||||
**Mission.** Provide a **fast, deterministic, CI‑friendly** command‑line interface to drive Stella Ops workflows:
|
**Mission.** Provide a **fast, deterministic, CI‑friendly** command‑line interface to drive Stella Ops workflows:
|
||||||
|
|
||||||
* Build‑time SBOM generation via **Buildx generator** orchestration.
|
* Build‑time SBOM generation via **Buildx generator** orchestration.
|
||||||
* Post‑build **scan/compose/diff/export** against **Scanner.WebService**.
|
* Post‑build **scan/compose/diff/export** against **Scanner.WebService**.
|
||||||
* **Policy** operations and **VEX/Vuln** data pulls (operator tasks).
|
* **Policy** operations and **VEX/Vuln** data pulls (operator tasks).
|
||||||
* **Verification** (attestation, referrers, signatures) for audits.
|
* **Verification** (attestation, referrers, signatures) for audits.
|
||||||
* Air‑gapped/offline **kit** administration.
|
* Air‑gapped/offline **kit** administration.
|
||||||
|
|
||||||
**Boundaries.**
|
**Boundaries.**
|
||||||
|
|
||||||
* CLI **never** signs; it only calls **Signer**/**Attestor** via backend APIs when needed (e.g., `report --attest`).
|
* CLI **never** signs; it only calls **Signer**/**Attestor** via backend APIs when needed (e.g., `report --attest`).
|
||||||
* CLI **does not** store long‑lived credentials beyond OS keychain; tokens are **short** (Authority OpToks).
|
* CLI **does not** store long‑lived credentials beyond OS keychain; tokens are **short** (Authority OpToks).
|
||||||
* Heavy work (scanning, merging, policy) is executed **server‑side** (Scanner/Excititor/Concelier).
|
* Heavy work (scanning, merging, policy) is executed **server‑side** (Scanner/Excititor/Concelier).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 1) Solution layout & runtime form
|
## 1) Solution layout & runtime form
|
||||||
|
|
||||||
```
|
```
|
||||||
src/
|
src/
|
||||||
├─ StellaOps.Cli/ # net10.0 (Native AOT) single binary
|
├─ StellaOps.Cli/ # net10.0 (Native AOT) single binary
|
||||||
├─ StellaOps.Cli.Core/ # verb plumbing, config, HTTP, auth
|
├─ StellaOps.Cli.Core/ # verb plumbing, config, HTTP, auth
|
||||||
├─ StellaOps.Cli.Plugins/ # optional verbs packaged as plugins
|
├─ StellaOps.Cli.Plugins/ # optional verbs packaged as plugins
|
||||||
├─ StellaOps.Cli.Tests/ # unit + golden-output tests
|
├─ StellaOps.Cli.Tests/ # unit + golden-output tests
|
||||||
└─ packaging/
|
└─ packaging/
|
||||||
├─ msix / msi / deb / rpm / brew formula
|
├─ msix / msi / deb / rpm / brew formula
|
||||||
└─ scoop manifest / winget manifest
|
└─ scoop manifest / winget manifest
|
||||||
```
|
```
|
||||||
|
|
||||||
**Language/runtime**: .NET 10 **Native AOT** for speed/startup; Linux builds use **musl** static when possible.
|
**Language/runtime**: .NET 10 **Native AOT** for speed/startup; Linux builds use **musl** static when possible.
|
||||||
|
|
||||||
**Plug-in verbs.** Non-core verbs (Excititor, runtime helpers, future integrations) ship as restart-time plug-ins under `plugins/cli/**` with manifest descriptors. The launcher loads plug-ins on startup; hot reloading is intentionally unsupported. The inaugural bundle, `StellaOps.Cli.Plugins.NonCore`, packages the Excititor, runtime, and offline-kit command groups and publishes its manifest at `plugins/cli/StellaOps.Cli.Plugins.NonCore/`.
|
**Plug-in verbs.** Non-core verbs (Excititor, runtime helpers, future integrations) ship as restart-time plug-ins under `plugins/cli/**` with manifest descriptors. The launcher loads plug-ins on startup; hot reloading is intentionally unsupported. The inaugural bundle, `StellaOps.Cli.Plugins.NonCore`, packages the Excititor, runtime, and offline-kit command groups and publishes its manifest at `plugins/cli/StellaOps.Cli.Plugins.NonCore/`.
|
||||||
|
|
||||||
**OS targets**: linux‑x64/arm64, windows‑x64/arm64, macOS‑x64/arm64.
|
**OS targets**: linux‑x64/arm64, windows‑x64/arm64, macOS‑x64/arm64.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 2) Command surface (verbs)
|
## 2) Command surface (verbs)
|
||||||
|
|
||||||
> All verbs default to **JSON** output when `--json` is set (CI mode). Human output is concise, deterministic.
|
> All verbs default to **JSON** output when `--json` is set (CI mode). Human output is concise, deterministic.
|
||||||
|
|
||||||
### 2.1 Auth & profile
|
### 2.1 Auth & profile
|
||||||
|
|
||||||
* `auth login`
|
* `auth login`
|
||||||
|
|
||||||
* Modes: **device‑code** (default), **client‑credentials** (service principal).
|
* Modes: **device‑code** (default), **client‑credentials** (service principal).
|
||||||
* Produces **Authority** access token (OpTok) + stores **DPoP** keypair in OS keychain.
|
* Produces **Authority** access token (OpTok) + stores **DPoP** keypair in OS keychain.
|
||||||
* `auth status` — show current issuer, subject, audiences, expiry.
|
* `auth status` — show current issuer, subject, audiences, expiry.
|
||||||
* `auth logout` — wipe cached tokens/keys.
|
* `auth logout` — wipe cached tokens/keys.
|
||||||
|
|
||||||
### 2.2 Build‑time SBOM (Buildx)
|
### 2.2 Build‑time SBOM (Buildx)
|
||||||
|
|
||||||
* `buildx install` — install/update the **StellaOps.Scanner.Sbomer.BuildXPlugin** on the host.
|
* `buildx install` — install/update the **StellaOps.Scanner.Sbomer.BuildXPlugin** on the host.
|
||||||
* `buildx verify` — ensure generator is usable.
|
* `buildx verify` — ensure generator is usable.
|
||||||
* `buildx build` — thin wrapper around `docker buildx build --attest=type=sbom,generator=stellaops/sbom-indexer` with convenience flags:
|
* `buildx build` — thin wrapper around `docker buildx build --attest=type=sbom,generator=stellaops/sbom-indexer` with convenience flags:
|
||||||
|
|
||||||
* `--attest` (request Signer/Attestor via backend post‑push)
|
* `--attest` (request Signer/Attestor via backend post‑push)
|
||||||
* `--provenance` pass‑through (optional)
|
* `--provenance` pass‑through (optional)
|
||||||
|
|
||||||
### 2.3 Scanning & artifacts
|
### 2.3 Scanning & artifacts
|
||||||
|
|
||||||
* `scan image <ref|digest>`
|
* `scan image <ref|digest>`
|
||||||
|
|
||||||
* Options: `--force`, `--wait`, `--view=inventory|usage|both`, `--format=cdx-json|cdx-pb|spdx-json`, `--attest` (ask backend to sign/log).
|
* Options: `--force`, `--wait`, `--view=inventory|usage|both`, `--format=cdx-json|cdx-pb|spdx-json`, `--attest` (ask backend to sign/log).
|
||||||
* Streams progress; exits early unless `--wait`.
|
* Streams progress; exits early unless `--wait`.
|
||||||
* `diff image --old <digest> --new <digest> [--view ...]` — show layer‑attributed changes.
|
* `diff image --old <digest> --new <digest> [--view ...]` — show layer‑attributed changes.
|
||||||
* `export sbom <digest> [--view ... --format ... --out file]` — download artifact.
|
* `export sbom <digest> [--view ... --format ... --out file]` — download artifact.
|
||||||
* `report final <digest> [--policy-revision ... --attest]` — request PASS/FAIL report from backend (policy+vex) and optional attestation.
|
* `report final <digest> [--policy-revision ... --attest]` — request PASS/FAIL report from backend (policy+vex) and optional attestation.
|
||||||
|
|
||||||
### 2.4 Policy & data
|
### 2.4 Policy & data
|
||||||
|
|
||||||
* `policy get/set/apply` — fetch active policy, apply staged policy, compute digest.
|
* `policy get/set/apply` — fetch active policy, apply staged policy, compute digest.
|
||||||
* `concelier export` — trigger/export canonical JSON or Trivy DB (admin).
|
* `concelier export` — trigger/export canonical JSON or Trivy DB (admin).
|
||||||
* `excititor export` — trigger/export consensus/raw claims (admin).
|
* `excititor export` — trigger/export consensus/raw claims (admin).
|
||||||
|
|
||||||
### 2.5 Verification
|
### 2.5 Verification
|
||||||
|
|
||||||
* `verify attestation --uuid <rekor-uuid> | --artifact <sha256> | --bundle <path>` — call **Attestor /verify** and print proof summary.
|
* `verify attestation --uuid <rekor-uuid> | --artifact <sha256> | --bundle <path>` — call **Attestor /verify** and print proof summary.
|
||||||
* `verify referrers <digest>` — ask **Signer /verify/referrers** (is image Stella‑signed?).
|
* `verify referrers <digest>` — ask **Signer /verify/referrers** (is image Stella‑signed?).
|
||||||
* `verify image-signature <ref|digest>` — standalone cosign verification (optional, local).
|
* `verify image-signature <ref|digest>` — standalone cosign verification (optional, local).
|
||||||
|
|
||||||
### 2.6 Runtime (Zastava helper)
|
### 2.6 Runtime (Zastava helper)
|
||||||
|
|
||||||
* `runtime policy test --image/-i <digest> [--file <path> --ns <name> --label key=value --json]` — ask backend `/policy/runtime` like the webhook would (accepts multiple `--image`, comma/space lists, or stdin pipelines).
|
* `runtime policy test --image/-i <digest> [--file <path> --ns <name> --label key=value --json]` — ask backend `/policy/runtime` like the webhook would (accepts multiple `--image`, comma/space lists, or stdin pipelines).
|
||||||
|
|
||||||
### 2.7 Offline kit
|
### 2.7 Offline kit
|
||||||
|
|
||||||
* `offline kit pull` — fetch latest **Concelier JSON + Trivy DB + Excititor exports** as a tarball from a mirror.
|
* `offline kit pull` — fetch latest **Concelier JSON + Trivy DB + Excititor exports** as a tarball from a mirror.
|
||||||
* `offline kit import <tar>` — upload the kit to on‑prem services (Concelier/Excititor).
|
* `offline kit import <tar>` — upload the kit to on‑prem services (Concelier/Excititor).
|
||||||
* `offline kit status` — list current seed versions.
|
* `offline kit status` — list current seed versions.
|
||||||
|
|
||||||
### 2.8 Utilities
|
### 2.8 Utilities
|
||||||
|
|
||||||
* `config set/get` — endpoint & defaults.
|
* `config set/get` — endpoint & defaults.
|
||||||
* `whoami` — short auth display.
|
* `whoami` — short auth display.
|
||||||
* `version` — CLI + protocol versions; release channel.
|
* `version` — CLI + protocol versions; release channel.
|
||||||
|
|
||||||
### 2.9 Aggregation-only guard helpers
|
### 2.9 Aggregation-only guard helpers
|
||||||
|
|
||||||
* `sources ingest --dry-run --source <id> --input <path|uri> [--tenant ... --format table|json --output file]`
|
* `sources ingest --dry-run --source <id> --input <path|uri> [--tenant ... --format table|json --output file]`
|
||||||
|
|
||||||
* Normalises documents (handles gzip/base64), posts them to the backend `aoc/ingest/dry-run` route, and exits non-zero when guard violations are detected.
|
* Normalises documents (handles gzip/base64), posts them to the backend `aoc/ingest/dry-run` route, and exits non-zero when guard violations are detected.
|
||||||
* Defaults to table output with ANSI colour; `--json`/`--output` produce deterministic JSON for CI pipelines.
|
* Defaults to table output with ANSI colour; `--json`/`--output` produce deterministic JSON for CI pipelines.
|
||||||
|
|
||||||
* `aoc verify [--since <ISO8601|duration>] [--limit <count>] [--sources list] [--codes list] [--format table|json] [--export file] [--tenant id] [--no-color]`
|
* `aoc verify [--since <ISO8601|duration>] [--limit <count>] [--sources list] [--codes list] [--format table|json] [--export file] [--tenant id] [--no-color]`
|
||||||
|
|
||||||
* Replays guard checks against stored raw documents. Maps backend `ERR_AOC_00x` codes onto deterministic exit codes so CI can block regressions.
|
* Replays guard checks against stored raw documents. Maps backend `ERR_AOC_00x` codes onto deterministic exit codes so CI can block regressions.
|
||||||
* Supports pagination hints (`--limit`, `--since`), tenant scoping via `--tenant` or `STELLA_TENANT`, and JSON exports for evidence lockers.
|
* Supports pagination hints (`--limit`, `--since`), tenant scoping via `--tenant` or `STELLA_TENANT`, and JSON exports for evidence lockers.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 3) AuthN: Authority + DPoP
|
## 3) AuthN: Authority + DPoP
|
||||||
|
|
||||||
### 3.1 Token acquisition
|
### 3.1 Token acquisition
|
||||||
|
|
||||||
* **Device‑code**: the CLI opens an OIDC device code flow against **Authority**; the browser login is optional for service principals.
|
* **Device‑code**: the CLI opens an OIDC device code flow against **Authority**; the browser login is optional for service principals.
|
||||||
* **Client‑credentials**: service principals use **private_key_jwt** or **mTLS** to get tokens.
|
* **Client‑credentials**: service principals use **private_key_jwt** or **mTLS** to get tokens.
|
||||||
|
|
||||||
### 3.2 DPoP key management
|
### 3.2 DPoP key management
|
||||||
|
|
||||||
* On first login, the CLI generates an **ephemeral JWK** (Ed25519) and stores it in the **OS keychain** (Keychain/DPAPI/KWallet/Gnome Keyring).
|
* On first login, the CLI generates an **ephemeral JWK** (Ed25519) and stores it in the **OS keychain** (Keychain/DPAPI/KWallet/Gnome Keyring).
|
||||||
* Every request to backend services includes a **DPoP proof**; CLI refreshes tokens as needed.
|
* Every request to backend services includes a **DPoP proof**; CLI refreshes tokens as needed.
|
||||||
|
|
||||||
### 3.3 Multi‑audience & scopes
|
### 3.3 Multi‑audience & scopes
|
||||||
|
|
||||||
* CLI requests **audiences** as needed per verb:
|
* CLI requests **audiences** as needed per verb:
|
||||||
|
|
||||||
* `scanner` for scan/export/report/diff
|
* `scanner` for scan/export/report/diff
|
||||||
* `signer` (indirect; usually backend calls Signer)
|
* `signer` (indirect; usually backend calls Signer)
|
||||||
* `attestor` for verify
|
* `attestor` for verify
|
||||||
* `concelier`/`excititor` for admin verbs
|
* `concelier`/`excititor` for admin verbs
|
||||||
|
|
||||||
CLI rejects verbs if required scopes are missing.
|
CLI rejects verbs if required scopes are missing.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 4) Process model & reliability
|
## 4) Process model & reliability
|
||||||
|
|
||||||
### 4.1 HTTP client
|
### 4.1 HTTP client
|
||||||
|
|
||||||
* Single **http2** client with connection pooling, DNS pinning, retry/backoff (idempotent GET/POST marked safe).
|
* Single **http2** client with connection pooling, DNS pinning, retry/backoff (idempotent GET/POST marked safe).
|
||||||
* **DPoP nonce** handling: on `401` with nonce challenge, CLI replays once.
|
* **DPoP nonce** handling: on `401` with nonce challenge, CLI replays once.
|
||||||
|
|
||||||
### 4.2 Streaming
|
### 4.2 Streaming
|
||||||
|
|
||||||
* `scan` and `report` support **server‑sent JSON lines** (progress events).
|
* `scan` and `report` support **server‑sent JSON lines** (progress events).
|
||||||
* `--json` prints machine events; human mode shows compact spinners and crucial updates only.
|
* `--json` prints machine events; human mode shows compact spinners and crucial updates only.
|
||||||
|
|
||||||
### 4.3 Exit codes (CI‑safe)
|
### 4.3 Exit codes (CI‑safe)
|
||||||
|
|
||||||
| Code | Meaning |
|
| Code | Meaning |
|
||||||
| ---- | ------------------------------------------- |
|
| ---- | ------------------------------------------- |
|
||||||
| 0 | Success |
|
| 0 | Success |
|
||||||
| 2 | Policy fail (final report verdict=fail) |
|
| 2 | Policy fail (final report verdict=fail) |
|
||||||
| 3 | Verification failed (attestation/signature) |
|
| 3 | Verification failed (attestation/signature) |
|
||||||
| 4 | Auth error (invalid/missing token/DPoP) |
|
| 4 | Auth error (invalid/missing token/DPoP) |
|
||||||
| 5 | Resource not found (image/SBOM) |
|
| 5 | Resource not found (image/SBOM) |
|
||||||
| 6 | Rate limited / quota exceeded |
|
| 6 | Rate limited / quota exceeded |
|
||||||
| 7 | Backend unavailable (retryable) |
|
| 7 | Backend unavailable (retryable) |
|
||||||
| 9 | Invalid arguments |
|
| 9 | Invalid arguments |
|
||||||
| 11–17 | Aggregation-only guard violation (`ERR_AOC_00x`) |
|
| 11–17 | Aggregation-only guard violation (`ERR_AOC_00x`) |
|
||||||
| 18 | Verification truncated (increase `--limit`) |
|
| 18 | Verification truncated (increase `--limit`) |
|
||||||
| 70 | Transport/authentication failure |
|
| 70 | Transport/authentication failure |
|
||||||
| 71 | CLI usage error (missing tenant, invalid cursor) |
|
| 71 | CLI usage error (missing tenant, invalid cursor) |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 5) Configuration model
|
## 5) Configuration model
|
||||||
|
|
||||||
**Precedence:** CLI flags → env vars → config file → defaults.
|
**Precedence:** CLI flags → env vars → config file → defaults.
|
||||||
|
|
||||||
**Config file**: `${XDG_CONFIG_HOME}/stellaops/config.yaml` (Windows: `%APPDATA%\StellaOps\config.yaml`)
|
**Config file**: `${XDG_CONFIG_HOME}/stellaops/config.yaml` (Windows: `%APPDATA%\StellaOps\config.yaml`)
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
cli:
|
cli:
|
||||||
authority: "https://authority.internal"
|
authority: "https://authority.internal"
|
||||||
backend:
|
backend:
|
||||||
scanner: "https://scanner-web.internal"
|
scanner: "https://scanner-web.internal"
|
||||||
attestor: "https://attestor.internal"
|
attestor: "https://attestor.internal"
|
||||||
concelier: "https://concelier-web.internal"
|
concelier: "https://concelier-web.internal"
|
||||||
excititor: "https://excititor-web.internal"
|
excititor: "https://excititor-web.internal"
|
||||||
auth:
|
auth:
|
||||||
audienceDefault: "scanner"
|
audienceDefault: "scanner"
|
||||||
deviceCode: true
|
deviceCode: true
|
||||||
output:
|
output:
|
||||||
json: false
|
json: false
|
||||||
color: auto
|
color: auto
|
||||||
tls:
|
tls:
|
||||||
caBundle: "/etc/ssl/certs/ca-bundle.crt"
|
caBundle: "/etc/ssl/certs/ca-bundle.crt"
|
||||||
offline:
|
offline:
|
||||||
kitMirror: "s3://mirror/stellaops-kit"
|
kitMirror: "s3://mirror/stellaops-kit"
|
||||||
```
|
```
|
||||||
|
|
||||||
Environment variables: `STELLAOPS_AUTHORITY`, `STELLAOPS_SCANNER_URL`, etc.
|
Environment variables: `STELLAOPS_AUTHORITY`, `STELLAOPS_SCANNER_URL`, etc.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 6) Buildx generator orchestration
|
## 6) Buildx generator orchestration
|
||||||
|
|
||||||
* `buildx install` locates the Docker root directory, writes the **generator** plugin manifest, and pulls `stellaops/sbom-indexer` image (pinned digest).
|
* `buildx install` locates the Docker root directory, writes the **generator** plugin manifest, and pulls `stellaops/sbom-indexer` image (pinned digest).
|
||||||
* `buildx build` wrapper injects:
|
* `buildx build` wrapper injects:
|
||||||
|
|
||||||
* `--attest=type=sbom,generator=stellaops/sbom-indexer`
|
* `--attest=type=sbom,generator=stellaops/sbom-indexer`
|
||||||
* `--label org.stellaops.request=sbom`
|
* `--label org.stellaops.request=sbom`
|
||||||
* Post‑build: CLI optionally calls **Scanner.WebService** to **verify referrers**, **compose** image SBOMs, and **attest** via Signer/Attestor.
|
* Post‑build: CLI optionally calls **Scanner.WebService** to **verify referrers**, **compose** image SBOMs, and **attest** via Signer/Attestor.
|
||||||
|
|
||||||
**Detection**: If Buildx or generator unavailable, CLI falls back to **post‑build scan** with a warning.
|
**Detection**: If Buildx or generator unavailable, CLI falls back to **post‑build scan** with a warning.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 7) Artifact handling
|
## 7) Artifact handling
|
||||||
|
|
||||||
* **Downloads** (`export sbom`, `report final`): stream to file; compute sha256 on the fly; write sidecar `.sha256` and optional **verification bundle** (if `--bundle`).
|
* **Downloads** (`export sbom`, `report final`): stream to file; compute sha256 on the fly; write sidecar `.sha256` and optional **verification bundle** (if `--bundle`).
|
||||||
* **Uploads** (`offline kit import`): chunked upload; retry on transient errors; show progress bar (unless `--json`).
|
* **Uploads** (`offline kit import`): chunked upload; retry on transient errors; show progress bar (unless `--json`).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 8) Security posture
|
## 8) Security posture
|
||||||
|
|
||||||
* **DPoP private keys** stored in **OS keychain**; metadata cached in config.
|
* **DPoP private keys** stored in **OS keychain**; metadata cached in config.
|
||||||
* **No plaintext tokens** on disk; short‑lived **OpToks** held in memory.
|
* **No plaintext tokens** on disk; short‑lived **OpToks** held in memory.
|
||||||
* **TLS**: verify backend certificates; allow custom CA bundle for on‑prem.
|
* **TLS**: verify backend certificates; allow custom CA bundle for on‑prem.
|
||||||
* **Redaction**: CLI logs remove `Authorization`, DPoP headers, PoE tokens.
|
* **Redaction**: CLI logs remove `Authorization`, DPoP headers, PoE tokens.
|
||||||
* **Supply chain**: CLI distribution binaries are **cosign‑signed**; `stellaops version --verify` checks its own signature.
|
* **Supply chain**: CLI distribution binaries are **cosign‑signed**; `stellaops version --verify` checks its own signature.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 9) Observability
|
## 9) Observability
|
||||||
|
|
||||||
* `--verbose` adds request IDs, timings, and retry traces.
|
* `--verbose` adds request IDs, timings, and retry traces.
|
||||||
* **Metrics** (optional, disabled by default): Prometheus text file exporter for local monitoring in long‑running agents.
|
* **Metrics** (optional, disabled by default): Prometheus text file exporter for local monitoring in long‑running agents.
|
||||||
* **Structured logs** (`--json`): per‑event JSON lines with `ts`, `verb`, `status`, `latencyMs`.
|
* **Structured logs** (`--json`): per‑event JSON lines with `ts`, `verb`, `status`, `latencyMs`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 10) Performance targets
|
## 10) Performance targets
|
||||||
|
|
||||||
* Startup ≤ **20 ms** (AOT).
|
* Startup ≤ **20 ms** (AOT).
|
||||||
* `scan image` request/response overhead ≤ **5 ms** (excluding server work).
|
* `scan image` request/response overhead ≤ **5 ms** (excluding server work).
|
||||||
* Buildx wrapper overhead negligible (<1 ms).
|
* Buildx wrapper overhead negligible (<1 ms).
|
||||||
* Large artifact download (100 MB) sustained ≥ **80 MB/s** on local networks.
|
* Large artifact download (100 MB) sustained ≥ **80 MB/s** on local networks.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 11) Tests & golden outputs
|
## 11) Tests & golden outputs
|
||||||
|
|
||||||
* **Unit tests**: argument parsing, config precedence, URL resolution, DPoP proof creation.
|
* **Unit tests**: argument parsing, config precedence, URL resolution, DPoP proof creation.
|
||||||
* **Integration tests** (Testcontainers): mock Authority/Scanner/Attestor; CI pipeline with fake registry.
|
* **Integration tests** (Testcontainers): mock Authority/Scanner/Attestor; CI pipeline with fake registry.
|
||||||
* **Golden outputs**: verb snapshots for `--json` across OSes; kept in `tests/golden/…`.
|
* **Golden outputs**: verb snapshots for `--json` across OSes; kept in `tests/golden/…`.
|
||||||
* **Contract tests**: ensure API shapes match service OpenAPI; fail build if incompatible.
|
* **Contract tests**: ensure API shapes match service OpenAPI; fail build if incompatible.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 12) Error envelopes (human + JSON)
|
## 12) Error envelopes (human + JSON)
|
||||||
|
|
||||||
**Human:**
|
**Human:**
|
||||||
|
|
||||||
```
|
```
|
||||||
✖ Policy FAIL: 3 high, 1 critical (VEX suppressed 12)
|
✖ Policy FAIL: 3 high, 1 critical (VEX suppressed 12)
|
||||||
- pkg:rpm/openssl (CVE-2025-12345) — affected (vendor) — fixed in 3.0.14
|
- pkg:rpm/openssl (CVE-2025-12345) — affected (vendor) — fixed in 3.0.14
|
||||||
- pkg:npm/lodash (GHSA-xxxx) — affected — no fix
|
- pkg:npm/lodash (GHSA-xxxx) — affected — no fix
|
||||||
See: https://ui.internal/scans/sha256:...
|
See: https://ui.internal/scans/sha256:...
|
||||||
Exit code: 2
|
Exit code: 2
|
||||||
```
|
```
|
||||||
|
|
||||||
**JSON (`--json`):**
|
**JSON (`--json`):**
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{ "event":"report", "status":"fail", "critical":1, "high":3, "url":"https://ui..." }
|
{ "event":"report", "status":"fail", "critical":1, "high":3, "url":"https://ui..." }
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 13) Admin & advanced flags
|
## 13) Admin & advanced flags
|
||||||
|
|
||||||
* `--authority`, `--scanner`, `--attestor`, `--concelier`, `--excititor` override config URLs.
|
* `--authority`, `--scanner`, `--attestor`, `--concelier`, `--excititor` override config URLs.
|
||||||
* `--no-color`, `--quiet`, `--json`.
|
* `--no-color`, `--quiet`, `--json`.
|
||||||
* `--timeout`, `--retries`, `--retry-backoff-ms`.
|
* `--timeout`, `--retries`, `--retry-backoff-ms`.
|
||||||
* `--ca-bundle`, `--insecure` (dev only; prints warning).
|
* `--ca-bundle`, `--insecure` (dev only; prints warning).
|
||||||
* `--trace` (dump HTTP traces to file; scrubbed).
|
* `--trace` (dump HTTP traces to file; scrubbed).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 14) Interop with other tools
|
## 14) Interop with other tools
|
||||||
|
|
||||||
* Emits **CycloneDX Protobuf** directly to stdout when `export sbom --format cdx-pb --out -`.
|
* Emits **CycloneDX Protobuf** directly to stdout when `export sbom --format cdx-pb --out -`.
|
||||||
* Pipes to `jq`/`yq` cleanly in JSON mode.
|
* Pipes to `jq`/`yq` cleanly in JSON mode.
|
||||||
* Can act as a **credential helper** for scripts: `stellaops auth token --aud scanner` prints a one‑shot token for curl.
|
* Can act as a **credential helper** for scripts: `stellaops auth token --aud scanner` prints a one‑shot token for curl.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 15) Packaging & distribution
|
## 15) Packaging & distribution
|
||||||
|
|
||||||
* **Installers**: deb/rpm (postinst registers completions), Homebrew, Scoop, Winget, MSI/MSIX.
|
* **Installers**: deb/rpm (postinst registers completions), Homebrew, Scoop, Winget, MSI/MSIX.
|
||||||
* **Shell completions**: bash/zsh/fish/pwsh.
|
* **Shell completions**: bash/zsh/fish/pwsh.
|
||||||
* **Update channel**: `stellaops self-update` (optional) fetches cosign‑signed release manifest; corporate environments can disable.
|
* **Update channel**: `stellaops self-update` (optional) fetches cosign‑signed release manifest; corporate environments can disable.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 16) Security hard lines
|
## 16) Security hard lines
|
||||||
|
|
||||||
* Refuse to print token values; redact Authorization headers in verbose output.
|
* Refuse to print token values; redact Authorization headers in verbose output.
|
||||||
* Disallow `--insecure` unless `STELLAOPS_CLI_ALLOW_INSECURE=1` set (double opt‑in).
|
* Disallow `--insecure` unless `STELLAOPS_CLI_ALLOW_INSECURE=1` set (double opt‑in).
|
||||||
* Enforce **short token TTL**; refresh proactively when <30 s left.
|
* Enforce **short token TTL**; refresh proactively when <30 s left.
|
||||||
* Device‑code cache binding to **machine** and **user** (protect against copy to other machines).
|
* Device‑code cache binding to **machine** and **user** (protect against copy to other machines).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 17) Wire sequences
|
## 17) Wire sequences
|
||||||
|
|
||||||
**A) Scan & wait with attestation**
|
**A) Scan & wait with attestation**
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
sequenceDiagram
|
sequenceDiagram
|
||||||
autonumber
|
autonumber
|
||||||
participant CLI
|
participant CLI
|
||||||
participant Auth as Authority
|
participant Auth as Authority
|
||||||
participant SW as Scanner.WebService
|
participant SW as Scanner.WebService
|
||||||
participant SG as Signer
|
participant SG as Signer
|
||||||
participant AT as Attestor
|
participant AT as Attestor
|
||||||
|
|
||||||
CLI->>Auth: device code flow (DPoP)
|
CLI->>Auth: device code flow (DPoP)
|
||||||
Auth-->>CLI: OpTok (aud=scanner)
|
Auth-->>CLI: OpTok (aud=scanner)
|
||||||
|
|
||||||
CLI->>SW: POST /scans { imageRef, attest:true }
|
CLI->>SW: POST /scans { imageRef, attest:true }
|
||||||
SW-->>CLI: { scanId }
|
SW-->>CLI: { scanId }
|
||||||
CLI->>SW: GET /scans/{id} (poll)
|
CLI->>SW: GET /scans/{id} (poll)
|
||||||
SW-->>CLI: { status: completed, artifacts, rekor? } # if attested
|
SW-->>CLI: { status: completed, artifacts, rekor? } # if attested
|
||||||
|
|
||||||
alt attestation pending
|
alt attestation pending
|
||||||
SW->>SG: POST /sign/dsse (server-side)
|
SW->>SG: POST /sign/dsse (server-side)
|
||||||
SG-->>SW: DSSE
|
SG-->>SW: DSSE
|
||||||
SW->>AT: POST /rekor/entries
|
SW->>AT: POST /rekor/entries
|
||||||
AT-->>SW: { uuid, proof }
|
AT-->>SW: { uuid, proof }
|
||||||
end
|
end
|
||||||
|
|
||||||
CLI->>SW: GET /sboms/<digest>?format=cdx-pb&view=usage
|
CLI->>SW: GET /sboms/<digest>?format=cdx-pb&view=usage
|
||||||
SW-->>CLI: bytes
|
SW-->>CLI: bytes
|
||||||
```
|
```
|
||||||
|
|
||||||
**B) Verify attestation by artifact**
|
**B) Verify attestation by artifact**
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
sequenceDiagram
|
sequenceDiagram
|
||||||
autonumber
|
autonumber
|
||||||
participant CLI
|
participant CLI
|
||||||
participant AT as Attestor
|
participant AT as Attestor
|
||||||
|
|
||||||
CLI->>AT: POST /rekor/verify { artifactSha256 }
|
CLI->>AT: POST /rekor/verify { artifactSha256 }
|
||||||
AT-->>CLI: { ok:true, uuid, index, logURL }
|
AT-->>CLI: { ok:true, uuid, index, logURL }
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 18) Roadmap (CLI)
|
## 18) Roadmap (CLI)
|
||||||
|
|
||||||
* `scan fs <path>` (local filesystem tree) → upload to backend for analysis.
|
* `scan fs <path>` (local filesystem tree) → upload to backend for analysis.
|
||||||
* `policy test --sbom <file>` (simulate policy results offline using local policy bundle).
|
* `policy test --sbom <file>` (simulate policy results offline using local policy bundle).
|
||||||
* `runtime capture` (developer mode) — capture small `/proc/<pid>/maps` for troubleshooting.
|
* `runtime capture` (developer mode) — capture small `/proc/<pid>/maps` for troubleshooting.
|
||||||
* Pluggable output renderers for SARIF/HTML (admin‑controlled).
|
* Pluggable output renderers for SARIF/HTML (admin‑controlled).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 19) Example CI snippets
|
## 19) Example CI snippets
|
||||||
|
|
||||||
**GitHub Actions (post‑build)**
|
**GitHub Actions (post‑build)**
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- name: Login (device code w/ OIDC broker)
|
- name: Login (device code w/ OIDC broker)
|
||||||
run: stellaops auth login --json --authority ${{ secrets.AUTHORITY_URL }}
|
run: stellaops auth login --json --authority ${{ secrets.AUTHORITY_URL }}
|
||||||
|
|
||||||
- name: Scan
|
- name: Scan
|
||||||
run: stellaops scan image ${{ steps.build.outputs.digest }} --wait --json
|
run: stellaops scan image ${{ steps.build.outputs.digest }} --wait --json
|
||||||
|
|
||||||
- name: Export (usage view, protobuf)
|
- name: Export (usage view, protobuf)
|
||||||
run: stellaops export sbom ${{ steps.build.outputs.digest }} --view usage --format cdx-pb --out sbom.pb
|
run: stellaops export sbom ${{ steps.build.outputs.digest }} --view usage --format cdx-pb --out sbom.pb
|
||||||
|
|
||||||
- name: Verify attestation
|
- name: Verify attestation
|
||||||
run: stellaops verify attestation --artifact $(sha256sum sbom.pb | cut -d' ' -f1) --json
|
run: stellaops verify attestation --artifact $(sha256sum sbom.pb | cut -d' ' -f1) --json
|
||||||
```
|
```
|
||||||
|
|
||||||
**GitLab (buildx generator)**
|
**GitLab (buildx generator)**
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
script:
|
script:
|
||||||
- stellaops buildx install
|
- stellaops buildx install
|
||||||
- docker buildx build --attest=type=sbom,generator=stellaops/sbom-indexer -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
|
- docker buildx build --attest=type=sbom,generator=stellaops/sbom-indexer -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
|
||||||
- stellaops scan image $CI_REGISTRY_IMAGE@$IMAGE_DIGEST --wait --json
|
- stellaops scan image $CI_REGISTRY_IMAGE@$IMAGE_DIGEST --wait --json
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 20) Test matrix (OS/arch)
|
## 20) Test matrix (OS/arch)
|
||||||
|
|
||||||
* Linux: ubuntu‑20.04/22.04/24.04 (x64, arm64), alpine (musl).
|
* Linux: ubuntu‑20.04/22.04/24.04 (x64, arm64), alpine (musl).
|
||||||
* macOS: 13–15 (x64, arm64).
|
* macOS: 13–15 (x64, arm64).
|
||||||
* Windows: 10/11, Server 2019/2022 (x64, arm64).
|
* Windows: 10/11, Server 2019/2022 (x64, arm64).
|
||||||
* Docker engines: Docker Desktop, containerd‑based runners.
|
* Docker engines: Docker Desktop, containerd‑based runners.
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -98,7 +98,7 @@ At startup, services **self‑advertise** their semver & channel; the UI surface
|
|||||||
**Gating policy**:
|
**Gating policy**:
|
||||||
|
|
||||||
* **Core images** (Authority, Scanner, Concelier, Excititor, Attestor, UI): public **read**.
|
* **Core images** (Authority, Scanner, Concelier, Excititor, Attestor, UI): public **read**.
|
||||||
* **Enterprise add‑ons** (if any) and **pre‑release**: private repos via the **Registry Token Service** (`src/StellaOps.Registry.TokenService`) which exchanges Authority-issued OpToks for short-lived Docker registry bearer tokens.
|
* **Enterprise add‑ons** (if any) and **pre‑release**: private repos via the **Registry Token Service** (`src/Registry/StellaOps.Registry.TokenService`) which exchanges Authority-issued OpToks for short-lived Docker registry bearer tokens.
|
||||||
|
|
||||||
> Monetization lever is **signing** (PoE gate), not image pulls, so the core remains simple to consume.
|
> Monetization lever is **signing** (PoE gate), not image pulls, so the core remains simple to consume.
|
||||||
|
|
||||||
|
|||||||
@@ -1,487 +1,487 @@
|
|||||||
# component_architecture_scanner.md — **Stella Ops Scanner** (2025Q4)
|
# component_architecture_scanner.md — **Stella Ops Scanner** (2025Q4)
|
||||||
|
|
||||||
> **Scope.** Implementation‑ready architecture for the **Scanner** subsystem: WebService, Workers, analyzers, SBOM assembly (inventory & usage), per‑layer caching, three‑way diffs, artifact catalog (RustFS default + Mongo, S3-compatible fallback), attestation hand‑off, and scale/security posture. This document is the contract between the scanning plane and everything else (Policy, Excititor, Concelier, UI, CLI).
|
> **Scope.** Implementation‑ready architecture for the **Scanner** subsystem: WebService, Workers, analyzers, SBOM assembly (inventory & usage), per‑layer caching, three‑way diffs, artifact catalog (RustFS default + Mongo, S3-compatible fallback), attestation hand‑off, and scale/security posture. This document is the contract between the scanning plane and everything else (Policy, Excititor, Concelier, UI, CLI).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 0) Mission & boundaries
|
## 0) Mission & boundaries
|
||||||
|
|
||||||
**Mission.** Produce **deterministic**, **explainable** SBOMs and diffs for container images and filesystems, quickly and repeatedly, without guessing. Emit two views: **Inventory** (everything present) and **Usage** (entrypoint closure + actually linked libs). Attach attestations through **Signer→Attestor→Rekor v2**.
|
**Mission.** Produce **deterministic**, **explainable** SBOMs and diffs for container images and filesystems, quickly and repeatedly, without guessing. Emit two views: **Inventory** (everything present) and **Usage** (entrypoint closure + actually linked libs). Attach attestations through **Signer→Attestor→Rekor v2**.
|
||||||
|
|
||||||
**Boundaries.**
|
**Boundaries.**
|
||||||
|
|
||||||
* Scanner **does not** produce PASS/FAIL. The backend (Policy + Excititor + Concelier) decides presentation and verdicts.
|
* Scanner **does not** produce PASS/FAIL. The backend (Policy + Excititor + Concelier) decides presentation and verdicts.
|
||||||
* Scanner **does not** keep third‑party SBOM warehouses. It may **bind** to existing attestations for exact hashes.
|
* Scanner **does not** keep third‑party SBOM warehouses. It may **bind** to existing attestations for exact hashes.
|
||||||
* Core analyzers are **deterministic** (no fuzzy identity). Optional heuristic plug‑ins (e.g., patch‑presence) run under explicit flags and never contaminate the core SBOM.
|
* Core analyzers are **deterministic** (no fuzzy identity). Optional heuristic plug‑ins (e.g., patch‑presence) run under explicit flags and never contaminate the core SBOM.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 1) Solution & project layout
|
## 1) Solution & project layout
|
||||||
|
|
||||||
```
|
```
|
||||||
src/
|
src/
|
||||||
├─ StellaOps.Scanner.WebService/ # REST control plane, catalog, diff, exports
|
├─ StellaOps.Scanner.WebService/ # REST control plane, catalog, diff, exports
|
||||||
├─ StellaOps.Scanner.Worker/ # queue consumer; executes analyzers
|
├─ StellaOps.Scanner.Worker/ # queue consumer; executes analyzers
|
||||||
├─ StellaOps.Scanner.Models/ # DTOs, evidence, graph nodes, CDX/SPDX adapters
|
├─ StellaOps.Scanner.Models/ # DTOs, evidence, graph nodes, CDX/SPDX adapters
|
||||||
├─ StellaOps.Scanner.Storage/ # Mongo repositories; RustFS object client (default) + S3 fallback; ILM/GC
|
├─ StellaOps.Scanner.Storage/ # Mongo repositories; RustFS object client (default) + S3 fallback; ILM/GC
|
||||||
├─ StellaOps.Scanner.Queue/ # queue abstraction (Redis/NATS/RabbitMQ)
|
├─ StellaOps.Scanner.Queue/ # queue abstraction (Redis/NATS/RabbitMQ)
|
||||||
├─ StellaOps.Scanner.Cache/ # layer cache; file CAS; bloom/bitmap indexes
|
├─ StellaOps.Scanner.Cache/ # layer cache; file CAS; bloom/bitmap indexes
|
||||||
├─ StellaOps.Scanner.EntryTrace/ # ENTRYPOINT/CMD → terminal program resolver (shell AST)
|
├─ StellaOps.Scanner.EntryTrace/ # ENTRYPOINT/CMD → terminal program resolver (shell AST)
|
||||||
├─ StellaOps.Scanner.Analyzers.OS.[Apk|Dpkg|Rpm]/
|
├─ StellaOps.Scanner.Analyzers.OS.[Apk|Dpkg|Rpm]/
|
||||||
├─ StellaOps.Scanner.Analyzers.Lang.[Java|Node|Python|Go|DotNet|Rust]/
|
├─ StellaOps.Scanner.Analyzers.Lang.[Java|Node|Python|Go|DotNet|Rust]/
|
||||||
├─ StellaOps.Scanner.Analyzers.Native.[ELF|PE|MachO]/ # PE/Mach-O planned (M2)
|
├─ StellaOps.Scanner.Analyzers.Native.[ELF|PE|MachO]/ # PE/Mach-O planned (M2)
|
||||||
├─ StellaOps.Scanner.Emit.CDX/ # CycloneDX (JSON + Protobuf)
|
├─ StellaOps.Scanner.Emit.CDX/ # CycloneDX (JSON + Protobuf)
|
||||||
├─ StellaOps.Scanner.Emit.SPDX/ # SPDX 3.0.1 JSON
|
├─ StellaOps.Scanner.Emit.SPDX/ # SPDX 3.0.1 JSON
|
||||||
├─ StellaOps.Scanner.Diff/ # image→layer→component three‑way diff
|
├─ StellaOps.Scanner.Diff/ # image→layer→component three‑way diff
|
||||||
├─ StellaOps.Scanner.Index/ # BOM‑Index sidecar (purls + roaring bitmaps)
|
├─ StellaOps.Scanner.Index/ # BOM‑Index sidecar (purls + roaring bitmaps)
|
||||||
├─ StellaOps.Scanner.Tests.* # unit/integration/e2e fixtures
|
├─ StellaOps.Scanner.Tests.* # unit/integration/e2e fixtures
|
||||||
└─ tools/
|
└─ tools/
|
||||||
├─ StellaOps.Scanner.Sbomer.BuildXPlugin/ # BuildKit generator (image referrer SBOMs)
|
├─ StellaOps.Scanner.Sbomer.BuildXPlugin/ # BuildKit generator (image referrer SBOMs)
|
||||||
└─ StellaOps.Scanner.Sbomer.DockerImage/ # CLI‑driven scanner container
|
└─ StellaOps.Scanner.Sbomer.DockerImage/ # CLI‑driven scanner container
|
||||||
```
|
```
|
||||||
|
|
||||||
Analyzer assemblies and buildx generators are packaged as **restart-time plug-ins** under `plugins/scanner/**` with manifests; services must restart to activate new plug-ins.
|
Analyzer assemblies and buildx generators are packaged as **restart-time plug-ins** under `plugins/scanner/**` with manifests; services must restart to activate new plug-ins.
|
||||||
|
|
||||||
### 1.1 Queue backbone (Redis / NATS)
|
### 1.1 Queue backbone (Redis / NATS)
|
||||||
|
|
||||||
`StellaOps.Scanner.Queue` exposes a transport-agnostic contract (`IScanQueue`/`IScanQueueLease`) used by the WebService producer and Worker consumers. Sprint 9 introduces two first-party transports:
|
`StellaOps.Scanner.Queue` exposes a transport-agnostic contract (`IScanQueue`/`IScanQueueLease`) used by the WebService producer and Worker consumers. Sprint 9 introduces two first-party transports:
|
||||||
|
|
||||||
- **Redis Streams** (default). Uses consumer groups, deterministic idempotency keys (`scanner:jobs:idemp:*`), and supports lease claim (`XCLAIM`), renewal, exponential-backoff retries, and a `scanner:jobs:dead` stream for exhausted attempts.
|
- **Redis Streams** (default). Uses consumer groups, deterministic idempotency keys (`scanner:jobs:idemp:*`), and supports lease claim (`XCLAIM`), renewal, exponential-backoff retries, and a `scanner:jobs:dead` stream for exhausted attempts.
|
||||||
- **NATS JetStream**. Provisions the `SCANNER_JOBS` work-queue stream + durable consumer `scanner-workers`, publishes with `MsgId` for dedupe, applies backoff via `NAK` delays, and routes dead-lettered jobs to `SCANNER_JOBS_DEAD`.
|
- **NATS JetStream**. Provisions the `SCANNER_JOBS` work-queue stream + durable consumer `scanner-workers`, publishes with `MsgId` for dedupe, applies backoff via `NAK` delays, and routes dead-lettered jobs to `SCANNER_JOBS_DEAD`.
|
||||||
|
|
||||||
Metrics are emitted via `Meter` counters (`scanner_queue_enqueued_total`, `scanner_queue_retry_total`, `scanner_queue_deadletter_total`), and `ScannerQueueHealthCheck` pings the active backend (Redis `PING`, NATS `PING`). Configuration is bound from `scanner.queue`:
|
Metrics are emitted via `Meter` counters (`scanner_queue_enqueued_total`, `scanner_queue_retry_total`, `scanner_queue_deadletter_total`), and `ScannerQueueHealthCheck` pings the active backend (Redis `PING`, NATS `PING`). Configuration is bound from `scanner.queue`:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
scanner:
|
scanner:
|
||||||
queue:
|
queue:
|
||||||
kind: redis # or nats
|
kind: redis # or nats
|
||||||
redis:
|
redis:
|
||||||
connectionString: "redis://queue:6379/0"
|
connectionString: "redis://queue:6379/0"
|
||||||
streamName: "scanner:jobs"
|
streamName: "scanner:jobs"
|
||||||
nats:
|
nats:
|
||||||
url: "nats://queue:4222"
|
url: "nats://queue:4222"
|
||||||
stream: "SCANNER_JOBS"
|
stream: "SCANNER_JOBS"
|
||||||
subject: "scanner.jobs"
|
subject: "scanner.jobs"
|
||||||
durableConsumer: "scanner-workers"
|
durableConsumer: "scanner-workers"
|
||||||
deadLetterSubject: "scanner.jobs.dead"
|
deadLetterSubject: "scanner.jobs.dead"
|
||||||
maxDeliveryAttempts: 5
|
maxDeliveryAttempts: 5
|
||||||
retryInitialBackoff: 00:00:05
|
retryInitialBackoff: 00:00:05
|
||||||
retryMaxBackoff: 00:02:00
|
retryMaxBackoff: 00:02:00
|
||||||
```
|
```
|
||||||
|
|
||||||
The DI extension (`AddScannerQueue`) wires the selected transport, so future additions (e.g., RabbitMQ) only implement the same contract and register.
|
The DI extension (`AddScannerQueue`) wires the selected transport, so future additions (e.g., RabbitMQ) only implement the same contract and register.
|
||||||
|
|
||||||
**Runtime form‑factor:** two deployables
|
**Runtime form‑factor:** two deployables
|
||||||
|
|
||||||
* **Scanner.WebService** (stateless REST)
|
* **Scanner.WebService** (stateless REST)
|
||||||
* **Scanner.Worker** (N replicas; queue‑driven)
|
* **Scanner.Worker** (N replicas; queue‑driven)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 2) External dependencies
|
## 2) External dependencies
|
||||||
|
|
||||||
* **OCI registry** with **Referrers API** (discover attached SBOMs/signatures).
|
* **OCI registry** with **Referrers API** (discover attached SBOMs/signatures).
|
||||||
* **RustFS** (default, offline-first) for SBOM artifacts; optional S3/MinIO compatibility retained for migration; **Object Lock** semantics emulated via retention headers; **ILM** for TTL.
|
* **RustFS** (default, offline-first) for SBOM artifacts; optional S3/MinIO compatibility retained for migration; **Object Lock** semantics emulated via retention headers; **ILM** for TTL.
|
||||||
* **MongoDB** for catalog, job state, diffs, ILM rules.
|
* **MongoDB** for catalog, job state, diffs, ILM rules.
|
||||||
* **Queue** (Redis Streams/NATS/RabbitMQ).
|
* **Queue** (Redis Streams/NATS/RabbitMQ).
|
||||||
* **Authority** (on‑prem OIDC) for **OpToks** (DPoP/mTLS).
|
* **Authority** (on‑prem OIDC) for **OpToks** (DPoP/mTLS).
|
||||||
* **Signer** + **Attestor** (+ **Fulcio/KMS** + **Rekor v2**) for DSSE + transparency.
|
* **Signer** + **Attestor** (+ **Fulcio/KMS** + **Rekor v2**) for DSSE + transparency.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 3) Contracts & data model
|
## 3) Contracts & data model
|
||||||
|
|
||||||
### 3.1 Evidence‑first component model
|
### 3.1 Evidence‑first component model
|
||||||
|
|
||||||
**Nodes**
|
**Nodes**
|
||||||
|
|
||||||
* `Image`, `Layer`, `File`
|
* `Image`, `Layer`, `File`
|
||||||
* `Component` (`purl?`, `name`, `version?`, `type`, `id` — may be `bin:{sha256}`)
|
* `Component` (`purl?`, `name`, `version?`, `type`, `id` — may be `bin:{sha256}`)
|
||||||
* `Executable` (ELF/PE/Mach‑O), `Library` (native or managed), `EntryScript` (shell/launcher)
|
* `Executable` (ELF/PE/Mach‑O), `Library` (native or managed), `EntryScript` (shell/launcher)
|
||||||
|
|
||||||
**Edges** (all carry **Evidence**)
|
**Edges** (all carry **Evidence**)
|
||||||
|
|
||||||
* `contains(Image|Layer → File)`
|
* `contains(Image|Layer → File)`
|
||||||
* `installs(PackageDB → Component)` (OS database row)
|
* `installs(PackageDB → Component)` (OS database row)
|
||||||
* `declares(InstalledMetadata → Component)` (dist‑info, pom.properties, deps.json…)
|
* `declares(InstalledMetadata → Component)` (dist‑info, pom.properties, deps.json…)
|
||||||
* `links_to(Executable → Library)` (ELF `DT_NEEDED`, PE imports)
|
* `links_to(Executable → Library)` (ELF `DT_NEEDED`, PE imports)
|
||||||
* `calls(EntryScript → Program)` (file:line from shell AST)
|
* `calls(EntryScript → Program)` (file:line from shell AST)
|
||||||
* `attests(Rekor → Component|Image)` (SBOM/predicate binding)
|
* `attests(Rekor → Component|Image)` (SBOM/predicate binding)
|
||||||
* `bound_from_attestation(Component_attested → Component_observed)` (hash equality proof)
|
* `bound_from_attestation(Component_attested → Component_observed)` (hash equality proof)
|
||||||
|
|
||||||
**Evidence**
|
**Evidence**
|
||||||
|
|
||||||
```
|
```
|
||||||
{ source: enum, locator: (path|offset|line), sha256?, method: enum, timestamp }
|
{ source: enum, locator: (path|offset|line), sha256?, method: enum, timestamp }
|
||||||
```
|
```
|
||||||
|
|
||||||
No confidences. Either a fact is proven with listed mechanisms, or it is not claimed.
|
No confidences. Either a fact is proven with listed mechanisms, or it is not claimed.
|
||||||
|
|
||||||
### 3.2 Catalog schema (Mongo)
|
### 3.2 Catalog schema (Mongo)
|
||||||
|
|
||||||
* `artifacts`
|
* `artifacts`
|
||||||
|
|
||||||
```
|
```
|
||||||
{ _id, type: layer-bom|image-bom|diff|index,
|
{ _id, type: layer-bom|image-bom|diff|index,
|
||||||
format: cdx-json|cdx-pb|spdx-json,
|
format: cdx-json|cdx-pb|spdx-json,
|
||||||
bytesSha256, size, rekor: { uuid,index,url }?,
|
bytesSha256, size, rekor: { uuid,index,url }?,
|
||||||
ttlClass, immutable, refCount, createdAt }
|
ttlClass, immutable, refCount, createdAt }
|
||||||
```
|
```
|
||||||
* `images { imageDigest, repo, tag?, arch, createdAt, lastSeen }`
|
* `images { imageDigest, repo, tag?, arch, createdAt, lastSeen }`
|
||||||
* `layers { layerDigest, mediaType, size, createdAt, lastSeen }`
|
* `layers { layerDigest, mediaType, size, createdAt, lastSeen }`
|
||||||
* `links { fromType, fromDigest, artifactId }` // image/layer -> artifact
|
* `links { fromType, fromDigest, artifactId }` // image/layer -> artifact
|
||||||
* `jobs { _id, kind, args, state, startedAt, heartbeatAt, endedAt, error }`
|
* `jobs { _id, kind, args, state, startedAt, heartbeatAt, endedAt, error }`
|
||||||
* `lifecycleRules { ruleId, scope, ttlDays, retainIfReferenced, immutable }`
|
* `lifecycleRules { ruleId, scope, ttlDays, retainIfReferenced, immutable }`
|
||||||
|
|
||||||
### 3.3 Object store layout (RustFS)
|
### 3.3 Object store layout (RustFS)
|
||||||
|
|
||||||
```
|
```
|
||||||
layers/<sha256>/sbom.cdx.json.zst
|
layers/<sha256>/sbom.cdx.json.zst
|
||||||
layers/<sha256>/sbom.spdx.json.zst
|
layers/<sha256>/sbom.spdx.json.zst
|
||||||
images/<imgDigest>/inventory.cdx.pb # CycloneDX Protobuf
|
images/<imgDigest>/inventory.cdx.pb # CycloneDX Protobuf
|
||||||
images/<imgDigest>/usage.cdx.pb
|
images/<imgDigest>/usage.cdx.pb
|
||||||
indexes/<imgDigest>/bom-index.bin # purls + roaring bitmaps
|
indexes/<imgDigest>/bom-index.bin # purls + roaring bitmaps
|
||||||
diffs/<old>_<new>/diff.json.zst
|
diffs/<old>_<new>/diff.json.zst
|
||||||
attest/<artifactSha256>.dsse.json # DSSE bundle (cert chain + Rekor proof)
|
attest/<artifactSha256>.dsse.json # DSSE bundle (cert chain + Rekor proof)
|
||||||
```
|
```
|
||||||
|
|
||||||
RustFS exposes a deterministic HTTP API (`PUT|GET|DELETE /api/v1/buckets/{bucket}/objects/{key}`).
|
RustFS exposes a deterministic HTTP API (`PUT|GET|DELETE /api/v1/buckets/{bucket}/objects/{key}`).
|
||||||
Scanner clients tag immutable uploads with `X-RustFS-Immutable: true` and, when retention applies,
|
Scanner clients tag immutable uploads with `X-RustFS-Immutable: true` and, when retention applies,
|
||||||
`X-RustFS-Retain-Seconds: <ttlSeconds>`. Additional headers can be injected via
|
`X-RustFS-Retain-Seconds: <ttlSeconds>`. Additional headers can be injected via
|
||||||
`scanner.artifactStore.headers` to support custom auth or proxy requirements. Legacy MinIO/S3
|
`scanner.artifactStore.headers` to support custom auth or proxy requirements. Legacy MinIO/S3
|
||||||
deployments remain supported by setting `scanner.artifactStore.driver = "s3"` during phased
|
deployments remain supported by setting `scanner.artifactStore.driver = "s3"` during phased
|
||||||
migrations.
|
migrations.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 4) REST API (Scanner.WebService)
|
## 4) REST API (Scanner.WebService)
|
||||||
|
|
||||||
All under `/api/v1/scanner`. Auth: **OpTok** (DPoP/mTLS); RBAC scopes.
|
All under `/api/v1/scanner`. Auth: **OpTok** (DPoP/mTLS); RBAC scopes.
|
||||||
|
|
||||||
```
|
```
|
||||||
POST /scans { imageRef|digest, force?:bool } → { scanId }
|
POST /scans { imageRef|digest, force?:bool } → { scanId }
|
||||||
GET /scans/{id} → { status, imageDigest, artifacts[], rekor? }
|
GET /scans/{id} → { status, imageDigest, artifacts[], rekor? }
|
||||||
GET /sboms/{imageDigest} ?format=cdx-json|cdx-pb|spdx-json&view=inventory|usage → bytes
|
GET /sboms/{imageDigest} ?format=cdx-json|cdx-pb|spdx-json&view=inventory|usage → bytes
|
||||||
GET /diff?old=<digest>&new=<digest>&view=inventory|usage → diff.json
|
GET /diff?old=<digest>&new=<digest>&view=inventory|usage → diff.json
|
||||||
POST /exports { imageDigest, format, view, attest?:bool } → { artifactId, rekor? }
|
POST /exports { imageDigest, format, view, attest?:bool } → { artifactId, rekor? }
|
||||||
POST /reports { imageDigest, policyRevision? } → { reportId, rekor? } # delegates to backend policy+vex
|
POST /reports { imageDigest, policyRevision? } → { reportId, rekor? } # delegates to backend policy+vex
|
||||||
GET /catalog/artifacts/{id} → { meta }
|
GET /catalog/artifacts/{id} → { meta }
|
||||||
GET /healthz | /readyz | /metrics
|
GET /healthz | /readyz | /metrics
|
||||||
```
|
```
|
||||||
|
|
||||||
### Report events
|
### Report events
|
||||||
|
|
||||||
When `scanner.events.enabled = true`, the WebService serialises the signed report (canonical JSON + DSSE envelope) with `NotifyCanonicalJsonSerializer` and publishes two Redis Stream entries (`scanner.report.ready`, `scanner.scan.completed`) to the configured stream (default `stella.events`). The stream fields carry the whole envelope plus lightweight headers (`kind`, `tenant`, `ts`) so Notify and UI timelines can consume the event bus without recomputing signatures. Publish timeouts and bounded stream length are controlled via `scanner:events:publishTimeoutSeconds` and `scanner:events:maxStreamLength`. If the queue driver is already Redis and no explicit events DSN is provided, the host reuses the queue connection and auto-enables event emission so deployments get live envelopes without extra wiring. Compose/Helm bundles expose the same knobs via the `SCANNER__EVENTS__*` environment variables for quick tuning.
|
When `scanner.events.enabled = true`, the WebService serialises the signed report (canonical JSON + DSSE envelope) with `NotifyCanonicalJsonSerializer` and publishes two Redis Stream entries (`scanner.report.ready`, `scanner.scan.completed`) to the configured stream (default `stella.events`). The stream fields carry the whole envelope plus lightweight headers (`kind`, `tenant`, `ts`) so Notify and UI timelines can consume the event bus without recomputing signatures. Publish timeouts and bounded stream length are controlled via `scanner:events:publishTimeoutSeconds` and `scanner:events:maxStreamLength`. If the queue driver is already Redis and no explicit events DSN is provided, the host reuses the queue connection and auto-enables event emission so deployments get live envelopes without extra wiring. Compose/Helm bundles expose the same knobs via the `SCANNER__EVENTS__*` environment variables for quick tuning.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 5) Execution flow (Worker)
|
## 5) Execution flow (Worker)
|
||||||
|
|
||||||
### 5.1 Acquire & verify
|
### 5.1 Acquire & verify
|
||||||
|
|
||||||
1. **Resolve image** (prefer `repo@sha256:…`).
|
1. **Resolve image** (prefer `repo@sha256:…`).
|
||||||
2. **(Optional) verify image signature** per policy (cosign).
|
2. **(Optional) verify image signature** per policy (cosign).
|
||||||
3. **Pull blobs**, compute layer digests; record metadata.
|
3. **Pull blobs**, compute layer digests; record metadata.
|
||||||
|
|
||||||
### 5.2 Layer union FS
|
### 5.2 Layer union FS
|
||||||
|
|
||||||
* Apply whiteouts; materialize final filesystem; map **file → first introducing layer**.
|
* Apply whiteouts; materialize final filesystem; map **file → first introducing layer**.
|
||||||
* Windows layers (MSI/SxS/GAC) planned in **M2**.
|
* Windows layers (MSI/SxS/GAC) planned in **M2**.
|
||||||
|
|
||||||
### 5.3 Evidence harvest (parallel analyzers; deterministic only)
|
### 5.3 Evidence harvest (parallel analyzers; deterministic only)
|
||||||
|
|
||||||
**A) OS packages**
|
**A) OS packages**
|
||||||
|
|
||||||
* **apk**: `/lib/apk/db/installed`
|
* **apk**: `/lib/apk/db/installed`
|
||||||
* **dpkg**: `/var/lib/dpkg/status`, `/var/lib/dpkg/info/*.list`
|
* **dpkg**: `/var/lib/dpkg/status`, `/var/lib/dpkg/info/*.list`
|
||||||
* **rpm**: `/var/lib/rpm/Packages` (via librpm or parser)
|
* **rpm**: `/var/lib/rpm/Packages` (via librpm or parser)
|
||||||
* Record `name`, `version` (epoch/revision), `arch`, source package where present, and **declared file lists**.
|
* Record `name`, `version` (epoch/revision), `arch`, source package where present, and **declared file lists**.
|
||||||
|
|
||||||
> **Data flow note:** Each OS analyzer now writes its canonical output into the shared `ScanAnalysisStore` under
|
> **Data flow note:** Each OS analyzer now writes its canonical output into the shared `ScanAnalysisStore` under
|
||||||
> `analysis.os.packages` (raw results), `analysis.os.fragments` (per-analyzer layer fragments), and contributes to
|
> `analysis.os.packages` (raw results), `analysis.os.fragments` (per-analyzer layer fragments), and contributes to
|
||||||
> `analysis.layers.fragments` (the aggregated view consumed by emit/diff pipelines). Helpers in
|
> `analysis.layers.fragments` (the aggregated view consumed by emit/diff pipelines). Helpers in
|
||||||
> `ScanAnalysisCompositionBuilder` convert these fragments into SBOM composition requests and component graphs so the
|
> `ScanAnalysisCompositionBuilder` convert these fragments into SBOM composition requests and component graphs so the
|
||||||
> diff/emit stages no longer reach back into individual analyzer implementations.
|
> diff/emit stages no longer reach back into individual analyzer implementations.
|
||||||
|
|
||||||
**B) Language ecosystems (installed state only)**
|
**B) Language ecosystems (installed state only)**
|
||||||
|
|
||||||
* **Java**: `META-INF/maven/*/pom.properties`, MANIFEST → `pkg:maven/...`
|
* **Java**: `META-INF/maven/*/pom.properties`, MANIFEST → `pkg:maven/...`
|
||||||
* **Node**: `node_modules/**/package.json` → `pkg:npm/...`
|
* **Node**: `node_modules/**/package.json` → `pkg:npm/...`
|
||||||
* **Python**: `*.dist-info/{METADATA,RECORD}` → `pkg:pypi/...`
|
* **Python**: `*.dist-info/{METADATA,RECORD}` → `pkg:pypi/...`
|
||||||
* **Go**: Go **buildinfo** in binaries → `pkg:golang/...`
|
* **Go**: Go **buildinfo** in binaries → `pkg:golang/...`
|
||||||
* **.NET**: `*.deps.json` + assembly metadata → `pkg:nuget/...`
|
* **.NET**: `*.deps.json` + assembly metadata → `pkg:nuget/...`
|
||||||
* **Rust**: crates only when **explicitly present** (embedded metadata or cargo/registry traces); otherwise binaries reported as `bin:{sha256}`.
|
* **Rust**: crates only when **explicitly present** (embedded metadata or cargo/registry traces); otherwise binaries reported as `bin:{sha256}`.
|
||||||
|
|
||||||
> **Rule:** We only report components proven **on disk** with authoritative metadata. Lockfiles are evidence only.
|
> **Rule:** We only report components proven **on disk** with authoritative metadata. Lockfiles are evidence only.
|
||||||
|
|
||||||
**C) Native link graph**
|
**C) Native link graph**
|
||||||
|
|
||||||
* **ELF**: parse `PT_INTERP`, `DT_NEEDED`, RPATH/RUNPATH, **GNU symbol versions**; map **SONAMEs** to file paths; link executables → libs.
|
* **ELF**: parse `PT_INTERP`, `DT_NEEDED`, RPATH/RUNPATH, **GNU symbol versions**; map **SONAMEs** to file paths; link executables → libs.
|
||||||
* **PE/Mach‑O** (planned M2): import table, delay‑imports; version resources; code signatures.
|
* **PE/Mach‑O** (planned M2): import table, delay‑imports; version resources; code signatures.
|
||||||
* Map libs back to **OS packages** if possible (via file lists); else emit `bin:{sha256}` components.
|
* Map libs back to **OS packages** if possible (via file lists); else emit `bin:{sha256}` components.
|
||||||
* The exported metadata (`stellaops.os.*` properties, license list, source package) feeds policy scoring and export pipelines
|
* The exported metadata (`stellaops.os.*` properties, license list, source package) feeds policy scoring and export pipelines
|
||||||
directly – Policy evaluates quiet rules against package provenance while Exporters forward the enriched fields into
|
directly – Policy evaluates quiet rules against package provenance while Exporters forward the enriched fields into
|
||||||
downstream JSON/Trivy payloads.
|
downstream JSON/Trivy payloads.
|
||||||
|
|
||||||
**D) EntryTrace (ENTRYPOINT/CMD → terminal program)**
|
**D) EntryTrace (ENTRYPOINT/CMD → terminal program)**
|
||||||
|
|
||||||
* Read image config; parse shell (POSIX/Bash subset) with AST: `source`/`.` includes; `case/if`; `exec`/`command`; `run‑parts`.
|
* Read image config; parse shell (POSIX/Bash subset) with AST: `source`/`.` includes; `case/if`; `exec`/`command`; `run‑parts`.
|
||||||
* Resolve commands via **PATH** within the **built rootfs**; follow language launchers (Java/Node/Python) to identify the terminal program (ELF/JAR/venv script).
|
* Resolve commands via **PATH** within the **built rootfs**; follow language launchers (Java/Node/Python) to identify the terminal program (ELF/JAR/venv script).
|
||||||
* Record **file:line** and choices for each hop; output chain graph.
|
* Record **file:line** and choices for each hop; output chain graph.
|
||||||
* Unresolvable dynamic constructs are recorded as **unknown** edges with reasons (e.g., `$FOO` unresolved).
|
* Unresolvable dynamic constructs are recorded as **unknown** edges with reasons (e.g., `$FOO` unresolved).
|
||||||
|
|
||||||
**E) Attestation & SBOM bind (optional)**
|
**E) Attestation & SBOM bind (optional)**
|
||||||
|
|
||||||
* For each **file hash** or **binary hash**, query local cache of **Rekor v2** indices; if an SBOM attestation is found for **exact hash**, bind it to the component (origin=`attested`).
|
* For each **file hash** or **binary hash**, query local cache of **Rekor v2** indices; if an SBOM attestation is found for **exact hash**, bind it to the component (origin=`attested`).
|
||||||
* For the **image** digest, likewise bind SBOM attestations (build‑time referrers).
|
* For the **image** digest, likewise bind SBOM attestations (build‑time referrers).
|
||||||
|
|
||||||
### 5.4 Component normalization (exact only)
|
### 5.4 Component normalization (exact only)
|
||||||
|
|
||||||
* Create `Component` nodes only with deterministic identities: purl, or **`bin:{sha256}`** for unlabeled binaries.
|
* Create `Component` nodes only with deterministic identities: purl, or **`bin:{sha256}`** for unlabeled binaries.
|
||||||
* Record **origin** (OS DB, installed metadata, linker, attestation).
|
* Record **origin** (OS DB, installed metadata, linker, attestation).
|
||||||
|
|
||||||
### 5.5 SBOM assembly & emit
|
### 5.5 SBOM assembly & emit
|
||||||
|
|
||||||
* **Per-layer SBOM fragments**: components introduced by the layer (+ relationships).
|
* **Per-layer SBOM fragments**: components introduced by the layer (+ relationships).
|
||||||
* **Image SBOMs**: merge fragments; refer back to them via **CycloneDX BOM‑Link** (or SPDX ExternalRef).
|
* **Image SBOMs**: merge fragments; refer back to them via **CycloneDX BOM‑Link** (or SPDX ExternalRef).
|
||||||
* Emit both **Inventory** & **Usage** views.
|
* Emit both **Inventory** & **Usage** views.
|
||||||
* When the native analyzer reports an ELF `buildId`, attach it to component metadata and surface it as `stellaops:buildId` in CycloneDX properties (and diff metadata). This keeps SBOM/diff output in lockstep with runtime events and the debug-store manifest.
|
* When the native analyzer reports an ELF `buildId`, attach it to component metadata and surface it as `stellaops:buildId` in CycloneDX properties (and diff metadata). This keeps SBOM/diff output in lockstep with runtime events and the debug-store manifest.
|
||||||
* Serialize **CycloneDX JSON** and **CycloneDX Protobuf**; optionally **SPDX 3.0.1 JSON**.
|
* Serialize **CycloneDX JSON** and **CycloneDX Protobuf**; optionally **SPDX 3.0.1 JSON**.
|
||||||
* Build **BOM‑Index** sidecar: purl table + roaring bitmap; flag `usedByEntrypoint` components for fast backend joins.
|
* Build **BOM‑Index** sidecar: purl table + roaring bitmap; flag `usedByEntrypoint` components for fast backend joins.
|
||||||
|
|
||||||
The emitted `buildId` metadata is preserved in component hashes, diff payloads, and `/policy/runtime` responses so operators can pivot from SBOM entries → runtime events → `debug/.build-id/<aa>/<rest>.debug` within the Offline Kit or release bundle.
|
The emitted `buildId` metadata is preserved in component hashes, diff payloads, and `/policy/runtime` responses so operators can pivot from SBOM entries → runtime events → `debug/.build-id/<aa>/<rest>.debug` within the Offline Kit or release bundle.
|
||||||
|
|
||||||
### 5.6 DSSE attestation (via Signer/Attestor)
|
### 5.6 DSSE attestation (via Signer/Attestor)
|
||||||
|
|
||||||
* WebService constructs **predicate** with `image_digest`, `stellaops_version`, `license_id`, `policy_digest?` (when emitting **final reports**), timestamps.
|
* WebService constructs **predicate** with `image_digest`, `stellaops_version`, `license_id`, `policy_digest?` (when emitting **final reports**), timestamps.
|
||||||
* Calls **Signer** (requires **OpTok + PoE**); Signer verifies **entitlement + scanner image integrity** and returns **DSSE bundle**.
|
* Calls **Signer** (requires **OpTok + PoE**); Signer verifies **entitlement + scanner image integrity** and returns **DSSE bundle**.
|
||||||
* **Attestor** logs to **Rekor v2**; returns `{uuid,index,proof}` → stored in `artifacts.rekor`.
|
* **Attestor** logs to **Rekor v2**; returns `{uuid,index,proof}` → stored in `artifacts.rekor`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 6) Three‑way diff (image → layer → component)
|
## 6) Three‑way diff (image → layer → component)
|
||||||
|
|
||||||
### 6.1 Keys & classification
|
### 6.1 Keys & classification
|
||||||
|
|
||||||
* Component key: **purl** when present; else `bin:{sha256}`.
|
* Component key: **purl** when present; else `bin:{sha256}`.
|
||||||
* Diff classes: `added`, `removed`, `version_changed` (`upgraded|downgraded`), `metadata_changed` (e.g., origin from attestation vs observed).
|
* Diff classes: `added`, `removed`, `version_changed` (`upgraded|downgraded`), `metadata_changed` (e.g., origin from attestation vs observed).
|
||||||
* Layer attribution: for each change, resolve the **introducing/removing layer**.
|
* Layer attribution: for each change, resolve the **introducing/removing layer**.
|
||||||
|
|
||||||
### 6.2 Algorithm (outline)
|
### 6.2 Algorithm (outline)
|
||||||
|
|
||||||
```
|
```
|
||||||
A = components(imageOld, key)
|
A = components(imageOld, key)
|
||||||
B = components(imageNew, key)
|
B = components(imageNew, key)
|
||||||
|
|
||||||
added = B \ A
|
added = B \ A
|
||||||
removed = A \ B
|
removed = A \ B
|
||||||
changed = { k in A∩B : version(A[k]) != version(B[k]) || origin changed }
|
changed = { k in A∩B : version(A[k]) != version(B[k]) || origin changed }
|
||||||
|
|
||||||
for each item in added/removed/changed:
|
for each item in added/removed/changed:
|
||||||
layer = attribute_to_layer(item, imageOld|imageNew)
|
layer = attribute_to_layer(item, imageOld|imageNew)
|
||||||
usageFlag = usedByEntrypoint(item, imageNew)
|
usageFlag = usedByEntrypoint(item, imageNew)
|
||||||
emit diff.json (grouped by layer with badges)
|
emit diff.json (grouped by layer with badges)
|
||||||
```
|
```
|
||||||
|
|
||||||
Diffs are stored as artifacts and feed **UI** and **CLI**.
|
Diffs are stored as artifacts and feed **UI** and **CLI**.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 7) Build‑time SBOMs (fast CI path)
|
## 7) Build‑time SBOMs (fast CI path)
|
||||||
|
|
||||||
**Scanner.Sbomer.BuildXPlugin** can act as a BuildKit **generator**:
|
**Scanner.Sbomer.BuildXPlugin** can act as a BuildKit **generator**:
|
||||||
|
|
||||||
* During `docker buildx build --attest=type=sbom,generator=stellaops/sbom-indexer`, run analyzers on the build context/output; attach SBOMs as OCI **referrers** to the built image.
|
* During `docker buildx build --attest=type=sbom,generator=stellaops/sbom-indexer`, run analyzers on the build context/output; attach SBOMs as OCI **referrers** to the built image.
|
||||||
* Optionally request **Signer/Attestor** to produce **Stella Ops‑verified** attestation immediately; else, Scanner.WebService can verify and re‑attest post‑push.
|
* Optionally request **Signer/Attestor** to produce **Stella Ops‑verified** attestation immediately; else, Scanner.WebService can verify and re‑attest post‑push.
|
||||||
* Scanner.WebService trusts build‑time SBOMs per policy, enabling **no‑rescan** for unchanged bases.
|
* Scanner.WebService trusts build‑time SBOMs per policy, enabling **no‑rescan** for unchanged bases.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 8) Configuration (YAML)
|
## 8) Configuration (YAML)
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
scanner:
|
scanner:
|
||||||
queue:
|
queue:
|
||||||
kind: redis
|
kind: redis
|
||||||
url: "redis://queue:6379/0"
|
url: "redis://queue:6379/0"
|
||||||
mongo:
|
mongo:
|
||||||
uri: "mongodb://mongo/scanner"
|
uri: "mongodb://mongo/scanner"
|
||||||
s3:
|
s3:
|
||||||
endpoint: "http://minio:9000"
|
endpoint: "http://minio:9000"
|
||||||
bucket: "stellaops"
|
bucket: "stellaops"
|
||||||
objectLock: "governance" # or 'compliance'
|
objectLock: "governance" # or 'compliance'
|
||||||
analyzers:
|
analyzers:
|
||||||
os: { apk: true, dpkg: true, rpm: true }
|
os: { apk: true, dpkg: true, rpm: true }
|
||||||
lang: { java: true, node: true, python: true, go: true, dotnet: true, rust: true }
|
lang: { java: true, node: true, python: true, go: true, dotnet: true, rust: true }
|
||||||
native: { elf: true, pe: false, macho: false } # PE/Mach-O in M2
|
native: { elf: true, pe: false, macho: false } # PE/Mach-O in M2
|
||||||
entryTrace: { enabled: true, shellMaxDepth: 64, followRunParts: true }
|
entryTrace: { enabled: true, shellMaxDepth: 64, followRunParts: true }
|
||||||
emit:
|
emit:
|
||||||
cdx: { json: true, protobuf: true }
|
cdx: { json: true, protobuf: true }
|
||||||
spdx: { json: true }
|
spdx: { json: true }
|
||||||
compress: "zstd"
|
compress: "zstd"
|
||||||
rekor:
|
rekor:
|
||||||
url: "https://rekor-v2.internal"
|
url: "https://rekor-v2.internal"
|
||||||
signer:
|
signer:
|
||||||
url: "https://signer.internal"
|
url: "https://signer.internal"
|
||||||
limits:
|
limits:
|
||||||
maxParallel: 8
|
maxParallel: 8
|
||||||
perRegistryConcurrency: 2
|
perRegistryConcurrency: 2
|
||||||
policyHints:
|
policyHints:
|
||||||
verifyImageSignature: false
|
verifyImageSignature: false
|
||||||
trustBuildTimeSboms: true
|
trustBuildTimeSboms: true
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 9) Scale & performance
|
## 9) Scale & performance
|
||||||
|
|
||||||
* **Parallelism**: per‑analyzer concurrency; bounded directory walkers; file CAS dedupe by sha256.
|
* **Parallelism**: per‑analyzer concurrency; bounded directory walkers; file CAS dedupe by sha256.
|
||||||
* **Distributed locks** per **layer digest** to prevent duplicate work across Workers.
|
* **Distributed locks** per **layer digest** to prevent duplicate work across Workers.
|
||||||
* **Registry throttles**: per‑host concurrency budgets; exponential backoff on 429/5xx.
|
* **Registry throttles**: per‑host concurrency budgets; exponential backoff on 429/5xx.
|
||||||
* **Targets**:
|
* **Targets**:
|
||||||
|
|
||||||
* **Build‑time**: P95 ≤ 3–5 s on warmed bases (CI generator).
|
* **Build‑time**: P95 ≤ 3–5 s on warmed bases (CI generator).
|
||||||
* **Post‑build delta**: P95 ≤ 10 s for 200 MB images with cache hit.
|
* **Post‑build delta**: P95 ≤ 10 s for 200 MB images with cache hit.
|
||||||
* **Emit**: CycloneDX Protobuf ≤ 150 ms for 5k components; JSON ≤ 500 ms.
|
* **Emit**: CycloneDX Protobuf ≤ 150 ms for 5k components; JSON ≤ 500 ms.
|
||||||
* **Diff**: ≤ 200 ms for 5k vs 5k components.
|
* **Diff**: ≤ 200 ms for 5k vs 5k components.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 10) Security posture
|
## 10) Security posture
|
||||||
|
|
||||||
* **AuthN**: Authority‑issued short OpToks (DPoP/mTLS).
|
* **AuthN**: Authority‑issued short OpToks (DPoP/mTLS).
|
||||||
* **AuthZ**: scopes (`scanner.scan`, `scanner.export`, `scanner.catalog.read`).
|
* **AuthZ**: scopes (`scanner.scan`, `scanner.export`, `scanner.catalog.read`).
|
||||||
* **mTLS** to **Signer**/**Attestor**; only **Signer** can sign.
|
* **mTLS** to **Signer**/**Attestor**; only **Signer** can sign.
|
||||||
* **No network fetches** during analysis (except registry pulls and optional Rekor index reads).
|
* **No network fetches** during analysis (except registry pulls and optional Rekor index reads).
|
||||||
* **Sandboxing**: non‑root containers; read‑only FS; seccomp profiles; disable execution of scanned content.
|
* **Sandboxing**: non‑root containers; read‑only FS; seccomp profiles; disable execution of scanned content.
|
||||||
* **Release integrity**: all first‑party images are **cosign‑signed**; Workers/WebService self‑verify at startup.
|
* **Release integrity**: all first‑party images are **cosign‑signed**; Workers/WebService self‑verify at startup.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 11) Observability & audit
|
## 11) Observability & audit
|
||||||
|
|
||||||
* **Metrics**:
|
* **Metrics**:
|
||||||
|
|
||||||
* `scanner.jobs_inflight`, `scanner.scan_latency_seconds`
|
* `scanner.jobs_inflight`, `scanner.scan_latency_seconds`
|
||||||
* `scanner.layer_cache_hits_total`, `scanner.file_cas_hits_total`
|
* `scanner.layer_cache_hits_total`, `scanner.file_cas_hits_total`
|
||||||
* `scanner.artifact_bytes_total{format}`
|
* `scanner.artifact_bytes_total{format}`
|
||||||
* `scanner.attestation_latency_seconds`, `scanner.rekor_failures_total`
|
* `scanner.attestation_latency_seconds`, `scanner.rekor_failures_total`
|
||||||
* `scanner_analyzer_golang_heuristic_total{indicator,version_hint}` — increments whenever the Go analyzer falls back to heuristics (build-id or runtime markers). Grafana panel: `sum by (indicator) (rate(scanner_analyzer_golang_heuristic_total[5m]))`; alert when the rate is ≥ 1 for 15 minutes to highlight unexpected stripped binaries.
|
* `scanner_analyzer_golang_heuristic_total{indicator,version_hint}` — increments whenever the Go analyzer falls back to heuristics (build-id or runtime markers). Grafana panel: `sum by (indicator) (rate(scanner_analyzer_golang_heuristic_total[5m]))`; alert when the rate is ≥ 1 for 15 minutes to highlight unexpected stripped binaries.
|
||||||
* **Tracing**: spans for acquire→union→analyzers→compose→emit→sign→log.
|
* **Tracing**: spans for acquire→union→analyzers→compose→emit→sign→log.
|
||||||
* **Audit logs**: DSSE requests log `license_id`, `image_digest`, `artifactSha256`, `policy_digest?`, Rekor UUID on success.
|
* **Audit logs**: DSSE requests log `license_id`, `image_digest`, `artifactSha256`, `policy_digest?`, Rekor UUID on success.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 12) Testing matrix
|
## 12) Testing matrix
|
||||||
|
|
||||||
* **Determinism:** given same image + analyzers → byte‑identical **CDX Protobuf**; JSON normalized.
|
* **Determinism:** given same image + analyzers → byte‑identical **CDX Protobuf**; JSON normalized.
|
||||||
* **OS packages:** ground‑truth images per distro; compare to package DB.
|
* **OS packages:** ground‑truth images per distro; compare to package DB.
|
||||||
* **Lang ecosystems:** sample images per ecosystem (Java/Node/Python/Go/.NET/Rust) with installed metadata; negative tests w/ lockfile‑only.
|
* **Lang ecosystems:** sample images per ecosystem (Java/Node/Python/Go/.NET/Rust) with installed metadata; negative tests w/ lockfile‑only.
|
||||||
* **Native & EntryTrace:** ELF graph correctness; shell AST cases (includes, run‑parts, exec, case/if).
|
* **Native & EntryTrace:** ELF graph correctness; shell AST cases (includes, run‑parts, exec, case/if).
|
||||||
* **Diff:** layer attribution against synthetic two‑image sequences.
|
* **Diff:** layer attribution against synthetic two‑image sequences.
|
||||||
* **Performance:** cold vs warm cache; large `node_modules` and `site‑packages`.
|
* **Performance:** cold vs warm cache; large `node_modules` and `site‑packages`.
|
||||||
* **Security:** ensure no code execution from image; fuzz parser inputs; path traversal resistance on layer extract.
|
* **Security:** ensure no code execution from image; fuzz parser inputs; path traversal resistance on layer extract.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 13) Failure modes & degradations
|
## 13) Failure modes & degradations
|
||||||
|
|
||||||
* **Missing OS DB** (files exist, DB removed): record **files**; do **not** fabricate package components; emit `bin:{sha256}` where unavoidable; flag in evidence.
|
* **Missing OS DB** (files exist, DB removed): record **files**; do **not** fabricate package components; emit `bin:{sha256}` where unavoidable; flag in evidence.
|
||||||
* **Unreadable metadata** (corrupt dist‑info): record file evidence; skip component creation; annotate.
|
* **Unreadable metadata** (corrupt dist‑info): record file evidence; skip component creation; annotate.
|
||||||
* **Dynamic shell constructs**: mark unresolved edges with reasons (env var unknown) and continue; **Usage** view may be partial.
|
* **Dynamic shell constructs**: mark unresolved edges with reasons (env var unknown) and continue; **Usage** view may be partial.
|
||||||
* **Registry rate limits**: honor backoff; queue job retries with jitter.
|
* **Registry rate limits**: honor backoff; queue job retries with jitter.
|
||||||
* **Signer refusal** (license/plan/version): scan completes; artifact produced; **no attestation**; WebService marks result as **unverified**.
|
* **Signer refusal** (license/plan/version): scan completes; artifact produced; **no attestation**; WebService marks result as **unverified**.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 14) Optional plug‑ins (off by default)
|
## 14) Optional plug‑ins (off by default)
|
||||||
|
|
||||||
* **Patch‑presence detector** (signature‑based backport checks). Reads curated function‑level signatures from advisories; inspects binaries for patched code snippets to lower false‑positives for backported fixes. Runs as a sidecar analyzer that **annotates** components; never overrides core identities.
|
* **Patch‑presence detector** (signature‑based backport checks). Reads curated function‑level signatures from advisories; inspects binaries for patched code snippets to lower false‑positives for backported fixes. Runs as a sidecar analyzer that **annotates** components; never overrides core identities.
|
||||||
* **Runtime probes** (with Zastava): when allowed, compare **/proc/<pid>/maps** (DSOs actually loaded) with static **Usage** view for precision.
|
* **Runtime probes** (with Zastava): when allowed, compare **/proc/<pid>/maps** (DSOs actually loaded) with static **Usage** view for precision.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 15) DevOps & operations
|
## 15) DevOps & operations
|
||||||
|
|
||||||
* **HA**: WebService horizontal scale; Workers autoscale by queue depth & CPU; distributed locks on layers.
|
* **HA**: WebService horizontal scale; Workers autoscale by queue depth & CPU; distributed locks on layers.
|
||||||
* **Retention**: ILM rules per artifact class (`short`, `default`, `compliance`); **Object Lock** for compliance artifacts (reports, signed SBOMs).
|
* **Retention**: ILM rules per artifact class (`short`, `default`, `compliance`); **Object Lock** for compliance artifacts (reports, signed SBOMs).
|
||||||
* **Upgrades**: bump **cache schema** when analyzer outputs change; WebService triggers refresh of dependent artifacts.
|
* **Upgrades**: bump **cache schema** when analyzer outputs change; WebService triggers refresh of dependent artifacts.
|
||||||
* **Backups**: Mongo (daily dumps); RustFS snapshots (filesystem-level rsync/ZFS) or S3 versioning when legacy driver enabled; Rekor v2 DB snapshots.
|
* **Backups**: Mongo (daily dumps); RustFS snapshots (filesystem-level rsync/ZFS) or S3 versioning when legacy driver enabled; Rekor v2 DB snapshots.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 16) CLI & UI touch points
|
## 16) CLI & UI touch points
|
||||||
|
|
||||||
* **CLI**: `stellaops scan <ref>`, `stellaops diff --old --new`, `stellaops export`, `stellaops verify attestation <bundle|url>`.
|
* **CLI**: `stellaops scan <ref>`, `stellaops diff --old --new`, `stellaops export`, `stellaops verify attestation <bundle|url>`.
|
||||||
* **UI**: Scan detail shows **Inventory/Usage** toggles, **Diff by Layer**, **Attestation badge** (verified/unverified), Rekor link, and **EntryTrace** chain with file:line breadcrumbs.
|
* **UI**: Scan detail shows **Inventory/Usage** toggles, **Diff by Layer**, **Attestation badge** (verified/unverified), Rekor link, and **EntryTrace** chain with file:line breadcrumbs.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 17) Roadmap (Scanner)
|
## 17) Roadmap (Scanner)
|
||||||
|
|
||||||
* **M2**: Windows containers (MSI/SxS/GAC analyzers), PE/Mach‑O native analyzer, deeper Rust metadata.
|
* **M2**: Windows containers (MSI/SxS/GAC analyzers), PE/Mach‑O native analyzer, deeper Rust metadata.
|
||||||
* **M2**: Buildx generator GA (certified external registries), cross‑registry trust policies.
|
* **M2**: Buildx generator GA (certified external registries), cross‑registry trust policies.
|
||||||
* **M3**: Patch‑presence plug‑in GA (opt‑in), cross‑image corpus clustering (evidence‑only; not identity).
|
* **M3**: Patch‑presence plug‑in GA (opt‑in), cross‑image corpus clustering (evidence‑only; not identity).
|
||||||
* **M3**: Advanced EntryTrace (POSIX shell features breadth, busybox detection).
|
* **M3**: Advanced EntryTrace (POSIX shell features breadth, busybox detection).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Appendix A — EntryTrace resolution (pseudo)
|
### Appendix A — EntryTrace resolution (pseudo)
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
ResolveEntrypoint(ImageConfig cfg, RootFs fs):
|
ResolveEntrypoint(ImageConfig cfg, RootFs fs):
|
||||||
cmd = Normalize(cfg.ENTRYPOINT, cfg.CMD)
|
cmd = Normalize(cfg.ENTRYPOINT, cfg.CMD)
|
||||||
stack = [ Script(cmd, path=FindOnPath(cmd[0], fs)) ]
|
stack = [ Script(cmd, path=FindOnPath(cmd[0], fs)) ]
|
||||||
visited = set()
|
visited = set()
|
||||||
|
|
||||||
while stack not empty and depth < MAX:
|
while stack not empty and depth < MAX:
|
||||||
cur = stack.pop()
|
cur = stack.pop()
|
||||||
if cur in visited: continue
|
if cur in visited: continue
|
||||||
visited.add(cur)
|
visited.add(cur)
|
||||||
|
|
||||||
if IsShellScript(cur.path):
|
if IsShellScript(cur.path):
|
||||||
ast = ParseShell(cur.path)
|
ast = ParseShell(cur.path)
|
||||||
foreach directive in ast:
|
foreach directive in ast:
|
||||||
if directive is Source include:
|
if directive is Source include:
|
||||||
p = ResolveInclude(include.path, cur.env, fs)
|
p = ResolveInclude(include.path, cur.env, fs)
|
||||||
stack.push(Script(p))
|
stack.push(Script(p))
|
||||||
if directive is Exec call:
|
if directive is Exec call:
|
||||||
p = ResolveExec(call.argv[0], cur.env, fs)
|
p = ResolveExec(call.argv[0], cur.env, fs)
|
||||||
stack.push(Program(p, argv=call.argv))
|
stack.push(Program(p, argv=call.argv))
|
||||||
if directive is Interpreter (python -m / node / java -jar):
|
if directive is Interpreter (python -m / node / java -jar):
|
||||||
term = ResolveInterpreterTarget(call, fs)
|
term = ResolveInterpreterTarget(call, fs)
|
||||||
stack.push(Program(term))
|
stack.push(Program(term))
|
||||||
else:
|
else:
|
||||||
return Terminal(cur.path)
|
return Terminal(cur.path)
|
||||||
|
|
||||||
return Unknown(reason)
|
return Unknown(reason)
|
||||||
```
|
```
|
||||||
|
|
||||||
### Appendix A.1 — EntryTrace Explainability
|
### Appendix A.1 — EntryTrace Explainability
|
||||||
|
|
||||||
EntryTrace emits structured diagnostics and metrics so operators can quickly understand why resolution succeeded or degraded:
|
EntryTrace emits structured diagnostics and metrics so operators can quickly understand why resolution succeeded or degraded:
|
||||||
|
|
||||||
| Reason | Description | Typical Mitigation |
|
| Reason | Description | Typical Mitigation |
|
||||||
|--------|-------------|--------------------|
|
|--------|-------------|--------------------|
|
||||||
| `CommandNotFound` | A command referenced in the script cannot be located in the layered root filesystem or `PATH`. | Ensure binaries exist in the image or extend `PATH` hints. |
|
| `CommandNotFound` | A command referenced in the script cannot be located in the layered root filesystem or `PATH`. | Ensure binaries exist in the image or extend `PATH` hints. |
|
||||||
| `MissingFile` | `source`/`.`/`run-parts` targets are missing. | Bundle the script or guard the include. |
|
| `MissingFile` | `source`/`.`/`run-parts` targets are missing. | Bundle the script or guard the include. |
|
||||||
| `DynamicEnvironmentReference` | Path depends on `$VARS` that are unknown at scan time. | Provide defaults via scan metadata or accept partial usage. |
|
| `DynamicEnvironmentReference` | Path depends on `$VARS` that are unknown at scan time. | Provide defaults via scan metadata or accept partial usage. |
|
||||||
| `RecursionLimitReached` | Nested includes exceeded the analyzer depth limit (default 64). | Flatten indirection or increase the limit in options. |
|
| `RecursionLimitReached` | Nested includes exceeded the analyzer depth limit (default 64). | Flatten indirection or increase the limit in options. |
|
||||||
| `RunPartsEmpty` | `run-parts` directory contained no executable entries. | Remove empty directories or ignore if intentional. |
|
| `RunPartsEmpty` | `run-parts` directory contained no executable entries. | Remove empty directories or ignore if intentional. |
|
||||||
| `JarNotFound` / `ModuleNotFound` | Java/Python targets missing, preventing interpreter tracing. | Ship the jar/module with the image or adjust the launcher. |
|
| `JarNotFound` / `ModuleNotFound` | Java/Python targets missing, preventing interpreter tracing. | Ship the jar/module with the image or adjust the launcher. |
|
||||||
|
|
||||||
Diagnostics drive two metrics published by `EntryTraceMetrics`:
|
Diagnostics drive two metrics published by `EntryTraceMetrics`:
|
||||||
|
|
||||||
- `entrytrace_resolutions_total{outcome}` — resolution attempts segmented by outcome (`resolved`, `partiallyresolved`, `unresolved`).
|
- `entrytrace_resolutions_total{outcome}` — resolution attempts segmented by outcome (`resolved`, `partiallyresolved`, `unresolved`).
|
||||||
- `entrytrace_unresolved_total{reason}` — diagnostic counts keyed by reason.
|
- `entrytrace_unresolved_total{reason}` — diagnostic counts keyed by reason.
|
||||||
|
|
||||||
Structured logs include `entrytrace.path`, `entrytrace.command`, `entrytrace.reason`, and `entrytrace.depth`, all correlated with scan/job IDs. Timestamps are normalized to UTC (microsecond precision) to keep DSSE attestations and UI traces explainable.
|
Structured logs include `entrytrace.path`, `entrytrace.command`, `entrytrace.reason`, and `entrytrace.depth`, all correlated with scan/job IDs. Timestamps are normalized to UTC (microsecond precision) to keep DSSE attestations and UI traces explainable.
|
||||||
|
|
||||||
### Appendix B — BOM‑Index sidecar
|
### Appendix B — BOM‑Index sidecar
|
||||||
|
|
||||||
```
|
```
|
||||||
struct Header { magic, version, imageDigest, createdAt }
|
struct Header { magic, version, imageDigest, createdAt }
|
||||||
vector<string> purls
|
vector<string> purls
|
||||||
map<purlIndex, roaring_bitmap> components
|
map<purlIndex, roaring_bitmap> components
|
||||||
optional map<purlIndex, roaring_bitmap> usedByEntrypoint
|
optional map<purlIndex, roaring_bitmap> usedByEntrypoint
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -1,463 +1,463 @@
|
|||||||
# component_architecture_vexer.md — **Stella Ops Vexer** (2025Q4)
|
# component_architecture_vexer.md — **Stella Ops Vexer** (2025Q4)
|
||||||
|
|
||||||
> **Scope.** This document specifies the **Vexer** service: its purpose, trust model, data structures, APIs, plug‑in contracts, storage schema, normalization/consensus algorithms, performance budgets, testing matrix, and how it integrates with Scanner, Policy, Feedser, and the attestation chain. It is implementation‑ready.
|
> **Scope.** This document specifies the **Vexer** service: its purpose, trust model, data structures, APIs, plug‑in contracts, storage schema, normalization/consensus algorithms, performance budgets, testing matrix, and how it integrates with Scanner, Policy, Feedser, and the attestation chain. It is implementation‑ready.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 0) Mission & role in the platform
|
## 0) Mission & role in the platform
|
||||||
|
|
||||||
**Mission.** Convert heterogeneous **VEX** statements (OpenVEX, CSAF VEX, CycloneDX VEX; vendor/distro/platform sources) into **canonical, queryable claims**; compute **deterministic consensus** per *(vuln, product)*; preserve **conflicts with provenance**; publish **stable, attestable exports** that the backend uses to suppress non‑exploitable findings, prioritize remaining risk, and explain decisions.
|
**Mission.** Convert heterogeneous **VEX** statements (OpenVEX, CSAF VEX, CycloneDX VEX; vendor/distro/platform sources) into **canonical, queryable claims**; compute **deterministic consensus** per *(vuln, product)*; preserve **conflicts with provenance**; publish **stable, attestable exports** that the backend uses to suppress non‑exploitable findings, prioritize remaining risk, and explain decisions.
|
||||||
|
|
||||||
**Boundaries.**
|
**Boundaries.**
|
||||||
|
|
||||||
* Vexer **does not** decide PASS/FAIL. It supplies **evidence** (statuses + justifications + provenance weights).
|
* Vexer **does not** decide PASS/FAIL. It supplies **evidence** (statuses + justifications + provenance weights).
|
||||||
* Vexer preserves **conflicting claims** unchanged; consensus encodes how we would pick, but the raw set is always exportable.
|
* Vexer preserves **conflicting claims** unchanged; consensus encodes how we would pick, but the raw set is always exportable.
|
||||||
* VEX consumption is **backend‑only**: Scanner never applies VEX. The backend’s **Policy Engine** asks Vexer for status evidence and then decides what to show.
|
* VEX consumption is **backend‑only**: Scanner never applies VEX. The backend’s **Policy Engine** asks Vexer for status evidence and then decides what to show.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 1) Inputs, outputs & canonical domain
|
## 1) Inputs, outputs & canonical domain
|
||||||
|
|
||||||
### 1.1 Accepted input formats (ingest)
|
### 1.1 Accepted input formats (ingest)
|
||||||
|
|
||||||
* **OpenVEX** JSON documents (attested or raw).
|
* **OpenVEX** JSON documents (attested or raw).
|
||||||
* **CSAF VEX** 2.x (vendor PSIRTs and distros commonly publish CSAF).
|
* **CSAF VEX** 2.x (vendor PSIRTs and distros commonly publish CSAF).
|
||||||
* **CycloneDX VEX** 1.4+ (standalone VEX or embedded VEX blocks).
|
* **CycloneDX VEX** 1.4+ (standalone VEX or embedded VEX blocks).
|
||||||
* **OCI‑attached attestations** (VEX statements shipped as OCI referrers) — optional connectors.
|
* **OCI‑attached attestations** (VEX statements shipped as OCI referrers) — optional connectors.
|
||||||
|
|
||||||
All connectors register **source metadata**: provider identity, trust tier, signature expectations (PGP/cosign/PKI), fetch windows, rate limits, and time anchors.
|
All connectors register **source metadata**: provider identity, trust tier, signature expectations (PGP/cosign/PKI), fetch windows, rate limits, and time anchors.
|
||||||
|
|
||||||
### 1.2 Canonical model (normalized)
|
### 1.2 Canonical model (normalized)
|
||||||
|
|
||||||
Every incoming statement becomes a set of **VexClaim** records:
|
Every incoming statement becomes a set of **VexClaim** records:
|
||||||
|
|
||||||
```
|
```
|
||||||
VexClaim
|
VexClaim
|
||||||
- providerId // 'redhat', 'suse', 'ubuntu', 'github', 'vendorX'
|
- providerId // 'redhat', 'suse', 'ubuntu', 'github', 'vendorX'
|
||||||
- vulnId // 'CVE-2025-12345', 'GHSA-xxxx', canonicalized
|
- vulnId // 'CVE-2025-12345', 'GHSA-xxxx', canonicalized
|
||||||
- productKey // canonical product identity (see §2.2)
|
- productKey // canonical product identity (see §2.2)
|
||||||
- status // affected | not_affected | fixed | under_investigation
|
- status // affected | not_affected | fixed | under_investigation
|
||||||
- justification? // for 'not_affected'/'affected' where provided
|
- justification? // for 'not_affected'/'affected' where provided
|
||||||
- introducedVersion? // semantics per provider (range or exact)
|
- introducedVersion? // semantics per provider (range or exact)
|
||||||
- fixedVersion? // where provided (range or exact)
|
- fixedVersion? // where provided (range or exact)
|
||||||
- lastObserved // timestamp from source or fetch time
|
- lastObserved // timestamp from source or fetch time
|
||||||
- provenance // doc digest, signature status, fetch URI, line/offset anchors
|
- provenance // doc digest, signature status, fetch URI, line/offset anchors
|
||||||
- evidence[] // raw source snippets for explainability
|
- evidence[] // raw source snippets for explainability
|
||||||
- supersedes? // optional cross-doc chain (docDigest → docDigest)
|
- supersedes? // optional cross-doc chain (docDigest → docDigest)
|
||||||
```
|
```
|
||||||
|
|
||||||
### 1.3 Exports (consumption)
|
### 1.3 Exports (consumption)
|
||||||
|
|
||||||
* **VexConsensus** per `(vulnId, productKey)` with:
|
* **VexConsensus** per `(vulnId, productKey)` with:
|
||||||
|
|
||||||
* `rollupStatus` (after policy weights/justification gates),
|
* `rollupStatus` (after policy weights/justification gates),
|
||||||
* `sources[]` (winning + losing claims with weights & reasons),
|
* `sources[]` (winning + losing claims with weights & reasons),
|
||||||
* `policyRevisionId` (identifier of the Vexer policy used),
|
* `policyRevisionId` (identifier of the Vexer policy used),
|
||||||
* `consensusDigest` (stable SHA‑256 over canonical JSON).
|
* `consensusDigest` (stable SHA‑256 over canonical JSON).
|
||||||
* **Raw claims** export for auditing (unchanged, with provenance).
|
* **Raw claims** export for auditing (unchanged, with provenance).
|
||||||
* **Provider snapshots** (per source, last N days) for operator debugging.
|
* **Provider snapshots** (per source, last N days) for operator debugging.
|
||||||
* **Index** optimized for backend joins: `(productKey, vulnId) → (status, confidence, sourceSet)`.
|
* **Index** optimized for backend joins: `(productKey, vulnId) → (status, confidence, sourceSet)`.
|
||||||
|
|
||||||
All exports are **deterministic**, and (optionally) **attested** via DSSE and logged to Rekor v2.
|
All exports are **deterministic**, and (optionally) **attested** via DSSE and logged to Rekor v2.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 2) Identity model — products & joins
|
## 2) Identity model — products & joins
|
||||||
|
|
||||||
### 2.1 Vuln identity
|
### 2.1 Vuln identity
|
||||||
|
|
||||||
* Accepts **CVE**, **GHSA**, vendor IDs (MSRC, RHSA…), distro IDs (DSA/USN/RHSA…) — normalized to `vulnId` with alias sets.
|
* Accepts **CVE**, **GHSA**, vendor IDs (MSRC, RHSA…), distro IDs (DSA/USN/RHSA…) — normalized to `vulnId` with alias sets.
|
||||||
* **Alias graph** maintained (from Feedser) to map vendor/distro IDs → CVE (primary) and to **GHSA** where applicable.
|
* **Alias graph** maintained (from Feedser) to map vendor/distro IDs → CVE (primary) and to **GHSA** where applicable.
|
||||||
|
|
||||||
### 2.2 Product identity (`productKey`)
|
### 2.2 Product identity (`productKey`)
|
||||||
|
|
||||||
* **Primary:** `purl` (Package URL).
|
* **Primary:** `purl` (Package URL).
|
||||||
* **Secondary links:** `cpe`, **OS package NVRA/EVR**, NuGet/Maven/Golang identity, and **OS package name** when purl unavailable.
|
* **Secondary links:** `cpe`, **OS package NVRA/EVR**, NuGet/Maven/Golang identity, and **OS package name** when purl unavailable.
|
||||||
* **Fallback:** `oci:<registry>/<repo>@<digest>` for image‑level VEX.
|
* **Fallback:** `oci:<registry>/<repo>@<digest>` for image‑level VEX.
|
||||||
* **Special cases:** kernel modules, firmware, platforms → provider‑specific mapping helpers (connector captures provider’s product taxonomy → canonical `productKey`).
|
* **Special cases:** kernel modules, firmware, platforms → provider‑specific mapping helpers (connector captures provider’s product taxonomy → canonical `productKey`).
|
||||||
|
|
||||||
> Vexer does not invent identities. If a provider cannot be mapped to purl/CPE/NVRA deterministically, we keep the native **product string** and mark the claim as **non‑joinable**; the backend will ignore it unless a policy explicitly whitelists that provider mapping.
|
> Vexer does not invent identities. If a provider cannot be mapped to purl/CPE/NVRA deterministically, we keep the native **product string** and mark the claim as **non‑joinable**; the backend will ignore it unless a policy explicitly whitelists that provider mapping.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 3) Storage schema (MongoDB)
|
## 3) Storage schema (MongoDB)
|
||||||
|
|
||||||
Database: `vexer`
|
Database: `vexer`
|
||||||
|
|
||||||
### 3.1 Collections
|
### 3.1 Collections
|
||||||
|
|
||||||
**`vex.providers`**
|
**`vex.providers`**
|
||||||
|
|
||||||
```
|
```
|
||||||
_id: providerId
|
_id: providerId
|
||||||
name, homepage, contact
|
name, homepage, contact
|
||||||
trustTier: enum {vendor, distro, platform, hub, attestation}
|
trustTier: enum {vendor, distro, platform, hub, attestation}
|
||||||
signaturePolicy: { type: pgp|cosign|x509|none, keys[], certs[], cosignKeylessRoots[] }
|
signaturePolicy: { type: pgp|cosign|x509|none, keys[], certs[], cosignKeylessRoots[] }
|
||||||
fetch: { baseUrl, kind: http|oci|file, rateLimit, etagSupport, windowDays }
|
fetch: { baseUrl, kind: http|oci|file, rateLimit, etagSupport, windowDays }
|
||||||
enabled: bool
|
enabled: bool
|
||||||
createdAt, modifiedAt
|
createdAt, modifiedAt
|
||||||
```
|
```
|
||||||
|
|
||||||
**`vex.raw`** (immutable raw documents)
|
**`vex.raw`** (immutable raw documents)
|
||||||
|
|
||||||
```
|
```
|
||||||
_id: sha256(doc bytes)
|
_id: sha256(doc bytes)
|
||||||
providerId
|
providerId
|
||||||
uri
|
uri
|
||||||
ingestedAt
|
ingestedAt
|
||||||
contentType
|
contentType
|
||||||
sig: { verified: bool, method: pgp|cosign|x509|none, keyId|certSubject, bundle? }
|
sig: { verified: bool, method: pgp|cosign|x509|none, keyId|certSubject, bundle? }
|
||||||
payload: GridFS pointer (if large)
|
payload: GridFS pointer (if large)
|
||||||
disposition: kept|replaced|superseded
|
disposition: kept|replaced|superseded
|
||||||
correlation: { replaces?: sha256, replacedBy?: sha256 }
|
correlation: { replaces?: sha256, replacedBy?: sha256 }
|
||||||
```
|
```
|
||||||
|
|
||||||
**`vex.claims`** (normalized rows; dedupe on providerId+vulnId+productKey+docDigest)
|
**`vex.claims`** (normalized rows; dedupe on providerId+vulnId+productKey+docDigest)
|
||||||
|
|
||||||
```
|
```
|
||||||
_id
|
_id
|
||||||
providerId
|
providerId
|
||||||
vulnId
|
vulnId
|
||||||
productKey
|
productKey
|
||||||
status
|
status
|
||||||
justification?
|
justification?
|
||||||
introducedVersion?
|
introducedVersion?
|
||||||
fixedVersion?
|
fixedVersion?
|
||||||
lastObserved
|
lastObserved
|
||||||
docDigest
|
docDigest
|
||||||
provenance { uri, line?, pointer?, signatureState }
|
provenance { uri, line?, pointer?, signatureState }
|
||||||
evidence[] { key, value, locator }
|
evidence[] { key, value, locator }
|
||||||
indices:
|
indices:
|
||||||
- {vulnId:1, productKey:1}
|
- {vulnId:1, productKey:1}
|
||||||
- {providerId:1, lastObserved:-1}
|
- {providerId:1, lastObserved:-1}
|
||||||
- {status:1}
|
- {status:1}
|
||||||
- text index (optional) on evidence.value for debugging
|
- text index (optional) on evidence.value for debugging
|
||||||
```
|
```
|
||||||
|
|
||||||
**`vex.consensus`** (rollups)
|
**`vex.consensus`** (rollups)
|
||||||
|
|
||||||
```
|
```
|
||||||
_id: sha256(canonical(vulnId, productKey, policyRevision))
|
_id: sha256(canonical(vulnId, productKey, policyRevision))
|
||||||
vulnId
|
vulnId
|
||||||
productKey
|
productKey
|
||||||
rollupStatus
|
rollupStatus
|
||||||
sources[]: [
|
sources[]: [
|
||||||
{ providerId, status, justification?, weight, lastObserved, accepted:bool, reason }
|
{ providerId, status, justification?, weight, lastObserved, accepted:bool, reason }
|
||||||
]
|
]
|
||||||
policyRevisionId
|
policyRevisionId
|
||||||
evaluatedAt
|
evaluatedAt
|
||||||
consensusDigest // same as _id
|
consensusDigest // same as _id
|
||||||
indices:
|
indices:
|
||||||
- {vulnId:1, productKey:1}
|
- {vulnId:1, productKey:1}
|
||||||
- {policyRevisionId:1, evaluatedAt:-1}
|
- {policyRevisionId:1, evaluatedAt:-1}
|
||||||
```
|
```
|
||||||
|
|
||||||
**`vex.exports`** (manifest of emitted artifacts)
|
**`vex.exports`** (manifest of emitted artifacts)
|
||||||
|
|
||||||
```
|
```
|
||||||
_id
|
_id
|
||||||
querySignature
|
querySignature
|
||||||
format: raw|consensus|index
|
format: raw|consensus|index
|
||||||
artifactSha256
|
artifactSha256
|
||||||
rekor { uuid, index, url }?
|
rekor { uuid, index, url }?
|
||||||
createdAt
|
createdAt
|
||||||
policyRevisionId
|
policyRevisionId
|
||||||
cacheable: bool
|
cacheable: bool
|
||||||
```
|
```
|
||||||
|
|
||||||
**`vex.cache`**
|
**`vex.cache`**
|
||||||
|
|
||||||
```
|
```
|
||||||
querySignature -> exportId (for fast reuse)
|
querySignature -> exportId (for fast reuse)
|
||||||
ttl, hits
|
ttl, hits
|
||||||
```
|
```
|
||||||
|
|
||||||
**`vex.migrations`**
|
**`vex.migrations`**
|
||||||
|
|
||||||
* ordered migrations applied at bootstrap to ensure indexes.
|
* ordered migrations applied at bootstrap to ensure indexes.
|
||||||
|
|
||||||
### 3.2 Indexing strategy
|
### 3.2 Indexing strategy
|
||||||
|
|
||||||
* Hot path queries use exact `(vulnId, productKey)` and time‑bounded windows; compound indexes cover both.
|
* Hot path queries use exact `(vulnId, productKey)` and time‑bounded windows; compound indexes cover both.
|
||||||
* Providers list view by `lastObserved` for monitoring staleness.
|
* Providers list view by `lastObserved` for monitoring staleness.
|
||||||
* `vex.consensus` keyed by `(vulnId, productKey, policyRevision)` for deterministic reuse.
|
* `vex.consensus` keyed by `(vulnId, productKey, policyRevision)` for deterministic reuse.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 4) Ingestion pipeline
|
## 4) Ingestion pipeline
|
||||||
|
|
||||||
### 4.1 Connector contract
|
### 4.1 Connector contract
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
public interface IVexConnector
|
public interface IVexConnector
|
||||||
{
|
{
|
||||||
string ProviderId { get; }
|
string ProviderId { get; }
|
||||||
Task FetchAsync(VexConnectorContext ctx, CancellationToken ct); // raw docs
|
Task FetchAsync(VexConnectorContext ctx, CancellationToken ct); // raw docs
|
||||||
Task NormalizeAsync(VexConnectorContext ctx, CancellationToken ct); // raw -> VexClaim[]
|
Task NormalizeAsync(VexConnectorContext ctx, CancellationToken ct); // raw -> VexClaim[]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
* **Fetch** must implement: window scheduling, conditional GET (ETag/If‑Modified‑Since), rate limiting, retry/backoff.
|
* **Fetch** must implement: window scheduling, conditional GET (ETag/If‑Modified‑Since), rate limiting, retry/backoff.
|
||||||
* **Normalize** parses the format, validates schema, maps product identities deterministically, emits `VexClaim` records with **provenance**.
|
* **Normalize** parses the format, validates schema, maps product identities deterministically, emits `VexClaim` records with **provenance**.
|
||||||
|
|
||||||
### 4.2 Signature verification (per provider)
|
### 4.2 Signature verification (per provider)
|
||||||
|
|
||||||
* **cosign (keyless or keyful)** for OCI referrers or HTTP‑served JSON with Sigstore bundles.
|
* **cosign (keyless or keyful)** for OCI referrers or HTTP‑served JSON with Sigstore bundles.
|
||||||
* **PGP** (provider keyrings) for distro/vendor feeds that sign docs.
|
* **PGP** (provider keyrings) for distro/vendor feeds that sign docs.
|
||||||
* **x509** (mutual TLS / provider‑pinned certs) where applicable.
|
* **x509** (mutual TLS / provider‑pinned certs) where applicable.
|
||||||
* Signature state is stored on **vex.raw.sig** and copied into **provenance.signatureState** on claims.
|
* Signature state is stored on **vex.raw.sig** and copied into **provenance.signatureState** on claims.
|
||||||
|
|
||||||
> Claims from sources failing signature policy are marked `"signatureState.verified=false"` and **policy** can down‑weight or ignore them.
|
> Claims from sources failing signature policy are marked `"signatureState.verified=false"` and **policy** can down‑weight or ignore them.
|
||||||
|
|
||||||
### 4.3 Time discipline
|
### 4.3 Time discipline
|
||||||
|
|
||||||
* For each doc, prefer **provider’s document timestamp**; if absent, use fetch time.
|
* For each doc, prefer **provider’s document timestamp**; if absent, use fetch time.
|
||||||
* Claims carry `lastObserved` which drives **tie‑breaking** within equal weight tiers.
|
* Claims carry `lastObserved` which drives **tie‑breaking** within equal weight tiers.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 5) Normalization: product & status semantics
|
## 5) Normalization: product & status semantics
|
||||||
|
|
||||||
### 5.1 Product mapping
|
### 5.1 Product mapping
|
||||||
|
|
||||||
* **purl** first; **cpe** second; OS package NVRA/EVR mapping helpers (distro connectors) produce purls via canonical tables (e.g., rpm→purl:rpm, deb→purl:deb).
|
* **purl** first; **cpe** second; OS package NVRA/EVR mapping helpers (distro connectors) produce purls via canonical tables (e.g., rpm→purl:rpm, deb→purl:deb).
|
||||||
* Where a provider publishes **platform‑level** VEX (e.g., “RHEL 9 not affected”), connectors expand to known product inventory rules (e.g., map to sets of packages/components shipped in the platform). Expansion tables are versioned and kept per provider; every expansion emits **evidence** indicating the rule applied.
|
* Where a provider publishes **platform‑level** VEX (e.g., “RHEL 9 not affected”), connectors expand to known product inventory rules (e.g., map to sets of packages/components shipped in the platform). Expansion tables are versioned and kept per provider; every expansion emits **evidence** indicating the rule applied.
|
||||||
* If expansion would be speculative, the claim remains **platform‑scoped** with `productKey="platform:redhat:rhel:9"` and is flagged **non‑joinable**; backend can decide to use platform VEX only when Scanner proves the platform runtime.
|
* If expansion would be speculative, the claim remains **platform‑scoped** with `productKey="platform:redhat:rhel:9"` and is flagged **non‑joinable**; backend can decide to use platform VEX only when Scanner proves the platform runtime.
|
||||||
|
|
||||||
### 5.2 Status + justification mapping
|
### 5.2 Status + justification mapping
|
||||||
|
|
||||||
* Canonical **status**: `affected | not_affected | fixed | under_investigation`.
|
* Canonical **status**: `affected | not_affected | fixed | under_investigation`.
|
||||||
* **Justifications** normalized to a controlled vocabulary (CISA‑aligned), e.g.:
|
* **Justifications** normalized to a controlled vocabulary (CISA‑aligned), e.g.:
|
||||||
|
|
||||||
* `component_not_present`
|
* `component_not_present`
|
||||||
* `vulnerable_code_not_in_execute_path`
|
* `vulnerable_code_not_in_execute_path`
|
||||||
* `vulnerable_configuration_unused`
|
* `vulnerable_configuration_unused`
|
||||||
* `inline_mitigation_applied`
|
* `inline_mitigation_applied`
|
||||||
* `fix_available` (with `fixedVersion`)
|
* `fix_available` (with `fixedVersion`)
|
||||||
* `under_investigation`
|
* `under_investigation`
|
||||||
* Providers with free‑text justifications are mapped by deterministic tables; raw text preserved as `evidence`.
|
* Providers with free‑text justifications are mapped by deterministic tables; raw text preserved as `evidence`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 6) Consensus algorithm
|
## 6) Consensus algorithm
|
||||||
|
|
||||||
**Goal:** produce a **stable**, explainable `rollupStatus` per `(vulnId, productKey)` given possibly conflicting claims.
|
**Goal:** produce a **stable**, explainable `rollupStatus` per `(vulnId, productKey)` given possibly conflicting claims.
|
||||||
|
|
||||||
### 6.1 Inputs
|
### 6.1 Inputs
|
||||||
|
|
||||||
* Set **S** of `VexClaim` for the key.
|
* Set **S** of `VexClaim` for the key.
|
||||||
* **Vexer policy snapshot**:
|
* **Vexer policy snapshot**:
|
||||||
|
|
||||||
* **weights** per provider tier and per provider overrides.
|
* **weights** per provider tier and per provider overrides.
|
||||||
* **justification gates** (e.g., require justification for `not_affected` to be acceptable).
|
* **justification gates** (e.g., require justification for `not_affected` to be acceptable).
|
||||||
* **minEvidence** rules (e.g., `not_affected` must come from ≥1 vendor or 2 distros).
|
* **minEvidence** rules (e.g., `not_affected` must come from ≥1 vendor or 2 distros).
|
||||||
* **signature requirements** (e.g., require verified signature for ‘fixed’ to be considered).
|
* **signature requirements** (e.g., require verified signature for ‘fixed’ to be considered).
|
||||||
|
|
||||||
### 6.2 Steps
|
### 6.2 Steps
|
||||||
|
|
||||||
1. **Filter invalid** claims by signature policy & justification gates → set `S'`.
|
1. **Filter invalid** claims by signature policy & justification gates → set `S'`.
|
||||||
2. **Score** each claim:
|
2. **Score** each claim:
|
||||||
`score = weight(provider) * freshnessFactor(lastObserved)` where freshnessFactor ∈ [0.8, 1.0] for staleness decay (configurable; small effect).
|
`score = weight(provider) * freshnessFactor(lastObserved)` where freshnessFactor ∈ [0.8, 1.0] for staleness decay (configurable; small effect).
|
||||||
3. **Aggregate** scores per status: `W(status) = Σ score(claims with that status)`.
|
3. **Aggregate** scores per status: `W(status) = Σ score(claims with that status)`.
|
||||||
4. **Pick** `rollupStatus = argmax_status W(status)`.
|
4. **Pick** `rollupStatus = argmax_status W(status)`.
|
||||||
5. **Tie‑breakers** (in order):
|
5. **Tie‑breakers** (in order):
|
||||||
|
|
||||||
* Higher **max single** provider score wins (vendor > distro > platform > hub).
|
* Higher **max single** provider score wins (vendor > distro > platform > hub).
|
||||||
* More **recent** lastObserved wins.
|
* More **recent** lastObserved wins.
|
||||||
* Deterministic lexicographic order of status (`fixed` > `not_affected` > `under_investigation` > `affected`) as final tiebreaker.
|
* Deterministic lexicographic order of status (`fixed` > `not_affected` > `under_investigation` > `affected`) as final tiebreaker.
|
||||||
6. **Explain**: mark accepted sources (`accepted=true; reason="weight"`/`"freshness"`), mark rejected sources with explicit `reason` (`"insufficient_justification"`, `"signature_unverified"`, `"lower_weight"`).
|
6. **Explain**: mark accepted sources (`accepted=true; reason="weight"`/`"freshness"`), mark rejected sources with explicit `reason` (`"insufficient_justification"`, `"signature_unverified"`, `"lower_weight"`).
|
||||||
|
|
||||||
> The algorithm is **pure** given S and policy snapshot; result is reproducible and hashed into `consensusDigest`.
|
> The algorithm is **pure** given S and policy snapshot; result is reproducible and hashed into `consensusDigest`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 7) Query & export APIs
|
## 7) Query & export APIs
|
||||||
|
|
||||||
All endpoints are versioned under `/api/v1/vex`.
|
All endpoints are versioned under `/api/v1/vex`.
|
||||||
|
|
||||||
### 7.1 Query (online)
|
### 7.1 Query (online)
|
||||||
|
|
||||||
```
|
```
|
||||||
POST /claims/search
|
POST /claims/search
|
||||||
body: { vulnIds?: string[], productKeys?: string[], providers?: string[], since?: timestamp, limit?: int, pageToken?: string }
|
body: { vulnIds?: string[], productKeys?: string[], providers?: string[], since?: timestamp, limit?: int, pageToken?: string }
|
||||||
→ { claims[], nextPageToken? }
|
→ { claims[], nextPageToken? }
|
||||||
|
|
||||||
POST /consensus/search
|
POST /consensus/search
|
||||||
body: { vulnIds?: string[], productKeys?: string[], policyRevisionId?: string, since?: timestamp, limit?: int, pageToken?: string }
|
body: { vulnIds?: string[], productKeys?: string[], policyRevisionId?: string, since?: timestamp, limit?: int, pageToken?: string }
|
||||||
→ { entries[], nextPageToken? }
|
→ { entries[], nextPageToken? }
|
||||||
|
|
||||||
POST /excititor/resolve (scope: vex.read)
|
POST /excititor/resolve (scope: vex.read)
|
||||||
body: { productKeys?: string[], purls?: string[], vulnerabilityIds: string[], policyRevisionId?: string }
|
body: { productKeys?: string[], purls?: string[], vulnerabilityIds: string[], policyRevisionId?: string }
|
||||||
→ { policy, resolvedAt, results: [ { vulnerabilityId, productKey, status, sources[], conflicts[], decisions[], signals?, summary?, envelope: { artifact, contentSignature?, attestation?, attestationEnvelope?, attestationSignature? } } ] }
|
→ { policy, resolvedAt, results: [ { vulnerabilityId, productKey, status, sources[], conflicts[], decisions[], signals?, summary?, envelope: { artifact, contentSignature?, attestation?, attestationEnvelope?, attestationSignature? } } ] }
|
||||||
```
|
```
|
||||||
|
|
||||||
### 7.2 Exports (cacheable snapshots)
|
### 7.2 Exports (cacheable snapshots)
|
||||||
|
|
||||||
```
|
```
|
||||||
POST /exports
|
POST /exports
|
||||||
body: { signature: { vulnFilter?, productFilter?, providers?, since? }, format: raw|consensus|index, policyRevisionId?: string, force?: bool }
|
body: { signature: { vulnFilter?, productFilter?, providers?, since? }, format: raw|consensus|index, policyRevisionId?: string, force?: bool }
|
||||||
→ { exportId, artifactSha256, rekor? }
|
→ { exportId, artifactSha256, rekor? }
|
||||||
|
|
||||||
GET /exports/{exportId} → bytes (application/json or binary index)
|
GET /exports/{exportId} → bytes (application/json or binary index)
|
||||||
GET /exports/{exportId}/meta → { signature, policyRevisionId, createdAt, artifactSha256, rekor? }
|
GET /exports/{exportId}/meta → { signature, policyRevisionId, createdAt, artifactSha256, rekor? }
|
||||||
```
|
```
|
||||||
|
|
||||||
### 7.3 Provider operations
|
### 7.3 Provider operations
|
||||||
|
|
||||||
```
|
```
|
||||||
GET /providers → provider list & signature policy
|
GET /providers → provider list & signature policy
|
||||||
POST /providers/{id}/refresh → trigger fetch/normalize window
|
POST /providers/{id}/refresh → trigger fetch/normalize window
|
||||||
GET /providers/{id}/status → last fetch, doc counts, signature stats
|
GET /providers/{id}/status → last fetch, doc counts, signature stats
|
||||||
```
|
```
|
||||||
|
|
||||||
**Auth:** service‑to‑service via Authority tokens; operator operations via UI/CLI with RBAC.
|
**Auth:** service‑to‑service via Authority tokens; operator operations via UI/CLI with RBAC.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 8) Attestation integration
|
## 8) Attestation integration
|
||||||
|
|
||||||
* Exports can be **DSSE‑signed** via **Signer** and logged to **Rekor v2** via **Attestor** (optional but recommended for regulated pipelines).
|
* Exports can be **DSSE‑signed** via **Signer** and logged to **Rekor v2** via **Attestor** (optional but recommended for regulated pipelines).
|
||||||
* `vex.exports.rekor` stores `{uuid, index, url}` when present.
|
* `vex.exports.rekor` stores `{uuid, index, url}` when present.
|
||||||
* **Predicate type**: `https://stella-ops.org/attestations/vex-export/1` with fields:
|
* **Predicate type**: `https://stella-ops.org/attestations/vex-export/1` with fields:
|
||||||
|
|
||||||
* `querySignature`, `policyRevisionId`, `artifactSha256`, `createdAt`.
|
* `querySignature`, `policyRevisionId`, `artifactSha256`, `createdAt`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 9) Configuration (YAML)
|
## 9) Configuration (YAML)
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
vexer:
|
vexer:
|
||||||
mongo: { uri: "mongodb://mongo/vexer" }
|
mongo: { uri: "mongodb://mongo/vexer" }
|
||||||
s3:
|
s3:
|
||||||
endpoint: http://minio:9000
|
endpoint: http://minio:9000
|
||||||
bucket: stellaops
|
bucket: stellaops
|
||||||
policy:
|
policy:
|
||||||
weights:
|
weights:
|
||||||
vendor: 1.0
|
vendor: 1.0
|
||||||
distro: 0.9
|
distro: 0.9
|
||||||
platform: 0.7
|
platform: 0.7
|
||||||
hub: 0.5
|
hub: 0.5
|
||||||
attestation: 0.6
|
attestation: 0.6
|
||||||
providerOverrides:
|
providerOverrides:
|
||||||
redhat: 1.0
|
redhat: 1.0
|
||||||
suse: 0.95
|
suse: 0.95
|
||||||
requireJustificationForNotAffected: true
|
requireJustificationForNotAffected: true
|
||||||
signatureRequiredForFixed: true
|
signatureRequiredForFixed: true
|
||||||
minEvidence:
|
minEvidence:
|
||||||
not_affected:
|
not_affected:
|
||||||
vendorOrTwoDistros: true
|
vendorOrTwoDistros: true
|
||||||
connectors:
|
connectors:
|
||||||
- providerId: redhat
|
- providerId: redhat
|
||||||
kind: csaf
|
kind: csaf
|
||||||
baseUrl: https://access.redhat.com/security/data/csaf/v2/
|
baseUrl: https://access.redhat.com/security/data/csaf/v2/
|
||||||
signaturePolicy: { type: pgp, keys: [ "…redhat-pgp-key…" ] }
|
signaturePolicy: { type: pgp, keys: [ "…redhat-pgp-key…" ] }
|
||||||
windowDays: 7
|
windowDays: 7
|
||||||
- providerId: suse
|
- providerId: suse
|
||||||
kind: csaf
|
kind: csaf
|
||||||
baseUrl: https://ftp.suse.com/pub/projects/security/csaf/
|
baseUrl: https://ftp.suse.com/pub/projects/security/csaf/
|
||||||
signaturePolicy: { type: pgp, keys: [ "…suse-pgp-key…" ] }
|
signaturePolicy: { type: pgp, keys: [ "…suse-pgp-key…" ] }
|
||||||
- providerId: ubuntu
|
- providerId: ubuntu
|
||||||
kind: openvex
|
kind: openvex
|
||||||
baseUrl: https://…/vex/
|
baseUrl: https://…/vex/
|
||||||
signaturePolicy: { type: none }
|
signaturePolicy: { type: none }
|
||||||
- providerId: vendorX
|
- providerId: vendorX
|
||||||
kind: cyclonedx-vex
|
kind: cyclonedx-vex
|
||||||
ociRef: ghcr.io/vendorx/vex@sha256:…
|
ociRef: ghcr.io/vendorx/vex@sha256:…
|
||||||
signaturePolicy: { type: cosign, cosignKeylessRoots: [ "sigstore-root" ] }
|
signaturePolicy: { type: cosign, cosignKeylessRoots: [ "sigstore-root" ] }
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 10) Security model
|
## 10) Security model
|
||||||
|
|
||||||
* **Input signature verification** enforced per provider policy (PGP, cosign, x509).
|
* **Input signature verification** enforced per provider policy (PGP, cosign, x509).
|
||||||
* **Connector allowlists**: outbound fetch constrained to configured domains.
|
* **Connector allowlists**: outbound fetch constrained to configured domains.
|
||||||
* **Tenant isolation**: per‑tenant DB prefixes or separate DBs; per‑tenant S3 prefixes; per‑tenant policies.
|
* **Tenant isolation**: per‑tenant DB prefixes or separate DBs; per‑tenant S3 prefixes; per‑tenant policies.
|
||||||
* **AuthN/Z**: Authority‑issued OpToks; RBAC roles (`vex.read`, `vex.admin`, `vex.export`).
|
* **AuthN/Z**: Authority‑issued OpToks; RBAC roles (`vex.read`, `vex.admin`, `vex.export`).
|
||||||
* **No secrets in logs**; deterministic logging contexts include providerId, docDigest, claim keys.
|
* **No secrets in logs**; deterministic logging contexts include providerId, docDigest, claim keys.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 11) Performance & scale
|
## 11) Performance & scale
|
||||||
|
|
||||||
* **Targets:**
|
* **Targets:**
|
||||||
|
|
||||||
* Normalize 10k VEX claims/minute/core.
|
* Normalize 10k VEX claims/minute/core.
|
||||||
* Consensus compute ≤ 50 ms for 1k unique `(vuln, product)` pairs in hot cache.
|
* Consensus compute ≤ 50 ms for 1k unique `(vuln, product)` pairs in hot cache.
|
||||||
* Export (consensus) 1M rows in ≤ 60 s on 8 cores with streaming writer.
|
* Export (consensus) 1M rows in ≤ 60 s on 8 cores with streaming writer.
|
||||||
|
|
||||||
* **Scaling:**
|
* **Scaling:**
|
||||||
|
|
||||||
* WebService handles control APIs; **Worker** background services (same image) execute fetch/normalize in parallel with rate‑limits; Mongo writes batched; upserts by natural keys.
|
* WebService handles control APIs; **Worker** background services (same image) execute fetch/normalize in parallel with rate‑limits; Mongo writes batched; upserts by natural keys.
|
||||||
* Exports stream straight to S3 (MinIO) with rolling buffers.
|
* Exports stream straight to S3 (MinIO) with rolling buffers.
|
||||||
|
|
||||||
* **Caching:**
|
* **Caching:**
|
||||||
|
|
||||||
* `vex.cache` maps query signatures → export; TTL to avoid stampedes; optimistic reuse unless `force`.
|
* `vex.cache` maps query signatures → export; TTL to avoid stampedes; optimistic reuse unless `force`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 12) Observability
|
## 12) Observability
|
||||||
|
|
||||||
* **Metrics:**
|
* **Metrics:**
|
||||||
|
|
||||||
* `vex.ingest.docs_total{provider}`
|
* `vex.ingest.docs_total{provider}`
|
||||||
* `vex.normalize.claims_total{provider}`
|
* `vex.normalize.claims_total{provider}`
|
||||||
* `vex.signature.failures_total{provider,method}`
|
* `vex.signature.failures_total{provider,method}`
|
||||||
* `vex.consensus.conflicts_total{vulnId}`
|
* `vex.consensus.conflicts_total{vulnId}`
|
||||||
* `vex.exports.bytes{format}` / `vex.exports.latency_seconds`
|
* `vex.exports.bytes{format}` / `vex.exports.latency_seconds`
|
||||||
* **Tracing:** spans for fetch, verify, parse, map, consensus, export.
|
* **Tracing:** spans for fetch, verify, parse, map, consensus, export.
|
||||||
* **Dashboards:** provider staleness, top conflicting vulns/components, signature posture, export cache hit‑rate.
|
* **Dashboards:** provider staleness, top conflicting vulns/components, signature posture, export cache hit‑rate.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 13) Testing matrix
|
## 13) Testing matrix
|
||||||
|
|
||||||
* **Connectors:** golden raw docs → deterministic claims (fixtures per provider/format).
|
* **Connectors:** golden raw docs → deterministic claims (fixtures per provider/format).
|
||||||
* **Signature policies:** valid/invalid PGP/cosign/x509 samples; ensure rejects are recorded but not accepted.
|
* **Signature policies:** valid/invalid PGP/cosign/x509 samples; ensure rejects are recorded but not accepted.
|
||||||
* **Normalization edge cases:** platform‑only claims, free‑text justifications, non‑purl products.
|
* **Normalization edge cases:** platform‑only claims, free‑text justifications, non‑purl products.
|
||||||
* **Consensus:** conflict scenarios across tiers; check tie‑breakers; justification gates.
|
* **Consensus:** conflict scenarios across tiers; check tie‑breakers; justification gates.
|
||||||
* **Performance:** 1M‑row export timing; memory ceilings; stream correctness.
|
* **Performance:** 1M‑row export timing; memory ceilings; stream correctness.
|
||||||
* **Determinism:** same inputs + policy → identical `consensusDigest` and export bytes.
|
* **Determinism:** same inputs + policy → identical `consensusDigest` and export bytes.
|
||||||
* **API contract tests:** pagination, filters, RBAC, rate limits.
|
* **API contract tests:** pagination, filters, RBAC, rate limits.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 14) Integration points
|
## 14) Integration points
|
||||||
|
|
||||||
* **Backend Policy Engine** (in Scanner.WebService): calls `POST /excititor/resolve` (scope `vex.read`) with batched `(purl, vulnId)` pairs to fetch `rollupStatus + sources`.
|
* **Backend Policy Engine** (in Scanner.WebService): calls `POST /excititor/resolve` (scope `vex.read`) with batched `(purl, vulnId)` pairs to fetch `rollupStatus + sources`.
|
||||||
* **Feedser**: provides alias graph (CVE↔vendor IDs) and may supply VEX‑adjacent metadata (e.g., KEV flag) for policy escalation.
|
* **Feedser**: provides alias graph (CVE↔vendor IDs) and may supply VEX‑adjacent metadata (e.g., KEV flag) for policy escalation.
|
||||||
* **UI**: VEX explorer screens use `/claims/search` and `/consensus/search`; show conflicts & provenance.
|
* **UI**: VEX explorer screens use `/claims/search` and `/consensus/search`; show conflicts & provenance.
|
||||||
* **CLI**: `stellaops vex export --consensus --since 7d --out vex.json` for audits.
|
* **CLI**: `stellaops vex export --consensus --since 7d --out vex.json` for audits.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 15) Failure modes & fallback
|
## 15) Failure modes & fallback
|
||||||
|
|
||||||
* **Provider unreachable:** stale thresholds trigger warnings; policy can down‑weight stale providers automatically (freshness factor).
|
* **Provider unreachable:** stale thresholds trigger warnings; policy can down‑weight stale providers automatically (freshness factor).
|
||||||
* **Signature outage:** continue to ingest but mark `signatureState.verified=false`; consensus will likely exclude or down‑weight per policy.
|
* **Signature outage:** continue to ingest but mark `signatureState.verified=false`; consensus will likely exclude or down‑weight per policy.
|
||||||
* **Schema drift:** unknown fields are preserved as `evidence`; normalization rejects only on **invalid identity** or **status**.
|
* **Schema drift:** unknown fields are preserved as `evidence`; normalization rejects only on **invalid identity** or **status**.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 16) Rollout plan (incremental)
|
## 16) Rollout plan (incremental)
|
||||||
|
|
||||||
1. **MVP**: OpenVEX + CSAF connectors for 3 major providers (e.g., Red Hat/SUSE/Ubuntu), normalization + consensus + `/excititor/resolve`.
|
1. **MVP**: OpenVEX + CSAF connectors for 3 major providers (e.g., Red Hat/SUSE/Ubuntu), normalization + consensus + `/excititor/resolve`.
|
||||||
2. **Signature policies**: PGP for distros; cosign for OCI.
|
2. **Signature policies**: PGP for distros; cosign for OCI.
|
||||||
3. **Exports + optional attestation**.
|
3. **Exports + optional attestation**.
|
||||||
4. **CycloneDX VEX** connectors; platform claim expansion tables; UI explorer.
|
4. **CycloneDX VEX** connectors; platform claim expansion tables; UI explorer.
|
||||||
5. **Scale hardening**: export indexes; conflict analytics.
|
5. **Scale hardening**: export indexes; conflict analytics.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 17) Appendix — canonical JSON (stable ordering)
|
## 17) Appendix — canonical JSON (stable ordering)
|
||||||
|
|
||||||
All exports and consensus entries are serialized via `VexCanonicalJsonSerializer`:
|
All exports and consensus entries are serialized via `VexCanonicalJsonSerializer`:
|
||||||
|
|
||||||
* UTF‑8 without BOM;
|
* UTF‑8 without BOM;
|
||||||
* keys sorted (ASCII);
|
* keys sorted (ASCII);
|
||||||
* arrays sorted by `(providerId, vulnId, productKey, lastObserved)` unless semantic order mandated;
|
* arrays sorted by `(providerId, vulnId, productKey, lastObserved)` unless semantic order mandated;
|
||||||
* timestamps in `YYYY‑MM‑DDThh:mm:ssZ`;
|
* timestamps in `YYYY‑MM‑DDThh:mm:ssZ`;
|
||||||
* no insignificant whitespace.
|
* no insignificant whitespace.
|
||||||
|
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ Everything here is open‑source and versioned — when you check out a git ta
|
|||||||
- **70a – [Policy Gateway](policy/gateway.md)**
|
- **70a – [Policy Gateway](policy/gateway.md)**
|
||||||
- **71 – [Policy Examples](examples/policies/README.md)**
|
- **71 – [Policy Examples](examples/policies/README.md)**
|
||||||
- **72 – [Policy FAQ](faq/policy-faq.md)**
|
- **72 – [Policy FAQ](faq/policy-faq.md)**
|
||||||
- **73 – [Policy Run DTOs](../src/StellaOps.Scheduler.Models/docs/SCHED-MODELS-20-001-POLICY-RUNS.md)**
|
- **73 – [Policy Run DTOs](../src/Scheduler/__Libraries/StellaOps.Scheduler.Models/docs/SCHED-MODELS-20-001-POLICY-RUNS.md)**
|
||||||
- **30 – [Fixture Maintenance](dev/fixtures.md)**
|
- **30 – [Fixture Maintenance](dev/fixtures.md)**
|
||||||
- **74 – [Export Center Overview](export-center/overview.md)**
|
- **74 – [Export Center Overview](export-center/overview.md)**
|
||||||
- **75 – [Export Center Architecture](export-center/architecture.md)**
|
- **75 – [Export Center Architecture](export-center/architecture.md)**
|
||||||
@@ -147,10 +147,10 @@ Everything here is open‑source and versioned — when you check out a git ta
|
|||||||
|
|
||||||
> Imposed rule: Work of this type or tasks of this type on this component must also be applied everywhere else it should be applied.
|
> Imposed rule: Work of this type or tasks of this type on this component must also be applied everywhere else it should be applied.
|
||||||
|
|
||||||
- **Aggregation-Only Contract (AOC).** Ingestion services aggregate and link facts only—derived precedence, severity, and safe-fix hints live in Policy overlays and dedicated explorers. Review [`../AGENTS.md`](../AGENTS.md) and the AOC guardrails in [`aoc/aoc-guardrails.md`](aoc/aoc-guardrails.md).
|
- **Aggregation-Only Contract (AOC).** Ingestion services aggregate and link facts only—derived precedence, severity, and safe-fix hints live in Policy overlays and dedicated explorers. Review [`implplan/AGENTS.md`](implplan/AGENTS.md) and the AOC guardrails in [`aoc/aoc-guardrails.md`](aoc/aoc-guardrails.md).
|
||||||
- **Cartographer owns graphs.** SBOM Service emits projections/events; Cartographer (`CARTO-GRAPH-21-00x`) builds graph storage, overlays, and tiles. See `ARCHITECTURE_CONCELIER.md` (Cartographer handshake section) for handoff boundaries.
|
- **Cartographer owns graphs.** SBOM Service emits projections/events; Cartographer (`CARTO-GRAPH-21-00x`) builds graph storage, overlays, and tiles. See `ARCHITECTURE_CONCELIER.md` (Cartographer handshake section) for handoff boundaries.
|
||||||
- **Notifier replaces legacy Notify.** Sprint‑15 `StellaOps.Notify.*` tasks are frozen; use the Notifications Studio/Notifier backlogs (`NOTIFY-SVC-38..40`, `WEB-NOTIFY-3x-00x`, `CLI-NOTIFY-3x-00x`).
|
- **Notifier replaces legacy Notify.** Sprint‑15 `StellaOps.Notify.*` tasks are frozen; use the Notifications Studio/Notifier backlogs (`NOTIFY-SVC-38..40`, `WEB-NOTIFY-3x-00x`, `CLI-NOTIFY-3x-00x`).
|
||||||
- **Dedicated services for Vuln & Policy.** Vuln Explorer work flows through `src/StellaOps.VulnExplorer.Api`/Console/CLI (Sprint 29); gateway routes proxy only. Policy Engine remains the sole source for precedence/suppression overlays.
|
- **Dedicated services for Vuln & Policy.** Vuln Explorer work flows through `src/VulnExplorer/StellaOps.VulnExplorer.Api`/Console/CLI (Sprint 29); gateway routes proxy only. Policy Engine remains the sole source for precedence/suppression overlays.
|
||||||
- **Cleanup log.** The backlog consolidation summary lives in [`backlog/2025-10-cleanup.md`](backlog/2025-10-cleanup.md).
|
- **Cleanup log.** The backlog consolidation summary lives in [`backlog/2025-10-cleanup.md`](backlog/2025-10-cleanup.md).
|
||||||
|
|
||||||
© 2025 Stella Ops contributors – licensed AGPL‑3.0‑or‑later
|
© 2025 Stella Ops contributors – licensed AGPL‑3.0‑or‑later
|
||||||
|
|||||||
762
docs/TASKS.md
762
docs/TASKS.md
@@ -1,381 +1,381 @@
|
|||||||
# Docs Guild Task Board (UTC 2025-10-10)
|
# Docs Guild Task Board (UTC 2025-10-10)
|
||||||
|
|
||||||
| ID | Status | Owner(s) | Depends on | Description | Exit Criteria |
|
| ID | Status | Owner(s) | Depends on | Description | Exit Criteria |
|
||||||
|----|--------|----------|------------|-------------|---------------|
|
|----|--------|----------|------------|-------------|---------------|
|
||||||
| DOC7.README-INDEX | DONE (2025-10-17) | Docs Guild | — | Refresh index docs (docs/README.md + root README) after architecture dossier split and Offline Kit overhaul. | ✅ ToC reflects new component architecture docs; ✅ root README highlights updated doc set; ✅ Offline Kit guide linked correctly. |
|
| DOC7.README-INDEX | DONE (2025-10-17) | Docs Guild | — | Refresh index docs (docs/README.md + root README) after architecture dossier split and Offline Kit overhaul. | ✅ ToC reflects new component architecture docs; ✅ root README highlights updated doc set; ✅ Offline Kit guide linked correctly. |
|
||||||
| DOC4.AUTH-PDG | DONE (2025-10-19) | Docs Guild, Plugin Team | PLG6.DOC | Copy-edit `docs/dev/31_AUTHORITY_PLUGIN_DEVELOPER_GUIDE.md`, export lifecycle diagram, add LDAP RFC cross-link. | ✅ PR merged with polish; ✅ Diagram committed; ✅ Slack handoff posted. |
|
| DOC4.AUTH-PDG | DONE (2025-10-19) | Docs Guild, Plugin Team | PLG6.DOC | Copy-edit `docs/dev/31_AUTHORITY_PLUGIN_DEVELOPER_GUIDE.md`, export lifecycle diagram, add LDAP RFC cross-link. | ✅ PR merged with polish; ✅ Diagram committed; ✅ Slack handoff posted. |
|
||||||
| DOC1.AUTH | DONE (2025-10-12) | Docs Guild, Authority Core | CORE5B.DOC | Draft `docs/11_AUTHORITY.md` covering architecture, configuration, bootstrap flows. | ✅ Architecture + config sections approved by Core; ✅ Samples reference latest options; ✅ Offline note added. |
|
| DOC1.AUTH | DONE (2025-10-12) | Docs Guild, Authority Core | CORE5B.DOC | Draft `docs/11_AUTHORITY.md` covering architecture, configuration, bootstrap flows. | ✅ Architecture + config sections approved by Core; ✅ Samples reference latest options; ✅ Offline note added. |
|
||||||
| DOC3.Concelier-Authority | DONE (2025-10-12) | Docs Guild, DevEx | FSR4 | Polish operator/runbook sections (DOC3/DOC5) to document Concelier authority rollout, bypass logging, and enforcement checklist. | ✅ DOC3/DOC5 updated with audit runbook references; ✅ enforcement deadline highlighted; ✅ Docs guild sign-off. |
|
| DOC3.Concelier-Authority | DONE (2025-10-12) | Docs Guild, DevEx | FSR4 | Polish operator/runbook sections (DOC3/DOC5) to document Concelier authority rollout, bypass logging, and enforcement checklist. | ✅ DOC3/DOC5 updated with audit runbook references; ✅ enforcement deadline highlighted; ✅ Docs guild sign-off. |
|
||||||
| DOC5.Concelier-Runbook | DONE (2025-10-12) | Docs Guild | DOC3.Concelier-Authority | Produce dedicated Concelier authority audit runbook covering log fields, monitoring recommendations, and troubleshooting steps. | ✅ Runbook published; ✅ linked from DOC3/DOC5; ✅ alerting guidance included. |
|
| DOC5.Concelier-Runbook | DONE (2025-10-12) | Docs Guild | DOC3.Concelier-Authority | Produce dedicated Concelier authority audit runbook covering log fields, monitoring recommendations, and troubleshooting steps. | ✅ Runbook published; ✅ linked from DOC3/DOC5; ✅ alerting guidance included. |
|
||||||
| FEEDDOCS-DOCS-05-001 | DONE (2025-10-11) | Docs Guild | FEEDMERGE-ENGINE-04-001, FEEDMERGE-ENGINE-04-002 | Publish Concelier conflict resolution runbook covering precedence workflow, merge-event auditing, and Sprint 3 metrics. | ✅ `docs/ops/concelier-conflict-resolution.md` committed; ✅ metrics/log tables align with latest merge code; ✅ Ops alert guidance handed to Concelier team. |
|
| FEEDDOCS-DOCS-05-001 | DONE (2025-10-11) | Docs Guild | FEEDMERGE-ENGINE-04-001, FEEDMERGE-ENGINE-04-002 | Publish Concelier conflict resolution runbook covering precedence workflow, merge-event auditing, and Sprint 3 metrics. | ✅ `docs/ops/concelier-conflict-resolution.md` committed; ✅ metrics/log tables align with latest merge code; ✅ Ops alert guidance handed to Concelier team. |
|
||||||
| FEEDDOCS-DOCS-05-002 | DONE (2025-10-16) | Docs Guild, Concelier Ops | FEEDDOCS-DOCS-05-001 | Ops sign-off captured: conflict runbook circulated, alert thresholds tuned, and rollout decisions documented in change log. | ✅ Ops review recorded; ✅ alert thresholds finalised using `docs/ops/concelier-authority-audit-runbook.md`; ✅ change-log entry linked from runbook once GHSA/NVD/OSV regression fixtures land. |
|
| FEEDDOCS-DOCS-05-002 | DONE (2025-10-16) | Docs Guild, Concelier Ops | FEEDDOCS-DOCS-05-001 | Ops sign-off captured: conflict runbook circulated, alert thresholds tuned, and rollout decisions documented in change log. | ✅ Ops review recorded; ✅ alert thresholds finalised using `docs/ops/concelier-authority-audit-runbook.md`; ✅ change-log entry linked from runbook once GHSA/NVD/OSV regression fixtures land. |
|
||||||
| DOCS-ADR-09-001 | DONE (2025-10-19) | Docs Guild, DevEx | — | Establish ADR process (`docs/adr/0000-template.md`) and document usage guidelines. | Template published; README snippet linking ADR process; announcement posted (`docs/updates/2025-10-18-docs-guild.md`). |
|
| DOCS-ADR-09-001 | DONE (2025-10-19) | Docs Guild, DevEx | — | Establish ADR process (`docs/adr/0000-template.md`) and document usage guidelines. | Template published; README snippet linking ADR process; announcement posted (`docs/updates/2025-10-18-docs-guild.md`). |
|
||||||
| DOCS-EVENTS-09-002 | DONE (2025-10-19) | Docs Guild, Platform Events | SCANNER-EVENTS-15-201 | Publish event schema catalog (`docs/events/`) for `scanner.report.ready@1`, `scheduler.rescan.delta@1`, `attestor.logged@1`. | Schemas validated (Ajv CI hooked); docs/events/README summarises usage; Platform Events notified via `docs/updates/2025-10-18-docs-guild.md`. |
|
| DOCS-EVENTS-09-002 | DONE (2025-10-19) | Docs Guild, Platform Events | SCANNER-EVENTS-15-201 | Publish event schema catalog (`docs/events/`) for `scanner.report.ready@1`, `scheduler.rescan.delta@1`, `attestor.logged@1`. | Schemas validated (Ajv CI hooked); docs/events/README summarises usage; Platform Events notified via `docs/updates/2025-10-18-docs-guild.md`. |
|
||||||
| DOCS-EVENTS-09-003 | DONE (2025-10-19) | Docs Guild | DOCS-EVENTS-09-002 | Add human-readable envelope field references and canonical payload samples for published events, including offline validation workflow. | Tables explain common headers/payload segments; versioned sample payloads committed; README links to validation instructions and samples. |
|
| DOCS-EVENTS-09-003 | DONE (2025-10-19) | Docs Guild | DOCS-EVENTS-09-002 | Add human-readable envelope field references and canonical payload samples for published events, including offline validation workflow. | Tables explain common headers/payload segments; versioned sample payloads committed; README links to validation instructions and samples. |
|
||||||
| DOCS-EVENTS-09-004 | DONE (2025-10-19) | Docs Guild, Scanner WebService | SCANNER-EVENTS-15-201 | Refresh scanner event docs to mirror DSSE-backed report fields, document `scanner.scan.completed`, and capture canonical sample validation. | Schemas updated for new payload shape; README references DSSE reuse and validation test; samples align with emitted events. |
|
| DOCS-EVENTS-09-004 | DONE (2025-10-19) | Docs Guild, Scanner WebService | SCANNER-EVENTS-15-201 | Refresh scanner event docs to mirror DSSE-backed report fields, document `scanner.scan.completed`, and capture canonical sample validation. | Schemas updated for new payload shape; README references DSSE reuse and validation test; samples align with emitted events. |
|
||||||
| PLATFORM-EVENTS-09-401 | DONE (2025-10-21) | Platform Events Guild | DOCS-EVENTS-09-003 | Embed canonical event samples into contract/integration tests and ensure CI validates payloads against published schemas. | Notify models tests now run schema validation against `docs/events/*.json`, event schemas allow optional `attributes`, and docs capture the new validation workflow. |
|
| PLATFORM-EVENTS-09-401 | DONE (2025-10-21) | Platform Events Guild | DOCS-EVENTS-09-003 | Embed canonical event samples into contract/integration tests and ensure CI validates payloads against published schemas. | Notify models tests now run schema validation against `docs/events/*.json`, event schemas allow optional `attributes`, and docs capture the new validation workflow. |
|
||||||
| RUNTIME-GUILD-09-402 | DONE (2025-10-19) | Runtime Guild | SCANNER-POLICY-09-107 | Confirm Scanner WebService surfaces `quietedFindingCount` and progress hints to runtime consumers; document readiness checklist. | Runtime verification run captures enriched payload; checklist/doc updates merged; stakeholders acknowledge availability. |
|
| RUNTIME-GUILD-09-402 | DONE (2025-10-19) | Runtime Guild | SCANNER-POLICY-09-107 | Confirm Scanner WebService surfaces `quietedFindingCount` and progress hints to runtime consumers; document readiness checklist. | Runtime verification run captures enriched payload; checklist/doc updates merged; stakeholders acknowledge availability. |
|
||||||
| DOCS-CONCELIER-07-201 | DONE (2025-10-22) | Docs Guild, Concelier WebService | FEEDWEB-DOCS-01-001 | Final editorial review and publish pass for Concelier authority toggle documentation (Quickstart + operator guide). | Review feedback resolved, publish PR merged, release notes updated with documentation pointer. |
|
| DOCS-CONCELIER-07-201 | DONE (2025-10-22) | Docs Guild, Concelier WebService | FEEDWEB-DOCS-01-001 | Final editorial review and publish pass for Concelier authority toggle documentation (Quickstart + operator guide). | Review feedback resolved, publish PR merged, release notes updated with documentation pointer. |
|
||||||
| DOCS-RUNTIME-17-004 | DONE (2025-10-26) | Docs Guild, Runtime Guild | SCANNER-EMIT-17-701, ZASTAVA-OBS-17-005, DEVOPS-REL-17-002 | Document build-id workflows: SBOM exposure, runtime event payloads (`process.buildId`), Scanner `/policy/runtime` response (`buildIds` list), debug-store layout, and operator guidance for symbol retrieval. | Architecture + operator docs updated with build-id sections (Observer, Scanner, CLI), examples show `readelf` output + debuginfod usage, references linked from Offline Kit/Release guides + CLI help. |
|
| DOCS-RUNTIME-17-004 | DONE (2025-10-26) | Docs Guild, Runtime Guild | SCANNER-EMIT-17-701, ZASTAVA-OBS-17-005, DEVOPS-REL-17-002 | Document build-id workflows: SBOM exposure, runtime event payloads (`process.buildId`), Scanner `/policy/runtime` response (`buildIds` list), debug-store layout, and operator guidance for symbol retrieval. | Architecture + operator docs updated with build-id sections (Observer, Scanner, CLI), examples show `readelf` output + debuginfod usage, references linked from Offline Kit/Release guides + CLI help. |
|
||||||
| DOCS-OBS-50-001 | BLOCKED (2025-10-26) | Docs Guild, Observability Guild | TELEMETRY-OBS-50-001 | Publish `/docs/observability/overview.md` introducing scope, imposed rule banner, architecture diagram, and tenant guarantees. | Doc merged with imposed rule banner; diagram committed; cross-links to telemetry stack + evidence locker docs. |
|
| DOCS-OBS-50-001 | BLOCKED (2025-10-26) | Docs Guild, Observability Guild | TELEMETRY-OBS-50-001 | Publish `/docs/observability/overview.md` introducing scope, imposed rule banner, architecture diagram, and tenant guarantees. | Doc merged with imposed rule banner; diagram committed; cross-links to telemetry stack + evidence locker docs. |
|
||||||
> Blocked: waiting on telemetry core deliverable (TELEMETRY-OBS-50-001) to finalise architecture details and diagrams.
|
> Blocked: waiting on telemetry core deliverable (TELEMETRY-OBS-50-001) to finalise architecture details and diagrams.
|
||||||
| DOCS-OBS-50-002 | TODO | Docs Guild, Security Guild | TELEMETRY-OBS-50-002 | Author `/docs/observability/telemetry-standards.md` detailing common fields, scrubbing policy, sampling defaults, and redaction override procedure. | Doc merged; imposed rule banner present; examples validated with telemetry fixtures; security review sign-off captured. |
|
| DOCS-OBS-50-002 | TODO | Docs Guild, Security Guild | TELEMETRY-OBS-50-002 | Author `/docs/observability/telemetry-standards.md` detailing common fields, scrubbing policy, sampling defaults, and redaction override procedure. | Doc merged; imposed rule banner present; examples validated with telemetry fixtures; security review sign-off captured. |
|
||||||
| DOCS-OBS-50-003 | TODO | Docs Guild, Observability Guild | TELEMETRY-OBS-50-001 | Create `/docs/observability/logging.md` covering structured log schema, dos/don'ts, tenant isolation, and copyable examples. | Doc merged with banner; sample logs redacted; lint passes; linked from coding standards. |
|
| DOCS-OBS-50-003 | TODO | Docs Guild, Observability Guild | TELEMETRY-OBS-50-001 | Create `/docs/observability/logging.md` covering structured log schema, dos/don'ts, tenant isolation, and copyable examples. | Doc merged with banner; sample logs redacted; lint passes; linked from coding standards. |
|
||||||
| DOCS-OBS-50-004 | TODO | Docs Guild, Observability Guild | TELEMETRY-OBS-50-002 | Draft `/docs/observability/tracing.md` explaining context propagation, async linking, CLI header usage, and sampling strategies. | Doc merged; imposed rule banner included; diagrams updated; references to CLI/Console features added. |
|
| DOCS-OBS-50-004 | TODO | Docs Guild, Observability Guild | TELEMETRY-OBS-50-002 | Draft `/docs/observability/tracing.md` explaining context propagation, async linking, CLI header usage, and sampling strategies. | Doc merged; imposed rule banner included; diagrams updated; references to CLI/Console features added. |
|
||||||
| DOCS-OBS-51-001 | TODO | Docs Guild, DevOps Guild | WEB-OBS-51-001, DEVOPS-OBS-51-001 | Publish `/docs/observability/metrics-and-slos.md` cataloging metrics, SLO targets, burn rate policies, and alert runbooks. | Doc merged with banner; SLO tables verified; alert workflows linked to incident runbook. |
|
| DOCS-OBS-51-001 | TODO | Docs Guild, DevOps Guild | WEB-OBS-51-001, DEVOPS-OBS-51-001 | Publish `/docs/observability/metrics-and-slos.md` cataloging metrics, SLO targets, burn rate policies, and alert runbooks. | Doc merged with banner; SLO tables verified; alert workflows linked to incident runbook. |
|
||||||
| DOCS-SEC-OBS-50-001 | TODO | Docs Guild, Security Guild | TELEMETRY-OBS-51-002 | Update `/docs/security/redaction-and-privacy.md` to cover telemetry privacy controls, tenant opt-in debug, and imposed rule reminder. | Doc merged; redaction matrix updated; banner present; security sign-off recorded. |
|
| DOCS-SEC-OBS-50-001 | TODO | Docs Guild, Security Guild | TELEMETRY-OBS-51-002 | Update `/docs/security/redaction-and-privacy.md` to cover telemetry privacy controls, tenant opt-in debug, and imposed rule reminder. | Doc merged; redaction matrix updated; banner present; security sign-off recorded. |
|
||||||
| DOCS-INSTALL-50-001 | TODO | Docs Guild, DevOps Guild | DEVOPS-OBS-50-003 | Add `/docs/install/telemetry-stack.md` with collector deployment, exporter options, offline kit notes, and imposed rule banner. | Doc merged; install steps verified on air-gapped profile; banner present; screenshots attached. |
|
| DOCS-INSTALL-50-001 | TODO | Docs Guild, DevOps Guild | DEVOPS-OBS-50-003 | Add `/docs/install/telemetry-stack.md` with collector deployment, exporter options, offline kit notes, and imposed rule banner. | Doc merged; install steps verified on air-gapped profile; banner present; screenshots attached. |
|
||||||
| DOCS-FORENSICS-53-001 | TODO | Docs Guild, Evidence Locker Guild | EVID-OBS-53-003 | Publish `/docs/forensics/evidence-locker.md` describing bundle formats, WORM options, retention, legal hold, and imposed rule banner. | Doc merged; manifest examples validated; banner present; legal hold steps aligned with API. |
|
| DOCS-FORENSICS-53-001 | TODO | Docs Guild, Evidence Locker Guild | EVID-OBS-53-003 | Publish `/docs/forensics/evidence-locker.md` describing bundle formats, WORM options, retention, legal hold, and imposed rule banner. | Doc merged; manifest examples validated; banner present; legal hold steps aligned with API. |
|
||||||
| DOCS-FORENSICS-53-002 | TODO | Docs Guild, Provenance Guild | PROV-OBS-54-001 | Release `/docs/forensics/provenance-attestation.md` covering DSSE schema, signing process, verification workflow, and imposed rule banner. | Doc merged; sample statements reference fixtures; banner included; verification steps tested. |
|
| DOCS-FORENSICS-53-002 | TODO | Docs Guild, Provenance Guild | PROV-OBS-54-001 | Release `/docs/forensics/provenance-attestation.md` covering DSSE schema, signing process, verification workflow, and imposed rule banner. | Doc merged; sample statements reference fixtures; banner included; verification steps tested. |
|
||||||
| DOCS-FORENSICS-53-003 | TODO | Docs Guild, Timeline Indexer Guild | TIMELINE-OBS-52-003 | Publish `/docs/forensics/timeline.md` with schema, event kinds, filters, query examples, and imposed rule banner. | Doc merged; query examples validated; banner present; linked from Console/CLI docs. |
|
| DOCS-FORENSICS-53-003 | TODO | Docs Guild, Timeline Indexer Guild | TIMELINE-OBS-52-003 | Publish `/docs/forensics/timeline.md` with schema, event kinds, filters, query examples, and imposed rule banner. | Doc merged; query examples validated; banner present; linked from Console/CLI docs. |
|
||||||
| DOCS-CONSOLE-OBS-52-001 | TODO | Docs Guild, Console Guild | CONSOLE-OBS-51-001 | Document `/docs/console/observability.md` showcasing Observability Hub widgets, trace/log search, imposed rule banner, and accessibility tips. | Doc merged; screenshots updated; banner present; navigation steps verified. |
|
| DOCS-CONSOLE-OBS-52-001 | TODO | Docs Guild, Console Guild | CONSOLE-OBS-51-001 | Document `/docs/console/observability.md` showcasing Observability Hub widgets, trace/log search, imposed rule banner, and accessibility tips. | Doc merged; screenshots updated; banner present; navigation steps verified. |
|
||||||
| DOCS-CONSOLE-OBS-52-002 | TODO | Docs Guild, Console Guild | CONSOLE-OBS-52-002, CONSOLE-OBS-53-001 | Publish `/docs/console/forensics.md` covering timeline explorer, evidence viewer, attestation verifier, imposed rule banner, and troubleshooting. | Doc merged; banner included; workflows validated via Playwright capture; troubleshooting section populated. |
|
| DOCS-CONSOLE-OBS-52-002 | TODO | Docs Guild, Console Guild | CONSOLE-OBS-52-002, CONSOLE-OBS-53-001 | Publish `/docs/console/forensics.md` covering timeline explorer, evidence viewer, attestation verifier, imposed rule banner, and troubleshooting. | Doc merged; banner included; workflows validated via Playwright capture; troubleshooting section populated. |
|
||||||
| DOCS-CLI-OBS-52-001 | TODO | Docs Guild, DevEx/CLI Guild | CLI-OBS-52-001 | Create `/docs/cli/observability.md` detailing `stella obs` commands, examples, exit codes, imposed rule banner, and scripting tips. | Doc merged; examples tested; banner included; CLI parity matrix updated. |
|
| DOCS-CLI-OBS-52-001 | TODO | Docs Guild, DevEx/CLI Guild | CLI-OBS-52-001 | Create `/docs/cli/observability.md` detailing `stella obs` commands, examples, exit codes, imposed rule banner, and scripting tips. | Doc merged; examples tested; banner included; CLI parity matrix updated. |
|
||||||
| DOCS-CLI-FORENSICS-53-001 | TODO | Docs Guild, DevEx/CLI Guild | CLI-FORENSICS-54-001 | Publish `/docs/cli/forensics.md` for snapshot/verify/attest commands with sample outputs, imposed rule banner, and offline workflows. | Doc merged; sample bundles verified; banner present; offline notes cross-linked. |
|
| DOCS-CLI-FORENSICS-53-001 | TODO | Docs Guild, DevEx/CLI Guild | CLI-FORENSICS-54-001 | Publish `/docs/cli/forensics.md` for snapshot/verify/attest commands with sample outputs, imposed rule banner, and offline workflows. | Doc merged; sample bundles verified; banner present; offline notes cross-linked. |
|
||||||
| DOCS-RUNBOOK-55-001 | TODO | Docs Guild, Ops Guild | DEVOPS-OBS-55-001, WEB-OBS-55-001 | Author `/docs/runbooks/incidents.md` describing incident mode activation, escalation steps, retention impact, verification checklist, and imposed rule banner. | Doc merged; runbook rehearsed; banner included; linked from alerts. |
|
| DOCS-RUNBOOK-55-001 | TODO | Docs Guild, Ops Guild | DEVOPS-OBS-55-001, WEB-OBS-55-001 | Author `/docs/runbooks/incidents.md` describing incident mode activation, escalation steps, retention impact, verification checklist, and imposed rule banner. | Doc merged; runbook rehearsed; banner included; linked from alerts. |
|
||||||
| DOCS-AOC-19-001 | DONE (2025-10-26) | Docs Guild, Concelier Guild | CONCELIER-WEB-AOC-19-001, EXCITITOR-WEB-AOC-19-001 | Author `/docs/ingestion/aggregation-only-contract.md` covering philosophy, invariants, schemas, error codes, migration, observability, and security checklist. | New doc published with compliance checklist; cross-links from existing docs added. |
|
| DOCS-AOC-19-001 | DONE (2025-10-26) | Docs Guild, Concelier Guild | CONCELIER-WEB-AOC-19-001, EXCITITOR-WEB-AOC-19-001 | Author `/docs/ingestion/aggregation-only-contract.md` covering philosophy, invariants, schemas, error codes, migration, observability, and security checklist. | New doc published with compliance checklist; cross-links from existing docs added. |
|
||||||
| DOCS-AOC-19-002 | DONE (2025-10-26) | Docs Guild, Architecture Guild | DOCS-AOC-19-001 | Update `/docs/architecture/overview.md` to include AOC boundary, raw stores, and sequence diagram (fetch → guard → raw insert → policy evaluation). | Overview doc updated with diagrams/text; lint passes; stakeholders sign off. |
|
| DOCS-AOC-19-002 | DONE (2025-10-26) | Docs Guild, Architecture Guild | DOCS-AOC-19-001 | Update `/docs/architecture/overview.md` to include AOC boundary, raw stores, and sequence diagram (fetch → guard → raw insert → policy evaluation). | Overview doc updated with diagrams/text; lint passes; stakeholders sign off. |
|
||||||
| DOCS-AOC-19-003 | DONE (2025-10-26) | Docs Guild, Policy Guild | POLICY-AOC-19-003 | Refresh `/docs/architecture/policy-engine.md` clarifying ingestion boundary, raw inputs, and policy-only derived data. | Doc highlights raw-only ingestion contract, updated diagrams merge, compliance checklist added. |
|
| DOCS-AOC-19-003 | DONE (2025-10-26) | Docs Guild, Policy Guild | POLICY-AOC-19-003 | Refresh `/docs/architecture/policy-engine.md` clarifying ingestion boundary, raw inputs, and policy-only derived data. | Doc highlights raw-only ingestion contract, updated diagrams merge, compliance checklist added. |
|
||||||
| DOCS-AOC-19-004 | DONE (2025-10-26) | Docs Guild, UI Guild | UI-AOC-19-001 | Extend `/docs/ui/console.md` with Sources dashboard tiles, violation drill-down workflow, and verification action. | UI doc updated with screenshots/flow descriptions, compliance checklist appended. |
|
| DOCS-AOC-19-004 | DONE (2025-10-26) | Docs Guild, UI Guild | UI-AOC-19-001 | Extend `/docs/ui/console.md` with Sources dashboard tiles, violation drill-down workflow, and verification action. | UI doc updated with screenshots/flow descriptions, compliance checklist appended. |
|
||||||
> DOCS-AOC-19-004: Architecture overview & policy-engine updates landed 2025-10-26; incorporate the new AOC boundary diagrams and metrics references.
|
> DOCS-AOC-19-004: Architecture overview & policy-engine updates landed 2025-10-26; incorporate the new AOC boundary diagrams and metrics references.
|
||||||
| DOCS-AOC-19-005 | DONE (2025-10-26) | Docs Guild, CLI Guild | CLI-AOC-19-003 | Update `/docs/cli/cli-reference.md` with `stella sources ingest --dry-run` and `stella aoc verify` usage, exit codes, and offline notes. | CLI reference + quickstart sections updated; examples validated; compliance checklist added. |
|
| DOCS-AOC-19-005 | DONE (2025-10-26) | Docs Guild, CLI Guild | CLI-AOC-19-003 | Update `/docs/cli/cli-reference.md` with `stella sources ingest --dry-run` and `stella aoc verify` usage, exit codes, and offline notes. | CLI reference + quickstart sections updated; examples validated; compliance checklist added. |
|
||||||
> DOCS-AOC-19-005: New ingestion reference + architecture overview published 2025-10-26; ensure CLI docs link to both and surface AOC exit codes mapping.
|
> DOCS-AOC-19-005: New ingestion reference + architecture overview published 2025-10-26; ensure CLI docs link to both and surface AOC exit codes mapping.
|
||||||
| DOCS-AOC-19-006 | DONE (2025-10-26) | Docs Guild, Observability Guild | CONCELIER-WEB-AOC-19-002, EXCITITOR-WEB-AOC-19-002 | Document new metrics/traces/log keys in `/docs/observability/observability.md`. | Observability doc lists new metrics/traces/log fields; dashboards referenced; compliance checklist appended. |
|
| DOCS-AOC-19-006 | DONE (2025-10-26) | Docs Guild, Observability Guild | CONCELIER-WEB-AOC-19-002, EXCITITOR-WEB-AOC-19-002 | Document new metrics/traces/log keys in `/docs/observability/observability.md`. | Observability doc lists new metrics/traces/log fields; dashboards referenced; compliance checklist appended. |
|
||||||
| DOCS-AOC-19-007 | DONE (2025-10-26) | Docs Guild, Authority Core | AUTH-AOC-19-001 | Update `/docs/security/authority-scopes.md` with new ingestion scopes and tenancy enforcement notes. | Doc reflects new scopes, sample policies updated, compliance checklist added. |
|
| DOCS-AOC-19-007 | DONE (2025-10-26) | Docs Guild, Authority Core | AUTH-AOC-19-001 | Update `/docs/security/authority-scopes.md` with new ingestion scopes and tenancy enforcement notes. | Doc reflects new scopes, sample policies updated, compliance checklist added. |
|
||||||
| DOCS-AOC-19-008 | DONE (2025-10-26) | Docs Guild, DevOps Guild | DEVOPS-AOC-19-002 | Refresh `/docs/deploy/containers.md` to cover validator enablement, guard env flags, and read-only verify user. | Deploy doc updated; offline kit section mentions validator scripts; compliance checklist appended. |
|
| DOCS-AOC-19-008 | DONE (2025-10-26) | Docs Guild, DevOps Guild | DEVOPS-AOC-19-002 | Refresh `/docs/deploy/containers.md` to cover validator enablement, guard env flags, and read-only verify user. | Deploy doc updated; offline kit section mentions validator scripts; compliance checklist appended. |
|
||||||
| DOCS-AOC-19-009 | DONE (2025-10-26) | Docs Guild, Authority Core | AUTH-AOC-19-001 | Update AOC docs/samples to reflect new `advisory:*`, `vex:*`, and `aoc:verify` scopes. | Docs reference new scopes, samples aligned, compliance checklist updated. |
|
| DOCS-AOC-19-009 | DONE (2025-10-26) | Docs Guild, Authority Core | AUTH-AOC-19-001 | Update AOC docs/samples to reflect new `advisory:*`, `vex:*`, and `aoc:verify` scopes. | Docs reference new scopes, samples aligned, compliance checklist updated. |
|
||||||
|
|
||||||
## Air-Gapped Mode (Epic 16)
|
## Air-Gapped Mode (Epic 16)
|
||||||
| ID | Status | Owner(s) | Depends on | Description | Exit Criteria |
|
| ID | Status | Owner(s) | Depends on | Description | Exit Criteria |
|
||||||
|----|--------|----------|------------|-------------|---------------|
|
|----|--------|----------|------------|-------------|---------------|
|
||||||
| DOCS-AIRGAP-56-001 | TODO | Docs Guild, AirGap Controller Guild | AIRGAP-CTL-56-002 | Publish `/docs/airgap/overview.md` outlining modes, lifecycle, responsibilities, and imposed rule banner. | Doc merged; banner present; diagrams included. |
|
| DOCS-AIRGAP-56-001 | TODO | Docs Guild, AirGap Controller Guild | AIRGAP-CTL-56-002 | Publish `/docs/airgap/overview.md` outlining modes, lifecycle, responsibilities, and imposed rule banner. | Doc merged; banner present; diagrams included. |
|
||||||
| DOCS-AIRGAP-56-002 | TODO | Docs Guild, DevOps Guild | DEVOPS-AIRGAP-56-001 | Author `/docs/airgap/sealing-and-egress.md` covering network policies, EgressPolicy facade usage, and verification steps. | Doc merged; examples validated; banner included. |
|
| DOCS-AIRGAP-56-002 | TODO | Docs Guild, DevOps Guild | DEVOPS-AIRGAP-56-001 | Author `/docs/airgap/sealing-and-egress.md` covering network policies, EgressPolicy facade usage, and verification steps. | Doc merged; examples validated; banner included. |
|
||||||
| DOCS-AIRGAP-56-003 | TODO | Docs Guild, Exporter Guild | EXPORT-AIRGAP-56-001 | Create `/docs/airgap/mirror-bundles.md` describing bundle format, DSSE/TUF/Merkle validation, creation/import workflows. | Doc merged; sample commands verified; banner present. |
|
| DOCS-AIRGAP-56-003 | TODO | Docs Guild, Exporter Guild | EXPORT-AIRGAP-56-001 | Create `/docs/airgap/mirror-bundles.md` describing bundle format, DSSE/TUF/Merkle validation, creation/import workflows. | Doc merged; sample commands verified; banner present. |
|
||||||
| DOCS-AIRGAP-56-004 | TODO | Docs Guild, Deployment Guild | DEVOPS-AIRGAP-56-003 | Publish `/docs/airgap/bootstrap.md` detailing Bootstrap Pack creation, validation, and install procedures. | Doc merged; checklist appended; screenshots verified. |
|
| DOCS-AIRGAP-56-004 | TODO | Docs Guild, Deployment Guild | DEVOPS-AIRGAP-56-003 | Publish `/docs/airgap/bootstrap.md` detailing Bootstrap Pack creation, validation, and install procedures. | Doc merged; checklist appended; screenshots verified. |
|
||||||
| DOCS-AIRGAP-57-001 | TODO | Docs Guild, AirGap Time Guild | AIRGAP-TIME-58-001 | Write `/docs/airgap/staleness-and-time.md` explaining time anchors, drift policies, staleness budgets, and UI indicators. | Doc merged; math checked; banner included. |
|
| DOCS-AIRGAP-57-001 | TODO | Docs Guild, AirGap Time Guild | AIRGAP-TIME-58-001 | Write `/docs/airgap/staleness-and-time.md` explaining time anchors, drift policies, staleness budgets, and UI indicators. | Doc merged; math checked; banner included. |
|
||||||
| DOCS-AIRGAP-57-002 | TODO | Docs Guild, Console Guild | CONSOLE-AIRGAP-57-001 | Publish `/docs/console/airgap.md` covering sealed badge, import wizard, staleness dashboards. | Doc merged; screenshots captured; banner present. |
|
| DOCS-AIRGAP-57-002 | TODO | Docs Guild, Console Guild | CONSOLE-AIRGAP-57-001 | Publish `/docs/console/airgap.md` covering sealed badge, import wizard, staleness dashboards. | Doc merged; screenshots captured; banner present. |
|
||||||
| DOCS-AIRGAP-57-003 | TODO | Docs Guild, CLI Guild | CLI-AIRGAP-57-001 | Publish `/docs/cli/airgap.md` documenting commands, examples, exit codes. | Doc merged; examples validated; banner present. |
|
| DOCS-AIRGAP-57-003 | TODO | Docs Guild, CLI Guild | CLI-AIRGAP-57-001 | Publish `/docs/cli/airgap.md` documenting commands, examples, exit codes. | Doc merged; examples validated; banner present. |
|
||||||
| DOCS-AIRGAP-57-004 | TODO | Docs Guild, Ops Guild | DEVOPS-AIRGAP-56-002 | Create `/docs/airgap/operations.md` with runbooks for imports, failure recovery, and auditing. | Doc merged; runbooks rehearsed; banner included. |
|
| DOCS-AIRGAP-57-004 | TODO | Docs Guild, Ops Guild | DEVOPS-AIRGAP-56-002 | Create `/docs/airgap/operations.md` with runbooks for imports, failure recovery, and auditing. | Doc merged; runbooks rehearsed; banner included. |
|
||||||
| DOCS-AIRGAP-58-001 | TODO | Docs Guild, Product Guild | CONSOLE-AIRGAP-58-002 | Provide `/docs/airgap/degradation-matrix.md` enumerating feature availability, fallbacks, remediation. | Doc merged; matrix reviewed; banner included. |
|
| DOCS-AIRGAP-58-001 | TODO | Docs Guild, Product Guild | CONSOLE-AIRGAP-58-002 | Provide `/docs/airgap/degradation-matrix.md` enumerating feature availability, fallbacks, remediation. | Doc merged; matrix reviewed; banner included. |
|
||||||
| DOCS-AIRGAP-58-002 | TODO | Docs Guild, Security Guild | PROV-OBS-54-001 | Update `/docs/security/trust-and-signing.md` with DSSE/TUF roots, rotation, and signed time tokens. | Doc merged; security sign-off recorded; banner present. |
|
| DOCS-AIRGAP-58-002 | TODO | Docs Guild, Security Guild | PROV-OBS-54-001 | Update `/docs/security/trust-and-signing.md` with DSSE/TUF roots, rotation, and signed time tokens. | Doc merged; security sign-off recorded; banner present. |
|
||||||
| DOCS-AIRGAP-58-003 | TODO | Docs Guild, DevEx Guild | AIRGAP-POL-56-001 | Publish `/docs/dev/airgap-contracts.md` describing EgressPolicy usage, sealed-mode tests, linting. | Doc merged; sample code validated; banner included. |
|
| DOCS-AIRGAP-58-003 | TODO | Docs Guild, DevEx Guild | AIRGAP-POL-56-001 | Publish `/docs/dev/airgap-contracts.md` describing EgressPolicy usage, sealed-mode tests, linting. | Doc merged; sample code validated; banner included. |
|
||||||
| DOCS-AIRGAP-58-004 | TODO | Docs Guild, Evidence Locker Guild | EVID-OBS-55-001 | Document `/docs/airgap/portable-evidence.md` for exporting/importing portable evidence bundles across enclaves. | Doc merged; verification steps tested; banner present. |
|
| DOCS-AIRGAP-58-004 | TODO | Docs Guild, Evidence Locker Guild | EVID-OBS-55-001 | Document `/docs/airgap/portable-evidence.md` for exporting/importing portable evidence bundles across enclaves. | Doc merged; verification steps tested; banner present. |
|
||||||
|
|
||||||
## SDKs & OpenAPI (Epic 17)
|
## SDKs & OpenAPI (Epic 17)
|
||||||
| ID | Status | Owner(s) | Depends on | Description | Exit Criteria |
|
| ID | Status | Owner(s) | Depends on | Description | Exit Criteria |
|
||||||
|----|--------|----------|------------|-------------|---------------|
|
|----|--------|----------|------------|-------------|---------------|
|
||||||
| DOCS-OAS-61-001 | TODO | Docs Guild, API Contracts Guild | OAS-61-002 | Publish `/docs/api/overview.md` covering auth, tenancy, pagination, idempotency, rate limits with banner. | Doc merged; examples validated; banner present. |
|
| DOCS-OAS-61-001 | TODO | Docs Guild, API Contracts Guild | OAS-61-002 | Publish `/docs/api/overview.md` covering auth, tenancy, pagination, idempotency, rate limits with banner. | Doc merged; examples validated; banner present. |
|
||||||
| DOCS-OAS-61-002 | TODO | Docs Guild, API Governance Guild | APIGOV-61-001 | Author `/docs/api/conventions.md` capturing naming, errors, filters, sorting, examples. | Doc merged; lint passes; banner included. |
|
| DOCS-OAS-61-002 | TODO | Docs Guild, API Governance Guild | APIGOV-61-001 | Author `/docs/api/conventions.md` capturing naming, errors, filters, sorting, examples. | Doc merged; lint passes; banner included. |
|
||||||
| DOCS-OAS-61-003 | TODO | Docs Guild, API Governance Guild | APIGOV-63-001 | Publish `/docs/api/versioning.md` describing SemVer, deprecation headers, migration playbooks. | Doc merged; example headers validated; banner present. |
|
| DOCS-OAS-61-003 | TODO | Docs Guild, API Governance Guild | APIGOV-63-001 | Publish `/docs/api/versioning.md` describing SemVer, deprecation headers, migration playbooks. | Doc merged; example headers validated; banner present. |
|
||||||
| DOCS-OAS-62-001 | TODO | Docs Guild, Developer Portal Guild | DEVPORT-62-002 | Stand up `/docs/api/reference/` auto-generated site; integrate with portal nav. | Reference site builds; search works; banner included. |
|
| DOCS-OAS-62-001 | TODO | Docs Guild, Developer Portal Guild | DEVPORT-62-002 | Stand up `/docs/api/reference/` auto-generated site; integrate with portal nav. | Reference site builds; search works; banner included. |
|
||||||
| DOCS-SDK-62-001 | TODO | Docs Guild, SDK Generator Guild | SDKGEN-63-001 | Publish `/docs/sdks/overview.md` plus language guides (`typescript.md`, `python.md`, `go.md`, `java.md`). | Docs merged; code samples pulled from tested examples; banner present. |
|
| DOCS-SDK-62-001 | TODO | Docs Guild, SDK Generator Guild | SDKGEN-63-001 | Publish `/docs/sdks/overview.md` plus language guides (`typescript.md`, `python.md`, `go.md`, `java.md`). | Docs merged; code samples pulled from tested examples; banner present. |
|
||||||
| DOCS-DEVPORT-62-001 | TODO | Docs Guild, Developer Portal Guild | DEVPORT-62-001 | Document `/docs/devportal/publishing.md` for build pipeline, offline bundle steps. | Doc merged; cross-links validated; banner included. |
|
| DOCS-DEVPORT-62-001 | TODO | Docs Guild, Developer Portal Guild | DEVPORT-62-001 | Document `/docs/devportal/publishing.md` for build pipeline, offline bundle steps. | Doc merged; cross-links validated; banner included. |
|
||||||
| DOCS-CONTRIB-62-001 | TODO | Docs Guild, API Governance Guild | APIGOV-61-001 | Publish `/docs/contributing/api-contracts.md` detailing how to edit OAS, lint rules, compatibility checks. | Doc merged; banner present; examples validated. |
|
| DOCS-CONTRIB-62-001 | TODO | Docs Guild, API Governance Guild | APIGOV-61-001 | Publish `/docs/contributing/api-contracts.md` detailing how to edit OAS, lint rules, compatibility checks. | Doc merged; banner present; examples validated. |
|
||||||
| DOCS-TEST-62-001 | TODO | Docs Guild, Contract Testing Guild | CONTR-62-001 | Author `/docs/testing/contract-testing.md` covering mock server, replay tests, golden fixtures. | Doc merged; references to tooling validated; banner present. |
|
| DOCS-TEST-62-001 | TODO | Docs Guild, Contract Testing Guild | CONTR-62-001 | Author `/docs/testing/contract-testing.md` covering mock server, replay tests, golden fixtures. | Doc merged; references to tooling validated; banner present. |
|
||||||
| DOCS-SEC-62-001 | TODO | Docs Guild, Authority Core | AUTH-AIRGAP-56-001 | Update `/docs/security/auth-scopes.md` with OAuth2/PAT scopes, tenancy header usage. | Doc merged; scope tables verified; banner included. |
|
| DOCS-SEC-62-001 | TODO | Docs Guild, Authority Core | AUTH-AIRGAP-56-001 | Update `/docs/security/auth-scopes.md` with OAuth2/PAT scopes, tenancy header usage. | Doc merged; scope tables verified; banner included. |
|
||||||
| DOCS-AIRGAP-DEVPORT-64-001 | TODO | Docs Guild, DevPortal Offline Guild | DVOFF-64-001 | Create `/docs/airgap/devportal-offline.md` describing offline bundle usage and verification. | Doc merged; verification steps tested; banner present. |
|
| DOCS-AIRGAP-DEVPORT-64-001 | TODO | Docs Guild, DevPortal Offline Guild | DVOFF-64-001 | Create `/docs/airgap/devportal-offline.md` describing offline bundle usage and verification. | Doc merged; verification steps tested; banner present. |
|
||||||
|
|
||||||
## Risk Profiles (Epic 18)
|
## Risk Profiles (Epic 18)
|
||||||
| ID | Status | Owner(s) | Depends on | Description | Exit Criteria |
|
| ID | Status | Owner(s) | Depends on | Description | Exit Criteria |
|
||||||
|----|--------|----------|------------|-------------|---------------|
|
|----|--------|----------|------------|-------------|---------------|
|
||||||
| DOCS-RISK-66-001 | TODO | Docs Guild, Risk Profile Schema Guild | POLICY-RISK-66-001 | Publish `/docs/risk/overview.md` covering concepts and glossary. | Doc merged with banner; terminology reviewed. |
|
| DOCS-RISK-66-001 | TODO | Docs Guild, Risk Profile Schema Guild | POLICY-RISK-66-001 | Publish `/docs/risk/overview.md` covering concepts and glossary. | Doc merged with banner; terminology reviewed. |
|
||||||
| DOCS-RISK-66-002 | TODO | Docs Guild, Policy Guild | POLICY-RISK-66-003 | Author `/docs/risk/profiles.md` (authoring, versioning, scope). | Doc merged; schema examples validated; banner present. |
|
| DOCS-RISK-66-002 | TODO | Docs Guild, Policy Guild | POLICY-RISK-66-003 | Author `/docs/risk/profiles.md` (authoring, versioning, scope). | Doc merged; schema examples validated; banner present. |
|
||||||
| DOCS-RISK-66-003 | TODO | Docs Guild, Risk Engine Guild | RISK-ENGINE-67-001 | Publish `/docs/risk/factors.md` cataloging signals, transforms, reducers, TTLs. | Document merged; tables verified; banner included. |
|
| DOCS-RISK-66-003 | TODO | Docs Guild, Risk Engine Guild | RISK-ENGINE-67-001 | Publish `/docs/risk/factors.md` cataloging signals, transforms, reducers, TTLs. | Document merged; tables verified; banner included. |
|
||||||
| DOCS-RISK-66-004 | TODO | Docs Guild, Risk Engine Guild | RISK-ENGINE-66-002 | Create `/docs/risk/formulas.md` detailing math, normalization, gating, severity. | Doc merged; equations rendered; banner present. |
|
| DOCS-RISK-66-004 | TODO | Docs Guild, Risk Engine Guild | RISK-ENGINE-66-002 | Create `/docs/risk/formulas.md` detailing math, normalization, gating, severity. | Doc merged; equations rendered; banner present. |
|
||||||
| DOCS-RISK-67-001 | TODO | Docs Guild, Risk Engine Guild | RISK-ENGINE-68-001 | Publish `/docs/risk/explainability.md` showing artifact schema and UI screenshots. | Doc merged; CLI examples validated; banner included. |
|
| DOCS-RISK-67-001 | TODO | Docs Guild, Risk Engine Guild | RISK-ENGINE-68-001 | Publish `/docs/risk/explainability.md` showing artifact schema and UI screenshots. | Doc merged; CLI examples validated; banner included. |
|
||||||
| DOCS-RISK-67-002 | TODO | Docs Guild, API Guild | POLICY-RISK-67-002 | Produce `/docs/risk/api.md` with endpoint reference/examples. | Doc merged; OAS examples synced; banner present. |
|
| DOCS-RISK-67-002 | TODO | Docs Guild, API Guild | POLICY-RISK-67-002 | Produce `/docs/risk/api.md` with endpoint reference/examples. | Doc merged; OAS examples synced; banner present. |
|
||||||
| DOCS-RISK-67-003 | TODO | Docs Guild, Console Guild | CONSOLE-RISK-66-001 | Document `/docs/console/risk-ui.md` for authoring, simulation, dashboards. | Doc merged; screenshots updated; banner included. |
|
| DOCS-RISK-67-003 | TODO | Docs Guild, Console Guild | CONSOLE-RISK-66-001 | Document `/docs/console/risk-ui.md` for authoring, simulation, dashboards. | Doc merged; screenshots updated; banner included. |
|
||||||
| DOCS-RISK-67-004 | TODO | Docs Guild, CLI Guild | CLI-RISK-66-001 | Publish `/docs/cli/risk.md` covering CLI workflows. | Doc merged; command examples validated; banner present. |
|
| DOCS-RISK-67-004 | TODO | Docs Guild, CLI Guild | CLI-RISK-66-001 | Publish `/docs/cli/risk.md` covering CLI workflows. | Doc merged; command examples validated; banner present. |
|
||||||
| DOCS-RISK-68-001 | TODO | Docs Guild, Export Guild | RISK-BUNDLE-69-001 | Add `/docs/airgap/risk-bundles.md` for offline factor bundles. | Doc merged; verification steps confirmed; banner included. |
|
| DOCS-RISK-68-001 | TODO | Docs Guild, Export Guild | RISK-BUNDLE-69-001 | Add `/docs/airgap/risk-bundles.md` for offline factor bundles. | Doc merged; verification steps confirmed; banner included. |
|
||||||
| DOCS-RISK-68-002 | TODO | Docs Guild, Security Guild | POLICY-RISK-66-003 | Update `/docs/security/aoc-invariants.md` with risk scoring provenance guarantees. | Doc merged; audit references updated; banner present. |
|
| DOCS-RISK-68-002 | TODO | Docs Guild, Security Guild | POLICY-RISK-66-003 | Update `/docs/security/aoc-invariants.md` with risk scoring provenance guarantees. | Doc merged; audit references updated; banner present. |
|
||||||
|
|
||||||
## Attestor Console (Epic 19)
|
## Attestor Console (Epic 19)
|
||||||
| ID | Status | Owner(s) | Depends on | Description | Exit Criteria |
|
| ID | Status | Owner(s) | Depends on | Description | Exit Criteria |
|
||||||
|----|--------|----------|------------|-------------|---------------|
|
|----|--------|----------|------------|-------------|---------------|
|
||||||
| DOCS-ATTEST-73-001 | TODO | Docs Guild, Attestor Service Guild | ATTEST-TYPES-73-001 | Publish `/docs/attestor/overview.md` with imposed rule banner. | Doc merged; terminology validated. |
|
| DOCS-ATTEST-73-001 | TODO | Docs Guild, Attestor Service Guild | ATTEST-TYPES-73-001 | Publish `/docs/attestor/overview.md` with imposed rule banner. | Doc merged; terminology validated. |
|
||||||
| DOCS-ATTEST-73-002 | TODO | Docs Guild, Attestation Payloads Guild | ATTEST-TYPES-73-002 | Write `/docs/attestor/payloads.md` with schemas/examples. | Doc merged; examples validated via tests. |
|
| DOCS-ATTEST-73-002 | TODO | Docs Guild, Attestation Payloads Guild | ATTEST-TYPES-73-002 | Write `/docs/attestor/payloads.md` with schemas/examples. | Doc merged; examples validated via tests. |
|
||||||
| DOCS-ATTEST-73-003 | TODO | Docs Guild, Policy Guild | POLICY-ATTEST-73-002 | Publish `/docs/attestor/policies.md` covering verification policies. | Doc merged; policy examples validated. |
|
| DOCS-ATTEST-73-003 | TODO | Docs Guild, Policy Guild | POLICY-ATTEST-73-002 | Publish `/docs/attestor/policies.md` covering verification policies. | Doc merged; policy examples validated. |
|
||||||
| DOCS-ATTEST-73-004 | TODO | Docs Guild, Attestor Service Guild | ATTESTOR-73-002 | Add `/docs/attestor/workflows.md` detailing ingest, verify, bulk operations. | Doc merged; workflows tested. |
|
| DOCS-ATTEST-73-004 | TODO | Docs Guild, Attestor Service Guild | ATTESTOR-73-002 | Add `/docs/attestor/workflows.md` detailing ingest, verify, bulk operations. | Doc merged; workflows tested. |
|
||||||
| DOCS-ATTEST-74-001 | TODO | Docs Guild, KMS Guild | KMS-73-001 | Publish `/docs/attestor/keys-and-issuers.md`. | Doc merged; rotation guidance verified. |
|
| DOCS-ATTEST-74-001 | TODO | Docs Guild, KMS Guild | KMS-73-001 | Publish `/docs/attestor/keys-and-issuers.md`. | Doc merged; rotation guidance verified. |
|
||||||
| DOCS-ATTEST-74-002 | TODO | Docs Guild, Transparency Guild | TRANSP-74-001 | Document `/docs/attestor/transparency.md` with witness usage/offline validation. | Doc merged; proofs validated. |
|
| DOCS-ATTEST-74-002 | TODO | Docs Guild, Transparency Guild | TRANSP-74-001 | Document `/docs/attestor/transparency.md` with witness usage/offline validation. | Doc merged; proofs validated. |
|
||||||
| DOCS-ATTEST-74-003 | TODO | Docs Guild, Attestor Console Guild | CONSOLE-ATTEST-73-001 | Write `/docs/console/attestor-ui.md` with screenshots/workflows. | Doc merged; screenshots captured; banner present. |
|
| DOCS-ATTEST-74-003 | TODO | Docs Guild, Attestor Console Guild | CONSOLE-ATTEST-73-001 | Write `/docs/console/attestor-ui.md` with screenshots/workflows. | Doc merged; screenshots captured; banner present. |
|
||||||
| DOCS-ATTEST-74-004 | TODO | Docs Guild, CLI Attestor Guild | CLI-ATTEST-73-001 | Publish `/docs/cli/attest.md` covering CLI usage. | Doc merged; commands validated. |
|
| DOCS-ATTEST-74-004 | TODO | Docs Guild, CLI Attestor Guild | CLI-ATTEST-73-001 | Publish `/docs/cli/attest.md` covering CLI usage. | Doc merged; commands validated. |
|
||||||
| DOCS-ATTEST-75-001 | TODO | Docs Guild, Export Attestation Guild | EXPORT-ATTEST-75-002 | Add `/docs/attestor/airgap.md` for attestation bundles. | Doc merged; verification steps confirmed. |
|
| DOCS-ATTEST-75-001 | TODO | Docs Guild, Export Attestation Guild | EXPORT-ATTEST-75-002 | Add `/docs/attestor/airgap.md` for attestation bundles. | Doc merged; verification steps confirmed. |
|
||||||
| DOCS-ATTEST-75-002 | TODO | Docs Guild, Security Guild | ATTESTOR-73-002 | Update `/docs/security/aoc-invariants.md` with attestation invariants. | Doc merged; invariants detailed. |
|
| DOCS-ATTEST-75-002 | TODO | Docs Guild, Security Guild | ATTESTOR-73-002 | Update `/docs/security/aoc-invariants.md` with attestation invariants. | Doc merged; invariants detailed. |
|
||||||
## Policy Engine v2
|
## Policy Engine v2
|
||||||
|
|
||||||
| ID | Status | Owner(s) | Depends on | Description | Exit Criteria |
|
| ID | Status | Owner(s) | Depends on | Description | Exit Criteria |
|
||||||
|----|--------|----------|------------|-------------|---------------|
|
|----|--------|----------|------------|-------------|---------------|
|
||||||
| DOCS-POLICY-20-001 | DONE (2025-10-26) | Docs Guild, Policy Guild | POLICY-ENGINE-20-000 | Author `/docs/policy/overview.md` covering concepts, inputs/outputs, determinism, and compliance checklist. | Doc published with diagrams + glossary; lint passes; checklist included. |
|
| DOCS-POLICY-20-001 | DONE (2025-10-26) | Docs Guild, Policy Guild | POLICY-ENGINE-20-000 | Author `/docs/policy/overview.md` covering concepts, inputs/outputs, determinism, and compliance checklist. | Doc published with diagrams + glossary; lint passes; checklist included. |
|
||||||
| DOCS-POLICY-20-002 | DONE (2025-10-26) | Docs Guild, Policy Guild | POLICY-ENGINE-20-001 | Write `/docs/policy/dsl.md` with grammar, built-ins, examples, anti-patterns. | DSL doc includes grammar tables, examples, compliance checklist; validated against parser tests. |
|
| DOCS-POLICY-20-002 | DONE (2025-10-26) | Docs Guild, Policy Guild | POLICY-ENGINE-20-001 | Write `/docs/policy/dsl.md` with grammar, built-ins, examples, anti-patterns. | DSL doc includes grammar tables, examples, compliance checklist; validated against parser tests. |
|
||||||
| DOCS-POLICY-20-003 | DONE (2025-10-26) | Docs Guild, Authority Core | AUTH-POLICY-20-001 | Publish `/docs/policy/lifecycle.md` describing draft→approve workflow, roles, audit, compliance list. | Lifecycle doc linked from UI/CLI help; approvals roles documented; checklist appended. |
|
| DOCS-POLICY-20-003 | DONE (2025-10-26) | Docs Guild, Authority Core | AUTH-POLICY-20-001 | Publish `/docs/policy/lifecycle.md` describing draft→approve workflow, roles, audit, compliance list. | Lifecycle doc linked from UI/CLI help; approvals roles documented; checklist appended. |
|
||||||
| DOCS-POLICY-20-004 | DONE (2025-10-26) | Docs Guild, Scheduler Guild | SCHED-MODELS-20-001 | Create `/docs/policy/runs.md` detailing run modes, incremental mechanics, cursors, replay. | Run doc includes sequence diagrams + compliance checklist; cross-links to scheduler docs. |
|
| DOCS-POLICY-20-004 | DONE (2025-10-26) | Docs Guild, Scheduler Guild | SCHED-MODELS-20-001 | Create `/docs/policy/runs.md` detailing run modes, incremental mechanics, cursors, replay. | Run doc includes sequence diagrams + compliance checklist; cross-links to scheduler docs. |
|
||||||
| DOCS-POLICY-20-005 | DONE (2025-10-26) | Docs Guild, BE-Base Platform Guild | WEB-POLICY-20-001 | Draft `/docs/api/policy.md` describing endpoints, schemas, error codes. | API doc validated against OpenAPI; examples included; checklist appended. |
|
| DOCS-POLICY-20-005 | DONE (2025-10-26) | Docs Guild, BE-Base Platform Guild | WEB-POLICY-20-001 | Draft `/docs/api/policy.md` describing endpoints, schemas, error codes. | API doc validated against OpenAPI; examples included; checklist appended. |
|
||||||
| DOCS-POLICY-20-006 | DONE (2025-10-26) | Docs Guild, DevEx/CLI Guild | CLI-POLICY-20-002 | Produce `/docs/cli/policy.md` with command usage, exit codes, JSON output contracts. | CLI doc includes examples, exit codes, compliance checklist. |
|
| DOCS-POLICY-20-006 | DONE (2025-10-26) | Docs Guild, DevEx/CLI Guild | CLI-POLICY-20-002 | Produce `/docs/cli/policy.md` with command usage, exit codes, JSON output contracts. | CLI doc includes examples, exit codes, compliance checklist. |
|
||||||
| DOCS-POLICY-20-007 | DONE (2025-10-26) | Docs Guild, UI Guild | UI-POLICY-20-001 | Document `/docs/ui/policy-editor.md` covering editor, simulation, diff workflows, approvals. | UI doc includes screenshots/placeholders, accessibility notes, compliance checklist. |
|
| DOCS-POLICY-20-007 | DONE (2025-10-26) | Docs Guild, UI Guild | UI-POLICY-20-001 | Document `/docs/ui/policy-editor.md` covering editor, simulation, diff workflows, approvals. | UI doc includes screenshots/placeholders, accessibility notes, compliance checklist. |
|
||||||
| DOCS-POLICY-20-008 | DONE (2025-10-26) | Docs Guild, Architecture Guild | POLICY-ENGINE-20-003 | Write `/docs/architecture/policy-engine.md` (new epic content) with sequence diagrams, selection strategy, schema. | Architecture doc merged with diagrams; compliance checklist appended; references updated. |
|
| DOCS-POLICY-20-008 | DONE (2025-10-26) | Docs Guild, Architecture Guild | POLICY-ENGINE-20-003 | Write `/docs/architecture/policy-engine.md` (new epic content) with sequence diagrams, selection strategy, schema. | Architecture doc merged with diagrams; compliance checklist appended; references updated. |
|
||||||
| DOCS-POLICY-20-009 | DONE (2025-10-26) | Docs Guild, Observability Guild | POLICY-ENGINE-20-007 | Add `/docs/observability/policy.md` for metrics/traces/logs, sample dashboards. | Observability doc includes metrics tables, dashboard screenshots, checklist. |
|
| DOCS-POLICY-20-009 | DONE (2025-10-26) | Docs Guild, Observability Guild | POLICY-ENGINE-20-007 | Add `/docs/observability/policy.md` for metrics/traces/logs, sample dashboards. | Observability doc includes metrics tables, dashboard screenshots, checklist. |
|
||||||
| DOCS-POLICY-20-010 | DONE (2025-10-26) | Docs Guild, Security Guild | AUTH-POLICY-20-002 | Publish `/docs/security/policy-governance.md` covering scopes, approvals, tenancy, least privilege. | Security doc merged; compliance checklist appended; reviewed by Security Guild. |
|
| DOCS-POLICY-20-010 | DONE (2025-10-26) | Docs Guild, Security Guild | AUTH-POLICY-20-002 | Publish `/docs/security/policy-governance.md` covering scopes, approvals, tenancy, least privilege. | Security doc merged; compliance checklist appended; reviewed by Security Guild. |
|
||||||
| DOCS-POLICY-20-011 | DONE (2025-10-26) | Docs Guild, Policy Guild | POLICY-ENGINE-20-001 | Populate `/docs/examples/policies/` with baseline/serverless/internal-only samples and commentary. | Example policies committed with explanations; lint passes; compliance checklist per file. |
|
| DOCS-POLICY-20-011 | DONE (2025-10-26) | Docs Guild, Policy Guild | POLICY-ENGINE-20-001 | Populate `/docs/examples/policies/` with baseline/serverless/internal-only samples and commentary. | Example policies committed with explanations; lint passes; compliance checklist per file. |
|
||||||
| DOCS-POLICY-20-012 | DONE (2025-10-26) | Docs Guild, Support Guild | WEB-POLICY-20-003 | Draft `/docs/faq/policy-faq.md` addressing common pitfalls, VEX conflicts, determinism issues. | FAQ published with Q/A entries, cross-links, compliance checklist. |
|
| DOCS-POLICY-20-012 | DONE (2025-10-26) | Docs Guild, Support Guild | WEB-POLICY-20-003 | Draft `/docs/faq/policy-faq.md` addressing common pitfalls, VEX conflicts, determinism issues. | FAQ published with Q/A entries, cross-links, compliance checklist. |
|
||||||
|
|
||||||
## Graph Explorer v1
|
## Graph Explorer v1
|
||||||
|
|
||||||
| ID | Status | Owner(s) | Depends on | Description | Exit Criteria |
|
| ID | Status | Owner(s) | Depends on | Description | Exit Criteria |
|
||||||
|----|--------|----------|------------|-------------|---------------|
|
|----|--------|----------|------------|-------------|---------------|
|
||||||
|
|
||||||
## Link-Not-Merge v1
|
## Link-Not-Merge v1
|
||||||
|
|
||||||
| ID | Status | Owner(s) | Depends on | Description | Exit Criteria |
|
| ID | Status | Owner(s) | Depends on | Description | Exit Criteria |
|
||||||
|----|--------|----------|------------|-------------|---------------|
|
|----|--------|----------|------------|-------------|---------------|
|
||||||
| DOCS-LNM-22-001 | BLOCKED (2025-10-27) | Docs Guild, Concelier Guild | CONCELIER-LNM-21-001..003 | Author `/docs/advisories/aggregation.md` covering observation vs linkset, conflict handling, AOC requirements, and reviewer checklist. | Draft doc merged with examples + checklist; final sign-off blocked until Concelier schema/API tasks land. |
|
| DOCS-LNM-22-001 | BLOCKED (2025-10-27) | Docs Guild, Concelier Guild | CONCELIER-LNM-21-001..003 | Author `/docs/advisories/aggregation.md` covering observation vs linkset, conflict handling, AOC requirements, and reviewer checklist. | Draft doc merged with examples + checklist; final sign-off blocked until Concelier schema/API tasks land. |
|
||||||
> Blocker (2025-10-27): `CONCELIER-LNM-21-001..003` still TODO; update doc + fixtures once schema/API implementations are available.
|
> Blocker (2025-10-27): `CONCELIER-LNM-21-001..003` still TODO; update doc + fixtures once schema/API implementations are available.
|
||||||
| DOCS-LNM-22-002 | BLOCKED (2025-10-27) | Docs Guild, Excititor Guild | EXCITITOR-LNM-21-001..003 | Publish `/docs/vex/aggregation.md` describing VEX observation/linkset model, product matching, conflicts. | Draft doc merged with fixtures; final approval blocked until Excititor observation/linkset work ships. |
|
| DOCS-LNM-22-002 | BLOCKED (2025-10-27) | Docs Guild, Excititor Guild | EXCITITOR-LNM-21-001..003 | Publish `/docs/vex/aggregation.md` describing VEX observation/linkset model, product matching, conflicts. | Draft doc merged with fixtures; final approval blocked until Excititor observation/linkset work ships. |
|
||||||
> Blocker (2025-10-27): `EXCITITOR-LNM-21-001..003` remain TODO; refresh doc, fixtures, and examples post-implementation.
|
> Blocker (2025-10-27): `EXCITITOR-LNM-21-001..003` remain TODO; refresh doc, fixtures, and examples post-implementation.
|
||||||
| DOCS-LNM-22-003 | BLOCKED (2025-10-27) | Docs Guild, BE-Base Platform Guild | WEB-LNM-21-001..003 | Update `/docs/api/advisories.md` and `/docs/api/vex.md` for new endpoints, parameters, errors, exports. | Draft pending gateway/API delivery; unblock once endpoints + OpenAPI specs are available. |
|
| DOCS-LNM-22-003 | BLOCKED (2025-10-27) | Docs Guild, BE-Base Platform Guild | WEB-LNM-21-001..003 | Update `/docs/api/advisories.md` and `/docs/api/vex.md` for new endpoints, parameters, errors, exports. | Draft pending gateway/API delivery; unblock once endpoints + OpenAPI specs are available. |
|
||||||
> Blocker (2025-10-27): `WEB-LNM-21-001..003` all TODO—no gateway endpoints/OpenAPI to document yet.
|
> Blocker (2025-10-27): `WEB-LNM-21-001..003` all TODO—no gateway endpoints/OpenAPI to document yet.
|
||||||
| DOCS-LNM-22-004 | TODO | Docs Guild, Policy Guild | POLICY-ENGINE-40-001 | Create `/docs/policy/effective-severity.md` detailing severity selection strategies from multiple sources. | Doc merged with policy examples; checklist included. |
|
| DOCS-LNM-22-004 | TODO | Docs Guild, Policy Guild | POLICY-ENGINE-40-001 | Create `/docs/policy/effective-severity.md` detailing severity selection strategies from multiple sources. | Doc merged with policy examples; checklist included. |
|
||||||
| DOCS-LNM-22-005 | BLOCKED (2025-10-27) | Docs Guild, UI Guild | UI-LNM-22-001..003 | Document `/docs/ui/evidence-panel.md` with screenshots, conflict badges, accessibility guidance. | Awaiting UI implementation to capture screenshots + flows; unblock once Evidence panel ships. |
|
| DOCS-LNM-22-005 | BLOCKED (2025-10-27) | Docs Guild, UI Guild | UI-LNM-22-001..003 | Document `/docs/ui/evidence-panel.md` with screenshots, conflict badges, accessibility guidance. | Awaiting UI implementation to capture screenshots + flows; unblock once Evidence panel ships. |
|
||||||
> Blocker (2025-10-27): `UI-LNM-22-001..003` all TODO; documentation requires final UI states and accessibility audit artifacts.
|
> Blocker (2025-10-27): `UI-LNM-22-001..003` all TODO; documentation requires final UI states and accessibility audit artifacts.
|
||||||
|
|
||||||
## StellaOps Console (Sprint 23)
|
## StellaOps Console (Sprint 23)
|
||||||
|
|
||||||
| ID | Status | Owner(s) | Depends on | Description | Exit Criteria |
|
| ID | Status | Owner(s) | Depends on | Description | Exit Criteria |
|
||||||
|----|--------|----------|------------|-------------|---------------|
|
|----|--------|----------|------------|-------------|---------------|
|
||||||
| DOCS-CONSOLE-23-001 | DONE (2025-10-26) | Docs Guild, Console Guild | CONSOLE-CORE-23-004 | Publish `/docs/ui/console-overview.md` covering IA, tenant model, global filters, and AOC alignment with compliance checklist. | Doc merged with diagrams + overview tables; checklist appended; Console Guild sign-off. |
|
| DOCS-CONSOLE-23-001 | DONE (2025-10-26) | Docs Guild, Console Guild | CONSOLE-CORE-23-004 | Publish `/docs/ui/console-overview.md` covering IA, tenant model, global filters, and AOC alignment with compliance checklist. | Doc merged with diagrams + overview tables; checklist appended; Console Guild sign-off. |
|
||||||
| DOCS-CONSOLE-23-002 | DONE (2025-10-26) | Docs Guild, Console Guild | DOCS-CONSOLE-23-001 | Author `/docs/ui/navigation.md` detailing routes, breadcrumbs, keyboard shortcuts, deep links, and tenant context switching. | Navigation doc merged with shortcut tables and screenshots; accessibility checklist satisfied. |
|
| DOCS-CONSOLE-23-002 | DONE (2025-10-26) | Docs Guild, Console Guild | DOCS-CONSOLE-23-001 | Author `/docs/ui/navigation.md` detailing routes, breadcrumbs, keyboard shortcuts, deep links, and tenant context switching. | Navigation doc merged with shortcut tables and screenshots; accessibility checklist satisfied. |
|
||||||
| DOCS-CONSOLE-23-003 | DONE (2025-10-26) | Docs Guild, SBOM Service Guild, Console Guild | SBOM-CONSOLE-23-001, CONSOLE-FEAT-23-102 | Document `/docs/ui/sbom-explorer.md` (catalog, detail, graph overlays, exports) including compliance checklist and performance tips. | Doc merged with annotated screenshots, export instructions, and overlay examples; checklist appended. |
|
| DOCS-CONSOLE-23-003 | DONE (2025-10-26) | Docs Guild, SBOM Service Guild, Console Guild | SBOM-CONSOLE-23-001, CONSOLE-FEAT-23-102 | Document `/docs/ui/sbom-explorer.md` (catalog, detail, graph overlays, exports) including compliance checklist and performance tips. | Doc merged with annotated screenshots, export instructions, and overlay examples; checklist appended. |
|
||||||
| DOCS-CONSOLE-23-004 | DONE (2025-10-26) | Docs Guild, Concelier Guild, Excititor Guild | CONCELIER-CONSOLE-23-001, EXCITITOR-CONSOLE-23-001 | Produce `/docs/ui/advisories-and-vex.md` explaining aggregation-not-merge, conflict indicators, raw viewers, and provenance banners. | Doc merged; raw JSON examples included; compliance checklist complete. |
|
| DOCS-CONSOLE-23-004 | DONE (2025-10-26) | Docs Guild, Concelier Guild, Excititor Guild | CONCELIER-CONSOLE-23-001, EXCITITOR-CONSOLE-23-001 | Produce `/docs/ui/advisories-and-vex.md` explaining aggregation-not-merge, conflict indicators, raw viewers, and provenance banners. | Doc merged; raw JSON examples included; compliance checklist complete. |
|
||||||
| DOCS-CONSOLE-23-005 | DONE (2025-10-26) | Docs Guild, Policy Guild | POLICY-CONSOLE-23-001, CONSOLE-FEAT-23-104 | Write `/docs/ui/findings.md` describing filters, saved views, explain drawer, exports, and CLI parity callouts. | Doc merged with filter matrix + explain walkthrough; checklist appended. |
|
| DOCS-CONSOLE-23-005 | DONE (2025-10-26) | Docs Guild, Policy Guild | POLICY-CONSOLE-23-001, CONSOLE-FEAT-23-104 | Write `/docs/ui/findings.md` describing filters, saved views, explain drawer, exports, and CLI parity callouts. | Doc merged with filter matrix + explain walkthrough; checklist appended. |
|
||||||
| DOCS-CONSOLE-23-006 | DONE (2025-10-26) | Docs Guild, Policy Guild, Product Ops | POLICY-CONSOLE-23-002, CONSOLE-FEAT-23-105 | Publish `/docs/ui/policies.md` with editor, simulation, approvals, compliance checklist, and RBAC mapping. | Doc merged; Monaco screenshots + simulation diff examples included; approval flow described; checklist appended. |
|
| DOCS-CONSOLE-23-006 | DONE (2025-10-26) | Docs Guild, Policy Guild, Product Ops | POLICY-CONSOLE-23-002, CONSOLE-FEAT-23-105 | Publish `/docs/ui/policies.md` with editor, simulation, approvals, compliance checklist, and RBAC mapping. | Doc merged; Monaco screenshots + simulation diff examples included; approval flow described; checklist appended. |
|
||||||
| DOCS-CONSOLE-23-007 | DONE (2025-10-26) | Docs Guild, Scheduler Guild | SCHED-CONSOLE-23-001, CONSOLE-FEAT-23-106 | Document `/docs/ui/runs.md` covering queues, live progress, diffs, retries, evidence downloads, and troubleshooting. | Doc merged with SSE troubleshooting, metrics references, compliance checklist. |
|
| DOCS-CONSOLE-23-007 | DONE (2025-10-26) | Docs Guild, Scheduler Guild | SCHED-CONSOLE-23-001, CONSOLE-FEAT-23-106 | Document `/docs/ui/runs.md` covering queues, live progress, diffs, retries, evidence downloads, and troubleshooting. | Doc merged with SSE troubleshooting, metrics references, compliance checklist. |
|
||||||
| DOCS-CONSOLE-23-008 | DONE (2025-10-26) | Docs Guild, Authority Guild | AUTH-CONSOLE-23-002, CONSOLE-FEAT-23-108 | Draft `/docs/ui/admin.md` describing users/roles, tenants, tokens, integrations, fresh-auth prompts, and RBAC mapping. | Doc merged with tables for scopes vs roles, screenshots, compliance checklist. |
|
| DOCS-CONSOLE-23-008 | DONE (2025-10-26) | Docs Guild, Authority Guild | AUTH-CONSOLE-23-002, CONSOLE-FEAT-23-108 | Draft `/docs/ui/admin.md` describing users/roles, tenants, tokens, integrations, fresh-auth prompts, and RBAC mapping. | Doc merged with tables for scopes vs roles, screenshots, compliance checklist. |
|
||||||
| DOCS-CONSOLE-23-009 | DONE (2025-10-27) | Docs Guild, DevOps Guild | DOWNLOADS-CONSOLE-23-001, CONSOLE-FEAT-23-109 | Publish `/docs/ui/downloads.md` listing product images, commands, offline instructions, parity with CLI, and compliance checklist. | Doc merged; manifest sample included; copy-to-clipboard guidance documented; checklist complete. |
|
| DOCS-CONSOLE-23-009 | DONE (2025-10-27) | Docs Guild, DevOps Guild | DOWNLOADS-CONSOLE-23-001, CONSOLE-FEAT-23-109 | Publish `/docs/ui/downloads.md` listing product images, commands, offline instructions, parity with CLI, and compliance checklist. | Doc merged; manifest sample included; copy-to-clipboard guidance documented; checklist complete. |
|
||||||
| DOCS-CONSOLE-23-010 | DONE (2025-10-27) | Docs Guild, Deployment Guild, Console Guild | DEVOPS-CONSOLE-23-002, CONSOLE-REL-23-301 | Write `/docs/deploy/console.md` (Helm, ingress, TLS, CSP, env vars, health checks) with compliance checklist. | Deploy doc merged; templates validated; CSP guidance included; checklist appended. |
|
| DOCS-CONSOLE-23-010 | DONE (2025-10-27) | Docs Guild, Deployment Guild, Console Guild | DEVOPS-CONSOLE-23-002, CONSOLE-REL-23-301 | Write `/docs/deploy/console.md` (Helm, ingress, TLS, CSP, env vars, health checks) with compliance checklist. | Deploy doc merged; templates validated; CSP guidance included; checklist appended. |
|
||||||
| DOCS-CONSOLE-23-011 | DONE (2025-10-28) | Docs Guild, Deployment Guild | DOCS-CONSOLE-23-010 | Update `/docs/install/docker.md` to cover Console image, Compose/Helm usage, offline tarballs, parity with CLI. | Doc updated with new sections; commands validated; compliance checklist appended. |
|
| DOCS-CONSOLE-23-011 | DONE (2025-10-28) | Docs Guild, Deployment Guild | DOCS-CONSOLE-23-010 | Update `/docs/install/docker.md` to cover Console image, Compose/Helm usage, offline tarballs, parity with CLI. | Doc updated with new sections; commands validated; compliance checklist appended. |
|
||||||
| DOCS-CONSOLE-23-012 | DONE (2025-10-28) | Docs Guild, Security Guild | AUTH-CONSOLE-23-003, WEB-CONSOLE-23-002 | Publish `/docs/security/console-security.md` detailing OIDC flows, scopes, CSP, fresh-auth, evidence handling, and compliance checklist. | Security doc merged; threat model notes included; checklist appended. |
|
| DOCS-CONSOLE-23-012 | DONE (2025-10-28) | Docs Guild, Security Guild | AUTH-CONSOLE-23-003, WEB-CONSOLE-23-002 | Publish `/docs/security/console-security.md` detailing OIDC flows, scopes, CSP, fresh-auth, evidence handling, and compliance checklist. | Security doc merged; threat model notes included; checklist appended. |
|
||||||
| DOCS-CONSOLE-23-013 | DONE (2025-10-28) | Docs Guild, Observability Guild | TELEMETRY-CONSOLE-23-001, CONSOLE-QA-23-403 | Write `/docs/observability/ui-telemetry.md` cataloguing metrics/logs/traces, dashboards, alerts, and feature flags. | Doc merged with instrumentation tables, dashboard screenshots, checklist appended. |
|
| DOCS-CONSOLE-23-013 | DONE (2025-10-28) | Docs Guild, Observability Guild | TELEMETRY-CONSOLE-23-001, CONSOLE-QA-23-403 | Write `/docs/observability/ui-telemetry.md` cataloguing metrics/logs/traces, dashboards, alerts, and feature flags. | Doc merged with instrumentation tables, dashboard screenshots, checklist appended. |
|
||||||
| DOCS-CONSOLE-23-014 | DONE (2025-10-28) | Docs Guild, Console Guild, CLI Guild | CONSOLE-DOC-23-502 | Maintain `/docs/cli-vs-ui-parity.md` matrix and integrate CI check guidance. | Matrix published with parity status, CI workflow documented, compliance checklist appended. |
|
| DOCS-CONSOLE-23-014 | DONE (2025-10-28) | Docs Guild, Console Guild, CLI Guild | CONSOLE-DOC-23-502 | Maintain `/docs/cli-vs-ui-parity.md` matrix and integrate CI check guidance. | Matrix published with parity status, CI workflow documented, compliance checklist appended. |
|
||||||
> 2025-10-28: Install Docker guide references pending CLI commands (`stella downloads manifest`, `stella downloads mirror`, `stella console status`). Update once CLI parity lands.
|
> 2025-10-28: Install Docker guide references pending CLI commands (`stella downloads manifest`, `stella downloads mirror`, `stella console status`). Update once CLI parity lands.
|
||||||
| DOCS-CONSOLE-23-015 | DONE (2025-10-27) | Docs Guild, Architecture Guild | CONSOLE-CORE-23-001, WEB-CONSOLE-23-001 | Produce `/docs/architecture/console.md` describing frontend packages, data flow diagrams, SSE design, performance budgets. | Architecture doc merged with diagrams + compliance checklist; reviewers approve. |
|
| DOCS-CONSOLE-23-015 | DONE (2025-10-27) | Docs Guild, Architecture Guild | CONSOLE-CORE-23-001, WEB-CONSOLE-23-001 | Produce `/docs/architecture/console.md` describing frontend packages, data flow diagrams, SSE design, performance budgets. | Architecture doc merged with diagrams + compliance checklist; reviewers approve. |
|
||||||
| DOCS-CONSOLE-23-016 | DONE (2025-10-28) | Docs Guild, Accessibility Guild | CONSOLE-QA-23-402, CONSOLE-FEAT-23-102 | Refresh `/docs/accessibility.md` with Console-specific keyboard flows, color tokens, testing tools, and compliance checklist updates. | Accessibility doc updated; audits referenced; checklist appended. |
|
| DOCS-CONSOLE-23-016 | DONE (2025-10-28) | Docs Guild, Accessibility Guild | CONSOLE-QA-23-402, CONSOLE-FEAT-23-102 | Refresh `/docs/accessibility.md` with Console-specific keyboard flows, color tokens, testing tools, and compliance checklist updates. | Accessibility doc updated; audits referenced; checklist appended. |
|
||||||
> 2025-10-28: Added guide covering keyboard matrix, screen reader behaviour, colour/focus tokens, testing workflow, offline guidance, and compliance checklist.
|
> 2025-10-28: Added guide covering keyboard matrix, screen reader behaviour, colour/focus tokens, testing workflow, offline guidance, and compliance checklist.
|
||||||
| DOCS-CONSOLE-23-017 | DONE (2025-10-27) | Docs Guild, Console Guild | CONSOLE-FEAT-23-101..109 | Create `/docs/examples/ui-tours.md` providing triage, audit, policy rollout walkthroughs with annotated screenshots and GIFs. | UI tours doc merged; capture instructions + asset placeholders committed; compliance checklist appended. |
|
| DOCS-CONSOLE-23-017 | DONE (2025-10-27) | Docs Guild, Console Guild | CONSOLE-FEAT-23-101..109 | Create `/docs/examples/ui-tours.md` providing triage, audit, policy rollout walkthroughs with annotated screenshots and GIFs. | UI tours doc merged; capture instructions + asset placeholders committed; compliance checklist appended. |
|
||||||
| DOCS-CONSOLE-23-018 | DONE (2025-10-27) | Docs Guild, Security Guild | DOCS-CONSOLE-23-012 | Execute console security compliance checklist and capture Security Guild sign-off in Sprint 23 log. | Checklist completed; findings addressed or tickets filed; sign-off noted in updates file. |
|
| DOCS-CONSOLE-23-018 | DONE (2025-10-27) | Docs Guild, Security Guild | DOCS-CONSOLE-23-012 | Execute console security compliance checklist and capture Security Guild sign-off in Sprint 23 log. | Checklist completed; findings addressed or tickets filed; sign-off noted in updates file. |
|
||||||
| DOCS-LNM-22-006 | DONE (2025-10-27) | Docs Guild, Architecture Guild | CONCELIER-LNM-21-001..005, EXCITITOR-LNM-21-001..005 | Refresh `/docs/architecture/conseiller.md` and `/docs/architecture/excitator.md` describing observation/linkset pipelines and event contracts. | Architecture docs updated with observation/linkset flow + event tables; revisit once service implementations land. |
|
| DOCS-LNM-22-006 | DONE (2025-10-27) | Docs Guild, Architecture Guild | CONCELIER-LNM-21-001..005, EXCITITOR-LNM-21-001..005 | Refresh `/docs/architecture/conseiller.md` and `/docs/architecture/excitator.md` describing observation/linkset pipelines and event contracts. | Architecture docs updated with observation/linkset flow + event tables; revisit once service implementations land. |
|
||||||
> Follow-up: align diagrams/examples after `CONCELIER-LNM-21` & `EXCITITOR-LNM-21` work merges (currently TODO).
|
> Follow-up: align diagrams/examples after `CONCELIER-LNM-21` & `EXCITITOR-LNM-21` work merges (currently TODO).
|
||||||
| DOCS-LNM-22-007 | TODO | Docs Guild, Observability Guild | CONCELIER-LNM-21-005, EXCITITOR-LNM-21-005, DEVOPS-LNM-22-002 | Publish `/docs/observability/aggregation.md` with metrics/traces/logs/SLOs. | Observability doc merged; dashboards referenced; checklist appended. |
|
| DOCS-LNM-22-007 | TODO | Docs Guild, Observability Guild | CONCELIER-LNM-21-005, EXCITITOR-LNM-21-005, DEVOPS-LNM-22-002 | Publish `/docs/observability/aggregation.md` with metrics/traces/logs/SLOs. | Observability doc merged; dashboards referenced; checklist appended. |
|
||||||
| DOCS-LNM-22-008 | TODO | Docs Guild, DevOps Guild | MERGE-LNM-21-001, CONCELIER-LNM-21-102 | Write `/docs/migration/no-merge.md` describing migration plan, backfill steps, rollback, feature flags. | Migration doc approved by stakeholders; checklist appended. |
|
| DOCS-LNM-22-008 | TODO | Docs Guild, DevOps Guild | MERGE-LNM-21-001, CONCELIER-LNM-21-102 | Write `/docs/migration/no-merge.md` describing migration plan, backfill steps, rollback, feature flags. | Migration doc approved by stakeholders; checklist appended. |
|
||||||
|
|
||||||
## Policy Engine + Editor v1
|
## Policy Engine + Editor v1
|
||||||
|
|
||||||
| ID | Status | Owner(s) | Depends on | Description | Exit Criteria |
|
| ID | Status | Owner(s) | Depends on | Description | Exit Criteria |
|
||||||
|----|--------|----------|------------|-------------|---------------|
|
|----|--------|----------|------------|-------------|---------------|
|
||||||
| DOCS-POLICY-23-001 | TODO | Docs Guild, Policy Guild | POLICY-SPL-23-001..003 | Author `/docs/policy/overview.md` describing SPL philosophy, layering, and glossary with reviewer checklist. | Doc merged; lint passes; checklist appended. |
|
| DOCS-POLICY-23-001 | TODO | Docs Guild, Policy Guild | POLICY-SPL-23-001..003 | Author `/docs/policy/overview.md` describing SPL philosophy, layering, and glossary with reviewer checklist. | Doc merged; lint passes; checklist appended. |
|
||||||
| DOCS-POLICY-23-002 | TODO | Docs Guild, Policy Guild | POLICY-SPL-23-001 | Write `/docs/policy/spl-v1.md` (language reference, JSON Schema, examples). | Reference published with schema snippets; checklist completed. |
|
| DOCS-POLICY-23-002 | TODO | Docs Guild, Policy Guild | POLICY-SPL-23-001 | Write `/docs/policy/spl-v1.md` (language reference, JSON Schema, examples). | Reference published with schema snippets; checklist completed. |
|
||||||
| DOCS-POLICY-23-003 | TODO | Docs Guild, Policy Guild | POLICY-ENGINE-50-001..004 | Produce `/docs/policy/runtime.md` covering compiler, evaluator, caching, events, SLOs. | Runtime doc merged with diagrams; observability references included. |
|
| DOCS-POLICY-23-003 | TODO | Docs Guild, Policy Guild | POLICY-ENGINE-50-001..004 | Produce `/docs/policy/runtime.md` covering compiler, evaluator, caching, events, SLOs. | Runtime doc merged with diagrams; observability references included. |
|
||||||
| DOCS-POLICY-23-004 | TODO | Docs Guild, UI Guild | UI-POLICY-23-001..006 | Document `/docs/policy/editor.md` (UI walkthrough, validation, simulation, approvals). | Editor doc merged with screenshots; accessibility checklist satisfied. |
|
| DOCS-POLICY-23-004 | TODO | Docs Guild, UI Guild | UI-POLICY-23-001..006 | Document `/docs/policy/editor.md` (UI walkthrough, validation, simulation, approvals). | Editor doc merged with screenshots; accessibility checklist satisfied. |
|
||||||
| DOCS-POLICY-23-005 | TODO | Docs Guild, Security Guild | AUTH-POLICY-23-001..002 | Publish `/docs/policy/governance.md` (roles, scopes, approvals, signing, exceptions). | Governance doc merged; checklist appended. |
|
| DOCS-POLICY-23-005 | TODO | Docs Guild, Security Guild | AUTH-POLICY-23-001..002 | Publish `/docs/policy/governance.md` (roles, scopes, approvals, signing, exceptions). | Governance doc merged; checklist appended. |
|
||||||
| DOCS-POLICY-23-006 | TODO | Docs Guild, BE-Base Platform Guild | WEB-POLICY-23-001..004 | Update `/docs/api/policy.md` with new endpoints, schemas, errors, pagination. | API doc aligns with OpenAPI; examples validated; checklist included. |
|
| DOCS-POLICY-23-006 | TODO | Docs Guild, BE-Base Platform Guild | WEB-POLICY-23-001..004 | Update `/docs/api/policy.md` with new endpoints, schemas, errors, pagination. | API doc aligns with OpenAPI; examples validated; checklist included. |
|
||||||
| DOCS-POLICY-23-007 | TODO | Docs Guild, DevEx/CLI Guild | CLI-POLICY-23-004..006 | Update `/docs/cli/policy.md` for lint/simulate/activate/history commands, exit codes. | CLI doc updated; samples verified; checklist appended. |
|
| DOCS-POLICY-23-007 | TODO | Docs Guild, DevEx/CLI Guild | CLI-POLICY-23-004..006 | Update `/docs/cli/policy.md` for lint/simulate/activate/history commands, exit codes. | CLI doc updated; samples verified; checklist appended. |
|
||||||
| DOCS-POLICY-23-008 | TODO | Docs Guild, Architecture Guild | POLICY-ENGINE-50-005..006 | Refresh `/docs/architecture/policy-engine.md` with data model, sequence diagrams, event flows. | Architecture doc merged with diagrams; checklist appended. |
|
| DOCS-POLICY-23-008 | TODO | Docs Guild, Architecture Guild | POLICY-ENGINE-50-005..006 | Refresh `/docs/architecture/policy-engine.md` with data model, sequence diagrams, event flows. | Architecture doc merged with diagrams; checklist appended. |
|
||||||
| DOCS-POLICY-23-009 | TODO | Docs Guild, DevOps Guild | MERGE-LNM-21-001, DEVOPS-LNM-22-001 | Create `/docs/migration/policy-parity.md` covering dual-run parity plan and rollback. | Migration doc approved; checklist appended. |
|
| DOCS-POLICY-23-009 | TODO | Docs Guild, DevOps Guild | MERGE-LNM-21-001, DEVOPS-LNM-22-001 | Create `/docs/migration/policy-parity.md` covering dual-run parity plan and rollback. | Migration doc approved; checklist appended. |
|
||||||
| DOCS-POLICY-23-010 | TODO | Docs Guild, UI Guild | UI-POLICY-23-006 | Write `/docs/ui/explainers.md` showing explain trees, evidence overlays, interpretation guidance. | Doc merged with annotated screenshots; checklist appended. |
|
| DOCS-POLICY-23-010 | TODO | Docs Guild, UI Guild | UI-POLICY-23-006 | Write `/docs/ui/explainers.md` showing explain trees, evidence overlays, interpretation guidance. | Doc merged with annotated screenshots; checklist appended. |
|
||||||
|
|
||||||
## Graph & Vuln Explorer v1
|
## Graph & Vuln Explorer v1
|
||||||
|
|
||||||
| ID | Status | Owner(s) | Depends on | Description | Exit Criteria |
|
| ID | Status | Owner(s) | Depends on | Description | Exit Criteria |
|
||||||
|----|--------|----------|------------|-------------|---------------|
|
|----|--------|----------|------------|-------------|---------------|
|
||||||
| DOCS-GRAPH-24-001 | TODO | Docs Guild, UI Guild | UI-GRAPH-24-001..006 | Author `/docs/ui/sbom-graph-explorer.md` detailing overlays, filters, saved views, accessibility, and AOC visibility. | Doc merged; screenshots included; checklist appended. |
|
| DOCS-GRAPH-24-001 | TODO | Docs Guild, UI Guild | UI-GRAPH-24-001..006 | Author `/docs/ui/sbom-graph-explorer.md` detailing overlays, filters, saved views, accessibility, and AOC visibility. | Doc merged; screenshots included; checklist appended. |
|
||||||
| DOCS-GRAPH-24-002 | TODO | Docs Guild, UI Guild | UI-GRAPH-24-005 | Publish `/docs/ui/vulnerability-explorer.md` covering table usage, grouping, fix suggestions, Why drawer. | Doc merged with annotated images; accessibility checklist satisfied. |
|
| DOCS-GRAPH-24-002 | TODO | Docs Guild, UI Guild | UI-GRAPH-24-005 | Publish `/docs/ui/vulnerability-explorer.md` covering table usage, grouping, fix suggestions, Why drawer. | Doc merged with annotated images; accessibility checklist satisfied. |
|
||||||
| DOCS-GRAPH-24-003 | TODO | Docs Guild, SBOM Service Guild | SBOM-GRAPH-24-001..003 | Create `/docs/architecture/graph-index.md` describing data model, ingestion pipeline, caches, events. | Architecture doc merged with diagrams; checklist appended. |
|
| DOCS-GRAPH-24-003 | TODO | Docs Guild, SBOM Service Guild | SBOM-GRAPH-24-001..003 | Create `/docs/architecture/graph-index.md` describing data model, ingestion pipeline, caches, events. | Architecture doc merged with diagrams; checklist appended. |
|
||||||
| DOCS-GRAPH-24-004 | TODO | Docs Guild, BE-Base Platform Guild | WEB-GRAPH-24-001..003 | Document `/docs/api/graph.md` and `/docs/api/vuln.md` avec endpoints, parameters, errors, RBAC. | API docs aligned with OpenAPI; examples validated; checklist appended. |
|
| DOCS-GRAPH-24-004 | TODO | Docs Guild, BE-Base Platform Guild | WEB-GRAPH-24-001..003 | Document `/docs/api/graph.md` and `/docs/api/vuln.md` avec endpoints, parameters, errors, RBAC. | API docs aligned with OpenAPI; examples validated; checklist appended. |
|
||||||
| DOCS-GRAPH-24-005 | TODO | Docs Guild, DevEx/CLI Guild | CLI-GRAPH-24-001..003 | Update `/docs/cli/graph-and-vuln.md` covering new CLI commands, exit codes, scripting. | CLI doc merged; examples tested; checklist appended. |
|
| DOCS-GRAPH-24-005 | TODO | Docs Guild, DevEx/CLI Guild | CLI-GRAPH-24-001..003 | Update `/docs/cli/graph-and-vuln.md` covering new CLI commands, exit codes, scripting. | CLI doc merged; examples tested; checklist appended. |
|
||||||
| DOCS-GRAPH-24-006 | TODO | Docs Guild, Policy Guild | POLICY-ENGINE-60-001..002 | Write `/docs/policy/ui-integration.md` explaining overlays, cache usage, simulator contracts. | Doc merged; references cross-linked; checklist appended. |
|
| DOCS-GRAPH-24-006 | TODO | Docs Guild, Policy Guild | POLICY-ENGINE-60-001..002 | Write `/docs/policy/ui-integration.md` explaining overlays, cache usage, simulator contracts. | Doc merged; references cross-linked; checklist appended. |
|
||||||
| DOCS-GRAPH-24-007 | TODO | Docs Guild, DevOps Guild | DEVOPS-GRAPH-24-001..003 | Produce `/docs/migration/graph-parity.md` with rollout plan, parity checks, fallback guidance. | Migration doc approved; checklist appended. |
|
| DOCS-GRAPH-24-007 | TODO | Docs Guild, DevOps Guild | DEVOPS-GRAPH-24-001..003 | Produce `/docs/migration/graph-parity.md` with rollout plan, parity checks, fallback guidance. | Migration doc approved; checklist appended. |
|
||||||
|
|
||||||
## Exceptions v1
|
## Exceptions v1
|
||||||
|
|
||||||
| ID | Status | Owner(s) | Depends on | Description | Exit Criteria |
|
| ID | Status | Owner(s) | Depends on | Description | Exit Criteria |
|
||||||
|----|--------|----------|------------|-------------|---------------|
|
|----|--------|----------|------------|-------------|---------------|
|
||||||
| DOCS-EXC-25-001 | TODO | Docs Guild, Governance Guild | WEB-EXC-25-001 | Author `/docs/governance/exceptions.md` covering lifecycle, scope patterns, examples, compliance checklist. | Doc merged; reviewers sign off; checklist included. |
|
| DOCS-EXC-25-001 | TODO | Docs Guild, Governance Guild | WEB-EXC-25-001 | Author `/docs/governance/exceptions.md` covering lifecycle, scope patterns, examples, compliance checklist. | Doc merged; reviewers sign off; checklist included. |
|
||||||
| DOCS-EXC-25-002 | TODO | Docs Guild, Authority Core | AUTH-EXC-25-001 | Publish `/docs/governance/approvals-and-routing.md` detailing roles, routing matrix, MFA rules, audit trails. | Doc merged; routing examples validated; checklist appended. |
|
| DOCS-EXC-25-002 | TODO | Docs Guild, Authority Core | AUTH-EXC-25-001 | Publish `/docs/governance/approvals-and-routing.md` detailing roles, routing matrix, MFA rules, audit trails. | Doc merged; routing examples validated; checklist appended. |
|
||||||
| DOCS-EXC-25-003 | TODO | Docs Guild, BE-Base Platform Guild | WEB-EXC-25-001..003 | Create `/docs/api/exceptions.md` with endpoints, payloads, errors, idempotency notes. | API doc aligned with OpenAPI; examples tested; checklist appended. |
|
| DOCS-EXC-25-003 | TODO | Docs Guild, BE-Base Platform Guild | WEB-EXC-25-001..003 | Create `/docs/api/exceptions.md` with endpoints, payloads, errors, idempotency notes. | API doc aligned with OpenAPI; examples tested; checklist appended. |
|
||||||
| DOCS-EXC-25-004 | DONE (2025-10-27) | Docs Guild, Policy Guild | POLICY-ENGINE-70-001 | Document `/docs/policy/exception-effects.md` explaining evaluation order, conflicts, simulation. | Doc merged; tests cross-referenced; checklist appended. |
|
| DOCS-EXC-25-004 | DONE (2025-10-27) | Docs Guild, Policy Guild | POLICY-ENGINE-70-001 | Document `/docs/policy/exception-effects.md` explaining evaluation order, conflicts, simulation. | Doc merged; tests cross-referenced; checklist appended. |
|
||||||
| DOCS-EXC-25-005 | TODO | Docs Guild, UI Guild | UI-EXC-25-001..004 | Write `/docs/ui/exception-center.md` with UI walkthrough, badges, accessibility, shortcuts. | Doc merged with screenshots; accessibility checklist completed. |
|
| DOCS-EXC-25-005 | TODO | Docs Guild, UI Guild | UI-EXC-25-001..004 | Write `/docs/ui/exception-center.md` with UI walkthrough, badges, accessibility, shortcuts. | Doc merged with screenshots; accessibility checklist completed. |
|
||||||
| DOCS-EXC-25-006 | TODO | Docs Guild, DevEx/CLI Guild | CLI-EXC-25-001..002 | Update `/docs/cli/exceptions.md` covering command usage and exit codes. | CLI doc updated; examples validated; checklist appended. |
|
| DOCS-EXC-25-006 | TODO | Docs Guild, DevEx/CLI Guild | CLI-EXC-25-001..002 | Update `/docs/cli/exceptions.md` covering command usage and exit codes. | CLI doc updated; examples validated; checklist appended. |
|
||||||
| DOCS-EXC-25-007 | TODO | Docs Guild, DevOps Guild | SCHED-WORKER-25-101, DEVOPS-GRAPH-24-003 | Publish `/docs/migration/exception-governance.md` describing cutover from legacy suppressions, notifications, rollback. | Migration doc approved; checklist included. |
|
| DOCS-EXC-25-007 | TODO | Docs Guild, DevOps Guild | SCHED-WORKER-25-101, DEVOPS-GRAPH-24-003 | Publish `/docs/migration/exception-governance.md` describing cutover from legacy suppressions, notifications, rollback. | Migration doc approved; checklist included. |
|
||||||
|
|
||||||
> Update statuses (TODO/DOING/REVIEW/DONE/BLOCKED) as progress changes. Keep guides in sync with configuration samples under `etc/`.
|
> Update statuses (TODO/DOING/REVIEW/DONE/BLOCKED) as progress changes. Keep guides in sync with configuration samples under `etc/`.
|
||||||
|
|
||||||
> Remark (2025-10-13, DOC4.AUTH-PDG): Rate limit guide published (`docs/security/rate-limits.md`) and handed to plugin docs team for diagram uplift once PLG6.DIAGRAM lands.
|
> Remark (2025-10-13, DOC4.AUTH-PDG): Rate limit guide published (`docs/security/rate-limits.md`) and handed to plugin docs team for diagram uplift once PLG6.DIAGRAM lands.
|
||||||
|
|
||||||
## Orchestrator Dashboard (Epic 9)
|
## Orchestrator Dashboard (Epic 9)
|
||||||
|
|
||||||
| ID | Status | Owner(s) | Depends on | Description | Exit Criteria |
|
| ID | Status | Owner(s) | Depends on | Description | Exit Criteria |
|
||||||
|----|--------|----------|------------|-------------|---------------|
|
|----|--------|----------|------------|-------------|---------------|
|
||||||
| DOCS-ORCH-32-001 | TODO | Docs Guild | ORCH-SVC-32-001, AUTH-ORCH-32-001 | Author `/docs/orchestrator/overview.md` covering mission, roles, AOC alignment, governance, with imposed rule reminder. | Doc merged with diagrams; imposed rule statement included; entry linked from docs index. |
|
| DOCS-ORCH-32-001 | TODO | Docs Guild | ORCH-SVC-32-001, AUTH-ORCH-32-001 | Author `/docs/orchestrator/overview.md` covering mission, roles, AOC alignment, governance, with imposed rule reminder. | Doc merged with diagrams; imposed rule statement included; entry linked from docs index. |
|
||||||
| DOCS-ORCH-32-002 | TODO | Docs Guild | ORCH-SVC-32-002 | Author `/docs/orchestrator/architecture.md` detailing scheduler, DAGs, rate limits, data model, message bus, storage layout, restating imposed rule. | Architecture doc merged; diagrams reviewed; imposed rule noted. |
|
| DOCS-ORCH-32-002 | TODO | Docs Guild | ORCH-SVC-32-002 | Author `/docs/orchestrator/architecture.md` detailing scheduler, DAGs, rate limits, data model, message bus, storage layout, restating imposed rule. | Architecture doc merged; diagrams reviewed; imposed rule noted. |
|
||||||
| DOCS-ORCH-33-001 | TODO | Docs Guild | ORCH-SVC-33-001..004, WEB-ORCH-33-001 | Publish `/docs/orchestrator/api.md` (REST/WebSocket endpoints, payloads, error codes) with imposed rule note. | API doc merged; examples validated; imposed rule appended. |
|
| DOCS-ORCH-33-001 | TODO | Docs Guild | ORCH-SVC-33-001..004, WEB-ORCH-33-001 | Publish `/docs/orchestrator/api.md` (REST/WebSocket endpoints, payloads, error codes) with imposed rule note. | API doc merged; examples validated; imposed rule appended. |
|
||||||
| DOCS-ORCH-33-002 | TODO | Docs Guild | CONSOLE-ORCH-32-002, CONSOLE-ORCH-33-001..002 | Publish `/docs/orchestrator/console.md` covering screens, a11y, live updates, control actions, reiterating imposed rule. | Console doc merged with screenshots; accessibility checklist done; imposed rule statement present. |
|
| DOCS-ORCH-33-002 | TODO | Docs Guild | CONSOLE-ORCH-32-002, CONSOLE-ORCH-33-001..002 | Publish `/docs/orchestrator/console.md` covering screens, a11y, live updates, control actions, reiterating imposed rule. | Console doc merged with screenshots; accessibility checklist done; imposed rule statement present. |
|
||||||
| DOCS-ORCH-33-003 | TODO | Docs Guild | CLI-ORCH-33-001 | Publish `/docs/orchestrator/cli.md` documenting commands, options, exit codes, streaming output, offline usage, and imposed rule. | CLI doc merged; examples tested; imposed rule appended. |
|
| DOCS-ORCH-33-003 | TODO | Docs Guild | CLI-ORCH-33-001 | Publish `/docs/orchestrator/cli.md` documenting commands, options, exit codes, streaming output, offline usage, and imposed rule. | CLI doc merged; examples tested; imposed rule appended. |
|
||||||
| DOCS-ORCH-34-001 | TODO | Docs Guild | ORCH-SVC-34-002, LEDGER-34-101 | Author `/docs/orchestrator/run-ledger.md` covering ledger schema, provenance chain, audit workflows, with imposed rule reminder. | Run-ledger doc merged; payload samples validated; imposed rule included; cross-links added. |
|
| DOCS-ORCH-34-001 | TODO | Docs Guild | ORCH-SVC-34-002, LEDGER-34-101 | Author `/docs/orchestrator/run-ledger.md` covering ledger schema, provenance chain, audit workflows, with imposed rule reminder. | Run-ledger doc merged; payload samples validated; imposed rule included; cross-links added. |
|
||||||
| DOCS-ORCH-34-002 | TODO | Docs Guild | AUTH-ORCH-32-001, AUTH-ORCH-34-001 | Update `/docs/security/secrets-handling.md` for orchestrator KMS refs, redaction badges, operator hygiene, reiterating imposed rule. | Security doc merged; checklists updated; imposed rule restated; references from Console/CLI docs added. |
|
| DOCS-ORCH-34-002 | TODO | Docs Guild | AUTH-ORCH-32-001, AUTH-ORCH-34-001 | Update `/docs/security/secrets-handling.md` for orchestrator KMS refs, redaction badges, operator hygiene, reiterating imposed rule. | Security doc merged; checklists updated; imposed rule restated; references from Console/CLI docs added. |
|
||||||
| DOCS-ORCH-34-003 | TODO | Docs Guild | ORCH-SVC-33-003, ORCH-SVC-34-001, DEVOPS-ORCH-34-001 | Publish `/docs/operations/orchestrator-runbook.md` (incident playbook, backfill guide, circuit breakers, throttling) with imposed rule statement. | Runbook merged; steps validated with DevOps; imposed rule included; runbook linked from ops index. |
|
| DOCS-ORCH-34-003 | TODO | Docs Guild | ORCH-SVC-33-003, ORCH-SVC-34-001, DEVOPS-ORCH-34-001 | Publish `/docs/operations/orchestrator-runbook.md` (incident playbook, backfill guide, circuit breakers, throttling) with imposed rule statement. | Runbook merged; steps validated with DevOps; imposed rule included; runbook linked from ops index. |
|
||||||
| DOCS-ORCH-34-004 | TODO | Docs Guild | ORCH-SVC-32-005, WORKER-GO-33-001, WORKER-PY-33-001 | Document `/docs/schemas/artifacts.md` describing artifact kinds, schema versions, hashing, storage layout, restating imposed rule. | Schema doc merged; JSON schema provided; imposed rule included; sample payload validated. |
|
| DOCS-ORCH-34-004 | TODO | Docs Guild | ORCH-SVC-32-005, WORKER-GO-33-001, WORKER-PY-33-001 | Document `/docs/schemas/artifacts.md` describing artifact kinds, schema versions, hashing, storage layout, restating imposed rule. | Schema doc merged; JSON schema provided; imposed rule included; sample payload validated. |
|
||||||
| DOCS-ORCH-34-005 | TODO | Docs Guild | ORCH-SVC-34-001, DEVOPS-ORCH-34-001 | Author `/docs/slo/orchestrator-slo.md` defining SLOs, burn alerts, measurement, and reiterating imposed rule. | SLO doc merged; dashboard screenshots embedded; imposed rule appended; alerts documented. |
|
| DOCS-ORCH-34-005 | TODO | Docs Guild | ORCH-SVC-34-001, DEVOPS-ORCH-34-001 | Author `/docs/slo/orchestrator-slo.md` defining SLOs, burn alerts, measurement, and reiterating imposed rule. | SLO doc merged; dashboard screenshots embedded; imposed rule appended; alerts documented. |
|
||||||
|
|
||||||
## Export Center (Epic 10)
|
## Export Center (Epic 10)
|
||||||
|
|
||||||
| ID | Status | Owner(s) | Depends on | Description | Exit Criteria |
|
| ID | Status | Owner(s) | Depends on | Description | Exit Criteria |
|
||||||
|----|--------|----------|------------|-------------|---------------|
|
|----|--------|----------|------------|-------------|---------------|
|
||||||
| DOCS-EXPORT-35-001 | DONE (2025-10-29) | Docs Guild | EXPORT-SVC-35-001..006 | Author `/docs/export-center/overview.md` covering purpose, profiles, security, AOC alignment, surfaces, ending with imposed rule statement. | Doc merged with diagrams/examples; imposed rule line present; index updated. |
|
| DOCS-EXPORT-35-001 | DONE (2025-10-29) | Docs Guild | EXPORT-SVC-35-001..006 | Author `/docs/export-center/overview.md` covering purpose, profiles, security, AOC alignment, surfaces, ending with imposed rule statement. | Doc merged with diagrams/examples; imposed rule line present; index updated. |
|
||||||
| DOCS-EXPORT-35-002 | DONE (2025-10-29) | Docs Guild | EXPORT-SVC-35-002..005 | Publish `/docs/export-center/architecture.md` describing planner, adapters, manifests, signing, distribution flows, restating imposed rule. | Architecture doc merged; sequence diagrams included; rule statement appended. |
|
| DOCS-EXPORT-35-002 | DONE (2025-10-29) | Docs Guild | EXPORT-SVC-35-002..005 | Publish `/docs/export-center/architecture.md` describing planner, adapters, manifests, signing, distribution flows, restating imposed rule. | Architecture doc merged; sequence diagrams included; rule statement appended. |
|
||||||
| DOCS-EXPORT-35-003 | DONE (2025-10-29) | Docs Guild | EXPORT-SVC-35-003..004 | Publish `/docs/export-center/profiles.md` detailing schema fields, examples, compatibility, and imposed rule reminder. | Profiles doc merged; JSON schemas linked; imposed rule noted. |
|
| DOCS-EXPORT-35-003 | DONE (2025-10-29) | Docs Guild | EXPORT-SVC-35-003..004 | Publish `/docs/export-center/profiles.md` detailing schema fields, examples, compatibility, and imposed rule reminder. | Profiles doc merged; JSON schemas linked; imposed rule noted. |
|
||||||
| DOCS-EXPORT-36-004 | DONE (2025-10-29) | Docs Guild | EXPORT-SVC-36-001..004, WEB-EXPORT-36-001 | Publish `/docs/export-center/api.md` covering endpoints, payloads, errors, and mention imposed rule. | API doc merged; examples validated; rule included. |
|
| DOCS-EXPORT-36-004 | DONE (2025-10-29) | Docs Guild | EXPORT-SVC-36-001..004, WEB-EXPORT-36-001 | Publish `/docs/export-center/api.md` covering endpoints, payloads, errors, and mention imposed rule. | API doc merged; examples validated; rule included. |
|
||||||
| DOCS-EXPORT-36-005 | DONE (2025-10-29) | Docs Guild | CLI-EXPORT-35-001, CLI-EXPORT-36-001 | Publish `/docs/export-center/cli.md` with command reference, CI scripts, verification steps, restating imposed rule. | CLI doc merged; script snippets tested; rule appended. |
|
| DOCS-EXPORT-36-005 | DONE (2025-10-29) | Docs Guild | CLI-EXPORT-35-001, CLI-EXPORT-36-001 | Publish `/docs/export-center/cli.md` with command reference, CI scripts, verification steps, restating imposed rule. | CLI doc merged; script snippets tested; rule appended. |
|
||||||
| DOCS-EXPORT-36-006 | DONE (2025-10-29) | Docs Guild | EXPORT-SVC-36-001, DEVOPS-EXPORT-36-001 | Publish `/docs/export-center/trivy-adapter.md` covering field mappings, compatibility matrix, and imposed rule reminder. | Doc merged; mapping tables validated; rule included. |
|
| DOCS-EXPORT-36-006 | DONE (2025-10-29) | Docs Guild | EXPORT-SVC-36-001, DEVOPS-EXPORT-36-001 | Publish `/docs/export-center/trivy-adapter.md` covering field mappings, compatibility matrix, and imposed rule reminder. | Doc merged; mapping tables validated; rule included. |
|
||||||
| DOCS-EXPORT-37-001 | DONE (2025-10-29) | Docs Guild | EXPORT-SVC-37-001, DEVOPS-EXPORT-37-001 | Publish `/docs/export-center/mirror-bundles.md` describing filesystem/OCI layouts, delta/encryption, import guide, ending with imposed rule. | Doc merged; diagrams provided; verification steps tested; rule stated. |
|
| DOCS-EXPORT-37-001 | DONE (2025-10-29) | Docs Guild | EXPORT-SVC-37-001, DEVOPS-EXPORT-37-001 | Publish `/docs/export-center/mirror-bundles.md` describing filesystem/OCI layouts, delta/encryption, import guide, ending with imposed rule. | Doc merged; diagrams provided; verification steps tested; rule stated. |
|
||||||
| DOCS-EXPORT-37-002 | DONE (2025-10-29) | Docs Guild | EXPORT-SVC-35-005, EXPORT-SVC-37-002 | Publish `/docs/export-center/provenance-and-signing.md` detailing manifests, attestation flow, verification, reiterating imposed rule. | Doc merged; signature examples validated; rule appended. |
|
| DOCS-EXPORT-37-002 | DONE (2025-10-29) | Docs Guild | EXPORT-SVC-35-005, EXPORT-SVC-37-002 | Publish `/docs/export-center/provenance-and-signing.md` detailing manifests, attestation flow, verification, reiterating imposed rule. | Doc merged; signature examples validated; rule appended. |
|
||||||
| DOCS-EXPORT-37-003 | DONE (2025-10-29) | Docs Guild | DEVOPS-EXPORT-37-001 | Publish `/docs/operations/export-runbook.md` covering failures, tuning, capacity planning, with imposed rule reminder. | Runbook merged; procedures validated; rule included. |
|
| DOCS-EXPORT-37-003 | DONE (2025-10-29) | Docs Guild | DEVOPS-EXPORT-37-001 | Publish `/docs/operations/export-runbook.md` covering failures, tuning, capacity planning, with imposed rule reminder. | Runbook merged; procedures validated; rule included. |
|
||||||
| DOCS-EXPORT-37-004 | TODO | Docs Guild | AUTH-EXPORT-37-001, EXPORT-SVC-37-002 | Publish `/docs/security/export-hardening.md` outlining RBAC, tenancy, encryption, redaction, restating imposed rule. | Security doc merged; checklist updated; rule appended. |
|
| DOCS-EXPORT-37-004 | TODO | Docs Guild | AUTH-EXPORT-37-001, EXPORT-SVC-37-002 | Publish `/docs/security/export-hardening.md` outlining RBAC, tenancy, encryption, redaction, restating imposed rule. | Security doc merged; checklist updated; rule appended. |
|
||||||
| DOCS-EXPORT-37-101 | TODO | Docs Guild, DevEx/CLI Guild | CLI-EXPORT-37-001 | Refresh CLI verification sections once `stella export verify` lands (flags, exit codes, samples). | `docs/export-center/cli.md` & `docs/export-center/provenance-and-signing.md` updated with final command syntax; examples tested; rule reminder retained. |
|
| DOCS-EXPORT-37-101 | TODO | Docs Guild, DevEx/CLI Guild | CLI-EXPORT-37-001 | Refresh CLI verification sections once `stella export verify` lands (flags, exit codes, samples). | `docs/export-center/cli.md` & `docs/export-center/provenance-and-signing.md` updated with final command syntax; examples tested; rule reminder retained. |
|
||||||
| DOCS-EXPORT-37-102 | TODO | Docs Guild, DevOps Guild | DEVOPS-EXPORT-37-001 | Embed export dashboards/alerts references into provenance/runbook docs after Grafana work ships. | Docs updated with dashboard IDs/alert notes; update logged; rule reminder present. |
|
| DOCS-EXPORT-37-102 | TODO | Docs Guild, DevOps Guild | DEVOPS-EXPORT-37-001 | Embed export dashboards/alerts references into provenance/runbook docs after Grafana work ships. | Docs updated with dashboard IDs/alert notes; update logged; rule reminder present. |
|
||||||
| DOCS-EXPORT-37-005 | TODO | Docs Guild, Exporter Service Guild | EXPORT-SVC-35-006, DEVOPS-EXPORT-36-001 | Validate Export Center docs against live Trivy/mirror bundles once implementation lands; refresh examples and CLI snippets accordingly. | Real bundle examples recorded; docs updated; verification steps confirmed with production artefacts. |
|
| DOCS-EXPORT-37-005 | TODO | Docs Guild, Exporter Service Guild | EXPORT-SVC-35-006, DEVOPS-EXPORT-36-001 | Validate Export Center docs against live Trivy/mirror bundles once implementation lands; refresh examples and CLI snippets accordingly. | Real bundle examples recorded; docs updated; verification steps confirmed with production artefacts. |
|
||||||
> Note (2025-10-29): Blocked until exporter API (`EXPORT-SVC-35-006`) and Trivy/mirror adapters (`EXPORT-SVC-36-001`, `EXPORT-SVC-37-001`) ship. Requires access to CI smoke outputs (`DEVOPS-EXPORT-36-001`) for verification artifacts.
|
> Note (2025-10-29): Blocked until exporter API (`EXPORT-SVC-35-006`) and Trivy/mirror adapters (`EXPORT-SVC-36-001`, `EXPORT-SVC-37-001`) ship. Requires access to CI smoke outputs (`DEVOPS-EXPORT-36-001`) for verification artifacts.
|
||||||
|
|
||||||
## Reachability v1
|
## Reachability v1
|
||||||
|
|
||||||
| ID | Status | Owner(s) | Depends on | Description | Exit Criteria |
|
| ID | Status | Owner(s) | Depends on | Description | Exit Criteria |
|
||||||
|----|--------|----------|------------|-------------|---------------|
|
|----|--------|----------|------------|-------------|---------------|
|
||||||
| DOCS-SIG-26-001 | TODO | Docs Guild, Signals Guild | SIGNALS-24-004 | Write `/docs/signals/reachability.md` covering states, scores, provenance, retention. | Doc merged with diagrams/examples; checklist appended. |
|
| DOCS-SIG-26-001 | TODO | Docs Guild, Signals Guild | SIGNALS-24-004 | Write `/docs/signals/reachability.md` covering states, scores, provenance, retention. | Doc merged with diagrams/examples; checklist appended. |
|
||||||
| DOCS-SIG-26-002 | TODO | Docs Guild, Signals Guild | SIGNALS-24-002 | Publish `/docs/signals/callgraph-formats.md` with schemas and validation errors. | Doc merged; examples tested; checklist included. |
|
| DOCS-SIG-26-002 | TODO | Docs Guild, Signals Guild | SIGNALS-24-002 | Publish `/docs/signals/callgraph-formats.md` with schemas and validation errors. | Doc merged; examples tested; checklist included. |
|
||||||
| DOCS-SIG-26-003 | TODO | Docs Guild, Runtime Guild | SIGNALS-24-003 | Create `/docs/signals/runtime-facts.md` detailing agent capabilities, privacy safeguards, opt-in flags. | Doc merged; privacy review done; checklist appended. |
|
| DOCS-SIG-26-003 | TODO | Docs Guild, Runtime Guild | SIGNALS-24-003 | Create `/docs/signals/runtime-facts.md` detailing agent capabilities, privacy safeguards, opt-in flags. | Doc merged; privacy review done; checklist appended. |
|
||||||
| DOCS-SIG-26-004 | TODO | Docs Guild, Policy Guild | POLICY-ENGINE-80-001 | Document `/docs/policy/signals-weighting.md` for SPL predicates and weighting strategies. | Doc merged; sample policies validated; checklist appended. |
|
| DOCS-SIG-26-004 | TODO | Docs Guild, Policy Guild | POLICY-ENGINE-80-001 | Document `/docs/policy/signals-weighting.md` for SPL predicates and weighting strategies. | Doc merged; sample policies validated; checklist appended. |
|
||||||
| DOCS-SIG-26-005 | TODO | Docs Guild, UI Guild | UI-SIG-26-001..003 | Draft `/docs/ui/reachability-overlays.md` with badges, timelines, shortcuts. | Doc merged with screenshots; accessibility checklist completed. |
|
| DOCS-SIG-26-005 | TODO | Docs Guild, UI Guild | UI-SIG-26-001..003 | Draft `/docs/ui/reachability-overlays.md` with badges, timelines, shortcuts. | Doc merged with screenshots; accessibility checklist completed. |
|
||||||
| DOCS-SIG-26-006 | TODO | Docs Guild, DevEx/CLI Guild | CLI-SIG-26-001..002 | Update `/docs/cli/reachability.md` for new commands and automation recipes. | Doc merged; examples verified; checklist appended. |
|
| DOCS-SIG-26-006 | TODO | Docs Guild, DevEx/CLI Guild | CLI-SIG-26-001..002 | Update `/docs/cli/reachability.md` for new commands and automation recipes. | Doc merged; examples verified; checklist appended. |
|
||||||
| DOCS-SIG-26-007 | TODO | Docs Guild, BE-Base Platform Guild | WEB-SIG-26-001..003 | Publish `/docs/api/signals.md` covering endpoints, payloads, ETags, errors. | API doc aligned with OpenAPI; examples tested; checklist appended. |
|
| DOCS-SIG-26-007 | TODO | Docs Guild, BE-Base Platform Guild | WEB-SIG-26-001..003 | Publish `/docs/api/signals.md` covering endpoints, payloads, ETags, errors. | API doc aligned with OpenAPI; examples tested; checklist appended. |
|
||||||
| DOCS-SIG-26-008 | TODO | Docs Guild, DevOps Guild | DEVOPS-SIG-26-001..002 | Write `/docs/migration/enable-reachability.md` guiding rollout, fallbacks, monitoring. | Migration doc approved; checklist appended. |
|
| DOCS-SIG-26-008 | TODO | Docs Guild, DevOps Guild | DEVOPS-SIG-26-001..002 | Write `/docs/migration/enable-reachability.md` guiding rollout, fallbacks, monitoring. | Migration doc approved; checklist appended. |
|
||||||
|
|
||||||
## Policy Studio (Sprint 27)
|
## Policy Studio (Sprint 27)
|
||||||
|
|
||||||
| ID | Status | Owner(s) | Depends on | Description | Exit Criteria |
|
| ID | Status | Owner(s) | Depends on | Description | Exit Criteria |
|
||||||
|----|--------|----------|------------|-------------|---------------|
|
|----|--------|----------|------------|-------------|---------------|
|
||||||
| DOCS-POLICY-27-001 | BLOCKED (2025-10-27) | Docs Guild, Policy Guild | REGISTRY-API-27-001, POLICY-ENGINE-27-001 | Publish `/docs/policy/studio-overview.md` covering lifecycle, roles, glossary, and compliance checklist. | Doc merged with diagrams + lifecycle table; checklist appended; stakeholders sign off. |
|
| DOCS-POLICY-27-001 | BLOCKED (2025-10-27) | Docs Guild, Policy Guild | REGISTRY-API-27-001, POLICY-ENGINE-27-001 | Publish `/docs/policy/studio-overview.md` covering lifecycle, roles, glossary, and compliance checklist. | Doc merged with diagrams + lifecycle table; checklist appended; stakeholders sign off. |
|
||||||
> Blocked by `REGISTRY-API-27-001` and `POLICY-ENGINE-27-001`; need spec + compile data.
|
> Blocked by `REGISTRY-API-27-001` and `POLICY-ENGINE-27-001`; need spec + compile data.
|
||||||
> Blocker: Registry OpenAPI (`REGISTRY-API-27-001`) and policy compile enrichments (`POLICY-ENGINE-27-001`) are still TODO; need final interfaces before drafting overview.
|
> Blocker: Registry OpenAPI (`REGISTRY-API-27-001`) and policy compile enrichments (`POLICY-ENGINE-27-001`) are still TODO; need final interfaces before drafting overview.
|
||||||
| DOCS-POLICY-27-002 | BLOCKED (2025-10-27) | Docs Guild, Console Guild | CONSOLE-STUDIO-27-001 | Write `/docs/policy/authoring.md` detailing workspace templates, snippets, lint rules, IDE shortcuts, and best practices. | Authoring doc includes annotated screenshots, snippet catalog, compliance checklist. |
|
| DOCS-POLICY-27-002 | BLOCKED (2025-10-27) | Docs Guild, Console Guild | CONSOLE-STUDIO-27-001 | Write `/docs/policy/authoring.md` detailing workspace templates, snippets, lint rules, IDE shortcuts, and best practices. | Authoring doc includes annotated screenshots, snippet catalog, compliance checklist. |
|
||||||
> Blocked by `CONSOLE-STUDIO-27-001` Studio authoring UI pending.
|
> Blocked by `CONSOLE-STUDIO-27-001` Studio authoring UI pending.
|
||||||
> Blocker: Console Studio authoring UI (`CONSOLE-STUDIO-27-001`) not implemented; awaiting UX to capture flows/snippets.
|
> Blocker: Console Studio authoring UI (`CONSOLE-STUDIO-27-001`) not implemented; awaiting UX to capture flows/snippets.
|
||||||
| DOCS-POLICY-27-003 | BLOCKED (2025-10-27) | Docs Guild, Policy Registry Guild | REGISTRY-API-27-007 | Document `/docs/policy/versioning-and-publishing.md` (semver rules, attestations, rollback) with compliance checklist. | Doc merged with flow diagrams; attestation steps documented; checklist appended. |
|
| DOCS-POLICY-27-003 | BLOCKED (2025-10-27) | Docs Guild, Policy Registry Guild | REGISTRY-API-27-007 | Document `/docs/policy/versioning-and-publishing.md` (semver rules, attestations, rollback) with compliance checklist. | Doc merged with flow diagrams; attestation steps documented; checklist appended. |
|
||||||
> Blocked by `REGISTRY-API-27-007` publish/sign pipeline outstanding.
|
> Blocked by `REGISTRY-API-27-007` publish/sign pipeline outstanding.
|
||||||
> Blocker: Registry publish/sign workflow (`REGISTRY-API-27-007`) pending.
|
> Blocker: Registry publish/sign workflow (`REGISTRY-API-27-007`) pending.
|
||||||
| DOCS-POLICY-27-004 | BLOCKED (2025-10-27) | Docs Guild, Scheduler Guild | REGISTRY-API-27-005, SCHED-WORKER-27-301 | Write `/docs/policy/simulation.md` covering quick vs batch sim, thresholds, evidence bundles, CLI examples. | Simulation doc includes charts, sample manifests, checklist appended. |
|
| DOCS-POLICY-27-004 | BLOCKED (2025-10-27) | Docs Guild, Scheduler Guild | REGISTRY-API-27-005, SCHED-WORKER-27-301 | Write `/docs/policy/simulation.md` covering quick vs batch sim, thresholds, evidence bundles, CLI examples. | Simulation doc includes charts, sample manifests, checklist appended. |
|
||||||
> Blocked by `REGISTRY-API-27-005`/`SCHED-WORKER-27-301` batch simulation not ready.
|
> Blocked by `REGISTRY-API-27-005`/`SCHED-WORKER-27-301` batch simulation not ready.
|
||||||
> Blocker: Batch simulation APIs/workers (`REGISTRY-API-27-005`, `SCHED-WORKER-27-301`) still TODO.
|
> Blocker: Batch simulation APIs/workers (`REGISTRY-API-27-005`, `SCHED-WORKER-27-301`) still TODO.
|
||||||
| DOCS-POLICY-27-005 | BLOCKED (2025-10-27) | Docs Guild, Product Ops | REGISTRY-API-27-006 | Publish `/docs/policy/review-and-approval.md` with approver requirements, comments, webhooks, audit trail guidance. | Doc merged with role matrix + webhook schema; checklist appended. |
|
| DOCS-POLICY-27-005 | BLOCKED (2025-10-27) | Docs Guild, Product Ops | REGISTRY-API-27-006 | Publish `/docs/policy/review-and-approval.md` with approver requirements, comments, webhooks, audit trail guidance. | Doc merged with role matrix + webhook schema; checklist appended. |
|
||||||
> Blocked by `REGISTRY-API-27-006` review workflow not implemented.
|
> Blocked by `REGISTRY-API-27-006` review workflow not implemented.
|
||||||
> Blocker: Review workflow (`REGISTRY-API-27-006`) not landed.
|
> Blocker: Review workflow (`REGISTRY-API-27-006`) not landed.
|
||||||
| DOCS-POLICY-27-006 | BLOCKED (2025-10-27) | Docs Guild, Policy Guild | REGISTRY-API-27-008 | Author `/docs/policy/promotion.md` covering environments, canary, rollback, and monitoring steps. | Promotion doc includes examples + checklist; verified by Policy Ops. |
|
| DOCS-POLICY-27-006 | BLOCKED (2025-10-27) | Docs Guild, Policy Guild | REGISTRY-API-27-008 | Author `/docs/policy/promotion.md` covering environments, canary, rollback, and monitoring steps. | Promotion doc includes examples + checklist; verified by Policy Ops. |
|
||||||
> Blocked by `REGISTRY-API-27-008` promotion APIs pending.
|
> Blocked by `REGISTRY-API-27-008` promotion APIs pending.
|
||||||
> Blocker: Promotion/canary APIs (`REGISTRY-API-27-008`) outstanding.
|
> Blocker: Promotion/canary APIs (`REGISTRY-API-27-008`) outstanding.
|
||||||
| DOCS-POLICY-27-007 | BLOCKED (2025-10-27) | Docs Guild, DevEx/CLI Guild | CLI-POLICY-27-001..004 | Update `/docs/policy/cli.md` with new commands, JSON schemas, CI usage, and compliance checklist. | CLI doc merged with transcripts; schema references validated; checklist appended. |
|
| DOCS-POLICY-27-007 | BLOCKED (2025-10-27) | Docs Guild, DevEx/CLI Guild | CLI-POLICY-27-001..004 | Update `/docs/policy/cli.md` with new commands, JSON schemas, CI usage, and compliance checklist. | CLI doc merged with transcripts; schema references validated; checklist appended. |
|
||||||
> Blocked by `CLI-POLICY-27-001..004` CLI commands missing.
|
> Blocked by `CLI-POLICY-27-001..004` CLI commands missing.
|
||||||
> Blocker: Policy CLI commands (`CLI-POLICY-27-001..004`) yet to implement.
|
> Blocker: Policy CLI commands (`CLI-POLICY-27-001..004`) yet to implement.
|
||||||
| DOCS-POLICY-27-008 | BLOCKED (2025-10-27) | Docs Guild, Policy Registry Guild | REGISTRY-API-27-001..008 | Publish `/docs/policy/api.md` describing Registry endpoints, request/response schemas, errors, and feature flags. | API doc aligned with OpenAPI; examples validated; checklist appended. |
|
| DOCS-POLICY-27-008 | BLOCKED (2025-10-27) | Docs Guild, Policy Registry Guild | REGISTRY-API-27-001..008 | Publish `/docs/policy/api.md` describing Registry endpoints, request/response schemas, errors, and feature flags. | API doc aligned with OpenAPI; examples validated; checklist appended. |
|
||||||
> Blocked by `REGISTRY-API-27-001..008` OpenAPI + endpoints incomplete.
|
> Blocked by `REGISTRY-API-27-001..008` OpenAPI + endpoints incomplete.
|
||||||
> Blocker: Registry OpenAPI/spec suite (`REGISTRY-API-27-001..008`) incomplete.
|
> Blocker: Registry OpenAPI/spec suite (`REGISTRY-API-27-001..008`) incomplete.
|
||||||
| DOCS-POLICY-27-009 | BLOCKED (2025-10-27) | Docs Guild, Security Guild | AUTH-POLICY-27-002 | Create `/docs/security/policy-attestations.md` covering signing, verification, key rotation, and compliance checklist. | Security doc approved by Security Guild; verifier steps documented; checklist appended. |
|
| DOCS-POLICY-27-009 | BLOCKED (2025-10-27) | Docs Guild, Security Guild | AUTH-POLICY-27-002 | Create `/docs/security/policy-attestations.md` covering signing, verification, key rotation, and compliance checklist. | Security doc approved by Security Guild; verifier steps documented; checklist appended. |
|
||||||
> Blocked by `AUTH-POLICY-27-002` signing enforcement pending.
|
> Blocked by `AUTH-POLICY-27-002` signing enforcement pending.
|
||||||
> Blocker: Authority signing enforcement (`AUTH-POLICY-27-002`) pending.
|
> Blocker: Authority signing enforcement (`AUTH-POLICY-27-002`) pending.
|
||||||
| DOCS-POLICY-27-010 | BLOCKED (2025-10-27) | Docs Guild, Architecture Guild | REGISTRY-API-27-001, SCHED-WORKER-27-301 | Author `/docs/architecture/policy-registry.md` (service design, schemas, queues, failure modes) with diagrams and checklist. | Architecture doc merged; diagrams committed; checklist appended. |
|
| DOCS-POLICY-27-010 | BLOCKED (2025-10-27) | Docs Guild, Architecture Guild | REGISTRY-API-27-001, SCHED-WORKER-27-301 | Author `/docs/architecture/policy-registry.md` (service design, schemas, queues, failure modes) with diagrams and checklist. | Architecture doc merged; diagrams committed; checklist appended. |
|
||||||
> Blocked by `REGISTRY-API-27-001` & `SCHED-WORKER-27-301` need delivery.
|
> Blocked by `REGISTRY-API-27-001` & `SCHED-WORKER-27-301` need delivery.
|
||||||
> Blocker: Policy Registry schema/workers not delivered (see `REGISTRY-API-27-001`, `SCHED-WORKER-27-301`).
|
> Blocker: Policy Registry schema/workers not delivered (see `REGISTRY-API-27-001`, `SCHED-WORKER-27-301`).
|
||||||
| DOCS-POLICY-27-011 | BLOCKED (2025-10-27) | Docs Guild, Observability Guild | DEVOPS-POLICY-27-004 | Publish `/docs/observability/policy-telemetry.md` with metrics/log tables, dashboards, alerts, and compliance checklist. | Observability doc merged; dashboards linked; checklist appended. |
|
| DOCS-POLICY-27-011 | BLOCKED (2025-10-27) | Docs Guild, Observability Guild | DEVOPS-POLICY-27-004 | Publish `/docs/observability/policy-telemetry.md` with metrics/log tables, dashboards, alerts, and compliance checklist. | Observability doc merged; dashboards linked; checklist appended. |
|
||||||
> Blocked by `DEVOPS-POLICY-27-004` observability dashboards outstanding.
|
> Blocked by `DEVOPS-POLICY-27-004` observability dashboards outstanding.
|
||||||
> Blocker: Observability dashboards (`DEVOPS-POLICY-27-004`) not built.
|
> Blocker: Observability dashboards (`DEVOPS-POLICY-27-004`) not built.
|
||||||
| DOCS-POLICY-27-012 | BLOCKED (2025-10-27) | Docs Guild, Ops Guild | DEPLOY-POLICY-27-002 | Write `/docs/runbooks/policy-incident.md` detailing rollback, freeze, forensic steps, notifications. | Runbook merged; rehearsal recorded; checklist appended. |
|
| DOCS-POLICY-27-012 | BLOCKED (2025-10-27) | Docs Guild, Ops Guild | DEPLOY-POLICY-27-002 | Write `/docs/runbooks/policy-incident.md` detailing rollback, freeze, forensic steps, notifications. | Runbook merged; rehearsal recorded; checklist appended. |
|
||||||
> Blocked by `DEPLOY-POLICY-27-002` incident runbook inputs pending.
|
> Blocked by `DEPLOY-POLICY-27-002` incident runbook inputs pending.
|
||||||
> Blocker: Ops runbook inputs (`DEPLOY-POLICY-27-002`) pending.
|
> Blocker: Ops runbook inputs (`DEPLOY-POLICY-27-002`) pending.
|
||||||
| DOCS-POLICY-27-013 | BLOCKED (2025-10-27) | Docs Guild, Policy Guild | CONSOLE-STUDIO-27-001, REGISTRY-API-27-002 | Update `/docs/examples/policy-templates.md` with new templates, snippets, and sample policies. | Examples committed with commentary; lint passes; checklist appended. |
|
| DOCS-POLICY-27-013 | BLOCKED (2025-10-27) | Docs Guild, Policy Guild | CONSOLE-STUDIO-27-001, REGISTRY-API-27-002 | Update `/docs/examples/policy-templates.md` with new templates, snippets, and sample policies. | Examples committed with commentary; lint passes; checklist appended. |
|
||||||
> Blocked by `CONSOLE-STUDIO-27-001`/`REGISTRY-API-27-002` templates missing.
|
> Blocked by `CONSOLE-STUDIO-27-001`/`REGISTRY-API-27-002` templates missing.
|
||||||
> Blocker: Studio templates and registry storage (`CONSOLE-STUDIO-27-001`, `REGISTRY-API-27-002`) not available.
|
> Blocker: Studio templates and registry storage (`CONSOLE-STUDIO-27-001`, `REGISTRY-API-27-002`) not available.
|
||||||
| DOCS-POLICY-27-014 | BLOCKED (2025-10-27) | Docs Guild, Policy Registry Guild | REGISTRY-API-27-003, WEB-POLICY-27-001 | Refresh `/docs/aoc/aoc-guardrails.md` to include Studio-specific guardrails and validation scenarios. | Doc updated with Studio guardrails; compliance checklist appended. |
|
| DOCS-POLICY-27-014 | BLOCKED (2025-10-27) | Docs Guild, Policy Registry Guild | REGISTRY-API-27-003, WEB-POLICY-27-001 | Refresh `/docs/aoc/aoc-guardrails.md` to include Studio-specific guardrails and validation scenarios. | Doc updated with Studio guardrails; compliance checklist appended. |
|
||||||
> Blocked by `REGISTRY-API-27-003` & `WEB-POLICY-27-001` guardrails not implemented.
|
> Blocked by `REGISTRY-API-27-003` & `WEB-POLICY-27-001` guardrails not implemented.
|
||||||
> Blocker: Registry compile pipeline/web proxy (`REGISTRY-API-27-003`, `WEB-POLICY-27-001`) outstanding.
|
> Blocker: Registry compile pipeline/web proxy (`REGISTRY-API-27-003`, `WEB-POLICY-27-001`) outstanding.
|
||||||
|
|
||||||
## Vulnerability Explorer (Sprint 29)
|
## Vulnerability Explorer (Sprint 29)
|
||||||
|
|
||||||
| ID | Status | Owner(s) | Depends on | Description | Exit Criteria |
|
| ID | Status | Owner(s) | Depends on | Description | Exit Criteria |
|
||||||
|----|--------|----------|------------|-------------|---------------|
|
|----|--------|----------|------------|-------------|---------------|
|
||||||
| DOCS-VULN-29-001 | TODO | Docs Guild, Vuln Explorer Guild | VULN-API-29-001 | Publish `/docs/vuln/explorer-overview.md` covering domain model, identities, AOC guarantees, workflow summary. | Doc merged with diagrams/table; compliance checklist appended. |
|
| DOCS-VULN-29-001 | TODO | Docs Guild, Vuln Explorer Guild | VULN-API-29-001 | Publish `/docs/vuln/explorer-overview.md` covering domain model, identities, AOC guarantees, workflow summary. | Doc merged with diagrams/table; compliance checklist appended. |
|
||||||
| DOCS-VULN-29-002 | TODO | Docs Guild, Console Guild | CONSOLE-VULN-29-001..006 | Write `/docs/vuln/explorer-using-console.md` with workflows, screenshots, keyboard shortcuts, saved views, deep links. | Doc merged; images stored; WCAG notes included; checklist appended. |
|
| DOCS-VULN-29-002 | TODO | Docs Guild, Console Guild | CONSOLE-VULN-29-001..006 | Write `/docs/vuln/explorer-using-console.md` with workflows, screenshots, keyboard shortcuts, saved views, deep links. | Doc merged; images stored; WCAG notes included; checklist appended. |
|
||||||
| DOCS-VULN-29-003 | TODO | Docs Guild, Vuln Explorer API Guild | VULN-API-29-001..009 | Author `/docs/vuln/explorer-api.md` (endpoints, query schema, grouping, errors, rate limits). | Doc aligned with OpenAPI; examples validated; checklist appended. |
|
| DOCS-VULN-29-003 | TODO | Docs Guild, Vuln Explorer API Guild | VULN-API-29-001..009 | Author `/docs/vuln/explorer-api.md` (endpoints, query schema, grouping, errors, rate limits). | Doc aligned with OpenAPI; examples validated; checklist appended. |
|
||||||
| DOCS-VULN-29-004 | TODO | Docs Guild, DevEx/CLI Guild | CLI-VULN-29-001..005 | Publish `/docs/vuln/explorer-cli.md` with command reference, samples, exit codes, CI snippets. | CLI doc merged; transcripts/JSON outputs validated; checklist appended. |
|
| DOCS-VULN-29-004 | TODO | Docs Guild, DevEx/CLI Guild | CLI-VULN-29-001..005 | Publish `/docs/vuln/explorer-cli.md` with command reference, samples, exit codes, CI snippets. | CLI doc merged; transcripts/JSON outputs validated; checklist appended. |
|
||||||
| DOCS-VULN-29-005 | TODO | Docs Guild, Findings Ledger Guild | LEDGER-29-001..009 | Write `/docs/vuln/findings-ledger.md` detailing event schema, hashing, Merkle roots, replay tooling. | Doc merged; compliance checklist appended; audit team sign-off. |
|
| DOCS-VULN-29-005 | TODO | Docs Guild, Findings Ledger Guild | LEDGER-29-001..009 | Write `/docs/vuln/findings-ledger.md` detailing event schema, hashing, Merkle roots, replay tooling. | Doc merged; compliance checklist appended; audit team sign-off. |
|
||||||
| DOCS-VULN-29-006 | TODO | Docs Guild, Policy Guild | POLICY-ENGINE-29-001..003 | Update `/docs/policy/vuln-determinations.md` for new rationale, signals, simulation semantics. | Doc updated; examples validated; checklist appended. |
|
| DOCS-VULN-29-006 | TODO | Docs Guild, Policy Guild | POLICY-ENGINE-29-001..003 | Update `/docs/policy/vuln-determinations.md` for new rationale, signals, simulation semantics. | Doc updated; examples validated; checklist appended. |
|
||||||
| DOCS-VULN-29-007 | TODO | Docs Guild, Excititor Guild | EXCITITOR-VULN-29-001..004 | Publish `/docs/vex/explorer-integration.md` covering CSAF mapping, suppression precedence, status semantics. | Doc merged; compliance checklist appended. |
|
| DOCS-VULN-29-007 | TODO | Docs Guild, Excititor Guild | EXCITITOR-VULN-29-001..004 | Publish `/docs/vex/explorer-integration.md` covering CSAF mapping, suppression precedence, status semantics. | Doc merged; compliance checklist appended. |
|
||||||
| DOCS-VULN-29-008 | TODO | Docs Guild, Concelier Guild | CONCELIER-VULN-29-001..004 | Publish `/docs/advisories/explorer-integration.md` covering key normalization, withdrawn handling, provenance. | Doc merged; checklist appended. |
|
| DOCS-VULN-29-008 | TODO | Docs Guild, Concelier Guild | CONCELIER-VULN-29-001..004 | Publish `/docs/advisories/explorer-integration.md` covering key normalization, withdrawn handling, provenance. | Doc merged; checklist appended. |
|
||||||
| DOCS-VULN-29-009 | TODO | Docs Guild, SBOM Service Guild | SBOM-VULN-29-001..002 | Author `/docs/sbom/vuln-resolution.md` detailing version semantics, scope, paths, safe version hints. | Doc merged; ecosystem tables validated; checklist appended. |
|
| DOCS-VULN-29-009 | TODO | Docs Guild, SBOM Service Guild | SBOM-VULN-29-001..002 | Author `/docs/sbom/vuln-resolution.md` detailing version semantics, scope, paths, safe version hints. | Doc merged; ecosystem tables validated; checklist appended. |
|
||||||
| DOCS-VULN-29-010 | TODO | Docs Guild, Observability Guild | VULN-API-29-009, DEVOPS-VULN-29-002 | Publish `/docs/observability/vuln-telemetry.md` (metrics, logs, tracing, dashboards, SLOs). | Doc merged; dashboards linked; checklist appended. |
|
| DOCS-VULN-29-010 | TODO | Docs Guild, Observability Guild | VULN-API-29-009, DEVOPS-VULN-29-002 | Publish `/docs/observability/vuln-telemetry.md` (metrics, logs, tracing, dashboards, SLOs). | Doc merged; dashboards linked; checklist appended. |
|
||||||
| DOCS-VULN-29-011 | TODO | Docs Guild, Security Guild | AUTH-VULN-29-001..003 | Create `/docs/security/vuln-rbac.md` for roles, ABAC policies, attachment encryption, CSRF. | Security doc approved; checklist appended. |
|
| DOCS-VULN-29-011 | TODO | Docs Guild, Security Guild | AUTH-VULN-29-001..003 | Create `/docs/security/vuln-rbac.md` for roles, ABAC policies, attachment encryption, CSRF. | Security doc approved; checklist appended. |
|
||||||
| DOCS-VULN-29-012 | TODO | Docs Guild, Ops Guild | DEVOPS-VULN-29-002, SCHED-WORKER-29-003 | Write `/docs/runbooks/vuln-ops.md` (projector lag, resolver storms, export failures, policy activation). | Runbook merged; rehearsal recorded; checklist appended. |
|
| DOCS-VULN-29-012 | TODO | Docs Guild, Ops Guild | DEVOPS-VULN-29-002, SCHED-WORKER-29-003 | Write `/docs/runbooks/vuln-ops.md` (projector lag, resolver storms, export failures, policy activation). | Runbook merged; rehearsal recorded; checklist appended. |
|
||||||
| DOCS-VULN-29-013 | TODO | Docs Guild, Deployment Guild | DEPLOY-VULN-29-001..002 | Update `/docs/install/containers.md` with Findings Ledger & Vuln Explorer API images, manifests, resource sizing, health checks. | Install doc updated; validation commands included; checklist appended. |
|
| DOCS-VULN-29-013 | TODO | Docs Guild, Deployment Guild | DEPLOY-VULN-29-001..002 | Update `/docs/install/containers.md` with Findings Ledger & Vuln Explorer API images, manifests, resource sizing, health checks. | Install doc updated; validation commands included; checklist appended. |
|
||||||
|
|
||||||
## VEX Lens (Sprint 30)
|
## VEX Lens (Sprint 30)
|
||||||
| ID | Status | Owner(s) | Depends on | Description | Exit Criteria |
|
| ID | Status | Owner(s) | Depends on | Description | Exit Criteria |
|
||||||
|----|--------|----------|------------|-------------|---------------|
|
|----|--------|----------|------------|-------------|---------------|
|
||||||
| DOCS-VEX-30-001 | TODO | Docs Guild, VEX Lens Guild | VEXLENS-30-005 | Publish `/docs/vex/consensus-overview.md` describing purpose, scope, AOC guarantees. | Doc merged with diagrams/terminology tables; compliance checklist appended. |
|
| DOCS-VEX-30-001 | TODO | Docs Guild, VEX Lens Guild | VEXLENS-30-005 | Publish `/docs/vex/consensus-overview.md` describing purpose, scope, AOC guarantees. | Doc merged with diagrams/terminology tables; compliance checklist appended. |
|
||||||
| DOCS-VEX-30-002 | TODO | Docs Guild, VEX Lens Guild | VEXLENS-30-005 | Author `/docs/vex/consensus-algorithm.md` covering normalization, weighting, thresholds, examples. | Doc merged; math reviewed by Policy; checklist appended. |
|
| DOCS-VEX-30-002 | TODO | Docs Guild, VEX Lens Guild | VEXLENS-30-005 | Author `/docs/vex/consensus-algorithm.md` covering normalization, weighting, thresholds, examples. | Doc merged; math reviewed by Policy; checklist appended. |
|
||||||
| DOCS-VEX-30-003 | TODO | Docs Guild, Issuer Directory Guild | ISSUER-30-001..003 | Document `/docs/vex/issuer-directory.md` (issuer management, keys, trust overrides, audit). | Doc merged; security review done; checklist appended. |
|
| DOCS-VEX-30-003 | TODO | Docs Guild, Issuer Directory Guild | ISSUER-30-001..003 | Document `/docs/vex/issuer-directory.md` (issuer management, keys, trust overrides, audit). | Doc merged; security review done; checklist appended. |
|
||||||
| DOCS-VEX-30-004 | TODO | Docs Guild, VEX Lens Guild | VEXLENS-30-007 | Publish `/docs/vex/consensus-api.md` with endpoint specs, query params, rate limits. | API doc aligned with OpenAPI; examples validated; checklist appended. |
|
| DOCS-VEX-30-004 | TODO | Docs Guild, VEX Lens Guild | VEXLENS-30-007 | Publish `/docs/vex/consensus-api.md` with endpoint specs, query params, rate limits. | API doc aligned with OpenAPI; examples validated; checklist appended. |
|
||||||
| DOCS-VEX-30-005 | TODO | Docs Guild, Console Guild | CONSOLE-VEX-30-001 | Write `/docs/vex/consensus-console.md` covering UI workflows, filters, conflicts, accessibility. | Doc merged; screenshots added; checklist appended. |
|
| DOCS-VEX-30-005 | TODO | Docs Guild, Console Guild | CONSOLE-VEX-30-001 | Write `/docs/vex/consensus-console.md` covering UI workflows, filters, conflicts, accessibility. | Doc merged; screenshots added; checklist appended. |
|
||||||
| DOCS-VEX-30-006 | TODO | Docs Guild, Policy Guild | POLICY-ENGINE-29-001, VEXLENS-30-004 | Add `/docs/policy/vex-trust-model.md` detailing policy knobs, thresholds, simulation. | Doc merged; policy review completed; checklist appended. |
|
| DOCS-VEX-30-006 | TODO | Docs Guild, Policy Guild | POLICY-ENGINE-29-001, VEXLENS-30-004 | Add `/docs/policy/vex-trust-model.md` detailing policy knobs, thresholds, simulation. | Doc merged; policy review completed; checklist appended. |
|
||||||
| DOCS-VEX-30-007 | TODO | Docs Guild, SBOM Service Guild | VEXLENS-30-002 | Publish `/docs/sbom/vex-mapping.md` (CPE→purl strategy, edge cases, overrides). | Doc merged; mapping tables validated; checklist appended. |
|
| DOCS-VEX-30-007 | TODO | Docs Guild, SBOM Service Guild | VEXLENS-30-002 | Publish `/docs/sbom/vex-mapping.md` (CPE→purl strategy, edge cases, overrides). | Doc merged; mapping tables validated; checklist appended. |
|
||||||
| DOCS-VEX-30-008 | TODO | Docs Guild, Security Guild | ISSUER-30-002, VEXLENS-30-003 | Deliver `/docs/security/vex-signatures.md` (verification flow, key rotation, audit). | Doc approved by Security; checklist appended. |
|
| DOCS-VEX-30-008 | TODO | Docs Guild, Security Guild | ISSUER-30-002, VEXLENS-30-003 | Deliver `/docs/security/vex-signatures.md` (verification flow, key rotation, audit). | Doc approved by Security; checklist appended. |
|
||||||
| DOCS-VEX-30-009 | TODO | Docs Guild, DevOps Guild | VEXLENS-30-009, DEVOPS-VEX-30-001 | Create `/docs/runbooks/vex-ops.md` for recompute storms, mapping failures, signature errors. | Runbook merged; rehearsal logged; checklist appended. |
|
| DOCS-VEX-30-009 | TODO | Docs Guild, DevOps Guild | VEXLENS-30-009, DEVOPS-VEX-30-001 | Create `/docs/runbooks/vex-ops.md` for recompute storms, mapping failures, signature errors. | Runbook merged; rehearsal logged; checklist appended. |
|
||||||
|
|
||||||
## Advisory AI (Sprint 31)
|
## Advisory AI (Sprint 31)
|
||||||
|
|
||||||
| ID | Status | Owner(s) | Depends on | Description | Exit Criteria |
|
| ID | Status | Owner(s) | Depends on | Description | Exit Criteria |
|
||||||
|----|--------|----------|------------|-------------|---------------|
|
|----|--------|----------|------------|-------------|---------------|
|
||||||
| DOCS-AIAI-31-001 | TODO | Docs Guild, Advisory AI Guild | AIAI-31-006 | Publish `/docs/advisory-ai/overview.md` covering capabilities, guardrails, RBAC. | Doc merged with diagrams; compliance checklist appended. |
|
| DOCS-AIAI-31-001 | TODO | Docs Guild, Advisory AI Guild | AIAI-31-006 | Publish `/docs/advisory-ai/overview.md` covering capabilities, guardrails, RBAC. | Doc merged with diagrams; compliance checklist appended. |
|
||||||
| DOCS-AIAI-31-002 | TODO | Docs Guild, Advisory AI Guild | AIAI-31-004 | Author `/docs/advisory-ai/architecture.md` detailing RAG pipeline, deterministics, caching, model options. | Doc merged; architecture review done; checklist appended. |
|
| DOCS-AIAI-31-002 | TODO | Docs Guild, Advisory AI Guild | AIAI-31-004 | Author `/docs/advisory-ai/architecture.md` detailing RAG pipeline, deterministics, caching, model options. | Doc merged; architecture review done; checklist appended. |
|
||||||
| DOCS-AIAI-31-003 | TODO | Docs Guild, Advisory AI Guild | AIAI-31-006 | Write `/docs/advisory-ai/api.md` describing endpoints, schemas, errors, rate limits. | API doc aligned with OpenAPI; examples validated; checklist appended. |
|
| DOCS-AIAI-31-003 | TODO | Docs Guild, Advisory AI Guild | AIAI-31-006 | Write `/docs/advisory-ai/api.md` describing endpoints, schemas, errors, rate limits. | API doc aligned with OpenAPI; examples validated; checklist appended. |
|
||||||
| DOCS-AIAI-31-004 | TODO | Docs Guild, Console Guild | CONSOLE-VULN-29-001, CONSOLE-VEX-30-001 | Create `/docs/advisory-ai/console.md` with screenshots, a11y notes, copy-as-ticket instructions. | Doc merged; images stored; checklist appended. |
|
| DOCS-AIAI-31-004 | TODO | Docs Guild, Console Guild | CONSOLE-VULN-29-001, CONSOLE-VEX-30-001 | Create `/docs/advisory-ai/console.md` with screenshots, a11y notes, copy-as-ticket instructions. | Doc merged; images stored; checklist appended. |
|
||||||
| DOCS-AIAI-31-005 | TODO | Docs Guild, DevEx/CLI Guild | CLI-VULN-29-001, CLI-VEX-30-001 | Publish `/docs/advisory-ai/cli.md` covering commands, exit codes, scripting patterns. | Doc merged; examples tested; checklist appended. |
|
| DOCS-AIAI-31-005 | TODO | Docs Guild, DevEx/CLI Guild | CLI-VULN-29-001, CLI-VEX-30-001 | Publish `/docs/advisory-ai/cli.md` covering commands, exit codes, scripting patterns. | Doc merged; examples tested; checklist appended. |
|
||||||
| DOCS-AIAI-31-006 | TODO | Docs Guild, Policy Guild | POLICY-ENGINE-31-001 | Update `/docs/policy/assistant-parameters.md` covering temperature, token limits, ranking weights, TTLs. | Doc merged; policy review done; checklist appended. |
|
| DOCS-AIAI-31-006 | TODO | Docs Guild, Policy Guild | POLICY-ENGINE-31-001 | Update `/docs/policy/assistant-parameters.md` covering temperature, token limits, ranking weights, TTLs. | Doc merged; policy review done; checklist appended. |
|
||||||
| DOCS-AIAI-31-007 | TODO | Docs Guild, Security Guild | AIAI-31-005 | Write `/docs/security/assistant-guardrails.md` detailing redaction, injection defense, logging. | Doc approved by Security; checklist appended. |
|
| DOCS-AIAI-31-007 | TODO | Docs Guild, Security Guild | AIAI-31-005 | Write `/docs/security/assistant-guardrails.md` detailing redaction, injection defense, logging. | Doc approved by Security; checklist appended. |
|
||||||
| DOCS-AIAI-31-008 | TODO | Docs Guild, SBOM Service Guild | SBOM-AIAI-31-001 | Publish `/docs/sbom/remediation-heuristics.md` (feasibility scoring, blast radius). | Doc merged; heuristics reviewed; checklist appended. |
|
| DOCS-AIAI-31-008 | TODO | Docs Guild, SBOM Service Guild | SBOM-AIAI-31-001 | Publish `/docs/sbom/remediation-heuristics.md` (feasibility scoring, blast radius). | Doc merged; heuristics reviewed; checklist appended. |
|
||||||
| DOCS-AIAI-31-009 | TODO | Docs Guild, DevOps Guild | DEVOPS-AIAI-31-001 | Create `/docs/runbooks/assistant-ops.md` for warmup, cache priming, model outages, scaling. | Runbook merged; rehearsal logged; checklist appended. |
|
| DOCS-AIAI-31-009 | TODO | Docs Guild, DevOps Guild | DEVOPS-AIAI-31-001 | Create `/docs/runbooks/assistant-ops.md` for warmup, cache priming, model outages, scaling. | Runbook merged; rehearsal logged; checklist appended. |
|
||||||
|
|
||||||
## Notifications Studio
|
## Notifications Studio
|
||||||
|
|
||||||
| ID | Status | Owner(s) | Depends on | Description | Exit Criteria |
|
| ID | Status | Owner(s) | Depends on | Description | Exit Criteria |
|
||||||
|----|--------|----------|------------|-------------|---------------|
|
|----|--------|----------|------------|-------------|---------------|
|
||||||
| DOCS-NOTIFY-38-001 | DONE (2025-10-29) | Docs Guild, Notifications Service Guild | NOTIFY-SVC-38-001..004 | Publish `/docs/notifications/overview.md` and `/docs/notifications/architecture.md`, each ending with imposed rule reminder. | Docs merged; diagrams verified; imposed rule appended. |
|
| DOCS-NOTIFY-38-001 | DONE (2025-10-29) | Docs Guild, Notifications Service Guild | NOTIFY-SVC-38-001..004 | Publish `/docs/notifications/overview.md` and `/docs/notifications/architecture.md`, each ending with imposed rule reminder. | Docs merged; diagrams verified; imposed rule appended. |
|
||||||
| DOCS-NOTIFY-39-002 | DONE (2025-10-29) | Docs Guild, Notifications Service Guild | NOTIFY-SVC-39-001..004 | Publish `/docs/notifications/rules.md`, `/docs/notifications/templates.md`, `/docs/notifications/digests.md` with examples and imposed rule line. | Docs merged; examples validated; imposed rule appended. |
|
| DOCS-NOTIFY-39-002 | DONE (2025-10-29) | Docs Guild, Notifications Service Guild | NOTIFY-SVC-39-001..004 | Publish `/docs/notifications/rules.md`, `/docs/notifications/templates.md`, `/docs/notifications/digests.md` with examples and imposed rule line. | Docs merged; examples validated; imposed rule appended. |
|
||||||
| DOCS-NOTIFY-40-001 | TODO | Docs Guild, Security Guild | AUTH-NOTIFY-38-001, NOTIFY-SVC-40-001..004 | Publish `/docs/notifications/channels.md`, `/docs/notifications/escalations.md`, `/docs/notifications/api.md`, `/docs/operations/notifier-runbook.md`, `/docs/security/notifications-hardening.md`; each ends with imposed rule line. | Docs merged; accessibility checks passed; imposed rule appended. |
|
| DOCS-NOTIFY-40-001 | TODO | Docs Guild, Security Guild | AUTH-NOTIFY-38-001, NOTIFY-SVC-40-001..004 | Publish `/docs/notifications/channels.md`, `/docs/notifications/escalations.md`, `/docs/notifications/api.md`, `/docs/operations/notifier-runbook.md`, `/docs/security/notifications-hardening.md`; each ends with imposed rule line. | Docs merged; accessibility checks passed; imposed rule appended. |
|
||||||
|
|
||||||
## CLI Parity & Task Packs
|
## CLI Parity & Task Packs
|
||||||
|
|
||||||
| ID | Status | Owner(s) | Depends on | Description | Exit Criteria |
|
| ID | Status | Owner(s) | Depends on | Description | Exit Criteria |
|
||||||
|----|--------|----------|------------|-------------|---------------|
|
|----|--------|----------|------------|-------------|---------------|
|
||||||
| DOCS-CLI-41-001 | TODO | Docs Guild, DevEx/CLI Guild | CLI-CORE-41-001 | Publish `/docs/cli/overview.md`, `/docs/cli/configuration.md`, `/docs/cli/output-and-exit-codes.md` with imposed rule statements. | Docs merged; examples verified; imposed rule appended. |
|
| DOCS-CLI-41-001 | TODO | Docs Guild, DevEx/CLI Guild | CLI-CORE-41-001 | Publish `/docs/cli/overview.md`, `/docs/cli/configuration.md`, `/docs/cli/output-and-exit-codes.md` with imposed rule statements. | Docs merged; examples verified; imposed rule appended. |
|
||||||
| DOCS-CLI-42-001 | TODO | Docs Guild | DOCS-CLI-41-001, CLI-PARITY-41-001 | Publish `/docs/cli/parity-matrix.md` and command guides under `/docs/cli/commands/*.md` (policy, sbom, vuln, vex, advisory, export, orchestrator, notify, aoc, auth). | Guides merged; parity automation documented; imposed rule appended. |
|
| DOCS-CLI-42-001 | TODO | Docs Guild | DOCS-CLI-41-001, CLI-PARITY-41-001 | Publish `/docs/cli/parity-matrix.md` and command guides under `/docs/cli/commands/*.md` (policy, sbom, vuln, vex, advisory, export, orchestrator, notify, aoc, auth). | Guides merged; parity automation documented; imposed rule appended. |
|
||||||
| DOCS-PACKS-43-001 | DONE (2025-10-27) | Docs Guild, Task Runner Guild | PACKS-REG-42-001, TASKRUN-42-001 | Publish `/docs/task-packs/spec.md`, `/docs/task-packs/authoring-guide.md`, `/docs/task-packs/registry.md`, `/docs/task-packs/runbook.md`, `/docs/security/pack-signing-and-rbac.md`, `/docs/operations/cli-release-and-packaging.md` with imposed rule statements. | Docs merged; tutorials validated; imposed rule appended; cross-links added. |
|
| DOCS-PACKS-43-001 | DONE (2025-10-27) | Docs Guild, Task Runner Guild | PACKS-REG-42-001, TASKRUN-42-001 | Publish `/docs/task-packs/spec.md`, `/docs/task-packs/authoring-guide.md`, `/docs/task-packs/registry.md`, `/docs/task-packs/runbook.md`, `/docs/security/pack-signing-and-rbac.md`, `/docs/operations/cli-release-and-packaging.md` with imposed rule statements. | Docs merged; tutorials validated; imposed rule appended; cross-links added. |
|
||||||
|
|
||||||
## Containerized Distribution (Epic 13)
|
## Containerized Distribution (Epic 13)
|
||||||
|
|
||||||
| ID | Status | Owner(s) | Depends on | Description | Exit Criteria |
|
| ID | Status | Owner(s) | Depends on | Description | Exit Criteria |
|
||||||
|----|--------|----------|------------|-------------|---------------|
|
|----|--------|----------|------------|-------------|---------------|
|
||||||
| DOCS-INSTALL-44-001 | TODO | Docs Guild, Deployment Guild | COMPOSE-44-001 | Publish `/docs/install/overview.md` and `/docs/install/compose-quickstart.md` with imposed rule line and copy-ready commands. | Docs merged; screenshots/commands verified; imposed rule appended. |
|
| DOCS-INSTALL-44-001 | TODO | Docs Guild, Deployment Guild | COMPOSE-44-001 | Publish `/docs/install/overview.md` and `/docs/install/compose-quickstart.md` with imposed rule line and copy-ready commands. | Docs merged; screenshots/commands verified; imposed rule appended. |
|
||||||
| DOCS-INSTALL-45-001 | TODO | Docs Guild, Deployment Guild | HELM-45-001 | Publish `/docs/install/helm-prod.md` and `/docs/install/configuration-reference.md` with values tables and imposed rule reminder. | Docs merged; configuration matrix verified; imposed rule appended. |
|
| DOCS-INSTALL-45-001 | TODO | Docs Guild, Deployment Guild | HELM-45-001 | Publish `/docs/install/helm-prod.md` and `/docs/install/configuration-reference.md` with values tables and imposed rule reminder. | Docs merged; configuration matrix verified; imposed rule appended. |
|
||||||
| DOCS-INSTALL-46-001 | TODO | Docs Guild, Security Guild | DEPLOY-PACKS-43-001, CLI-PACKS-43-001 | Publish `/docs/install/airgap.md`, `/docs/security/supply-chain.md`, `/docs/operations/health-and-readiness.md`, `/docs/release/image-catalog.md`, `/docs/console/onboarding.md` (each with imposed rule). | Docs merged; checksum/signature sections validated; imposed rule appended. |
|
| DOCS-INSTALL-46-001 | TODO | Docs Guild, Security Guild | DEPLOY-PACKS-43-001, CLI-PACKS-43-001 | Publish `/docs/install/airgap.md`, `/docs/security/supply-chain.md`, `/docs/operations/health-and-readiness.md`, `/docs/release/image-catalog.md`, `/docs/console/onboarding.md` (each with imposed rule). | Docs merged; checksum/signature sections validated; imposed rule appended. |
|
||||||
|
|
||||||
## Authority-Backed Scopes & Tenancy (Epic 14)
|
## Authority-Backed Scopes & Tenancy (Epic 14)
|
||||||
| ID | Status | Owner(s) | Depends on | Description | Exit Criteria |
|
| ID | Status | Owner(s) | Depends on | Description | Exit Criteria |
|
||||||
|----|--------|----------|------------|-------------|---------------|
|
|----|--------|----------|------------|-------------|---------------|
|
||||||
| DOCS-TEN-47-001 | TODO | Docs Guild, Authority Core | AUTH-TEN-47-001 | Publish `/docs/security/tenancy-overview.md` and `/docs/security/scopes-and-roles.md` outlining scope grammar, tenant model, imposed rule reminder. | Docs merged; diagrams included; imposed rule appended. |
|
| DOCS-TEN-47-001 | TODO | Docs Guild, Authority Core | AUTH-TEN-47-001 | Publish `/docs/security/tenancy-overview.md` and `/docs/security/scopes-and-roles.md` outlining scope grammar, tenant model, imposed rule reminder. | Docs merged; diagrams included; imposed rule appended. |
|
||||||
| DOCS-TEN-48-001 | TODO | Docs Guild, Platform Ops | WEB-TEN-48-001 | Publish `/docs/operations/multi-tenancy.md`, `/docs/operations/rls-and-data-isolation.md`, `/docs/console/admin-tenants.md`. | Docs merged; examples validated; imposed rule appended. |
|
| DOCS-TEN-48-001 | TODO | Docs Guild, Platform Ops | WEB-TEN-48-001 | Publish `/docs/operations/multi-tenancy.md`, `/docs/operations/rls-and-data-isolation.md`, `/docs/console/admin-tenants.md`. | Docs merged; examples validated; imposed rule appended. |
|
||||||
| DOCS-TEN-49-001 | TODO | Docs & DevEx Guilds | CLI-TEN-47-001, AUTH-TEN-49-001 | Publish `/docs/cli/authentication.md`, `/docs/api/authentication.md`, `/docs/policy/examples/abac-overlays.md`, update `/docs/install/configuration-reference.md` with new env vars, all ending with imposed rule line. | Docs merged; command examples verified; imposed rule appended. |
|
| DOCS-TEN-49-001 | TODO | Docs & DevEx Guilds | CLI-TEN-47-001, AUTH-TEN-49-001 | Publish `/docs/cli/authentication.md`, `/docs/api/authentication.md`, `/docs/policy/examples/abac-overlays.md`, update `/docs/install/configuration-reference.md` with new env vars, all ending with imposed rule line. | Docs merged; command examples verified; imposed rule appended. |
|
||||||
|
|||||||
@@ -1,131 +1,131 @@
|
|||||||
# StellaOps Console Accessibility Guide
|
# StellaOps Console Accessibility Guide
|
||||||
|
|
||||||
> **Audience:** Accessibility Guild, Console Guild, Docs Guild, QA.
|
> **Audience:** Accessibility Guild, Console Guild, Docs Guild, QA.
|
||||||
> **Scope:** Keyboard interaction model, screen-reader behaviour, colour & focus tokens, testing workflows, offline considerations, and compliance checklist for the StellaOps Console (Sprint 23).
|
> **Scope:** Keyboard interaction model, screen-reader behaviour, colour & focus tokens, testing workflows, offline considerations, and compliance checklist for the StellaOps Console (Sprint 23).
|
||||||
|
|
||||||
The console targets **WCAG 2.2 AA** across all supported browsers (Chromium, Firefox ESR) and honours StellaOps’ sovereign/offline constraints. Every build must keep keyboard-only users, screen-reader users, and high-contrast operators productive without relying on third-party services.
|
The console targets **WCAG 2.2 AA** across all supported browsers (Chromium, Firefox ESR) and honours StellaOps’ sovereign/offline constraints. Every build must keep keyboard-only users, screen-reader users, and high-contrast operators productive without relying on third-party services.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 1 · Accessibility Principles
|
## 1 · Accessibility Principles
|
||||||
|
|
||||||
1. **Deterministic navigation** – Focus order, shortcuts, and announcements remain stable across releases; URLs encode state for deep links.
|
1. **Deterministic navigation** – Focus order, shortcuts, and announcements remain stable across releases; URLs encode state for deep links.
|
||||||
2. **Keyboard-first design** – Every actionable element is reachable via keyboard; shortcuts provide accelerators, and remapping is available via *Settings → Accessibility → Keyboard shortcuts*.
|
2. **Keyboard-first design** – Every actionable element is reachable via keyboard; shortcuts provide accelerators, and remapping is available via *Settings → Accessibility → Keyboard shortcuts*.
|
||||||
3. **Assistive technology parity** – ARIA roles and live regions mirror visual affordances (status banners, SSE tickers, progress drawers). Screen readers receive polite/atomic updates to avoid chatter.
|
3. **Assistive technology parity** – ARIA roles and live regions mirror visual affordances (status banners, SSE tickers, progress drawers). Screen readers receive polite/atomic updates to avoid chatter.
|
||||||
4. **Colour & contrast tokens** – All palettes derive from design tokens that achieve ≥ 4.5:1 contrast (text) and ≥ 3:1 for graphical indicators; tokens pass automated contrast linting.
|
4. **Colour & contrast tokens** – All palettes derive from design tokens that achieve ≥ 4.5:1 contrast (text) and ≥ 3:1 for graphical indicators; tokens pass automated contrast linting.
|
||||||
5. **Offline equivalence** – Accessibility features (shortcuts, offline banners, focus restoration) behave the same in sealed environments, with guidance when actions require online authority.
|
5. **Offline equivalence** – Accessibility features (shortcuts, offline banners, focus restoration) behave the same in sealed environments, with guidance when actions require online authority.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 2 · Keyboard Interaction Map
|
## 2 · Keyboard Interaction Map
|
||||||
|
|
||||||
### 2.1 Global shortcuts
|
### 2.1 Global shortcuts
|
||||||
|
|
||||||
| Action | Macs | Windows/Linux | Notes |
|
| Action | Macs | Windows/Linux | Notes |
|
||||||
|--------|------|---------------|-------|
|
|--------|------|---------------|-------|
|
||||||
| Command palette | `⌘ K` | `Ctrl K` | Focuses palette search; respects tenant scope. |
|
| Command palette | `⌘ K` | `Ctrl K` | Focuses palette search; respects tenant scope. |
|
||||||
| Tenant picker | `⌘ T` | `Ctrl T` | Opens modal; `Enter` confirms, `Esc` cancels. |
|
| Tenant picker | `⌘ T` | `Ctrl T` | Opens modal; `Enter` confirms, `Esc` cancels. |
|
||||||
| Filter tray toggle | `⇧ F` | `Shift F` | Focus lands on first filter; `Tab` cycles filters before returning to page. |
|
| Filter tray toggle | `⇧ F` | `Shift F` | Focus lands on first filter; `Tab` cycles filters before returning to page. |
|
||||||
| Saved view presets | `⌘ 1-9` | `Ctrl 1-9` | Bound per tenant; missing preset triggers tooltip. |
|
| Saved view presets | `⌘ 1-9` | `Ctrl 1-9` | Bound per tenant; missing preset triggers tooltip. |
|
||||||
| Keyboard reference | `?` | `?` | Opens overlay listing context-specific shortcuts; `Esc` closes. |
|
| Keyboard reference | `?` | `?` | Opens overlay listing context-specific shortcuts; `Esc` closes. |
|
||||||
| Global search (context) | `/` | `/` | When the filter tray is closed, focuses inline search field. |
|
| Global search (context) | `/` | `/` | When the filter tray is closed, focuses inline search field. |
|
||||||
|
|
||||||
### 2.2 Module-specific shortcuts
|
### 2.2 Module-specific shortcuts
|
||||||
|
|
||||||
| Module | Action | Macs | Windows/Linux | Notes |
|
| Module | Action | Macs | Windows/Linux | Notes |
|
||||||
|--------|--------|------|---------------|-------|
|
|--------|--------|------|---------------|-------|
|
||||||
| Findings | Explain search | `⌘ /` | `Ctrl /` | Only when Explain drawer open; announces results via live region. |
|
| Findings | Explain search | `⌘ /` | `Ctrl /` | Only when Explain drawer open; announces results via live region. |
|
||||||
| SBOM Explorer | Toggle overlays | `⌘ G` | `Ctrl G` | Persists per session (see `/docs/ui/sbom-explorer.md`). |
|
| SBOM Explorer | Toggle overlays | `⌘ G` | `Ctrl G` | Persists per session (see `/docs/ui/sbom-explorer.md`). |
|
||||||
| Advisories & VEX | Provider filter | `⌘ ⌥ F` | `Ctrl Alt F` | Moves focus to provider chip row. |
|
| Advisories & VEX | Provider filter | `⌘ ⌥ F` | `Ctrl Alt F` | Moves focus to provider chip row. |
|
||||||
| Runs | Refresh snapshot | `⌘ R` | `Ctrl R` | Soft refresh of SSE state; no full page reload. |
|
| Runs | Refresh snapshot | `⌘ R` | `Ctrl R` | Soft refresh of SSE state; no full page reload. |
|
||||||
| Policies | Save draft | `⌘ S` | `Ctrl S` | Requires edit scope; exposes toast + status live update. |
|
| Policies | Save draft | `⌘ S` | `Ctrl S` | Requires edit scope; exposes toast + status live update. |
|
||||||
| Downloads | Copy CLI command | `⇧ D` | `Shift D` | Copies manifest or export command; toast announces scope hints. |
|
| Downloads | Copy CLI command | `⇧ D` | `Shift D` | Copies manifest or export command; toast announces scope hints. |
|
||||||
|
|
||||||
All shortcuts are remappable. Remaps persist in IndexedDB (per tenant) and export as part of profile bundles so operators can restore preferences offline.
|
All shortcuts are remappable. Remaps persist in IndexedDB (per tenant) and export as part of profile bundles so operators can restore preferences offline.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 3 · Screen Reader & Focus Behaviour
|
## 3 · Screen Reader & Focus Behaviour
|
||||||
|
|
||||||
- **Skip navigation** – Each route exposes a “Skip to content” link revealed on keyboard focus. Focus order: global header → page breadcrumb → action shelf → data grid/list → drawers/dialogs.
|
- **Skip navigation** – Each route exposes a “Skip to content” link revealed on keyboard focus. Focus order: global header → page breadcrumb → action shelf → data grid/list → drawers/dialogs.
|
||||||
- **Live regions** – Status ticker and SSE progress bars use `aria-live="polite"` with throttling to avoid flooding AT. Error toasts use `aria-live="assertive"` and auto-focus dismiss buttons.
|
- **Live regions** – Status ticker and SSE progress bars use `aria-live="polite"` with throttling to avoid flooding AT. Error toasts use `aria-live="assertive"` and auto-focus dismiss buttons.
|
||||||
- **Drawers & modals** – Dialog components trap focus, support `Esc` to close, and restore focus to the launching control. Screen readers announce title + purpose.
|
- **Drawers & modals** – Dialog components trap focus, support `Esc` to close, and restore focus to the launching control. Screen readers announce title + purpose.
|
||||||
- **Tables & grids** – Large tables (Findings, SBOM inventory) switch to virtualised rows but retain ARIA grid semantics (`aria-rowcount`, `aria-colindex`). Column headers include sorting state via `aria-sort`.
|
- **Tables & grids** – Large tables (Findings, SBOM inventory) switch to virtualised rows but retain ARIA grid semantics (`aria-rowcount`, `aria-colindex`). Column headers include sorting state via `aria-sort`.
|
||||||
- **Tenancy context** – Tenant badge exposes `aria-describedby` linking to context summary (environment, offline snapshot). Switching tenant queues a polite announcement summarising new scope.
|
- **Tenancy context** – Tenant badge exposes `aria-describedby` linking to context summary (environment, offline snapshot). Switching tenant queues a polite announcement summarising new scope.
|
||||||
- **Command palette** – Uses `role="dialog"` with search input labelled. Keyboard navigation within results uses `Up/Down`; screen readers announce result category + command.
|
- **Command palette** – Uses `role="dialog"` with search input labelled. Keyboard navigation within results uses `Up/Down`; screen readers announce result category + command.
|
||||||
- **Offline banner** – When offline, a dismissible banner announces reason and includes instructions for CLI fallback. The banner has `role="status"` so it announces once without stealing focus.
|
- **Offline banner** – When offline, a dismissible banner announces reason and includes instructions for CLI fallback. The banner has `role="status"` so it announces once without stealing focus.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 4 · Colour & Focus Tokens
|
## 4 · Colour & Focus Tokens
|
||||||
|
|
||||||
Console consumes design tokens published by the Console Guild (tracked via CONSOLE-FEAT-23-102). Tokens live in the design system bundle (`ui/design/tokens/colors.json`, mirrored at build time). Key tokens:
|
Console consumes design tokens published by the Console Guild (tracked via CONSOLE-FEAT-23-102). Tokens live in the design system bundle (`ui/design/tokens/colors.json`, mirrored at build time). Key tokens:
|
||||||
|
|
||||||
| Token | Purpose | Contrast target |
|
| Token | Purpose | Contrast target |
|
||||||
|-------|---------|-----------------|
|
|-------|---------|-----------------|
|
||||||
| `so-color-surface-base` | Primary surface/background | ≥ 4.5:1 against `so-color-text-primary`. |
|
| `so-color-surface-base` | Primary surface/background | ≥ 4.5:1 against `so-color-text-primary`. |
|
||||||
| `so-color-surface-raised` | Cards, drawers, modals | ≥ 3:1 against surrounding surfaces. |
|
| `so-color-surface-raised` | Cards, drawers, modals | ≥ 3:1 against surrounding surfaces. |
|
||||||
| `so-color-text-primary` | Default text colour | ≥ 4.5:1 against base surfaces. |
|
| `so-color-text-primary` | Default text colour | ≥ 4.5:1 against base surfaces. |
|
||||||
| `so-color-text-inverted` | Text on accent buttons | ≥ 4.5:1 against accent fills. |
|
| `so-color-text-inverted` | Text on accent buttons | ≥ 4.5:1 against accent fills. |
|
||||||
| `so-color-accent-primary` | Action buttons, focus headings | ≥ 3:1 against surface. |
|
| `so-color-accent-primary` | Action buttons, focus headings | ≥ 3:1 against surface. |
|
||||||
| `so-color-status-critical` | Error toasts, violation chips | ≥ 4.5:1 for text; `critical-bg` provides >3:1 on neutral surface. |
|
| `so-color-status-critical` | Error toasts, violation chips | ≥ 4.5:1 for text; `critical-bg` provides >3:1 on neutral surface. |
|
||||||
| `so-color-status-warning` | Warning banners | Meets 3:1 on surface and 4.5:1 for text overlays. |
|
| `so-color-status-warning` | Warning banners | Meets 3:1 on surface and 4.5:1 for text overlays. |
|
||||||
| `so-color-status-success` | Success toasts, pass badges | ≥ 3:1 for iconography; text uses `text-primary`. |
|
| `so-color-status-success` | Success toasts, pass badges | ≥ 3:1 for iconography; text uses `text-primary`. |
|
||||||
| `so-focus-ring` | 2 px outline used across focusable elements | 3:1 against both light/dark surfaces. |
|
| `so-focus-ring` | 2 px outline used across focusable elements | 3:1 against both light/dark surfaces. |
|
||||||
|
|
||||||
Colour tokens undergo automated linting (**axe-core contrast checks** + custom luminance script) during build. Any new token must include dark/light variants and pass the token contract tests.
|
Colour tokens undergo automated linting (**axe-core contrast checks** + custom luminance script) during build. Any new token must include dark/light variants and pass the token contract tests.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 5 · Testing Workflow
|
## 5 · Testing Workflow
|
||||||
|
|
||||||
| Layer | Tooling | Frequency | Notes |
|
| Layer | Tooling | Frequency | Notes |
|
||||||
|-------|---------|-----------|-------|
|
|-------|---------|-----------|-------|
|
||||||
| Component a11y | Storybook + axe-core addon | On PR (story CI) | Fails when axe detects violations. |
|
| Component a11y | Storybook + axe-core addon | On PR (story CI) | Fails when axe detects violations. |
|
||||||
| Route regression | Playwright a11y sweep (`pnpm test:a11y`) | Nightly & release pipeline | Executes keyboard navigation, checks focus trap, runs Axe on key routes (Dashboard, Findings, SBOM, Admin). |
|
| Route regression | Playwright a11y sweep (`pnpm test:a11y`) | Nightly & release pipeline | Executes keyboard navigation, checks focus trap, runs Axe on key routes (Dashboard, Findings, SBOM, Admin). |
|
||||||
| Colour contrast lint | Token validator (`tools/a11y/check-contrast.ts`) | On token change | Guards design token updates. |
|
| Colour contrast lint | Token validator (`tools/a11y/check-contrast.ts`) | On token change | Guards design token updates. |
|
||||||
| CI parity | Pending `scripts/check-console-cli-parity.sh` (CONSOLE-DOC-23-502) | Release CI | Ensures CLI commands documented for parity features. |
|
| CI parity | Pending `scripts/check-console-cli-parity.sh` (CONSOLE-DOC-23-502) | Release CI | Ensures CLI commands documented for parity features. |
|
||||||
| Screen-reader spot checks | Manual NVDA + VoiceOver scripts | Pre-release checklist | Scenarios: tenant switch, explain drawer, downloads parity copy. |
|
| Screen-reader spot checks | Manual NVDA + VoiceOver scripts | Pre-release checklist | Scenarios: tenant switch, explain drawer, downloads parity copy. |
|
||||||
| Offline smoke | `stella offline kit import` + Playwright sealed-mode run | Prior to Offline Kit cut | Validates offline banners, disabled actions, keyboard flows without Authority. |
|
| Offline smoke | `stella offline kit import` + Playwright sealed-mode run | Prior to Offline Kit cut | Validates offline banners, disabled actions, keyboard flows without Authority. |
|
||||||
|
|
||||||
Accessibility QA (CONSOLE-QA-23-402) tracks failing scenarios via Playwright snapshots and publishes reports in the Downloads parity channel (`kind = "parity.report"` placeholder until CLI parity CI lands).
|
Accessibility QA (CONSOLE-QA-23-402) tracks failing scenarios via Playwright snapshots and publishes reports in the Downloads parity channel (`kind = "parity.report"` placeholder until CLI parity CI lands).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 6 · Offline & Internationalisation Considerations
|
## 6 · Offline & Internationalisation Considerations
|
||||||
|
|
||||||
- Offline mode surfaces staleness badges and disables remote-only palette entries; keyboard focus skips disabled controls.
|
- Offline mode surfaces staleness badges and disables remote-only palette entries; keyboard focus skips disabled controls.
|
||||||
- Saved shortcuts, presets, and remaps serialise into Offline Kit bundles so operators can restore preferences post-import.
|
- Saved shortcuts, presets, and remaps serialise into Offline Kit bundles so operators can restore preferences post-import.
|
||||||
- Locale switching (future feature flag) will load translations at runtime; ensure ARIA labels use i18n tokens rather than hard-coded strings.
|
- Locale switching (future feature flag) will load translations at runtime; ensure ARIA labels use i18n tokens rather than hard-coded strings.
|
||||||
- For sealed installs, guidance panels include CLI equivalents (`stella auth fresh-auth`, `stella runs export`) to unblock tasks when Authority is unavailable.
|
- For sealed installs, guidance panels include CLI equivalents (`stella auth fresh-auth`, `stella runs export`) to unblock tasks when Authority is unavailable.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 7 · Compliance Checklist
|
## 7 · Compliance Checklist
|
||||||
|
|
||||||
- [ ] Keyboard shortcut matrix validated (default + remapped) and documented.
|
- [ ] Keyboard shortcut matrix validated (default + remapped) and documented.
|
||||||
- [ ] Screen-reader pass recorded for tenant switch, Explain drawer, Downloads copy-to-clipboard.
|
- [ ] Screen-reader pass recorded for tenant switch, Explain drawer, Downloads copy-to-clipboard.
|
||||||
- [ ] Colour tokens audited; contrast reports stored with release artifacts.
|
- [ ] Colour tokens audited; contrast reports stored with release artifacts.
|
||||||
- [ ] Automated a11y pipelines (Storybook axe, Playwright a11y) green; failures feed the `#console-qa` channel.
|
- [ ] Automated a11y pipelines (Storybook axe, Playwright a11y) green; failures feed the `#console-qa` channel.
|
||||||
- [ ] Offline kit a11y smoke executed before publishing each bundle.
|
- [ ] Offline kit a11y smoke executed before publishing each bundle.
|
||||||
- [ ] CLI parity gaps logged in `/docs/cli-vs-ui-parity.md`; UI callouts reference fallback commands until parity closes.
|
- [ ] CLI parity gaps logged in `/docs/cli-vs-ui-parity.md`; UI callouts reference fallback commands until parity closes.
|
||||||
- [ ] Accessibility Guild sign-off captured in sprint log and release notes reference this guide.
|
- [ ] Accessibility Guild sign-off captured in sprint log and release notes reference this guide.
|
||||||
- [ ] References cross-checked (`/docs/ui/navigation.md`, `/docs/ui/downloads.md`, `/docs/security/console-security.md`, `/docs/observability/ui-telemetry.md`).
|
- [ ] References cross-checked (`/docs/ui/navigation.md`, `/docs/ui/downloads.md`, `/docs/security/console-security.md`, `/docs/observability/ui-telemetry.md`).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 8 · References
|
## 8 · References
|
||||||
|
|
||||||
- `/docs/ui/navigation.md` – shortcut definitions, URL schema.
|
- `/docs/ui/navigation.md` – shortcut definitions, URL schema.
|
||||||
- `/docs/ui/downloads.md` – CLI parity and offline copy workflows.
|
- `/docs/ui/downloads.md` – CLI parity and offline copy workflows.
|
||||||
- `/docs/ui/console-overview.md` – tenant model, filter behaviours.
|
- `/docs/ui/console-overview.md` – tenant model, filter behaviours.
|
||||||
- `/docs/security/console-security.md` – security metrics and DPoP/fresh-auth requirements.
|
- `/docs/security/console-security.md` – security metrics and DPoP/fresh-auth requirements.
|
||||||
- `/docs/observability/ui-telemetry.md` – telemetry metrics mapped to accessibility features.
|
- `/docs/observability/ui-telemetry.md` – telemetry metrics mapped to accessibility features.
|
||||||
- `/docs/cli-vs-ui-parity.md` – parity status per console feature.
|
- `/docs/cli-vs-ui-parity.md` – parity status per console feature.
|
||||||
- `CONSOLE-QA-23-402` – Accessibility QA backlog (Playwright + manual checks).
|
- `CONSOLE-QA-23-402` – Accessibility QA backlog (Playwright + manual checks).
|
||||||
- `CONSOLE-FEAT-23-102` – Design tokens & theming delivery.
|
- `CONSOLE-FEAT-23-102` – Design tokens & theming delivery.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
*Last updated: 2025-10-28 (Sprint 23).*
|
*Last updated: 2025-10-28 (Sprint 23).*
|
||||||
|
|
||||||
|
|||||||
@@ -1,218 +1,218 @@
|
|||||||
# Advisory Observations & Linksets
|
# Advisory Observations & Linksets
|
||||||
|
|
||||||
> Imposed rule: Work of this type or tasks of this type on this component must also
|
> Imposed rule: Work of this type or tasks of this type on this component must also
|
||||||
> be applied everywhere else it should be applied.
|
> be applied everywhere else it should be applied.
|
||||||
|
|
||||||
The Link-Not-Merge (LNM) initiative replaces the legacy "merge" pipeline with
|
The Link-Not-Merge (LNM) initiative replaces the legacy "merge" pipeline with
|
||||||
immutable observations and correlation linksets. This guide explains how
|
immutable observations and correlation linksets. This guide explains how
|
||||||
Concelier ingests advisory statements, preserves upstream truth, and produces
|
Concelier ingests advisory statements, preserves upstream truth, and produces
|
||||||
linksets that downstream services (Policy Engine, Vuln Explorer, Console) can
|
linksets that downstream services (Policy Engine, Vuln Explorer, Console) can
|
||||||
use without collapsing sources together.
|
use without collapsing sources together.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 1. Model overview
|
## 1. Model overview
|
||||||
|
|
||||||
### 1.1 Observation lifecycle
|
### 1.1 Observation lifecycle
|
||||||
|
|
||||||
1. **Ingest** – Connectors fetch upstream payloads (CSAF, OSV, vendor feeds),
|
1. **Ingest** – Connectors fetch upstream payloads (CSAF, OSV, vendor feeds),
|
||||||
validate signatures, and drop any derived fields prohibited by the
|
validate signatures, and drop any derived fields prohibited by the
|
||||||
Aggregation-Only Contract (AOC).
|
Aggregation-Only Contract (AOC).
|
||||||
2. **Persist** – Concelier writes immutable `advisory_observations` scoped by
|
2. **Persist** – Concelier writes immutable `advisory_observations` scoped by
|
||||||
`tenant`, `(source.vendor, upstreamId)`, and `contentHash`. Supersedes chains
|
`tenant`, `(source.vendor, upstreamId)`, and `contentHash`. Supersedes chains
|
||||||
capture revisions without mutating history.
|
capture revisions without mutating history.
|
||||||
3. **Expose** – WebService surfaces paged/read APIs; Offline Kit snapshots
|
3. **Expose** – WebService surfaces paged/read APIs; Offline Kit snapshots
|
||||||
include the same documents for air-gapped installs.
|
include the same documents for air-gapped installs.
|
||||||
|
|
||||||
Observation schema highlights:
|
Observation schema highlights:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
observationId = {tenant}:{source.vendor}:{upstreamId}:{revision}
|
observationId = {tenant}:{source.vendor}:{upstreamId}:{revision}
|
||||||
tenant, source{vendor, stream, api, collectorVersion}
|
tenant, source{vendor, stream, api, collectorVersion}
|
||||||
upstream{upstreamId, documentVersion, fetchedAt, receivedAt,
|
upstream{upstreamId, documentVersion, fetchedAt, receivedAt,
|
||||||
contentHash, signature{present, format, keyId, signature}}
|
contentHash, signature{present, format, keyId, signature}}
|
||||||
content{format, specVersion, raw}
|
content{format, specVersion, raw}
|
||||||
identifiers{cve?, ghsa?, aliases[], osvIds[]}
|
identifiers{cve?, ghsa?, aliases[], osvIds[]}
|
||||||
linkset{purls[], cpes[], aliases[], references[], conflicts[]?}
|
linkset{purls[], cpes[], aliases[], references[], conflicts[]?}
|
||||||
createdAt, attributes{batchId?, replayCursor?}
|
createdAt, attributes{batchId?, replayCursor?}
|
||||||
```
|
```
|
||||||
|
|
||||||
- **Immutable raw** (`content.raw`) mirrors upstream payloads exactly.
|
- **Immutable raw** (`content.raw`) mirrors upstream payloads exactly.
|
||||||
- **Provenance** (`source.*`, `upstream.*`) satisfies AOC guardrails and enables
|
- **Provenance** (`source.*`, `upstream.*`) satisfies AOC guardrails and enables
|
||||||
cryptographic attestations.
|
cryptographic attestations.
|
||||||
- **Identifiers** retain lossless extracts (CVE, GHSA, vendor aliases) that seed
|
- **Identifiers** retain lossless extracts (CVE, GHSA, vendor aliases) that seed
|
||||||
linksets.
|
linksets.
|
||||||
- **Linkset** captures join hints but never merges or adds derived severity.
|
- **Linkset** captures join hints but never merges or adds derived severity.
|
||||||
|
|
||||||
### 1.2 Linkset lifecycle
|
### 1.2 Linkset lifecycle
|
||||||
|
|
||||||
Linksets correlate observations that describe the same vulnerable product while
|
Linksets correlate observations that describe the same vulnerable product while
|
||||||
keeping each source intact.
|
keeping each source intact.
|
||||||
|
|
||||||
1. **Seed** – Observations emit normalized identifiers (`purl`, `cpe`,
|
1. **Seed** – Observations emit normalized identifiers (`purl`, `cpe`,
|
||||||
`alias`) during ingestion.
|
`alias`) during ingestion.
|
||||||
2. **Correlate** – Linkset builder groups observations by tenant, product
|
2. **Correlate** – Linkset builder groups observations by tenant, product
|
||||||
coordinates, and equivalence signals (PURL alias graph, CVE overlap, CVSS
|
coordinates, and equivalence signals (PURL alias graph, CVE overlap, CVSS
|
||||||
vector equality, fuzzy titles).
|
vector equality, fuzzy titles).
|
||||||
3. **Annotate** – Detected conflicts (severity disagreements, affected-range
|
3. **Annotate** – Detected conflicts (severity disagreements, affected-range
|
||||||
mismatch, incompatible references) are recorded with structured payloads and
|
mismatch, incompatible references) are recorded with structured payloads and
|
||||||
preserved for UI/API export.
|
preserved for UI/API export.
|
||||||
4. **Persist** – Results land in `advisory_linksets` with deterministic IDs
|
4. **Persist** – Results land in `advisory_linksets` with deterministic IDs
|
||||||
(`linksetId = {tenant}:{hash(aliases+purls+seedIds)}`) and append-only history
|
(`linksetId = {tenant}:{hash(aliases+purls+seedIds)}`) and append-only history
|
||||||
for reproducibility.
|
for reproducibility.
|
||||||
|
|
||||||
Linksets never suppress or prefer one source; they provide aligned evidence so
|
Linksets never suppress or prefer one source; they provide aligned evidence so
|
||||||
other services can apply policy.
|
other services can apply policy.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 2. Observation vs. linkset
|
## 2. Observation vs. linkset
|
||||||
|
|
||||||
- **Purpose**
|
- **Purpose**
|
||||||
- Observation: Immutable record per vendor and revision.
|
- Observation: Immutable record per vendor and revision.
|
||||||
- Linkset: Correlates observations that share product identity.
|
- Linkset: Correlates observations that share product identity.
|
||||||
- **Mutation**
|
- **Mutation**
|
||||||
- Observation: Append-only via supersedes chain.
|
- Observation: Append-only via supersedes chain.
|
||||||
- Linkset: Rebuilt deterministically from canonical signals.
|
- Linkset: Rebuilt deterministically from canonical signals.
|
||||||
- **Allowed fields**
|
- **Allowed fields**
|
||||||
- Observation: Raw payload, provenance, identifiers, join hints.
|
- Observation: Raw payload, provenance, identifiers, join hints.
|
||||||
- Linkset: Observation references, normalized product metadata, conflicts.
|
- Linkset: Observation references, normalized product metadata, conflicts.
|
||||||
- **Forbidden fields**
|
- **Forbidden fields**
|
||||||
- Observation: Derived severity, policy status, opinionated dedupe.
|
- Observation: Derived severity, policy status, opinionated dedupe.
|
||||||
- Linkset: Derived severity (conflicts recorded but unresolved).
|
- Linkset: Derived severity (conflicts recorded but unresolved).
|
||||||
- **Consumers**
|
- **Consumers**
|
||||||
- Observation: Evidence API, Offline Kit, CLI exports.
|
- Observation: Evidence API, Offline Kit, CLI exports.
|
||||||
- Linkset: Policy Engine overlay, UI evidence panel, Vuln Explorer.
|
- Linkset: Policy Engine overlay, UI evidence panel, Vuln Explorer.
|
||||||
|
|
||||||
### 2.1 Example sequence
|
### 2.1 Example sequence
|
||||||
|
|
||||||
1. Red Hat PSIRT publishes RHSA-2025:1234 for OpenSSL; Concelier inserts an
|
1. Red Hat PSIRT publishes RHSA-2025:1234 for OpenSSL; Concelier inserts an
|
||||||
observation for vendor `redhat` with `pkg:rpm/redhat/openssl@1.1.1w-12`.
|
observation for vendor `redhat` with `pkg:rpm/redhat/openssl@1.1.1w-12`.
|
||||||
2. NVD issues CVE-2025-0001; a second observation is inserted for vendor `nvd`.
|
2. NVD issues CVE-2025-0001; a second observation is inserted for vendor `nvd`.
|
||||||
3. Linkset builder runs, groups the two observations, records alias and PURL
|
3. Linkset builder runs, groups the two observations, records alias and PURL
|
||||||
overlap, and flags a CVSS disagreement (`7.5` vs `7.2`).
|
overlap, and flags a CVSS disagreement (`7.5` vs `7.2`).
|
||||||
4. Policy Engine reads the linkset, recognises the severity variance, and relies
|
4. Policy Engine reads the linkset, recognises the severity variance, and relies
|
||||||
on configured rules to decide the effective output.
|
on configured rules to decide the effective output.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 3. Conflict handling
|
## 3. Conflict handling
|
||||||
|
|
||||||
Conflicts record disagreements without altering source payloads. The builder
|
Conflicts record disagreements without altering source payloads. The builder
|
||||||
emits structured entries:
|
emits structured entries:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"type": "severity-mismatch",
|
"type": "severity-mismatch",
|
||||||
"field": "cvss.baseScore",
|
"field": "cvss.baseScore",
|
||||||
"observations": [
|
"observations": [
|
||||||
{
|
{
|
||||||
"source": "redhat",
|
"source": "redhat",
|
||||||
"value": "7.5",
|
"value": "7.5",
|
||||||
"vector": "AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N"
|
"vector": "AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"source": "nvd",
|
"source": "nvd",
|
||||||
"value": "7.2",
|
"value": "7.2",
|
||||||
"vector": "AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N"
|
"vector": "AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"confidence": "medium",
|
"confidence": "medium",
|
||||||
"detectedAt": "2025-10-27T14:00:00Z"
|
"detectedAt": "2025-10-27T14:00:00Z"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Supported conflict classes:
|
Supported conflict classes:
|
||||||
|
|
||||||
- `severity-mismatch` – CVSS or qualitative severities differ.
|
- `severity-mismatch` – CVSS or qualitative severities differ.
|
||||||
- `affected-range-divergence` – Product ranges, fixed versions, or platforms
|
- `affected-range-divergence` – Product ranges, fixed versions, or platforms
|
||||||
disagree.
|
disagree.
|
||||||
- `statement-disagreement` – One observation declares `not_affected` while
|
- `statement-disagreement` – One observation declares `not_affected` while
|
||||||
another states `affected`.
|
another states `affected`.
|
||||||
- `reference-clash` – URL or classifier collisions (for example, exploit URL vs
|
- `reference-clash` – URL or classifier collisions (for example, exploit URL vs
|
||||||
conflicting advisory).
|
conflicting advisory).
|
||||||
- `alias-inconsistency` – Aliases map to different canonical IDs (GHSA vs CVE).
|
- `alias-inconsistency` – Aliases map to different canonical IDs (GHSA vs CVE).
|
||||||
- `metadata-gap` – Required provenance missing on one source; logged as a
|
- `metadata-gap` – Required provenance missing on one source; logged as a
|
||||||
warning.
|
warning.
|
||||||
|
|
||||||
Conflict surfaces:
|
Conflict surfaces:
|
||||||
|
|
||||||
- WebService endpoints (`GET /advisories/linksets/{id}` → `conflicts[]`).
|
- WebService endpoints (`GET /advisories/linksets/{id}` → `conflicts[]`).
|
||||||
- UI evidence panel chips and conflict badges.
|
- UI evidence panel chips and conflict badges.
|
||||||
- CLI exports (JSON/OSV) exposed through LNM commands.
|
- CLI exports (JSON/OSV) exposed through LNM commands.
|
||||||
- Observability metrics (`advisory_linkset_conflicts_total{type}`).
|
- Observability metrics (`advisory_linkset_conflicts_total{type}`).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 4. AOC alignment
|
## 4. AOC alignment
|
||||||
|
|
||||||
Observations and linksets must satisfy Aggregation-Only Contract invariants:
|
Observations and linksets must satisfy Aggregation-Only Contract invariants:
|
||||||
|
|
||||||
- **No derived severity** – `content.raw` may include upstream severity, but the
|
- **No derived severity** – `content.raw` may include upstream severity, but the
|
||||||
observation body never injects or edits severity.
|
observation body never injects or edits severity.
|
||||||
- **No merges** – Each upstream document stays separate; linksets reference
|
- **No merges** – Each upstream document stays separate; linksets reference
|
||||||
observations via deterministic IDs.
|
observations via deterministic IDs.
|
||||||
- **Provenance mandatory** – Missing `signature` or `source` metadata is an AOC
|
- **Provenance mandatory** – Missing `signature` or `source` metadata is an AOC
|
||||||
violation (`ERR_AOC_004`).
|
violation (`ERR_AOC_004`).
|
||||||
- **Idempotent writes** – Duplicate `contentHash` yields a no-op; supersedes
|
- **Idempotent writes** – Duplicate `contentHash` yields a no-op; supersedes
|
||||||
pointer captures new revisions.
|
pointer captures new revisions.
|
||||||
- **Deterministic output** – Linkset builder sorts keys, normalizes timestamps
|
- **Deterministic output** – Linkset builder sorts keys, normalizes timestamps
|
||||||
(UTC ISO-8601), and uses canonical JSON hashing.
|
(UTC ISO-8601), and uses canonical JSON hashing.
|
||||||
|
|
||||||
Violations trigger guard errors (`ERR_AOC_00x`), emit `aoc_violation_total`
|
Violations trigger guard errors (`ERR_AOC_00x`), emit `aoc_violation_total`
|
||||||
metrics, and block persistence until corrected.
|
metrics, and block persistence until corrected.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 5. Downstream consumption
|
## 5. Downstream consumption
|
||||||
|
|
||||||
- **Policy Engine** – Computes effective severity and risk overlays from linkset
|
- **Policy Engine** – Computes effective severity and risk overlays from linkset
|
||||||
evidence and conflicts.
|
evidence and conflicts.
|
||||||
- **Console UI** – Renders per-source statements, signed hashes, and conflict
|
- **Console UI** – Renders per-source statements, signed hashes, and conflict
|
||||||
banners inside the evidence panel.
|
banners inside the evidence panel.
|
||||||
- **CLI (`stella advisories linkset …`)** – Exports observations and linksets as
|
- **CLI (`stella advisories linkset …`)** – Exports observations and linksets as
|
||||||
JSON or OSV for offline triage.
|
JSON or OSV for offline triage.
|
||||||
- **Offline Kit** – Shipping snapshots include observation and linkset
|
- **Offline Kit** – Shipping snapshots include observation and linkset
|
||||||
collections for air-gap parity.
|
collections for air-gap parity.
|
||||||
- **Observability** – Dashboards track ingestion latency, conflict counts, and
|
- **Observability** – Dashboards track ingestion latency, conflict counts, and
|
||||||
supersedes depth.
|
supersedes depth.
|
||||||
|
|
||||||
When adding new consumers, ensure they honour append-only semantics and do not
|
When adding new consumers, ensure they honour append-only semantics and do not
|
||||||
mutate observation or linkset collections.
|
mutate observation or linkset collections.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 6. Validation & testing
|
## 6. Validation & testing
|
||||||
|
|
||||||
- **Unit tests** (`StellaOps.Concelier.Core.Tests`) validate schema guards,
|
- **Unit tests** (`StellaOps.Concelier.Core.Tests`) validate schema guards,
|
||||||
deterministic linkset hashing, conflict detection fixtures, and supersedes
|
deterministic linkset hashing, conflict detection fixtures, and supersedes
|
||||||
chains.
|
chains.
|
||||||
- **Mongo integration tests** (`StellaOps.Concelier.Storage.Mongo.Tests`) verify
|
- **Mongo integration tests** (`StellaOps.Concelier.Storage.Mongo.Tests`) verify
|
||||||
indexes and idempotent writes under concurrency.
|
indexes and idempotent writes under concurrency.
|
||||||
- **CLI smoke suites** confirm `stella advisories observations` and `stella
|
- **CLI smoke suites** confirm `stella advisories observations` and `stella
|
||||||
advisories linksets` export stable JSON.
|
advisories linksets` export stable JSON.
|
||||||
- **Determinism checks** replay identical upstream payloads and assert that the
|
- **Determinism checks** replay identical upstream payloads and assert that the
|
||||||
resulting observation and linkset documents match byte for byte.
|
resulting observation and linkset documents match byte for byte.
|
||||||
- **Offline kit verification** simulates air-gapped bootstrap to confirm that
|
- **Offline kit verification** simulates air-gapped bootstrap to confirm that
|
||||||
snapshots align with live data.
|
snapshots align with live data.
|
||||||
|
|
||||||
Add fixtures whenever a new conflict type or correlation signal is introduced.
|
Add fixtures whenever a new conflict type or correlation signal is introduced.
|
||||||
Ensure canonical JSON serialization remains stable across .NET runtime updates.
|
Ensure canonical JSON serialization remains stable across .NET runtime updates.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 7. Reviewer checklist
|
## 7. Reviewer checklist
|
||||||
|
|
||||||
- Observation schema segment matches the latest `StellaOps.Concelier.Models`
|
- Observation schema segment matches the latest `StellaOps.Concelier.Models`
|
||||||
contract.
|
contract.
|
||||||
- Linkset lifecycle covers correlation signals, conflict classes, and
|
- Linkset lifecycle covers correlation signals, conflict classes, and
|
||||||
deterministic IDs.
|
deterministic IDs.
|
||||||
- AOC invariants are explicitly called out with violation codes.
|
- AOC invariants are explicitly called out with violation codes.
|
||||||
- Examples include multi-source correlation plus conflict annotation.
|
- Examples include multi-source correlation plus conflict annotation.
|
||||||
- Downstream consumer guidance reflects active APIs and CLI features.
|
- Downstream consumer guidance reflects active APIs and CLI features.
|
||||||
- Testing section lists required suites (Core, Storage, CLI, Offline).
|
- Testing section lists required suites (Core, Storage, CLI, Offline).
|
||||||
- Imposed rule reminder is present at the top of the document.
|
- Imposed rule reminder is present at the top of the document.
|
||||||
|
|
||||||
Confirmed against Concelier Link-Not-Merge tasks:
|
Confirmed against Concelier Link-Not-Merge tasks:
|
||||||
`CONCELIER-LNM-21-001..005`, `CONCELIER-LNM-21-101..103`,
|
`CONCELIER-LNM-21-001..005`, `CONCELIER-LNM-21-101..103`,
|
||||||
`CONCELIER-LNM-21-201..203`.
|
`CONCELIER-LNM-21-201..203`.
|
||||||
|
|||||||
@@ -1,429 +1,429 @@
|
|||||||
> **Imposed rule:** Work of this type or tasks of this type on this component must also be applied everywhere else it should be applied.
|
> **Imposed rule:** Work of this type or tasks of this type on this component must also be applied everywhere else it should be applied.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# Epic 16: Air‑Gapped Mode
|
# Epic 16: Air‑Gapped Mode
|
||||||
|
|
||||||
**Short name:** Air‑Gapped Mode
|
**Short name:** Air‑Gapped Mode
|
||||||
**Primary components:** Web Services API, Console, CLI, Orchestrator, Task Runner, Conseiller (Feedser), Excitator (VEXer), Policy Engine, Findings Ledger, Export Center, Authority & Tenancy, Notifications, Observability & Forensics
|
**Primary components:** Web Services API, Console, CLI, Orchestrator, Task Runner, Conseiller (Feedser), Excitator (VEXer), Policy Engine, Findings Ledger, Export Center, Authority & Tenancy, Notifications, Observability & Forensics
|
||||||
**Surfaces:** offline bootstrap, update ingestion via mirror bundles, sealed egress, deterministic jobs, offline advisories/VEX, offline policy packs, offline notifications, evidence exports
|
**Surfaces:** offline bootstrap, update ingestion via mirror bundles, sealed egress, deterministic jobs, offline advisories/VEX, offline policy packs, offline notifications, evidence exports
|
||||||
**Dependencies:** Export Center, Containerized Distribution, Authority‑Backed Scopes & Tenancy, Observability & Forensics, Policy Studio
|
**Dependencies:** Export Center, Containerized Distribution, Authority‑Backed Scopes & Tenancy, Observability & Forensics, Policy Studio
|
||||||
|
|
||||||
**AOC ground rule reminder:** Conseiller and Excitator aggregate and link advisories/VEX. They never merge or mutate source records. Air‑Gapped Mode must preserve this invariant even when mirroring and importing updates.
|
**AOC ground rule reminder:** Conseiller and Excitator aggregate and link advisories/VEX. They never merge or mutate source records. Air‑Gapped Mode must preserve this invariant even when mirroring and importing updates.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 1) What it is
|
## 1) What it is
|
||||||
|
|
||||||
A fully supported operating profile where StellaOps runs in a disconnected environment with:
|
A fully supported operating profile where StellaOps runs in a disconnected environment with:
|
||||||
|
|
||||||
* **Zero external egress** from platform services and jobs.
|
* **Zero external egress** from platform services and jobs.
|
||||||
* **Deterministic inputs** provided via signed, offline **Mirror Bundles** (advisories, VEX, policy packs, vendor feeds, Stella metadata, container images, dashboards).
|
* **Deterministic inputs** provided via signed, offline **Mirror Bundles** (advisories, VEX, policy packs, vendor feeds, Stella metadata, container images, dashboards).
|
||||||
* **Offline bootstrap** for images and charts, plus reproducible configuration and cryptographically verifiable updates.
|
* **Offline bootstrap** for images and charts, plus reproducible configuration and cryptographically verifiable updates.
|
||||||
* **Graceful feature degradation** with explicit UX: features that require external connectivity are either backed by local artifacts or clearly disabled with an explanation.
|
* **Graceful feature degradation** with explicit UX: features that require external connectivity are either backed by local artifacts or clearly disabled with an explanation.
|
||||||
* **Auditable import/export** including provenance attestations, evidence bundles, and chain‑of‑custody for all offline exchanges.
|
* **Auditable import/export** including provenance attestations, evidence bundles, and chain‑of‑custody for all offline exchanges.
|
||||||
|
|
||||||
Air‑Gapped Mode is selectable at install time and enforceable at runtime. When enabled, all components operate under an “egress sealed” policy and only consume data from local stores.
|
Air‑Gapped Mode is selectable at install time and enforceable at runtime. When enabled, all components operate under an “egress sealed” policy and only consume data from local stores.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 2) Why
|
## 2) Why
|
||||||
|
|
||||||
Many users operate in classified, regulated, or high‑sensitivity networks where egress is prohibited. They still need SBOM analysis, policy evaluation, advisory/VEX mapping, and reporting. Air‑Gapped Mode provides the same core outcomes with verifiable offline inputs and explicit operational guardrails.
|
Many users operate in classified, regulated, or high‑sensitivity networks where egress is prohibited. They still need SBOM analysis, policy evaluation, advisory/VEX mapping, and reporting. Air‑Gapped Mode provides the same core outcomes with verifiable offline inputs and explicit operational guardrails.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 3) How it should work
|
## 3) How it should work
|
||||||
|
|
||||||
### 3.1 Modes and lifecycle
|
### 3.1 Modes and lifecycle
|
||||||
|
|
||||||
* **Connected Mode:** normal operation; can create Mirror Bundles on a staging host.
|
* **Connected Mode:** normal operation; can create Mirror Bundles on a staging host.
|
||||||
* **Sealed Air‑Gapped Mode:** platform enforces no egress. Only local resources are allowed.
|
* **Sealed Air‑Gapped Mode:** platform enforces no egress. Only local resources are allowed.
|
||||||
* **Transition flow:**
|
* **Transition flow:**
|
||||||
|
|
||||||
1. Prepare an offline **Bootstrap Pack** with all container images, Helm/compose charts, seed database, and initial Mirror Bundle.
|
1. Prepare an offline **Bootstrap Pack** with all container images, Helm/compose charts, seed database, and initial Mirror Bundle.
|
||||||
2. Install in the air‑gapped enclave and **seal** egress.
|
2. Install in the air‑gapped enclave and **seal** egress.
|
||||||
3. Periodically import new **Mirror Bundles** via removable media.
|
3. Periodically import new **Mirror Bundles** via removable media.
|
||||||
4. Export evidence/reports as needed.
|
4. Export evidence/reports as needed.
|
||||||
|
|
||||||
### 3.2 Egress sealing
|
### 3.2 Egress sealing
|
||||||
|
|
||||||
* **Static guardrails:**
|
* **Static guardrails:**
|
||||||
|
|
||||||
* Platform flag `STELLA_AIRGAP=sealed` and database feature flag `env.mode='sealed'`.
|
* Platform flag `STELLA_AIRGAP=sealed` and database feature flag `env.mode='sealed'`.
|
||||||
* NetworkPolicy/iptables/eBPF deny‑all egress for namespaces/pods except loopback and the internal object store.
|
* NetworkPolicy/iptables/eBPF deny‑all egress for namespaces/pods except loopback and the internal object store.
|
||||||
* Outbound DNS blocked.
|
* Outbound DNS blocked.
|
||||||
* HTTP clients in code use a single `EgressPolicy` facade. When sealed, it panics on direct network calls and returns a typed error with remediation (“import a Mirror Bundle”).
|
* HTTP clients in code use a single `EgressPolicy` facade. When sealed, it panics on direct network calls and returns a typed error with remediation (“import a Mirror Bundle”).
|
||||||
* **Verification:** `GET /system/airgap/status` returns `sealed: true|false`, current policy hash, and last import timestamp. CLI prints warning if not sealed in declared air‑gapped install.
|
* **Verification:** `GET /system/airgap/status` returns `sealed: true|false`, current policy hash, and last import timestamp. CLI prints warning if not sealed in declared air‑gapped install.
|
||||||
|
|
||||||
### 3.3 Trusted time
|
### 3.3 Trusted time
|
||||||
|
|
||||||
* Air‑gapped systems cannot NTP. Each Mirror Bundle includes a **signed time token** (Roughtime‑style or RFC 3161) from a trusted authority. On import, platform stores `time_anchor` for drift calculations and staleness checks.
|
* Air‑gapped systems cannot NTP. Each Mirror Bundle includes a **signed time token** (Roughtime‑style or RFC 3161) from a trusted authority. On import, platform stores `time_anchor` for drift calculations and staleness checks.
|
||||||
* If time drift exceeds policy threshold, UI shows “stale view” badges and some jobs are blocked until a new bundle provides a fresh anchor.
|
* If time drift exceeds policy threshold, UI shows “stale view” badges and some jobs are blocked until a new bundle provides a fresh anchor.
|
||||||
|
|
||||||
### 3.4 Mirror Bundles (offline updates)
|
### 3.4 Mirror Bundles (offline updates)
|
||||||
|
|
||||||
* **Content types:**
|
* **Content types:**
|
||||||
|
|
||||||
* Public advisories (OSV, GHSA, vendor advisories), NVD mappings, CPE/Package metadata.
|
* Public advisories (OSV, GHSA, vendor advisories), NVD mappings, CPE/Package metadata.
|
||||||
* VEX statements from vendors/communities.
|
* VEX statements from vendors/communities.
|
||||||
* Policy packs (templates, baselines, versioned rule sets).
|
* Policy packs (templates, baselines, versioned rule sets).
|
||||||
* StellaOps engine metadata and schema migrations.
|
* StellaOps engine metadata and schema migrations.
|
||||||
* Optional: **OCI image set** for platform and recommended runners.
|
* Optional: **OCI image set** for platform and recommended runners.
|
||||||
* Optional: dashboards and alert rule packs.
|
* Optional: dashboards and alert rule packs.
|
||||||
* **Format:** a TUF‑like layout:
|
* **Format:** a TUF‑like layout:
|
||||||
|
|
||||||
```
|
```
|
||||||
root.json, snapshot.json, timestamp.json, targets/
|
root.json, snapshot.json, timestamp.json, targets/
|
||||||
advisories/*.jsonl.zst
|
advisories/*.jsonl.zst
|
||||||
vex/*.jsonl.zst
|
vex/*.jsonl.zst
|
||||||
policy/*.tar.zst
|
policy/*.tar.zst
|
||||||
images/* (OCI layout or oci-archive)
|
images/* (OCI layout or oci-archive)
|
||||||
meta/engine/*.tgz
|
meta/engine/*.tgz
|
||||||
meta/time-anchor.json (signed)
|
meta/time-anchor.json (signed)
|
||||||
```
|
```
|
||||||
* **Integrity & trust:**
|
* **Integrity & trust:**
|
||||||
|
|
||||||
* DSSE‑signed target manifests.
|
* DSSE‑signed target manifests.
|
||||||
* Root of trust rotated via `root.json` within strict policy; rotation requires manual dual approval in sealed mode.
|
* Root of trust rotated via `root.json` within strict policy; rotation requires manual dual approval in sealed mode.
|
||||||
* Each content artifact has a content digest and a **Merkle root** for the overall bundle.
|
* Each content artifact has a content digest and a **Merkle root** for the overall bundle.
|
||||||
* **Creation:** in connected networks, `stella mirror create --content advisories,vex,policy,images --since 2025-01-01 --out bundle.tgz`.
|
* **Creation:** in connected networks, `stella mirror create --content advisories,vex,policy,images --since 2025-01-01 --out bundle.tgz`.
|
||||||
* **Import:** in air‑gap, `stella airgap import bundle.tgz`. The importer verifies DSSE, TUF metadata, Merkle root, then writes to local object store and updates catalog tables.
|
* **Import:** in air‑gap, `stella airgap import bundle.tgz`. The importer verifies DSSE, TUF metadata, Merkle root, then writes to local object store and updates catalog tables.
|
||||||
* **Idempotence:** imports are content‑addressed; re‑imports deduplicate.
|
* **Idempotence:** imports are content‑addressed; re‑imports deduplicate.
|
||||||
|
|
||||||
### 3.5 Deterministic jobs and sources
|
### 3.5 Deterministic jobs and sources
|
||||||
|
|
||||||
* **Allowed sources:** filesystem, internal object store, tenant private registry, and pre‑approved connectors that don’t require external egress.
|
* **Allowed sources:** filesystem, internal object store, tenant private registry, and pre‑approved connectors that don’t require external egress.
|
||||||
* **Disallowed in sealed mode:** remote package registries, web scrapers, outbound webhooks, cloud KMS unless on the enclave network.
|
* **Disallowed in sealed mode:** remote package registries, web scrapers, outbound webhooks, cloud KMS unless on the enclave network.
|
||||||
* **Runner policy:** the Task Runner verifies job descriptors contain no network calls unless marked `internal:` with allow‑listed destinations. Violations fail at plan time with an explainable error.
|
* **Runner policy:** the Task Runner verifies job descriptors contain no network calls unless marked `internal:` with allow‑listed destinations. Violations fail at plan time with an explainable error.
|
||||||
|
|
||||||
### 3.6 Conseiller and Excitator in air‑gap
|
### 3.6 Conseiller and Excitator in air‑gap
|
||||||
|
|
||||||
* **Conseiller (Feedser):** ingests advisories only from imported bundles or tenant local feeds. It preserves source identities and never merges. Linkage uses bundle‑provided cross‑refs and local heuristics.
|
* **Conseiller (Feedser):** ingests advisories only from imported bundles or tenant local feeds. It preserves source identities and never merges. Linkage uses bundle‑provided cross‑refs and local heuristics.
|
||||||
* **Excitator (VEXer):** imports VEX records as‑is, links them to components and advisories, and records the origin bundle and statement digests. Consensus Lens (Epic 7) operates offline across the imported sources.
|
* **Excitator (VEXer):** imports VEX records as‑is, links them to components and advisories, and records the origin bundle and statement digests. Consensus Lens (Epic 7) operates offline across the imported sources.
|
||||||
|
|
||||||
### 3.7 Policy Engine and Studio
|
### 3.7 Policy Engine and Studio
|
||||||
|
|
||||||
* Policy packs are versioned and imported via bundles.
|
* Policy packs are versioned and imported via bundles.
|
||||||
* Simulation and authoring work locally. Exports of new or updated policies can be packaged as **Policy Sub‑Bundles** for transfer back to connected environments if needed.
|
* Simulation and authoring work locally. Exports of new or updated policies can be packaged as **Policy Sub‑Bundles** for transfer back to connected environments if needed.
|
||||||
* Engine shows which rules depend on external evidence and how they degrade in sealed mode (e.g., “No external EPSS; using cached percentile from last bundle.”).
|
* Engine shows which rules depend on external evidence and how they degrade in sealed mode (e.g., “No external EPSS; using cached percentile from last bundle.”).
|
||||||
|
|
||||||
### 3.8 Notifications in sealed mode
|
### 3.8 Notifications in sealed mode
|
||||||
|
|
||||||
* Default to **local delivery** only: SMTP relay inside enclave, syslog, file sink.
|
* Default to **local delivery** only: SMTP relay inside enclave, syslog, file sink.
|
||||||
* External webhooks are disabled.
|
* External webhooks are disabled.
|
||||||
* Notification templates show “air‑gap compliant channel” tags to avoid misconfiguration.
|
* Notification templates show “air‑gap compliant channel” tags to avoid misconfiguration.
|
||||||
|
|
||||||
### 3.9 Observability & Forensics
|
### 3.9 Observability & Forensics
|
||||||
|
|
||||||
* Traces, logs, metrics remain local.
|
* Traces, logs, metrics remain local.
|
||||||
* Evidence Locker supports **portable evidence packages** for cross‑domain transfer: `stella forensic snapshot create --portable`.
|
* Evidence Locker supports **portable evidence packages** for cross‑domain transfer: `stella forensic snapshot create --portable`.
|
||||||
* Importing an evidence bundle in another enclave verifies signatures and maintains chain‑of‑custody.
|
* Importing an evidence bundle in another enclave verifies signatures and maintains chain‑of‑custody.
|
||||||
|
|
||||||
### 3.10 Console and CLI behavior
|
### 3.10 Console and CLI behavior
|
||||||
|
|
||||||
* Console shows a prominent **Air‑Gapped: Sealed** badge with last import time and staleness indicators for advisories, VEX, and policy packs.
|
* Console shows a prominent **Air‑Gapped: Sealed** badge with last import time and staleness indicators for advisories, VEX, and policy packs.
|
||||||
* CLI commands gain `--sealed` awareness: any operation that would egress prints a refusal with remediation suggesting the appropriate import.
|
* CLI commands gain `--sealed` awareness: any operation that would egress prints a refusal with remediation suggesting the appropriate import.
|
||||||
|
|
||||||
### 3.11 Multi‑tenant and scope
|
### 3.11 Multi‑tenant and scope
|
||||||
|
|
||||||
* Tenancy works unchanged. Bundle imports can target:
|
* Tenancy works unchanged. Bundle imports can target:
|
||||||
|
|
||||||
* `--tenant-global`: shared catalogs (advisories, VEX, policy baselines).
|
* `--tenant-global`: shared catalogs (advisories, VEX, policy baselines).
|
||||||
* `--tenant=<id>`: tenant‑specific content (e.g., private advisories).
|
* `--tenant=<id>`: tenant‑specific content (e.g., private advisories).
|
||||||
* Authority scopes gain `airgap:import`, `airgap:status:read`, `airgap:seal` (admin‑only).
|
* Authority scopes gain `airgap:import`, `airgap:status:read`, `airgap:seal` (admin‑only).
|
||||||
|
|
||||||
### 3.12 Feature degradation matrix
|
### 3.12 Feature degradation matrix
|
||||||
|
|
||||||
* **AI Assistant:** offline variants use local models if installed; otherwise feature is disabled with a message.
|
* **AI Assistant:** offline variants use local models if installed; otherwise feature is disabled with a message.
|
||||||
* **External reputation feeds (e.g., EPSS‑like):** replaced by cached values from the bundle.
|
* **External reputation feeds (e.g., EPSS‑like):** replaced by cached values from the bundle.
|
||||||
* **Container base image lookups:** rely on imported metadata or tenant private registry.
|
* **Container base image lookups:** rely on imported metadata or tenant private registry.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 4) Architecture
|
## 4) Architecture
|
||||||
|
|
||||||
### 4.1 New modules
|
### 4.1 New modules
|
||||||
|
|
||||||
* `airgap/controller`
|
* `airgap/controller`
|
||||||
|
|
||||||
* Sealing state machine; status API; guardrails wiring into HTTP clients and runner.
|
* Sealing state machine; status API; guardrails wiring into HTTP clients and runner.
|
||||||
* `airgap/importer`
|
* `airgap/importer`
|
||||||
|
|
||||||
* TUF/DSSE verification, Merkle validation, object store loader, catalog updater.
|
* TUF/DSSE verification, Merkle validation, object store loader, catalog updater.
|
||||||
* `mirror/creator`
|
* `mirror/creator`
|
||||||
|
|
||||||
* Connected‑side builder for bundles; content plug‑ins for advisories/VEX/policy/images.
|
* Connected‑side builder for bundles; content plug‑ins for advisories/VEX/policy/images.
|
||||||
* `airgap/policy`
|
* `airgap/policy`
|
||||||
|
|
||||||
* Enforcement library exposing `EgressPolicy` facade and job plan validators.
|
* Enforcement library exposing `EgressPolicy` facade and job plan validators.
|
||||||
* `airgap/time`
|
* `airgap/time`
|
||||||
|
|
||||||
* Time anchor parser, drift checks, staleness annotations.
|
* Time anchor parser, drift checks, staleness annotations.
|
||||||
* `console/airgap`
|
* `console/airgap`
|
||||||
|
|
||||||
* Sealed badge, import UI, staleness dashboards, degradation notices.
|
* Sealed badge, import UI, staleness dashboards, degradation notices.
|
||||||
* `cli/airgap`
|
* `cli/airgap`
|
||||||
|
|
||||||
* `stella airgap seal|status|import|verify` commands; `stella mirror create|verify`.
|
* `stella airgap seal|status|import|verify` commands; `stella mirror create|verify`.
|
||||||
|
|
||||||
### 4.2 Data model additions
|
### 4.2 Data model additions
|
||||||
|
|
||||||
* `airgap_state(id, sealed BOOLEAN, policy_hash TEXT, last_import_at TIMESTAMP, time_anchor JSONB)`
|
* `airgap_state(id, sealed BOOLEAN, policy_hash TEXT, last_import_at TIMESTAMP, time_anchor JSONB)`
|
||||||
* `bundle_catalog(id, kind ENUM, merkle_root TEXT, dsse_signer TEXT, created_at TIMESTAMP, imported_at TIMESTAMP, scope ENUM('global','tenant'), tenant_id NULLABLE, labels JSONB)`
|
* `bundle_catalog(id, kind ENUM, merkle_root TEXT, dsse_signer TEXT, created_at TIMESTAMP, imported_at TIMESTAMP, scope ENUM('global','tenant'), tenant_id NULLABLE, labels JSONB)`
|
||||||
* `bundle_items(bundle_id, path TEXT, sha256 TEXT, size BIGINT, type TEXT, meta JSONB)`
|
* `bundle_items(bundle_id, path TEXT, sha256 TEXT, size BIGINT, type TEXT, meta JSONB)`
|
||||||
* `import_audit(id, bundle_id, actor, tenant_scope, verify_result, trace_id, created_at)`
|
* `import_audit(id, bundle_id, actor, tenant_scope, verify_result, trace_id, created_at)`
|
||||||
|
|
||||||
RLS: tenant‑scoped rows when `scope='tenant'`; global rows readable only with `stella:airgap:status:read`.
|
RLS: tenant‑scoped rows when `scope='tenant'`; global rows readable only with `stella:airgap:status:read`.
|
||||||
|
|
||||||
### 4.3 Storage layout
|
### 4.3 Storage layout
|
||||||
|
|
||||||
Object store paths:
|
Object store paths:
|
||||||
|
|
||||||
```
|
```
|
||||||
tenants/_global/mirror/<bundle_id>/targets/...
|
tenants/_global/mirror/<bundle_id>/targets/...
|
||||||
tenants/<tenant>/mirror/<bundle_id>/targets/...
|
tenants/<tenant>/mirror/<bundle_id>/targets/...
|
||||||
tenants/_global/images/<digest>/...
|
tenants/_global/images/<digest>/...
|
||||||
```
|
```
|
||||||
|
|
||||||
Evidence locker remains separate. Imported images use **OCI layout** for local registry sync.
|
Evidence locker remains separate. Imported images use **OCI layout** for local registry sync.
|
||||||
|
|
||||||
### 4.4 Message topics
|
### 4.4 Message topics
|
||||||
|
|
||||||
* `stella.<tenant>.airgap.imported` with bundle metadata.
|
* `stella.<tenant>.airgap.imported` with bundle metadata.
|
||||||
* `stella.<tenant>.airgap.staleness` periodic events emitted for UX.
|
* `stella.<tenant>.airgap.staleness` periodic events emitted for UX.
|
||||||
* `stella.<tenant>.policy.degraded` when rules fall back due to sealed mode.
|
* `stella.<tenant>.policy.degraded` when rules fall back due to sealed mode.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 5) APIs and contracts
|
## 5) APIs and contracts
|
||||||
|
|
||||||
### 5.1 Status and control
|
### 5.1 Status and control
|
||||||
|
|
||||||
* `GET /system/airgap/status` → `{ sealed, policy_hash, last_import_at, time_anchor, drift_seconds, staleness: { advisories_days, vex_days, policy_days } }`
|
* `GET /system/airgap/status` → `{ sealed, policy_hash, last_import_at, time_anchor, drift_seconds, staleness: { advisories_days, vex_days, policy_days } }`
|
||||||
* `POST /system/airgap/seal` → seals environment; requires `stella:airgap:seal#tenant/<id or global>`.
|
* `POST /system/airgap/seal` → seals environment; requires `stella:airgap:seal#tenant/<id or global>`.
|
||||||
* `POST /system/airgap/unseal` → only allowed if installed mode is not declared “permanently sealed” at bootstrap. Typically disabled.
|
* `POST /system/airgap/unseal` → only allowed if installed mode is not declared “permanently sealed” at bootstrap. Typically disabled.
|
||||||
|
|
||||||
### 5.2 Import & verify
|
### 5.2 Import & verify
|
||||||
|
|
||||||
* `POST /airgap/import` multipart or file reference → runs verify, writes catalog, returns bundle summary and warnings.
|
* `POST /airgap/import` multipart or file reference → runs verify, writes catalog, returns bundle summary and warnings.
|
||||||
* `POST /airgap/verify` dry‑run verification returning DSSE/TUF and Merkle results.
|
* `POST /airgap/verify` dry‑run verification returning DSSE/TUF and Merkle results.
|
||||||
* `GET /airgap/bundles` list imported bundles with filters.
|
* `GET /airgap/bundles` list imported bundles with filters.
|
||||||
|
|
||||||
### 5.3 Conseiller/Excitator sources
|
### 5.3 Conseiller/Excitator sources
|
||||||
|
|
||||||
* `POST /feeds/register` supports `kind=mirror` with `bundle_id` and paths; disallowed to point to external URLs in sealed mode.
|
* `POST /feeds/register` supports `kind=mirror` with `bundle_id` and paths; disallowed to point to external URLs in sealed mode.
|
||||||
* `GET /feeds/status` shows per‑source staleness and last artifact version.
|
* `GET /feeds/status` shows per‑source staleness and last artifact version.
|
||||||
|
|
||||||
### 5.4 Errors
|
### 5.4 Errors
|
||||||
|
|
||||||
Standardized sealed‑mode error:
|
Standardized sealed‑mode error:
|
||||||
|
|
||||||
```
|
```
|
||||||
{
|
{
|
||||||
"code": "AIRGAP_EGRESS_BLOCKED",
|
"code": "AIRGAP_EGRESS_BLOCKED",
|
||||||
"message": "Egress is sealed. Import a Mirror Bundle with advisories.",
|
"message": "Egress is sealed. Import a Mirror Bundle with advisories.",
|
||||||
"remediation": "Run: stella airgap import bundle.tgz",
|
"remediation": "Run: stella airgap import bundle.tgz",
|
||||||
"trace_id": "..."
|
"trace_id": "..."
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 6) Documentation changes
|
## 6) Documentation changes
|
||||||
|
|
||||||
Create or update:
|
Create or update:
|
||||||
|
|
||||||
1. `/docs/airgap/overview.md`
|
1. `/docs/airgap/overview.md`
|
||||||
|
|
||||||
* Modes, lifecycle, responsibilities, threat model, what degrades.
|
* Modes, lifecycle, responsibilities, threat model, what degrades.
|
||||||
2. `/docs/airgap/bootstrap.md`
|
2. `/docs/airgap/bootstrap.md`
|
||||||
|
|
||||||
* Offline Bootstrap Pack creation, validation, install steps for Helm/compose, local registry seeding.
|
* Offline Bootstrap Pack creation, validation, install steps for Helm/compose, local registry seeding.
|
||||||
3. `/docs/airgap/mirror-bundles.md`
|
3. `/docs/airgap/mirror-bundles.md`
|
||||||
|
|
||||||
* Bundle format, DSSE/TUF/Merkle, signed time, creation on connected host, import in sealed environment, rotation of roots.
|
* Bundle format, DSSE/TUF/Merkle, signed time, creation on connected host, import in sealed environment, rotation of roots.
|
||||||
4. `/docs/airgap/sealing-and-egress.md`
|
4. `/docs/airgap/sealing-and-egress.md`
|
||||||
|
|
||||||
* Network policies, EgressPolicy facade, runner validation, verifying sealed status.
|
* Network policies, EgressPolicy facade, runner validation, verifying sealed status.
|
||||||
5. `/docs/airgap/staleness-and-time.md`
|
5. `/docs/airgap/staleness-and-time.md`
|
||||||
|
|
||||||
* Time anchor, drift, staleness budgets and UI behavior.
|
* Time anchor, drift, staleness budgets and UI behavior.
|
||||||
6. `/docs/airgap/operations.md`
|
6. `/docs/airgap/operations.md`
|
||||||
|
|
||||||
* Periodic update cadence, runbooks, failure scenarios, disaster recovery.
|
* Periodic update cadence, runbooks, failure scenarios, disaster recovery.
|
||||||
7. `/docs/airgap/degradation-matrix.md`
|
7. `/docs/airgap/degradation-matrix.md`
|
||||||
|
|
||||||
* Feature map: available, degraded, disabled; with remediation.
|
* Feature map: available, degraded, disabled; with remediation.
|
||||||
8. `/docs/console/airgap.md`
|
8. `/docs/console/airgap.md`
|
||||||
|
|
||||||
* Status badges, import wizard, staleness indicators.
|
* Status badges, import wizard, staleness indicators.
|
||||||
9. `/docs/cli/airgap.md`
|
9. `/docs/cli/airgap.md`
|
||||||
|
|
||||||
* Commands, examples, exit codes.
|
* Commands, examples, exit codes.
|
||||||
10. `/docs/security/trust-and-signing.md`
|
10. `/docs/security/trust-and-signing.md`
|
||||||
|
|
||||||
* Roots of trust, key rotation, DSSE, TUF model.
|
* Roots of trust, key rotation, DSSE, TUF model.
|
||||||
|
|
||||||
11. `/docs/dev/airgap-contracts.md`
|
11. `/docs/dev/airgap-contracts.md`
|
||||||
|
|
||||||
* EgressPolicy usage, testing patterns, sealed‑mode CI gates.
|
* EgressPolicy usage, testing patterns, sealed‑mode CI gates.
|
||||||
|
|
||||||
Add the banner at the top of each page:
|
Add the banner at the top of each page:
|
||||||
|
|
||||||
> **Imposed rule:** Work of this type or tasks of this type on this component must also be applied everywhere else it should be applied.
|
> **Imposed rule:** Work of this type or tasks of this type on this component must also be applied everywhere else it should be applied.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 7) Implementation plan
|
## 7) Implementation plan
|
||||||
|
|
||||||
### Phase 1 — Foundations
|
### Phase 1 — Foundations
|
||||||
|
|
||||||
* Add `airgap/controller` with sealed state and status API.
|
* Add `airgap/controller` with sealed state and status API.
|
||||||
* Integrate `EgressPolicy` facade in all outbound network call sites.
|
* Integrate `EgressPolicy` facade in all outbound network call sites.
|
||||||
* Provide default NetworkPolicy/iptables templates and Helm values to block egress.
|
* Provide default NetworkPolicy/iptables templates and Helm values to block egress.
|
||||||
* Console shows sealed badge and status.
|
* Console shows sealed badge and status.
|
||||||
|
|
||||||
### Phase 2 — Mirror Bundles
|
### Phase 2 — Mirror Bundles
|
||||||
|
|
||||||
* Implement `mirror/creator` in connected mode with content plug‑ins.
|
* Implement `mirror/creator` in connected mode with content plug‑ins.
|
||||||
* Implement `airgap/importer` with DSSE/TUF/Merkle verification and catalog updates.
|
* Implement `airgap/importer` with DSSE/TUF/Merkle verification and catalog updates.
|
||||||
* Export Center gains **Mirror bundle** build and verify commands (connected side).
|
* Export Center gains **Mirror bundle** build and verify commands (connected side).
|
||||||
|
|
||||||
### Phase 3 — Deterministic jobs
|
### Phase 3 — Deterministic jobs
|
||||||
|
|
||||||
* Add job plan validation in the Task Runner.
|
* Add job plan validation in the Task Runner.
|
||||||
* Restrict sources in sealed mode.
|
* Restrict sources in sealed mode.
|
||||||
* Conseiller/Excitator add “mirror source” adapters.
|
* Conseiller/Excitator add “mirror source” adapters.
|
||||||
|
|
||||||
### Phase 4 — Staleness and time
|
### Phase 4 — Staleness and time
|
||||||
|
|
||||||
* Parse time anchors; enforce staleness budgets; add UI indicators and task refusal when budgets exceeded.
|
* Parse time anchors; enforce staleness budgets; add UI indicators and task refusal when budgets exceeded.
|
||||||
* Notifications for expiring anchors.
|
* Notifications for expiring anchors.
|
||||||
|
|
||||||
### Phase 5 — Degradation matrix and UX
|
### Phase 5 — Degradation matrix and UX
|
||||||
|
|
||||||
* Wire feature flags and fallbacks in Console and APIs.
|
* Wire feature flags and fallbacks in Console and APIs.
|
||||||
* Improve error messages with remediation guidance.
|
* Improve error messages with remediation guidance.
|
||||||
|
|
||||||
### Phase 6 — Evidence portability
|
### Phase 6 — Evidence portability
|
||||||
|
|
||||||
* Portable evidence packages: export/import with full verification.
|
* Portable evidence packages: export/import with full verification.
|
||||||
* Document cross‑domain workflows.
|
* Document cross‑domain workflows.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 8) Engineering tasks
|
## 8) Engineering tasks
|
||||||
|
|
||||||
**Air‑gap controller and sealing**
|
**Air‑gap controller and sealing**
|
||||||
|
|
||||||
* [ ] Implement `airgap/controller` with persistent state and RBAC.
|
* [ ] Implement `airgap/controller` with persistent state and RBAC.
|
||||||
* [ ] Add `GET /system/airgap/status`, `POST /system/airgap/seal`.
|
* [ ] Add `GET /system/airgap/status`, `POST /system/airgap/seal`.
|
||||||
* [ ] Provide cluster egress templates for Kubernetes and for docker‑compose.
|
* [ ] Provide cluster egress templates for Kubernetes and for docker‑compose.
|
||||||
* [ ] Instrument startup checks to refuse running in sealed mode if egress rules aren’t applied.
|
* [ ] Instrument startup checks to refuse running in sealed mode if egress rules aren’t applied.
|
||||||
|
|
||||||
**EgressPolicy integration**
|
**EgressPolicy integration**
|
||||||
|
|
||||||
* [ ] Create `pkg/egress` facade and replace all direct HTTP client constructions in services.
|
* [ ] Create `pkg/egress` facade and replace all direct HTTP client constructions in services.
|
||||||
* [ ] Add linter rule and CI check forbidding raw `http.NewClient` in server code.
|
* [ ] Add linter rule and CI check forbidding raw `http.NewClient` in server code.
|
||||||
* [ ] Add unit tests for sealed and unsealed behavior.
|
* [ ] Add unit tests for sealed and unsealed behavior.
|
||||||
|
|
||||||
**Mirror bundles**
|
**Mirror bundles**
|
||||||
|
|
||||||
* [ ] Implement TUF/DSSE verifiers and Merkle root builder.
|
* [ ] Implement TUF/DSSE verifiers and Merkle root builder.
|
||||||
* [ ] Build content plug‑ins: advisories, VEX, policy packs, images.
|
* [ ] Build content plug‑ins: advisories, VEX, policy packs, images.
|
||||||
* [ ] Write `bundle_catalog` and `bundle_items` tables with RLS.
|
* [ ] Write `bundle_catalog` and `bundle_items` tables with RLS.
|
||||||
* [ ] CLI: `stella mirror create|verify`, `stella airgap import|verify`.
|
* [ ] CLI: `stella mirror create|verify`, `stella airgap import|verify`.
|
||||||
|
|
||||||
**Conseiller/Excitator**
|
**Conseiller/Excitator**
|
||||||
|
|
||||||
* [ ] Add mirror adapters for read‑only ingestion from bundle paths.
|
* [ ] Add mirror adapters for read‑only ingestion from bundle paths.
|
||||||
* [ ] Persist source digests and bundle IDs on each linked record.
|
* [ ] Persist source digests and bundle IDs on each linked record.
|
||||||
* [ ] Unit tests to ensure no merge behavior is introduced by bundle ingestion.
|
* [ ] Unit tests to ensure no merge behavior is introduced by bundle ingestion.
|
||||||
|
|
||||||
**Policy Engine & Studio**
|
**Policy Engine & Studio**
|
||||||
|
|
||||||
* [ ] Accept policy packs from bundles; track `policy_version` and `bundle_id`.
|
* [ ] Accept policy packs from bundles; track `policy_version` and `bundle_id`.
|
||||||
* [ ] Add degradation notices for rules requiring external reputation; provide cached fallbacks.
|
* [ ] Add degradation notices for rules requiring external reputation; provide cached fallbacks.
|
||||||
|
|
||||||
**Task Runner & Orchestrator**
|
**Task Runner & Orchestrator**
|
||||||
|
|
||||||
* [ ] Plan‑time validation against network calls; add `internal:` allow‑list mapping.
|
* [ ] Plan‑time validation against network calls; add `internal:` allow‑list mapping.
|
||||||
* [ ] Emit sealed‑mode violations to Timeline with remediation text.
|
* [ ] Emit sealed‑mode violations to Timeline with remediation text.
|
||||||
|
|
||||||
**Console**
|
**Console**
|
||||||
|
|
||||||
* [ ] Status panel: sealed badge, last import, staleness meters.
|
* [ ] Status panel: sealed badge, last import, staleness meters.
|
||||||
* [ ] Import wizard with verify results and catalog diff preview.
|
* [ ] Import wizard with verify results and catalog diff preview.
|
||||||
* [ ] Degradation matrix UI and contextual tooltips.
|
* [ ] Degradation matrix UI and contextual tooltips.
|
||||||
|
|
||||||
**Observability & Forensics**
|
**Observability & Forensics**
|
||||||
|
|
||||||
* [ ] Mark sealed mode in telemetry attributes.
|
* [ ] Mark sealed mode in telemetry attributes.
|
||||||
* [ ] Add portable evidence package export/import; verify on read.
|
* [ ] Add portable evidence package export/import; verify on read.
|
||||||
|
|
||||||
**Authority & Tenancy**
|
**Authority & Tenancy**
|
||||||
|
|
||||||
* [ ] New scopes: `airgap:seal`, `airgap:import`, `airgap:status:read`.
|
* [ ] New scopes: `airgap:seal`, `airgap:import`, `airgap:status:read`.
|
||||||
* [ ] Audit import actions with actor and trace ID.
|
* [ ] Audit import actions with actor and trace ID.
|
||||||
|
|
||||||
**Docs**
|
**Docs**
|
||||||
|
|
||||||
* [ ] Author all pages listed in section 6, include signed‑time workflow diagrams.
|
* [ ] Author all pages listed in section 6, include signed‑time workflow diagrams.
|
||||||
* [ ] Insert banner statement in each page.
|
* [ ] Insert banner statement in each page.
|
||||||
|
|
||||||
**Testing**
|
**Testing**
|
||||||
|
|
||||||
* [ ] Sealed‑mode e2e: attempt egress; ensure refusal and remediation.
|
* [ ] Sealed‑mode e2e: attempt egress; ensure refusal and remediation.
|
||||||
* [ ] Bundle import e2e: corrupt DSSE, wrong root, tampered artifact → rejected.
|
* [ ] Bundle import e2e: corrupt DSSE, wrong root, tampered artifact → rejected.
|
||||||
* [ ] Performance: large advisory bundle import within target time (see Acceptance).
|
* [ ] Performance: large advisory bundle import within target time (see Acceptance).
|
||||||
* [ ] Time drift scenarios and staleness budget enforcement.
|
* [ ] Time drift scenarios and staleness budget enforcement.
|
||||||
* [ ] Regression: ensure AOC rules unchanged in sealed mode.
|
* [ ] Regression: ensure AOC rules unchanged in sealed mode.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 9) Feature changes required in other components
|
## 9) Feature changes required in other components
|
||||||
|
|
||||||
* **Export Center:** add mirror bundle export profile, signed‑time token inclusion, and portable evidence packages.
|
* **Export Center:** add mirror bundle export profile, signed‑time token inclusion, and portable evidence packages.
|
||||||
* **Notifications:** remove external webhooks by default in sealed mode; add local SMTP/syslog sinks.
|
* **Notifications:** remove external webhooks by default in sealed mode; add local SMTP/syslog sinks.
|
||||||
* **CLI Parity:** ensure all admin and import operations are exposed; add sealed‑mode safety prompts.
|
* **CLI Parity:** ensure all admin and import operations are exposed; add sealed‑mode safety prompts.
|
||||||
* **Containerized Distribution:** ship **Bootstrap Pack** that includes all images and charts in a single oci‑archive set with index manifest.
|
* **Containerized Distribution:** ship **Bootstrap Pack** that includes all images and charts in a single oci‑archive set with index manifest.
|
||||||
* **Observability:** disable remote exporters; include local dashboards; mark sealed mode in UI.
|
* **Observability:** disable remote exporters; include local dashboards; mark sealed mode in UI.
|
||||||
* **Policy Studio:** enable offline authoring and export of policy sub‑bundles.
|
* **Policy Studio:** enable offline authoring and export of policy sub‑bundles.
|
||||||
* **VEX Consensus Lens:** ensure it operates solely on imported VEX statements; highlight coverage vs. stale.
|
* **VEX Consensus Lens:** ensure it operates solely on imported VEX statements; highlight coverage vs. stale.
|
||||||
|
|
||||||
> **Imposed rule reminder:** Work of this type or tasks of this type on this component must also be applied everywhere else it should be applied.
|
> **Imposed rule reminder:** Work of this type or tasks of this type on this component must also be applied everywhere else it should be applied.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 10) Acceptance criteria
|
## 10) Acceptance criteria
|
||||||
|
|
||||||
* Environment can be **sealed** and verified via API, CLI, and network policies.
|
* Environment can be **sealed** and verified via API, CLI, and network policies.
|
||||||
* Import of a valid Mirror Bundle succeeds; DSSE, TUF, and Merkle validations recorded in `import_audit`.
|
* Import of a valid Mirror Bundle succeeds; DSSE, TUF, and Merkle validations recorded in `import_audit`.
|
||||||
* Conseiller and Excitator operate only on imported sources; linkage reflects original source identities.
|
* Conseiller and Excitator operate only on imported sources; linkage reflects original source identities.
|
||||||
* Policy packs are importable and versioned; rules that depend on external evidence show clear degradation.
|
* Policy packs are importable and versioned; rules that depend on external evidence show clear degradation.
|
||||||
* Large bundle (e.g., 8–12 GB with images) imports in under 20 minutes on SSD storage and indexes advisories in under 5 minutes on a 4‑core node.
|
* Large bundle (e.g., 8–12 GB with images) imports in under 20 minutes on SSD storage and indexes advisories in under 5 minutes on a 4‑core node.
|
||||||
* Console displays sealed badge, last import, staleness, and degradation matrix.
|
* Console displays sealed badge, last import, staleness, and degradation matrix.
|
||||||
* Attempted egress in sealed mode fails with `AIRGAP_EGRESS_BLOCKED` and remediation.
|
* Attempted egress in sealed mode fails with `AIRGAP_EGRESS_BLOCKED` and remediation.
|
||||||
* Portable evidence packages export and verify across separate enclaves.
|
* Portable evidence packages export and verify across separate enclaves.
|
||||||
* All changes documented with the banner statement.
|
* All changes documented with the banner statement.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 11) Risks and mitigations
|
## 11) Risks and mitigations
|
||||||
|
|
||||||
* **Key management complexity:** rotate TUF roots with dual‑control workflow and explicit docs; fail‑safe to previous root if rotation bundle absent.
|
* **Key management complexity:** rotate TUF roots with dual‑control workflow and explicit docs; fail‑safe to previous root if rotation bundle absent.
|
||||||
* **Staleness risk:** enforce budgets and block risk‑critical jobs when expired; provide monitoring and notifications for impending staleness.
|
* **Staleness risk:** enforce budgets and block risk‑critical jobs when expired; provide monitoring and notifications for impending staleness.
|
||||||
* **Operator error during import:** dry‑run verification, diff preview of catalog changes, and ability to roll back via content address.
|
* **Operator error during import:** dry‑run verification, diff preview of catalog changes, and ability to roll back via content address.
|
||||||
* **Hidden egress paths:** CI lints and runtime guardrails; network policies enforced at cluster layer.
|
* **Hidden egress paths:** CI lints and runtime guardrails; network policies enforced at cluster layer.
|
||||||
* **Bundle size bloat:** Zstandard compression, delta bundles, and selective content flags for creation.
|
* **Bundle size bloat:** Zstandard compression, delta bundles, and selective content flags for creation.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 12) Philosophy
|
## 12) Philosophy
|
||||||
|
|
||||||
* **Predictable over perfect:** deterministic, explainable results beat unknown “live” results in sensitive networks.
|
* **Predictable over perfect:** deterministic, explainable results beat unknown “live” results in sensitive networks.
|
||||||
* **Trust is earned:** every offline exchange is signed, verifiable, and auditable.
|
* **Trust is earned:** every offline exchange is signed, verifiable, and auditable.
|
||||||
* **Degrade transparently:** when features reduce capability, explain it and guide remediation.
|
* **Degrade transparently:** when features reduce capability, explain it and guide remediation.
|
||||||
|
|
||||||
> **Imposed rule:** Work of this type or tasks of this type on this component must also be applied everywhere else it should be applied.
|
> **Imposed rule:** Work of this type or tasks of this type on this component must also be applied everywhere else it should be applied.
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
# Aggregation-Only Contract (AOC) Guardrails
|
# Aggregation-Only Contract (AOC) Guardrails
|
||||||
|
|
||||||
The Aggregation-Only Contract keeps ingestion services deterministic and policy-neutral. Use these checkpoints whenever you add or modify backlog items:
|
The Aggregation-Only Contract keeps ingestion services deterministic and policy-neutral. Use these checkpoints whenever you add or modify backlog items:
|
||||||
|
|
||||||
1. **Ingestion writes raw facts only.** Concelier and Excititor append immutable observations/linksets. No precedence, severity, suppression, or "safe fix" hints may be computed at ingest time.
|
1. **Ingestion writes raw facts only.** Concelier and Excititor append immutable observations/linksets. No precedence, severity, suppression, or "safe fix" hints may be computed at ingest time.
|
||||||
2. **Derived semantics live elsewhere.** Policy Engine overlays, Vuln Explorer composition, and downstream reporting layers attach severity, precedence, policy verdicts, and UI hints.
|
2. **Derived semantics live elsewhere.** Policy Engine overlays, Vuln Explorer composition, and downstream reporting layers attach severity, precedence, policy verdicts, and UI hints.
|
||||||
3. **Provenance is mandatory.** Every ingestion write must include original source metadata, digests, and signing/provenance evidence when available. Reject writes lacking provenance.
|
3. **Provenance is mandatory.** Every ingestion write must include original source metadata, digests, and signing/provenance evidence when available. Reject writes lacking provenance.
|
||||||
4. **Deterministic outputs.** Given the same inputs, ingestion must produce identical documents, hashes, and event payloads across reruns.
|
4. **Deterministic outputs.** Given the same inputs, ingestion must produce identical documents, hashes, and event payloads across reruns.
|
||||||
5. **Guardrails everywhere.** Roslyn analyzers, schema validators, and CI smoke tests should fail builds that attempt forbidden writes.
|
5. **Guardrails everywhere.** Roslyn analyzers, schema validators, and CI smoke tests should fail builds that attempt forbidden writes.
|
||||||
|
|
||||||
For detailed roles and ownership boundaries, see `AGENTS.md` at the repo root and the module-specific `ARCHITECTURE_*.md` dossiers.
|
For detailed roles and ownership boundaries, see `AGENTS.md` at the repo root and the module-specific `ARCHITECTURE_*.md` dossiers.
|
||||||
|
|
||||||
Need the full contract? Read the [Aggregation-Only Contract reference](../ingestion/aggregation-only-contract.md) for schemas, error codes, and migration guidance.
|
Need the full contract? Read the [Aggregation-Only Contract reference](../ingestion/aggregation-only-contract.md) for schemas, error codes, and migration guidance.
|
||||||
|
|||||||
@@ -41,9 +41,9 @@ Net result: partners and internal teams integrate quickly without reverse‑engi
|
|||||||
|
|
||||||
### 3.1 Source of truth and layout
|
### 3.1 Source of truth and layout
|
||||||
|
|
||||||
* Each service owns a **module-scoped OAS** file: `src/StellaOps.Api.OpenApi/<service>/openapi.yaml`.
|
* Each service owns a **module-scoped OAS** file: `src/Api/StellaOps.Api.OpenApi/<service>/openapi.yaml`.
|
||||||
* Authority authentication/token surface now lives at `src/StellaOps.Api.OpenApi/authority/openapi.yaml`, covering `/token`, `/introspect`, `/revoke`, and `/jwks` flows with examples and scope catalog metadata.
|
* Authority authentication/token surface now lives at `src/Api/StellaOps.Api.OpenApi/authority/openapi.yaml`, covering `/token`, `/introspect`, `/revoke`, and `/jwks` flows with examples and scope catalog metadata.
|
||||||
* An aggregate spec `src/StellaOps.Api.OpenApi/stella.yaml` is produced by build tooling that composes per-service specs, resolves `$ref`s, and validates cross-service schemas.
|
* An aggregate spec `src/Api/StellaOps.Api.OpenApi/stella.yaml` is produced by build tooling that composes per-service specs, resolves `$ref`s, and validates cross-service schemas.
|
||||||
* JSON Schema dialect: 2020‑12 (OpenAPI 3.1). No vendor‑specific features for core models.
|
* JSON Schema dialect: 2020‑12 (OpenAPI 3.1). No vendor‑specific features for core models.
|
||||||
* Every response and error has at least one **validated example**.
|
* Every response and error has at least one **validated example**.
|
||||||
|
|
||||||
@@ -138,13 +138,13 @@ Net result: partners and internal teams integrate quickly without reverse‑engi
|
|||||||
|
|
||||||
### 4.1 New modules
|
### 4.1 New modules
|
||||||
|
|
||||||
* `src/StellaOps.Api.OpenApi/*` per service and aggregate composer
|
* `src/Api/StellaOps.Api.OpenApi/*` per service and aggregate composer
|
||||||
* `src/StellaOps.Api.Governance` OAS linter rules and compatibility checker
|
* `src/Api/StellaOps.Api.Governance` OAS linter rules and compatibility checker
|
||||||
* `src/StellaOps.Sdk.Generator` codegen drivers, post‑processing templates, smoke tests
|
* `src/Sdk/StellaOps.Sdk.Generator` codegen drivers, post‑processing templates, smoke tests
|
||||||
* `src/StellaOps.Sdk.Release` packaging, signing, publishing
|
* `src/Sdk/StellaOps.Sdk.Release` packaging, signing, publishing
|
||||||
* `src/StellaOps.DevPortal.Site` static generator and assets
|
* `src/DevPortal/StellaOps.DevPortal.Site` static generator and assets
|
||||||
* `test/contract` mock server config, golden examples
|
* `test/contract` mock server config, golden examples
|
||||||
* `src/StellaOps.ExportCenter.DevPortalOffline` bundler
|
* `src/ExportCenter/StellaOps.ExportCenter.DevPortalOffline` bundler
|
||||||
|
|
||||||
### 4.2 Build flow
|
### 4.2 Build flow
|
||||||
|
|
||||||
@@ -254,7 +254,7 @@ Add the banner at the top of each page:
|
|||||||
|
|
||||||
**OAS & governance**
|
**OAS & governance**
|
||||||
|
|
||||||
* [ ] Create `src/StellaOps.Api.OpenApi/<service>/openapi.yaml` for all services with minimal paths and shared components.
|
* [ ] Create `src/Api/StellaOps.Api.OpenApi/<service>/openapi.yaml` for all services with minimal paths and shared components.
|
||||||
* [ ] Implement aggregate composer and `$ref` resolver.
|
* [ ] Implement aggregate composer and `$ref` resolver.
|
||||||
* [ ] Add CI job: lint, validate, compatibility diff; block merges on failure.
|
* [ ] Add CI job: lint, validate, compatibility diff; block merges on failure.
|
||||||
* [ ] Migrate all endpoints to standard error envelope and provide examples.
|
* [ ] Migrate all endpoints to standard error envelope and provide examples.
|
||||||
|
|||||||
@@ -230,7 +230,7 @@ Slim wrapper used by CLI; returns 204 on success or `ERR_POL_001` payload.
|
|||||||
|
|
||||||
## 6 · Run & Simulation APIs
|
## 6 · Run & Simulation APIs
|
||||||
|
|
||||||
> Schema reference: canonical policy run request/status/diff payloads ship with the Scheduler Models guide (`src/StellaOps.Scheduler.Models/docs/SCHED-MODELS-20-001-POLICY-RUNS.md`) and JSON fixtures under `samples/api/scheduler/policy-*.json`.
|
> Schema reference: canonical policy run request/status/diff payloads ship with the Scheduler Models guide (`src/Scheduler/__Libraries/StellaOps.Scheduler.Models/docs/SCHED-MODELS-20-001-POLICY-RUNS.md`) and JSON fixtures under `samples/api/scheduler/policy-*.json`.
|
||||||
|
|
||||||
### 6.1 Trigger Run
|
### 6.1 Trigger Run
|
||||||
|
|
||||||
@@ -389,7 +389,7 @@ Returns rule hit sequence:
|
|||||||
|
|
||||||
## 9 · Compliance Checklist
|
## 9 · Compliance Checklist
|
||||||
|
|
||||||
- [ ] **Scopes enforced:** Endpoint access requires correct Authority scope mapping (see `/src/StellaOps.Authority/TASKS.md`).
|
- [ ] **Scopes enforced:** Endpoint access requires correct Authority scope mapping (see `/src/Authority/StellaOps.Authority/TASKS.md`).
|
||||||
- [ ] **Schemas current:** JSON examples align with Scheduler Models (`SCHED-MODELS-20-001`) and Policy Engine DTOs; update when contracts change.
|
- [ ] **Schemas current:** JSON examples align with Scheduler Models (`SCHED-MODELS-20-001`) and Policy Engine DTOs; update when contracts change.
|
||||||
- [ ] **Error codes mapped:** `ERR_POL_*` table reflects implementation and CI tests cover edge cases.
|
- [ ] **Error codes mapped:** `ERR_POL_*` table reflects implementation and CI tests cover edge cases.
|
||||||
- [ ] **Pagination documented:** List endpoints specify page/size and cursor semantics; responses include `X-Total-Count` or `nextCursor`.
|
- [ ] **Pagination documented:** List endpoints specify page/size and cursor semantics; responses include `X-Total-Count` or `nextCursor`.
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ Non-goals: authoring ingestion logic, mutating Policy overlays, exposing interna
|
|||||||
|
|
||||||
## 2 · Workspace & Packages
|
## 2 · Workspace & Packages
|
||||||
|
|
||||||
The console is implemented in `src/StellaOps.Web`, an Angular 17 workspace built on standalone components and Signals.
|
The console is implemented in `src/Web/StellaOps.Web`, an Angular 17 workspace built on standalone components and Signals.
|
||||||
|
|
||||||
| Path | Purpose | Highlights |
|
| Path | Purpose | Highlights |
|
||||||
|------|---------|------------|
|
|------|---------|------------|
|
||||||
@@ -148,7 +148,7 @@ Optimisation levers:
|
|||||||
## 6 · Offline & Configuration Workflows
|
## 6 · Offline & Configuration Workflows
|
||||||
|
|
||||||
- **Config manifest:** `/config.json` includes Authority issuer/client ID, gateway base URL, feature flags, telemetry endpoints, and offline hints. Operators can swap config by copying `src/config/config.sample.json` and editing before build, or by rewriting the response at gateway runtime.
|
- **Config manifest:** `/config.json` includes Authority issuer/client ID, gateway base URL, feature flags, telemetry endpoints, and offline hints. Operators can swap config by copying `src/config/config.sample.json` and editing before build, or by rewriting the response at gateway runtime.
|
||||||
- **Deterministic install:** Documented in `src/StellaOps.Web/docs/DeterministicInstall.md`—`npm run ci:install` plus Chromium provisioning ensures offline runners reproduce builds.
|
- **Deterministic install:** Documented in `src/Web/StellaOps.Web/docs/DeterministicInstall.md`—`npm run ci:install` plus Chromium provisioning ensures offline runners reproduce builds.
|
||||||
- **Offline Kit parity:** UI validates downloads manifest signatures (cosign) and surfaces snapshot timestamps per tenant. When offline, buttons switch to CLI snippets (`stella runs export`, `stella downloads sync`).
|
- **Offline Kit parity:** UI validates downloads manifest signatures (cosign) and surfaces snapshot timestamps per tenant. When offline, buttons switch to CLI snippets (`stella runs export`, `stella downloads sync`).
|
||||||
- **Feature flags:** `CONSOLE_FEATURE_FLAGS` toggles modules (`runs`, `downloads`, `telemetry`); offline bundles include flag manifest so UI can render only supported panes.
|
- **Feature flags:** `CONSOLE_FEATURE_FLAGS` toggles modules (`runs`, `downloads`, `telemetry`); offline bundles include flag manifest so UI can render only supported panes.
|
||||||
- **Snapshot awareness:** Global banner shows snapshot timestamp and disables actions needing Authority fresh-auth when running in sealed mode.
|
- **Snapshot awareness:** Global banner shows snapshot timestamp and disables actions needing Authority fresh-auth when running in sealed mode.
|
||||||
|
|||||||
@@ -1,168 +1,168 @@
|
|||||||
# StellaOps Architecture Overview (Sprint 19)
|
# StellaOps Architecture Overview (Sprint 19)
|
||||||
|
|
||||||
> **Ownership:** Architecture Guild • Docs Guild
|
> **Ownership:** Architecture Guild • Docs Guild
|
||||||
> **Audience:** Service owners, platform engineers, solution architects
|
> **Audience:** Service owners, platform engineers, solution architects
|
||||||
> **Related:** [High-Level Architecture](../07_HIGH_LEVEL_ARCHITECTURE.md), [Concelier Architecture](../ARCHITECTURE_CONCELIER.md), [Policy Engine Architecture](policy-engine.md), [Aggregation-Only Contract](../ingestion/aggregation-only-contract.md)
|
> **Related:** [High-Level Architecture](../07_HIGH_LEVEL_ARCHITECTURE.md), [Concelier Architecture](../ARCHITECTURE_CONCELIER.md), [Policy Engine Architecture](policy-engine.md), [Aggregation-Only Contract](../ingestion/aggregation-only-contract.md)
|
||||||
|
|
||||||
This dossier summarises the end-to-end runtime topology after the Aggregation-Only Contract (AOC) rollout. It highlights where raw facts live, how ingest services enforce guardrails, and how downstream components consume those facts to derive policy decisions and user-facing experiences.
|
This dossier summarises the end-to-end runtime topology after the Aggregation-Only Contract (AOC) rollout. It highlights where raw facts live, how ingest services enforce guardrails, and how downstream components consume those facts to derive policy decisions and user-facing experiences.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 1 · System landscape
|
## 1 · System landscape
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
graph TD
|
graph TD
|
||||||
subgraph Edge["Clients & Automation"]
|
subgraph Edge["Clients & Automation"]
|
||||||
CLI[stella CLI]
|
CLI[stella CLI]
|
||||||
UI[Console SPA]
|
UI[Console SPA]
|
||||||
APIClients[CI / API Clients]
|
APIClients[CI / API Clients]
|
||||||
end
|
end
|
||||||
Gateway[API Gateway<br/>(JWT + DPoP scopes)]
|
Gateway[API Gateway<br/>(JWT + DPoP scopes)]
|
||||||
subgraph Scanner["Fact Collection"]
|
subgraph Scanner["Fact Collection"]
|
||||||
ScannerWeb[Scanner.WebService]
|
ScannerWeb[Scanner.WebService]
|
||||||
ScannerWorkers[Scanner.Workers]
|
ScannerWorkers[Scanner.Workers]
|
||||||
Agent[Agent Runtime]
|
Agent[Agent Runtime]
|
||||||
end
|
end
|
||||||
subgraph Ingestion["Aggregation-Only Ingestion (AOC)"]
|
subgraph Ingestion["Aggregation-Only Ingestion (AOC)"]
|
||||||
Concelier[Concelier.WebService]
|
Concelier[Concelier.WebService]
|
||||||
Excititor[Excititor.WebService]
|
Excititor[Excititor.WebService]
|
||||||
RawStore[(MongoDB<br/>advisory_raw / vex_raw)]
|
RawStore[(MongoDB<br/>advisory_raw / vex_raw)]
|
||||||
end
|
end
|
||||||
subgraph Derivation["Policy & Overlay"]
|
subgraph Derivation["Policy & Overlay"]
|
||||||
Policy[Policy Engine]
|
Policy[Policy Engine]
|
||||||
Scheduler[Scheduler Services]
|
Scheduler[Scheduler Services]
|
||||||
Notify[Notifier]
|
Notify[Notifier]
|
||||||
end
|
end
|
||||||
subgraph Experience["UX & Export"]
|
subgraph Experience["UX & Export"]
|
||||||
UIService[Console Backend]
|
UIService[Console Backend]
|
||||||
Exporters[Export / Offline Kit]
|
Exporters[Export / Offline Kit]
|
||||||
end
|
end
|
||||||
Observability[Telemetry Stack]
|
Observability[Telemetry Stack]
|
||||||
|
|
||||||
CLI --> Gateway
|
CLI --> Gateway
|
||||||
UI --> Gateway
|
UI --> Gateway
|
||||||
APIClients --> Gateway
|
APIClients --> Gateway
|
||||||
Gateway --> ScannerWeb
|
Gateway --> ScannerWeb
|
||||||
ScannerWeb --> ScannerWorkers
|
ScannerWeb --> ScannerWorkers
|
||||||
ScannerWorkers --> Concelier
|
ScannerWorkers --> Concelier
|
||||||
ScannerWorkers --> Excititor
|
ScannerWorkers --> Excititor
|
||||||
Concelier --> RawStore
|
Concelier --> RawStore
|
||||||
Excititor --> RawStore
|
Excititor --> RawStore
|
||||||
RawStore --> Policy
|
RawStore --> Policy
|
||||||
Policy --> Scheduler
|
Policy --> Scheduler
|
||||||
Policy --> Notify
|
Policy --> Notify
|
||||||
Policy --> UIService
|
Policy --> UIService
|
||||||
Scheduler --> UIService
|
Scheduler --> UIService
|
||||||
UIService --> Exporters
|
UIService --> Exporters
|
||||||
Exporters --> CLI
|
Exporters --> CLI
|
||||||
Exporters --> Offline[Offline Kit]
|
Exporters --> Offline[Offline Kit]
|
||||||
Observability -.-> ScannerWeb
|
Observability -.-> ScannerWeb
|
||||||
Observability -.-> Concelier
|
Observability -.-> Concelier
|
||||||
Observability -.-> Excititor
|
Observability -.-> Excititor
|
||||||
Observability -.-> Policy
|
Observability -.-> Policy
|
||||||
Observability -.-> Scheduler
|
Observability -.-> Scheduler
|
||||||
Observability -.-> Notify
|
Observability -.-> Notify
|
||||||
```
|
```
|
||||||
|
|
||||||
Key boundaries:
|
Key boundaries:
|
||||||
|
|
||||||
- **AOC border.** Everything inside the Ingestion subgraph writes only immutable raw facts plus link hints. Derived severity, consensus, and risk remain outside the border.
|
- **AOC border.** Everything inside the Ingestion subgraph writes only immutable raw facts plus link hints. Derived severity, consensus, and risk remain outside the border.
|
||||||
- **Policy-only derivation.** Policy Engine materialises `effective_finding_*` collections and emits overlays; other services consume but never mutate them.
|
- **Policy-only derivation.** Policy Engine materialises `effective_finding_*` collections and emits overlays; other services consume but never mutate them.
|
||||||
- **Tenant enforcement.** Authority-issued DPoP scopes flow through Gateway to every service; raw stores and overlays include `tenant` strictly.
|
- **Tenant enforcement.** Authority-issued DPoP scopes flow through Gateway to every service; raw stores and overlays include `tenant` strictly.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 2 · Aggregation-Only Contract focus
|
## 2 · Aggregation-Only Contract focus
|
||||||
|
|
||||||
### 2.1 Responsibilities at the boundary
|
### 2.1 Responsibilities at the boundary
|
||||||
|
|
||||||
| Area | Services | Responsibilities under AOC | Forbidden under AOC |
|
| Area | Services | Responsibilities under AOC | Forbidden under AOC |
|
||||||
|------|----------|-----------------------------|---------------------|
|
|------|----------|-----------------------------|---------------------|
|
||||||
| **Ingestion (Concelier / Excititor)** | `StellaOps.Concelier.WebService`, `StellaOps.Excititor.WebService` | Fetch upstream advisories/VEX, verify signatures, compute linksets, append immutable documents to `advisory_raw` / `vex_raw`, emit observability signals, expose raw read APIs. | Computing severity, consensus, suppressions, or policy hints; merging upstream sources into a single derived record; mutating existing documents. |
|
| **Ingestion (Concelier / Excititor)** | `StellaOps.Concelier.WebService`, `StellaOps.Excititor.WebService` | Fetch upstream advisories/VEX, verify signatures, compute linksets, append immutable documents to `advisory_raw` / `vex_raw`, emit observability signals, expose raw read APIs. | Computing severity, consensus, suppressions, or policy hints; merging upstream sources into a single derived record; mutating existing documents. |
|
||||||
| **Policy & Overlay** | `StellaOps.Policy.Engine`, Scheduler | Join SBOM inventory with raw advisories/VEX, evaluate policies, issue `effective_finding_*` overlays, drive remediation workflows. | Writing to raw collections; bypassing guard scopes; running without recorded provenance. |
|
| **Policy & Overlay** | `StellaOps.Policy.Engine`, Scheduler | Join SBOM inventory with raw advisories/VEX, evaluate policies, issue `effective_finding_*` overlays, drive remediation workflows. | Writing to raw collections; bypassing guard scopes; running without recorded provenance. |
|
||||||
| **Experience layers** | Console, CLI, Exporters | Surface raw facts + policy overlays; run `stella aoc verify`; render AOC dashboards and reports. | Accepting ingestion payloads that lack provenance or violate guard results. |
|
| **Experience layers** | Console, CLI, Exporters | Surface raw facts + policy overlays; run `stella aoc verify`; render AOC dashboards and reports. | Accepting ingestion payloads that lack provenance or violate guard results. |
|
||||||
|
|
||||||
### 2.2 Raw stores
|
### 2.2 Raw stores
|
||||||
|
|
||||||
| Collection | Purpose | Key fields | Notes |
|
| Collection | Purpose | Key fields | Notes |
|
||||||
|------------|---------|------------|-------|
|
|------------|---------|------------|-------|
|
||||||
| `advisory_raw` | Immutable vendor/ecosystem advisory documents. | `_id`, `tenant`, `source.*`, `upstream.*`, `content.raw`, `linkset`, `supersedes`. | Idempotent by `(source.vendor, upstream.upstream_id, upstream.content_hash)`. |
|
| `advisory_raw` | Immutable vendor/ecosystem advisory documents. | `_id`, `tenant`, `source.*`, `upstream.*`, `content.raw`, `linkset`, `supersedes`. | Idempotent by `(source.vendor, upstream.upstream_id, upstream.content_hash)`. |
|
||||||
| `vex_raw` | Immutable vendor VEX statements. | Mirrors `advisory_raw`; `identifiers.statements` summarises affected components. | Maintains supersedes chain identical to advisory flow. |
|
| `vex_raw` | Immutable vendor VEX statements. | Mirrors `advisory_raw`; `identifiers.statements` summarises affected components. | Maintains supersedes chain identical to advisory flow. |
|
||||||
| Change streams (`advisory_raw_stream`, `vex_raw_stream`) | Feed Policy Engine and Scheduler. | `operationType`, `documentKey`, `fullDocument`, `tenant`, `traceId`. | Scope filtered per tenant before delivery. |
|
| Change streams (`advisory_raw_stream`, `vex_raw_stream`) | Feed Policy Engine and Scheduler. | `operationType`, `documentKey`, `fullDocument`, `tenant`, `traceId`. | Scope filtered per tenant before delivery. |
|
||||||
|
|
||||||
### 2.3 Guarded ingestion sequence
|
### 2.3 Guarded ingestion sequence
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
sequenceDiagram
|
sequenceDiagram
|
||||||
participant Upstream as Upstream Source
|
participant Upstream as Upstream Source
|
||||||
participant Connector as Concelier/Excititor Connector
|
participant Connector as Concelier/Excititor Connector
|
||||||
participant Guard as AOCWriteGuard
|
participant Guard as AOCWriteGuard
|
||||||
participant Mongo as MongoDB (advisory_raw / vex_raw)
|
participant Mongo as MongoDB (advisory_raw / vex_raw)
|
||||||
participant Stream as Change Stream
|
participant Stream as Change Stream
|
||||||
participant Policy as Policy Engine
|
participant Policy as Policy Engine
|
||||||
|
|
||||||
Upstream-->>Connector: CSAF / OSV / VEX document
|
Upstream-->>Connector: CSAF / OSV / VEX document
|
||||||
Connector->>Connector: Normalize transport, compute content_hash
|
Connector->>Connector: Normalize transport, compute content_hash
|
||||||
Connector->>Guard: Candidate raw doc (source + upstream + content + linkset)
|
Connector->>Guard: Candidate raw doc (source + upstream + content + linkset)
|
||||||
Guard-->>Connector: ERR_AOC_00x on violation
|
Guard-->>Connector: ERR_AOC_00x on violation
|
||||||
Guard->>Mongo: Append immutable document (with tenant & supersedes)
|
Guard->>Mongo: Append immutable document (with tenant & supersedes)
|
||||||
Mongo-->>Stream: Change event (tenant scoped)
|
Mongo-->>Stream: Change event (tenant scoped)
|
||||||
Stream->>Policy: Raw delta payload
|
Stream->>Policy: Raw delta payload
|
||||||
Policy->>Policy: Evaluate policies, compute effective findings
|
Policy->>Policy: Evaluate policies, compute effective findings
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### 2.4 Authority scopes & tenancy
|
### 2.4 Authority scopes & tenancy
|
||||||
|
|
||||||
| Scope | Holder | Purpose | Notes |
|
| Scope | Holder | Purpose | Notes |
|
||||||
|-------|--------|---------|-------|
|
|-------|--------|---------|-------|
|
||||||
| `advisory:ingest` / `vex:ingest` | Concelier / Excititor collectors | Append raw documents through ingestion endpoints. | Paired with tenant claims; requests without tenant are rejected. |
|
| `advisory:ingest` / `vex:ingest` | Concelier / Excititor collectors | Append raw documents through ingestion endpoints. | Paired with tenant claims; requests without tenant are rejected. |
|
||||||
| `advisory:read` / `vex:read` | DevOps verify identity, CLI | Run `stella aoc verify` or call `/aoc/verify`. | Read-only; cannot mutate raw docs. |
|
| `advisory:read` / `vex:read` | DevOps verify identity, CLI | Run `stella aoc verify` or call `/aoc/verify`. | Read-only; cannot mutate raw docs. |
|
||||||
| `effective:write` | Policy Engine | Materialise `effective_finding_*` overlays. | Only Policy Engine identity may hold; ingestion contexts receive `ERR_AOC_006` if they attempt. |
|
| `effective:write` | Policy Engine | Materialise `effective_finding_*` overlays. | Only Policy Engine identity may hold; ingestion contexts receive `ERR_AOC_006` if they attempt. |
|
||||||
| `findings:read` | Console, CLI, exports | Consume derived findings. | Enforced by Gateway and downstream services. |
|
| `findings:read` | Console, CLI, exports | Consume derived findings. | Enforced by Gateway and downstream services. |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 3 · Data & control flow highlights
|
## 3 · Data & control flow highlights
|
||||||
|
|
||||||
1. **Ingestion:** Concelier / Excititor connectors fetch upstream documents, compute linksets, and hand payloads to `AOCWriteGuard`. Guards validate schema, provenance, forbidden fields, supersedes pointers, and append-only rules before writing to Mongo.
|
1. **Ingestion:** Concelier / Excititor connectors fetch upstream documents, compute linksets, and hand payloads to `AOCWriteGuard`. Guards validate schema, provenance, forbidden fields, supersedes pointers, and append-only rules before writing to Mongo.
|
||||||
2. **Verification:** `stella aoc verify` (CLI/CI) and `/aoc/verify` endpoints replay guard checks against stored documents, mapping `ERR_AOC_00x` codes to exit codes for automation.
|
2. **Verification:** `stella aoc verify` (CLI/CI) and `/aoc/verify` endpoints replay guard checks against stored documents, mapping `ERR_AOC_00x` codes to exit codes for automation.
|
||||||
3. **Policy evaluation:** Mongo change streams deliver tenant-scoped raw deltas. Policy Engine joins SBOM inventory (via BOM Index), executes deterministic policies, writes overlays, and emits events to Scheduler/Notify.
|
3. **Policy evaluation:** Mongo change streams deliver tenant-scoped raw deltas. Policy Engine joins SBOM inventory (via BOM Index), executes deterministic policies, writes overlays, and emits events to Scheduler/Notify.
|
||||||
4. **Experience surfaces:** Console renders an AOC dashboard showing ingestion latency, guard violations, and supersedes depth. CLI exposes raw-document fetch helpers for auditing. Offline Kit bundles raw collections alongside guard configs to keep air-gapped installs verifiable.
|
4. **Experience surfaces:** Console renders an AOC dashboard showing ingestion latency, guard violations, and supersedes depth. CLI exposes raw-document fetch helpers for auditing. Offline Kit bundles raw collections alongside guard configs to keep air-gapped installs verifiable.
|
||||||
5. **Observability:** All services emit `ingestion_write_total`, `aoc_violation_total{code}`, `ingestion_latency_seconds`, and trace spans `ingest.fetch`, `ingest.transform`, `ingest.write`, `aoc.guard`. Logs correlate via `traceId`, `tenant`, `source.vendor`, and `content_hash`.
|
5. **Observability:** All services emit `ingestion_write_total`, `aoc_violation_total{code}`, `ingestion_latency_seconds`, and trace spans `ingest.fetch`, `ingest.transform`, `ingest.write`, `aoc.guard`. Logs correlate via `traceId`, `tenant`, `source.vendor`, and `content_hash`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 4 · Offline & disaster readiness
|
## 4 · Offline & disaster readiness
|
||||||
|
|
||||||
- **Offline Kit:** Packages raw Mongo snapshots (`advisory_raw`, `vex_raw`) plus guard configuration and CLI verifier binaries so air-gapped sites can re-run AOC checks before promotion.
|
- **Offline Kit:** Packages raw Mongo snapshots (`advisory_raw`, `vex_raw`) plus guard configuration and CLI verifier binaries so air-gapped sites can re-run AOC checks before promotion.
|
||||||
- **Recovery:** Supersedes chains allow rollback to prior revisions without mutating documents. Disaster exercises must rehearse restoring from snapshot, replaying change streams into Policy Engine, and re-validating guard compliance.
|
- **Recovery:** Supersedes chains allow rollback to prior revisions without mutating documents. Disaster exercises must rehearse restoring from snapshot, replaying change streams into Policy Engine, and re-validating guard compliance.
|
||||||
- **Migration:** Legacy normalised fields are moved to temporary views during cutover; ingestion runtime removes writes once guard-enforced path is live (see [Migration playbook](../ingestion/aggregation-only-contract.md#8-migration-playbook)).
|
- **Migration:** Legacy normalised fields are moved to temporary views during cutover; ingestion runtime removes writes once guard-enforced path is live (see [Migration playbook](../ingestion/aggregation-only-contract.md#8-migration-playbook)).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 5 · References
|
## 5 · References
|
||||||
|
|
||||||
- [Aggregation-Only Contract reference](../ingestion/aggregation-only-contract.md)
|
- [Aggregation-Only Contract reference](../ingestion/aggregation-only-contract.md)
|
||||||
- [Concelier architecture](../ARCHITECTURE_CONCELIER.md)
|
- [Concelier architecture](../ARCHITECTURE_CONCELIER.md)
|
||||||
- [Excititor architecture](../ARCHITECTURE_EXCITITOR.md)
|
- [Excititor architecture](../ARCHITECTURE_EXCITITOR.md)
|
||||||
- [Policy Engine architecture](policy-engine.md)
|
- [Policy Engine architecture](policy-engine.md)
|
||||||
- [Authority service](../ARCHITECTURE_AUTHORITY.md)
|
- [Authority service](../ARCHITECTURE_AUTHORITY.md)
|
||||||
- [Observability standards (upcoming)](../observability/policy.md) – interim reference for telemetry naming.
|
- [Observability standards (upcoming)](../observability/policy.md) – interim reference for telemetry naming.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 6 · Compliance checklist
|
## 6 · Compliance checklist
|
||||||
|
|
||||||
- [ ] AOC guard enabled for all Concelier and Excititor write paths in production.
|
- [ ] AOC guard enabled for all Concelier and Excititor write paths in production.
|
||||||
- [ ] Mongo schema validators deployed for `advisory_raw` and `vex_raw`; change streams scoped per tenant.
|
- [ ] Mongo schema validators deployed for `advisory_raw` and `vex_raw`; change streams scoped per tenant.
|
||||||
- [ ] Authority scopes (`advisory:*`, `vex:*`, `effective:*`) configured in Gateway and validated via integration tests.
|
- [ ] Authority scopes (`advisory:*`, `vex:*`, `effective:*`) configured in Gateway and validated via integration tests.
|
||||||
- [ ] `stella aoc verify` wired into CI/CD pipelines with seeded violation fixtures.
|
- [ ] `stella aoc verify` wired into CI/CD pipelines with seeded violation fixtures.
|
||||||
- [ ] Console AOC dashboard and CLI documentation reference the new ingestion contract.
|
- [ ] Console AOC dashboard and CLI documentation reference the new ingestion contract.
|
||||||
- [ ] Offline Kit bundles include guard configs, verifier tooling, and documentation updates.
|
- [ ] Offline Kit bundles include guard configs, verifier tooling, and documentation updates.
|
||||||
- [ ] Observability dashboards include violation, latency, and supersedes depth metrics with alert thresholds.
|
- [ ] Observability dashboards include violation, latency, and supersedes depth metrics with alert thresholds.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
*Last updated: 2025-10-26 (Sprint 19).*
|
*Last updated: 2025-10-26 (Sprint 19).*
|
||||||
|
|||||||
@@ -1,243 +1,243 @@
|
|||||||
# Policy Engine Architecture (v2)
|
# Policy Engine Architecture (v2)
|
||||||
|
|
||||||
> **Ownership:** Policy Guild • Platform Guild
|
> **Ownership:** Policy Guild • Platform Guild
|
||||||
> **Services:** `StellaOps.Policy.Engine` (Minimal API + worker host)
|
> **Services:** `StellaOps.Policy.Engine` (Minimal API + worker host)
|
||||||
> **Data Stores:** MongoDB (`policies`, `policy_runs`, `effective_finding_*`), Object storage (explain bundles), optional NATS/Mongo queue
|
> **Data Stores:** MongoDB (`policies`, `policy_runs`, `effective_finding_*`), Object storage (explain bundles), optional NATS/Mongo queue
|
||||||
> **Related docs:** [Policy overview](../policy/overview.md), [DSL](../policy/dsl.md), [Lifecycle](../policy/lifecycle.md), [Runs](../policy/runs.md), [REST API](../api/policy.md), [Policy CLI](../cli/policy.md), [Architecture overview](../architecture/overview.md), [AOC reference](../ingestion/aggregation-only-contract.md)
|
> **Related docs:** [Policy overview](../policy/overview.md), [DSL](../policy/dsl.md), [Lifecycle](../policy/lifecycle.md), [Runs](../policy/runs.md), [REST API](../api/policy.md), [Policy CLI](../cli/policy.md), [Architecture overview](../architecture/overview.md), [AOC reference](../ingestion/aggregation-only-contract.md)
|
||||||
|
|
||||||
This dossier describes the internal structure of the Policy Engine service delivered in Epic 2. It focuses on module boundaries, deterministic evaluation, orchestration, and integration contracts with Concelier, Excititor, SBOM Service, Authority, Scheduler, and Observability stacks.
|
This dossier describes the internal structure of the Policy Engine service delivered in Epic 2. It focuses on module boundaries, deterministic evaluation, orchestration, and integration contracts with Concelier, Excititor, SBOM Service, Authority, Scheduler, and Observability stacks.
|
||||||
|
|
||||||
The service operates strictly downstream of the **Aggregation-Only Contract (AOC)**. It consumes immutable `advisory_raw` and `vex_raw` documents emitted by Concelier and Excititor, derives findings inside Policy-owned collections, and never mutates ingestion stores. Refer to the architecture overview and AOC reference for system-wide guardrails and provenance obligations.
|
The service operates strictly downstream of the **Aggregation-Only Contract (AOC)**. It consumes immutable `advisory_raw` and `vex_raw` documents emitted by Concelier and Excititor, derives findings inside Policy-owned collections, and never mutates ingestion stores. Refer to the architecture overview and AOC reference for system-wide guardrails and provenance obligations.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 1 · Responsibilities & Constraints
|
## 1 · Responsibilities & Constraints
|
||||||
|
|
||||||
- Compile and evaluate `stella-dsl@1` policy packs into deterministic verdicts.
|
- Compile and evaluate `stella-dsl@1` policy packs into deterministic verdicts.
|
||||||
- Join SBOM inventory, Concelier advisories, and Excititor VEX evidence via canonical linksets and equivalence tables.
|
- Join SBOM inventory, Concelier advisories, and Excititor VEX evidence via canonical linksets and equivalence tables.
|
||||||
- Materialise effective findings (`effective_finding_{policyId}`) with append-only history and produce explain traces.
|
- Materialise effective findings (`effective_finding_{policyId}`) with append-only history and produce explain traces.
|
||||||
- Operate incrementally: react to change streams (advisory/vex/SBOM deltas) with ≤ 5 min SLA.
|
- Operate incrementally: react to change streams (advisory/vex/SBOM deltas) with ≤ 5 min SLA.
|
||||||
- Provide simulations with diff summaries for UI/CLI workflows without modifying state.
|
- Provide simulations with diff summaries for UI/CLI workflows without modifying state.
|
||||||
- Enforce strict determinism guard (no wall-clock, RNG, network beyond allow-listed services) and RBAC + tenancy via Authority scopes.
|
- Enforce strict determinism guard (no wall-clock, RNG, network beyond allow-listed services) and RBAC + tenancy via Authority scopes.
|
||||||
- Support sealed/air-gapped deployments with offline bundles and sealed-mode hints.
|
- Support sealed/air-gapped deployments with offline bundles and sealed-mode hints.
|
||||||
|
|
||||||
Non-goals: policy authoring UI (handled by Console), ingestion or advisory normalisation (Concelier), VEX consensus (Excititor), runtime enforcement (Zastava).
|
Non-goals: policy authoring UI (handled by Console), ingestion or advisory normalisation (Concelier), VEX consensus (Excititor), runtime enforcement (Zastava).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 2 · High-Level Architecture
|
## 2 · High-Level Architecture
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
graph TD
|
graph TD
|
||||||
subgraph Clients
|
subgraph Clients
|
||||||
CLI[stella CLI]
|
CLI[stella CLI]
|
||||||
UI[Console Policy Editor]
|
UI[Console Policy Editor]
|
||||||
CI[CI Pipelines]
|
CI[CI Pipelines]
|
||||||
end
|
end
|
||||||
subgraph PolicyEngine["StellaOps.Policy.Engine"]
|
subgraph PolicyEngine["StellaOps.Policy.Engine"]
|
||||||
API[Minimal API Host]
|
API[Minimal API Host]
|
||||||
Orchestrator[Run Orchestrator]
|
Orchestrator[Run Orchestrator]
|
||||||
WorkerPool[Evaluation Workers]
|
WorkerPool[Evaluation Workers]
|
||||||
Compiler[DSL Compiler Cache]
|
Compiler[DSL Compiler Cache]
|
||||||
Materializer[Effective Findings Writer]
|
Materializer[Effective Findings Writer]
|
||||||
end
|
end
|
||||||
subgraph RawStores["Raw Stores (AOC)"]
|
subgraph RawStores["Raw Stores (AOC)"]
|
||||||
AdvisoryRaw[(MongoDB<br/>advisory_raw)]
|
AdvisoryRaw[(MongoDB<br/>advisory_raw)]
|
||||||
VexRaw[(MongoDB<br/>vex_raw)]
|
VexRaw[(MongoDB<br/>vex_raw)]
|
||||||
end
|
end
|
||||||
subgraph Derived["Derived Stores"]
|
subgraph Derived["Derived Stores"]
|
||||||
Mongo[(MongoDB<br/>policies / policy_runs / effective_finding_*)]
|
Mongo[(MongoDB<br/>policies / policy_runs / effective_finding_*)]
|
||||||
Blob[(Object Store / Evidence Locker)]
|
Blob[(Object Store / Evidence Locker)]
|
||||||
Queue[(Mongo Queue / NATS)]
|
Queue[(Mongo Queue / NATS)]
|
||||||
end
|
end
|
||||||
Concelier[(Concelier APIs)]
|
Concelier[(Concelier APIs)]
|
||||||
Excititor[(Excititor APIs)]
|
Excititor[(Excititor APIs)]
|
||||||
SBOM[(SBOM Service)]
|
SBOM[(SBOM Service)]
|
||||||
Authority[(Authority / DPoP Gateway)]
|
Authority[(Authority / DPoP Gateway)]
|
||||||
|
|
||||||
CLI --> API
|
CLI --> API
|
||||||
UI --> API
|
UI --> API
|
||||||
CI --> API
|
CI --> API
|
||||||
API --> Compiler
|
API --> Compiler
|
||||||
API --> Orchestrator
|
API --> Orchestrator
|
||||||
Orchestrator --> Queue
|
Orchestrator --> Queue
|
||||||
Queue --> WorkerPool
|
Queue --> WorkerPool
|
||||||
Concelier --> AdvisoryRaw
|
Concelier --> AdvisoryRaw
|
||||||
Excititor --> VexRaw
|
Excititor --> VexRaw
|
||||||
WorkerPool --> AdvisoryRaw
|
WorkerPool --> AdvisoryRaw
|
||||||
WorkerPool --> VexRaw
|
WorkerPool --> VexRaw
|
||||||
WorkerPool --> SBOM
|
WorkerPool --> SBOM
|
||||||
WorkerPool --> Materializer
|
WorkerPool --> Materializer
|
||||||
Materializer --> Mongo
|
Materializer --> Mongo
|
||||||
WorkerPool --> Blob
|
WorkerPool --> Blob
|
||||||
API --> Mongo
|
API --> Mongo
|
||||||
API --> Blob
|
API --> Blob
|
||||||
API --> Authority
|
API --> Authority
|
||||||
Orchestrator --> Mongo
|
Orchestrator --> Mongo
|
||||||
Authority --> API
|
Authority --> API
|
||||||
```
|
```
|
||||||
|
|
||||||
Key notes:
|
Key notes:
|
||||||
|
|
||||||
- API host exposes lifecycle, run, simulate, findings endpoints with DPoP-bound OAuth enforcement.
|
- API host exposes lifecycle, run, simulate, findings endpoints with DPoP-bound OAuth enforcement.
|
||||||
- Orchestrator manages run scheduling/fairness; writes run tickets to queue, leases jobs to worker pool.
|
- Orchestrator manages run scheduling/fairness; writes run tickets to queue, leases jobs to worker pool.
|
||||||
- Workers evaluate policies using cached IR; join external services via tenant-scoped clients; pull immutable advisories/VEX from the raw stores; write derived overlays to Mongo and optional explain bundles to blob storage.
|
- Workers evaluate policies using cached IR; join external services via tenant-scoped clients; pull immutable advisories/VEX from the raw stores; write derived overlays to Mongo and optional explain bundles to blob storage.
|
||||||
- Observability (metrics/traces/logs) integrated via OpenTelemetry (not shown).
|
- Observability (metrics/traces/logs) integrated via OpenTelemetry (not shown).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### 2.1 · AOC inputs & immutability
|
### 2.1 · AOC inputs & immutability
|
||||||
|
|
||||||
- **Raw-only reads.** Evaluation workers access `advisory_raw` / `vex_raw` via tenant-scoped Mongo clients or the Concelier/Excititor raw APIs. No Policy Engine component is permitted to mutate these collections.
|
- **Raw-only reads.** Evaluation workers access `advisory_raw` / `vex_raw` via tenant-scoped Mongo clients or the Concelier/Excititor raw APIs. No Policy Engine component is permitted to mutate these collections.
|
||||||
- **Guarded ingestion.** `AOCWriteGuard` rejects forbidden fields before data reaches the raw stores. Policy tests replay known `ERR_AOC_00x` violations to confirm ingestion compliance.
|
- **Guarded ingestion.** `AOCWriteGuard` rejects forbidden fields before data reaches the raw stores. Policy tests replay known `ERR_AOC_00x` violations to confirm ingestion compliance.
|
||||||
- **Change streams as contract.** Run orchestration stores resumable cursors for raw change streams. Replays of these cursors (e.g., after failover) must yield identical materialisation outcomes.
|
- **Change streams as contract.** Run orchestration stores resumable cursors for raw change streams. Replays of these cursors (e.g., after failover) must yield identical materialisation outcomes.
|
||||||
- **Derived stores only.** All severity, consensus, and suppression state lives in `effective_finding_*` collections and explain bundles owned by Policy Engine. Provenance fields link back to raw document IDs so auditors can trace every verdict.
|
- **Derived stores only.** All severity, consensus, and suppression state lives in `effective_finding_*` collections and explain bundles owned by Policy Engine. Provenance fields link back to raw document IDs so auditors can trace every verdict.
|
||||||
- **Authority scopes.** Only the Policy Engine service identity holds `effective:write`. Ingestion identities retain `advisory:*`/`vex:*` scopes, ensuring separation of duties enforced by Authority and the API Gateway.
|
- **Authority scopes.** Only the Policy Engine service identity holds `effective:write`. Ingestion identities retain `advisory:*`/`vex:*` scopes, ensuring separation of duties enforced by Authority and the API Gateway.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 3 · Module Breakdown
|
## 3 · Module Breakdown
|
||||||
|
|
||||||
| Module | Responsibility | Notes |
|
| Module | Responsibility | Notes |
|
||||||
|--------|----------------|-------|
|
|--------|----------------|-------|
|
||||||
| **Configuration** (`Configuration/`) | Bind settings (Mongo URIs, queue options, service URLs, sealed mode), validate on start. | Strict schema; fails fast on missing secrets. |
|
| **Configuration** (`Configuration/`) | Bind settings (Mongo URIs, queue options, service URLs, sealed mode), validate on start. | Strict schema; fails fast on missing secrets. |
|
||||||
| **Authority Client** (`Authority/`) | Acquire tokens, enforce scopes, perform DPoP key rotation. | Only service identity uses `effective:write`. |
|
| **Authority Client** (`Authority/`) | Acquire tokens, enforce scopes, perform DPoP key rotation. | Only service identity uses `effective:write`. |
|
||||||
| **DSL Compiler** (`Dsl/`) | Parse, canonicalise, IR generation, checksum caching. | Uses Roslyn-like pipeline; caches by `policyId+version+hash`. |
|
| **DSL Compiler** (`Dsl/`) | Parse, canonicalise, IR generation, checksum caching. | Uses Roslyn-like pipeline; caches by `policyId+version+hash`. |
|
||||||
| **Selection Layer** (`Selection/`) | Batch SBOM ↔ advisory ↔ VEX joiners; apply equivalence tables; support incremental cursors. | Deterministic ordering (SBOM → advisory → VEX). |
|
| **Selection Layer** (`Selection/`) | Batch SBOM ↔ advisory ↔ VEX joiners; apply equivalence tables; support incremental cursors. | Deterministic ordering (SBOM → advisory → VEX). |
|
||||||
| **Evaluator** (`Evaluation/`) | Execute IR with first-match semantics, compute severity/trust/reachability weights, record rule hits. | Stateless; all inputs provided by selection layer. |
|
| **Evaluator** (`Evaluation/`) | Execute IR with first-match semantics, compute severity/trust/reachability weights, record rule hits. | Stateless; all inputs provided by selection layer. |
|
||||||
| **Materialiser** (`Materialization/`) | Upsert effective findings, append history, manage explain bundle exports. | Mongo transactions per SBOM chunk. |
|
| **Materialiser** (`Materialization/`) | Upsert effective findings, append history, manage explain bundle exports. | Mongo transactions per SBOM chunk. |
|
||||||
| **Orchestrator** (`Runs/`) | Change-stream ingestion, fairness, retry/backoff, queue writer. | Works with Scheduler Models DTOs. |
|
| **Orchestrator** (`Runs/`) | Change-stream ingestion, fairness, retry/backoff, queue writer. | Works with Scheduler Models DTOs. |
|
||||||
| **API** (`Api/`) | Minimal API endpoints, DTO validation, problem responses, idempotency. | Generated clients for CLI/UI. |
|
| **API** (`Api/`) | Minimal API endpoints, DTO validation, problem responses, idempotency. | Generated clients for CLI/UI. |
|
||||||
| **Observability** (`Telemetry/`) | Metrics (`policy_run_seconds`, `rules_fired_total`), traces, structured logs. | Sampled rule-hit logs with redaction. |
|
| **Observability** (`Telemetry/`) | Metrics (`policy_run_seconds`, `rules_fired_total`), traces, structured logs. | Sampled rule-hit logs with redaction. |
|
||||||
| **Offline Adapter** (`Offline/`) | Bundle export/import (policies, simulations, runs), sealed-mode enforcement. | Uses DSSE signing via Signer service. |
|
| **Offline Adapter** (`Offline/`) | Bundle export/import (policies, simulations, runs), sealed-mode enforcement. | Uses DSSE signing via Signer service. |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 4 · Data Model & Persistence
|
## 4 · Data Model & Persistence
|
||||||
|
|
||||||
### 4.1 Collections
|
### 4.1 Collections
|
||||||
|
|
||||||
- `policies` – policy versions, metadata, lifecycle states, simulation artefact references.
|
- `policies` – policy versions, metadata, lifecycle states, simulation artefact references.
|
||||||
- `policy_runs` – run records, inputs (cursors, env), stats, determinism hash, run status.
|
- `policy_runs` – run records, inputs (cursors, env), stats, determinism hash, run status.
|
||||||
- `policy_run_events` – append-only log (queued, leased, completed, failed, canceled, replay).
|
- `policy_run_events` – append-only log (queued, leased, completed, failed, canceled, replay).
|
||||||
- `effective_finding_{policyId}` – current verdict snapshot per finding.
|
- `effective_finding_{policyId}` – current verdict snapshot per finding.
|
||||||
- `effective_finding_{policyId}_history` – append-only history (previous verdicts, timestamps, runId).
|
- `effective_finding_{policyId}_history` – append-only history (previous verdicts, timestamps, runId).
|
||||||
- `policy_reviews` – review comments/decisions.
|
- `policy_reviews` – review comments/decisions.
|
||||||
|
|
||||||
### 4.2 Schema Highlights
|
### 4.2 Schema Highlights
|
||||||
|
|
||||||
- Run records include `changeDigests` (hash of advisory/VEX inputs) for replay verification.
|
- Run records include `changeDigests` (hash of advisory/VEX inputs) for replay verification.
|
||||||
- Effective findings store provenance references (`advisory_raw_ids`, `vex_raw_ids`, `sbom_component_id`).
|
- Effective findings store provenance references (`advisory_raw_ids`, `vex_raw_ids`, `sbom_component_id`).
|
||||||
- All collections include `tenant`, `policyId`, `version`, `createdAt`, `updatedAt`, `traceId` for audit.
|
- All collections include `tenant`, `policyId`, `version`, `createdAt`, `updatedAt`, `traceId` for audit.
|
||||||
|
|
||||||
### 4.3 Indexing
|
### 4.3 Indexing
|
||||||
|
|
||||||
- Compound indexes: `{tenant, policyId, status}` on `policies`; `{tenant, policyId, status, startedAt}` on `policy_runs`; `{policyId, sbomId, findingKey}` on findings.
|
- Compound indexes: `{tenant, policyId, status}` on `policies`; `{tenant, policyId, status, startedAt}` on `policy_runs`; `{policyId, sbomId, findingKey}` on findings.
|
||||||
- TTL indexes on transient explain bundle references (configurable).
|
- TTL indexes on transient explain bundle references (configurable).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 5 · Evaluation Pipeline
|
## 5 · Evaluation Pipeline
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
sequenceDiagram
|
sequenceDiagram
|
||||||
autonumber
|
autonumber
|
||||||
participant Worker as EvaluationWorker
|
participant Worker as EvaluationWorker
|
||||||
participant Compiler as CompilerCache
|
participant Compiler as CompilerCache
|
||||||
participant Selector as SelectionLayer
|
participant Selector as SelectionLayer
|
||||||
participant Eval as Evaluator
|
participant Eval as Evaluator
|
||||||
participant Mat as Materialiser
|
participant Mat as Materialiser
|
||||||
participant Expl as ExplainStore
|
participant Expl as ExplainStore
|
||||||
|
|
||||||
Worker->>Compiler: Load IR (policyId, version, digest)
|
Worker->>Compiler: Load IR (policyId, version, digest)
|
||||||
Compiler-->>Worker: CompiledPolicy (cached or compiled)
|
Compiler-->>Worker: CompiledPolicy (cached or compiled)
|
||||||
Worker->>Selector: Fetch tuple batches (sbom, advisory, vex)
|
Worker->>Selector: Fetch tuple batches (sbom, advisory, vex)
|
||||||
Selector-->>Worker: Deterministic batches (1024 tuples)
|
Selector-->>Worker: Deterministic batches (1024 tuples)
|
||||||
loop For each batch
|
loop For each batch
|
||||||
Worker->>Eval: Execute rules (batch, env)
|
Worker->>Eval: Execute rules (batch, env)
|
||||||
Eval-->>Worker: Verdicts + rule hits
|
Eval-->>Worker: Verdicts + rule hits
|
||||||
Worker->>Mat: Upsert effective findings
|
Worker->>Mat: Upsert effective findings
|
||||||
Mat-->>Worker: Success
|
Mat-->>Worker: Success
|
||||||
Worker->>Expl: Persist sampled explain traces (optional)
|
Worker->>Expl: Persist sampled explain traces (optional)
|
||||||
end
|
end
|
||||||
Worker->>Mat: Append history + run stats
|
Worker->>Mat: Append history + run stats
|
||||||
Worker-->>Worker: Compute determinism hash
|
Worker-->>Worker: Compute determinism hash
|
||||||
Worker->>+Mat: Finalize transaction
|
Worker->>+Mat: Finalize transaction
|
||||||
Mat-->>Worker: Ack
|
Mat-->>Worker: Ack
|
||||||
```
|
```
|
||||||
|
|
||||||
Determinism guard instrumentation wraps the evaluator, rejecting access to forbidden APIs and ensuring batch ordering remains stable.
|
Determinism guard instrumentation wraps the evaluator, rejecting access to forbidden APIs and ensuring batch ordering remains stable.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 6 · Run Orchestration & Incremental Flow
|
## 6 · Run Orchestration & Incremental Flow
|
||||||
|
|
||||||
- **Change streams:** Concelier and Excititor publish document changes to the scheduler queue (`policy.trigger.delta`). Payload includes `tenant`, `source`, `linkset digests`, `cursor`.
|
- **Change streams:** Concelier and Excititor publish document changes to the scheduler queue (`policy.trigger.delta`). Payload includes `tenant`, `source`, `linkset digests`, `cursor`.
|
||||||
- **Orchestrator:** Maintains per-tenant backlog; merges deltas until time/size thresholds met, then enqueues `PolicyRunRequest`.
|
- **Orchestrator:** Maintains per-tenant backlog; merges deltas until time/size thresholds met, then enqueues `PolicyRunRequest`.
|
||||||
- **Queue:** Mongo queue with lease; each job assigned `leaseDuration`, `maxAttempts`.
|
- **Queue:** Mongo queue with lease; each job assigned `leaseDuration`, `maxAttempts`.
|
||||||
- **Workers:** Lease jobs, execute evaluation pipeline, report status (success/failure/canceled). Failures with recoverable errors requeue with backoff; determinism or schema violations mark job `failed` and raise incident event.
|
- **Workers:** Lease jobs, execute evaluation pipeline, report status (success/failure/canceled). Failures with recoverable errors requeue with backoff; determinism or schema violations mark job `failed` and raise incident event.
|
||||||
- **Fairness:** Round-robin per `{tenant, policyId}`; emergency jobs (`priority=emergency`) jump queue but limited via circuit breaker.
|
- **Fairness:** Round-robin per `{tenant, policyId}`; emergency jobs (`priority=emergency`) jump queue but limited via circuit breaker.
|
||||||
- **Replay:** On demand, orchestrator rehydrates run via stored cursors and exports sealed bundle for audit/CI determinism checks.
|
- **Replay:** On demand, orchestrator rehydrates run via stored cursors and exports sealed bundle for audit/CI determinism checks.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 7 · Security & Tenancy
|
## 7 · Security & Tenancy
|
||||||
|
|
||||||
- **Auth:** All API calls pass through Authority gateway; DPoP tokens enforced for service-to-service (Policy Engine service principal). CLI/UI tokens include scope claims.
|
- **Auth:** All API calls pass through Authority gateway; DPoP tokens enforced for service-to-service (Policy Engine service principal). CLI/UI tokens include scope claims.
|
||||||
- **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.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 8 · Observability
|
## 8 · Observability
|
||||||
|
|
||||||
- Metrics:
|
- Metrics:
|
||||||
- `policy_run_seconds{mode,tenant,policy}` (histogram)
|
- `policy_run_seconds{mode,tenant,policy}` (histogram)
|
||||||
- `policy_run_queue_depth{tenant}`
|
- `policy_run_queue_depth{tenant}`
|
||||||
- `policy_rules_fired_total{policy,rule}`
|
- `policy_rules_fired_total{policy,rule}`
|
||||||
- `policy_vex_overrides_total{policy,vendor}`
|
- `policy_vex_overrides_total{policy,vendor}`
|
||||||
- Logs: Structured JSON with `traceId`, `policyId`, `version`, `runId`, `tenant`, `phase`. Guard ensures no sensitive data leakage.
|
- Logs: Structured JSON with `traceId`, `policyId`, `version`, `runId`, `tenant`, `phase`. Guard ensures no sensitive data leakage.
|
||||||
- Traces: Spans `policy.select`, `policy.evaluate`, `policy.materialize`, `policy.simulate`. Trace IDs surfaced to CLI/UI.
|
- Traces: Spans `policy.select`, `policy.evaluate`, `policy.materialize`, `policy.simulate`. Trace IDs surfaced to CLI/UI.
|
||||||
- Incident mode toggles 100 % sampling and extended retention windows.
|
- Incident mode toggles 100 % sampling and extended retention windows.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 9 · Offline / Bundle Integration
|
## 9 · Offline / Bundle Integration
|
||||||
|
|
||||||
- **Imports:** Offline Kit delivers policy packs, advisory/VEX snapshots, SBOM updates. Policy Engine ingests bundles via `offline import`.
|
- **Imports:** Offline Kit delivers policy packs, advisory/VEX snapshots, SBOM updates. Policy Engine ingests bundles via `offline import`.
|
||||||
- **Exports:** `stella policy bundle export` packages policy, IR digest, simulations, run metadata; UI provides export triggers.
|
- **Exports:** `stella policy bundle export` packages policy, IR digest, simulations, run metadata; UI provides export triggers.
|
||||||
- **Sealed hints:** Explain traces annotate when cached values used (EPSS, KEV). Run records mark `env.sealed=true`.
|
- **Sealed hints:** Explain traces annotate when cached values used (EPSS, KEV). Run records mark `env.sealed=true`.
|
||||||
- **Sync cadence:** Operators perform monthly bundle sync; Policy Engine warns when snapshots > configured staleness (default 14 days).
|
- **Sync cadence:** Operators perform monthly bundle sync; Policy Engine warns when snapshots > configured staleness (default 14 days).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 10 · Testing & Quality
|
## 10 · Testing & Quality
|
||||||
|
|
||||||
- **Unit tests:** DSL parsing, evaluator semantics, guard enforcement.
|
- **Unit tests:** DSL parsing, evaluator semantics, guard enforcement.
|
||||||
- **Integration tests:** Joiners with sample SBOM/advisory/VEX data; materialisation with deterministic ordering; API contract tests generated from OpenAPI.
|
- **Integration tests:** Joiners with sample SBOM/advisory/VEX data; materialisation with deterministic ordering; API contract tests generated from OpenAPI.
|
||||||
- **Property tests:** Ensure rule evaluation deterministic across permutations.
|
- **Property tests:** Ensure rule evaluation deterministic across permutations.
|
||||||
- **Golden tests:** Replay recorded runs, compare determinism hash.
|
- **Golden tests:** Replay recorded runs, compare determinism hash.
|
||||||
- **Performance tests:** Evaluate 100k component / 1M advisory dataset under warmed caches (<30 s full run).
|
- **Performance tests:** Evaluate 100k component / 1M advisory dataset under warmed caches (<30 s full run).
|
||||||
- **Chaos hooks:** Optional toggles to simulate upstream latency/failures; used in staging.
|
- **Chaos hooks:** Optional toggles to simulate upstream latency/failures; used in staging.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 11 · Compliance Checklist
|
## 11 · Compliance Checklist
|
||||||
|
|
||||||
- [ ] **Determinism guard enforced:** Static analyzer + runtime guard block wall-clock, RNG, unauthorized network calls.
|
- [ ] **Determinism guard enforced:** Static analyzer + runtime guard block wall-clock, RNG, unauthorized network calls.
|
||||||
- [ ] **Incremental correctness:** Change-stream cursors stored and replayed during tests; unit/integration coverage for dedupe.
|
- [ ] **Incremental correctness:** Change-stream cursors stored and replayed during tests; unit/integration coverage for dedupe.
|
||||||
- [ ] **RBAC validated:** Endpoint scope requirements match Authority configuration; integration tests cover deny/allow.
|
- [ ] **RBAC validated:** Endpoint scope requirements match Authority configuration; integration tests cover deny/allow.
|
||||||
- [ ] **AOC separation enforced:** No code path writes to `advisory_raw` / `vex_raw`; integration tests capture `ERR_AOC_00x` handling; read-only clients verified.
|
- [ ] **AOC separation enforced:** No code path writes to `advisory_raw` / `vex_raw`; integration tests capture `ERR_AOC_00x` handling; read-only clients verified.
|
||||||
- [ ] **Effective findings ownership:** Only Policy Engine identity holds `effective:write`; unauthorized callers receive `ERR_AOC_006`.
|
- [ ] **Effective findings ownership:** Only Policy Engine identity holds `effective:write`; unauthorized callers receive `ERR_AOC_006`.
|
||||||
- [ ] **Observability wired:** Metrics/traces/logs exported with correlation IDs; dashboards include `aoc_violation_total` and ingest latency panels.
|
- [ ] **Observability wired:** Metrics/traces/logs exported with correlation IDs; dashboards include `aoc_violation_total` and ingest latency panels.
|
||||||
- [ ] **Offline parity:** Sealed-mode tests executed; bundle import/export flows documented and validated.
|
- [ ] **Offline parity:** Sealed-mode tests executed; bundle import/export flows documented and validated.
|
||||||
- [ ] **Schema docs synced:** DTOs match Scheduler Models (`SCHED-MODELS-20-001`); JSON schemas committed.
|
- [ ] **Schema docs synced:** DTOs match Scheduler Models (`SCHED-MODELS-20-001`); JSON schemas committed.
|
||||||
- [ ] **Security reviews complete:** Threat model (including queue poisoning, determinism bypass, data exfiltration) documented; mitigations in place.
|
- [ ] **Security reviews complete:** Threat model (including queue poisoning, determinism bypass, data exfiltration) documented; mitigations in place.
|
||||||
- [ ] **Disaster recovery rehearsed:** Run replay+rollback procedures tested and recorded.
|
- [ ] **Disaster recovery rehearsed:** Run replay+rollback procedures tested and recorded.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
*Last updated: 2025-10-26 (Sprint 19).*
|
*Last updated: 2025-10-26 (Sprint 19).*
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
# UI Tours Media Assets
|
# UI Tours Media Assets
|
||||||
|
|
||||||
Store annotated screenshots and GIFs referenced by `/docs/examples/ui-tours.md` in this directory. Use the naming convention documented in the guide (e.g., `triage-step-01.png`, `triage-flow.gif`).
|
Store annotated screenshots and GIFs referenced by `/docs/examples/ui-tours.md` in this directory. Use the naming convention documented in the guide (e.g., `triage-step-01.png`, `triage-flow.gif`).
|
||||||
|
|
||||||
## Contribution checklist
|
## Contribution checklist
|
||||||
|
|
||||||
- Capture at 1920×1080 resolution unless otherwise specified.
|
- Capture at 1920×1080 resolution unless otherwise specified.
|
||||||
- Add annotations using the shared Docs Guild template (narrow callouts, numbered badges).
|
- Add annotations using the shared Docs Guild template (narrow callouts, numbered badges).
|
||||||
- Optimize images to stay below 2 MB (PNG) and 8 MB (GIF) while preserving legibility.
|
- Optimize images to stay below 2 MB (PNG) and 8 MB (GIF) while preserving legibility.
|
||||||
- Record GIFs at ≤30 seconds using 12–15 fps for balance between smoothness and size.
|
- Record GIFs at ≤30 seconds using 12–15 fps for balance between smoothness and size.
|
||||||
- Update the capture checklist in `docs/examples/ui-tours.md` when assets are added or replaced.
|
- Update the capture checklist in `docs/examples/ui-tours.md` when assets are added or replaced.
|
||||||
- Commit binaries using Git LFS if size exceeds repository limits; otherwise store directly.
|
- Commit binaries using Git LFS if size exceeds repository limits; otherwise store directly.
|
||||||
- Include the console build hash in the asset metadata or caption, matching the Downloads manifest version.
|
- Include the console build hash in the asset metadata or caption, matching the Downloads manifest version.
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ Use compressed JSON payloads, cached verification results, batched operations, a
|
|||||||
|
|
||||||
## 4) Architecture
|
## 4) Architecture
|
||||||
|
|
||||||
New services (`src/StellaOps.Attestor/`), libraries (`src/StellaOps.Attestor.Envelope/`, `src/StellaOps.Attestor.Types/`, `src/StellaOps.Attestor.Verify/`), CLI (`src/StellaOps.Cli/`), export tooling (`src/StellaOps.ExportCenter.AttestationBundles/`), and shared KMS providers (`src/StellaOps.Cryptography.Kms/`). REST endpoints documented in OpenAPI.
|
New services (`src/Attestor/StellaOps.Attestor/`), libraries (`src/Attestor/StellaOps.Attestor.Envelope/`, `src/Attestor/StellaOps.Attestor.Types/`, `src/Attestor/StellaOps.Attestor.Verify/`), CLI (`src/Cli/StellaOps.Cli/`), export tooling (`src/ExportCenter/StellaOps.ExportCenter.AttestationBundles/`), and shared KMS providers (`src/__Libraries/StellaOps.Cryptography.Kms/`). REST endpoints documented in OpenAPI.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,6 @@ This note captures the Sprint backlog hygiene pass applied on 26 October 2025. T
|
|||||||
- **CI/Offline adjustments.** `DEVOPS-UI-13-006` and `DEVOPS-OFFLINE-18-003` moved under Console release tasks (`CONSOLE-QA-23-401`, `DEVOPS-CONSOLE-23-001`, `CONSOLE-REL-23-302`).
|
- **CI/Offline adjustments.** `DEVOPS-UI-13-006` and `DEVOPS-OFFLINE-18-003` moved under Console release tasks (`CONSOLE-QA-23-401`, `DEVOPS-CONSOLE-23-001`, `CONSOLE-REL-23-302`).
|
||||||
|
|
||||||
## Follow-up
|
## Follow-up
|
||||||
- Update module task boards only under their active backlogs (`src/StellaOps.Notifier`, Cartographer, Vuln Explorer).
|
- Update module task boards only under their active backlogs (`src/Notifier/StellaOps.Notifier`, Cartographer, Vuln Explorer).
|
||||||
- Ensure future ingestion tasks reference AOC guardrails and avoid derived semantics.
|
- Ensure future ingestion tasks reference AOC guardrails and avoid derived semantics.
|
||||||
- Cross-check `SPRINTS.md` after adding new tasks to keep tables consistent with module `TASKS.md` files.
|
- Cross-check `../implplan/SPRINTS.md` after adding new tasks to keep tables consistent with module `TASKS.md` files.
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ The script should emit a parity report that feeds into the Downloads workspace (
|
|||||||
- `/docs/install/docker.md` – CLI parity section for deployments.
|
- `/docs/install/docker.md` – CLI parity section for deployments.
|
||||||
- `/docs/observability/ui-telemetry.md` – telemetry metrics referencing CLI checks.
|
- `/docs/observability/ui-telemetry.md` – telemetry metrics referencing CLI checks.
|
||||||
- `/docs/security/console-security.md` – security metrics & CLI parity expectations.
|
- `/docs/security/console-security.md` – security metrics & CLI parity expectations.
|
||||||
- `src/StellaOps.Cli/TASKS.md` – authoritative status for CLI backlog.
|
- `src/Cli/StellaOps.Cli/TASKS.md` – authoritative status for CLI backlog.
|
||||||
- `/docs/updates/2025-10-28-docs-guild.md` – coordination note for Authority/Security follow-up.
|
- `/docs/updates/2025-10-28-docs-guild.md` – coordination note for Authority/Security follow-up.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -1,316 +1,316 @@
|
|||||||
# CLI AOC Commands Reference
|
# CLI AOC Commands Reference
|
||||||
|
|
||||||
> **Audience:** DevEx engineers, operators, and CI authors integrating the `stella` CLI with Aggregation-Only Contract (AOC) workflows.
|
> **Audience:** DevEx engineers, operators, and CI authors integrating the `stella` CLI with Aggregation-Only Contract (AOC) workflows.
|
||||||
> **Scope:** Command synopsis, options, exit codes, and offline considerations for `stella sources ingest --dry-run` and `stella aoc verify` as introduced in Sprint 19.
|
> **Scope:** Command synopsis, options, exit codes, and offline considerations for `stella sources ingest --dry-run` and `stella aoc verify` as introduced in Sprint 19.
|
||||||
|
|
||||||
Both commands are designed to enforce the AOC guardrails documented in the [aggregation-only reference](../ingestion/aggregation-only-contract.md) and the [architecture overview](../architecture/overview.md). They consume Authority-issued tokens with tenant scopes and never mutate ingestion stores.
|
Both commands are designed to enforce the AOC guardrails documented in the [aggregation-only reference](../ingestion/aggregation-only-contract.md) and the [architecture overview](../architecture/overview.md). They consume Authority-issued tokens with tenant scopes and never mutate ingestion stores.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 1 · Prerequisites
|
## 1 · Prerequisites
|
||||||
|
|
||||||
- CLI version: `stella` ≥ 0.19.0 (AOC feature gate enabled).
|
- CLI version: `stella` ≥ 0.19.0 (AOC feature gate enabled).
|
||||||
- Required scopes (DPoP-bound):
|
- Required scopes (DPoP-bound):
|
||||||
- `advisory:read` for Concelier sources.
|
- `advisory:read` for Concelier sources.
|
||||||
- `vex:read` for Excititor sources (optional but required for VEX checks).
|
- `vex:read` for Excititor sources (optional but required for VEX checks).
|
||||||
- `aoc:verify` to invoke guard verification endpoints.
|
- `aoc:verify` to invoke guard verification endpoints.
|
||||||
- `tenant:select` if your deployment uses tenant switching.
|
- `tenant:select` if your deployment uses tenant switching.
|
||||||
- Connectivity: direct access to Concelier/Excititor APIs or Offline Kit snapshot (see § 4).
|
- Connectivity: direct access to Concelier/Excititor APIs or Offline Kit snapshot (see § 4).
|
||||||
- Environment: set `STELLA_AUTHORITY_URL`, `STELLA_TENANT`, and export a valid OpTok via `stella auth login` or existing token cache.
|
- Environment: set `STELLA_AUTHORITY_URL`, `STELLA_TENANT`, and export a valid OpTok via `stella auth login` or existing token cache.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 2 · `stella sources ingest --dry-run`
|
## 2 · `stella sources ingest --dry-run`
|
||||||
|
|
||||||
### 2.1 Synopsis
|
### 2.1 Synopsis
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
stella sources ingest --dry-run \
|
stella sources ingest --dry-run \
|
||||||
--source <source-key> \
|
--source <source-key> \
|
||||||
--input <path-or-uri> \
|
--input <path-or-uri> \
|
||||||
[--tenant <tenant-id>] \
|
[--tenant <tenant-id>] \
|
||||||
[--format json|table] \
|
[--format json|table] \
|
||||||
[--no-color] \
|
[--no-color] \
|
||||||
[--output <file>]
|
[--output <file>]
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2.2 Description
|
### 2.2 Description
|
||||||
|
|
||||||
Previews an ingestion write without touching MongoDB. The command loads an upstream advisory or VEX document, computes the would-write payload, runs it through the `AOCWriteGuard`, and reports any forbidden fields, provenance gaps, or idempotency issues. Use it during connector development, CI validation, or while triaging incidents.
|
Previews an ingestion write without touching MongoDB. The command loads an upstream advisory or VEX document, computes the would-write payload, runs it through the `AOCWriteGuard`, and reports any forbidden fields, provenance gaps, or idempotency issues. Use it during connector development, CI validation, or while triaging incidents.
|
||||||
|
|
||||||
### 2.3 Options
|
### 2.3 Options
|
||||||
|
|
||||||
| Option | Description |
|
| Option | Description |
|
||||||
|--------|-------------|
|
|--------|-------------|
|
||||||
| `--source <source-key>` | Logical source name (`redhat`, `ubuntu`, `osv`, etc.). Mirrors connector configuration. |
|
| `--source <source-key>` | Logical source name (`redhat`, `ubuntu`, `osv`, etc.). Mirrors connector configuration. |
|
||||||
| `--input <path-or-uri>` | Path to local CSAF/OSV/VEX file or HTTPS URI. CLI normalises transport (gzip/base64) before guard evaluation. |
|
| `--input <path-or-uri>` | Path to local CSAF/OSV/VEX file or HTTPS URI. CLI normalises transport (gzip/base64) before guard evaluation. |
|
||||||
| `--tenant <tenant-id>` | Overrides default tenant for multi-tenant deployments. Mandatory when `STELLA_TENANT` is not set. |
|
| `--tenant <tenant-id>` | Overrides default tenant for multi-tenant deployments. Mandatory when `STELLA_TENANT` is not set. |
|
||||||
| `--format json|table` | Output format. `table` (default) prints summary with highlighted violations; `json` emits machine-readable report (see below). |
|
| `--format json|table` | Output format. `table` (default) prints summary with highlighted violations; `json` emits machine-readable report (see below). |
|
||||||
| `--no-color` | Disables ANSI colour output for CI logs. |
|
| `--no-color` | Disables ANSI colour output for CI logs. |
|
||||||
| `--output <file>` | Writes the JSON report to file while still printing human-readable summary to stdout. |
|
| `--output <file>` | Writes the JSON report to file while still printing human-readable summary to stdout. |
|
||||||
|
|
||||||
### 2.4 Output schema (JSON)
|
### 2.4 Output schema (JSON)
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"source": "redhat",
|
"source": "redhat",
|
||||||
"tenant": "default",
|
"tenant": "default",
|
||||||
"guardVersion": "1.0.0",
|
"guardVersion": "1.0.0",
|
||||||
"status": "ok",
|
"status": "ok",
|
||||||
"document": {
|
"document": {
|
||||||
"contentHash": "sha256:…",
|
"contentHash": "sha256:…",
|
||||||
"supersedes": null,
|
"supersedes": null,
|
||||||
"provenance": {
|
"provenance": {
|
||||||
"signature": { "format": "pgp", "present": true }
|
"signature": { "format": "pgp", "present": true }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"violations": []
|
"violations": []
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
When violations exist, `status` becomes `error` and `violations` contains entries with `code` (`ERR_AOC_00x`), a short `message`, and JSON Pointer `path` values indicating offending fields.
|
When violations exist, `status` becomes `error` and `violations` contains entries with `code` (`ERR_AOC_00x`), a short `message`, and JSON Pointer `path` values indicating offending fields.
|
||||||
|
|
||||||
### 2.5 Exit codes
|
### 2.5 Exit codes
|
||||||
|
|
||||||
| Exit code | Meaning |
|
| Exit code | Meaning |
|
||||||
|-----------|---------|
|
|-----------|---------|
|
||||||
| `0` | Guard passed; would-write payload is AOC compliant. |
|
| `0` | Guard passed; would-write payload is AOC compliant. |
|
||||||
| `11` | `ERR_AOC_001` – Forbidden field (`severity`, `cvss`, etc.) detected. |
|
| `11` | `ERR_AOC_001` – Forbidden field (`severity`, `cvss`, etc.) detected. |
|
||||||
| `12` | `ERR_AOC_002` – Merge attempt (multiple upstream sources fused). |
|
| `12` | `ERR_AOC_002` – Merge attempt (multiple upstream sources fused). |
|
||||||
| `13` | `ERR_AOC_003` – Idempotency violation (duplicate without supersedes). |
|
| `13` | `ERR_AOC_003` – Idempotency violation (duplicate without supersedes). |
|
||||||
| `14` | `ERR_AOC_004` – Missing provenance fields. |
|
| `14` | `ERR_AOC_004` – Missing provenance fields. |
|
||||||
| `15` | `ERR_AOC_005` – Signature/checksum mismatch. |
|
| `15` | `ERR_AOC_005` – Signature/checksum mismatch. |
|
||||||
| `16` | `ERR_AOC_006` – Effective findings present (Policy-only data). |
|
| `16` | `ERR_AOC_006` – Effective findings present (Policy-only data). |
|
||||||
| `17` | `ERR_AOC_007` – Unknown top-level fields / schema violation. |
|
| `17` | `ERR_AOC_007` – Unknown top-level fields / schema violation. |
|
||||||
| `70` | Transport error (network, auth, malformed input). |
|
| `70` | Transport error (network, auth, malformed input). |
|
||||||
|
|
||||||
> Exit codes map directly to the `ERR_AOC_00x` table for scripting consistency. Multiple violations yield the highest-priority code (e.g., 11 takes precedence over 14).
|
> Exit codes map directly to the `ERR_AOC_00x` table for scripting consistency. Multiple violations yield the highest-priority code (e.g., 11 takes precedence over 14).
|
||||||
|
|
||||||
### 2.6 Examples
|
### 2.6 Examples
|
||||||
|
|
||||||
Dry-run a local CSAF file:
|
Dry-run a local CSAF file:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
stella sources ingest --dry-run \
|
stella sources ingest --dry-run \
|
||||||
--source redhat \
|
--source redhat \
|
||||||
--input ./fixtures/redhat/RHSA-2025-1234.json
|
--input ./fixtures/redhat/RHSA-2025-1234.json
|
||||||
```
|
```
|
||||||
|
|
||||||
Stream from HTTPS and emit JSON for CI:
|
Stream from HTTPS and emit JSON for CI:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
stella sources ingest --dry-run \
|
stella sources ingest --dry-run \
|
||||||
--source osv \
|
--source osv \
|
||||||
--input https://osv.dev/vulnerability/GHSA-aaaa-bbbb \
|
--input https://osv.dev/vulnerability/GHSA-aaaa-bbbb \
|
||||||
--format json \
|
--format json \
|
||||||
--output artifacts/osv-dry-run.json
|
--output artifacts/osv-dry-run.json
|
||||||
|
|
||||||
cat artifacts/osv-dry-run.json | jq '.violations'
|
cat artifacts/osv-dry-run.json | jq '.violations'
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2.7 Offline notes
|
### 2.7 Offline notes
|
||||||
|
|
||||||
When operating in sealed/offline mode:
|
When operating in sealed/offline mode:
|
||||||
|
|
||||||
- Use `--input` paths pointing to Offline Kit snapshots (`offline-kit/advisories/*.json`).
|
- Use `--input` paths pointing to Offline Kit snapshots (`offline-kit/advisories/*.json`).
|
||||||
- Provide `--tenant` explicitly if the offline bundle contains multiple tenants.
|
- Provide `--tenant` explicitly if the offline bundle contains multiple tenants.
|
||||||
- The command does not attempt network access when given a file path.
|
- The command does not attempt network access when given a file path.
|
||||||
- Store reports with `--output` to include in transfer packages for policy review.
|
- Store reports with `--output` to include in transfer packages for policy review.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 3 · `stella aoc verify`
|
## 3 · `stella aoc verify`
|
||||||
|
|
||||||
### 3.1 Synopsis
|
### 3.1 Synopsis
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
stella aoc verify \
|
stella aoc verify \
|
||||||
[--since <iso8601|duration>] \
|
[--since <iso8601|duration>] \
|
||||||
[--limit <count>] \
|
[--limit <count>] \
|
||||||
[--sources <list>] \
|
[--sources <list>] \
|
||||||
[--codes <ERR_AOC_00x,...>] \
|
[--codes <ERR_AOC_00x,...>] \
|
||||||
[--format table|json] \
|
[--format table|json] \
|
||||||
[--export <file>] \
|
[--export <file>] \
|
||||||
[--tenant <tenant-id>] \
|
[--tenant <tenant-id>] \
|
||||||
[--no-color]
|
[--no-color]
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3.2 Description
|
### 3.2 Description
|
||||||
|
|
||||||
Replays the AOC guard against stored raw documents. By default it checks all advisories and VEX statements ingested in the last 24 hours for the active tenant, reporting totals, top violation codes, and sample documents. Use it in CI pipelines, scheduled verifications, or during incident response.
|
Replays the AOC guard against stored raw documents. By default it checks all advisories and VEX statements ingested in the last 24 hours for the active tenant, reporting totals, top violation codes, and sample documents. Use it in CI pipelines, scheduled verifications, or during incident response.
|
||||||
|
|
||||||
### 3.3 Options
|
### 3.3 Options
|
||||||
|
|
||||||
| Option | Description |
|
| Option | Description |
|
||||||
|--------|-------------|
|
|--------|-------------|
|
||||||
| `--since <value>` | Verification window. Accepts ISO 8601 timestamp (`2025-10-25T12:00:00Z`) or duration (`48h`, `7d`). Defaults to `24h`. |
|
| `--since <value>` | Verification window. Accepts ISO 8601 timestamp (`2025-10-25T12:00:00Z`) or duration (`48h`, `7d`). Defaults to `24h`. |
|
||||||
| `--limit <count>` | Maximum number of violations to display (per code). `0` means show all. Defaults to `20`. |
|
| `--limit <count>` | Maximum number of violations to display (per code). `0` means show all. Defaults to `20`. |
|
||||||
| `--sources <list>` | Comma-separated list of sources (`redhat,ubuntu,osv`). Filters both advisories and VEX entries. |
|
| `--sources <list>` | Comma-separated list of sources (`redhat,ubuntu,osv`). Filters both advisories and VEX entries. |
|
||||||
| `--codes <list>` | Restricts output to specific `ERR_AOC_00x` codes. Useful for regression tracking. |
|
| `--codes <list>` | Restricts output to specific `ERR_AOC_00x` codes. Useful for regression tracking. |
|
||||||
| `--format table|json` | `table` (default) prints summary plus top violations; `json` outputs machine-readable report identical to the `/aoc/verify` API. |
|
| `--format table|json` | `table` (default) prints summary plus top violations; `json` outputs machine-readable report identical to the `/aoc/verify` API. |
|
||||||
| `--export <file>` | Writes the JSON report to disk (useful for audits/offline uploads). |
|
| `--export <file>` | Writes the JSON report to disk (useful for audits/offline uploads). |
|
||||||
| `--tenant <tenant-id>` | Overrides tenant context. Required for cross-tenant verifications when run by platform operators. |
|
| `--tenant <tenant-id>` | Overrides tenant context. Required for cross-tenant verifications when run by platform operators. |
|
||||||
| `--no-color` | Disables ANSI colours. |
|
| `--no-color` | Disables ANSI colours. |
|
||||||
|
|
||||||
`table` mode prints a summary showing the active tenant, evaluated window, counts of checked advisories/VEX statements, the active limit, total writes/violations, and whether the page was truncated. Status is colour-coded as `ok`, `violations`, or `truncated`. When violations exist the detail table lists the code, total occurrences, first sample document (`source` + `documentId` + `contentHash`), and JSON pointer path.
|
`table` mode prints a summary showing the active tenant, evaluated window, counts of checked advisories/VEX statements, the active limit, total writes/violations, and whether the page was truncated. Status is colour-coded as `ok`, `violations`, or `truncated`. When violations exist the detail table lists the code, total occurrences, first sample document (`source` + `documentId` + `contentHash`), and JSON pointer path.
|
||||||
|
|
||||||
### 3.4 Report structure (JSON)
|
### 3.4 Report structure (JSON)
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"tenant": "default",
|
"tenant": "default",
|
||||||
"window": {
|
"window": {
|
||||||
"from": "2025-10-25T12:00:00Z",
|
"from": "2025-10-25T12:00:00Z",
|
||||||
"to": "2025-10-26T12:00:00Z"
|
"to": "2025-10-26T12:00:00Z"
|
||||||
},
|
},
|
||||||
"checked": {
|
"checked": {
|
||||||
"advisories": 482,
|
"advisories": 482,
|
||||||
"vex": 75
|
"vex": 75
|
||||||
},
|
},
|
||||||
"violations": [
|
"violations": [
|
||||||
{
|
{
|
||||||
"code": "ERR_AOC_001",
|
"code": "ERR_AOC_001",
|
||||||
"count": 2,
|
"count": 2,
|
||||||
"examples": [
|
"examples": [
|
||||||
{
|
{
|
||||||
"source": "redhat",
|
"source": "redhat",
|
||||||
"documentId": "advisory_raw:redhat:RHSA-2025:1",
|
"documentId": "advisory_raw:redhat:RHSA-2025:1",
|
||||||
"contentHash": "sha256:…",
|
"contentHash": "sha256:…",
|
||||||
"path": "/content/raw/cvss"
|
"path": "/content/raw/cvss"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"metrics": {
|
"metrics": {
|
||||||
"ingestion_write_total": 557,
|
"ingestion_write_total": 557,
|
||||||
"aoc_violation_total": 2
|
"aoc_violation_total": 2
|
||||||
},
|
},
|
||||||
"truncated": false
|
"truncated": false
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3.5 Exit codes
|
### 3.5 Exit codes
|
||||||
|
|
||||||
| Exit code | Meaning |
|
| Exit code | Meaning |
|
||||||
|-----------|---------|
|
|-----------|---------|
|
||||||
| `0` | Verification succeeded with zero violations. |
|
| `0` | Verification succeeded with zero violations. |
|
||||||
| `11…17` | Same mapping as § 2.5 when violations are detected. Highest-priority code returned. |
|
| `11…17` | Same mapping as § 2.5 when violations are detected. Highest-priority code returned. |
|
||||||
| `18` | Verification ran but results truncated (limit reached) – treat as warning; rerun with higher `--limit`. |
|
| `18` | Verification ran but results truncated (limit reached) – treat as warning; rerun with higher `--limit`. |
|
||||||
| `70` | Transport/authentication error. |
|
| `70` | Transport/authentication error. |
|
||||||
| `71` | CLI misconfiguration (missing tenant, invalid `--since`, etc.). |
|
| `71` | CLI misconfiguration (missing tenant, invalid `--since`, etc.). |
|
||||||
|
|
||||||
### 3.6 Examples
|
### 3.6 Examples
|
||||||
|
|
||||||
Daily verification across all sources:
|
Daily verification across all sources:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
stella aoc verify --since 24h --format table
|
stella aoc verify --since 24h --format table
|
||||||
```
|
```
|
||||||
|
|
||||||
CI pipeline focusing on errant sources and exporting evidence:
|
CI pipeline focusing on errant sources and exporting evidence:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
stella aoc verify \
|
stella aoc verify \
|
||||||
--sources redhat,ubuntu \
|
--sources redhat,ubuntu \
|
||||||
--codes ERR_AOC_001,ERR_AOC_004 \
|
--codes ERR_AOC_001,ERR_AOC_004 \
|
||||||
--format json \
|
--format json \
|
||||||
--limit 100 \
|
--limit 100 \
|
||||||
--export artifacts/aoc-verify.json
|
--export artifacts/aoc-verify.json
|
||||||
|
|
||||||
jq '.violations[] | {code, count}' artifacts/aoc-verify.json
|
jq '.violations[] | {code, count}' artifacts/aoc-verify.json
|
||||||
```
|
```
|
||||||
|
|
||||||
Air-gapped verification using Offline Kit snapshot (example script):
|
Air-gapped verification using Offline Kit snapshot (example script):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
stella aoc verify \
|
stella aoc verify \
|
||||||
--since 7d \
|
--since 7d \
|
||||||
--format json \
|
--format json \
|
||||||
--export /mnt/offline/aoc-verify-$(date +%F).json
|
--export /mnt/offline/aoc-verify-$(date +%F).json
|
||||||
|
|
||||||
sha256sum /mnt/offline/aoc-verify-*.json > /mnt/offline/checksums.txt
|
sha256sum /mnt/offline/aoc-verify-*.json > /mnt/offline/checksums.txt
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3.7 Automation tips
|
### 3.7 Automation tips
|
||||||
|
|
||||||
- Schedule with `cron` or platform scheduler and fail the job when exit code ≥ 11.
|
- Schedule with `cron` or platform scheduler and fail the job when exit code ≥ 11.
|
||||||
- Pair with `stella sources ingest --dry-run` for pre-flight validation before re-enabling a paused source.
|
- Pair with `stella sources ingest --dry-run` for pre-flight validation before re-enabling a paused source.
|
||||||
- Push JSON exports to observability pipelines for historical tracking of violation counts.
|
- Push JSON exports to observability pipelines for historical tracking of violation counts.
|
||||||
|
|
||||||
### 3.8 Offline notes
|
### 3.8 Offline notes
|
||||||
|
|
||||||
- Works against Offline Kit Mongo snapshots when CLI is pointed at the local API gateway included in the bundle.
|
- Works against Offline Kit Mongo snapshots when CLI is pointed at the local API gateway included in the bundle.
|
||||||
- When fully disconnected, run against exported `aoc verify` reports generated on production and replay them using `--format json --export` (automation recipe above).
|
- When fully disconnected, run against exported `aoc verify` reports generated on production and replay them using `--format json --export` (automation recipe above).
|
||||||
- Include verification output in compliance packages alongside Offline Kit manifests.
|
- Include verification output in compliance packages alongside Offline Kit manifests.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 4 · Global exit-code reference
|
## 4 · Global exit-code reference
|
||||||
|
|
||||||
| Code | Summary |
|
| Code | Summary |
|
||||||
|------|---------|
|
|------|---------|
|
||||||
| `0` | Success / no violations. |
|
| `0` | Success / no violations. |
|
||||||
| `11` | `ERR_AOC_001` – Forbidden field present. |
|
| `11` | `ERR_AOC_001` – Forbidden field present. |
|
||||||
| `12` | `ERR_AOC_002` – Merge attempt detected. |
|
| `12` | `ERR_AOC_002` – Merge attempt detected. |
|
||||||
| `13` | `ERR_AOC_003` – Idempotency violation. |
|
| `13` | `ERR_AOC_003` – Idempotency violation. |
|
||||||
| `14` | `ERR_AOC_004` – Missing provenance/signature metadata. |
|
| `14` | `ERR_AOC_004` – Missing provenance/signature metadata. |
|
||||||
| `15` | `ERR_AOC_005` – Signature/checksum mismatch. |
|
| `15` | `ERR_AOC_005` – Signature/checksum mismatch. |
|
||||||
| `16` | `ERR_AOC_006` – Effective findings in ingestion payload. |
|
| `16` | `ERR_AOC_006` – Effective findings in ingestion payload. |
|
||||||
| `17` | `ERR_AOC_007` – Schema violation / unknown fields. |
|
| `17` | `ERR_AOC_007` – Schema violation / unknown fields. |
|
||||||
| `18` | Partial verification (limit reached). |
|
| `18` | Partial verification (limit reached). |
|
||||||
| `70` | Transport or HTTP failure. |
|
| `70` | Transport or HTTP failure. |
|
||||||
| `71` | CLI usage error (invalid arguments, missing tenant). |
|
| `71` | CLI usage error (invalid arguments, missing tenant). |
|
||||||
|
|
||||||
Use these codes in CI to map outcomes to build statuses or alert severities.
|
Use these codes in CI to map outcomes to build statuses or alert severities.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 4 · `stella vuln observations` (Overlay paging)
|
## 4 · `stella vuln observations` (Overlay paging)
|
||||||
|
|
||||||
`stella vuln observations` lists raw advisory observations for downstream overlays (Graph Explorer, Policy simulations, Console). Large tenants can now page through results deterministically.
|
`stella vuln observations` lists raw advisory observations for downstream overlays (Graph Explorer, Policy simulations, Console). Large tenants can now page through results deterministically.
|
||||||
|
|
||||||
| Option | Description |
|
| Option | Description |
|
||||||
|--------|-------------|
|
|--------|-------------|
|
||||||
| `--limit <count>` | Caps the number of observations returned in a single call. Defaults to `200`; values above `500` are clamped server-side. |
|
| `--limit <count>` | Caps the number of observations returned in a single call. Defaults to `200`; values above `500` are clamped server-side. |
|
||||||
| `--cursor <token>` | Opaque continuation token produced by the previous page (`nextCursor` in JSON output). Pass it back to resume iteration. |
|
| `--cursor <token>` | Opaque continuation token produced by the previous page (`nextCursor` in JSON output). Pass it back to resume iteration. |
|
||||||
|
|
||||||
Additional notes:
|
Additional notes:
|
||||||
|
|
||||||
- Table mode prints a hint when `hasMore` is `true`:
|
- Table mode prints a hint when `hasMore` is `true`:
|
||||||
`[yellow]More observations available. Continue with --cursor <token>[/]`.
|
`[yellow]More observations available. Continue with --cursor <token>[/]`.
|
||||||
- JSON mode returns `nextCursor` and `hasMore` alongside the observation list so automation can loop until `hasMore` is `false`.
|
- JSON mode returns `nextCursor` and `hasMore` alongside the observation list so automation can loop until `hasMore` is `false`.
|
||||||
- Supplying a non-positive limit falls back to the default (`200`). Invalid/expired cursors yield `400 Bad Request`; restart without `--cursor` to begin a fresh iteration.
|
- Supplying a non-positive limit falls back to the default (`200`). Invalid/expired cursors yield `400 Bad Request`; restart without `--cursor` to begin a fresh iteration.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 5 · Related references
|
## 5 · Related references
|
||||||
|
|
||||||
- [Aggregation-Only Contract reference](../ingestion/aggregation-only-contract.md)
|
- [Aggregation-Only Contract reference](../ingestion/aggregation-only-contract.md)
|
||||||
- [Architecture overview](../architecture/overview.md)
|
- [Architecture overview](../architecture/overview.md)
|
||||||
- [Console AOC dashboard](../ui/console.md)
|
- [Console AOC dashboard](../ui/console.md)
|
||||||
- [Authority scopes](../ARCHITECTURE_AUTHORITY.md)
|
- [Authority scopes](../ARCHITECTURE_AUTHORITY.md)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 6 · Compliance checklist
|
## 6 · Compliance checklist
|
||||||
|
|
||||||
- [ ] Usage documented for both table and JSON formats.
|
- [ ] Usage documented for both table and JSON formats.
|
||||||
- [ ] Exit-code mapping matches `ERR_AOC_00x` definitions and automation guidance.
|
- [ ] Exit-code mapping matches `ERR_AOC_00x` definitions and automation guidance.
|
||||||
- [ ] Offline/air-gap workflow captured for both commands.
|
- [ ] Offline/air-gap workflow captured for both commands.
|
||||||
- [ ] References to AOC architecture and console docs included.
|
- [ ] References to AOC architecture and console docs included.
|
||||||
- [ ] Examples validated against current CLI syntax (update post-implementation).
|
- [ ] Examples validated against current CLI syntax (update post-implementation).
|
||||||
- [ ] Docs guild screenshot/narrative placeholder logged for release notes (pending CLI team capture).
|
- [ ] Docs guild screenshot/narrative placeholder logged for release notes (pending CLI team capture).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
*Last updated: 2025-10-29 (Sprint 24).*
|
*Last updated: 2025-10-29 (Sprint 24).*
|
||||||
|
|
||||||
## 13. Authority configuration quick reference
|
## 13. Authority configuration quick reference
|
||||||
|
|
||||||
| Setting | Purpose | How to set |
|
| Setting | Purpose | How to set |
|
||||||
|---------|---------|------------|
|
|---------|---------|------------|
|
||||||
| `StellaOps:Authority:OperatorReason` | Incident/change description recorded with `orch:operate` tokens. | CLI flag `--Authority:OperatorReason=...` or env `STELLAOPS_ORCH_REASON`. |
|
| `StellaOps:Authority:OperatorReason` | Incident/change description recorded with `orch:operate` tokens. | CLI flag `--Authority:OperatorReason=...` or env `STELLAOPS_ORCH_REASON`. |
|
||||||
| `StellaOps:Authority:OperatorTicket` | Change/incident ticket reference paired with orchestrator control actions. | CLI flag `--Authority:OperatorTicket=...` or env `STELLAOPS_ORCH_TICKET`. |
|
| `StellaOps:Authority:OperatorTicket` | Change/incident ticket reference paired with orchestrator control actions. | CLI flag `--Authority:OperatorTicket=...` or env `STELLAOPS_ORCH_TICKET`. |
|
||||||
|
|
||||||
> Tokens requesting `orch:operate` will fail with `invalid_request` unless both values are present. Choose concise strings (≤256 chars for reason, ≤128 chars for ticket) and avoid sensitive data.
|
> Tokens requesting `orch:operate` will fail with `invalid_request` unless both values are present. Choose concise strings (≤256 chars for reason, ≤128 chars for ticket) and avoid sensitive data.
|
||||||
|
|
||||||
|
|||||||
@@ -185,7 +185,7 @@ Output fields (JSON):
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
> Schema reminder: CLI commands surface objects defined in `src/StellaOps.Scheduler.Models/docs/SCHED-MODELS-20-001-POLICY-RUNS.md`; use the samples in `samples/api/scheduler/` for contract validation when extending output parsing.
|
> Schema reminder: CLI commands surface objects defined in `src/Scheduler/__Libraries/StellaOps.Scheduler.Models/docs/SCHED-MODELS-20-001-POLICY-RUNS.md`; use the samples in `samples/api/scheduler/` for contract validation when extending output parsing.
|
||||||
|
|
||||||
Exit codes:
|
Exit codes:
|
||||||
|
|
||||||
|
|||||||
@@ -1,228 +1,228 @@
|
|||||||
# Deploying the StellaOps Console
|
# Deploying the StellaOps Console
|
||||||
|
|
||||||
> **Audience:** Deployment Guild, Console Guild, operators rolling out the web console.
|
> **Audience:** Deployment Guild, Console Guild, operators rolling out the web console.
|
||||||
> **Scope:** Helm and Docker Compose deployment steps, ingress/TLS configuration, required environment variables, health checks, offline/air-gap operation, and compliance checklist (Sprint 23).
|
> **Scope:** Helm and Docker Compose deployment steps, ingress/TLS configuration, required environment variables, health checks, offline/air-gap operation, and compliance checklist (Sprint 23).
|
||||||
|
|
||||||
The StellaOps Console ships as part of the `stellaops` stack Helm chart and Compose bundles maintained under `deploy/`. This guide describes the supported deployment paths, the configuration surface, and operational checks needed to run the console in connected or air-gapped environments.
|
The StellaOps Console ships as part of the `stellaops` stack Helm chart and Compose bundles maintained under `deploy/`. This guide describes the supported deployment paths, the configuration surface, and operational checks needed to run the console in connected or air-gapped environments.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 1. Prerequisites
|
## 1. Prerequisites
|
||||||
|
|
||||||
- Kubernetes cluster (v1.28+) with ingress controller (NGINX, Traefik, or equivalent) and Cert-Manager for automated TLS, or Docker host for Compose deployments.
|
- Kubernetes cluster (v1.28+) with ingress controller (NGINX, Traefik, or equivalent) and Cert-Manager for automated TLS, or Docker host for Compose deployments.
|
||||||
- Container registry access to `registry.stella-ops.org` (or mirrored registry) for all images listed in `deploy/releases/*.yaml`.
|
- Container registry access to `registry.stella-ops.org` (or mirrored registry) for all images listed in `deploy/releases/*.yaml`.
|
||||||
- Authority service configured with console client (`aud=ui`, scopes `ui.read`, `ui.admin`).
|
- Authority service configured with console client (`aud=ui`, scopes `ui.read`, `ui.admin`).
|
||||||
- DNS entry pointing to the console hostname (for example, `console.acme.internal`).
|
- DNS entry pointing to the console hostname (for example, `console.acme.internal`).
|
||||||
- Cosign public key for manifest verification (`deploy/releases/manifest.json.sig`).
|
- Cosign public key for manifest verification (`deploy/releases/manifest.json.sig`).
|
||||||
- Optional: Offline Kit bundle for air-gapped sites (`stella-ops-offline-kit-<ver>.tar.gz`).
|
- Optional: Offline Kit bundle for air-gapped sites (`stella-ops-offline-kit-<ver>.tar.gz`).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 2. Helm deployment (recommended)
|
## 2. Helm deployment (recommended)
|
||||||
|
|
||||||
### 2.1 Install chart repository
|
### 2.1 Install chart repository
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
helm repo add stellaops https://downloads.stella-ops.org/helm
|
helm repo add stellaops https://downloads.stella-ops.org/helm
|
||||||
helm repo update stellaops
|
helm repo update stellaops
|
||||||
```
|
```
|
||||||
|
|
||||||
If operating offline, copy the chart archive from the Offline Kit (`deploy/helm/stellaops-<ver>.tgz`) and run:
|
If operating offline, copy the chart archive from the Offline Kit (`deploy/helm/stellaops-<ver>.tgz`) and run:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
helm install stellaops ./stellaops-<ver>.tgz --namespace stellaops --create-namespace
|
helm install stellaops ./stellaops-<ver>.tgz --namespace stellaops --create-namespace
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2.2 Base installation
|
### 2.2 Base installation
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
helm install stellaops stellaops/stellaops \
|
helm install stellaops stellaops/stellaops \
|
||||||
--namespace stellaops \
|
--namespace stellaops \
|
||||||
--create-namespace \
|
--create-namespace \
|
||||||
--values deploy/helm/stellaops/values-prod.yaml
|
--values deploy/helm/stellaops/values-prod.yaml
|
||||||
```
|
```
|
||||||
|
|
||||||
The chart deploys Authority, Console web/API gateway, Scanner API, Scheduler, and supporting services. The console frontend pod is labelled `app=stellaops-web-ui`.
|
The chart deploys Authority, Console web/API gateway, Scanner API, Scheduler, and supporting services. The console frontend pod is labelled `app=stellaops-web-ui`.
|
||||||
|
|
||||||
### 2.3 Helm values highlights
|
### 2.3 Helm values highlights
|
||||||
|
|
||||||
Key sections in `deploy/helm/stellaops/values-prod.yaml`:
|
Key sections in `deploy/helm/stellaops/values-prod.yaml`:
|
||||||
|
|
||||||
| Path | Description |
|
| Path | Description |
|
||||||
|------|-------------|
|
|------|-------------|
|
||||||
| `console.ingress.host` | Hostname served by the console (`console.example.com`). |
|
| `console.ingress.host` | Hostname served by the console (`console.example.com`). |
|
||||||
| `console.ingress.tls.secretName` | Kubernetes secret containing TLS certificate (generated by Cert-Manager or uploaded manually). |
|
| `console.ingress.tls.secretName` | Kubernetes secret containing TLS certificate (generated by Cert-Manager or uploaded manually). |
|
||||||
| `console.config.apiGateway.baseUrl` | Internal base URL the UI uses to reach the gateway (defaults to `https://stellaops-web`). |
|
| `console.config.apiGateway.baseUrl` | Internal base URL the UI uses to reach the gateway (defaults to `https://stellaops-web`). |
|
||||||
| `console.env.AUTHORITY_ISSUER` | Authority issuer URL (for example, `https://authority.example.com`). |
|
| `console.env.AUTHORITY_ISSUER` | Authority issuer URL (for example, `https://authority.example.com`). |
|
||||||
| `console.env.AUTHORITY_CLIENT_ID` | Authority client ID for the console UI. |
|
| `console.env.AUTHORITY_CLIENT_ID` | Authority client ID for the console UI. |
|
||||||
| `console.env.AUTHORITY_SCOPES` | Space-separated scopes required by UI (`ui.read ui.admin`). |
|
| `console.env.AUTHORITY_SCOPES` | Space-separated scopes required by UI (`ui.read ui.admin`). |
|
||||||
| `console.resources` | CPU/memory requests and limits (default 250m CPU / 512Mi memory). |
|
| `console.resources` | CPU/memory requests and limits (default 250m CPU / 512Mi memory). |
|
||||||
| `console.podAnnotations` | Optional annotations for service mesh or monitoring. |
|
| `console.podAnnotations` | Optional annotations for service mesh or monitoring. |
|
||||||
|
|
||||||
Use `values-stage.yaml`, `values-dev.yaml`, or `values-airgap.yaml` as templates for other environments.
|
Use `values-stage.yaml`, `values-dev.yaml`, or `values-airgap.yaml` as templates for other environments.
|
||||||
|
|
||||||
### 2.4 TLS and ingress
|
### 2.4 TLS and ingress
|
||||||
|
|
||||||
Example ingress override:
|
Example ingress override:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
console:
|
console:
|
||||||
ingress:
|
ingress:
|
||||||
enabled: true
|
enabled: true
|
||||||
className: nginx
|
className: nginx
|
||||||
host: console.acme.internal
|
host: console.acme.internal
|
||||||
tls:
|
tls:
|
||||||
enabled: true
|
enabled: true
|
||||||
secretName: console-tls
|
secretName: console-tls
|
||||||
```
|
```
|
||||||
|
|
||||||
Generate certificates using Cert-Manager or provide an existing secret. For air-gapped deployments, pre-create the secret with the mirrored CA chain.
|
Generate certificates using Cert-Manager or provide an existing secret. For air-gapped deployments, pre-create the secret with the mirrored CA chain.
|
||||||
|
|
||||||
### 2.5 Health checks
|
### 2.5 Health checks
|
||||||
|
|
||||||
Console pods expose:
|
Console pods expose:
|
||||||
|
|
||||||
| Path | Purpose | Notes |
|
| Path | Purpose | Notes |
|
||||||
|------|---------|-------|
|
|------|---------|-------|
|
||||||
| `/health/live` | Liveness probe | Confirms process responsive. |
|
| `/health/live` | Liveness probe | Confirms process responsive. |
|
||||||
| `/health/ready` | Readiness probe | Verifies configuration bootstrap and Authority reachability. |
|
| `/health/ready` | Readiness probe | Verifies configuration bootstrap and Authority reachability. |
|
||||||
| `/metrics` | Prometheus metrics | Enabled when `console.metrics.enabled=true`. |
|
| `/metrics` | Prometheus metrics | Enabled when `console.metrics.enabled=true`. |
|
||||||
|
|
||||||
Helm chart sets default probes (`initialDelaySeconds: 10`, `periodSeconds: 15`). Adjust via `console.livenessProbe` and `console.readinessProbe`.
|
Helm chart sets default probes (`initialDelaySeconds: 10`, `periodSeconds: 15`). Adjust via `console.livenessProbe` and `console.readinessProbe`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 3. Docker Compose deployment
|
## 3. Docker Compose deployment
|
||||||
|
|
||||||
Located in `deploy/compose/docker-compose.console.yaml`. Quick start:
|
Located in `deploy/compose/docker-compose.console.yaml`. Quick start:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd deploy/compose
|
cd deploy/compose
|
||||||
docker compose -f docker-compose.console.yaml --env-file console.env up -d
|
docker compose -f docker-compose.console.yaml --env-file console.env up -d
|
||||||
```
|
```
|
||||||
|
|
||||||
`console.env` should define:
|
`console.env` should define:
|
||||||
|
|
||||||
```
|
```
|
||||||
CONSOLE_PUBLIC_BASE_URL=https://console.acme.internal
|
CONSOLE_PUBLIC_BASE_URL=https://console.acme.internal
|
||||||
AUTHORITY_ISSUER=https://authority.acme.internal
|
AUTHORITY_ISSUER=https://authority.acme.internal
|
||||||
AUTHORITY_CLIENT_ID=console-ui
|
AUTHORITY_CLIENT_ID=console-ui
|
||||||
AUTHORITY_CLIENT_SECRET=<if using confidential client>
|
AUTHORITY_CLIENT_SECRET=<if using confidential client>
|
||||||
AUTHORITY_SCOPES=ui.read ui.admin
|
AUTHORITY_SCOPES=ui.read ui.admin
|
||||||
CONSOLE_GATEWAY_BASE_URL=https://api.acme.internal
|
CONSOLE_GATEWAY_BASE_URL=https://api.acme.internal
|
||||||
```
|
```
|
||||||
|
|
||||||
The compose bundle includes Traefik as reverse proxy with TLS termination. Update `traefik/dynamic/console.yml` for custom certificates or additional middlewares (CSP headers, rate limits).
|
The compose bundle includes Traefik as reverse proxy with TLS termination. Update `traefik/dynamic/console.yml` for custom certificates or additional middlewares (CSP headers, rate limits).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 4. Environment variables
|
## 4. Environment variables
|
||||||
|
|
||||||
| Variable | Description | Default |
|
| Variable | Description | Default |
|
||||||
|----------|-------------|---------|
|
|----------|-------------|---------|
|
||||||
| `CONSOLE_PUBLIC_BASE_URL` | External URL used for redirects, deep links, and telemetry. | None (required). |
|
| `CONSOLE_PUBLIC_BASE_URL` | External URL used for redirects, deep links, and telemetry. | None (required). |
|
||||||
| `CONSOLE_GATEWAY_BASE_URL` | URL of the web gateway that proxies API calls (`/console/*`). | Chart service name. |
|
| `CONSOLE_GATEWAY_BASE_URL` | URL of the web gateway that proxies API calls (`/console/*`). | Chart service name. |
|
||||||
| `AUTHORITY_ISSUER` | Authority issuer (`https://authority.example.com`). | None (required). |
|
| `AUTHORITY_ISSUER` | Authority issuer (`https://authority.example.com`). | None (required). |
|
||||||
| `AUTHORITY_CLIENT_ID` | OIDC client configured in Authority. | None (required). |
|
| `AUTHORITY_CLIENT_ID` | OIDC client configured in Authority. | None (required). |
|
||||||
| `AUTHORITY_SCOPES` | Space-separated scopes assigned to the console client. | `ui.read ui.admin`. |
|
| `AUTHORITY_SCOPES` | Space-separated scopes assigned to the console client. | `ui.read ui.admin`. |
|
||||||
| `AUTHORITY_DPOP_ENABLED` | Enables DPoP challenge/response (recommended true). | `true`. |
|
| `AUTHORITY_DPOP_ENABLED` | Enables DPoP challenge/response (recommended true). | `true`. |
|
||||||
| `CONSOLE_FEATURE_FLAGS` | Comma-separated feature flags (`runs`, `downloads.offline`, etc.). | `runs,downloads,policies`. |
|
| `CONSOLE_FEATURE_FLAGS` | Comma-separated feature flags (`runs`, `downloads.offline`, etc.). | `runs,downloads,policies`. |
|
||||||
| `CONSOLE_LOG_LEVEL` | Minimum log level (`Information`, `Debug`, etc.). | `Information`. |
|
| `CONSOLE_LOG_LEVEL` | Minimum log level (`Information`, `Debug`, etc.). | `Information`. |
|
||||||
| `CONSOLE_METRICS_ENABLED` | Expose `/metrics` endpoint. | `true`. |
|
| `CONSOLE_METRICS_ENABLED` | Expose `/metrics` endpoint. | `true`. |
|
||||||
| `CONSOLE_SENTRY_DSN` | Optional error reporting DSN. | Blank. |
|
| `CONSOLE_SENTRY_DSN` | Optional error reporting DSN. | Blank. |
|
||||||
|
|
||||||
When running behind additional proxies, set `ASPNETCORE_FORWARDEDHEADERS_ENABLED=true` to honour `X-Forwarded-*` headers.
|
When running behind additional proxies, set `ASPNETCORE_FORWARDEDHEADERS_ENABLED=true` to honour `X-Forwarded-*` headers.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 5. Security headers and CSP
|
## 5. Security headers and CSP
|
||||||
|
|
||||||
The console serves a strict Content Security Policy (CSP) by default:
|
The console serves a strict Content Security Policy (CSP) by default:
|
||||||
|
|
||||||
```
|
```
|
||||||
default-src 'self';
|
default-src 'self';
|
||||||
connect-src 'self' https://*.stella-ops.local;
|
connect-src 'self' https://*.stella-ops.local;
|
||||||
script-src 'self';
|
script-src 'self';
|
||||||
style-src 'self' 'unsafe-inline';
|
style-src 'self' 'unsafe-inline';
|
||||||
img-src 'self' data:;
|
img-src 'self' data:;
|
||||||
font-src 'self';
|
font-src 'self';
|
||||||
frame-ancestors 'none';
|
frame-ancestors 'none';
|
||||||
```
|
```
|
||||||
|
|
||||||
Adjust via `console.config.cspOverrides` if additional domains are required. For integrations embedding the console, update OIDC redirect URIs and Authority scopes accordingly.
|
Adjust via `console.config.cspOverrides` if additional domains are required. For integrations embedding the console, update OIDC redirect URIs and Authority scopes accordingly.
|
||||||
|
|
||||||
TLS recommendations:
|
TLS recommendations:
|
||||||
|
|
||||||
- Use TLS 1.2+ with modern cipher suite policy.
|
- Use TLS 1.2+ with modern cipher suite policy.
|
||||||
- Enable HSTS (`Strict-Transport-Security: max-age=31536000; includeSubDomains`).
|
- Enable HSTS (`Strict-Transport-Security: max-age=31536000; includeSubDomains`).
|
||||||
- Provide custom trust bundles via `console.config.trustBundleSecret` when using private CAs.
|
- Provide custom trust bundles via `console.config.trustBundleSecret` when using private CAs.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 6. Logging and metrics
|
## 6. Logging and metrics
|
||||||
|
|
||||||
- Structured logs emitted to stdout with correlation IDs. Configure log shipping via Fluent Bit or similar.
|
- Structured logs emitted to stdout with correlation IDs. Configure log shipping via Fluent Bit or similar.
|
||||||
- Metrics available at `/metrics` in Prometheus format. Key metrics include `ui_request_duration_seconds`, `ui_tenant_switch_total`, and `ui_download_manifest_refresh_seconds`.
|
- Metrics available at `/metrics` in Prometheus format. Key metrics include `ui_request_duration_seconds`, `ui_tenant_switch_total`, and `ui_download_manifest_refresh_seconds`.
|
||||||
- Enable OpenTelemetry exporter by setting `OTEL_EXPORTER_OTLP_ENDPOINT` and associated headers in environment variables.
|
- Enable OpenTelemetry exporter by setting `OTEL_EXPORTER_OTLP_ENDPOINT` and associated headers in environment variables.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 7. Offline and air-gap deployment
|
## 7. Offline and air-gap deployment
|
||||||
|
|
||||||
- Mirror container images using the Downloads workspace or Offline Kit manifest. Example:
|
- Mirror container images using the Downloads workspace or Offline Kit manifest. Example:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
oras copy registry.stella-ops.org/stellaops/web-ui@sha256:<digest> \
|
oras copy registry.stella-ops.org/stellaops/web-ui@sha256:<digest> \
|
||||||
registry.airgap.local/stellaops/web-ui:2025.10.0
|
registry.airgap.local/stellaops/web-ui:2025.10.0
|
||||||
```
|
```
|
||||||
|
|
||||||
- Import Offline Kit using `stella ouk import` before starting the console so manifest parity checks succeed.
|
- Import Offline Kit using `stella ouk import` before starting the console so manifest parity checks succeed.
|
||||||
- Use `values-airgap.yaml` to disable external telemetry endpoints and configure internal certificate chains.
|
- Use `values-airgap.yaml` to disable external telemetry endpoints and configure internal certificate chains.
|
||||||
- Run `helm upgrade --install` using the mirrored chart (`stellaops-<ver>.tgz`) and set `console.offlineMode=true` to surface offline banners.
|
- Run `helm upgrade --install` using the mirrored chart (`stellaops-<ver>.tgz`) and set `console.offlineMode=true` to surface offline banners.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 8. Health checks and remediation
|
## 8. Health checks and remediation
|
||||||
|
|
||||||
| Check | Command | Expected result |
|
| Check | Command | Expected result |
|
||||||
|-------|---------|-----------------|
|
|-------|---------|-----------------|
|
||||||
| Pod status | `kubectl get pods -n stellaops` | `Running` state with restarts = 0. |
|
| Pod status | `kubectl get pods -n stellaops` | `Running` state with restarts = 0. |
|
||||||
| Liveness | `kubectl exec deploy/stellaops-web-ui -- curl -fsS http://localhost:8080/health/live` | Returns `{"status":"Healthy"}`. |
|
| Liveness | `kubectl exec deploy/stellaops-web-ui -- curl -fsS http://localhost:8080/health/live` | Returns `{"status":"Healthy"}`. |
|
||||||
| Readiness | `kubectl exec deploy/stellaops-web-ui -- curl -fsS http://localhost:8080/health/ready` | Returns `{"status":"Ready"}`. |
|
| Readiness | `kubectl exec deploy/stellaops-web-ui -- curl -fsS http://localhost:8080/health/ready` | Returns `{"status":"Ready"}`. |
|
||||||
| Gateway reachability | `curl -I https://console.example.com/api/console/status` | `200 OK` with CSP headers. |
|
| Gateway reachability | `curl -I https://console.example.com/api/console/status` | `200 OK` with CSP headers. |
|
||||||
| Static assets | `curl -I https://console.example.com/static/assets/app.js` | `200 OK` with long cache headers. |
|
| Static assets | `curl -I https://console.example.com/static/assets/app.js` | `200 OK` with long cache headers. |
|
||||||
|
|
||||||
Troubleshooting steps:
|
Troubleshooting steps:
|
||||||
|
|
||||||
- **Authority unreachable:** readiness fails with `AUTHORITY_UNREACHABLE`. Check DNS, trust bundles, and Authority service health.
|
- **Authority unreachable:** readiness fails with `AUTHORITY_UNREACHABLE`. Check DNS, trust bundles, and Authority service health.
|
||||||
- **Manifest mismatch:** console logs `DOWNLOAD_MANIFEST_SIGNATURE_INVALID`. Verify cosign key and re-sync manifest.
|
- **Manifest mismatch:** console logs `DOWNLOAD_MANIFEST_SIGNATURE_INVALID`. Verify cosign key and re-sync manifest.
|
||||||
- **Ingress 404:** ensure ingress controller routes host to `stellaops-web-ui` service; check TLS secret name.
|
- **Ingress 404:** ensure ingress controller routes host to `stellaops-web-ui` service; check TLS secret name.
|
||||||
- **SSE blocked:** confirm proxy allows HTTP/1.1 and disables buffering on `/console/runs/*`.
|
- **SSE blocked:** confirm proxy allows HTTP/1.1 and disables buffering on `/console/runs/*`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 9. References
|
## 9. References
|
||||||
|
|
||||||
- `deploy/helm/stellaops/values-*.yaml` - environment-specific overrides.
|
- `deploy/helm/stellaops/values-*.yaml` - environment-specific overrides.
|
||||||
- `deploy/compose/docker-compose.console.yaml` - Compose bundle.
|
- `deploy/compose/docker-compose.console.yaml` - Compose bundle.
|
||||||
- `/docs/ui/downloads.md` - manifest and offline bundle guidance.
|
- `/docs/ui/downloads.md` - manifest and offline bundle guidance.
|
||||||
- `/docs/security/console-security.md` - CSP and Authority scopes.
|
- `/docs/security/console-security.md` - CSP and Authority scopes.
|
||||||
- `/docs/24_OFFLINE_KIT.md` - Offline kit packaging and verification.
|
- `/docs/24_OFFLINE_KIT.md` - Offline kit packaging and verification.
|
||||||
- `/docs/ops/deployment-runbook.md` (pending) - wider platform deployment steps.
|
- `/docs/ops/deployment-runbook.md` (pending) - wider platform deployment steps.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 10. Compliance checklist
|
## 10. Compliance checklist
|
||||||
|
|
||||||
- [ ] Helm and Compose instructions verified against `deploy/` assets.
|
- [ ] Helm and Compose instructions verified against `deploy/` assets.
|
||||||
- [ ] Ingress/TLS guidance aligns with Security Guild recommendations.
|
- [ ] Ingress/TLS guidance aligns with Security Guild recommendations.
|
||||||
- [ ] Environment variables documented with defaults and required values.
|
- [ ] Environment variables documented with defaults and required values.
|
||||||
- [ ] Health/liveness/readiness endpoints tested and listed.
|
- [ ] Health/liveness/readiness endpoints tested and listed.
|
||||||
- [ ] Offline workflow (mirrors, manifest parity) captured.
|
- [ ] Offline workflow (mirrors, manifest parity) captured.
|
||||||
- [ ] Logging and metrics surface documented metrics.
|
- [ ] Logging and metrics surface documented metrics.
|
||||||
- [ ] CSP and security header defaults stated alongside override guidance.
|
- [ ] CSP and security header defaults stated alongside override guidance.
|
||||||
- [ ] Troubleshooting section linked to relevant runbooks.
|
- [ ] Troubleshooting section linked to relevant runbooks.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
*Last updated: 2025-10-27 (Sprint 23).*
|
*Last updated: 2025-10-27 (Sprint 23).*
|
||||||
|
|||||||
@@ -1,160 +1,160 @@
|
|||||||
# Container Deployment Guide — AOC Update
|
# Container Deployment Guide — AOC Update
|
||||||
|
|
||||||
> **Audience:** DevOps Guild, platform operators deploying StellaOps services.
|
> **Audience:** DevOps Guild, platform operators deploying StellaOps services.
|
||||||
> **Scope:** Deployment configuration changes required by the Aggregation-Only Contract (AOC), including schema validators, guard environment flags, and verifier identities.
|
> **Scope:** Deployment configuration changes required by the Aggregation-Only Contract (AOC), including schema validators, guard environment flags, and verifier identities.
|
||||||
|
|
||||||
This guide supplements existing deployment manuals with AOC-specific configuration. It assumes familiarity with the base Compose/Helm manifests described in `ops/deployment/` and `docs/ARCHITECTURE_DEVOPS.md`.
|
This guide supplements existing deployment manuals with AOC-specific configuration. It assumes familiarity with the base Compose/Helm manifests described in `ops/deployment/` and `docs/ARCHITECTURE_DEVOPS.md`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 1 · Schema validator enablement
|
## 1 · Schema validator enablement
|
||||||
|
|
||||||
### 1.1 MongoDB validators
|
### 1.1 MongoDB validators
|
||||||
|
|
||||||
- Apply JSON schema validators to `advisory_raw` and `vex_raw` collections before enabling AOC guards.
|
- Apply JSON schema validators to `advisory_raw` and `vex_raw` collections before enabling AOC guards.
|
||||||
- Before enabling validators or the idempotency index, run the duplicate audit helper to confirm no conflicting raw advisories remain:
|
- Before enabling validators or the idempotency index, run the duplicate audit helper to confirm no conflicting raw advisories remain:
|
||||||
```bash
|
```bash
|
||||||
mongo concelier ops/devops/scripts/check-advisory-raw-duplicates.js --eval 'var LIMIT=200;'
|
mongo concelier ops/devops/scripts/check-advisory-raw-duplicates.js --eval 'var LIMIT=200;'
|
||||||
```
|
```
|
||||||
Resolve any reported rows prior to rollout.
|
Resolve any reported rows prior to rollout.
|
||||||
- Use the migration script provided in `ops/devops/scripts/apply-aoc-validators.js`:
|
- Use the migration script provided in `ops/devops/scripts/apply-aoc-validators.js`:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl exec -n concelier deploy/concelier-mongo -- \
|
kubectl exec -n concelier deploy/concelier-mongo -- \
|
||||||
mongo concelier ops/devops/scripts/apply-aoc-validators.js
|
mongo concelier ops/devops/scripts/apply-aoc-validators.js
|
||||||
|
|
||||||
kubectl exec -n excititor deploy/excititor-mongo -- \
|
kubectl exec -n excititor deploy/excititor-mongo -- \
|
||||||
mongo excititor ops/devops/scripts/apply-aoc-validators.js
|
mongo excititor ops/devops/scripts/apply-aoc-validators.js
|
||||||
```
|
```
|
||||||
|
|
||||||
- Validators enforce required fields (`tenant`, `source`, `upstream`, `linkset`) and reject forbidden keys at DB level.
|
- Validators enforce required fields (`tenant`, `source`, `upstream`, `linkset`) and reject forbidden keys at DB level.
|
||||||
- Rollback plan: validators are applied with `validationLevel: moderate`—downgrade via the same script with `--remove` if required.
|
- Rollback plan: validators are applied with `validationLevel: moderate`—downgrade via the same script with `--remove` if required.
|
||||||
|
|
||||||
### 1.2 Migration order
|
### 1.2 Migration order
|
||||||
|
|
||||||
1. Deploy validators in maintenance window.
|
1. Deploy validators in maintenance window.
|
||||||
2. Roll out Concelier/Excititor images with guard middleware enabled (`AOC_GUARD_ENABLED=true`).
|
2. Roll out Concelier/Excititor images with guard middleware enabled (`AOC_GUARD_ENABLED=true`).
|
||||||
3. Run smoke tests (`stella sources ingest --dry-run` fixtures) before resuming production ingestion.
|
3. Run smoke tests (`stella sources ingest --dry-run` fixtures) before resuming production ingestion.
|
||||||
|
|
||||||
### 1.3 Supersedes backfill verification
|
### 1.3 Supersedes backfill verification
|
||||||
|
|
||||||
1. **Duplicate audit:** Confirm `mongo concelier ops/devops/scripts/check-advisory-raw-duplicates.js --eval 'var LIMIT=200;'` reports no conflicts before restarting Concelier with the new migrations.
|
1. **Duplicate audit:** Confirm `mongo concelier ops/devops/scripts/check-advisory-raw-duplicates.js --eval 'var LIMIT=200;'` reports no conflicts before restarting Concelier with the new migrations.
|
||||||
2. **Post-migration check:** After the service restarts, validate that `db.advisory` is a view pointing to `advisory_backup_20251028`:
|
2. **Post-migration check:** After the service restarts, validate that `db.advisory` is a view pointing to `advisory_backup_20251028`:
|
||||||
```bash
|
```bash
|
||||||
mongo concelier --quiet --eval 'db.getCollectionInfos({ name: "advisory" })[0]'
|
mongo concelier --quiet --eval 'db.getCollectionInfos({ name: "advisory" })[0]'
|
||||||
```
|
```
|
||||||
The `type` should be `"view"` and `options.viewOn` should equal `"advisory_backup_20251028"`.
|
The `type` should be `"view"` and `options.viewOn` should equal `"advisory_backup_20251028"`.
|
||||||
3. **Supersedes chain spot-check:** Inspect a sample set to ensure deterministic chaining:
|
3. **Supersedes chain spot-check:** Inspect a sample set to ensure deterministic chaining:
|
||||||
```bash
|
```bash
|
||||||
mongo concelier --quiet --eval '
|
mongo concelier --quiet --eval '
|
||||||
db.advisory_raw.aggregate([
|
db.advisory_raw.aggregate([
|
||||||
{ $match: { "upstream.upstream_id": { $exists: true } } },
|
{ $match: { "upstream.upstream_id": { $exists: true } } },
|
||||||
{ $sort: { "tenant": 1, "source.vendor": 1, "upstream.upstream_id": 1, "upstream.retrieved_at": 1 } },
|
{ $sort: { "tenant": 1, "source.vendor": 1, "upstream.upstream_id": 1, "upstream.retrieved_at": 1 } },
|
||||||
{ $limit: 5 },
|
{ $limit: 5 },
|
||||||
{ $project: { _id: 1, supersedes: 1 } }
|
{ $project: { _id: 1, supersedes: 1 } }
|
||||||
]).forEach(printjson)'
|
]).forEach(printjson)'
|
||||||
```
|
```
|
||||||
Each revision should reference the previous `_id` (or `null` for the first revision). Record findings in the change ticket before proceeding to production.
|
Each revision should reference the previous `_id` (or `null` for the first revision). Record findings in the change ticket before proceeding to production.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 2 · Container environment flags
|
## 2 · Container environment flags
|
||||||
|
|
||||||
Add the following environment variables to Concelier/Excititor deployments:
|
Add the following environment variables to Concelier/Excititor deployments:
|
||||||
|
|
||||||
| Variable | Default | Description |
|
| Variable | Default | Description |
|
||||||
|----------|---------|-------------|
|
|----------|---------|-------------|
|
||||||
| `AOC_GUARD_ENABLED` | `true` | Enables `AOCWriteGuard` interception. Set `false` only for controlled rollback. |
|
| `AOC_GUARD_ENABLED` | `true` | Enables `AOCWriteGuard` interception. Set `false` only for controlled rollback. |
|
||||||
| `AOC_ALLOW_SUPERSEDES_RETROFIT` | `false` | Allows temporary supersedes backfill during migration. Remove after cutover. |
|
| `AOC_ALLOW_SUPERSEDES_RETROFIT` | `false` | Allows temporary supersedes backfill during migration. Remove after cutover. |
|
||||||
| `AOC_METRICS_ENABLED` | `true` | Emits `ingestion_write_total`, `aoc_violation_total`, etc. |
|
| `AOC_METRICS_ENABLED` | `true` | Emits `ingestion_write_total`, `aoc_violation_total`, etc. |
|
||||||
| `AOC_TENANT_HEADER` | `X-Stella-Tenant` | Header name expected from Gateway. |
|
| `AOC_TENANT_HEADER` | `X-Stella-Tenant` | Header name expected from Gateway. |
|
||||||
| `AOC_VERIFIER_USER` | `stella-aoc-verify` | Read-only service user used by UI/CLI verification. |
|
| `AOC_VERIFIER_USER` | `stella-aoc-verify` | Read-only service user used by UI/CLI verification. |
|
||||||
|
|
||||||
Compose snippet:
|
Compose snippet:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
environment:
|
environment:
|
||||||
- AOC_GUARD_ENABLED=true
|
- AOC_GUARD_ENABLED=true
|
||||||
- AOC_ALLOW_SUPERSEDES_RETROFIT=false
|
- AOC_ALLOW_SUPERSEDES_RETROFIT=false
|
||||||
- AOC_METRICS_ENABLED=true
|
- AOC_METRICS_ENABLED=true
|
||||||
- AOC_TENANT_HEADER=X-Stella-Tenant
|
- AOC_TENANT_HEADER=X-Stella-Tenant
|
||||||
- AOC_VERIFIER_USER=stella-aoc-verify
|
- AOC_VERIFIER_USER=stella-aoc-verify
|
||||||
```
|
```
|
||||||
|
|
||||||
Ensure `AOC_VERIFIER_USER` exists in Authority with `aoc:verify` scope and no write permissions.
|
Ensure `AOC_VERIFIER_USER` exists in Authority with `aoc:verify` scope and no write permissions.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 3 · Verifier identity
|
## 3 · Verifier identity
|
||||||
|
|
||||||
- Create a dedicated client (`stella-aoc-verify`) via Authority bootstrap:
|
- Create a dedicated client (`stella-aoc-verify`) via Authority bootstrap:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
clients:
|
clients:
|
||||||
- clientId: stella-aoc-verify
|
- clientId: stella-aoc-verify
|
||||||
grantTypes: [client_credentials]
|
grantTypes: [client_credentials]
|
||||||
scopes: [aoc:verify, advisory:read, vex:read]
|
scopes: [aoc:verify, advisory:read, vex:read]
|
||||||
tenants: [default]
|
tenants: [default]
|
||||||
```
|
```
|
||||||
|
|
||||||
- Store credentials in secret store (`Kubernetes Secret`, `Docker swarm secret`).
|
- Store credentials in secret store (`Kubernetes Secret`, `Docker swarm secret`).
|
||||||
- Bind credentials to `stella aoc verify` CI jobs and Console verification service.
|
- Bind credentials to `stella aoc verify` CI jobs and Console verification service.
|
||||||
- Rotate quarterly; document in `ops/authority-key-rotation.md`.
|
- Rotate quarterly; document in `ops/authority-key-rotation.md`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 4 · Deployment steps
|
## 4 · Deployment steps
|
||||||
|
|
||||||
1. **Pre-checks:** Confirm database backups, alerting in maintenance mode, and staging environment validated.
|
1. **Pre-checks:** Confirm database backups, alerting in maintenance mode, and staging environment validated.
|
||||||
2. **Apply validators:** Run scripts per § 1.1.
|
2. **Apply validators:** Run scripts per § 1.1.
|
||||||
3. **Update manifests:** Inject environment variables (§ 2) and mount guard configuration configmaps.
|
3. **Update manifests:** Inject environment variables (§ 2) and mount guard configuration configmaps.
|
||||||
4. **Redeploy services:** Rolling restart Concelier/Excititor pods. Monitor `ingestion_write_total` for steady throughput.
|
4. **Redeploy services:** Rolling restart Concelier/Excititor pods. Monitor `ingestion_write_total` for steady throughput.
|
||||||
5. **Seed verifier:** Deploy read-only verifier user and store credentials.
|
5. **Seed verifier:** Deploy read-only verifier user and store credentials.
|
||||||
6. **Run verification:** Execute `stella aoc verify --since 24h` and ensure exit code `0`.
|
6. **Run verification:** Execute `stella aoc verify --since 24h` and ensure exit code `0`.
|
||||||
7. **Update dashboards:** Point Grafana panels to new metrics (`aoc_violation_total`).
|
7. **Update dashboards:** Point Grafana panels to new metrics (`aoc_violation_total`).
|
||||||
8. **Record handoff:** Capture console screenshots and verification logs for release notes.
|
8. **Record handoff:** Capture console screenshots and verification logs for release notes.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 5 · Offline Kit updates
|
## 5 · Offline Kit updates
|
||||||
|
|
||||||
- Ship validator scripts with Offline Kit (`offline-kit/scripts/apply-aoc-validators.js`).
|
- Ship validator scripts with Offline Kit (`offline-kit/scripts/apply-aoc-validators.js`).
|
||||||
- Include pre-generated verification reports for air-gapped deployments.
|
- Include pre-generated verification reports for air-gapped deployments.
|
||||||
- Document offline CLI workflow in bundle README referencing `docs/cli/cli-reference.md`.
|
- Document offline CLI workflow in bundle README referencing `docs/cli/cli-reference.md`.
|
||||||
- Ensure `stella-aoc-verify` credentials are scoped to offline tenant and rotated during bundle refresh.
|
- Ensure `stella-aoc-verify` credentials are scoped to offline tenant and rotated during bundle refresh.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 6 · Rollback plan
|
## 6 · Rollback plan
|
||||||
|
|
||||||
1. Disable guard via `AOC_GUARD_ENABLED=false` on Concelier/Excititor and rollout.
|
1. Disable guard via `AOC_GUARD_ENABLED=false` on Concelier/Excititor and rollout.
|
||||||
2. Remove validators with the migration script (`--remove`).
|
2. Remove validators with the migration script (`--remove`).
|
||||||
3. Pause verification jobs to prevent noise.
|
3. Pause verification jobs to prevent noise.
|
||||||
4. Investigate and remediate upstream issues before re-enabling guards.
|
4. Investigate and remediate upstream issues before re-enabling guards.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 7 · References
|
## 7 · References
|
||||||
|
|
||||||
- [Aggregation-Only Contract reference](../ingestion/aggregation-only-contract.md)
|
- [Aggregation-Only Contract reference](../ingestion/aggregation-only-contract.md)
|
||||||
- [Authority scopes & tenancy](../security/authority-scopes.md)
|
- [Authority scopes & tenancy](../security/authority-scopes.md)
|
||||||
- [Observability guide](../observability/observability.md)
|
- [Observability guide](../observability/observability.md)
|
||||||
- [CLI AOC commands](../cli/cli-reference.md)
|
- [CLI AOC commands](../cli/cli-reference.md)
|
||||||
- [Concelier architecture](../ARCHITECTURE_CONCELIER.md)
|
- [Concelier architecture](../ARCHITECTURE_CONCELIER.md)
|
||||||
- [Excititor architecture](../ARCHITECTURE_EXCITITOR.md)
|
- [Excititor architecture](../ARCHITECTURE_EXCITITOR.md)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 8 · Compliance checklist
|
## 8 · Compliance checklist
|
||||||
|
|
||||||
- [ ] Validators documented and scripts referenced for online/offline deployments.
|
- [ ] Validators documented and scripts referenced for online/offline deployments.
|
||||||
- [ ] Environment variables cover guard enablement, metrics, and tenant header.
|
- [ ] Environment variables cover guard enablement, metrics, and tenant header.
|
||||||
- [ ] Read-only verifier user installation steps included.
|
- [ ] Read-only verifier user installation steps included.
|
||||||
- [ ] Offline kit instructions align with validator/verification workflow.
|
- [ ] Offline kit instructions align with validator/verification workflow.
|
||||||
- [ ] Rollback procedure captured.
|
- [ ] Rollback procedure captured.
|
||||||
- [ ] Cross-links to AOC docs, Authority scopes, and observability guides present.
|
- [ ] Cross-links to AOC docs, Authority scopes, and observability guides present.
|
||||||
- [ ] DevOps Guild sign-off tracked (owner: @devops-guild, due 2025-10-29).
|
- [ ] DevOps Guild sign-off tracked (owner: @devops-guild, due 2025-10-29).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
*Last updated: 2025-10-26 (Sprint 19).*
|
*Last updated: 2025-10-26 (Sprint 19).*
|
||||||
|
|||||||
@@ -1,220 +1,220 @@
|
|||||||
# Excititor Connector Packaging Guide
|
# Excititor Connector Packaging Guide
|
||||||
|
|
||||||
> **Audience:** teams implementing new Excititor provider plug‑ins (CSAF feeds,
|
> **Audience:** teams implementing new Excititor provider plug‑ins (CSAF feeds,
|
||||||
> OpenVEX attestations, etc.)
|
> OpenVEX attestations, etc.)
|
||||||
> **Prerequisites:** read `docs/ARCHITECTURE_EXCITITOR.md` and the module
|
> **Prerequisites:** read `docs/ARCHITECTURE_EXCITITOR.md` and the module
|
||||||
> `AGENTS.md` in `src/StellaOps.Excititor.Connectors.Abstractions/`.
|
> `AGENTS.md` in `src/Excititor/__Libraries/StellaOps.Excititor.Connectors.Abstractions/`.
|
||||||
|
|
||||||
The Excititor connector SDK gives you:
|
The Excititor connector SDK gives you:
|
||||||
|
|
||||||
- `VexConnectorBase` – deterministic logging, SHA‑256 helpers, time provider.
|
- `VexConnectorBase` – deterministic logging, SHA‑256 helpers, time provider.
|
||||||
- `VexConnectorOptionsBinder` – strongly typed YAML/JSON configuration binding.
|
- `VexConnectorOptionsBinder` – strongly typed YAML/JSON configuration binding.
|
||||||
- `IVexConnectorOptionsValidator<T>` – custom validation hooks (offline defaults, auth invariants).
|
- `IVexConnectorOptionsValidator<T>` – custom validation hooks (offline defaults, auth invariants).
|
||||||
- `VexConnectorDescriptor` & metadata helpers for consistent telemetry.
|
- `VexConnectorDescriptor` & metadata helpers for consistent telemetry.
|
||||||
|
|
||||||
This guide explains how to package a connector so the Excititor Worker/WebService
|
This guide explains how to package a connector so the Excititor Worker/WebService
|
||||||
can load it via the plugin host.
|
can load it via the plugin host.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 1. Project layout
|
## 1. Project layout
|
||||||
|
|
||||||
Start from the template under
|
Start from the template under
|
||||||
`docs/dev/templates/excititor-connector/`. It contains:
|
`docs/dev/templates/excititor-connector/`. It contains:
|
||||||
|
|
||||||
```
|
```
|
||||||
Excititor.MyConnector/
|
Excititor.MyConnector/
|
||||||
├── src/
|
├── src/
|
||||||
│ ├── Excititor.MyConnector.csproj
|
│ ├── Excititor.MyConnector.csproj
|
||||||
│ ├── MyConnectorOptions.cs
|
│ ├── MyConnectorOptions.cs
|
||||||
│ ├── MyConnector.cs
|
│ ├── MyConnector.cs
|
||||||
│ └── MyConnectorPlugin.cs
|
│ └── MyConnectorPlugin.cs
|
||||||
└── manifest/
|
└── manifest/
|
||||||
└── connector.manifest.yaml
|
└── connector.manifest.yaml
|
||||||
```
|
```
|
||||||
|
|
||||||
Key points:
|
Key points:
|
||||||
|
|
||||||
- Target `net10.0`, enable `TreatWarningsAsErrors`, reference the
|
- Target `net10.0`, enable `TreatWarningsAsErrors`, reference the
|
||||||
`StellaOps.Excititor.Connectors.Abstractions` project (or NuGet once published).
|
`StellaOps.Excititor.Connectors.Abstractions` project (or NuGet once published).
|
||||||
- Keep project ID prefix `StellaOps.Excititor.Connectors.<Provider>` so the
|
- Keep project ID prefix `StellaOps.Excititor.Connectors.<Provider>` so the
|
||||||
plugin loader can discover it with the default search pattern.
|
plugin loader can discover it with the default search pattern.
|
||||||
|
|
||||||
### 1.1 csproj snippet
|
### 1.1 csproj snippet
|
||||||
|
|
||||||
```xml
|
```xml
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net10.0</TargetFramework>
|
<TargetFramework>net10.0</TargetFramework>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\..\src\StellaOps.Excititor.Connectors.Abstractions\StellaOps.Excititor.Connectors.Abstractions.csproj" />
|
<ProjectReference Include="..\..\..\src\StellaOps.Excititor.Connectors.Abstractions\StellaOps.Excititor.Connectors.Abstractions.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
```
|
```
|
||||||
|
|
||||||
Adjust the `ProjectReference` for your checkout (or switch to a NuGet package
|
Adjust the `ProjectReference` for your checkout (or switch to a NuGet package
|
||||||
once published).
|
once published).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 2. Implement the connector
|
## 2. Implement the connector
|
||||||
|
|
||||||
1. **Options model** – create an options POCO with data-annotation attributes.
|
1. **Options model** – create an options POCO with data-annotation attributes.
|
||||||
Bind it via `VexConnectorOptionsBinder.Bind<TOptions>` in your connector
|
Bind it via `VexConnectorOptionsBinder.Bind<TOptions>` in your connector
|
||||||
constructor or `ValidateAsync`.
|
constructor or `ValidateAsync`.
|
||||||
2. **Validator** – implement `IVexConnectorOptionsValidator<TOptions>` to add
|
2. **Validator** – implement `IVexConnectorOptionsValidator<TOptions>` to add
|
||||||
complex checks (e.g., ensure both `clientId` and `clientSecret` are present).
|
complex checks (e.g., ensure both `clientId` and `clientSecret` are present).
|
||||||
3. **Connector** – inherit from `VexConnectorBase`. Implement:
|
3. **Connector** – inherit from `VexConnectorBase`. Implement:
|
||||||
- `ValidateAsync` – run binder/validators, log configuration summary.
|
- `ValidateAsync` – run binder/validators, log configuration summary.
|
||||||
- `FetchAsync` – stream raw documents to `context.RawSink`.
|
- `FetchAsync` – stream raw documents to `context.RawSink`.
|
||||||
- `NormalizeAsync` – convert raw documents into `VexClaimBatch` via
|
- `NormalizeAsync` – convert raw documents into `VexClaimBatch` via
|
||||||
format-specific normalizers (`context.Normalizers`).
|
format-specific normalizers (`context.Normalizers`).
|
||||||
4. **Plugin adapter** – expose the connector via a plugin entry point so the
|
4. **Plugin adapter** – expose the connector via a plugin entry point so the
|
||||||
host can instantiate it.
|
host can instantiate it.
|
||||||
|
|
||||||
### 2.1 Options binding example
|
### 2.1 Options binding example
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
public sealed class MyConnectorOptions
|
public sealed class MyConnectorOptions
|
||||||
{
|
{
|
||||||
[Required]
|
[Required]
|
||||||
[Url]
|
[Url]
|
||||||
public string CatalogUri { get; set; } = default!;
|
public string CatalogUri { get; set; } = default!;
|
||||||
|
|
||||||
[Required]
|
[Required]
|
||||||
public string ApiKey { get; set; } = default!;
|
public string ApiKey { get; set; } = default!;
|
||||||
|
|
||||||
[Range(1, 64)]
|
[Range(1, 64)]
|
||||||
public int MaxParallelRequests { get; set; } = 4;
|
public int MaxParallelRequests { get; set; } = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class MyConnectorOptionsValidator : IVexConnectorOptionsValidator<MyConnectorOptions>
|
public sealed class MyConnectorOptionsValidator : IVexConnectorOptionsValidator<MyConnectorOptions>
|
||||||
{
|
{
|
||||||
public void Validate(VexConnectorDescriptor descriptor, MyConnectorOptions options, IList<string> errors)
|
public void Validate(VexConnectorDescriptor descriptor, MyConnectorOptions options, IList<string> errors)
|
||||||
{
|
{
|
||||||
if (!options.CatalogUri.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
|
if (!options.CatalogUri.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
errors.Add("CatalogUri must use HTTPS.");
|
errors.Add("CatalogUri must use HTTPS.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Bind inside the connector:
|
Bind inside the connector:
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
private readonly MyConnectorOptions _options;
|
private readonly MyConnectorOptions _options;
|
||||||
|
|
||||||
public MyConnector(VexConnectorDescriptor descriptor, ILogger<MyConnector> logger, TimeProvider timeProvider)
|
public MyConnector(VexConnectorDescriptor descriptor, ILogger<MyConnector> logger, TimeProvider timeProvider)
|
||||||
: base(descriptor, logger, timeProvider)
|
: base(descriptor, logger, timeProvider)
|
||||||
{
|
{
|
||||||
// `settings` comes from the orchestrator; validators registered via DI.
|
// `settings` comes from the orchestrator; validators registered via DI.
|
||||||
_options = VexConnectorOptionsBinder.Bind<MyConnectorOptions>(
|
_options = VexConnectorOptionsBinder.Bind<MyConnectorOptions>(
|
||||||
descriptor,
|
descriptor,
|
||||||
VexConnectorSettings.Empty,
|
VexConnectorSettings.Empty,
|
||||||
validators: new[] { new MyConnectorOptionsValidator() });
|
validators: new[] { new MyConnectorOptionsValidator() });
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Replace `VexConnectorSettings.Empty` with the actual settings from context
|
Replace `VexConnectorSettings.Empty` with the actual settings from context
|
||||||
inside `ValidateAsync`.
|
inside `ValidateAsync`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 3. Plugin adapter & manifest
|
## 3. Plugin adapter & manifest
|
||||||
|
|
||||||
Create a simple plugin class that implements
|
Create a simple plugin class that implements
|
||||||
`StellaOps.Plugin.IConnectorPlugin`. The Worker/WebService plugin host uses
|
`StellaOps.Plugin.IConnectorPlugin`. The Worker/WebService plugin host uses
|
||||||
this contract today.
|
this contract today.
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
public sealed class MyConnectorPlugin : IConnectorPlugin
|
public sealed class MyConnectorPlugin : IConnectorPlugin
|
||||||
{
|
{
|
||||||
private static readonly VexConnectorDescriptor Descriptor =
|
private static readonly VexConnectorDescriptor Descriptor =
|
||||||
new("excititor:my-provider", VexProviderKind.Vendor, "My Provider VEX");
|
new("excititor:my-provider", VexProviderKind.Vendor, "My Provider VEX");
|
||||||
|
|
||||||
public string Name => Descriptor.DisplayName;
|
public string Name => Descriptor.DisplayName;
|
||||||
|
|
||||||
public bool IsAvailable(IServiceProvider services) => true; // inject feature flags if needed
|
public bool IsAvailable(IServiceProvider services) => true; // inject feature flags if needed
|
||||||
|
|
||||||
public IFeedConnector Create(IServiceProvider services)
|
public IFeedConnector Create(IServiceProvider services)
|
||||||
{
|
{
|
||||||
var logger = services.GetRequiredService<ILogger<MyConnector>>();
|
var logger = services.GetRequiredService<ILogger<MyConnector>>();
|
||||||
var timeProvider = services.GetRequiredService<TimeProvider>();
|
var timeProvider = services.GetRequiredService<TimeProvider>();
|
||||||
return new MyConnector(Descriptor, logger, timeProvider);
|
return new MyConnector(Descriptor, logger, timeProvider);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
> **Note:** the Excititor Worker currently instantiates connectors through the
|
> **Note:** the Excititor Worker currently instantiates connectors through the
|
||||||
> shared `IConnectorPlugin` contract. Once a dedicated Excititor plugin interface
|
> shared `IConnectorPlugin` contract. Once a dedicated Excititor plugin interface
|
||||||
> lands you simply swap the base interface; the descriptor/connector code
|
> lands you simply swap the base interface; the descriptor/connector code
|
||||||
> remains unchanged.
|
> remains unchanged.
|
||||||
|
|
||||||
Provide a manifest describing the assembly for operational tooling:
|
Provide a manifest describing the assembly for operational tooling:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
# manifest/connector.manifest.yaml
|
# manifest/connector.manifest.yaml
|
||||||
id: excititor-my-provider
|
id: excititor-my-provider
|
||||||
assembly: StellaOps.Excititor.Connectors.MyProvider.dll
|
assembly: StellaOps.Excititor.Connectors.MyProvider.dll
|
||||||
entryPoint: StellaOps.Excititor.Connectors.MyProvider.MyConnectorPlugin
|
entryPoint: StellaOps.Excititor.Connectors.MyProvider.MyConnectorPlugin
|
||||||
description: >
|
description: >
|
||||||
Official VEX feed for ExampleCorp products (CSAF JSON, daily updates).
|
Official VEX feed for ExampleCorp products (CSAF JSON, daily updates).
|
||||||
tags:
|
tags:
|
||||||
- excititor
|
- excititor
|
||||||
- csaf
|
- csaf
|
||||||
- vendor
|
- vendor
|
||||||
```
|
```
|
||||||
|
|
||||||
Store manifests under `/opt/stella/excititor/plugins/<connector>/manifest/` in
|
Store manifests under `/opt/stella/excititor/plugins/<connector>/manifest/` in
|
||||||
production so the deployment tooling can inventory and verify plug‑ins.
|
production so the deployment tooling can inventory and verify plug‑ins.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 4. Packaging workflow
|
## 4. Packaging workflow
|
||||||
|
|
||||||
1. `dotnet publish -c Release` → copy the published DLLs to
|
1. `dotnet publish -c Release` → copy the published DLLs to
|
||||||
`/opt/stella/excititor/plugins/<Provider>/`.
|
`/opt/stella/excititor/plugins/<Provider>/`.
|
||||||
2. Place `connector.manifest.yaml` next to the binaries.
|
2. Place `connector.manifest.yaml` next to the binaries.
|
||||||
3. Restart the Excititor Worker or WebService (hot reload not supported yet).
|
3. Restart the Excititor Worker or WebService (hot reload not supported yet).
|
||||||
4. Verify logs: `VEX-ConnectorLoader` should list the connector descriptor.
|
4. Verify logs: `VEX-ConnectorLoader` should list the connector descriptor.
|
||||||
|
|
||||||
### 4.1 Offline kits
|
### 4.1 Offline kits
|
||||||
|
|
||||||
- Add the connector folder (binaries + manifest) to the Offline Kit bundle.
|
- Add the connector folder (binaries + manifest) to the Offline Kit bundle.
|
||||||
- Include a `settings.sample.yaml` demonstrating offline-friendly defaults.
|
- Include a `settings.sample.yaml` demonstrating offline-friendly defaults.
|
||||||
- Document any external dependencies (e.g., SHA mirrors) in the manifest `notes`
|
- Document any external dependencies (e.g., SHA mirrors) in the manifest `notes`
|
||||||
field.
|
field.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 5. Testing checklist
|
## 5. Testing checklist
|
||||||
|
|
||||||
- Unit tests around options binding & validators.
|
- Unit tests around options binding & validators.
|
||||||
- Integration tests (future `StellaOps.Excititor.Connectors.Abstractions.Tests`)
|
- Integration tests (future `StellaOps.Excititor.Connectors.Abstractions.Tests`)
|
||||||
verifying deterministic logging scopes:
|
verifying deterministic logging scopes:
|
||||||
`logger.BeginScope` should produce `vex.connector.id`, `vex.connector.kind`,
|
`logger.BeginScope` should produce `vex.connector.id`, `vex.connector.kind`,
|
||||||
and `vex.connector.operation`.
|
and `vex.connector.operation`.
|
||||||
- Deterministic SHA tests: repeated `CreateRawDocument` calls with identical
|
- Deterministic SHA tests: repeated `CreateRawDocument` calls with identical
|
||||||
content must return the same digest.
|
content must return the same digest.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 6. Reference template
|
## 6. Reference template
|
||||||
|
|
||||||
See `docs/dev/templates/excititor-connector/` for the full quick‑start including:
|
See `docs/dev/templates/excititor-connector/` for the full quick‑start including:
|
||||||
|
|
||||||
- Sample options class + validator.
|
- Sample options class + validator.
|
||||||
- Connector implementation inheriting from `VexConnectorBase`.
|
- Connector implementation inheriting from `VexConnectorBase`.
|
||||||
- Plugin adapter + manifest.
|
- Plugin adapter + manifest.
|
||||||
|
|
||||||
Copy the directory, rename namespaces/IDs, then iterate on provider-specific
|
Copy the directory, rename namespaces/IDs, then iterate on provider-specific
|
||||||
logic.
|
logic.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
*Last updated: 2025-10-17*
|
*Last updated: 2025-10-17*
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
> **Audience:** teams implementing new Vexer provider plug‑ins (CSAF feeds,
|
> **Audience:** teams implementing new Vexer provider plug‑ins (CSAF feeds,
|
||||||
> OpenVEX attestations, etc.)
|
> OpenVEX attestations, etc.)
|
||||||
> **Prerequisites:** read `docs/ARCHITECTURE_VEXER.md` and the module
|
> **Prerequisites:** read `docs/ARCHITECTURE_VEXER.md` and the module
|
||||||
> `AGENTS.md` in `src/StellaOps.Vexer.Connectors.Abstractions/`.
|
> `AGENTS.md` in `src/Excititor/__Libraries/StellaOps.Excititor.Connectors.Abstractions/`.
|
||||||
|
|
||||||
The Vexer connector SDK gives you:
|
The Vexer connector SDK gives you:
|
||||||
|
|
||||||
|
|||||||
@@ -1,212 +1,212 @@
|
|||||||
# Authority Plug-in Developer Guide
|
# Authority Plug-in Developer Guide
|
||||||
|
|
||||||
> **Status:** Updated 2025-10-11 (AUTHPLUG-DOCS-01-001) with lifecycle + limiter diagrams and refreshed rate-limit guidance aligned to PLG6 acceptance criteria.
|
> **Status:** Updated 2025-10-11 (AUTHPLUG-DOCS-01-001) with lifecycle + limiter diagrams and refreshed rate-limit guidance aligned to PLG6 acceptance criteria.
|
||||||
|
|
||||||
## 1. Overview
|
## 1. Overview
|
||||||
Authority plug-ins extend the **StellaOps Authority** service with custom identity providers, credential stores, and client-management logic. Unlike Concelier plug-ins (which ingest or export advisories), Authority plug-ins participate directly in authentication flows:
|
Authority plug-ins extend the **StellaOps Authority** service with custom identity providers, credential stores, and client-management logic. Unlike Concelier plug-ins (which ingest or export advisories), Authority plug-ins participate directly in authentication flows:
|
||||||
|
|
||||||
- **Use cases:** integrate corporate directories (LDAP/AD)[^ldap-rfc], delegate to external IDPs, enforce bespoke password/lockout policies, or add client provisioning automation.
|
- **Use cases:** integrate corporate directories (LDAP/AD)[^ldap-rfc], delegate to external IDPs, enforce bespoke password/lockout policies, or add client provisioning automation.
|
||||||
- **Constraints:** plug-ins load only during service start (no hot-reload), must function without outbound internet access, and must emit deterministic results for identical configuration input.
|
- **Constraints:** plug-ins load only during service start (no hot-reload), must function without outbound internet access, and must emit deterministic results for identical configuration input.
|
||||||
- **Ship targets:** build against the host’s .NET 10 preview SDK, honour offline-first requirements, and surface actionable diagnostics so operators can triage issues from `/ready`.
|
- **Ship targets:** build against the host’s .NET 10 preview SDK, honour offline-first requirements, and surface actionable diagnostics so operators can triage issues from `/ready`.
|
||||||
|
|
||||||
## 2. Architecture Snapshot
|
## 2. Architecture Snapshot
|
||||||
Authority hosts follow a deterministic plug-in lifecycle. The exported diagram (`docs/assets/authority/authority-plugin-lifecycle.svg`) mirrors the steps below; regenerate it from the Mermaid source if you update the flow.
|
Authority hosts follow a deterministic plug-in lifecycle. The exported diagram (`docs/assets/authority/authority-plugin-lifecycle.svg`) mirrors the steps below; regenerate it from the Mermaid source if you update the flow.
|
||||||
|
|
||||||
1. **Configuration load** – `AuthorityPluginConfigurationLoader` resolves YAML manifests under `etc/authority.plugins/`.
|
1. **Configuration load** – `AuthorityPluginConfigurationLoader` resolves YAML manifests under `etc/authority.plugins/`.
|
||||||
2. **Assembly discovery** – the shared `PluginHost` scans `StellaOps.Authority.PluginBinaries` for `StellaOps.Authority.Plugin.*.dll` assemblies.
|
2. **Assembly discovery** – the shared `PluginHost` scans `StellaOps.Authority.PluginBinaries` for `StellaOps.Authority.Plugin.*.dll` assemblies.
|
||||||
3. **Registrar execution** – each assembly is searched for `IAuthorityPluginRegistrar` implementations. Registrars bind options, register services, and optionally queue bootstrap tasks.
|
3. **Registrar execution** – each assembly is searched for `IAuthorityPluginRegistrar` implementations. Registrars bind options, register services, and optionally queue bootstrap tasks.
|
||||||
4. **Runtime** – the host resolves `IIdentityProviderPlugin` instances, uses capability metadata to decide which OAuth grants to expose, and invokes health checks for readiness endpoints.
|
4. **Runtime** – the host resolves `IIdentityProviderPlugin` instances, uses capability metadata to decide which OAuth grants to expose, and invokes health checks for readiness endpoints.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
_Source:_ `docs/assets/authority/authority-plugin-lifecycle.mmd`
|
_Source:_ `docs/assets/authority/authority-plugin-lifecycle.mmd`
|
||||||
|
|
||||||
**Data persistence primer:** the standard Mongo-backed plugin stores users in collections named `authority_users_<pluginName>` and lockout metadata in embedded documents. Additional plugins must document their storage layout and provide deterministic collection naming to honour the Offline Kit replication process.
|
**Data persistence primer:** the standard Mongo-backed plugin stores users in collections named `authority_users_<pluginName>` and lockout metadata in embedded documents. Additional plugins must document their storage layout and provide deterministic collection naming to honour the Offline Kit replication process.
|
||||||
|
|
||||||
## 3. Capability Metadata
|
## 3. Capability Metadata
|
||||||
Capability flags let the host reason about what your plug-in supports:
|
Capability flags let the host reason about what your plug-in supports:
|
||||||
|
|
||||||
- Declare capabilities in your descriptor using the string constants from `AuthorityPluginCapabilities` (`password`, `mfa`, `clientProvisioning`, `bootstrap`). The configuration loader now validates these tokens and rejects unknown values at startup.
|
- Declare capabilities in your descriptor using the string constants from `AuthorityPluginCapabilities` (`password`, `mfa`, `clientProvisioning`, `bootstrap`). The configuration loader now validates these tokens and rejects unknown values at startup.
|
||||||
- `AuthorityIdentityProviderCapabilities.FromCapabilities` projects those strings into strongly typed booleans (`SupportsPassword`, etc.). Authority Core will use these flags when wiring flows such as the password grant. Built-in plugins (e.g., Standard) will fail fast or force-enable required capabilities if the descriptor is misconfigured, so keep manifests accurate.
|
- `AuthorityIdentityProviderCapabilities.FromCapabilities` projects those strings into strongly typed booleans (`SupportsPassword`, etc.). Authority Core will use these flags when wiring flows such as the password grant. Built-in plugins (e.g., Standard) will fail fast or force-enable required capabilities if the descriptor is misconfigured, so keep manifests accurate.
|
||||||
- Typical configuration (`etc/authority.plugins/standard.yaml`):
|
- Typical configuration (`etc/authority.plugins/standard.yaml`):
|
||||||
```yaml
|
```yaml
|
||||||
plugins:
|
plugins:
|
||||||
descriptors:
|
descriptors:
|
||||||
standard:
|
standard:
|
||||||
assemblyName: "StellaOps.Authority.Plugin.Standard"
|
assemblyName: "StellaOps.Authority.Plugin.Standard"
|
||||||
capabilities:
|
capabilities:
|
||||||
- password
|
- password
|
||||||
- bootstrap
|
- bootstrap
|
||||||
```
|
```
|
||||||
- Only declare a capability if the plug-in genuinely implements it. For example, if `SupportsClientProvisioning` is `true`, the plug-in must supply a working `IClientProvisioningStore`.
|
- Only declare a capability if the plug-in genuinely implements it. For example, if `SupportsClientProvisioning` is `true`, the plug-in must supply a working `IClientProvisioningStore`.
|
||||||
|
|
||||||
**Operational reminder:** the Authority host surfaces capability summaries during startup (see `AuthorityIdentityProviderRegistry` log lines). Use those logs during smoke tests to ensure manifests align with expectations.
|
**Operational reminder:** the Authority host surfaces capability summaries during startup (see `AuthorityIdentityProviderRegistry` log lines). Use those logs during smoke tests to ensure manifests align with expectations.
|
||||||
|
|
||||||
**Configuration path normalisation:** Manifest-relative paths (e.g., `tokenSigning.keyDirectory: "../keys"`) are resolved against the YAML file location and environment variables are expanded before validation. Plug-ins should expect to receive an absolute, canonical path when options are injected.
|
**Configuration path normalisation:** Manifest-relative paths (e.g., `tokenSigning.keyDirectory: "../keys"`) are resolved against the YAML file location and environment variables are expanded before validation. Plug-ins should expect to receive an absolute, canonical path when options are injected.
|
||||||
|
|
||||||
**Password policy guardrails:** The Standard registrar logs a warning when a plug-in weakens the default password policy (minimum length or required character classes). Keep overrides at least as strong as the compiled defaults—operators treat the warning as an actionable security deviation.
|
**Password policy guardrails:** The Standard registrar logs a warning when a plug-in weakens the default password policy (minimum length or required character classes). Keep overrides at least as strong as the compiled defaults—operators treat the warning as an actionable security deviation.
|
||||||
|
|
||||||
## 4. Project Scaffold
|
## 4. Project Scaffold
|
||||||
- Target **.NET 10 preview**, enable nullable, treat warnings as errors, and mark Authority plug-ins with `<IsAuthorityPlugin>true</IsAuthorityPlugin>`.
|
- Target **.NET 10 preview**, enable nullable, treat warnings as errors, and mark Authority plug-ins with `<IsAuthorityPlugin>true</IsAuthorityPlugin>`.
|
||||||
- Minimum references:
|
- Minimum references:
|
||||||
- `StellaOps.Authority.Plugins.Abstractions` (contracts & capability helpers)
|
- `StellaOps.Authority.Plugins.Abstractions` (contracts & capability helpers)
|
||||||
- `StellaOps.Plugin` (hosting/DI helpers)
|
- `StellaOps.Plugin` (hosting/DI helpers)
|
||||||
- `StellaOps.Auth.*` libraries as needed for shared token utilities (optional today).
|
- `StellaOps.Auth.*` libraries as needed for shared token utilities (optional today).
|
||||||
- Example `.csproj` (trimmed from `StellaOps.Authority.Plugin.Standard`):
|
- Example `.csproj` (trimmed from `StellaOps.Authority.Plugin.Standard`):
|
||||||
```xml
|
```xml
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net10.0</TargetFramework>
|
<TargetFramework>net10.0</TargetFramework>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||||
<IsAuthorityPlugin>true</IsAuthorityPlugin>
|
<IsAuthorityPlugin>true</IsAuthorityPlugin>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\StellaOps.Authority.Plugins.Abstractions\StellaOps.Authority.Plugins.Abstractions.csproj" />
|
<ProjectReference Include="..\StellaOps.Authority.Plugins.Abstractions\StellaOps.Authority.Plugins.Abstractions.csproj" />
|
||||||
<ProjectReference Include="..\..\StellaOps.Plugin\StellaOps.Plugin.csproj" />
|
<ProjectReference Include="..\..\StellaOps.Plugin\StellaOps.Plugin.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
```
|
```
|
||||||
(Add other references—e.g., MongoDB driver, shared auth libraries—according to your implementation.)
|
(Add other references—e.g., MongoDB driver, shared auth libraries—according to your implementation.)
|
||||||
|
|
||||||
## 5. Implementing `IAuthorityPluginRegistrar`
|
## 5. Implementing `IAuthorityPluginRegistrar`
|
||||||
- Create a parameterless registrar class that returns your plug-in type name via `PluginType`.
|
- Create a parameterless registrar class that returns your plug-in type name via `PluginType`.
|
||||||
- Use `AuthorityPluginRegistrationContext` to:
|
- Use `AuthorityPluginRegistrationContext` to:
|
||||||
- Bind options (`AddOptions<T>(pluginName).Bind(...)`).
|
- Bind options (`AddOptions<T>(pluginName).Bind(...)`).
|
||||||
- Register singletons for stores/enrichers using manifest metadata.
|
- Register singletons for stores/enrichers using manifest metadata.
|
||||||
- Register any hosted bootstrap tasks (e.g., seed admin users).
|
- Register any hosted bootstrap tasks (e.g., seed admin users).
|
||||||
- Always validate configuration inside `PostConfigure` and throw meaningful `InvalidOperationException` to fail fast during startup.
|
- Always validate configuration inside `PostConfigure` and throw meaningful `InvalidOperationException` to fail fast during startup.
|
||||||
- Use the provided `ILoggerFactory` from DI; avoid static loggers or console writes.
|
- Use the provided `ILoggerFactory` from DI; avoid static loggers or console writes.
|
||||||
- Example skeleton:
|
- Example skeleton:
|
||||||
```csharp
|
```csharp
|
||||||
internal sealed class MyPluginRegistrar : IAuthorityPluginRegistrar
|
internal sealed class MyPluginRegistrar : IAuthorityPluginRegistrar
|
||||||
{
|
{
|
||||||
public string PluginType => "my-custom";
|
public string PluginType => "my-custom";
|
||||||
|
|
||||||
public void Register(AuthorityPluginRegistrationContext context)
|
public void Register(AuthorityPluginRegistrationContext context)
|
||||||
{
|
{
|
||||||
var name = context.Plugin.Manifest.Name;
|
var name = context.Plugin.Manifest.Name;
|
||||||
|
|
||||||
context.Services.AddOptions<MyPluginOptions>(name)
|
context.Services.AddOptions<MyPluginOptions>(name)
|
||||||
.Bind(context.Plugin.Configuration)
|
.Bind(context.Plugin.Configuration)
|
||||||
.PostConfigure(opts => opts.Validate(name));
|
.PostConfigure(opts => opts.Validate(name));
|
||||||
|
|
||||||
context.Services.AddSingleton<IIdentityProviderPlugin>(sp =>
|
context.Services.AddSingleton<IIdentityProviderPlugin>(sp =>
|
||||||
new MyIdentityProvider(context.Plugin, sp.GetRequiredService<MyCredentialStore>(),
|
new MyIdentityProvider(context.Plugin, sp.GetRequiredService<MyCredentialStore>(),
|
||||||
sp.GetRequiredService<MyClaimsEnricher>(),
|
sp.GetRequiredService<MyClaimsEnricher>(),
|
||||||
sp.GetRequiredService<ILogger<MyIdentityProvider>>()));
|
sp.GetRequiredService<ILogger<MyIdentityProvider>>()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## 6. Identity Provider Surface
|
## 6. Identity Provider Surface
|
||||||
- Implement `IIdentityProviderPlugin` to expose:
|
- Implement `IIdentityProviderPlugin` to expose:
|
||||||
- `IUserCredentialStore` for password validation and user CRUD.
|
- `IUserCredentialStore` for password validation and user CRUD.
|
||||||
- `IClaimsEnricher` to append roles/attributes onto issued principals.
|
- `IClaimsEnricher` to append roles/attributes onto issued principals.
|
||||||
- Optional `IClientProvisioningStore` for machine-to-machine clients.
|
- Optional `IClientProvisioningStore` for machine-to-machine clients.
|
||||||
- `AuthorityIdentityProviderCapabilities` to advertise supported flows.
|
- `AuthorityIdentityProviderCapabilities` to advertise supported flows.
|
||||||
- Password guidance:
|
- Password guidance:
|
||||||
- Standard plug-in hashes via `ICryptoProvider` using Argon2id by default and emits PHC-compliant strings. Successful PBKDF2 logins trigger automatic rehashes so migrations complete gradually. See `docs/security/password-hashing.md` for tuning advice.
|
- Standard plug-in hashes via `ICryptoProvider` using Argon2id by default and emits PHC-compliant strings. Successful PBKDF2 logins trigger automatic rehashes so migrations complete gradually. See `docs/security/password-hashing.md` for tuning advice.
|
||||||
- Enforce password policies before hashing to avoid storing weak credentials.
|
- Enforce password policies before hashing to avoid storing weak credentials.
|
||||||
- Health checks should probe backing stores (e.g., Mongo `ping`) and return `AuthorityPluginHealthResult` so `/ready` can surface issues.
|
- Health checks should probe backing stores (e.g., Mongo `ping`) and return `AuthorityPluginHealthResult` so `/ready` can surface issues.
|
||||||
- When supporting additional factors (e.g., TOTP), implement `SupportsMfa` and document the enrolment flow for resource servers.
|
- When supporting additional factors (e.g., TOTP), implement `SupportsMfa` and document the enrolment flow for resource servers.
|
||||||
|
|
||||||
## 7. Configuration & Secrets
|
## 7. Configuration & Secrets
|
||||||
- Authority looks for manifests under `etc/authority.plugins/`. Each YAML file maps directly to a plug-in name.
|
- Authority looks for manifests under `etc/authority.plugins/`. Each YAML file maps directly to a plug-in name.
|
||||||
- Support environment overrides using `STELLAOPS_AUTHORITY_PLUGINS__DESCRIPTORS__<NAME>__...`.
|
- Support environment overrides using `STELLAOPS_AUTHORITY_PLUGINS__DESCRIPTORS__<NAME>__...`.
|
||||||
- Never store raw secrets in git: allow operators to supply them via `.local.yaml`, environment variables, or injected secret files. Document which keys are mandatory.
|
- Never store raw secrets in git: allow operators to supply them via `.local.yaml`, environment variables, or injected secret files. Document which keys are mandatory.
|
||||||
- Validate configuration as soon as the registrar runs; use explicit error messages to guide operators. The Standard plug-in now enforces complete bootstrap credentials (username + password) and positive lockout windows via `StandardPluginOptions.Validate`.
|
- Validate configuration as soon as the registrar runs; use explicit error messages to guide operators. The Standard plug-in now enforces complete bootstrap credentials (username + password) and positive lockout windows via `StandardPluginOptions.Validate`.
|
||||||
- Cross-reference bootstrap workflows with `docs/ops/authority_bootstrap.md` (to be published alongside CORE6) so operators can reuse the same payload formats for manual provisioning.
|
- Cross-reference bootstrap workflows with `docs/ops/authority_bootstrap.md` (to be published alongside CORE6) so operators can reuse the same payload formats for manual provisioning.
|
||||||
- `passwordHashing` inherits defaults from `authority.security.passwordHashing`. Override only when hardware constraints differ per plug-in:
|
- `passwordHashing` inherits defaults from `authority.security.passwordHashing`. Override only when hardware constraints differ per plug-in:
|
||||||
```yaml
|
```yaml
|
||||||
passwordHashing:
|
passwordHashing:
|
||||||
algorithm: Argon2id
|
algorithm: Argon2id
|
||||||
memorySizeInKib: 19456
|
memorySizeInKib: 19456
|
||||||
iterations: 2
|
iterations: 2
|
||||||
parallelism: 1
|
parallelism: 1
|
||||||
```
|
```
|
||||||
Invalid values (≤0) fail fast during startup, and legacy PBKDF2 hashes rehash automatically once the new algorithm succeeds.
|
Invalid values (≤0) fail fast during startup, and legacy PBKDF2 hashes rehash automatically once the new algorithm succeeds.
|
||||||
|
|
||||||
### 7.1 Token Persistence Contract
|
### 7.1 Token Persistence Contract
|
||||||
- The host automatically persists every issued principal (access, refresh, device, authorization code) in `authority_tokens`. Plug-in code **must not** bypass this store; use the provided `IAuthorityTokenStore` helpers when implementing custom flows.
|
- The host automatically persists every issued principal (access, refresh, device, authorization code) in `authority_tokens`. Plug-in code **must not** bypass this store; use the provided `IAuthorityTokenStore` helpers when implementing custom flows.
|
||||||
- When a plug-in disables a subject or client outside the standard handlers, call `IAuthorityTokenStore.UpdateStatusAsync(...)` for each affected token so revocation bundles stay consistent.
|
- When a plug-in disables a subject or client outside the standard handlers, call `IAuthorityTokenStore.UpdateStatusAsync(...)` for each affected token so revocation bundles stay consistent.
|
||||||
- Supply machine-friendly `revokedReason` codes (`compromised`, `rotation`, `policy`, `lifecycle`, etc.) and optional `revokedMetadata` entries when invalidating credentials. These flow straight into `revocation-bundle.json` and should remain deterministic.
|
- Supply machine-friendly `revokedReason` codes (`compromised`, `rotation`, `policy`, `lifecycle`, etc.) and optional `revokedMetadata` entries when invalidating credentials. These flow straight into `revocation-bundle.json` and should remain deterministic.
|
||||||
- Token scopes should be normalised (trimmed, unique, ordinal sort) before returning from plug-in verification paths. `TokenPersistenceHandlers` will keep that ordering for downstream consumers.
|
- Token scopes should be normalised (trimmed, unique, ordinal sort) before returning from plug-in verification paths. `TokenPersistenceHandlers` will keep that ordering for downstream consumers.
|
||||||
|
|
||||||
### 7.2 Claims & Enrichment Checklist
|
### 7.2 Claims & Enrichment Checklist
|
||||||
- Authority always sets the OpenID Connect basics: `sub`, `client_id`, `preferred_username`, optional `name`, and `role` (for password flows). Plug-ins must use `IClaimsEnricher` to append additional claims in a **deterministic** order (sort arrays, normalise casing) so resource servers can rely on stable shapes.
|
- Authority always sets the OpenID Connect basics: `sub`, `client_id`, `preferred_username`, optional `name`, and `role` (for password flows). Plug-ins must use `IClaimsEnricher` to append additional claims in a **deterministic** order (sort arrays, normalise casing) so resource servers can rely on stable shapes.
|
||||||
- Recommended enrichment keys:
|
- Recommended enrichment keys:
|
||||||
- `stellaops.realm` – plug-in/tenant identifier so services can scope policies.
|
- `stellaops.realm` – plug-in/tenant identifier so services can scope policies.
|
||||||
- `stellaops.subject.type` – values such as `human`, `service`, `bootstrap`.
|
- `stellaops.subject.type` – values such as `human`, `service`, `bootstrap`.
|
||||||
- `groups` / `projects` – sorted arrays describing operator entitlements.
|
- `groups` / `projects` – sorted arrays describing operator entitlements.
|
||||||
- Claims visible in tokens should mirror what `/token` and `/userinfo` emit. Avoid injecting sensitive PII directly; mark values with `ClassifiedString.Personal` inside the plug-in so audit sinks can tag them appropriately.
|
- Claims visible in tokens should mirror what `/token` and `/userinfo` emit. Avoid injecting sensitive PII directly; mark values with `ClassifiedString.Personal` inside the plug-in so audit sinks can tag them appropriately.
|
||||||
- For client-credential flows, remember to enrich both the client principal and the validation path (`TokenValidationHandlers`) so refresh flows keep the same metadata.
|
- For client-credential flows, remember to enrich both the client principal and the validation path (`TokenValidationHandlers`) so refresh flows keep the same metadata.
|
||||||
|
|
||||||
### 7.3 Revocation Bundles & Reasons
|
### 7.3 Revocation Bundles & Reasons
|
||||||
- Use `IAuthorityRevocationStore` to record subject/client/token revocations when credentials are deleted or rotated. Stick to the standard categories (`token`, `subject`, `client`, `key`).
|
- Use `IAuthorityRevocationStore` to record subject/client/token revocations when credentials are deleted or rotated. Stick to the standard categories (`token`, `subject`, `client`, `key`).
|
||||||
- Include a deterministic `reason` string and optional `reasonDescription` so operators understand *why* a subject was revoked when inspecting bundles offline.
|
- Include a deterministic `reason` string and optional `reasonDescription` so operators understand *why* a subject was revoked when inspecting bundles offline.
|
||||||
- Plug-ins should populate `metadata` with stable keys (e.g., `revokedBy`, `sourcePlugin`, `ticketId`) to simplify SOC correlation. The keys must be lowercase, ASCII, and free of secrets—bundles are mirrored to air-gapped agents.
|
- Plug-ins should populate `metadata` with stable keys (e.g., `revokedBy`, `sourcePlugin`, `ticketId`) to simplify SOC correlation. The keys must be lowercase, ASCII, and free of secrets—bundles are mirrored to air-gapped agents.
|
||||||
|
|
||||||
## 8. Rate Limiting & Lockout Interplay
|
## 8. Rate Limiting & Lockout Interplay
|
||||||
Rate limiting and account lockouts are complementary controls. Plug-ins must surface both deterministically so operators can correlate limiter hits with credential rejections.
|
Rate limiting and account lockouts are complementary controls. Plug-ins must surface both deterministically so operators can correlate limiter hits with credential rejections.
|
||||||
|
|
||||||
**Baseline quotas** (from `docs/dev/authority-rate-limit-tuning-outline.md`):
|
**Baseline quotas** (from `docs/dev/authority-rate-limit-tuning-outline.md`):
|
||||||
|
|
||||||
| Endpoint | Default policy | Notes |
|
| Endpoint | Default policy | Notes |
|
||||||
|----------|----------------|-------|
|
|----------|----------------|-------|
|
||||||
| `/token` | 30 requests / 60s, queue 0 | Drop to 10/60s for untrusted ranges; raise only with WAF + monitoring. |
|
| `/token` | 30 requests / 60s, queue 0 | Drop to 10/60s for untrusted ranges; raise only with WAF + monitoring. |
|
||||||
| `/authorize` | 60 requests / 60s, queue 10 | Reduce carefully; interactive UX depends on headroom. |
|
| `/authorize` | 60 requests / 60s, queue 10 | Reduce carefully; interactive UX depends on headroom. |
|
||||||
| `/internal/*` | Disabled by default; recommended 5/60s when enabled | Keep queue 0 for bootstrap APIs. |
|
| `/internal/*` | Disabled by default; recommended 5/60s when enabled | Keep queue 0 for bootstrap APIs. |
|
||||||
|
|
||||||
**Retry metadata:** The middleware stamps `Retry-After` plus tags `authority.client_id`, `authority.remote_ip`, and `authority.endpoint`. Plug-ins should keep these tags intact when crafting responses or telemetry so dashboards remain consistent.
|
**Retry metadata:** The middleware stamps `Retry-After` plus tags `authority.client_id`, `authority.remote_ip`, and `authority.endpoint`. Plug-ins should keep these tags intact when crafting responses or telemetry so dashboards remain consistent.
|
||||||
|
|
||||||
**Lockout counters:** Treat lockouts as **subject-scoped** decisions. When multiple instances update counters, reuse the deterministic tie-breakers documented in `src/DEDUP_CONFLICTS_RESOLUTION_ALGO.md` (freshness overrides, precedence, and stable hashes) to avoid divergent lockout states across replicas.
|
**Lockout counters:** Treat lockouts as **subject-scoped** decisions. When multiple instances update counters, reuse the deterministic tie-breakers documented in `src/DEDUP_CONFLICTS_RESOLUTION_ALGO.md` (freshness overrides, precedence, and stable hashes) to avoid divergent lockout states across replicas.
|
||||||
|
|
||||||
**Alerting hooks:** Emit structured logs/metrics when either the limiter or credential store rejects access. Suggested gauges include `aspnetcore_rate_limiting_rejections_total{limiter="authority-token"}` and any custom `auth.plugins.<pluginName>.lockouts_total` counter.
|
**Alerting hooks:** Emit structured logs/metrics when either the limiter or credential store rejects access. Suggested gauges include `aspnetcore_rate_limiting_rejections_total{limiter="authority-token"}` and any custom `auth.plugins.<pluginName>.lockouts_total` counter.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
_Source:_ `docs/assets/authority/authority-rate-limit-flow.mmd`
|
_Source:_ `docs/assets/authority/authority-rate-limit-flow.mmd`
|
||||||
|
|
||||||
## 9. Logging, Metrics, and Diagnostics
|
## 9. Logging, Metrics, and Diagnostics
|
||||||
- Always log via the injected `ILogger<T>`; include `pluginName` and correlation IDs where available.
|
- Always log via the injected `ILogger<T>`; include `pluginName` and correlation IDs where available.
|
||||||
- Activity/metric names should align with `AuthorityTelemetry` constants (`service.name=stellaops-authority`).
|
- Activity/metric names should align with `AuthorityTelemetry` constants (`service.name=stellaops-authority`).
|
||||||
- Expose additional diagnostics via structured logging rather than writing custom HTTP endpoints; the host will integrate these into `/health` and `/ready`.
|
- Expose additional diagnostics via structured logging rather than writing custom HTTP endpoints; the host will integrate these into `/health` and `/ready`.
|
||||||
- Emit metrics with stable names (`auth.plugins.<pluginName>.*`) when introducing custom instrumentation; coordinate with the Observability guild to reserve prefixes.
|
- Emit metrics with stable names (`auth.plugins.<pluginName>.*`) when introducing custom instrumentation; coordinate with the Observability guild to reserve prefixes.
|
||||||
|
|
||||||
## 10. Testing & Tooling
|
## 10. Testing & Tooling
|
||||||
- Unit tests: use Mongo2Go (or similar) to exercise credential stores without hitting production infrastructure (`StandardUserCredentialStoreTests` is a template).
|
- Unit tests: use Mongo2Go (or similar) to exercise credential stores without hitting production infrastructure (`StandardUserCredentialStoreTests` is a template).
|
||||||
- Determinism: fix timestamps to UTC and sort outputs consistently; avoid random GUIDs unless stable.
|
- Determinism: fix timestamps to UTC and sort outputs consistently; avoid random GUIDs unless stable.
|
||||||
- Smoke tests: launch `dotnet run --project src/StellaOps.Authority/StellaOps.Authority` with your plug-in under `StellaOps.Authority.PluginBinaries` and verify `/ready`.
|
- Smoke tests: launch `dotnet run --project src/Authority/StellaOps.Authority/StellaOps.Authority` with your plug-in under `StellaOps.Authority.PluginBinaries` and verify `/ready`.
|
||||||
- Example verification snippet:
|
- Example verification snippet:
|
||||||
```csharp
|
```csharp
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task VerifyPasswordAsync_ReturnsSuccess()
|
public async Task VerifyPasswordAsync_ReturnsSuccess()
|
||||||
{
|
{
|
||||||
var store = CreateCredentialStore();
|
var store = CreateCredentialStore();
|
||||||
await store.UpsertUserAsync(new AuthorityUserRegistration("alice", "Pa55!", null, null, false,
|
await store.UpsertUserAsync(new AuthorityUserRegistration("alice", "Pa55!", null, null, false,
|
||||||
Array.Empty<string>(), new Dictionary<string, string?>()), CancellationToken.None);
|
Array.Empty<string>(), new Dictionary<string, string?>()), CancellationToken.None);
|
||||||
|
|
||||||
var result = await store.VerifyPasswordAsync("alice", "Pa55!", CancellationToken.None);
|
var result = await store.VerifyPasswordAsync("alice", "Pa55!", CancellationToken.None);
|
||||||
Assert.True(result.Succeeded);
|
Assert.True(result.Succeeded);
|
||||||
Assert.True(result.User?.Roles.Count == 0);
|
Assert.True(result.User?.Roles.Count == 0);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## 11. Packaging & Delivery
|
## 11. Packaging & Delivery
|
||||||
- Output assembly should follow `StellaOps.Authority.Plugin.<Name>.dll` so the host’s search pattern picks it up.
|
- Output assembly should follow `StellaOps.Authority.Plugin.<Name>.dll` so the host’s search pattern picks it up.
|
||||||
- Place the compiled DLL plus dependencies under `StellaOps.Authority.PluginBinaries` for offline deployments; include hashes/signatures in release notes (Security Guild guidance forthcoming).
|
- Place the compiled DLL plus dependencies under `StellaOps.Authority.PluginBinaries` for offline deployments; include hashes/signatures in release notes (Security Guild guidance forthcoming).
|
||||||
- Document any external prerequisites (e.g., CA cert bundle) in your plug-in README.
|
- Document any external prerequisites (e.g., CA cert bundle) in your plug-in README.
|
||||||
- Update `etc/authority.plugins/<plugin>.yaml` samples and include deterministic SHA256 hashes for optional bootstrap payloads when distributing Offline Kit artefacts.
|
- Update `etc/authority.plugins/<plugin>.yaml` samples and include deterministic SHA256 hashes for optional bootstrap payloads when distributing Offline Kit artefacts.
|
||||||
|
|
||||||
[^ldap-rfc]: Lightweight Directory Access Protocol (LDAPv3) specification — [RFC 4511](https://datatracker.ietf.org/doc/html/rfc4511).
|
[^ldap-rfc]: Lightweight Directory Access Protocol (LDAPv3) specification — [RFC 4511](https://datatracker.ietf.org/doc/html/rfc4511).
|
||||||
|
|
||||||
## 12. Checklist & Handoff
|
## 12. Checklist & Handoff
|
||||||
- ✅ Capabilities declared and validated in automated tests.
|
- ✅ Capabilities declared and validated in automated tests.
|
||||||
- ✅ Bootstrap workflows documented (if `bootstrap` capability used) and repeatable.
|
- ✅ Bootstrap workflows documented (if `bootstrap` capability used) and repeatable.
|
||||||
- ✅ Local smoke test + unit/integration suites green (`dotnet test`).
|
- ✅ Local smoke test + unit/integration suites green (`dotnet test`).
|
||||||
- ✅ Operational docs updated: configuration keys, secrets guidance, troubleshooting.
|
- ✅ Operational docs updated: configuration keys, secrets guidance, troubleshooting.
|
||||||
- Submit the developer guide update referencing PLG6/DOC4 and tag DevEx + Docs reviewers for sign-off.
|
- Submit the developer guide update referencing PLG6/DOC4 and tag DevEx + Docs reviewers for sign-off.
|
||||||
|
|
||||||
---
|
---
|
||||||
Mermaid sources for the embedded diagrams live under `docs/assets/authority/`. Regenerate the SVG assets with your preferred renderer before committing future updates so the visuals stay in sync with the `.mmd` definitions.
|
Mermaid sources for the embedded diagrams live under `docs/assets/authority/`. Regenerate the SVG assets with your preferred renderer before committing future updates so the visuals stay in sync with the `.mmd` definitions.
|
||||||
|
|||||||
@@ -1,115 +1,115 @@
|
|||||||
# BuildX Generator Quickstart
|
# BuildX Generator Quickstart
|
||||||
|
|
||||||
This quickstart explains how to run the StellaOps **BuildX SBOM generator** offline, verify the CAS handshake, and emit OCI descriptors that downstream services can attest.
|
This quickstart explains how to run the StellaOps **BuildX SBOM generator** offline, verify the CAS handshake, and emit OCI descriptors that downstream services can attest.
|
||||||
|
|
||||||
## 1. Prerequisites
|
## 1. Prerequisites
|
||||||
|
|
||||||
- Docker 25+ with BuildKit enabled (`docker buildx` available).
|
- Docker 25+ with BuildKit enabled (`docker buildx` available).
|
||||||
- .NET 10 (preview) SDK matching the repository `global.json`.
|
- .NET 10 (preview) SDK matching the repository `global.json`.
|
||||||
- Optional: network access to a StellaOps Attestor endpoint (the quickstart uses a mock service).
|
- Optional: network access to a StellaOps Attestor endpoint (the quickstart uses a mock service).
|
||||||
|
|
||||||
## 2. Publish the plug-in binaries
|
## 2. Publish the plug-in binaries
|
||||||
|
|
||||||
The BuildX generator publishes as a .NET self-contained executable with its manifest under `plugins/scanner/buildx/`.
|
The BuildX generator publishes as a .NET self-contained executable with its manifest under `plugins/scanner/buildx/`.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# From the repository root
|
# From the repository root
|
||||||
DOTNET_CLI_HOME="${PWD}/.dotnet" \
|
DOTNET_CLI_HOME="${PWD}/.dotnet" \
|
||||||
dotnet publish src/StellaOps.Scanner.Sbomer.BuildXPlugin/StellaOps.Scanner.Sbomer.BuildXPlugin.csproj \
|
dotnet publish src/Scanner/StellaOps.Scanner.Sbomer.BuildXPlugin/StellaOps.Scanner.Sbomer.BuildXPlugin.csproj \
|
||||||
-c Release \
|
-c Release \
|
||||||
-o out/buildx
|
-o out/buildx
|
||||||
```
|
```
|
||||||
|
|
||||||
- `out/buildx/` now contains `StellaOps.Scanner.Sbomer.BuildXPlugin.dll` and the manifest `stellaops.sbom-indexer.manifest.json`.
|
- `out/buildx/` now contains `StellaOps.Scanner.Sbomer.BuildXPlugin.dll` and the manifest `stellaops.sbom-indexer.manifest.json`.
|
||||||
- `plugins/scanner/buildx/StellaOps.Scanner.Sbomer.BuildXPlugin/` receives the same artefacts for release packaging.
|
- `plugins/scanner/buildx/StellaOps.Scanner.Sbomer.BuildXPlugin/` receives the same artefacts for release packaging.
|
||||||
- The CI pipeline also tars and signs (SHA-256 manifest) the OS analyzer plug-ins located under
|
- The CI pipeline also tars and signs (SHA-256 manifest) the OS analyzer plug-ins located under
|
||||||
`plugins/scanner/analyzers/os/` so they ship alongside the BuildX generator artefacts.
|
`plugins/scanner/analyzers/os/` so they ship alongside the BuildX generator artefacts.
|
||||||
|
|
||||||
## 3. Verify the CAS handshake
|
## 3. Verify the CAS handshake
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
dotnet out/buildx/StellaOps.Scanner.Sbomer.BuildXPlugin.dll handshake \
|
dotnet out/buildx/StellaOps.Scanner.Sbomer.BuildXPlugin.dll handshake \
|
||||||
--manifest out/buildx \
|
--manifest out/buildx \
|
||||||
--cas out/cas
|
--cas out/cas
|
||||||
```
|
```
|
||||||
|
|
||||||
The command performs a deterministic probe write (`sha256`) into the provided CAS directory and prints the resolved path.
|
The command performs a deterministic probe write (`sha256`) into the provided CAS directory and prints the resolved path.
|
||||||
|
|
||||||
## 4. Emit a descriptor + provenance placeholder
|
## 4. Emit a descriptor + provenance placeholder
|
||||||
|
|
||||||
1. Build or identify the image you want to describe and capture its digest:
|
1. Build or identify the image you want to describe and capture its digest:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker buildx build --load -t stellaops/buildx-demo:ci samples/ci/buildx-demo
|
docker buildx build --load -t stellaops/buildx-demo:ci samples/ci/buildx-demo
|
||||||
DIGEST=$(docker image inspect stellaops/buildx-demo:ci --format '{{index .RepoDigests 0}}')
|
DIGEST=$(docker image inspect stellaops/buildx-demo:ci --format '{{index .RepoDigests 0}}')
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Generate a CycloneDX SBOM for the built image (any tool works; here we use `docker sbom`):
|
2. Generate a CycloneDX SBOM for the built image (any tool works; here we use `docker sbom`):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker sbom stellaops/buildx-demo:ci --format cyclonedx-json > out/buildx-sbom.cdx.json
|
docker sbom stellaops/buildx-demo:ci --format cyclonedx-json > out/buildx-sbom.cdx.json
|
||||||
```
|
```
|
||||||
|
|
||||||
3. Invoke the `descriptor` command, pointing at the SBOM file and optional metadata:
|
3. Invoke the `descriptor` command, pointing at the SBOM file and optional metadata:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
dotnet out/buildx/StellaOps.Scanner.Sbomer.BuildXPlugin.dll descriptor \
|
dotnet out/buildx/StellaOps.Scanner.Sbomer.BuildXPlugin.dll descriptor \
|
||||||
--manifest out/buildx \
|
--manifest out/buildx \
|
||||||
--image "$DIGEST" \
|
--image "$DIGEST" \
|
||||||
--sbom out/buildx-sbom.cdx.json \
|
--sbom out/buildx-sbom.cdx.json \
|
||||||
--sbom-name buildx-sbom.cdx.json \
|
--sbom-name buildx-sbom.cdx.json \
|
||||||
--artifact-type application/vnd.stellaops.sbom.layer+json \
|
--artifact-type application/vnd.stellaops.sbom.layer+json \
|
||||||
--sbom-format cyclonedx-json \
|
--sbom-format cyclonedx-json \
|
||||||
--sbom-kind inventory \
|
--sbom-kind inventory \
|
||||||
--repository git.stella-ops.org/stellaops/buildx-demo \
|
--repository git.stella-ops.org/stellaops/buildx-demo \
|
||||||
--build-ref $(git rev-parse HEAD) \
|
--build-ref $(git rev-parse HEAD) \
|
||||||
> out/buildx-descriptor.json
|
> out/buildx-descriptor.json
|
||||||
```
|
```
|
||||||
|
|
||||||
The output JSON captures:
|
The output JSON captures:
|
||||||
|
|
||||||
- OCI artifact descriptor including size, digest, and annotations (`org.stellaops.*`).
|
- OCI artifact descriptor including size, digest, and annotations (`org.stellaops.*`).
|
||||||
- Provenance placeholder (`expectedDsseSha256`, `nonce`, `attestorUri` when provided). `nonce` is derived deterministically from the image + SBOM metadata so repeated runs produce identical placeholders for identical inputs.
|
- Provenance placeholder (`expectedDsseSha256`, `nonce`, `attestorUri` when provided). `nonce` is derived deterministically from the image + SBOM metadata so repeated runs produce identical placeholders for identical inputs.
|
||||||
- Generator metadata and deterministic timestamps.
|
- Generator metadata and deterministic timestamps.
|
||||||
|
|
||||||
## 5. (Optional) Send the placeholder to an Attestor
|
## 5. (Optional) Send the placeholder to an Attestor
|
||||||
|
|
||||||
The plug-in can POST the descriptor metadata to an Attestor endpoint, returning once it receives an HTTP 202.
|
The plug-in can POST the descriptor metadata to an Attestor endpoint, returning once it receives an HTTP 202.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python3 - <<'PY' &
|
python3 - <<'PY' &
|
||||||
from http.server import BaseHTTPRequestHandler, HTTPServer
|
from http.server import BaseHTTPRequestHandler, HTTPServer
|
||||||
class Handler(BaseHTTPRequestHandler):
|
class Handler(BaseHTTPRequestHandler):
|
||||||
def do_POST(self):
|
def do_POST(self):
|
||||||
_ = self.rfile.read(int(self.headers.get('Content-Length', 0)))
|
_ = self.rfile.read(int(self.headers.get('Content-Length', 0)))
|
||||||
self.send_response(202); self.end_headers(); self.wfile.write(b'accepted')
|
self.send_response(202); self.end_headers(); self.wfile.write(b'accepted')
|
||||||
def log_message(self, fmt, *args):
|
def log_message(self, fmt, *args):
|
||||||
return
|
return
|
||||||
server = HTTPServer(('127.0.0.1', 8085), Handler)
|
server = HTTPServer(('127.0.0.1', 8085), Handler)
|
||||||
try:
|
try:
|
||||||
server.serve_forever()
|
server.serve_forever()
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
pass
|
pass
|
||||||
finally:
|
finally:
|
||||||
server.server_close()
|
server.server_close()
|
||||||
PY
|
PY
|
||||||
MOCK_PID=$!
|
MOCK_PID=$!
|
||||||
|
|
||||||
dotnet out/buildx/StellaOps.Scanner.Sbomer.BuildXPlugin.dll descriptor \
|
dotnet out/buildx/StellaOps.Scanner.Sbomer.BuildXPlugin.dll descriptor \
|
||||||
--manifest out/buildx \
|
--manifest out/buildx \
|
||||||
--image "$DIGEST" \
|
--image "$DIGEST" \
|
||||||
--sbom out/buildx-sbom.cdx.json \
|
--sbom out/buildx-sbom.cdx.json \
|
||||||
--attestor http://127.0.0.1:8085/provenance \
|
--attestor http://127.0.0.1:8085/provenance \
|
||||||
--attestor-token "$STELLAOPS_ATTESTOR_TOKEN" \
|
--attestor-token "$STELLAOPS_ATTESTOR_TOKEN" \
|
||||||
> out/buildx-descriptor.json
|
> out/buildx-descriptor.json
|
||||||
|
|
||||||
kill $MOCK_PID
|
kill $MOCK_PID
|
||||||
```
|
```
|
||||||
|
|
||||||
Set `STELLAOPS_ATTESTOR_TOKEN` (or pass `--attestor-token`) when the Attestor requires bearer authentication. Use `--attestor-insecure` for lab environments with self-signed certificates.
|
Set `STELLAOPS_ATTESTOR_TOKEN` (or pass `--attestor-token`) when the Attestor requires bearer authentication. Use `--attestor-insecure` for lab environments with self-signed certificates.
|
||||||
|
|
||||||
## 6. CI workflow example
|
## 6. CI workflow example
|
||||||
|
|
||||||
A reusable GitHub Actions workflow is provided under `samples/ci/buildx-demo/github-actions-buildx-demo.yml`. It publishes the plug-in, runs the handshake, builds the demo image, emits a descriptor, and uploads both the descriptor and the mock-Attestor request as artefacts.
|
A reusable GitHub Actions workflow is provided under `samples/ci/buildx-demo/github-actions-buildx-demo.yml`. It publishes the plug-in, runs the handshake, builds the demo image, emits a descriptor, and uploads both the descriptor and the mock-Attestor request as artefacts.
|
||||||
|
|
||||||
Add the workflow to your repository (or call it via `workflow_call`) and adjust the SBOM path + Attestor URL as needed. The workflow also re-runs the `descriptor` command and diffs the results (ignoring the `generatedAt` timestamp) so you catch regressions that would break deterministic CI use.
|
Add the workflow to your repository (or call it via `workflow_call`) and adjust the SBOM path + Attestor URL as needed. The workflow also re-runs the `descriptor` command and diffs the results (ignoring the `generatedAt` timestamp) so you catch regressions that would break deterministic CI use.
|
||||||
|
|||||||
@@ -1,86 +1,86 @@
|
|||||||
# Excititor Statement Backfill Runbook
|
# Excititor Statement Backfill Runbook
|
||||||
|
|
||||||
Last updated: 2025-10-19
|
Last updated: 2025-10-19
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
Use this runbook when you need to rebuild the `vex.statements` collection from historical raw documents. Typical scenarios:
|
Use this runbook when you need to rebuild the `vex.statements` collection from historical raw documents. Typical scenarios:
|
||||||
|
|
||||||
- Upgrading the statement schema (e.g., adding severity/KEV/EPSS signals).
|
- Upgrading the statement schema (e.g., adding severity/KEV/EPSS signals).
|
||||||
- Recovering from a partial ingest outage where statements were never persisted.
|
- Recovering from a partial ingest outage where statements were never persisted.
|
||||||
- Seeding a freshly provisioned Excititor deployment from an existing raw archive.
|
- Seeding a freshly provisioned Excititor deployment from an existing raw archive.
|
||||||
|
|
||||||
Backfill operates server-side via the Excititor WebService and reuses the same pipeline that powers the `/excititor/statements` ingestion endpoint. Each raw document is normalized, signed metadata is preserved, and duplicate statements are skipped unless the run is forced.
|
Backfill operates server-side via the Excititor WebService and reuses the same pipeline that powers the `/excititor/statements` ingestion endpoint. Each raw document is normalized, signed metadata is preserved, and duplicate statements are skipped unless the run is forced.
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
1. **Connectivity to Excititor WebService** – the CLI uses the backend URL configured in `stellaops.yml` or the `--backend-url` argument.
|
1. **Connectivity to Excititor WebService** – the CLI uses the backend URL configured in `stellaops.yml` or the `--backend-url` argument.
|
||||||
2. **Authority credentials** – the CLI honours the existing Authority client configuration; ensure the caller has permission to invoke admin endpoints.
|
2. **Authority credentials** – the CLI honours the existing Authority client configuration; ensure the caller has permission to invoke admin endpoints.
|
||||||
3. **Mongo replica set** (recommended) – causal consistency guarantees rely on majority read/write concerns. Standalone deployment works but skips cross-document transactions.
|
3. **Mongo replica set** (recommended) – causal consistency guarantees rely on majority read/write concerns. Standalone deployment works but skips cross-document transactions.
|
||||||
|
|
||||||
## CLI command
|
## CLI command
|
||||||
|
|
||||||
```
|
```
|
||||||
stellaops excititor backfill-statements \
|
stellaops excititor backfill-statements \
|
||||||
[--retrieved-since <ISO8601>] \
|
[--retrieved-since <ISO8601>] \
|
||||||
[--force] \
|
[--force] \
|
||||||
[--batch-size <int>] \
|
[--batch-size <int>] \
|
||||||
[--max-documents <int>]
|
[--max-documents <int>]
|
||||||
```
|
```
|
||||||
|
|
||||||
| Option | Description |
|
| Option | Description |
|
||||||
| ------ | ----------- |
|
| ------ | ----------- |
|
||||||
| `--retrieved-since` | Only process raw documents fetched on or after the specified timestamp (UTC by default). |
|
| `--retrieved-since` | Only process raw documents fetched on or after the specified timestamp (UTC by default). |
|
||||||
| `--force` | Reprocess documents even if matching statements already exist (useful after schema upgrades). |
|
| `--force` | Reprocess documents even if matching statements already exist (useful after schema upgrades). |
|
||||||
| `--batch-size` | Number of raw documents pulled per batch (default `100`). |
|
| `--batch-size` | Number of raw documents pulled per batch (default `100`). |
|
||||||
| `--max-documents` | Optional hard limit on the number of raw documents to evaluate. |
|
| `--max-documents` | Optional hard limit on the number of raw documents to evaluate. |
|
||||||
|
|
||||||
Example – replay the last 48 hours of Red Hat ingest while keeping existing statements:
|
Example – replay the last 48 hours of Red Hat ingest while keeping existing statements:
|
||||||
|
|
||||||
```
|
```
|
||||||
stellaops excititor backfill-statements \
|
stellaops excititor backfill-statements \
|
||||||
--retrieved-since "$(date -u -d '48 hours ago' +%Y-%m-%dT%H:%M:%SZ)"
|
--retrieved-since "$(date -u -d '48 hours ago' +%Y-%m-%dT%H:%M:%SZ)"
|
||||||
```
|
```
|
||||||
|
|
||||||
Example – full replay with forced overwrites, capped at 2,000 documents:
|
Example – full replay with forced overwrites, capped at 2,000 documents:
|
||||||
|
|
||||||
```
|
```
|
||||||
stellaops excititor backfill-statements --force --max-documents 2000
|
stellaops excititor backfill-statements --force --max-documents 2000
|
||||||
```
|
```
|
||||||
|
|
||||||
The command returns a summary similar to:
|
The command returns a summary similar to:
|
||||||
|
|
||||||
```
|
```
|
||||||
Backfill completed: evaluated 450, backfilled 180, claims written 320, skipped 270, failures 0.
|
Backfill completed: evaluated 450, backfilled 180, claims written 320, skipped 270, failures 0.
|
||||||
```
|
```
|
||||||
|
|
||||||
## Behaviour
|
## Behaviour
|
||||||
|
|
||||||
- Raw documents are streamed in ascending `retrievedAt` order.
|
- Raw documents are streamed in ascending `retrievedAt` order.
|
||||||
- Each document is normalized using the registered VEX normalizers (CSAF, CycloneDX, OpenVEX).
|
- Each document is normalized using the registered VEX normalizers (CSAF, CycloneDX, OpenVEX).
|
||||||
- Statements are appended through the same `IVexClaimStore.AppendAsync` path that powers `/excititor/statements`.
|
- Statements are appended through the same `IVexClaimStore.AppendAsync` path that powers `/excititor/statements`.
|
||||||
- Duplicate detection compares `Document.Digest`; duplicates are skipped unless `--force` is specified.
|
- Duplicate detection compares `Document.Digest`; duplicates are skipped unless `--force` is specified.
|
||||||
- Failures are logged with the offending digest and continue with the next document.
|
- Failures are logged with the offending digest and continue with the next document.
|
||||||
|
|
||||||
## Observability
|
## Observability
|
||||||
|
|
||||||
- CLI logs aggregate counts and the backend logs per-digest warnings or errors.
|
- CLI logs aggregate counts and the backend logs per-digest warnings or errors.
|
||||||
- Mongo writes carry majority write concern; expect backfill throughput to match ingest baselines (≈5 seconds warm, 30 seconds cold).
|
- Mongo writes carry majority write concern; expect backfill throughput to match ingest baselines (≈5 seconds warm, 30 seconds cold).
|
||||||
- Monitor the `excititor.storage.backfill` log scope for detailed telemetry.
|
- Monitor the `excititor.storage.backfill` log scope for detailed telemetry.
|
||||||
|
|
||||||
## Post-run verification
|
## Post-run verification
|
||||||
|
|
||||||
1. Inspect the `vex.statements` collection for the targeted window (check `InsertedAt`).
|
1. Inspect the `vex.statements` collection for the targeted window (check `InsertedAt`).
|
||||||
2. Re-run the Excititor storage test suite if possible:
|
2. Re-run the Excititor storage test suite if possible:
|
||||||
```
|
```
|
||||||
dotnet test src/StellaOps.Excititor.Storage.Mongo.Tests/StellaOps.Excititor.Storage.Mongo.Tests.csproj
|
dotnet test src/Excititor/__Tests/StellaOps.Excititor.Storage.Mongo.Tests/StellaOps.Excititor.Storage.Mongo.Tests.csproj
|
||||||
```
|
```
|
||||||
3. Optionally, call `/excititor/statements/{vulnerabilityId}/{productKey}` to confirm the expected statements exist.
|
3. Optionally, call `/excititor/statements/{vulnerabilityId}/{productKey}` to confirm the expected statements exist.
|
||||||
|
|
||||||
## Rollback
|
## Rollback
|
||||||
|
|
||||||
If a forced run produced incorrect statements, use the standard Mongo rollback procedure:
|
If a forced run produced incorrect statements, use the standard Mongo rollback procedure:
|
||||||
|
|
||||||
1. Identify the `InsertedAt` window for the backfill run.
|
1. Identify the `InsertedAt` window for the backfill run.
|
||||||
2. Delete affected records from `vex.statements` (and any downstream exports if applicable).
|
2. Delete affected records from `vex.statements` (and any downstream exports if applicable).
|
||||||
3. Rerun the backfill command with corrected parameters.
|
3. Rerun the backfill command with corrected parameters.
|
||||||
|
|||||||
@@ -1,146 +1,146 @@
|
|||||||
# Authority DPoP & mTLS Implementation Plan (2025-10-19)
|
# Authority DPoP & mTLS Implementation Plan (2025-10-19)
|
||||||
|
|
||||||
## Purpose
|
## Purpose
|
||||||
- Provide the implementation blueprint for AUTH-DPOP-11-001 and AUTH-MTLS-11-002.
|
- Provide the implementation blueprint for AUTH-DPOP-11-001 and AUTH-MTLS-11-002.
|
||||||
- Unify sender-constraint validation across Authority, downstream services, and clients.
|
- Unify sender-constraint validation across Authority, downstream services, and clients.
|
||||||
- Capture deterministic, testable steps that unblock UI/Signer guilds depending on DPoP/mTLS hardening.
|
- Capture deterministic, testable steps that unblock UI/Signer guilds depending on DPoP/mTLS hardening.
|
||||||
|
|
||||||
## Scope
|
## Scope
|
||||||
- Token endpoint validation, issuance, and storage changes inside `StellaOps.Authority`.
|
- Token endpoint validation, issuance, and storage changes inside `StellaOps.Authority`.
|
||||||
- Shared security primitives consumed by Authority, Scanner, Signer, CLI, and UI.
|
- Shared security primitives consumed by Authority, Scanner, Signer, CLI, and UI.
|
||||||
- Operator-facing configuration, auditing, and observability.
|
- Operator-facing configuration, auditing, and observability.
|
||||||
- Out of scope: PoE enforcement (Signer) and CLI/UI client UX; those teams consume the new capabilities.
|
- Out of scope: PoE enforcement (Signer) and CLI/UI client UX; those teams consume the new capabilities.
|
||||||
|
|
||||||
> **Status update (2025-10-19):** `ValidateDpopProofHandler`, `AuthorityClientCertificateValidator`, and the supporting storage/audit plumbing now live in `src/StellaOps.Authority`. DPoP proofs populate `cnf.jkt`, mTLS bindings enforce certificate thumbprints via `cnf.x5t#S256`, and token documents persist the sender constraint metadata. In-memory nonce issuance is wired (Redis implementation to follow). Documentation and configuration references were updated (`docs/11_AUTHORITY.md`). Targeted unit/integration tests were added; running the broader test suite is currently blocked by pre-existing `StellaOps.Concelier.Storage.Mongo` build errors.
|
> **Status update (2025-10-19):** `ValidateDpopProofHandler`, `AuthorityClientCertificateValidator`, and the supporting storage/audit plumbing now live in `src/Authority/StellaOps.Authority`. DPoP proofs populate `cnf.jkt`, mTLS bindings enforce certificate thumbprints via `cnf.x5t#S256`, and token documents persist the sender constraint metadata. In-memory nonce issuance is wired (Redis implementation to follow). Documentation and configuration references were updated (`docs/11_AUTHORITY.md`). Targeted unit/integration tests were added; running the broader test suite is currently blocked by pre-existing `StellaOps.Concelier.Storage.Mongo` build errors.
|
||||||
>
|
>
|
||||||
> **Status update (2025-10-20):** Redis-backed nonce configuration is exposed through `security.senderConstraints.dpop.nonce` with sample YAML (`etc/authority.yaml.sample`) and architecture docs refreshed. Operator guide now includes concrete Redis/required audiences snippet; nonce challenge regression remains covered by `ValidateDpopProof_IssuesNonceChallenge_WhenNonceMissing`.
|
> **Status update (2025-10-20):** Redis-backed nonce configuration is exposed through `security.senderConstraints.dpop.nonce` with sample YAML (`etc/authority.yaml.sample`) and architecture docs refreshed. Operator guide now includes concrete Redis/required audiences snippet; nonce challenge regression remains covered by `ValidateDpopProof_IssuesNonceChallenge_WhenNonceMissing`.
|
||||||
>
|
>
|
||||||
> **Status update (2025-10-23):** mTLS enforcement now honours `security.senderConstraints.mtls.enforceForAudiences`, automatically rejecting non-mTLS clients targeting audiences such as `signer`. Certificate bindings validate thumbprint, issuer, subject, serial number, and SAN values, producing deterministic error codes for operators. Introspection responses include `cnf.x5t#S256`, and new unit tests cover audience enforcement, binding mismatches, and bootstrap storage. Docs/sample config updated accordingly.
|
> **Status update (2025-10-23):** mTLS enforcement now honours `security.senderConstraints.mtls.enforceForAudiences`, automatically rejecting non-mTLS clients targeting audiences such as `signer`. Certificate bindings validate thumbprint, issuer, subject, serial number, and SAN values, producing deterministic error codes for operators. Introspection responses include `cnf.x5t#S256`, and new unit tests cover audience enforcement, binding mismatches, and bootstrap storage. Docs/sample config updated accordingly.
|
||||||
|
|
||||||
## Design Summary
|
## Design Summary
|
||||||
- Extract the existing Scanner `DpopProofValidator` stack into a shared `StellaOps.Auth.Security` library used by Authority and resource servers.
|
- Extract the existing Scanner `DpopProofValidator` stack into a shared `StellaOps.Auth.Security` library used by Authority and resource servers.
|
||||||
- Extend Authority configuration (`authority.yaml`) with strongly-typed `senderConstraints.dpop` and `senderConstraints.mtls` sections (map to sample already shown in architecture doc).
|
- Extend Authority configuration (`authority.yaml`) with strongly-typed `senderConstraints.dpop` and `senderConstraints.mtls` sections (map to sample already shown in architecture doc).
|
||||||
- Require DPoP proofs on `/token` when the registered client policy is `senderConstraint=dpop`; bind issued access tokens via `cnf.jkt`.
|
- Require DPoP proofs on `/token` when the registered client policy is `senderConstraint=dpop`; bind issued access tokens via `cnf.jkt`.
|
||||||
- Introduce Authority-managed nonce issuance for “high value” audiences (default: `signer`, `attestor`) with Redis-backed persistence and deterministic auditing.
|
- Introduce Authority-managed nonce issuance for “high value” audiences (default: `signer`, `attestor`) with Redis-backed persistence and deterministic auditing.
|
||||||
- Enable OAuth 2.0 mTLS (RFC 8705) by storing certificate bindings per client, requesting client certificates at TLS termination, and stamping `cnf.x5t#S256` into issued tokens plus introspection output.
|
- Enable OAuth 2.0 mTLS (RFC 8705) by storing certificate bindings per client, requesting client certificates at TLS termination, and stamping `cnf.x5t#S256` into issued tokens plus introspection output.
|
||||||
- Surface structured logs and counters for both DPoP and mTLS flows; provide integration tests that cover success, replay, invalid proof, and certificate mismatch cases.
|
- Surface structured logs and counters for both DPoP and mTLS flows; provide integration tests that cover success, replay, invalid proof, and certificate mismatch cases.
|
||||||
|
|
||||||
## AUTH-DPOP-11-001 — Proof Validation & Nonce Handling
|
## AUTH-DPOP-11-001 — Proof Validation & Nonce Handling
|
||||||
|
|
||||||
**Shared validator**
|
**Shared validator**
|
||||||
- Move `DpopProofValidator`, option types, and replay cache interfaces from `StellaOps.Scanner.Core` into a new assembly `StellaOps.Auth.Security`.
|
- Move `DpopProofValidator`, option types, and replay cache interfaces from `StellaOps.Scanner.Core` into a new assembly `StellaOps.Auth.Security`.
|
||||||
- Provide pluggable caches: `InMemoryDpopReplayCache` (existing) and new `RedisDpopReplayCache` (leveraging the Authority Redis connection).
|
- Provide pluggable caches: `InMemoryDpopReplayCache` (existing) and new `RedisDpopReplayCache` (leveraging the Authority Redis connection).
|
||||||
- Ensure the validator exposes the validated `SecurityKey`, `jti`, and `iat` so Authority can construct the `cnf` claim and compute nonce expiry.
|
- Ensure the validator exposes the validated `SecurityKey`, `jti`, and `iat` so Authority can construct the `cnf` claim and compute nonce expiry.
|
||||||
|
|
||||||
**Configuration model**
|
**Configuration model**
|
||||||
- Extend `StellaOpsAuthorityOptions.Security` with a `SenderConstraints` property containing:
|
- Extend `StellaOpsAuthorityOptions.Security` with a `SenderConstraints` property containing:
|
||||||
- `Dpop` (`enabled`, `allowedAlgorithms`, `maxAgeSeconds`, `clockSkewSeconds`, `replayWindowSeconds`, `nonce` settings with `enabled`, `ttlSeconds`, `requiredAudiences`, `maxIssuancePerMinute`).
|
- `Dpop` (`enabled`, `allowedAlgorithms`, `maxAgeSeconds`, `clockSkewSeconds`, `replayWindowSeconds`, `nonce` settings with `enabled`, `ttlSeconds`, `requiredAudiences`, `maxIssuancePerMinute`).
|
||||||
- `Mtls` (`enabled`, `requireChainValidation`, `clientCaBundle`, `allowedSubjectPatterns`, `allowedSanTypes`).
|
- `Mtls` (`enabled`, `requireChainValidation`, `clientCaBundle`, `allowedSubjectPatterns`, `allowedSanTypes`).
|
||||||
- Bind from YAML (`authority.security.senderConstraints.*`) while preserving backwards compatibility (defaults keep both disabled).
|
- Bind from YAML (`authority.security.senderConstraints.*`) while preserving backwards compatibility (defaults keep both disabled).
|
||||||
|
|
||||||
**Token endpoint pipeline**
|
**Token endpoint pipeline**
|
||||||
- Introduce a scoped OpenIddict handler `ValidateDpopProofHandler` inserted before `ValidateClientCredentialsHandler`.
|
- Introduce a scoped OpenIddict handler `ValidateDpopProofHandler` inserted before `ValidateClientCredentialsHandler`.
|
||||||
- Determine the required sender constraint from client metadata:
|
- Determine the required sender constraint from client metadata:
|
||||||
- Add `AuthorityClientMetadataKeys.SenderConstraint` storing `dpop` or `mtls`.
|
- Add `AuthorityClientMetadataKeys.SenderConstraint` storing `dpop` or `mtls`.
|
||||||
- Optionally allow per-client overrides for nonce requirement.
|
- Optionally allow per-client overrides for nonce requirement.
|
||||||
- When `dpop` is required:
|
- When `dpop` is required:
|
||||||
- Read the `DPoP` header from the ASP.NET request, reject with `invalid_token` + `WWW-Authenticate: DPoP error="invalid_dpop_proof"` if absent.
|
- Read the `DPoP` header from the ASP.NET request, reject with `invalid_token` + `WWW-Authenticate: DPoP error="invalid_dpop_proof"` if absent.
|
||||||
- Call the shared validator with method/URI. Enforce algorithm allowlist and `iat` window from options.
|
- Call the shared validator with method/URI. Enforce algorithm allowlist and `iat` window from options.
|
||||||
- Persist the `jkt` thumbprint plus replay cache state in the OpenIddict transaction (`AuthorityOpenIddictConstants.DpopKeyThumbprintProperty`, `DpopIssuedAtProperty`).
|
- Persist the `jkt` thumbprint plus replay cache state in the OpenIddict transaction (`AuthorityOpenIddictConstants.DpopKeyThumbprintProperty`, `DpopIssuedAtProperty`).
|
||||||
- When the requested audience intersects `SenderConstraints.Dpop.Nonce.RequiredAudiences`, require `nonce` in the proof; on first failure respond with HTTP 401, `error="use_dpop_nonce"`, and include `DPoP-Nonce` header (see nonce note below). Cache the rejection reason for audit logging.
|
- When the requested audience intersects `SenderConstraints.Dpop.Nonce.RequiredAudiences`, require `nonce` in the proof; on first failure respond with HTTP 401, `error="use_dpop_nonce"`, and include `DPoP-Nonce` header (see nonce note below). Cache the rejection reason for audit logging.
|
||||||
|
|
||||||
**Nonce service**
|
**Nonce service**
|
||||||
- Add `IDpopNonceStore` with methods `IssueAsync(audience, clientId, jkt)` and `TryConsumeAsync(nonce, audience, clientId, jkt)`.
|
- Add `IDpopNonceStore` with methods `IssueAsync(audience, clientId, jkt)` and `TryConsumeAsync(nonce, audience, clientId, jkt)`.
|
||||||
- Default implementation `RedisDpopNonceStore` storing SHA-256 hashes of nonces keyed by `audience:clientId:jkt`. TTL comes from `SenderConstraints.Dpop.Nonce.Ttl`.
|
- Default implementation `RedisDpopNonceStore` storing SHA-256 hashes of nonces keyed by `audience:clientId:jkt`. TTL comes from `SenderConstraints.Dpop.Nonce.Ttl`.
|
||||||
- Create helper `DpopNonceIssuer` used by `ValidateDpopProofHandler` to issue nonces when missing/expired, enforcing issuance rate limits (per options) and tagging audit/log records.
|
- Create helper `DpopNonceIssuer` used by `ValidateDpopProofHandler` to issue nonces when missing/expired, enforcing issuance rate limits (per options) and tagging audit/log records.
|
||||||
- On successful validation (nonce supplied and consumed) stamp metadata into the transaction for auditing.
|
- On successful validation (nonce supplied and consumed) stamp metadata into the transaction for auditing.
|
||||||
- Update `ClientCredentialsHandlers` to observe nonce enforcement: when a nonce challenge was sent, emit structured audit with `nonce_issued`, `audiences`, and `retry`.
|
- Update `ClientCredentialsHandlers` to observe nonce enforcement: when a nonce challenge was sent, emit structured audit with `nonce_issued`, `audiences`, and `retry`.
|
||||||
|
|
||||||
**Token issuance**
|
**Token issuance**
|
||||||
- In `HandleClientCredentialsHandler`, if the transaction contains a validated DPoP key:
|
- In `HandleClientCredentialsHandler`, if the transaction contains a validated DPoP key:
|
||||||
- Build `cnf.jkt` using thumbprint from validator.
|
- Build `cnf.jkt` using thumbprint from validator.
|
||||||
- Include `auth_time`/`dpop_jti` as needed for diagnostics.
|
- Include `auth_time`/`dpop_jti` as needed for diagnostics.
|
||||||
- Persist the thumbprint alongside token metadata in Mongo (extend `AuthorityTokenDocument` with `SenderConstraint`, `KeyThumbprint`, `Nonce` fields).
|
- Persist the thumbprint alongside token metadata in Mongo (extend `AuthorityTokenDocument` with `SenderConstraint`, `KeyThumbprint`, `Nonce` fields).
|
||||||
|
|
||||||
**Auditing & observability**
|
**Auditing & observability**
|
||||||
- Emit new audit events:
|
- Emit new audit events:
|
||||||
- `authority.dpop.proof.validated` (success/failure, clientId, audience, thumbprint, nonce status, jti).
|
- `authority.dpop.proof.validated` (success/failure, clientId, audience, thumbprint, nonce status, jti).
|
||||||
- `authority.dpop.nonce.issued` and `authority.dpop.nonce.consumed`.
|
- `authority.dpop.nonce.issued` and `authority.dpop.nonce.consumed`.
|
||||||
- Metrics (Prometheus style):
|
- Metrics (Prometheus style):
|
||||||
- `authority_dpop_validations_total{result,reason}`.
|
- `authority_dpop_validations_total{result,reason}`.
|
||||||
- `authority_dpop_nonce_issued_total{audience}` and `authority_dpop_nonce_fails_total{reason}`.
|
- `authority_dpop_nonce_issued_total{audience}` and `authority_dpop_nonce_fails_total{reason}`.
|
||||||
- Structured logs include `authority.sender_constraint=dpop`, `authority.dpop_thumbprint`, `authority.dpop_nonce`.
|
- Structured logs include `authority.sender_constraint=dpop`, `authority.dpop_thumbprint`, `authority.dpop_nonce`.
|
||||||
|
|
||||||
**Testing**
|
**Testing**
|
||||||
- Unit tests for the handler pipeline using fake OpenIddict transactions.
|
- Unit tests for the handler pipeline using fake OpenIddict transactions.
|
||||||
- Replay/nonce tests with in-memory and Redis stores.
|
- Replay/nonce tests with in-memory and Redis stores.
|
||||||
- Integration tests in `StellaOps.Authority.Tests` covering:
|
- Integration tests in `StellaOps.Authority.Tests` covering:
|
||||||
- Valid DPoP proof issuing `cnf.jkt`.
|
- Valid DPoP proof issuing `cnf.jkt`.
|
||||||
- Missing header → challenge with nonce.
|
- Missing header → challenge with nonce.
|
||||||
- Replayed `jti` rejected.
|
- Replayed `jti` rejected.
|
||||||
- Invalid nonce rejected even after issuance.
|
- Invalid nonce rejected even after issuance.
|
||||||
- Contract tests to ensure `/.well-known/openid-configuration` advertises `dpop_signing_alg_values_supported` and `dpop_nonce_supported` when enabled.
|
- Contract tests to ensure `/.well-known/openid-configuration` advertises `dpop_signing_alg_values_supported` and `dpop_nonce_supported` when enabled.
|
||||||
|
|
||||||
## AUTH-MTLS-11-002 — Certificate-Bound Tokens
|
## AUTH-MTLS-11-002 — Certificate-Bound Tokens
|
||||||
|
|
||||||
**Configuration model**
|
**Configuration model**
|
||||||
- Reuse `SenderConstraints.Mtls` described above; include:
|
- Reuse `SenderConstraints.Mtls` described above; include:
|
||||||
- `enforceForAudiences` list (defaults `signer`, `attestor`, `scheduler`).
|
- `enforceForAudiences` list (defaults `signer`, `attestor`, `scheduler`).
|
||||||
- `certificateRotationGraceSeconds` for overlap.
|
- `certificateRotationGraceSeconds` for overlap.
|
||||||
- `allowedClientCertificateAuthorities` absolute paths.
|
- `allowedClientCertificateAuthorities` absolute paths.
|
||||||
|
|
||||||
**Kestrel/TLS pipeline**
|
**Kestrel/TLS pipeline**
|
||||||
- Configure Kestrel with `ClientCertificateMode.AllowCertificate` globally and implement middleware that enforces certificate presence only when the resolved client requires mTLS.
|
- Configure Kestrel with `ClientCertificateMode.AllowCertificate` globally and implement middleware that enforces certificate presence only when the resolved client requires mTLS.
|
||||||
- Add `IAuthorityClientCertificateValidator` that validates presented certificate chain, SANs (`dns`, `uri`, optional SPIFFE), and thumbprint matches one of the stored bindings.
|
- Add `IAuthorityClientCertificateValidator` that validates presented certificate chain, SANs (`dns`, `uri`, optional SPIFFE), and thumbprint matches one of the stored bindings.
|
||||||
- Cache validation results per connection id to avoid rehashing on every request.
|
- Cache validation results per connection id to avoid rehashing on every request.
|
||||||
|
|
||||||
**Client registration & storage**
|
**Client registration & storage**
|
||||||
- Extend `AuthorityClientDocument` with `List<AuthorityClientCertificateBinding>` containing:
|
- Extend `AuthorityClientDocument` with `List<AuthorityClientCertificateBinding>` containing:
|
||||||
- `Thumbprint`, `SerialNumber`, `Subject`, `NotBefore`, `NotAfter`, `Sans`, `CreatedAt`, `UpdatedAt`, `Label`.
|
- `Thumbprint`, `SerialNumber`, `Subject`, `NotBefore`, `NotAfter`, `Sans`, `CreatedAt`, `UpdatedAt`, `Label`.
|
||||||
- Provide admin API mutations (`/admin/clients/{id}/certificates`) for ops tooling (deferred implementation but schema ready).
|
- Provide admin API mutations (`/admin/clients/{id}/certificates`) for ops tooling (deferred implementation but schema ready).
|
||||||
- Update plugin provisioning store (`StandardClientProvisioningStore`) to map descriptors with certificate bindings and `senderConstraint`.
|
- Update plugin provisioning store (`StandardClientProvisioningStore`) to map descriptors with certificate bindings and `senderConstraint`.
|
||||||
- Persist binding state in Mongo migrations (index on `{clientId, thumbprint}`).
|
- Persist binding state in Mongo migrations (index on `{clientId, thumbprint}`).
|
||||||
|
|
||||||
**Token issuance & introspection**
|
**Token issuance & introspection**
|
||||||
- Add a transaction property capturing the validated client certificate thumbprint.
|
- Add a transaction property capturing the validated client certificate thumbprint.
|
||||||
- `HandleClientCredentialsHandler`:
|
- `HandleClientCredentialsHandler`:
|
||||||
- When mTLS required, ensure certificate info present; reject otherwise.
|
- When mTLS required, ensure certificate info present; reject otherwise.
|
||||||
- Stamp `cnf` claim: `principal.SetClaim("cnf", JsonSerializer.Serialize(new { x5t#S256 = thumbprint }))`.
|
- Stamp `cnf` claim: `principal.SetClaim("cnf", JsonSerializer.Serialize(new { x5t#S256 = thumbprint }))`.
|
||||||
- Store binding metadata in issued token document for audit.
|
- Store binding metadata in issued token document for audit.
|
||||||
- Update `ValidateAccessTokenHandler` and introspection responses to surface `cnf.x5t#S256`.
|
- Update `ValidateAccessTokenHandler` and introspection responses to surface `cnf.x5t#S256`.
|
||||||
- Ensure refresh tokens (if ever enabled) copy the binding data.
|
- Ensure refresh tokens (if ever enabled) copy the binding data.
|
||||||
|
|
||||||
**Auditing & observability**
|
**Auditing & observability**
|
||||||
- Audit events:
|
- Audit events:
|
||||||
- `authority.mtls.handshake` (success/failure, clientId, thumbprint, issuer, subject).
|
- `authority.mtls.handshake` (success/failure, clientId, thumbprint, issuer, subject).
|
||||||
- `authority.mtls.binding.missing` when a required client posts without a cert.
|
- `authority.mtls.binding.missing` when a required client posts without a cert.
|
||||||
- Metrics:
|
- Metrics:
|
||||||
- `authority_mtls_handshakes_total{result}`.
|
- `authority_mtls_handshakes_total{result}`.
|
||||||
- `authority_mtls_certificate_rotations_total`.
|
- `authority_mtls_certificate_rotations_total`.
|
||||||
- Logs include `authority.sender_constraint=mtls`, `authority.mtls_thumbprint`, `authority.mtls_subject`.
|
- Logs include `authority.sender_constraint=mtls`, `authority.mtls_thumbprint`, `authority.mtls_subject`.
|
||||||
|
|
||||||
**Testing**
|
**Testing**
|
||||||
- Unit tests for certificate validation rules (SAN mismatches, expiry, CA trust).
|
- Unit tests for certificate validation rules (SAN mismatches, expiry, CA trust).
|
||||||
- Integration tests running Kestrel with test certificates:
|
- Integration tests running Kestrel with test certificates:
|
||||||
- Successful token issuance with bound certificate.
|
- Successful token issuance with bound certificate.
|
||||||
- Request without certificate → `invalid_client`.
|
- Request without certificate → `invalid_client`.
|
||||||
- Token introspection reveals `cnf.x5t#S256`.
|
- Token introspection reveals `cnf.x5t#S256`.
|
||||||
- Rotation scenario (old + new cert allowed during grace window).
|
- Rotation scenario (old + new cert allowed during grace window).
|
||||||
|
|
||||||
## Implementation Checklist
|
## Implementation Checklist
|
||||||
|
|
||||||
**DPoP work-stream**
|
**DPoP work-stream**
|
||||||
1. Extract shared validator into `StellaOps.Auth.Security`; update Scanner references.
|
1. Extract shared validator into `StellaOps.Auth.Security`; update Scanner references.
|
||||||
2. Introduce configuration classes and bind from YAML/environment.
|
2. Introduce configuration classes and bind from YAML/environment.
|
||||||
3. Implement nonce store (Redis + in-memory), handler integration, and OpenIddict transaction plumbing.
|
3. Implement nonce store (Redis + in-memory), handler integration, and OpenIddict transaction plumbing.
|
||||||
4. Stamp `cnf.jkt`, audit events, and metrics; update Mongo documents and migrations.
|
4. Stamp `cnf.jkt`, audit events, and metrics; update Mongo documents and migrations.
|
||||||
5. Extend docs: `docs/ARCHITECTURE_AUTHORITY.md`, `docs/security/audit-events.md`, `docs/security/rate-limits.md`, CLI/UI references.
|
5. Extend docs: `docs/ARCHITECTURE_AUTHORITY.md`, `docs/security/audit-events.md`, `docs/security/rate-limits.md`, CLI/UI references.
|
||||||
|
|
||||||
**mTLS work-stream**
|
**mTLS work-stream**
|
||||||
1. Extend client document/schema and provisioning stores with certificate bindings + sender constraint flag.
|
1. Extend client document/schema and provisioning stores with certificate bindings + sender constraint flag.
|
||||||
2. Configure Kestrel/middleware for optional client certificates and validation service.
|
2. Configure Kestrel/middleware for optional client certificates and validation service.
|
||||||
3. Update token issuance/introspection to honour certificate bindings and emit `cnf.x5t#S256`.
|
3. Update token issuance/introspection to honour certificate bindings and emit `cnf.x5t#S256`.
|
||||||
4. Add auditing/metrics and integration tests (happy path + failure).
|
4. Add auditing/metrics and integration tests (happy path + failure).
|
||||||
5. Refresh operator documentation (`docs/ops/authority-backup-restore.md`, `docs/ops/authority-monitoring.md`, sample `authority.yaml`) to cover certificate lifecycle.
|
5. Refresh operator documentation (`docs/ops/authority-backup-restore.md`, `docs/ops/authority-monitoring.md`, sample `authority.yaml`) to cover certificate lifecycle.
|
||||||
|
|
||||||
Both streams should conclude with `dotnet test src/StellaOps.Authority.sln` and documentation cross-links so dependent guilds can unblock UI/Signer work.
|
Both streams should conclude with `dotnet test src/Authority/StellaOps.Authority/StellaOps.Authority.sln` and documentation cross-links so dependent guilds can unblock UI/Signer work.
|
||||||
|
|||||||
@@ -2,42 +2,42 @@
|
|||||||
|
|
||||||
> Created: 2025-10-19 — Plugin Platform Guild & Authority Core
|
> Created: 2025-10-19 — Plugin Platform Guild & Authority Core
|
||||||
> Status: Completed (workshop held 2025-10-20 15:00–16:05 UTC)
|
> Status: Completed (workshop held 2025-10-20 15:00–16:05 UTC)
|
||||||
|
|
||||||
This document tracks preparation, agenda, and outcomes for the scoped-service workshop required before implementing PLUGIN-DI-08-002.
|
This document tracks preparation, agenda, and outcomes for the scoped-service workshop required before implementing PLUGIN-DI-08-002.
|
||||||
|
|
||||||
## Objectives
|
## Objectives
|
||||||
|
|
||||||
- Inventory Authority plug-in surfaces that need scoped service lifetimes.
|
- Inventory Authority plug-in surfaces that need scoped service lifetimes.
|
||||||
- Confirm session/scope handling for identity-provider registrars and background jobs.
|
- Confirm session/scope handling for identity-provider registrars and background jobs.
|
||||||
- Assign follow-up tasks/actions with owners and due dates.
|
- Assign follow-up tasks/actions with owners and due dates.
|
||||||
|
|
||||||
## Scheduling Snapshot
|
## Scheduling Snapshot
|
||||||
|
|
||||||
- **Meeting time:** 2025-10-20 15:00–16:00 UTC (10:00–11:00 CDT / 08:00–09:00 PDT).
|
- **Meeting time:** 2025-10-20 15:00–16:00 UTC (10:00–11:00 CDT / 08:00–09:00 PDT).
|
||||||
- **Facilitator:** Plugin Platform Guild — Alicia Rivera.
|
- **Facilitator:** Plugin Platform Guild — Alicia Rivera.
|
||||||
- **Attendees (confirmed):** Authority Core — Jasmin Patel; Authority Security Guild — Mohan Singh; Plugin Platform — Alicia Rivera, Leah Chen.
|
- **Attendees (confirmed):** Authority Core — Jasmin Patel; Authority Security Guild — Mohan Singh; Plugin Platform — Alicia Rivera, Leah Chen.
|
||||||
- **Optional invitees:** DevOps liaison — Sofia Ortega (accepted).
|
- **Optional invitees:** DevOps liaison — Sofia Ortega (accepted).
|
||||||
- **Logistics:** Invites sent via shared calendar on 2025-10-19 15:30 UTC with Teams bridge + offline dial-in. Meeting notes will be captured here.
|
- **Logistics:** Invites sent via shared calendar on 2025-10-19 15:30 UTC with Teams bridge + offline dial-in. Meeting notes will be captured here.
|
||||||
- **Preparation deadline:** 2025-10-20 12:00 UTC — complete checklist below.
|
- **Preparation deadline:** 2025-10-20 12:00 UTC — complete checklist below.
|
||||||
|
|
||||||
## Pre-work Checklist
|
## Pre-work Checklist
|
||||||
|
|
||||||
- Review `ServiceBindingAttribute` contract introduced by PLUGIN-DI-08-001.
|
- Review `ServiceBindingAttribute` contract introduced by PLUGIN-DI-08-001.
|
||||||
- Collect existing Authority plug-in registration code paths to evaluate.
|
- Collect existing Authority plug-in registration code paths to evaluate.
|
||||||
- Audit background jobs that assume singleton lifetimes.
|
- Audit background jobs that assume singleton lifetimes.
|
||||||
- Identify plug-in health checks/telemetry surfaces impacted by scoped lifetimes.
|
- Identify plug-in health checks/telemetry surfaces impacted by scoped lifetimes.
|
||||||
|
|
||||||
### Pre-work References
|
### Pre-work References
|
||||||
|
|
||||||
| Focus | Path | Notes |
|
| Focus | Path | Notes |
|
||||||
|-------|------|-------|
|
|-------|------|-------|
|
||||||
| Host DI wiring | `src/StellaOps.Authority/StellaOps.Authority/Program.cs:159` | Startup registers `IAuthorityIdentityProviderRegistry` as a singleton and invokes `AuthorityPluginLoader.RegisterPlugins(...)` before the container is built. Any scoped plugin services will currently be captured in the singleton registry context. |
|
| Host DI wiring | `src/Authority/StellaOps.Authority/StellaOps.Authority/Program.cs:159` | Startup registers `IAuthorityIdentityProviderRegistry` as a singleton and invokes `AuthorityPluginLoader.RegisterPlugins(...)` before the container is built. Any scoped plugin services will currently be captured in the singleton registry context. |
|
||||||
| Registrar discovery | `src/StellaOps.Authority/StellaOps.Authority/Plugins/AuthorityPluginLoader.cs:46` | Loader instantiates `IAuthorityPluginRegistrar` implementations via `Activator.CreateInstance`, so registrars cannot depend on host services yet. Need agreement on whether to move discovery post-build or introduce `ActivatorUtilities`. |
|
| Registrar discovery | `src/Authority/StellaOps.Authority/StellaOps.Authority/Plugins/AuthorityPluginLoader.cs:46` | Loader instantiates `IAuthorityPluginRegistrar` implementations via `Activator.CreateInstance`, so registrars cannot depend on host services yet. Need agreement on whether to move discovery post-build or introduce `ActivatorUtilities`. |
|
||||||
| Registry aggregation | `src/StellaOps.Authority/StellaOps.Authority/AuthorityIdentityProviderRegistry.cs:16` | Registry caches `IIdentityProviderPlugin` instances at construction time. With scoped lifetimes we must revisit how providers are resolved (factory vs accessor). |
|
| Registry aggregation | `src/Authority/StellaOps.Authority/StellaOps.Authority/AuthorityIdentityProviderRegistry.cs:16` | Registry caches `IIdentityProviderPlugin` instances at construction time. With scoped lifetimes we must revisit how providers are resolved (factory vs accessor). |
|
||||||
| Standard registrar services | `src/StellaOps.Authority/StellaOps.Authority.Plugin.Standard/StandardPluginRegistrar.cs:21` | All plugin services are registered as singletons today (`StandardUserCredentialStore`, `StandardClientProvisioningStore`, hosted bootstrapper). This registrar is our baseline for migrating to scoped bindings. |
|
| Standard registrar services | `src/Authority/StellaOps.Authority/StellaOps.Authority.Plugin.Standard/StandardPluginRegistrar.cs:21` | All plugin services are registered as singletons today (`StandardUserCredentialStore`, `StandardClientProvisioningStore`, hosted bootstrapper). This registrar is our baseline for migrating to scoped bindings. |
|
||||||
| Hosted bootstrapper | `src/StellaOps.Authority/StellaOps.Authority.Plugin.Standard/Bootstrap/StandardPluginBootstrapper.cs:17` | Background job directly consumes `StandardUserCredentialStore`. If the store becomes scoped we will need an `IServiceScopeFactory` bridge. |
|
| Hosted bootstrapper | `src/Authority/StellaOps.Authority/StellaOps.Authority.Plugin.Standard/Bootstrap/StandardPluginBootstrapper.cs:17` | Background job directly consumes `StandardUserCredentialStore`. If the store becomes scoped we will need an `IServiceScopeFactory` bridge. |
|
||||||
| Password grant handler | `src/StellaOps.Authority/StellaOps.Authority/OpenIddict/Handlers/PasswordGrantHandlers.cs:26` | Password flow resolves `IIdentityProviderPlugin` during scoped requests. Scope semantics must ensure credential stores stay cancellation-aware. |
|
| Password grant handler | `src/Authority/StellaOps.Authority/StellaOps.Authority/OpenIddict/Handlers/PasswordGrantHandlers.cs:26` | Password flow resolves `IIdentityProviderPlugin` during scoped requests. Scope semantics must ensure credential stores stay cancellation-aware. |
|
||||||
| Client credential handler | `src/StellaOps.Authority/StellaOps.Authority/OpenIddict/Handlers/ClientCredentialsHandlers.cs:21` | Handler fetches provider + `ClientProvisioning` store; confirms need for consistent scoping in both user and client flows. |
|
| Client credential handler | `src/Authority/StellaOps.Authority/StellaOps.Authority/OpenIddict/Handlers/ClientCredentialsHandlers.cs:21` | Handler fetches provider + `ClientProvisioning` store; confirms need for consistent scoping in both user and client flows. |
|
||||||
|
|
||||||
## Preliminary Findings — 2025-10-20
|
## Preliminary Findings — 2025-10-20
|
||||||
|
|
||||||
@@ -49,15 +49,15 @@ This document tracks preparation, agenda, and outcomes for the scoped-service wo
|
|||||||
- 2025-10-20 (PLUGIN-DI-08-003): Registry implementation updated to expose metadata + scoped handles; OpenIddict flows, bootstrap endpoints, and `/health` now resolve providers via scoped leases with accompanying test coverage.
|
- 2025-10-20 (PLUGIN-DI-08-003): Registry implementation updated to expose metadata + scoped handles; OpenIddict flows, bootstrap endpoints, and `/health` now resolve providers via scoped leases with accompanying test coverage.
|
||||||
- 2025-10-20 (PLUGIN-DI-08-004): Authority plugin loader now instantiates registrars via scoped DI activations and honours `[ServiceBinding]` metadata in plugin assemblies.
|
- 2025-10-20 (PLUGIN-DI-08-004): Authority plugin loader now instantiates registrars via scoped DI activations and honours `[ServiceBinding]` metadata in plugin assemblies.
|
||||||
- 2025-10-20 (PLUGIN-DI-08-005): `StandardPluginBootstrapper` shifted to scope-per-run execution using `IServiceScopeFactory`, enabling future scoped stores without singleton leaks.
|
- 2025-10-20 (PLUGIN-DI-08-005): `StandardPluginBootstrapper` shifted to scope-per-run execution using `IServiceScopeFactory`, enabling future scoped stores without singleton leaks.
|
||||||
|
|
||||||
## Draft Agenda
|
## Draft Agenda
|
||||||
|
|
||||||
1. Context recap (5 min) — why scoped DI is needed; summary of PLUGIN-DI-08-001 changes.
|
1. Context recap (5 min) — why scoped DI is needed; summary of PLUGIN-DI-08-001 changes.
|
||||||
2. Authority plug-in surfaces (15 min) — registrars, background services, telemetry.
|
2. Authority plug-in surfaces (15 min) — registrars, background services, telemetry.
|
||||||
3. Session handling strategy (10 min) — scope creation semantics, cancellation propagation.
|
3. Session handling strategy (10 min) — scope creation semantics, cancellation propagation.
|
||||||
4. Action items & owners (10 min) — capture code/docs/test tasks with due dates.
|
4. Action items & owners (10 min) — capture code/docs/test tasks with due dates.
|
||||||
5. Risks & follow-ups (5 min) — dependencies, rollout sequencing.
|
5. Risks & follow-ups (5 min) — dependencies, rollout sequencing.
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
- Session opened with recap of scoped-service goals and PLUGIN-DI-08-001 changes, confirming Authority readiness to adopt `[ServiceBinding]` metadata.
|
- Session opened with recap of scoped-service goals and PLUGIN-DI-08-001 changes, confirming Authority readiness to adopt `[ServiceBinding]` metadata.
|
||||||
@@ -65,11 +65,11 @@ This document tracks preparation, agenda, and outcomes for the scoped-service wo
|
|||||||
- Standard plug-in bootstrap will create scopes via `IServiceScopeFactory` and pass cancellation tokens through to avoid lingering singleton references.
|
- Standard plug-in bootstrap will create scopes via `IServiceScopeFactory` and pass cancellation tokens through to avoid lingering singleton references.
|
||||||
- Authority Plugin Loader will enumerate plug-in assemblies at startup but defer registrar activation until a scoped service provider is available, aligning with PLUGIN-DI-08-004 implementation.
|
- Authority Plugin Loader will enumerate plug-in assemblies at startup but defer registrar activation until a scoped service provider is available, aligning with PLUGIN-DI-08-004 implementation.
|
||||||
- Follow-up engineering tasks assigned to land PLUGIN-DI-08-002 code path adjustments and Authority host updates before 2025-10-24.
|
- Follow-up engineering tasks assigned to land PLUGIN-DI-08-002 code path adjustments and Authority host updates before 2025-10-24.
|
||||||
|
|
||||||
## Action Item Log
|
## Action Item Log
|
||||||
|
|
||||||
| Item | Owner | Due | Status | Notes |
|
| Item | Owner | Due | Status | Notes |
|
||||||
|------|-------|-----|--------|-------|
|
|------|-------|-----|--------|-------|
|
||||||
| Confirm meeting time | Alicia Rivera | 2025-10-19 15:30 UTC | DONE | Calendar invite sent; all required attendees accepted |
|
| Confirm meeting time | Alicia Rivera | 2025-10-19 15:30 UTC | DONE | Calendar invite sent; all required attendees accepted |
|
||||||
| Compile Authority plug-in DI entry points | Jasmin Patel | 2025-10-20 | DONE (2025-10-20) | Scoped-service touchpoints summarised in **Pre-work References** and **Preliminary Findings** ahead of the workshop. |
|
| Compile Authority plug-in DI entry points | Jasmin Patel | 2025-10-20 | DONE (2025-10-20) | Scoped-service touchpoints summarised in **Pre-work References** and **Preliminary Findings** ahead of the workshop. |
|
||||||
| Outline scoped-session pattern for background jobs | Leah Chen | 2025-10-21 | DONE (2025-10-20) | Pattern agreed: bootstrap services must open transient scopes per execution via `IServiceScopeFactory`; document update to follow in PLUGIN-DI-08-002 patch. |
|
| Outline scoped-session pattern for background jobs | Leah Chen | 2025-10-21 | DONE (2025-10-20) | Pattern agreed: bootstrap services must open transient scopes per execution via `IServiceScopeFactory`; document update to follow in PLUGIN-DI-08-002 patch. |
|
||||||
|
|||||||
@@ -7,39 +7,39 @@ fixture sets, where they live, and how to regenerate them safely.
|
|||||||
|
|
||||||
## GHSA ↔ OSV parity fixtures
|
## GHSA ↔ OSV parity fixtures
|
||||||
|
|
||||||
- **Location:** `src/StellaOps.Concelier.Connector.Osv.Tests/Fixtures/osv-ghsa.*.json`
|
- **Location:** `src/Concelier/StellaOps.Concelier.PluginBinaries/StellaOps.Concelier.Connector.Osv.Tests/Fixtures/osv-ghsa.*.json`
|
||||||
- **Purpose:** Exercised by `OsvGhsaParityRegressionTests` to ensure OSV + GHSA outputs stay aligned on aliases,
|
- **Purpose:** Exercised by `OsvGhsaParityRegressionTests` to ensure OSV + GHSA outputs stay aligned on aliases,
|
||||||
ranges, references, and credits.
|
ranges, references, and credits.
|
||||||
- **Regeneration:** Either run the test harness with online regeneration (`UPDATE_PARITY_FIXTURES=1 dotnet test src/StellaOps.Concelier.Connector.Osv.Tests/StellaOps.Concelier.Connector.Osv.Tests.csproj`)
|
- **Regeneration:** Either run the test harness with online regeneration (`UPDATE_PARITY_FIXTURES=1 dotnet test src/Concelier/StellaOps.Concelier.PluginBinaries/StellaOps.Concelier.Connector.Osv.Tests/StellaOps.Concelier.Connector.Osv.Tests.csproj`)
|
||||||
or execute the fixture updater (`dotnet run --project tools/FixtureUpdater/FixtureUpdater.csproj`). Both paths
|
or execute the fixture updater (`dotnet run --project tools/FixtureUpdater/FixtureUpdater.csproj`). Both paths
|
||||||
normalise timestamps and canonical ordering.
|
normalise timestamps and canonical ordering.
|
||||||
- **SemVer provenance:** The regenerated fixtures should show `normalizedVersions[].notes` in the
|
- **SemVer provenance:** The regenerated fixtures should show `normalizedVersions[].notes` in the
|
||||||
`osv:{ecosystem}:{advisoryId}:{identifier}` shape emitted by `SemVerRangeRuleBuilder`. Confirm the
|
`osv:{ecosystem}:{advisoryId}:{identifier}` shape emitted by `SemVerRangeRuleBuilder`. Confirm the
|
||||||
constraints and notes line up with GHSA/NVD composites before committing.
|
constraints and notes line up with GHSA/NVD composites before committing.
|
||||||
- **Verification:** Inspect the diff, then re-run `dotnet test src/StellaOps.Concelier.Connector.Osv.Tests/StellaOps.Concelier.Connector.Osv.Tests.csproj` to confirm parity.
|
- **Verification:** Inspect the diff, then re-run `dotnet test src/Concelier/StellaOps.Concelier.PluginBinaries/StellaOps.Concelier.Connector.Osv.Tests/StellaOps.Concelier.Connector.Osv.Tests.csproj` to confirm parity.
|
||||||
|
|
||||||
## GHSA credit parity fixtures
|
## GHSA credit parity fixtures
|
||||||
|
|
||||||
- **Location:** `src/StellaOps.Concelier.Connector.Ghsa.Tests/Fixtures/credit-parity.{ghsa,osv,nvd}.json`
|
- **Location:** `src/Concelier/StellaOps.Concelier.PluginBinaries/StellaOps.Concelier.Connector.Ghsa.Tests/Fixtures/credit-parity.{ghsa,osv,nvd}.json`
|
||||||
- **Purpose:** Exercised by `GhsaCreditParityRegressionTests` to guarantee GHSA/NVD/OSV acknowledgements remain in lockstep.
|
- **Purpose:** Exercised by `GhsaCreditParityRegressionTests` to guarantee GHSA/NVD/OSV acknowledgements remain in lockstep.
|
||||||
- **Regeneration:** `dotnet run --project tools/FixtureUpdater/FixtureUpdater.csproj` rewrites all three canonical snapshots.
|
- **Regeneration:** `dotnet run --project tools/FixtureUpdater/FixtureUpdater.csproj` rewrites all three canonical snapshots.
|
||||||
- **Verification:** `dotnet test src/StellaOps.Concelier.Connector.Ghsa.Tests/StellaOps.Concelier.Connector.Ghsa.Tests.csproj`.
|
- **Verification:** `dotnet test src/Concelier/StellaOps.Concelier.PluginBinaries/StellaOps.Concelier.Connector.Ghsa.Tests/StellaOps.Concelier.Connector.Ghsa.Tests.csproj`.
|
||||||
|
|
||||||
> Always commit fixture changes together with the code that motivated them and reference the regression test that guards the behaviour.
|
> Always commit fixture changes together with the code that motivated them and reference the regression test that guards the behaviour.
|
||||||
|
|
||||||
## Apple security update fixtures
|
## Apple security update fixtures
|
||||||
|
|
||||||
- **Location:** `src/StellaOps.Concelier.Connector.Vndr.Apple.Tests/Apple/Fixtures/*.html` and `.expected.json`.
|
- **Location:** `src/Concelier/__Tests/StellaOps.Concelier.Connector.Vndr.Apple.Tests/Apple/Fixtures/*.html` and `.expected.json`.
|
||||||
- **Purpose:** Exercised by `AppleLiveRegressionTests` to guarantee the Apple HTML parser and mapper stay deterministic while covering Rapid Security Responses and multi-device advisories.
|
- **Purpose:** Exercised by `AppleLiveRegressionTests` to guarantee the Apple HTML parser and mapper stay deterministic while covering Rapid Security Responses and multi-device advisories.
|
||||||
- **Regeneration:** Use the helper scripts (`scripts/update-apple-fixtures.sh` or `scripts/update-apple-fixtures.ps1`). They export `UPDATE_APPLE_FIXTURES=1`, propagate the flag through `WSLENV`, touch `.update-apple-fixtures`, and then run the Apple test project. This keeps WSL/VSCode test invocations in sync while the refresh workflow fetches live Apple support pages, sanitises them, and rewrites both the HTML and expected DTO snapshots with normalised ordering.
|
- **Regeneration:** Use the helper scripts (`scripts/update-apple-fixtures.sh` or `scripts/update-apple-fixtures.ps1`). They export `UPDATE_APPLE_FIXTURES=1`, propagate the flag through `WSLENV`, touch `.update-apple-fixtures`, and then run the Apple test project. This keeps WSL/VSCode test invocations in sync while the refresh workflow fetches live Apple support pages, sanitises them, and rewrites both the HTML and expected DTO snapshots with normalised ordering.
|
||||||
- **Verification:** Inspect the generated diffs and re-run `dotnet test src/StellaOps.Concelier.Connector.Vndr.Apple.Tests/StellaOps.Concelier.Connector.Vndr.Apple.Tests.csproj` without the env var to confirm determinism.
|
- **Verification:** Inspect the generated diffs and re-run `dotnet test src/Concelier/__Tests/StellaOps.Concelier.Connector.Vndr.Apple.Tests/StellaOps.Concelier.Connector.Vndr.Apple.Tests.csproj` without the env var to confirm determinism.
|
||||||
|
|
||||||
> **Tip for other connector owners:** mirror the sentinel + `WSLENV` pattern (`touch .update-<connector>-fixtures`, append the env var via `WSLENV`) when you add fixture refresh scripts so contributors running under WSL inherit the regeneration flag automatically.
|
> **Tip for other connector owners:** mirror the sentinel + `WSLENV` pattern (`touch .update-<connector>-fixtures`, append the env var via `WSLENV`) when you add fixture refresh scripts so contributors running under WSL inherit the regeneration flag automatically.
|
||||||
|
|
||||||
## KISA advisory fixtures
|
## KISA advisory fixtures
|
||||||
|
|
||||||
- **Location:** `src/StellaOps.Concelier.Connector.Kisa.Tests/Fixtures/kisa-{feed,detail}.(xml|json)`
|
- **Location:** `src/Concelier/__Tests/StellaOps.Concelier.Connector.Kisa.Tests/Fixtures/kisa-{feed,detail}.(xml|json)`
|
||||||
- **Purpose:** Used by `KisaConnectorTests` to verify Hangul-aware fetch → parse → map flows and to assert telemetry counters stay wired.
|
- **Purpose:** Used by `KisaConnectorTests` to verify Hangul-aware fetch → parse → map flows and to assert telemetry counters stay wired.
|
||||||
- **Regeneration:** `UPDATE_KISA_FIXTURES=1 dotnet test src/StellaOps.Concelier.Connector.Kisa.Tests/StellaOps.Concelier.Connector.Kisa.Tests.csproj`
|
- **Regeneration:** `UPDATE_KISA_FIXTURES=1 dotnet test src/Concelier/__Tests/StellaOps.Concelier.Connector.Kisa.Tests/StellaOps.Concelier.Connector.Kisa.Tests.csproj`
|
||||||
- **Verification:** Re-run the same test suite without the env var; confirm advisory content remains NFC-normalised and HTML is sanitised. Metrics assertions will fail if counters drift.
|
- **Verification:** Re-run the same test suite without the env var; confirm advisory content remains NFC-normalised and HTML is sanitised. Metrics assertions will fail if counters drift.
|
||||||
- **Localisation note:** RSS `category` values (e.g. `취약점정보`) remain in Hangul—do not translate them in fixtures; they feed directly into metrics/log tags.
|
- **Localisation note:** RSS `category` values (e.g. `취약점정보`) remain in Hangul—do not translate them in fixtures; they feed directly into metrics/log tags.
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ The messages use structured properties (`Idx`, `Category`, `DocumentId`, `Severi
|
|||||||
- Hangul fields (`title`, `summary`, `category`, `reference.label`, product vendor/name) are normalised to NFC before storage. Sample category `취약점정보` roughly translates to “vulnerability information”.
|
- Hangul fields (`title`, `summary`, `category`, `reference.label`, product vendor/name) are normalised to NFC before storage. Sample category `취약점정보` roughly translates to “vulnerability information”.
|
||||||
- Advisory HTML is sanitised via `HtmlContentSanitizer`, stripping script/style while preserving inline anchors for translation pipelines.
|
- Advisory HTML is sanitised via `HtmlContentSanitizer`, stripping script/style while preserving inline anchors for translation pipelines.
|
||||||
- Metrics carry Hangul `category` tags and logging keeps Hangul strings intact; this ensures air-gapped operators can validate native-language content without relying on MT.
|
- Metrics carry Hangul `category` tags and logging keeps Hangul strings intact; this ensures air-gapped operators can validate native-language content without relying on MT.
|
||||||
- Fixtures live under `src/StellaOps.Concelier.Connector.Kisa.Tests/Fixtures/`. Regenerate with `UPDATE_KISA_FIXTURES=1 dotnet test src/StellaOps.Concelier.Connector.Kisa.Tests/StellaOps.Concelier.Connector.Kisa.Tests.csproj`.
|
- Fixtures live under `src/Concelier/__Tests/StellaOps.Concelier.Connector.Kisa.Tests/Fixtures/`. Regenerate with `UPDATE_KISA_FIXTURES=1 dotnet test src/Concelier/__Tests/StellaOps.Concelier.Connector.Kisa.Tests/StellaOps.Concelier.Connector.Kisa.Tests.csproj`.
|
||||||
- The regression suite asserts canonical mapping, state cleanup, and telemetry counters (`KisaConnectorTests.Telemetry_RecordsMetrics`) so QA can track instrumentation drift.
|
- The regression suite asserts canonical mapping, state cleanup, and telemetry counters (`KisaConnectorTests.Telemetry_RecordsMetrics`) so QA can track instrumentation drift.
|
||||||
|
|
||||||
For operator docs, link to this brief when documenting Hangul handling or counter dashboards so localisation reviewers have a single reference point.
|
For operator docs, link to this brief when documenting Hangul handling or counter dashboards so localisation reviewers have a single reference point.
|
||||||
|
|||||||
@@ -1,154 +1,154 @@
|
|||||||
# Concelier SemVer Merge Playbook (Sprint 1–2)
|
# Concelier SemVer Merge Playbook (Sprint 1–2)
|
||||||
|
|
||||||
This playbook describes how the merge layer and connector teams should emit the new SemVer primitives introduced in Sprint 1–2, how those primitives become normalized version rules, and how downstream jobs query them deterministically.
|
This playbook describes how the merge layer and connector teams should emit the new SemVer primitives introduced in Sprint 1–2, how those primitives become normalized version rules, and how downstream jobs query them deterministically.
|
||||||
|
|
||||||
## 1. What landed in Sprint 1–2
|
## 1. What landed in Sprint 1–2
|
||||||
|
|
||||||
- `RangePrimitives.SemVer` now infers a canonical `style` (`range`, `exact`, `lt`, `lte`, `gt`, `gte`) and captures `exactValue` when the constraint is a single version.
|
- `RangePrimitives.SemVer` now infers a canonical `style` (`range`, `exact`, `lt`, `lte`, `gt`, `gte`) and captures `exactValue` when the constraint is a single version.
|
||||||
- `NormalizedVersionRule` documents the analytics-friendly projection of each `AffectedPackage` coverage entry and is persisted alongside legacy `versionRanges`.
|
- `NormalizedVersionRule` documents the analytics-friendly projection of each `AffectedPackage` coverage entry and is persisted alongside legacy `versionRanges`.
|
||||||
- `AdvisoryProvenance.decisionReason` records whether merge resolution favored precedence, freshness, or a tie-breaker comparison.
|
- `AdvisoryProvenance.decisionReason` records whether merge resolution favored precedence, freshness, or a tie-breaker comparison.
|
||||||
|
|
||||||
See `src/StellaOps.Concelier.Models/CANONICAL_RECORDS.md` for the full schema and field descriptions.
|
See `src/Concelier/__Libraries/StellaOps.Concelier.Models/CANONICAL_RECORDS.md` for the full schema and field descriptions.
|
||||||
|
|
||||||
## 2. Mapper pattern
|
## 2. Mapper pattern
|
||||||
|
|
||||||
Connectors should emit SemVer primitives as soon as they can normalize a vendor constraint. The helper `SemVerPrimitiveExtensions.ToNormalizedVersionRule` turns those primitives into the persisted rules:
|
Connectors should emit SemVer primitives as soon as they can normalize a vendor constraint. The helper `SemVerPrimitiveExtensions.ToNormalizedVersionRule` turns those primitives into the persisted rules:
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
var primitive = new SemVerPrimitive(
|
var primitive = new SemVerPrimitive(
|
||||||
introduced: "1.2.3",
|
introduced: "1.2.3",
|
||||||
introducedInclusive: true,
|
introducedInclusive: true,
|
||||||
fixed: "2.0.0",
|
fixed: "2.0.0",
|
||||||
fixedInclusive: false,
|
fixedInclusive: false,
|
||||||
lastAffected: null,
|
lastAffected: null,
|
||||||
lastAffectedInclusive: false,
|
lastAffectedInclusive: false,
|
||||||
constraintExpression: ">=1.2.3 <2.0.0",
|
constraintExpression: ">=1.2.3 <2.0.0",
|
||||||
exactValue: null);
|
exactValue: null);
|
||||||
|
|
||||||
var rule = primitive.ToNormalizedVersionRule(notes: "nvd:CVE-2025-1234");
|
var rule = primitive.ToNormalizedVersionRule(notes: "nvd:CVE-2025-1234");
|
||||||
// rule => scheme=semver, type=range, min=1.2.3, minInclusive=true, max=2.0.0, maxInclusive=false
|
// rule => scheme=semver, type=range, min=1.2.3, minInclusive=true, max=2.0.0, maxInclusive=false
|
||||||
```
|
```
|
||||||
|
|
||||||
If you omit the optional `notes` argument, `ToNormalizedVersionRule` now falls back to the primitive’s `ConstraintExpression`, ensuring the original comparator expression is preserved for provenance/audit queries.
|
If you omit the optional `notes` argument, `ToNormalizedVersionRule` now falls back to the primitive’s `ConstraintExpression`, ensuring the original comparator expression is preserved for provenance/audit queries.
|
||||||
|
|
||||||
Emit the resulting rule inside `AffectedPackage.NormalizedVersions` while continuing to populate `AffectedVersionRange.RangeExpression` for backward compatibility.
|
Emit the resulting rule inside `AffectedPackage.NormalizedVersions` while continuing to populate `AffectedVersionRange.RangeExpression` for backward compatibility.
|
||||||
|
|
||||||
## 3. Merge dedupe flow
|
## 3. Merge dedupe flow
|
||||||
|
|
||||||
During merge, feed all package candidates through `NormalizedVersionRuleComparer.Instance` prior to persistence. The comparer orders by scheme → type → min → minInclusive → max → maxInclusive → value → notes, guaranteeing consistent document layout and making `$unwind` pipelines deterministic.
|
During merge, feed all package candidates through `NormalizedVersionRuleComparer.Instance` prior to persistence. The comparer orders by scheme → type → min → minInclusive → max → maxInclusive → value → notes, guaranteeing consistent document layout and making `$unwind` pipelines deterministic.
|
||||||
|
|
||||||
If multiple connectors emit identical constraints, the merge layer should:
|
If multiple connectors emit identical constraints, the merge layer should:
|
||||||
|
|
||||||
1. Combine provenance entries (preserving one per source).
|
1. Combine provenance entries (preserving one per source).
|
||||||
2. Preserve a single normalized rule instance (thanks to `NormalizedVersionRuleEqualityComparer.Instance`).
|
2. Preserve a single normalized rule instance (thanks to `NormalizedVersionRuleEqualityComparer.Instance`).
|
||||||
3. Attach `decisionReason="precedence"` if one source overrides another.
|
3. Attach `decisionReason="precedence"` if one source overrides another.
|
||||||
|
|
||||||
## 4. Example Mongo pipeline
|
## 4. Example Mongo pipeline
|
||||||
|
|
||||||
Use the following aggregation to locate advisories that affect a specific SemVer:
|
Use the following aggregation to locate advisories that affect a specific SemVer:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
db.advisories.aggregate([
|
db.advisories.aggregate([
|
||||||
{ $match: { "affectedPackages.type": "semver", "affectedPackages.identifier": "pkg:npm/lodash" } },
|
{ $match: { "affectedPackages.type": "semver", "affectedPackages.identifier": "pkg:npm/lodash" } },
|
||||||
{ $unwind: "$affectedPackages" },
|
{ $unwind: "$affectedPackages" },
|
||||||
{ $unwind: "$affectedPackages.normalizedVersions" },
|
{ $unwind: "$affectedPackages.normalizedVersions" },
|
||||||
{ $match: {
|
{ $match: {
|
||||||
$or: [
|
$or: [
|
||||||
{ "affectedPackages.normalizedVersions.type": "exact",
|
{ "affectedPackages.normalizedVersions.type": "exact",
|
||||||
"affectedPackages.normalizedVersions.value": "4.17.21" },
|
"affectedPackages.normalizedVersions.value": "4.17.21" },
|
||||||
{ "affectedPackages.normalizedVersions.type": "range",
|
{ "affectedPackages.normalizedVersions.type": "range",
|
||||||
"affectedPackages.normalizedVersions.min": { $lte: "4.17.21" },
|
"affectedPackages.normalizedVersions.min": { $lte: "4.17.21" },
|
||||||
"affectedPackages.normalizedVersions.max": { $gt: "4.17.21" } },
|
"affectedPackages.normalizedVersions.max": { $gt: "4.17.21" } },
|
||||||
{ "affectedPackages.normalizedVersions.type": "gte",
|
{ "affectedPackages.normalizedVersions.type": "gte",
|
||||||
"affectedPackages.normalizedVersions.min": { $lte: "4.17.21" } },
|
"affectedPackages.normalizedVersions.min": { $lte: "4.17.21" } },
|
||||||
{ "affectedPackages.normalizedVersions.type": "lte",
|
{ "affectedPackages.normalizedVersions.type": "lte",
|
||||||
"affectedPackages.normalizedVersions.max": { $gte: "4.17.21" } }
|
"affectedPackages.normalizedVersions.max": { $gte: "4.17.21" } }
|
||||||
]
|
]
|
||||||
}},
|
}},
|
||||||
{ $project: { advisoryKey: 1, title: 1, "affectedPackages.identifier": 1 } }
|
{ $project: { advisoryKey: 1, title: 1, "affectedPackages.identifier": 1 } }
|
||||||
]);
|
]);
|
||||||
```
|
```
|
||||||
|
|
||||||
Pair this query with the indexes listed in [Normalized Versions Query Guide](mongo_indices.md).
|
Pair this query with the indexes listed in [Normalized Versions Query Guide](mongo_indices.md).
|
||||||
|
|
||||||
## 5. Recommended indexes
|
## 5. Recommended indexes
|
||||||
|
|
||||||
| Collection | Index | Purpose |
|
| Collection | Index | Purpose |
|
||||||
|------------|-------|---------|
|
|------------|-------|---------|
|
||||||
| `advisory` | `{ "affectedPackages.identifier": 1, "affectedPackages.normalizedVersions.scheme": 1, "affectedPackages.normalizedVersions.type": 1 }` (compound, multikey) | Speeds up `$match` on identifier + rule style. |
|
| `advisory` | `{ "affectedPackages.identifier": 1, "affectedPackages.normalizedVersions.scheme": 1, "affectedPackages.normalizedVersions.type": 1 }` (compound, multikey) | Speeds up `$match` on identifier + rule style. |
|
||||||
| `advisory` | `{ "affectedPackages.normalizedVersions.value": 1 }` (sparse) | Optimizes lookups for exact version hits. |
|
| `advisory` | `{ "affectedPackages.normalizedVersions.value": 1 }` (sparse) | Optimizes lookups for exact version hits. |
|
||||||
|
|
||||||
Coordinate with the Storage team when enabling these indexes so deployment windows account for collection size.
|
Coordinate with the Storage team when enabling these indexes so deployment windows account for collection size.
|
||||||
|
|
||||||
## 6. Dual-write rollout
|
## 6. Dual-write rollout
|
||||||
|
|
||||||
Follow the operational checklist in `docs/ops/migrations/SEMVER_STYLE.md`. The summary:
|
Follow the operational checklist in `docs/ops/migrations/SEMVER_STYLE.md`. The summary:
|
||||||
|
|
||||||
1. **Dual write (now)** – emit both legacy `versionRanges` and the new `normalizedVersions`.
|
1. **Dual write (now)** – emit both legacy `versionRanges` and the new `normalizedVersions`.
|
||||||
2. **Backfill** – follow the storage migration in `docs/ops/migrations/SEMVER_STYLE.md` to rewrite historical advisories before switching consumers.
|
2. **Backfill** – follow the storage migration in `docs/ops/migrations/SEMVER_STYLE.md` to rewrite historical advisories before switching consumers.
|
||||||
3. **Verify** – run the aggregation above (with `explain("executionStats")`) to ensure the new indexes are used.
|
3. **Verify** – run the aggregation above (with `explain("executionStats")`) to ensure the new indexes are used.
|
||||||
4. **Cutover** – after consumers switch to normalized rules, mark the old `rangeExpression` as deprecated.
|
4. **Cutover** – after consumers switch to normalized rules, mark the old `rangeExpression` as deprecated.
|
||||||
|
|
||||||
## 7. Checklist for connectors & merge
|
## 7. Checklist for connectors & merge
|
||||||
|
|
||||||
- [ ] Populate `SemVerPrimitive` for every SemVer-friendly constraint.
|
- [ ] Populate `SemVerPrimitive` for every SemVer-friendly constraint.
|
||||||
- [ ] Call `ToNormalizedVersionRule` and store the result.
|
- [ ] Call `ToNormalizedVersionRule` and store the result.
|
||||||
- [ ] Emit provenance masks covering both `versionRanges[].primitives.semver` and `normalizedVersions[]`.
|
- [ ] Emit provenance masks covering both `versionRanges[].primitives.semver` and `normalizedVersions[]`.
|
||||||
- [ ] Ensure merge deduping relies on the canonical comparer.
|
- [ ] Ensure merge deduping relies on the canonical comparer.
|
||||||
- [ ] Capture merge decisions via `decisionReason`.
|
- [ ] Capture merge decisions via `decisionReason`.
|
||||||
- [ ] Confirm integration tests include fixtures with normalized rules and SemVer styles.
|
- [ ] Confirm integration tests include fixtures with normalized rules and SemVer styles.
|
||||||
|
|
||||||
For deeper query examples and maintenance tasks, continue with [Normalized Versions Query Guide](mongo_indices.md).
|
For deeper query examples and maintenance tasks, continue with [Normalized Versions Query Guide](mongo_indices.md).
|
||||||
|
|
||||||
## 8. Storage projection reference
|
## 8. Storage projection reference
|
||||||
|
|
||||||
`NormalizedVersionDocumentFactory` copies each normalized rule into MongoDB using the shape below. Use this as a contract when reviewing connector fixtures or diagnosing merge/storage diffs:
|
`NormalizedVersionDocumentFactory` copies each normalized rule into MongoDB using the shape below. Use this as a contract when reviewing connector fixtures or diagnosing merge/storage diffs:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"packageId": "pkg:npm/example",
|
"packageId": "pkg:npm/example",
|
||||||
"packageType": "npm",
|
"packageType": "npm",
|
||||||
"scheme": "semver",
|
"scheme": "semver",
|
||||||
"type": "range",
|
"type": "range",
|
||||||
"style": "range",
|
"style": "range",
|
||||||
"min": "1.2.3",
|
"min": "1.2.3",
|
||||||
"minInclusive": true,
|
"minInclusive": true,
|
||||||
"max": "2.0.0",
|
"max": "2.0.0",
|
||||||
"maxInclusive": false,
|
"maxInclusive": false,
|
||||||
"value": null,
|
"value": null,
|
||||||
"notes": "ghsa:GHSA-xxxx-yyyy",
|
"notes": "ghsa:GHSA-xxxx-yyyy",
|
||||||
"decisionReason": "ghsa-precedence-over-nvd",
|
"decisionReason": "ghsa-precedence-over-nvd",
|
||||||
"constraint": ">= 1.2.3 < 2.0.0",
|
"constraint": ">= 1.2.3 < 2.0.0",
|
||||||
"source": "ghsa",
|
"source": "ghsa",
|
||||||
"recordedAt": "2025-10-11T00:00:00Z"
|
"recordedAt": "2025-10-11T00:00:00Z"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
For distro-specific ranges (`nevra`, `evr`) the same envelope applies with `scheme` switched accordingly. Example:
|
For distro-specific ranges (`nevra`, `evr`) the same envelope applies with `scheme` switched accordingly. Example:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"packageId": "bash",
|
"packageId": "bash",
|
||||||
"packageType": "rpm",
|
"packageType": "rpm",
|
||||||
"scheme": "nevra",
|
"scheme": "nevra",
|
||||||
"type": "range",
|
"type": "range",
|
||||||
"style": "range",
|
"style": "range",
|
||||||
"min": "0:4.4.18-2.el7",
|
"min": "0:4.4.18-2.el7",
|
||||||
"minInclusive": true,
|
"minInclusive": true,
|
||||||
"max": "0:4.4.20-1.el7",
|
"max": "0:4.4.20-1.el7",
|
||||||
"maxInclusive": false,
|
"maxInclusive": false,
|
||||||
"value": null,
|
"value": null,
|
||||||
"notes": "redhat:RHSA-2025:1234",
|
"notes": "redhat:RHSA-2025:1234",
|
||||||
"decisionReason": "rhel-priority-over-nvd",
|
"decisionReason": "rhel-priority-over-nvd",
|
||||||
"constraint": "<= 0:4.4.20-1.el7",
|
"constraint": "<= 0:4.4.20-1.el7",
|
||||||
"source": "redhat",
|
"source": "redhat",
|
||||||
"recordedAt": "2025-10-11T00:00:00Z"
|
"recordedAt": "2025-10-11T00:00:00Z"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
If a new scheme is required (for example, `apple.build` or `ios.semver`), raise it with the Models team before emitting documents so merge comparers and hashing logic can incorporate the change deterministically.
|
If a new scheme is required (for example, `apple.build` or `ios.semver`), raise it with the Models team before emitting documents so merge comparers and hashing logic can incorporate the change deterministically.
|
||||||
|
|
||||||
## 9. Observability signals
|
## 9. Observability signals
|
||||||
|
|
||||||
- `concelier.merge.normalized_rules` (counter, tags: `package_type`, `scheme`) – increments once per normalized rule retained after precedence merge.
|
- `concelier.merge.normalized_rules` (counter, tags: `package_type`, `scheme`) – increments once per normalized rule retained after precedence merge.
|
||||||
- `concelier.merge.normalized_rules_missing` (counter, tags: `package_type`) – increments when a merged package still carries version ranges but no normalized rules; watch for spikes to catch connectors that have not emitted normalized arrays yet.
|
- `concelier.merge.normalized_rules_missing` (counter, tags: `package_type`) – increments when a merged package still carries version ranges but no normalized rules; watch for spikes to catch connectors that have not emitted normalized arrays yet.
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ _Status date: 2025-10-20 19:10 UTC_
|
|||||||
|
|
||||||
This dashboard tracks connector readiness for emitting `AffectedPackage.NormalizedVersions` arrays and highlights upcoming coordination checkpoints. Use it alongside:
|
This dashboard tracks connector readiness for emitting `AffectedPackage.NormalizedVersions` arrays and highlights upcoming coordination checkpoints. Use it alongside:
|
||||||
|
|
||||||
- [`src/StellaOps.Concelier.Merge/RANGE_PRIMITIVES_COORDINATION.md`](../../src/StellaOps.Concelier.Merge/RANGE_PRIMITIVES_COORDINATION.md) for detailed guidance and timelines.
|
- [`src/Concelier/__Libraries/StellaOps.Concelier.Merge/RANGE_PRIMITIVES_COORDINATION.md`](../../src/Concelier/__Libraries/StellaOps.Concelier.Merge/RANGE_PRIMITIVES_COORDINATION.md) for detailed guidance and timelines.
|
||||||
- [Concelier SemVer Merge Playbook](merge_semver_playbook.md) §8 for persisted Mongo document shapes.
|
- [Concelier SemVer Merge Playbook](merge_semver_playbook.md) §8 for persisted Mongo document shapes.
|
||||||
- [Normalized Versions Query Guide](mongo_indices.md) for index/query validation steps.
|
- [Normalized Versions Query Guide](mongo_indices.md) for index/query validation steps.
|
||||||
|
|
||||||
@@ -20,20 +20,20 @@ This dashboard tracks connector readiness for emitting `AffectedPackage.Normaliz
|
|||||||
|
|
||||||
| Connector | Owner team | Normalized versions status | Last update | Next action / link |
|
| Connector | Owner team | Normalized versions status | Last update | Next action / link |
|
||||||
|-----------|------------|---------------------------|-------------|--------------------|
|
|-----------|------------|---------------------------|-------------|--------------------|
|
||||||
| Acsc | BE-Conn-ACSC | ❌ Not started – normalized helper pending relay stability | 2025-10-20 | Prepare builder integration plan for 2025-10-24 kickoff; update `src/StellaOps.Concelier.Connector.Acsc/TASKS.md` once branch opens. |
|
| Acsc | BE-Conn-ACSC | ❌ Not started – normalized helper pending relay stability | 2025-10-20 | Prepare builder integration plan for 2025-10-24 kickoff; update `src/Concelier/StellaOps.Concelier.PluginBinaries/StellaOps.Concelier.Connector.Acsc/TASKS.md` once branch opens. |
|
||||||
| Cccs | BE-Conn-CCCS | ⚠️ DOING – trailing-version helper MR reviewing (due 2025-10-21) | 2025-10-20 | Land helper + fixture refresh, post merge-counter screenshot; `src/StellaOps.Concelier.Connector.Cccs/TASKS.md`. |
|
| Cccs | BE-Conn-CCCS | ⚠️ DOING – trailing-version helper MR reviewing (due 2025-10-21) | 2025-10-20 | Land helper + fixture refresh, post merge-counter screenshot; `src/Concelier/StellaOps.Concelier.PluginBinaries/StellaOps.Concelier.Connector.Cccs/TASKS.md`. |
|
||||||
| CertBund | BE-Conn-CERTBUND | ⚠️ In progress – localisation translator WIP (due 2025-10-22) | 2025-10-20 | Finish translator + provenance notes, regenerate fixtures; `src/StellaOps.Concelier.Connector.CertBund/TASKS.md`. |
|
| CertBund | BE-Conn-CERTBUND | ⚠️ In progress – localisation translator WIP (due 2025-10-22) | 2025-10-20 | Finish translator + provenance notes, regenerate fixtures; `src/Concelier/StellaOps.Concelier.PluginBinaries/StellaOps.Concelier.Connector.CertBund/TASKS.md`. |
|
||||||
| CertCc | BE-Conn-CERTCC | ✅ Complete – `certcc.vendor` rules emitting | 2025-10-20 | Monitor VINCE payload changes; no action. |
|
| CertCc | BE-Conn-CERTCC | ✅ Complete – `certcc.vendor` rules emitting | 2025-10-20 | Monitor VINCE payload changes; no action. |
|
||||||
| Kev | BE-Conn-KEV | ✅ Complete – catalog/due-date rules verified | 2025-10-20 | Routine monitoring only. |
|
| Kev | BE-Conn-KEV | ✅ Complete – catalog/due-date rules verified | 2025-10-20 | Routine monitoring only. |
|
||||||
| Cve | BE-Conn-CVE | ✅ Complete – SemVer normalized rules live | 2025-10-20 | Keep fixtures in sync as CVE schema evolves. |
|
| Cve | BE-Conn-CVE | ✅ Complete – SemVer normalized rules live | 2025-10-20 | Keep fixtures in sync as CVE schema evolves. |
|
||||||
| Ghsa | BE-Conn-GHSA | ✅ Complete – rollout merged 2025-10-11 | 2025-10-20 | Maintain parity with OSV ecosystems; no action. |
|
| Ghsa | BE-Conn-GHSA | ✅ Complete – rollout merged 2025-10-11 | 2025-10-20 | Maintain parity with OSV ecosystems; no action. |
|
||||||
| Osv | BE-Conn-OSV | ✅ Complete – normalized rules shipping | 2025-10-20 | Watch for new ecosystems; refresh fixtures as needed. |
|
| Osv | BE-Conn-OSV | ✅ Complete – normalized rules shipping | 2025-10-20 | Watch for new ecosystems; refresh fixtures as needed. |
|
||||||
| Ics.Cisa | BE-Conn-ICS-CISA | ⚠️ Decision pending – exact SemVer promotion due 2025-10-23 | 2025-10-20 | Promote primitives or request new scheme; `src/StellaOps.Concelier.Connector.Ics.Cisa/TASKS.md`. |
|
| Ics.Cisa | BE-Conn-ICS-CISA | ⚠️ Decision pending – exact SemVer promotion due 2025-10-23 | 2025-10-20 | Promote primitives or request new scheme; `src/Concelier/StellaOps.Concelier.PluginBinaries/StellaOps.Concelier.Connector.Ics.Cisa/TASKS.md`. |
|
||||||
| Kisa | BE-Conn-KISA | ⚠️ Proposal drafting – firmware scheme due 2025-10-24 | 2025-10-20 | Finalise `kisa.build` proposal with Models; update mapper/tests; `src/StellaOps.Concelier.Connector.Kisa/TASKS.md`. |
|
| Kisa | BE-Conn-KISA | ⚠️ Proposal drafting – firmware scheme due 2025-10-24 | 2025-10-20 | Finalise `kisa.build` proposal with Models; update mapper/tests; `src/Concelier/StellaOps.Concelier.PluginBinaries/StellaOps.Concelier.Connector.Kisa/TASKS.md`. |
|
||||||
| Ru.Bdu | BE-Conn-BDU | ✅ Complete – `ru-bdu.raw` rules live | 2025-10-20 | Continue monitoring UTF-8 handling; no action. |
|
| Ru.Bdu | BE-Conn-BDU | ✅ Complete – `ru-bdu.raw` rules live | 2025-10-20 | Continue monitoring UTF-8 handling; no action. |
|
||||||
| Ru.Nkcki | BE-Conn-Nkcki | ✅ Complete – normalized rules emitted | 2025-10-20 | Maintain transliteration guidance; no action. |
|
| Ru.Nkcki | BE-Conn-Nkcki | ✅ Complete – normalized rules emitted | 2025-10-20 | Maintain transliteration guidance; no action. |
|
||||||
| Vndr.Apple | BE-Conn-Apple | ✅ Complete – normalized arrays emitting | 2025-10-20 | Add beta-channel coverage follow-up; see module README. |
|
| Vndr.Apple | BE-Conn-Apple | ✅ Complete – normalized arrays emitting | 2025-10-20 | Add beta-channel coverage follow-up; see module README. |
|
||||||
| Vndr.Cisco | BE-Conn-Cisco | ⚠️ DOING – normalized promotion branch open (due 2025-10-21) | 2025-10-20 | Merge helper branch, refresh fixtures, post counters; `src/StellaOps.Concelier.Connector.Vndr.Cisco/TASKS.md`. |
|
| Vndr.Cisco | BE-Conn-Cisco | ⚠️ DOING – normalized promotion branch open (due 2025-10-21) | 2025-10-20 | Merge helper branch, refresh fixtures, post counters; `src/Concelier/StellaOps.Concelier.PluginBinaries/StellaOps.Concelier.Connector.Vndr.Cisco/TASKS.md`. |
|
||||||
| Vndr.Msrc | BE-Conn-MSRC | ✅ Complete – `msrc.build` rules emitting | 2025-10-20 | Monitor monthly rollups; no action. |
|
| Vndr.Msrc | BE-Conn-MSRC | ✅ Complete – `msrc.build` rules emitting | 2025-10-20 | Monitor monthly rollups; no action. |
|
||||||
| Nvd | BE-Conn-NVD | ✅ Complete – normalized SemVer output live | 2025-10-20 | Keep provenance aligned with CVE IDs; monitor export parity toggle. |
|
| Nvd | BE-Conn-NVD | ✅ Complete – normalized SemVer output live | 2025-10-20 | Keep provenance aligned with CVE IDs; monitor export parity toggle. |
|
||||||
|
|
||||||
|
|||||||
@@ -1,27 +1,27 @@
|
|||||||
# Policy Schema Export Automation
|
# Policy Schema Export Automation
|
||||||
|
|
||||||
This utility generates JSON Schema documents for the Policy Engine run contracts.
|
This utility generates JSON Schema documents for the Policy Engine run contracts.
|
||||||
|
|
||||||
## Command
|
## Command
|
||||||
|
|
||||||
```
|
```
|
||||||
scripts/export-policy-schemas.sh [output-directory]
|
scripts/export-policy-schemas.sh [output-directory]
|
||||||
```
|
```
|
||||||
|
|
||||||
When no output directory is supplied, schemas are written to `docs/schemas/`.
|
When no output directory is supplied, schemas are written to `docs/schemas/`.
|
||||||
|
|
||||||
The exporter builds against `StellaOps.Scheduler.Models` and emits:
|
The exporter builds against `StellaOps.Scheduler.Models` and emits:
|
||||||
|
|
||||||
- `policy-run-request.schema.json`
|
- `policy-run-request.schema.json`
|
||||||
- `policy-run-status.schema.json`
|
- `policy-run-status.schema.json`
|
||||||
- `policy-diff-summary.schema.json`
|
- `policy-diff-summary.schema.json`
|
||||||
- `policy-explain-trace.schema.json`
|
- `policy-explain-trace.schema.json`
|
||||||
|
|
||||||
The build pipeline (`.gitea/workflows/build-test-deploy.yml`, job **Export policy run schemas**) runs this script on every push and pull request. Exports land under `artifacts/policy-schemas/<commit>/`, are published as the `policy-schema-exports` artifact, and changes trigger a Slack post to `#policy-engine` via the `POLICY_ENGINE_SCHEMA_WEBHOOK` secret. A unified diff is stored alongside the exports for downstream consumers.
|
The build pipeline (`.gitea/workflows/build-test-deploy.yml`, job **Export policy run schemas**) runs this script on every push and pull request. Exports land under `artifacts/policy-schemas/<commit>/`, are published as the `policy-schema-exports` artifact, and changes trigger a Slack post to `#policy-engine` via the `POLICY_ENGINE_SCHEMA_WEBHOOK` secret. A unified diff is stored alongside the exports for downstream consumers.
|
||||||
|
|
||||||
## CI integration checklist
|
## CI integration checklist
|
||||||
|
|
||||||
- [x] Invoke the script in the DevOps pipeline (see `DEVOPS-POLICY-20-004`).
|
- [x] Invoke the script in the DevOps pipeline (see `DEVOPS-POLICY-20-004`).
|
||||||
- [x] Publish the generated schemas as pipeline artifacts.
|
- [x] Publish the generated schemas as pipeline artifacts.
|
||||||
- [x] Notify downstream consumers when schemas change (Slack `#policy-engine`, changelog snippet).
|
- [x] Notify downstream consumers when schemas change (Slack `#policy-engine`, changelog snippet).
|
||||||
- [ ] Gate CLI validation once schema artifacts are available.
|
- [ ] Gate CLI validation once schema artifacts are available.
|
||||||
|
|||||||
@@ -1,121 +1,121 @@
|
|||||||
# Scanner Orchestrator Events (ORCH-SVC-38-101)
|
# Scanner Orchestrator Events (ORCH-SVC-38-101)
|
||||||
|
|
||||||
Last updated: 2025-10-26
|
Last updated: 2025-10-26
|
||||||
|
|
||||||
The Notifications Studio initiative (NOTIFY-SVC-38-001) and orchestrator backlog (ORCH-SVC-38-101) standardise how platform services emit lifecycle events. This document describes the Scanner WebService contract for the new **orchestrator envelopes** (`scanner.event.*`) and how they supersede the legacy Redis-backed `scanner.report.ready` / `scanner.scan.completed` events.
|
The Notifications Studio initiative (NOTIFY-SVC-38-001) and orchestrator backlog (ORCH-SVC-38-101) standardise how platform services emit lifecycle events. This document describes the Scanner WebService contract for the new **orchestrator envelopes** (`scanner.event.*`) and how they supersede the legacy Redis-backed `scanner.report.ready` / `scanner.scan.completed` events.
|
||||||
|
|
||||||
## 1. Envelope overview
|
## 1. Envelope overview
|
||||||
|
|
||||||
Orchestrator events share a deterministic JSON envelope:
|
Orchestrator events share a deterministic JSON envelope:
|
||||||
|
|
||||||
| Field | Type | Notes |
|
| Field | Type | Notes |
|
||||||
|-------|------|-------|
|
|-------|------|-------|
|
||||||
| `eventId` | `uuid` | Globally unique identifier generated per occurrence. |
|
| `eventId` | `uuid` | Globally unique identifier generated per occurrence. |
|
||||||
| `kind` | `string` | Event identifier; Scanner emits `scanner.event.report.ready` and `scanner.event.scan.completed`. |
|
| `kind` | `string` | Event identifier; Scanner emits `scanner.event.report.ready` and `scanner.event.scan.completed`. |
|
||||||
| `version` | `integer` | Schema version. Initial release uses `1`. |
|
| `version` | `integer` | Schema version. Initial release uses `1`. |
|
||||||
| `tenant` | `string` | Tenant that owns the scan/report. Mirrors Authority claims. |
|
| `tenant` | `string` | Tenant that owns the scan/report. Mirrors Authority claims. |
|
||||||
| `occurredAt` | `date-time` | UTC instant when the underlying state transition happened (e.g., report persisted). |
|
| `occurredAt` | `date-time` | UTC instant when the underlying state transition happened (e.g., report persisted). |
|
||||||
| `recordedAt` | `date-time` | UTC instant when the event was durably written. Optional but recommended. |
|
| `recordedAt` | `date-time` | UTC instant when the event was durably written. Optional but recommended. |
|
||||||
| `source` | `string` | Producer identifier (`scanner.webservice`). |
|
| `source` | `string` | Producer identifier (`scanner.webservice`). |
|
||||||
| `idempotencyKey` | `string` | Deterministic key for duplicate suppression (see §4). |
|
| `idempotencyKey` | `string` | Deterministic key for duplicate suppression (see §4). |
|
||||||
| `correlationId` | `string` | Maps back to the API request or scan identifier. |
|
| `correlationId` | `string` | Maps back to the API request or scan identifier. |
|
||||||
| `traceId` / `spanId` | `string` | W3C trace context propagated into downstream telemetry. |
|
| `traceId` / `spanId` | `string` | W3C trace context propagated into downstream telemetry. |
|
||||||
| `scope` | `object` | Describes the affected artefact. Requires `repo` and `digest`; optional `namespace`, `component`, `image`. |
|
| `scope` | `object` | Describes the affected artefact. Requires `repo` and `digest`; optional `namespace`, `component`, `image`. |
|
||||||
| `attributes` | `object` | Flat string map for frequently queried metadata (e.g., policy revision). |
|
| `attributes` | `object` | Flat string map for frequently queried metadata (e.g., policy revision). |
|
||||||
| `payload` | `object` | Event-specific body (see §2). |
|
| `payload` | `object` | Event-specific body (see §2). |
|
||||||
|
|
||||||
Canonical schemas live under `docs/events/scanner.event.*@1.json`. Samples that round-trip through `NotifyCanonicalJsonSerializer` are stored in `docs/events/samples/`.
|
Canonical schemas live under `docs/events/scanner.event.*@1.json`. Samples that round-trip through `NotifyCanonicalJsonSerializer` are stored in `docs/events/samples/`.
|
||||||
|
|
||||||
## 2. Event kinds and payloads
|
## 2. Event kinds and payloads
|
||||||
|
|
||||||
### 2.1 `scanner.event.report.ready`
|
### 2.1 `scanner.event.report.ready`
|
||||||
|
|
||||||
Emitted once a signed report is persisted and attested. Payload highlights:
|
Emitted once a signed report is persisted and attested. Payload highlights:
|
||||||
|
|
||||||
- `reportId` / `scanId` — identifiers for the persisted report and originating scan. Until Scan IDs are surfaced by the API, `scanId` mirrors `reportId` so downstream correlators can stabilise on a single key.
|
- `reportId` / `scanId` — identifiers for the persisted report and originating scan. Until Scan IDs are surfaced by the API, `scanId` mirrors `reportId` so downstream correlators can stabilise on a single key.
|
||||||
- **Attributes:** `reportId`, `policyRevisionId`, `policyDigest`, `verdict` — pre-sorted for deterministic routing.
|
- **Attributes:** `reportId`, `policyRevisionId`, `policyDigest`, `verdict` — pre-sorted for deterministic routing.
|
||||||
- **Links:**
|
- **Links:**
|
||||||
- `ui` → `/ui/reports/{reportId}` on the current host.
|
- `ui` → `/ui/reports/{reportId}` on the current host.
|
||||||
- `report` → `{apiBasePath}/{reportsSegment}/{reportId}` (defaults to `/api/v1/reports/{reportId}`).
|
- `report` → `{apiBasePath}/{reportsSegment}/{reportId}` (defaults to `/api/v1/reports/{reportId}`).
|
||||||
- `policy` → `{apiBasePath}/{policySegment}/revisions/{revisionId}` when a revision is present.
|
- `policy` → `{apiBasePath}/{policySegment}/revisions/{revisionId}` when a revision is present.
|
||||||
- `attestation` → `/ui/attestations/{reportId}` when a DSSE envelope is included.
|
- `attestation` → `/ui/attestations/{reportId}` when a DSSE envelope is included.
|
||||||
- `imageDigest` — OCI image digest associated with the analysis.
|
- `imageDigest` — OCI image digest associated with the analysis.
|
||||||
- `generatedAt` — report generation timestamp (ISO-8601 UTC).
|
- `generatedAt` — report generation timestamp (ISO-8601 UTC).
|
||||||
- `verdict` — `pass`, `warn`, or `fail` after policy evaluation.
|
- `verdict` — `pass`, `warn`, or `fail` after policy evaluation.
|
||||||
- `summary` — blocked/warned/ignored/quieted counters (all non-negative integers).
|
- `summary` — blocked/warned/ignored/quieted counters (all non-negative integers).
|
||||||
- `delta` — newly critical/high counts and optional `kev` array.
|
- `delta` — newly critical/high counts and optional `kev` array.
|
||||||
- `quietedFindingCount` — mirrors `summary.quieted`.
|
- `quietedFindingCount` — mirrors `summary.quieted`.
|
||||||
- `policy` — revision metadata (`digest`, `revisionId`) surfaced for routing.
|
- `policy` — revision metadata (`digest`, `revisionId`) surfaced for routing.
|
||||||
- `links` — UI/report/policy URLs suitable for operators.
|
- `links` — UI/report/policy URLs suitable for operators.
|
||||||
- `dsse` — embedded DSSE envelope (payload, type, signature list).
|
- `dsse` — embedded DSSE envelope (payload, type, signature list).
|
||||||
- `report` — canonical report document; identical to the DSSE payload.
|
- `report` — canonical report document; identical to the DSSE payload.
|
||||||
|
|
||||||
Schema: `docs/events/scanner.event.report.ready@1.json`
|
Schema: `docs/events/scanner.event.report.ready@1.json`
|
||||||
Sample: `docs/events/samples/scanner.event.report.ready@1.sample.json`
|
Sample: `docs/events/samples/scanner.event.report.ready@1.sample.json`
|
||||||
|
|
||||||
### 2.2 `scanner.event.scan.completed`
|
### 2.2 `scanner.event.scan.completed`
|
||||||
|
|
||||||
Emitted after scan execution finishes (success or policy failure). Payload highlights:
|
Emitted after scan execution finishes (success or policy failure). Payload highlights:
|
||||||
|
|
||||||
- `reportId` / `scanId` / `imageDigest` — identifiers mirroring the report-ready event. As with the report-ready payload, `scanId` currently mirrors `reportId` as a temporary shim.
|
- `reportId` / `scanId` / `imageDigest` — identifiers mirroring the report-ready event. As with the report-ready payload, `scanId` currently mirrors `reportId` as a temporary shim.
|
||||||
- **Attributes:** `reportId`, `policyRevisionId`, `policyDigest`, `verdict`.
|
- **Attributes:** `reportId`, `policyRevisionId`, `policyDigest`, `verdict`.
|
||||||
- **Links:** same as above (`ui`, `report`, `policy`) with `attestation` populated when DSSE metadata exists.
|
- **Links:** same as above (`ui`, `report`, `policy`) with `attestation` populated when DSSE metadata exists.
|
||||||
- `verdict`, `summary`, `delta`, `policy` — same semantics as above.
|
- `verdict`, `summary`, `delta`, `policy` — same semantics as above.
|
||||||
- `findings` — array of surfaced findings with `id`, `severity`, optional `cve`, `purl`, and `reachability`.
|
- `findings` — array of surfaced findings with `id`, `severity`, optional `cve`, `purl`, and `reachability`.
|
||||||
- `links`, `dsse`, `report` — same structure as §2.1 (allows Notifier to reuse signatures).
|
- `links`, `dsse`, `report` — same structure as §2.1 (allows Notifier to reuse signatures).
|
||||||
|
|
||||||
Schema: `docs/events/scanner.event.scan.completed@1.json`
|
Schema: `docs/events/scanner.event.scan.completed@1.json`
|
||||||
Sample: `docs/events/samples/scanner.event.scan.completed@1.sample.json`
|
Sample: `docs/events/samples/scanner.event.scan.completed@1.sample.json`
|
||||||
|
|
||||||
### 2.3 Relationship to legacy events
|
### 2.3 Relationship to legacy events
|
||||||
|
|
||||||
| Legacy Redis event | Replacement orchestrator event | Notes |
|
| Legacy Redis event | Replacement orchestrator event | Notes |
|
||||||
|--------------------|-------------------------------|-------|
|
|--------------------|-------------------------------|-------|
|
||||||
| `scanner.report.ready` | `scanner.event.report.ready` | Adds versioning, idempotency, trace context. Payload is a superset of the legacy fields. |
|
| `scanner.report.ready` | `scanner.event.report.ready` | Adds versioning, idempotency, trace context. Payload is a superset of the legacy fields. |
|
||||||
| `scanner.scan.completed` | `scanner.event.scan.completed` | Same data plus explicit scan identifiers and orchestrator metadata. |
|
| `scanner.scan.completed` | `scanner.event.scan.completed` | Same data plus explicit scan identifiers and orchestrator metadata. |
|
||||||
|
|
||||||
Legacy schemas remain for backwards-compatibility during migration, but new integrations **must** target the orchestrator variants.
|
Legacy schemas remain for backwards-compatibility during migration, but new integrations **must** target the orchestrator variants.
|
||||||
|
|
||||||
## 3. Deterministic serialization
|
## 3. Deterministic serialization
|
||||||
|
|
||||||
- Producers must serialise events using `NotifyCanonicalJsonSerializer` to guarantee consistent key ordering and whitespace.
|
- Producers must serialise events using `NotifyCanonicalJsonSerializer` to guarantee consistent key ordering and whitespace.
|
||||||
- Timestamps (`occurredAt`, `recordedAt`, `payload.generatedAt`) use `DateTimeOffset.UtcDateTime.ToString("O")`.
|
- Timestamps (`occurredAt`, `recordedAt`, `payload.generatedAt`) use `DateTimeOffset.UtcDateTime.ToString("O")`.
|
||||||
- Payload arrays (`delta.kev`, `findings`) should be pre-sorted (e.g., alphabetical CVE order) so hash-based consumers remain stable.
|
- Payload arrays (`delta.kev`, `findings`) should be pre-sorted (e.g., alphabetical CVE order) so hash-based consumers remain stable.
|
||||||
- Optional fields are omitted rather than emitted as `null`.
|
- Optional fields are omitted rather than emitted as `null`.
|
||||||
|
|
||||||
## 4. Idempotency and correlation
|
## 4. Idempotency and correlation
|
||||||
|
|
||||||
Idempotency keys dedupe repeated publishes and align with the orchestrator’s outbox pattern:
|
Idempotency keys dedupe repeated publishes and align with the orchestrator’s outbox pattern:
|
||||||
|
|
||||||
| Event kind | Idempotency key template |
|
| Event kind | Idempotency key template |
|
||||||
|------------|-------------------------|
|
|------------|-------------------------|
|
||||||
| `scanner.event.report.ready` | `scanner.event.report.ready:<tenant>:<reportId>` |
|
| `scanner.event.report.ready` | `scanner.event.report.ready:<tenant>:<reportId>` |
|
||||||
| `scanner.event.scan.completed` | `scanner.event.scan.completed:<tenant>:<scanId>` |
|
| `scanner.event.scan.completed` | `scanner.event.scan.completed:<tenant>:<scanId>` |
|
||||||
|
|
||||||
Keys are ASCII lowercase; components should be trimmed and validated before concatenation. Retries must reuse the same key.
|
Keys are ASCII lowercase; components should be trimmed and validated before concatenation. Retries must reuse the same key.
|
||||||
|
|
||||||
`correlationId` should match the scan identifier that appears in REST responses (`scanId`). Re-using the same value across the pair of events allows Notifier and orchestrator analytics to stitch lifecycle data together.
|
`correlationId` should match the scan identifier that appears in REST responses (`scanId`). Re-using the same value across the pair of events allows Notifier and orchestrator analytics to stitch lifecycle data together.
|
||||||
|
|
||||||
## 5. Versioning and evolution
|
## 5. Versioning and evolution
|
||||||
|
|
||||||
- Increment the `version` field and the `@<version>` suffix for **breaking** changes (field removals, type changes, semantic shifts).
|
- Increment the `version` field and the `@<version>` suffix for **breaking** changes (field removals, type changes, semantic shifts).
|
||||||
- Additive optional fields may remain within version 1; update the JSON schema and samples accordingly.
|
- Additive optional fields may remain within version 1; update the JSON schema and samples accordingly.
|
||||||
- When introducing `@2`, keep the `@1` schema/docs in place until orchestrator subscribers confirm migration.
|
- When introducing `@2`, keep the `@1` schema/docs in place until orchestrator subscribers confirm migration.
|
||||||
|
|
||||||
## 6. Consumer checklist
|
## 6. Consumer checklist
|
||||||
|
|
||||||
1. Validate incoming payloads against the schema for the targeted version.
|
1. Validate incoming payloads against the schema for the targeted version.
|
||||||
2. Use `idempotencyKey` for dedupe, not `eventId`.
|
2. Use `idempotencyKey` for dedupe, not `eventId`.
|
||||||
3. Map `traceId`/`spanId` into telemetry spans to preserve causality.
|
3. Map `traceId`/`spanId` into telemetry spans to preserve causality.
|
||||||
4. Prefer `payload.report` → `policy.revisionId` when populating templates; the top-level `attributes` are convenience duplicates for quick routing.
|
4. Prefer `payload.report` → `policy.revisionId` when populating templates; the top-level `attributes` are convenience duplicates for quick routing.
|
||||||
5. Reserve the legacy Redis events for transitional compatibility only; downstream systems should subscribe to the orchestrator bus exposed by ORCH-SVC-38-101.
|
5. Reserve the legacy Redis events for transitional compatibility only; downstream systems should subscribe to the orchestrator bus exposed by ORCH-SVC-38-101.
|
||||||
|
|
||||||
## 7. Implementation status and next actions
|
## 7. Implementation status and next actions
|
||||||
|
|
||||||
- **Scanner WebService** — `SCANNER-EVENTS-16-301` (blocked) and `SCANNER-EVENTS-16-302` (doing) track the production of these envelopes. The remaining blocker is the .NET 10 preview OpenAPI/Auth dependency drift that currently breaks `dotnet test`. Once Gateway and Notifier owners land the replacement packages, rerun the full test suite and capture fresh fixtures under `docs/events/samples/`.
|
- **Scanner WebService** — `SCANNER-EVENTS-16-301` (blocked) and `SCANNER-EVENTS-16-302` (doing) track the production of these envelopes. The remaining blocker is the .NET 10 preview OpenAPI/Auth dependency drift that currently breaks `dotnet test`. Once Gateway and Notifier owners land the replacement packages, rerun the full test suite and capture fresh fixtures under `docs/events/samples/`.
|
||||||
- **Gateway/Notifier consumers** — subscribe to the orchestrator stream documented in ORCH-SVC-38-101. When the Scanner tasks unblock, regenerate notifier contract tests against the sample events included here.
|
- **Gateway/Notifier consumers** — subscribe to the orchestrator stream documented in ORCH-SVC-38-101. When the Scanner tasks unblock, regenerate notifier contract tests against the sample events included here.
|
||||||
- **Docs cadence** — update this file and the matching JSON schemas whenever payload fields change. Use the rehearsal checklist in `docs/ops/launch-cutover.md` to confirm downstream validation before the production cutover. Record gaps or newly required fields in `docs/ops/launch-readiness.md` so they land in the launch checklist.
|
- **Docs cadence** — update this file and the matching JSON schemas whenever payload fields change. Use the rehearsal checklist in `docs/ops/launch-cutover.md` to confirm downstream validation before the production cutover. Record gaps or newly required fields in `docs/ops/launch-readiness.md` so they land in the launch checklist.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
**Imposed rule reminder:** work of this type or tasks of this type on this component must also be applied everywhere else it should be applied.
|
**Imposed rule reminder:** work of this type or tasks of this type on this component must also be applied everywhere else it should be applied.
|
||||||
|
|||||||
@@ -1,93 +1,93 @@
|
|||||||
{
|
{
|
||||||
"eventId": "6d2d1b77-f3c3-4f70-8a9d-6f2d0c8801ab",
|
"eventId": "6d2d1b77-f3c3-4f70-8a9d-6f2d0c8801ab",
|
||||||
"kind": "scanner.event.report.ready",
|
"kind": "scanner.event.report.ready",
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"tenant": "tenant-alpha",
|
"tenant": "tenant-alpha",
|
||||||
"occurredAt": "2025-10-19T12:34:56Z",
|
"occurredAt": "2025-10-19T12:34:56Z",
|
||||||
"recordedAt": "2025-10-19T12:34:57Z",
|
"recordedAt": "2025-10-19T12:34:57Z",
|
||||||
"source": "scanner.webservice",
|
"source": "scanner.webservice",
|
||||||
"idempotencyKey": "scanner.event.report.ready:tenant-alpha:report-abc",
|
"idempotencyKey": "scanner.event.report.ready:tenant-alpha:report-abc",
|
||||||
"correlationId": "report-abc",
|
"correlationId": "report-abc",
|
||||||
"traceId": "0af7651916cd43dd8448eb211c80319c",
|
"traceId": "0af7651916cd43dd8448eb211c80319c",
|
||||||
"spanId": "b7ad6b7169203331",
|
"spanId": "b7ad6b7169203331",
|
||||||
"scope": {
|
"scope": {
|
||||||
"namespace": "acme/edge",
|
"namespace": "acme/edge",
|
||||||
"repo": "api",
|
"repo": "api",
|
||||||
"digest": "sha256:feedface"
|
"digest": "sha256:feedface"
|
||||||
},
|
},
|
||||||
"attributes": {
|
"attributes": {
|
||||||
"reportId": "report-abc",
|
"reportId": "report-abc",
|
||||||
"policyRevisionId": "rev-42",
|
"policyRevisionId": "rev-42",
|
||||||
"policyDigest": "digest-123",
|
"policyDigest": "digest-123",
|
||||||
"verdict": "blocked"
|
"verdict": "blocked"
|
||||||
},
|
},
|
||||||
"payload": {
|
"payload": {
|
||||||
"reportId": "report-abc",
|
"reportId": "report-abc",
|
||||||
"scanId": "report-abc",
|
"scanId": "report-abc",
|
||||||
"imageDigest": "sha256:feedface",
|
"imageDigest": "sha256:feedface",
|
||||||
"generatedAt": "2025-10-19T12:34:56Z",
|
"generatedAt": "2025-10-19T12:34:56Z",
|
||||||
"verdict": "fail",
|
"verdict": "fail",
|
||||||
"summary": {
|
"summary": {
|
||||||
"total": 1,
|
"total": 1,
|
||||||
"blocked": 1,
|
"blocked": 1,
|
||||||
"warned": 0,
|
"warned": 0,
|
||||||
"ignored": 0,
|
"ignored": 0,
|
||||||
"quieted": 0
|
"quieted": 0
|
||||||
},
|
},
|
||||||
"delta": {
|
"delta": {
|
||||||
"newCritical": 1,
|
"newCritical": 1,
|
||||||
"kev": [
|
"kev": [
|
||||||
"CVE-2024-9999"
|
"CVE-2024-9999"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"quietedFindingCount": 0,
|
"quietedFindingCount": 0,
|
||||||
"policy": {
|
"policy": {
|
||||||
"digest": "digest-123",
|
"digest": "digest-123",
|
||||||
"revisionId": "rev-42"
|
"revisionId": "rev-42"
|
||||||
},
|
},
|
||||||
"links": {
|
"links": {
|
||||||
"ui": "https://scanner.example/ui/reports/report-abc",
|
"ui": "https://scanner.example/ui/reports/report-abc",
|
||||||
"report": "https://scanner.example/api/v1/reports/report-abc",
|
"report": "https://scanner.example/api/v1/reports/report-abc",
|
||||||
"policy": "https://scanner.example/api/v1/policy/revisions/rev-42",
|
"policy": "https://scanner.example/api/v1/policy/revisions/rev-42",
|
||||||
"attestation": "https://scanner.example/ui/attestations/report-abc"
|
"attestation": "https://scanner.example/ui/attestations/report-abc"
|
||||||
},
|
},
|
||||||
"dsse": {
|
"dsse": {
|
||||||
"payloadType": "application/vnd.stellaops.report+json",
|
"payloadType": "application/vnd.stellaops.report+json",
|
||||||
"payload": "eyJyZXBvcnRJZCI6InJlcG9ydC1hYmMiLCJpbWFnZURpZ2VzdCI6InNoYTI1NjpmZWVkZmFjZSIsImdlbmVyYXRlZEF0IjoiMjAyNS0xMC0xOVQxMjozNDo1NiswMDowMCIsInZlcmRpY3QiOiJibG9ja2VkIiwicG9saWN5Ijp7InJldmlzaW9uSWQiOiJyZXYtNDIiLCJkaWdlc3QiOiJkaWdlc3QtMTIzIn0sInN1bW1hcnkiOnsidG90YWwiOjEsImJsb2NrZWQiOjEsIndhcm5lZCI6MCwiaWdub3JlZCI6MCwicXVpZXRlZCI6MH0sInZlcmRpY3RzIjpbeyJmaW5kaW5nSWQiOiJmaW5kaW5nLTEiLCJzdGF0dXMiOiJCbG9ja2VkIiwic2NvcmUiOjQ3LjUsInNvdXJjZVRydXN0IjoiTlZEIiwicmVhY2hhYmlsaXR5IjoicnVudGltZSJ9XSwiaXNzdWVzIjpbXX0=",
|
"payload": "eyJyZXBvcnRJZCI6InJlcG9ydC1hYmMiLCJpbWFnZURpZ2VzdCI6InNoYTI1NjpmZWVkZmFjZSIsImdlbmVyYXRlZEF0IjoiMjAyNS0xMC0xOVQxMjozNDo1NiswMDowMCIsInZlcmRpY3QiOiJibG9ja2VkIiwicG9saWN5Ijp7InJldmlzaW9uSWQiOiJyZXYtNDIiLCJkaWdlc3QiOiJkaWdlc3QtMTIzIn0sInN1bW1hcnkiOnsidG90YWwiOjEsImJsb2NrZWQiOjEsIndhcm5lZCI6MCwiaWdub3JlZCI6MCwicXVpZXRlZCI6MH0sInZlcmRpY3RzIjpbeyJmaW5kaW5nSWQiOiJmaW5kaW5nLTEiLCJzdGF0dXMiOiJCbG9ja2VkIiwic2NvcmUiOjQ3LjUsInNvdXJjZVRydXN0IjoiTlZEIiwicmVhY2hhYmlsaXR5IjoicnVudGltZSJ9XSwiaXNzdWVzIjpbXX0=",
|
||||||
"signatures": [
|
"signatures": [
|
||||||
{
|
{
|
||||||
"keyId": "test-key",
|
"keyId": "test-key",
|
||||||
"algorithm": "hs256",
|
"algorithm": "hs256",
|
||||||
"signature": "signature-value"
|
"signature": "signature-value"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"report": {
|
"report": {
|
||||||
"reportId": "report-abc",
|
"reportId": "report-abc",
|
||||||
"generatedAt": "2025-10-19T12:34:56Z",
|
"generatedAt": "2025-10-19T12:34:56Z",
|
||||||
"imageDigest": "sha256:feedface",
|
"imageDigest": "sha256:feedface",
|
||||||
"policy": {
|
"policy": {
|
||||||
"digest": "digest-123",
|
"digest": "digest-123",
|
||||||
"revisionId": "rev-42"
|
"revisionId": "rev-42"
|
||||||
},
|
},
|
||||||
"summary": {
|
"summary": {
|
||||||
"total": 1,
|
"total": 1,
|
||||||
"blocked": 1,
|
"blocked": 1,
|
||||||
"warned": 0,
|
"warned": 0,
|
||||||
"ignored": 0,
|
"ignored": 0,
|
||||||
"quieted": 0
|
"quieted": 0
|
||||||
},
|
},
|
||||||
"verdict": "blocked",
|
"verdict": "blocked",
|
||||||
"verdicts": [
|
"verdicts": [
|
||||||
{
|
{
|
||||||
"findingId": "finding-1",
|
"findingId": "finding-1",
|
||||||
"status": "Blocked",
|
"status": "Blocked",
|
||||||
"score": 47.5,
|
"score": 47.5,
|
||||||
"sourceTrust": "NVD",
|
"sourceTrust": "NVD",
|
||||||
"reachability": "runtime"
|
"reachability": "runtime"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"issues": []
|
"issues": []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,99 +1,99 @@
|
|||||||
{
|
{
|
||||||
"eventId": "08a6de24-4a94-4d14-8432-9d14f36f6da3",
|
"eventId": "08a6de24-4a94-4d14-8432-9d14f36f6da3",
|
||||||
"kind": "scanner.event.scan.completed",
|
"kind": "scanner.event.scan.completed",
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"tenant": "tenant-alpha",
|
"tenant": "tenant-alpha",
|
||||||
"occurredAt": "2025-10-19T12:34:56Z",
|
"occurredAt": "2025-10-19T12:34:56Z",
|
||||||
"recordedAt": "2025-10-19T12:34:57Z",
|
"recordedAt": "2025-10-19T12:34:57Z",
|
||||||
"source": "scanner.webservice",
|
"source": "scanner.webservice",
|
||||||
"idempotencyKey": "scanner.event.scan.completed:tenant-alpha:report-abc",
|
"idempotencyKey": "scanner.event.scan.completed:tenant-alpha:report-abc",
|
||||||
"correlationId": "report-abc",
|
"correlationId": "report-abc",
|
||||||
"traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
|
"traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
|
||||||
"scope": {
|
"scope": {
|
||||||
"namespace": "acme/edge",
|
"namespace": "acme/edge",
|
||||||
"repo": "api",
|
"repo": "api",
|
||||||
"digest": "sha256:feedface"
|
"digest": "sha256:feedface"
|
||||||
},
|
},
|
||||||
"attributes": {
|
"attributes": {
|
||||||
"reportId": "report-abc",
|
"reportId": "report-abc",
|
||||||
"policyRevisionId": "rev-42",
|
"policyRevisionId": "rev-42",
|
||||||
"policyDigest": "digest-123",
|
"policyDigest": "digest-123",
|
||||||
"verdict": "blocked"
|
"verdict": "blocked"
|
||||||
},
|
},
|
||||||
"payload": {
|
"payload": {
|
||||||
"reportId": "report-abc",
|
"reportId": "report-abc",
|
||||||
"scanId": "report-abc",
|
"scanId": "report-abc",
|
||||||
"imageDigest": "sha256:feedface",
|
"imageDigest": "sha256:feedface",
|
||||||
"verdict": "fail",
|
"verdict": "fail",
|
||||||
"summary": {
|
"summary": {
|
||||||
"total": 1,
|
"total": 1,
|
||||||
"blocked": 1,
|
"blocked": 1,
|
||||||
"warned": 0,
|
"warned": 0,
|
||||||
"ignored": 0,
|
"ignored": 0,
|
||||||
"quieted": 0
|
"quieted": 0
|
||||||
},
|
},
|
||||||
"delta": {
|
"delta": {
|
||||||
"newCritical": 1,
|
"newCritical": 1,
|
||||||
"kev": [
|
"kev": [
|
||||||
"CVE-2024-9999"
|
"CVE-2024-9999"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"policy": {
|
"policy": {
|
||||||
"digest": "digest-123",
|
"digest": "digest-123",
|
||||||
"revisionId": "rev-42"
|
"revisionId": "rev-42"
|
||||||
},
|
},
|
||||||
"findings": [
|
"findings": [
|
||||||
{
|
{
|
||||||
"id": "finding-1",
|
"id": "finding-1",
|
||||||
"severity": "Critical",
|
"severity": "Critical",
|
||||||
"cve": "CVE-2024-9999",
|
"cve": "CVE-2024-9999",
|
||||||
"purl": "pkg:docker/acme/edge-api@sha256-feedface",
|
"purl": "pkg:docker/acme/edge-api@sha256-feedface",
|
||||||
"reachability": "runtime"
|
"reachability": "runtime"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"links": {
|
"links": {
|
||||||
"ui": "https://scanner.example/ui/reports/report-abc",
|
"ui": "https://scanner.example/ui/reports/report-abc",
|
||||||
"report": "https://scanner.example/api/v1/reports/report-abc",
|
"report": "https://scanner.example/api/v1/reports/report-abc",
|
||||||
"policy": "https://scanner.example/api/v1/policy/revisions/rev-42",
|
"policy": "https://scanner.example/api/v1/policy/revisions/rev-42",
|
||||||
"attestation": "https://scanner.example/ui/attestations/report-abc"
|
"attestation": "https://scanner.example/ui/attestations/report-abc"
|
||||||
},
|
},
|
||||||
"dsse": {
|
"dsse": {
|
||||||
"payloadType": "application/vnd.stellaops.report+json",
|
"payloadType": "application/vnd.stellaops.report+json",
|
||||||
"payload": "eyJyZXBvcnRJZCI6InJlcG9ydC1hYmMiLCJpbWFnZURpZ2VzdCI6InNoYTI1NjpmZWVkZmFjZSIsImdlbmVyYXRlZEF0IjoiMjAyNS0xMC0xOVQxMjozNDo1NiswMDowMCIsInZlcmRpY3QiOiJibG9ja2VkIiwicG9saWN5Ijp7InJldmlzaW9uSWQiOiJyZXYtNDIiLCJkaWdlc3QiOiJkaWdlc3QtMTIzIn0sInN1bW1hcnkiOnsidG90YWwiOjEsImJsb2NrZWQiOjEsIndhcm5lZCI6MCwiaWdub3JlZCI6MCwicXVpZXRlZCI6MH0sInZlcmRpY3RzIjpbeyJmaW5kaW5nSWQiOiJmaW5kaW5nLTEiLCJzdGF0dXMiOiJCbG9ja2VkIiwic2NvcmUiOjQ3LjUsInNvdXJjZVRydXN0IjoiTlZEIiwicmVhY2hhYmlsaXR5IjoicnVudGltZSJ9XSwiaXNzdWVzIjpbXX0=",
|
"payload": "eyJyZXBvcnRJZCI6InJlcG9ydC1hYmMiLCJpbWFnZURpZ2VzdCI6InNoYTI1NjpmZWVkZmFjZSIsImdlbmVyYXRlZEF0IjoiMjAyNS0xMC0xOVQxMjozNDo1NiswMDowMCIsInZlcmRpY3QiOiJibG9ja2VkIiwicG9saWN5Ijp7InJldmlzaW9uSWQiOiJyZXYtNDIiLCJkaWdlc3QiOiJkaWdlc3QtMTIzIn0sInN1bW1hcnkiOnsidG90YWwiOjEsImJsb2NrZWQiOjEsIndhcm5lZCI6MCwiaWdub3JlZCI6MCwicXVpZXRlZCI6MH0sInZlcmRpY3RzIjpbeyJmaW5kaW5nSWQiOiJmaW5kaW5nLTEiLCJzdGF0dXMiOiJCbG9ja2VkIiwic2NvcmUiOjQ3LjUsInNvdXJjZVRydXN0IjoiTlZEIiwicmVhY2hhYmlsaXR5IjoicnVudGltZSJ9XSwiaXNzdWVzIjpbXX0=",
|
||||||
"signatures": [
|
"signatures": [
|
||||||
{
|
{
|
||||||
"keyId": "test-key",
|
"keyId": "test-key",
|
||||||
"algorithm": "hs256",
|
"algorithm": "hs256",
|
||||||
"signature": "signature-value"
|
"signature": "signature-value"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"report": {
|
"report": {
|
||||||
"reportId": "report-abc",
|
"reportId": "report-abc",
|
||||||
"generatedAt": "2025-10-19T12:34:56Z",
|
"generatedAt": "2025-10-19T12:34:56Z",
|
||||||
"imageDigest": "sha256:feedface",
|
"imageDigest": "sha256:feedface",
|
||||||
"policy": {
|
"policy": {
|
||||||
"digest": "digest-123",
|
"digest": "digest-123",
|
||||||
"revisionId": "rev-42"
|
"revisionId": "rev-42"
|
||||||
},
|
},
|
||||||
"summary": {
|
"summary": {
|
||||||
"total": 1,
|
"total": 1,
|
||||||
"blocked": 1,
|
"blocked": 1,
|
||||||
"warned": 0,
|
"warned": 0,
|
||||||
"ignored": 0,
|
"ignored": 0,
|
||||||
"quieted": 0
|
"quieted": 0
|
||||||
},
|
},
|
||||||
"verdict": "blocked",
|
"verdict": "blocked",
|
||||||
"verdicts": [
|
"verdicts": [
|
||||||
{
|
{
|
||||||
"findingId": "finding-1",
|
"findingId": "finding-1",
|
||||||
"status": "Blocked",
|
"status": "Blocked",
|
||||||
"score": 47.5,
|
"score": 47.5,
|
||||||
"sourceTrust": "NVD",
|
"sourceTrust": "NVD",
|
||||||
"reachability": "runtime"
|
"reachability": "runtime"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"issues": []
|
"issues": []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,36 +1,36 @@
|
|||||||
{
|
{
|
||||||
"eventId": "4d33c19c-1c8a-44d1-9954-1d5e98b2af71",
|
"eventId": "4d33c19c-1c8a-44d1-9954-1d5e98b2af71",
|
||||||
"kind": "scheduler.graph.job.completed",
|
"kind": "scheduler.graph.job.completed",
|
||||||
"tenant": "tenant-alpha",
|
"tenant": "tenant-alpha",
|
||||||
"ts": "2025-10-26T12:00:45Z",
|
"ts": "2025-10-26T12:00:45Z",
|
||||||
"payload": {
|
"payload": {
|
||||||
"jobType": "build",
|
"jobType": "build",
|
||||||
"status": "completed",
|
"status": "completed",
|
||||||
"occurredAt": "2025-10-26T12:00:45Z",
|
"occurredAt": "2025-10-26T12:00:45Z",
|
||||||
"job": {
|
"job": {
|
||||||
"schemaVersion": "scheduler.graph-build-job@1",
|
"schemaVersion": "scheduler.graph-build-job@1",
|
||||||
"id": "gbj_20251026a",
|
"id": "gbj_20251026a",
|
||||||
"tenantId": "tenant-alpha",
|
"tenantId": "tenant-alpha",
|
||||||
"sbomId": "sbom_20251026",
|
"sbomId": "sbom_20251026",
|
||||||
"sbomVersionId": "sbom_ver_20251026",
|
"sbomVersionId": "sbom_ver_20251026",
|
||||||
"sbomDigest": "sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
|
"sbomDigest": "sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
|
||||||
"graphSnapshotId": "graph_snap_20251026",
|
"graphSnapshotId": "graph_snap_20251026",
|
||||||
"status": "completed",
|
"status": "completed",
|
||||||
"trigger": "sbom-version",
|
"trigger": "sbom-version",
|
||||||
"attempts": 1,
|
"attempts": 1,
|
||||||
"cartographerJobId": "carto_job_42",
|
"cartographerJobId": "carto_job_42",
|
||||||
"correlationId": "evt_svc_987",
|
"correlationId": "evt_svc_987",
|
||||||
"createdAt": "2025-10-26T12:00:00+00:00",
|
"createdAt": "2025-10-26T12:00:00+00:00",
|
||||||
"startedAt": "2025-10-26T12:00:05+00:00",
|
"startedAt": "2025-10-26T12:00:05+00:00",
|
||||||
"completedAt": "2025-10-26T12:00:45+00:00",
|
"completedAt": "2025-10-26T12:00:45+00:00",
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"sbomEventId": "sbom_evt_20251026"
|
"sbomEventId": "sbom_evt_20251026"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"resultUri": "oras://cartographer/offline/tenant-alpha/graph_snap_20251026"
|
"resultUri": "oras://cartographer/offline/tenant-alpha/graph_snap_20251026"
|
||||||
},
|
},
|
||||||
"attributes": {
|
"attributes": {
|
||||||
"cartographerCluster": "offline-kit",
|
"cartographerCluster": "offline-kit",
|
||||||
"plannerShard": "graph-builders-01"
|
"plannerShard": "graph-builders-01"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,164 +1,164 @@
|
|||||||
{
|
{
|
||||||
"$id": "https://stella-ops.org/schemas/events/scanner.event.report.ready@1.json",
|
"$id": "https://stella-ops.org/schemas/events/scanner.event.report.ready@1.json",
|
||||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
"title": "Scanner orchestrator event – report ready (v1)",
|
"title": "Scanner orchestrator event – report ready (v1)",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"required": [
|
"required": [
|
||||||
"eventId",
|
"eventId",
|
||||||
"kind",
|
"kind",
|
||||||
"version",
|
"version",
|
||||||
"tenant",
|
"tenant",
|
||||||
"occurredAt",
|
"occurredAt",
|
||||||
"source",
|
"source",
|
||||||
"idempotencyKey",
|
"idempotencyKey",
|
||||||
"payload"
|
"payload"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"eventId": {
|
"eventId": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "uuid",
|
"format": "uuid",
|
||||||
"description": "Globally unique identifier for this occurrence."
|
"description": "Globally unique identifier for this occurrence."
|
||||||
},
|
},
|
||||||
"kind": {
|
"kind": {
|
||||||
"const": "scanner.event.report.ready",
|
"const": "scanner.event.report.ready",
|
||||||
"description": "Event kind identifier consumed by orchestrator subscribers."
|
"description": "Event kind identifier consumed by orchestrator subscribers."
|
||||||
},
|
},
|
||||||
"version": {
|
"version": {
|
||||||
"const": 1,
|
"const": 1,
|
||||||
"description": "Schema version for orchestrator envelopes."
|
"description": "Schema version for orchestrator envelopes."
|
||||||
},
|
},
|
||||||
"tenant": {
|
"tenant": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Tenant that owns the scan/report."
|
"description": "Tenant that owns the scan/report."
|
||||||
},
|
},
|
||||||
"occurredAt": {
|
"occurredAt": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "date-time",
|
"format": "date-time",
|
||||||
"description": "Timestamp (UTC) when the report transitioned to ready."
|
"description": "Timestamp (UTC) when the report transitioned to ready."
|
||||||
},
|
},
|
||||||
"recordedAt": {
|
"recordedAt": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "date-time",
|
"format": "date-time",
|
||||||
"description": "Timestamp (UTC) when the event was persisted. Optional."
|
"description": "Timestamp (UTC) when the event was persisted. Optional."
|
||||||
},
|
},
|
||||||
"source": {
|
"source": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Producer identifier, e.g. `scanner.webservice`."
|
"description": "Producer identifier, e.g. `scanner.webservice`."
|
||||||
},
|
},
|
||||||
"idempotencyKey": {
|
"idempotencyKey": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"minLength": 8,
|
"minLength": 8,
|
||||||
"description": "Deterministic key used to deduplicate events downstream."
|
"description": "Deterministic key used to deduplicate events downstream."
|
||||||
},
|
},
|
||||||
"correlationId": {
|
"correlationId": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Correlation identifier that ties this event to a request or workflow."
|
"description": "Correlation identifier that ties this event to a request or workflow."
|
||||||
},
|
},
|
||||||
"traceId": {
|
"traceId": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "W3C trace ID (32 hex chars) for distributed tracing."
|
"description": "W3C trace ID (32 hex chars) for distributed tracing."
|
||||||
},
|
},
|
||||||
"spanId": {
|
"spanId": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Optional span identifier associated with traceId."
|
"description": "Optional span identifier associated with traceId."
|
||||||
},
|
},
|
||||||
"scope": {
|
"scope": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"required": ["repo", "digest"],
|
"required": ["repo", "digest"],
|
||||||
"properties": {
|
"properties": {
|
||||||
"namespace": {"type": "string"},
|
"namespace": {"type": "string"},
|
||||||
"repo": {"type": "string"},
|
"repo": {"type": "string"},
|
||||||
"digest": {"type": "string"},
|
"digest": {"type": "string"},
|
||||||
"component": {"type": "string"},
|
"component": {"type": "string"},
|
||||||
"image": {"type": "string"}
|
"image": {"type": "string"}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"attributes": {
|
"attributes": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"description": "String attributes for downstream correlation (policy revision, scan id, etc.).",
|
"description": "String attributes for downstream correlation (policy revision, scan id, etc.).",
|
||||||
"additionalProperties": {"type": "string"}
|
"additionalProperties": {"type": "string"}
|
||||||
},
|
},
|
||||||
"payload": {
|
"payload": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": true,
|
"additionalProperties": true,
|
||||||
"required": ["reportId", "verdict", "summary", "links", "report"],
|
"required": ["reportId", "verdict", "summary", "links", "report"],
|
||||||
"properties": {
|
"properties": {
|
||||||
"reportId": {"type": "string"},
|
"reportId": {"type": "string"},
|
||||||
"scanId": {"type": "string"},
|
"scanId": {"type": "string"},
|
||||||
"imageDigest": {"type": "string"},
|
"imageDigest": {"type": "string"},
|
||||||
"generatedAt": {"type": "string", "format": "date-time"},
|
"generatedAt": {"type": "string", "format": "date-time"},
|
||||||
"verdict": {"enum": ["pass", "warn", "fail"]},
|
"verdict": {"enum": ["pass", "warn", "fail"]},
|
||||||
"summary": {
|
"summary": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"required": ["total", "blocked", "warned", "ignored", "quieted"],
|
"required": ["total", "blocked", "warned", "ignored", "quieted"],
|
||||||
"properties": {
|
"properties": {
|
||||||
"total": {"type": "integer", "minimum": 0},
|
"total": {"type": "integer", "minimum": 0},
|
||||||
"blocked": {"type": "integer", "minimum": 0},
|
"blocked": {"type": "integer", "minimum": 0},
|
||||||
"warned": {"type": "integer", "minimum": 0},
|
"warned": {"type": "integer", "minimum": 0},
|
||||||
"ignored": {"type": "integer", "minimum": 0},
|
"ignored": {"type": "integer", "minimum": 0},
|
||||||
"quieted": {"type": "integer", "minimum": 0}
|
"quieted": {"type": "integer", "minimum": 0}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"delta": {
|
"delta": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"properties": {
|
"properties": {
|
||||||
"newCritical": {"type": "integer", "minimum": 0},
|
"newCritical": {"type": "integer", "minimum": 0},
|
||||||
"newHigh": {"type": "integer", "minimum": 0},
|
"newHigh": {"type": "integer", "minimum": 0},
|
||||||
"kev": {
|
"kev": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {"type": "string"}
|
"items": {"type": "string"}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"quietedFindingCount": {
|
"quietedFindingCount": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"minimum": 0
|
"minimum": 0
|
||||||
},
|
},
|
||||||
"policy": {
|
"policy": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"description": "Policy revision metadata surfaced alongside the report."
|
"description": "Policy revision metadata surfaced alongside the report."
|
||||||
},
|
},
|
||||||
"links": {
|
"links": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"properties": {
|
"properties": {
|
||||||
"ui": {"type": "string", "format": "uri"},
|
"ui": {"type": "string", "format": "uri"},
|
||||||
"report": {"type": "string", "format": "uri"},
|
"report": {"type": "string", "format": "uri"},
|
||||||
"policy": {"type": "string", "format": "uri"},
|
"policy": {"type": "string", "format": "uri"},
|
||||||
"attestation": {"type": "string", "format": "uri"}
|
"attestation": {"type": "string", "format": "uri"}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dsse": {
|
"dsse": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"required": ["payloadType", "payload", "signatures"],
|
"required": ["payloadType", "payload", "signatures"],
|
||||||
"properties": {
|
"properties": {
|
||||||
"payloadType": {"type": "string"},
|
"payloadType": {"type": "string"},
|
||||||
"payload": {"type": "string"},
|
"payload": {"type": "string"},
|
||||||
"signatures": {
|
"signatures": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"required": ["keyId", "algorithm", "signature"],
|
"required": ["keyId", "algorithm", "signature"],
|
||||||
"properties": {
|
"properties": {
|
||||||
"keyId": {"type": "string"},
|
"keyId": {"type": "string"},
|
||||||
"algorithm": {"type": "string"},
|
"algorithm": {"type": "string"},
|
||||||
"signature": {"type": "string"}
|
"signature": {"type": "string"}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"report": {
|
"report": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"description": "Canonical scanner report document that aligns with the DSSE payload."
|
"description": "Canonical scanner report document that aligns with the DSSE payload."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,174 +1,174 @@
|
|||||||
{
|
{
|
||||||
"$id": "https://stella-ops.org/schemas/events/scanner.event.scan.completed@1.json",
|
"$id": "https://stella-ops.org/schemas/events/scanner.event.scan.completed@1.json",
|
||||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
"title": "Scanner orchestrator event – scan completed (v1)",
|
"title": "Scanner orchestrator event – scan completed (v1)",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"required": [
|
"required": [
|
||||||
"eventId",
|
"eventId",
|
||||||
"kind",
|
"kind",
|
||||||
"version",
|
"version",
|
||||||
"tenant",
|
"tenant",
|
||||||
"occurredAt",
|
"occurredAt",
|
||||||
"source",
|
"source",
|
||||||
"idempotencyKey",
|
"idempotencyKey",
|
||||||
"payload"
|
"payload"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"eventId": {
|
"eventId": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "uuid",
|
"format": "uuid",
|
||||||
"description": "Globally unique identifier for this occurrence."
|
"description": "Globally unique identifier for this occurrence."
|
||||||
},
|
},
|
||||||
"kind": {
|
"kind": {
|
||||||
"const": "scanner.event.scan.completed",
|
"const": "scanner.event.scan.completed",
|
||||||
"description": "Event kind identifier consumed by orchestrator subscribers."
|
"description": "Event kind identifier consumed by orchestrator subscribers."
|
||||||
},
|
},
|
||||||
"version": {
|
"version": {
|
||||||
"const": 1,
|
"const": 1,
|
||||||
"description": "Schema version for orchestrator envelopes."
|
"description": "Schema version for orchestrator envelopes."
|
||||||
},
|
},
|
||||||
"tenant": {
|
"tenant": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Tenant that owns the scan."
|
"description": "Tenant that owns the scan."
|
||||||
},
|
},
|
||||||
"occurredAt": {
|
"occurredAt": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "date-time",
|
"format": "date-time",
|
||||||
"description": "Timestamp (UTC) when the scan completed."
|
"description": "Timestamp (UTC) when the scan completed."
|
||||||
},
|
},
|
||||||
"recordedAt": {
|
"recordedAt": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "date-time",
|
"format": "date-time",
|
||||||
"description": "Timestamp (UTC) when the event was persisted. Optional."
|
"description": "Timestamp (UTC) when the event was persisted. Optional."
|
||||||
},
|
},
|
||||||
"source": {
|
"source": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Producer identifier, e.g. `scanner.webservice`."
|
"description": "Producer identifier, e.g. `scanner.webservice`."
|
||||||
},
|
},
|
||||||
"idempotencyKey": {
|
"idempotencyKey": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"minLength": 8,
|
"minLength": 8,
|
||||||
"description": "Deterministic key used to deduplicate events downstream."
|
"description": "Deterministic key used to deduplicate events downstream."
|
||||||
},
|
},
|
||||||
"correlationId": {
|
"correlationId": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Correlation identifier tying this event to a request or workflow."
|
"description": "Correlation identifier tying this event to a request or workflow."
|
||||||
},
|
},
|
||||||
"traceId": {
|
"traceId": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "W3C trace ID (32 hex chars) for distributed tracing."
|
"description": "W3C trace ID (32 hex chars) for distributed tracing."
|
||||||
},
|
},
|
||||||
"spanId": {
|
"spanId": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Optional span identifier associated with traceId."
|
"description": "Optional span identifier associated with traceId."
|
||||||
},
|
},
|
||||||
"scope": {
|
"scope": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"required": ["repo", "digest"],
|
"required": ["repo", "digest"],
|
||||||
"properties": {
|
"properties": {
|
||||||
"namespace": {"type": "string"},
|
"namespace": {"type": "string"},
|
||||||
"repo": {"type": "string"},
|
"repo": {"type": "string"},
|
||||||
"digest": {"type": "string"},
|
"digest": {"type": "string"},
|
||||||
"component": {"type": "string"},
|
"component": {"type": "string"},
|
||||||
"image": {"type": "string"}
|
"image": {"type": "string"}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"attributes": {
|
"attributes": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"description": "String attributes for downstream correlation (policy revision, scan id, etc.).",
|
"description": "String attributes for downstream correlation (policy revision, scan id, etc.).",
|
||||||
"additionalProperties": {"type": "string"}
|
"additionalProperties": {"type": "string"}
|
||||||
},
|
},
|
||||||
"payload": {
|
"payload": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": true,
|
"additionalProperties": true,
|
||||||
"required": ["reportId", "scanId", "imageDigest", "verdict", "summary", "report"],
|
"required": ["reportId", "scanId", "imageDigest", "verdict", "summary", "report"],
|
||||||
"properties": {
|
"properties": {
|
||||||
"reportId": {"type": "string"},
|
"reportId": {"type": "string"},
|
||||||
"scanId": {"type": "string"},
|
"scanId": {"type": "string"},
|
||||||
"imageDigest": {"type": "string"},
|
"imageDigest": {"type": "string"},
|
||||||
"verdict": {"enum": ["pass", "warn", "fail"]},
|
"verdict": {"enum": ["pass", "warn", "fail"]},
|
||||||
"summary": {
|
"summary": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"required": ["total", "blocked", "warned", "ignored", "quieted"],
|
"required": ["total", "blocked", "warned", "ignored", "quieted"],
|
||||||
"properties": {
|
"properties": {
|
||||||
"total": {"type": "integer", "minimum": 0},
|
"total": {"type": "integer", "minimum": 0},
|
||||||
"blocked": {"type": "integer", "minimum": 0},
|
"blocked": {"type": "integer", "minimum": 0},
|
||||||
"warned": {"type": "integer", "minimum": 0},
|
"warned": {"type": "integer", "minimum": 0},
|
||||||
"ignored": {"type": "integer", "minimum": 0},
|
"ignored": {"type": "integer", "minimum": 0},
|
||||||
"quieted": {"type": "integer", "minimum": 0}
|
"quieted": {"type": "integer", "minimum": 0}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"delta": {
|
"delta": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"properties": {
|
"properties": {
|
||||||
"newCritical": {"type": "integer", "minimum": 0},
|
"newCritical": {"type": "integer", "minimum": 0},
|
||||||
"newHigh": {"type": "integer", "minimum": 0},
|
"newHigh": {"type": "integer", "minimum": 0},
|
||||||
"kev": {
|
"kev": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {"type": "string"}
|
"items": {"type": "string"}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"policy": {
|
"policy": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"description": "Policy revision metadata surfaced alongside the report."
|
"description": "Policy revision metadata surfaced alongside the report."
|
||||||
},
|
},
|
||||||
"findings": {
|
"findings": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"required": ["id"],
|
"required": ["id"],
|
||||||
"properties": {
|
"properties": {
|
||||||
"id": {"type": "string"},
|
"id": {"type": "string"},
|
||||||
"severity": {"type": "string"},
|
"severity": {"type": "string"},
|
||||||
"cve": {"type": "string"},
|
"cve": {"type": "string"},
|
||||||
"purl": {"type": "string"},
|
"purl": {"type": "string"},
|
||||||
"reachability": {"type": "string"}
|
"reachability": {"type": "string"}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"links": {
|
"links": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"properties": {
|
"properties": {
|
||||||
"ui": {"type": "string", "format": "uri"},
|
"ui": {"type": "string", "format": "uri"},
|
||||||
"report": {"type": "string", "format": "uri"},
|
"report": {"type": "string", "format": "uri"},
|
||||||
"policy": {"type": "string", "format": "uri"},
|
"policy": {"type": "string", "format": "uri"},
|
||||||
"attestation": {"type": "string", "format": "uri"}
|
"attestation": {"type": "string", "format": "uri"}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dsse": {
|
"dsse": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"required": ["payloadType", "payload", "signatures"],
|
"required": ["payloadType", "payload", "signatures"],
|
||||||
"properties": {
|
"properties": {
|
||||||
"payloadType": {"type": "string"},
|
"payloadType": {"type": "string"},
|
||||||
"payload": {"type": "string"},
|
"payload": {"type": "string"},
|
||||||
"signatures": {
|
"signatures": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"required": ["keyId", "algorithm", "signature"],
|
"required": ["keyId", "algorithm", "signature"],
|
||||||
"properties": {
|
"properties": {
|
||||||
"keyId": {"type": "string"},
|
"keyId": {"type": "string"},
|
||||||
"algorithm": {"type": "string"},
|
"algorithm": {"type": "string"},
|
||||||
"signature": {"type": "string"}
|
"signature": {"type": "string"}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"report": {
|
"report": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"description": "Canonical scanner report document that aligns with the DSSE payload."
|
"description": "Canonical scanner report document that aligns with the DSSE payload."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,196 +1,196 @@
|
|||||||
{
|
{
|
||||||
"$id": "https://stella-ops.org/schemas/events/scheduler.graph.job.completed@1.json",
|
"$id": "https://stella-ops.org/schemas/events/scheduler.graph.job.completed@1.json",
|
||||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
"title": "Scheduler Graph Job Completed Event",
|
"title": "Scheduler Graph Job Completed Event",
|
||||||
"description": "Legacy scheduler event emitted when a graph build or overlay job reaches a terminal state. Consumers validate downstream caches and surface overlay freshness.",
|
"description": "Legacy scheduler event emitted when a graph build or overlay job reaches a terminal state. Consumers validate downstream caches and surface overlay freshness.",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"required": ["eventId", "kind", "tenant", "ts", "payload"],
|
"required": ["eventId", "kind", "tenant", "ts", "payload"],
|
||||||
"properties": {
|
"properties": {
|
||||||
"eventId": {
|
"eventId": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "uuid",
|
"format": "uuid",
|
||||||
"description": "Globally unique identifier per event."
|
"description": "Globally unique identifier per event."
|
||||||
},
|
},
|
||||||
"kind": {
|
"kind": {
|
||||||
"const": "scheduler.graph.job.completed"
|
"const": "scheduler.graph.job.completed"
|
||||||
},
|
},
|
||||||
"tenant": {
|
"tenant": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Tenant identifier scoped to the originating job."
|
"description": "Tenant identifier scoped to the originating job."
|
||||||
},
|
},
|
||||||
"ts": {
|
"ts": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "date-time",
|
"format": "date-time",
|
||||||
"description": "UTC timestamp when the job reached a terminal state."
|
"description": "UTC timestamp when the job reached a terminal state."
|
||||||
},
|
},
|
||||||
"payload": {
|
"payload": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"required": ["jobType", "job", "status", "occurredAt"],
|
"required": ["jobType", "job", "status", "occurredAt"],
|
||||||
"properties": {
|
"properties": {
|
||||||
"jobType": {
|
"jobType": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["build", "overlay"],
|
"enum": ["build", "overlay"],
|
||||||
"description": "Job flavour, matches the CLR type of the serialized job payload."
|
"description": "Job flavour, matches the CLR type of the serialized job payload."
|
||||||
},
|
},
|
||||||
"status": {
|
"status": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["completed", "failed", "cancelled"],
|
"enum": ["completed", "failed", "cancelled"],
|
||||||
"description": "Terminal status recorded for the job."
|
"description": "Terminal status recorded for the job."
|
||||||
},
|
},
|
||||||
"occurredAt": {
|
"occurredAt": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "date-time",
|
"format": "date-time",
|
||||||
"description": "UTC timestamp of the terminal transition, mirrors job.CompletedAt."
|
"description": "UTC timestamp of the terminal transition, mirrors job.CompletedAt."
|
||||||
},
|
},
|
||||||
"job": {
|
"job": {
|
||||||
"oneOf": [
|
"oneOf": [
|
||||||
{"$ref": "#/definitions/graphBuildJob"},
|
{"$ref": "#/definitions/graphBuildJob"},
|
||||||
{"$ref": "#/definitions/graphOverlayJob"}
|
{"$ref": "#/definitions/graphOverlayJob"}
|
||||||
],
|
],
|
||||||
"description": "Canonical serialized representation of the finished job."
|
"description": "Canonical serialized representation of the finished job."
|
||||||
},
|
},
|
||||||
"resultUri": {
|
"resultUri": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Optional URI pointing to Cartographer snapshot or overlay bundle (if available)."
|
"description": "Optional URI pointing to Cartographer snapshot or overlay bundle (if available)."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"attributes": {
|
"attributes": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"description": "Optional correlation bag for downstream consumers.",
|
"description": "Optional correlation bag for downstream consumers.",
|
||||||
"additionalProperties": {
|
"additionalProperties": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"definitions": {
|
"definitions": {
|
||||||
"graphBuildJob": {
|
"graphBuildJob": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"required": [
|
"required": [
|
||||||
"schemaVersion",
|
"schemaVersion",
|
||||||
"id",
|
"id",
|
||||||
"tenantId",
|
"tenantId",
|
||||||
"sbomId",
|
"sbomId",
|
||||||
"sbomVersionId",
|
"sbomVersionId",
|
||||||
"sbomDigest",
|
"sbomDigest",
|
||||||
"status",
|
"status",
|
||||||
"trigger",
|
"trigger",
|
||||||
"attempts",
|
"attempts",
|
||||||
"createdAt"
|
"createdAt"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"schemaVersion": {
|
"schemaVersion": {
|
||||||
"const": "scheduler.graph-build-job@1"
|
"const": "scheduler.graph-build-job@1"
|
||||||
},
|
},
|
||||||
"id": {"type": "string"},
|
"id": {"type": "string"},
|
||||||
"tenantId": {"type": "string"},
|
"tenantId": {"type": "string"},
|
||||||
"sbomId": {"type": "string"},
|
"sbomId": {"type": "string"},
|
||||||
"sbomVersionId": {"type": "string"},
|
"sbomVersionId": {"type": "string"},
|
||||||
"sbomDigest": {
|
"sbomDigest": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"pattern": "^sha256:[a-f0-9]{64}$"
|
"pattern": "^sha256:[a-f0-9]{64}$"
|
||||||
},
|
},
|
||||||
"graphSnapshotId": {"type": "string"},
|
"graphSnapshotId": {"type": "string"},
|
||||||
"status": {
|
"status": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["pending", "queued", "running", "completed", "failed", "cancelled"]
|
"enum": ["pending", "queued", "running", "completed", "failed", "cancelled"]
|
||||||
},
|
},
|
||||||
"trigger": {
|
"trigger": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["sbom-version", "backfill", "manual"]
|
"enum": ["sbom-version", "backfill", "manual"]
|
||||||
},
|
},
|
||||||
"attempts": {
|
"attempts": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"minimum": 0
|
"minimum": 0
|
||||||
},
|
},
|
||||||
"cartographerJobId": {"type": "string"},
|
"cartographerJobId": {"type": "string"},
|
||||||
"correlationId": {"type": "string"},
|
"correlationId": {"type": "string"},
|
||||||
"createdAt": {
|
"createdAt": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "date-time"
|
"format": "date-time"
|
||||||
},
|
},
|
||||||
"startedAt": {
|
"startedAt": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "date-time"
|
"format": "date-time"
|
||||||
},
|
},
|
||||||
"completedAt": {
|
"completedAt": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "date-time"
|
"format": "date-time"
|
||||||
},
|
},
|
||||||
"error": {"type": "string"},
|
"error": {"type": "string"},
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": {"type": "string"}
|
"additionalProperties": {"type": "string"}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"graphOverlayJob": {
|
"graphOverlayJob": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"required": [
|
"required": [
|
||||||
"schemaVersion",
|
"schemaVersion",
|
||||||
"id",
|
"id",
|
||||||
"tenantId",
|
"tenantId",
|
||||||
"graphSnapshotId",
|
"graphSnapshotId",
|
||||||
"overlayKind",
|
"overlayKind",
|
||||||
"overlayKey",
|
"overlayKey",
|
||||||
"status",
|
"status",
|
||||||
"trigger",
|
"trigger",
|
||||||
"attempts",
|
"attempts",
|
||||||
"createdAt"
|
"createdAt"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"schemaVersion": {
|
"schemaVersion": {
|
||||||
"const": "scheduler.graph-overlay-job@1"
|
"const": "scheduler.graph-overlay-job@1"
|
||||||
},
|
},
|
||||||
"id": {"type": "string"},
|
"id": {"type": "string"},
|
||||||
"tenantId": {"type": "string"},
|
"tenantId": {"type": "string"},
|
||||||
"graphSnapshotId": {"type": "string"},
|
"graphSnapshotId": {"type": "string"},
|
||||||
"buildJobId": {"type": "string"},
|
"buildJobId": {"type": "string"},
|
||||||
"overlayKind": {
|
"overlayKind": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["policy", "advisory", "vex"]
|
"enum": ["policy", "advisory", "vex"]
|
||||||
},
|
},
|
||||||
"overlayKey": {"type": "string"},
|
"overlayKey": {"type": "string"},
|
||||||
"subjects": {
|
"subjects": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {"type": "string"},
|
"items": {"type": "string"},
|
||||||
"uniqueItems": true
|
"uniqueItems": true
|
||||||
},
|
},
|
||||||
"status": {
|
"status": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["pending", "queued", "running", "completed", "failed", "cancelled"]
|
"enum": ["pending", "queued", "running", "completed", "failed", "cancelled"]
|
||||||
},
|
},
|
||||||
"trigger": {
|
"trigger": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["policy", "advisory", "vex", "sbom-version", "manual"]
|
"enum": ["policy", "advisory", "vex", "sbom-version", "manual"]
|
||||||
},
|
},
|
||||||
"attempts": {
|
"attempts": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"minimum": 0
|
"minimum": 0
|
||||||
},
|
},
|
||||||
"correlationId": {"type": "string"},
|
"correlationId": {"type": "string"},
|
||||||
"createdAt": {
|
"createdAt": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "date-time"
|
"format": "date-time"
|
||||||
},
|
},
|
||||||
"startedAt": {
|
"startedAt": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "date-time"
|
"format": "date-time"
|
||||||
},
|
},
|
||||||
"completedAt": {
|
"completedAt": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "date-time"
|
"format": "date-time"
|
||||||
},
|
},
|
||||||
"error": {"type": "string"},
|
"error": {"type": "string"},
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": {"type": "string"}
|
"additionalProperties": {"type": "string"}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
# Policy Examples
|
# Policy Examples
|
||||||
|
|
||||||
Sample `stella-dsl@1` policies illustrating common deployment personas. Each example includes commentary, CLI usage hints, and a compliance checklist.
|
Sample `stella-dsl@1` policies illustrating common deployment personas. Each example includes commentary, CLI usage hints, and a compliance checklist.
|
||||||
|
|
||||||
| Example | Description |
|
| Example | Description |
|
||||||
|---------|-------------|
|
|---------|-------------|
|
||||||
| [Baseline](baseline.md) | Balanced production defaults (block critical, respect strong VEX). |
|
| [Baseline](baseline.md) | Balanced production defaults (block critical, respect strong VEX). |
|
||||||
| [Serverless](serverless.md) | Aggressive blocking for serverless workloads (no High+, pinned base images). |
|
| [Serverless](serverless.md) | Aggressive blocking for serverless workloads (no High+, pinned base images). |
|
||||||
| [Internal Only](internal-only.md) | Lenient policy for internal/dev environments with KEV safeguards. |
|
| [Internal Only](internal-only.md) | Lenient policy for internal/dev environments with KEV safeguards. |
|
||||||
|
|
||||||
Policy source files (`*.stella`) live alongside the documentation so you can copy/paste or use `stella policy new --from file://...`.
|
Policy source files (`*.stella`) live alongside the documentation so you can copy/paste or use `stella policy new --from file://...`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
*Last updated: 2025-10-26.*
|
*Last updated: 2025-10-26.*
|
||||||
|
|
||||||
|
|||||||
@@ -1,79 +1,79 @@
|
|||||||
# Baseline Policy Example (`baseline.stella`)
|
# Baseline Policy Example (`baseline.stella`)
|
||||||
|
|
||||||
This sample policy provides a balanced default for production workloads: block critical findings, require strong VEX justifications to suppress advisories, and warn on deprecated runtimes. Use it as a starting point for tenants that want guardrails without excessive noise.
|
This sample policy provides a balanced default for production workloads: block critical findings, require strong VEX justifications to suppress advisories, and warn on deprecated runtimes. Use it as a starting point for tenants that want guardrails without excessive noise.
|
||||||
|
|
||||||
```dsl
|
```dsl
|
||||||
policy "Baseline Production Policy" syntax "stella-dsl@1" {
|
policy "Baseline Production Policy" syntax "stella-dsl@1" {
|
||||||
metadata {
|
metadata {
|
||||||
description = "Block critical, escalate high, enforce VEX justifications."
|
description = "Block critical, escalate high, enforce VEX justifications."
|
||||||
tags = ["baseline","production"]
|
tags = ["baseline","production"]
|
||||||
}
|
}
|
||||||
|
|
||||||
profile severity {
|
profile severity {
|
||||||
map vendor_weight {
|
map vendor_weight {
|
||||||
source "GHSA" => +0.5
|
source "GHSA" => +0.5
|
||||||
source "OSV" => +0.0
|
source "OSV" => +0.0
|
||||||
source "VendorX" => -0.2
|
source "VendorX" => -0.2
|
||||||
}
|
}
|
||||||
env exposure_adjustments {
|
env exposure_adjustments {
|
||||||
if env.exposure == "internet" then +0.5
|
if env.exposure == "internet" then +0.5
|
||||||
if env.runtime == "legacy" then +0.3
|
if env.runtime == "legacy" then +0.3
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rule block_critical priority 5 {
|
rule block_critical priority 5 {
|
||||||
when severity.normalized >= "Critical"
|
when severity.normalized >= "Critical"
|
||||||
then status := "blocked"
|
then status := "blocked"
|
||||||
because "Critical severity must be remediated before deploy."
|
because "Critical severity must be remediated before deploy."
|
||||||
}
|
}
|
||||||
|
|
||||||
rule escalate_high_internet {
|
rule escalate_high_internet {
|
||||||
when severity.normalized == "High"
|
when severity.normalized == "High"
|
||||||
and env.exposure == "internet"
|
and env.exposure == "internet"
|
||||||
then escalate to severity_band("Critical")
|
then escalate to severity_band("Critical")
|
||||||
because "High severity on internet-exposed asset escalates to critical."
|
because "High severity on internet-exposed asset escalates to critical."
|
||||||
}
|
}
|
||||||
|
|
||||||
rule require_vex_justification {
|
rule require_vex_justification {
|
||||||
when vex.any(status in ["not_affected","fixed"])
|
when vex.any(status in ["not_affected","fixed"])
|
||||||
and vex.justification in ["component_not_present","vulnerable_code_not_present"]
|
and vex.justification in ["component_not_present","vulnerable_code_not_present"]
|
||||||
then status := vex.status
|
then status := vex.status
|
||||||
annotate winning_statement := vex.latest().statementId
|
annotate winning_statement := vex.latest().statementId
|
||||||
because "Respect strong vendor VEX claims."
|
because "Respect strong vendor VEX claims."
|
||||||
}
|
}
|
||||||
|
|
||||||
rule alert_warn_eol_runtime priority 1 {
|
rule alert_warn_eol_runtime priority 1 {
|
||||||
when severity.normalized <= "Medium"
|
when severity.normalized <= "Medium"
|
||||||
and sbom.has_tag("runtime:eol")
|
and sbom.has_tag("runtime:eol")
|
||||||
then warn message "Runtime marked as EOL; upgrade recommended."
|
then warn message "Runtime marked as EOL; upgrade recommended."
|
||||||
because "Deprecated runtime should be upgraded."
|
because "Deprecated runtime should be upgraded."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Commentary
|
## Commentary
|
||||||
|
|
||||||
- **Severity profile** tightens vendor weights and applies exposure modifiers so internet-facing/high severity pairs escalate automatically.
|
- **Severity profile** tightens vendor weights and applies exposure modifiers so internet-facing/high severity pairs escalate automatically.
|
||||||
- **VEX rule** only honours strong justifications, preventing weaker claims from hiding issues.
|
- **VEX rule** only honours strong justifications, preventing weaker claims from hiding issues.
|
||||||
- **Warnings first** – The `alert_warn_eol_runtime` rule name ensures it sorts before the require-VEX rule, keeping alerts visible without flipping to `RequiresVex`.
|
- **Warnings first** – The `alert_warn_eol_runtime` rule name ensures it sorts before the require-VEX rule, keeping alerts visible without flipping to `RequiresVex`.
|
||||||
- Works well as shared `tenant-global` baseline; use tenant overrides for stricter tolerant environments.
|
- Works well as shared `tenant-global` baseline; use tenant overrides for stricter tolerant environments.
|
||||||
|
|
||||||
## Try it out
|
## Try it out
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
stella policy new --policy-id P-baseline --template blank --open
|
stella policy new --policy-id P-baseline --template blank --open
|
||||||
stella policy lint examples/policies/baseline.stella
|
stella policy lint examples/policies/baseline.stella
|
||||||
stella policy simulate P-baseline --candidate 1 --sbom sbom:sample-prod
|
stella policy simulate P-baseline --candidate 1 --sbom sbom:sample-prod
|
||||||
```
|
```
|
||||||
|
|
||||||
## Compliance checklist
|
## Compliance checklist
|
||||||
|
|
||||||
- [ ] Policy compiled via `stella policy lint` without diagnostics.
|
- [ ] Policy compiled via `stella policy lint` without diagnostics.
|
||||||
- [ ] Simulation diff reviewed against golden SBOM set.
|
- [ ] Simulation diff reviewed against golden SBOM set.
|
||||||
- [ ] Approval note documents rationale before promoting to production.
|
- [ ] Approval note documents rationale before promoting to production.
|
||||||
- [ ] EOL runtime tags kept up to date in SBOM metadata.
|
- [ ] EOL runtime tags kept up to date in SBOM metadata.
|
||||||
- [ ] VEX vendor allow-list reviewed quarterly.
|
- [ ] VEX vendor allow-list reviewed quarterly.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
*Last updated: 2025-10-26.*
|
*Last updated: 2025-10-26.*
|
||||||
|
|||||||
@@ -1,46 +1,46 @@
|
|||||||
policy "Baseline Production Policy" syntax "stella-dsl@1" {
|
policy "Baseline Production Policy" syntax "stella-dsl@1" {
|
||||||
metadata {
|
metadata {
|
||||||
description = "Block critical, escalate high, enforce VEX justifications."
|
description = "Block critical, escalate high, enforce VEX justifications."
|
||||||
tags = ["baseline","production"]
|
tags = ["baseline","production"]
|
||||||
}
|
}
|
||||||
|
|
||||||
profile severity {
|
profile severity {
|
||||||
map vendor_weight {
|
map vendor_weight {
|
||||||
source "GHSA" => +0.5
|
source "GHSA" => +0.5
|
||||||
source "OSV" => +0.0
|
source "OSV" => +0.0
|
||||||
source "VendorX" => -0.2
|
source "VendorX" => -0.2
|
||||||
}
|
}
|
||||||
env exposure_adjustments {
|
env exposure_adjustments {
|
||||||
if env.exposure == "internet" then +0.5
|
if env.exposure == "internet" then +0.5
|
||||||
if env.runtime == "legacy" then +0.3
|
if env.runtime == "legacy" then +0.3
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rule block_critical priority 5 {
|
rule block_critical priority 5 {
|
||||||
when severity.normalized >= "Critical"
|
when severity.normalized >= "Critical"
|
||||||
then status := "blocked"
|
then status := "blocked"
|
||||||
because "Critical severity must be remediated before deploy."
|
because "Critical severity must be remediated before deploy."
|
||||||
}
|
}
|
||||||
|
|
||||||
rule escalate_high_internet {
|
rule escalate_high_internet {
|
||||||
when severity.normalized == "High"
|
when severity.normalized == "High"
|
||||||
and env.exposure == "internet"
|
and env.exposure == "internet"
|
||||||
then escalate to severity_band("Critical")
|
then escalate to severity_band("Critical")
|
||||||
because "High severity on internet-exposed asset escalates to critical."
|
because "High severity on internet-exposed asset escalates to critical."
|
||||||
}
|
}
|
||||||
|
|
||||||
rule require_vex_justification {
|
rule require_vex_justification {
|
||||||
when vex.any(status in ["not_affected","fixed"])
|
when vex.any(status in ["not_affected","fixed"])
|
||||||
and vex.justification in ["component_not_present","vulnerable_code_not_present"]
|
and vex.justification in ["component_not_present","vulnerable_code_not_present"]
|
||||||
then status := vex.status
|
then status := vex.status
|
||||||
annotate winning_statement := vex.latest().statementId
|
annotate winning_statement := vex.latest().statementId
|
||||||
because "Respect strong vendor VEX claims."
|
because "Respect strong vendor VEX claims."
|
||||||
}
|
}
|
||||||
|
|
||||||
rule alert_warn_eol_runtime priority 1 {
|
rule alert_warn_eol_runtime priority 1 {
|
||||||
when severity.normalized <= "Medium"
|
when severity.normalized <= "Medium"
|
||||||
and sbom.has_tag("runtime:eol")
|
and sbom.has_tag("runtime:eol")
|
||||||
then warn message "Runtime marked as EOL; upgrade recommended."
|
then warn message "Runtime marked as EOL; upgrade recommended."
|
||||||
because "Deprecated runtime should be upgraded."
|
because "Deprecated runtime should be upgraded."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,34 +1,34 @@
|
|||||||
version: "1.0"
|
version: "1.0"
|
||||||
metadata:
|
metadata:
|
||||||
description: Baseline production policy
|
description: Baseline production policy
|
||||||
tags:
|
tags:
|
||||||
- baseline
|
- baseline
|
||||||
- production
|
- production
|
||||||
rules:
|
rules:
|
||||||
- name: Block Critical
|
- name: Block Critical
|
||||||
severity: [Critical]
|
severity: [Critical]
|
||||||
action: block
|
action: block
|
||||||
|
|
||||||
- name: Escalate High Internet
|
- name: Escalate High Internet
|
||||||
severity: [High]
|
severity: [High]
|
||||||
environments: [internet]
|
environments: [internet]
|
||||||
action:
|
action:
|
||||||
type: escalate
|
type: escalate
|
||||||
escalate:
|
escalate:
|
||||||
minimumSeverity: Critical
|
minimumSeverity: Critical
|
||||||
|
|
||||||
- name: Require VEX justification
|
- name: Require VEX justification
|
||||||
sources: [NVD, GHSA]
|
sources: [NVD, GHSA]
|
||||||
action:
|
action:
|
||||||
type: requireVex
|
type: requireVex
|
||||||
requireVex:
|
requireVex:
|
||||||
vendors: [VendorX, VendorY]
|
vendors: [VendorX, VendorY]
|
||||||
justifications:
|
justifications:
|
||||||
- component_not_present
|
- component_not_present
|
||||||
- vulnerable_code_not_present
|
- vulnerable_code_not_present
|
||||||
|
|
||||||
- name: Alert warn EOL runtime
|
- name: Alert warn EOL runtime
|
||||||
priority: 1
|
priority: 1
|
||||||
severity: [Low, Medium]
|
severity: [Low, Medium]
|
||||||
tags: [runtime:eol]
|
tags: [runtime:eol]
|
||||||
action: warn
|
action: warn
|
||||||
|
|||||||
@@ -1,72 +1,72 @@
|
|||||||
# Internal-Only Policy Example (`internal-only.stella`)
|
# Internal-Only Policy Example (`internal-only.stella`)
|
||||||
|
|
||||||
A relaxed profile for internal services and development environments: allow Medium severities with warnings, rely on VEX more heavily, but still block KEV/actively exploited advisories.
|
A relaxed profile for internal services and development environments: allow Medium severities with warnings, rely on VEX more heavily, but still block KEV/actively exploited advisories.
|
||||||
|
|
||||||
```dsl
|
```dsl
|
||||||
policy "Internal Only Policy" syntax "stella-dsl@1" {
|
policy "Internal Only Policy" syntax "stella-dsl@1" {
|
||||||
metadata {
|
metadata {
|
||||||
description = "Lenient policy for internal / dev tenants."
|
description = "Lenient policy for internal / dev tenants."
|
||||||
tags = ["internal","dev"]
|
tags = ["internal","dev"]
|
||||||
}
|
}
|
||||||
|
|
||||||
profile severity {
|
profile severity {
|
||||||
env exposure_adjustments {
|
env exposure_adjustments {
|
||||||
if env.exposure == "internal" then -0.4
|
if env.exposure == "internal" then -0.4
|
||||||
if env.stage == "dev" then -0.6
|
if env.stage == "dev" then -0.6
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rule block_kev priority 1 {
|
rule block_kev priority 1 {
|
||||||
when advisory.has_tag("kev")
|
when advisory.has_tag("kev")
|
||||||
then status := "blocked"
|
then status := "blocked"
|
||||||
because "Known exploited vulnerabilities must be remediated."
|
because "Known exploited vulnerabilities must be remediated."
|
||||||
}
|
}
|
||||||
|
|
||||||
rule allow_medium_with_warning {
|
rule allow_medium_with_warning {
|
||||||
when severity.normalized == "Medium"
|
when severity.normalized == "Medium"
|
||||||
and env.exposure == "internal"
|
and env.exposure == "internal"
|
||||||
then warn message "Medium severity permitted in internal environments."
|
then warn message "Medium severity permitted in internal environments."
|
||||||
because "Allow Medium findings with warning for internal workloads."
|
because "Allow Medium findings with warning for internal workloads."
|
||||||
}
|
}
|
||||||
|
|
||||||
rule accept_vendor_vex {
|
rule accept_vendor_vex {
|
||||||
when vex.any(status in ["not_affected","fixed"])
|
when vex.any(status in ["not_affected","fixed"])
|
||||||
then status := vex.status
|
then status := vex.status
|
||||||
annotate justification := vex.latest().justification
|
annotate justification := vex.latest().justification
|
||||||
because "Trust vendor VEX statements for internal scope."
|
because "Trust vendor VEX statements for internal scope."
|
||||||
}
|
}
|
||||||
|
|
||||||
rule quiet_low_priority {
|
rule quiet_low_priority {
|
||||||
when severity.normalized <= "Low"
|
when severity.normalized <= "Low"
|
||||||
then ignore until "2026-01-01T00:00:00Z"
|
then ignore until "2026-01-01T00:00:00Z"
|
||||||
because "Quiet low severity until next annual remediation sweep."
|
because "Quiet low severity until next annual remediation sweep."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Commentary
|
## Commentary
|
||||||
|
|
||||||
- Suitable for staging/dev tenants with lower blast radius.
|
- Suitable for staging/dev tenants with lower blast radius.
|
||||||
- KEV advisories override lenient behaviour to maintain minimum security bar.
|
- KEV advisories override lenient behaviour to maintain minimum security bar.
|
||||||
- Warnings ensure Medium findings stay visible in dashboards and CLI outputs.
|
- Warnings ensure Medium findings stay visible in dashboards and CLI outputs.
|
||||||
- Quiet rule enforces planned clean-up date; update before expiry.
|
- Quiet rule enforces planned clean-up date; update before expiry.
|
||||||
|
|
||||||
## Try it out
|
## Try it out
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
stella policy lint examples/policies/internal-only.stella
|
stella policy lint examples/policies/internal-only.stella
|
||||||
stella policy simulate P-internal --candidate 1 \
|
stella policy simulate P-internal --candidate 1 \
|
||||||
--sbom sbom:internal-service --env exposure=internal --env stage=dev
|
--sbom sbom:internal-service --env exposure=internal --env stage=dev
|
||||||
```
|
```
|
||||||
|
|
||||||
## Compliance checklist
|
## Compliance checklist
|
||||||
|
|
||||||
- [ ] Tenant classified as internal-only with documented risk acceptance.
|
- [ ] Tenant classified as internal-only with documented risk acceptance.
|
||||||
- [ ] KEV feed synced (Concelier) and tags confirmed before relying on rule.
|
- [ ] KEV feed synced (Concelier) and tags confirmed before relying on rule.
|
||||||
- [ ] Quiet expiry tracked; remediation backlog updated prior to deadline.
|
- [ ] Quiet expiry tracked; remediation backlog updated prior to deadline.
|
||||||
- [ ] Developers informed that warnings still affect quality score.
|
- [ ] Developers informed that warnings still affect quality score.
|
||||||
- [ ] Policy not used for production or internet-exposed services.
|
- [ ] Policy not used for production or internet-exposed services.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
*Last updated: 2025-10-26.*
|
*Last updated: 2025-10-26.*
|
||||||
|
|||||||
@@ -1,39 +1,39 @@
|
|||||||
policy "Internal Only Policy" syntax "stella-dsl@1" {
|
policy "Internal Only Policy" syntax "stella-dsl@1" {
|
||||||
metadata {
|
metadata {
|
||||||
description = "Lenient policy for internal / dev tenants."
|
description = "Lenient policy for internal / dev tenants."
|
||||||
tags = ["internal","dev"]
|
tags = ["internal","dev"]
|
||||||
}
|
}
|
||||||
|
|
||||||
profile severity {
|
profile severity {
|
||||||
env exposure_adjustments {
|
env exposure_adjustments {
|
||||||
if env.exposure == "internal" then -0.4
|
if env.exposure == "internal" then -0.4
|
||||||
if env.stage == "dev" then -0.6
|
if env.stage == "dev" then -0.6
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rule block_kev priority 1 {
|
rule block_kev priority 1 {
|
||||||
when advisory.has_tag("kev")
|
when advisory.has_tag("kev")
|
||||||
then status := "blocked"
|
then status := "blocked"
|
||||||
because "Known exploited vulnerabilities must be remediated."
|
because "Known exploited vulnerabilities must be remediated."
|
||||||
}
|
}
|
||||||
|
|
||||||
rule allow_medium_with_warning {
|
rule allow_medium_with_warning {
|
||||||
when severity.normalized == "Medium"
|
when severity.normalized == "Medium"
|
||||||
and env.exposure == "internal"
|
and env.exposure == "internal"
|
||||||
then warn message "Medium severity permitted in internal environments."
|
then warn message "Medium severity permitted in internal environments."
|
||||||
because "Allow Medium findings with warning for internal workloads."
|
because "Allow Medium findings with warning for internal workloads."
|
||||||
}
|
}
|
||||||
|
|
||||||
rule accept_vendor_vex {
|
rule accept_vendor_vex {
|
||||||
when vex.any(status in ["not_affected","fixed"])
|
when vex.any(status in ["not_affected","fixed"])
|
||||||
then status := vex.status
|
then status := vex.status
|
||||||
annotate justification := vex.latest().justification
|
annotate justification := vex.latest().justification
|
||||||
because "Trust vendor VEX statements for internal scope."
|
because "Trust vendor VEX statements for internal scope."
|
||||||
}
|
}
|
||||||
|
|
||||||
rule quiet_low_priority {
|
rule quiet_low_priority {
|
||||||
when severity.normalized <= "Low"
|
when severity.normalized <= "Low"
|
||||||
then ignore until "2026-01-01T00:00:00Z"
|
then ignore until "2026-01-01T00:00:00Z"
|
||||||
because "Quiet low severity until next annual remediation sweep."
|
because "Quiet low severity until next annual remediation sweep."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,31 +1,31 @@
|
|||||||
version: "1.0"
|
version: "1.0"
|
||||||
metadata:
|
metadata:
|
||||||
description: Relaxed internal/development policy
|
description: Relaxed internal/development policy
|
||||||
tags:
|
tags:
|
||||||
- internal
|
- internal
|
||||||
- dev
|
- dev
|
||||||
rules:
|
rules:
|
||||||
- name: Block KEV advisories
|
- name: Block KEV advisories
|
||||||
tags: [kev]
|
tags: [kev]
|
||||||
action: block
|
action: block
|
||||||
|
|
||||||
- name: Warn medium severity
|
- name: Warn medium severity
|
||||||
severity: [Medium]
|
severity: [Medium]
|
||||||
environments: [internal]
|
environments: [internal]
|
||||||
action: warn
|
action: warn
|
||||||
|
|
||||||
- name: Accept vendor VEX
|
- name: Accept vendor VEX
|
||||||
action:
|
action:
|
||||||
type: require_vex
|
type: require_vex
|
||||||
requireVex:
|
requireVex:
|
||||||
vendors: [VendorX, VendorY]
|
vendors: [VendorX, VendorY]
|
||||||
justifications:
|
justifications:
|
||||||
- component_not_present
|
- component_not_present
|
||||||
- vulnerable_code_not_present
|
- vulnerable_code_not_present
|
||||||
|
|
||||||
- name: Quiet low severity
|
- name: Quiet low severity
|
||||||
severity: [Low, Informational]
|
severity: [Low, Informational]
|
||||||
action:
|
action:
|
||||||
type: ignore
|
type: ignore
|
||||||
until: 2026-01-01T00:00:00Z
|
until: 2026-01-01T00:00:00Z
|
||||||
justification: "Deferred to annual remediation cycle"
|
justification: "Deferred to annual remediation cycle"
|
||||||
|
|||||||
@@ -1,72 +1,72 @@
|
|||||||
# Serverless Policy Example (`serverless.stella`)
|
# Serverless Policy Example (`serverless.stella`)
|
||||||
|
|
||||||
Optimised for short-lived serverless workloads: focus on runtime integrity, disallow vulnerable layers entirely, and permit temporary suppressions only with strict justification windows.
|
Optimised for short-lived serverless workloads: focus on runtime integrity, disallow vulnerable layers entirely, and permit temporary suppressions only with strict justification windows.
|
||||||
|
|
||||||
```dsl
|
```dsl
|
||||||
policy "Serverless Tight Policy" syntax "stella-dsl@1" {
|
policy "Serverless Tight Policy" syntax "stella-dsl@1" {
|
||||||
metadata {
|
metadata {
|
||||||
description = "Aggressive blocking for serverless runtimes."
|
description = "Aggressive blocking for serverless runtimes."
|
||||||
tags = ["serverless","prod","strict"]
|
tags = ["serverless","prod","strict"]
|
||||||
}
|
}
|
||||||
|
|
||||||
profile severity {
|
profile severity {
|
||||||
env runtime_overrides {
|
env runtime_overrides {
|
||||||
if env.runtime == "serverless" then +0.7
|
if env.runtime == "serverless" then +0.7
|
||||||
if env.runtime == "batch" then +0.2
|
if env.runtime == "batch" then +0.2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rule block_any_high {
|
rule block_any_high {
|
||||||
when severity.normalized >= "High"
|
when severity.normalized >= "High"
|
||||||
then status := "blocked"
|
then status := "blocked"
|
||||||
because "Serverless workloads block High+ severities."
|
because "Serverless workloads block High+ severities."
|
||||||
}
|
}
|
||||||
|
|
||||||
rule forbid_unpinned_base {
|
rule forbid_unpinned_base {
|
||||||
when sbom.has_tag("image:latest-tag")
|
when sbom.has_tag("image:latest-tag")
|
||||||
then status := "blocked"
|
then status := "blocked"
|
||||||
because "Base image must be pinned (no :latest)."
|
because "Base image must be pinned (no :latest)."
|
||||||
}
|
}
|
||||||
|
|
||||||
rule zero_tolerance_vex {
|
rule zero_tolerance_vex {
|
||||||
when vex.any(status == "not_affected")
|
when vex.any(status == "not_affected")
|
||||||
then requireVex { vendors = ["VendorX","VendorY"], justifications = ["component_not_present"] }
|
then requireVex { vendors = ["VendorX","VendorY"], justifications = ["component_not_present"] }
|
||||||
because "Allow not_affected only from trusted vendors with strongest justification."
|
because "Allow not_affected only from trusted vendors with strongest justification."
|
||||||
}
|
}
|
||||||
|
|
||||||
rule temporary_quiet {
|
rule temporary_quiet {
|
||||||
when env.deployment == "canary"
|
when env.deployment == "canary"
|
||||||
and severity.normalized == "Medium"
|
and severity.normalized == "Medium"
|
||||||
then ignore until coalesce(env.quietUntil, "2025-12-31T00:00:00Z")
|
then ignore until coalesce(env.quietUntil, "2025-12-31T00:00:00Z")
|
||||||
because "Allow short canary quiet window while fix rolls out."
|
because "Allow short canary quiet window while fix rolls out."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Commentary
|
## Commentary
|
||||||
|
|
||||||
- Designed for serverless tenants where redeploy cost is low and failing fast is preferred.
|
- Designed for serverless tenants where redeploy cost is low and failing fast is preferred.
|
||||||
- `forbid_unpinned_base` enforces supply-chain best practices.
|
- `forbid_unpinned_base` enforces supply-chain best practices.
|
||||||
- `temporary_quiet` ensures quiet windows expire automatically; require deployments to set `env.quietUntil`.
|
- `temporary_quiet` ensures quiet windows expire automatically; require deployments to set `env.quietUntil`.
|
||||||
- Intended to be layered on top of baseline (override per tenant) or used standalone for serverless-only accounts.
|
- Intended to be layered on top of baseline (override per tenant) or used standalone for serverless-only accounts.
|
||||||
|
|
||||||
## Try it out
|
## Try it out
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
stella policy lint examples/policies/serverless.stella
|
stella policy lint examples/policies/serverless.stella
|
||||||
stella policy simulate P-serverless --candidate 1 \
|
stella policy simulate P-serverless --candidate 1 \
|
||||||
--sbom sbom:lambda-hello --env runtime=serverless --env deployment=canary
|
--sbom sbom:lambda-hello --env runtime=serverless --env deployment=canary
|
||||||
```
|
```
|
||||||
|
|
||||||
## Compliance checklist
|
## Compliance checklist
|
||||||
|
|
||||||
- [ ] Quiet window expirations tracked and documented.
|
- [ ] Quiet window expirations tracked and documented.
|
||||||
- [ ] Trusted VEX vendor list reviewed quarterly.
|
- [ ] Trusted VEX vendor list reviewed quarterly.
|
||||||
- [ ] Deployment pipeline enforces pinned base images before approval.
|
- [ ] Deployment pipeline enforces pinned base images before approval.
|
||||||
- [ ] Canary deployments monitored for recurrence before ignoring Medium severity.
|
- [ ] Canary deployments monitored for recurrence before ignoring Medium severity.
|
||||||
- [ ] Serverless teams acknowledge runbook for blocked deployments.
|
- [ ] Serverless teams acknowledge runbook for blocked deployments.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
*Last updated: 2025-10-26.*
|
*Last updated: 2025-10-26.*
|
||||||
|
|
||||||
|
|||||||
@@ -1,39 +1,39 @@
|
|||||||
policy "Serverless Tight Policy" syntax "stella-dsl@1" {
|
policy "Serverless Tight Policy" syntax "stella-dsl@1" {
|
||||||
metadata {
|
metadata {
|
||||||
description = "Aggressive blocking for serverless runtimes."
|
description = "Aggressive blocking for serverless runtimes."
|
||||||
tags = ["serverless","prod","strict"]
|
tags = ["serverless","prod","strict"]
|
||||||
}
|
}
|
||||||
|
|
||||||
profile severity {
|
profile severity {
|
||||||
env runtime_overrides {
|
env runtime_overrides {
|
||||||
if env.runtime == "serverless" then +0.7
|
if env.runtime == "serverless" then +0.7
|
||||||
if env.runtime == "batch" then +0.2
|
if env.runtime == "batch" then +0.2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rule block_any_high {
|
rule block_any_high {
|
||||||
when severity.normalized >= "High"
|
when severity.normalized >= "High"
|
||||||
then status := "blocked"
|
then status := "blocked"
|
||||||
because "Serverless workloads block High+ severities."
|
because "Serverless workloads block High+ severities."
|
||||||
}
|
}
|
||||||
|
|
||||||
rule forbid_unpinned_base {
|
rule forbid_unpinned_base {
|
||||||
when sbom.has_tag("image:latest-tag")
|
when sbom.has_tag("image:latest-tag")
|
||||||
then status := "blocked"
|
then status := "blocked"
|
||||||
because "Base image must be pinned (no :latest)."
|
because "Base image must be pinned (no :latest)."
|
||||||
}
|
}
|
||||||
|
|
||||||
rule zero_tolerance_vex {
|
rule zero_tolerance_vex {
|
||||||
when vex.any(status == "not_affected")
|
when vex.any(status == "not_affected")
|
||||||
then requireVex { vendors = ["VendorX","VendorY"], justifications = ["component_not_present"] }
|
then requireVex { vendors = ["VendorX","VendorY"], justifications = ["component_not_present"] }
|
||||||
because "Allow not_affected only from trusted vendors with strongest justification."
|
because "Allow not_affected only from trusted vendors with strongest justification."
|
||||||
}
|
}
|
||||||
|
|
||||||
rule temporary_quiet {
|
rule temporary_quiet {
|
||||||
when env.deployment == "canary"
|
when env.deployment == "canary"
|
||||||
and severity.normalized == "Medium"
|
and severity.normalized == "Medium"
|
||||||
then ignore until coalesce(env.quietUntil, "2025-12-31T00:00:00Z")
|
then ignore until coalesce(env.quietUntil, "2025-12-31T00:00:00Z")
|
||||||
because "Allow short canary quiet window while fix rolls out."
|
because "Allow short canary quiet window while fix rolls out."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,41 +1,41 @@
|
|||||||
version: "1.0"
|
version: "1.0"
|
||||||
metadata:
|
metadata:
|
||||||
description: Strict policy for serverless workloads
|
description: Strict policy for serverless workloads
|
||||||
tags:
|
tags:
|
||||||
- serverless
|
- serverless
|
||||||
- prod
|
- prod
|
||||||
- strict
|
- strict
|
||||||
exceptions:
|
exceptions:
|
||||||
effects:
|
effects:
|
||||||
- id: suppress-canary
|
- id: suppress-canary
|
||||||
name: Canary Freeze
|
name: Canary Freeze
|
||||||
effect: suppress
|
effect: suppress
|
||||||
routingTemplate: secops-approvers
|
routingTemplate: secops-approvers
|
||||||
maxDurationDays: 14
|
maxDurationDays: 14
|
||||||
routingTemplates:
|
routingTemplates:
|
||||||
- id: secops-approvers
|
- id: secops-approvers
|
||||||
authorityRouteId: governance.secops
|
authorityRouteId: governance.secops
|
||||||
requireMfa: true
|
requireMfa: true
|
||||||
rules:
|
rules:
|
||||||
- name: Block High And Above
|
- name: Block High And Above
|
||||||
severity: [High, Critical]
|
severity: [High, Critical]
|
||||||
action: block
|
action: block
|
||||||
|
|
||||||
- name: Forbid Unpinned Base Images
|
- name: Forbid Unpinned Base Images
|
||||||
tags: [image:latest-tag]
|
tags: [image:latest-tag]
|
||||||
action: block
|
action: block
|
||||||
|
|
||||||
- name: Require Trusted VEX
|
- name: Require Trusted VEX
|
||||||
action:
|
action:
|
||||||
type: require_vex
|
type: require_vex
|
||||||
requireVex:
|
requireVex:
|
||||||
vendors: [VendorX, VendorY]
|
vendors: [VendorX, VendorY]
|
||||||
justifications: [component_not_present]
|
justifications: [component_not_present]
|
||||||
|
|
||||||
- name: Quiet Medium Canary
|
- name: Quiet Medium Canary
|
||||||
severity: [Medium]
|
severity: [Medium]
|
||||||
environments: [canary]
|
environments: [canary]
|
||||||
action:
|
action:
|
||||||
type: ignore
|
type: ignore
|
||||||
until: 2025-12-31T00:00:00Z
|
until: 2025-12-31T00:00:00Z
|
||||||
justification: "Temporary canary exception"
|
justification: "Temporary canary exception"
|
||||||
|
|||||||
@@ -1,154 +1,154 @@
|
|||||||
# StellaOps Console – Guided Tours (Sprint 23)
|
# StellaOps Console – Guided Tours (Sprint 23)
|
||||||
|
|
||||||
> **Audience:** Field enablement, Docs Guild writers, Console product leads, and onboarding facilitators.
|
> **Audience:** Field enablement, Docs Guild writers, Console product leads, and onboarding facilitators.
|
||||||
> **Scope:** Ready-to-run walkthrough scripts that showcase the Console’s critical workflows—triage, audit evidence, and policy rollout—while reinforcing CLI parity, tenancy, and offline expectations.
|
> **Scope:** Ready-to-run walkthrough scripts that showcase the Console’s critical workflows—triage, audit evidence, and policy rollout—while reinforcing CLI parity, tenancy, and offline expectations.
|
||||||
|
|
||||||
These tours stitch together the primary Console workspaces so trainers can deliver consistent demos or capture annotated media (screenshots/GIFs). Each tour lists prerequisites, live steps, CLI fallbacks, and assets to capture. Use them alongside the workspace dossiers in `/docs/ui/*.md` when preparing customer sessions or internal dry runs.
|
These tours stitch together the primary Console workspaces so trainers can deliver consistent demos or capture annotated media (screenshots/GIFs). Each tour lists prerequisites, live steps, CLI fallbacks, and assets to capture. Use them alongside the workspace dossiers in `/docs/ui/*.md` when preparing customer sessions or internal dry runs.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 1 · Prerequisites & Setup
|
## 1 · Prerequisites & Setup
|
||||||
|
|
||||||
- **Environment:** Console deployed per [deployment guide](../deploy/console.md) with Scheduler, Policy Engine, Concelier, Excititor, SBOM Service, and Downloads manifest available.
|
- **Environment:** Console deployed per [deployment guide](../deploy/console.md) with Scheduler, Policy Engine, Concelier, Excititor, SBOM Service, and Downloads manifest available.
|
||||||
- **Tenant & data:** Sample tenant populated with recent scans, findings, runs, and export bundles. Ensure Offline Kit snapshot exists for offline callouts.
|
- **Tenant & data:** Sample tenant populated with recent scans, findings, runs, and export bundles. Ensure Offline Kit snapshot exists for offline callouts.
|
||||||
- **Scopes:** Presenter identity must hold `ui.read`, `findings.read`, `policy:*` (read/write/simulate/approve), `runs.read`, `downloads.read`, `aoc:verify`, and `ui.telemetry` to surface telemetry banners.
|
- **Scopes:** Presenter identity must hold `ui.read`, `findings.read`, `policy:*` (read/write/simulate/approve), `runs.read`, `downloads.read`, `aoc:verify`, and `ui.telemetry` to surface telemetry banners.
|
||||||
- **Browser tooling:** Enable screen recording (1920×1080 @ 60 fps) and keyboard overlay if capturing walkthroughs.
|
- **Browser tooling:** Enable screen recording (1920×1080 @ 60 fps) and keyboard overlay if capturing walkthroughs.
|
||||||
- **CLI parity:** Have `stella` CLI configured against the same tenant; keep terminal window ready for parity steps.
|
- **CLI parity:** Have `stella` CLI configured against the same tenant; keep terminal window ready for parity steps.
|
||||||
- **Assets directory:** Store captures under `docs/assets/ui/tours/` (see [`README`](../assets/ui/tours/README.md)) with the naming convention `<tour>-step-<nn>.png` and `<tour>-flow.gif`.
|
- **Assets directory:** Store captures under `docs/assets/ui/tours/` (see [`README`](../assets/ui/tours/README.md)) with the naming convention `<tour>-step-<nn>.png` and `<tour>-flow.gif`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 2 · Tour A — Critical Finding Triage
|
## 2 · Tour A — Critical Finding Triage
|
||||||
|
|
||||||
**Persona:** Security analyst responding to a fresh high-severity finding.
|
**Persona:** Security analyst responding to a fresh high-severity finding.
|
||||||
**Goal:** Navigate from dashboard signal to remediation decision, highlighting explain trails and run evidence.
|
**Goal:** Navigate from dashboard signal to remediation decision, highlighting explain trails and run evidence.
|
||||||
|
|
||||||
### 2.1 Key references
|
### 2.1 Key references
|
||||||
- [Console overview](../ui/console-overview.md) – tenant switching, status ticker.
|
- [Console overview](../ui/console-overview.md) – tenant switching, status ticker.
|
||||||
- [Navigation](../ui/navigation.md) – command palette, shortcuts.
|
- [Navigation](../ui/navigation.md) – command palette, shortcuts.
|
||||||
- [Findings workspace](../ui/findings.md) – filters, explain drawer, exports.
|
- [Findings workspace](../ui/findings.md) – filters, explain drawer, exports.
|
||||||
- [Runs workspace](../ui/runs.md) – live progress, evidence downloads.
|
- [Runs workspace](../ui/runs.md) – live progress, evidence downloads.
|
||||||
|
|
||||||
### 2.2 Live walkthrough
|
### 2.2 Live walkthrough
|
||||||
1. **Start on Dashboard:** Show status ticker surfacing new `Critical` badge. Call out tenant pill and offline banner behaviour (§3 of console overview).
|
1. **Start on Dashboard:** Show status ticker surfacing new `Critical` badge. Call out tenant pill and offline banner behaviour (§3 of console overview).
|
||||||
2. **Command palette jump:** Press `Ctrl/Cmd+K`, type `Findings`, hit `Enter`. Narrate keyboard accessibility from navigation guide.
|
2. **Command palette jump:** Press `Ctrl/Cmd+K`, type `Findings`, hit `Enter`. Narrate keyboard accessibility from navigation guide.
|
||||||
3. **Apply global filters:** Open filter tray (`Shift+F`), set `Severity = Critical`, `Status = affected`, time window `Last 24h`. Mention saved view presets triggered with `Ctrl/Cmd+1`.
|
3. **Apply global filters:** Open filter tray (`Shift+F`), set `Severity = Critical`, `Status = affected`, time window `Last 24h`. Mention saved view presets triggered with `Ctrl/Cmd+1`.
|
||||||
4. **Open explain drawer:** Select top finding, trigger `Explain` tab. Highlight rule chain, VEX impact, and evidence references (§5 of findings doc).
|
4. **Open explain drawer:** Select top finding, trigger `Explain` tab. Highlight rule chain, VEX impact, and evidence references (§5 of findings doc).
|
||||||
5. **Dive into related run:** Click `Run ID` link inside explain drawer → opens Runs detail drawer filtered by run ID. Show segmented progress SSE updates.
|
5. **Dive into related run:** Click `Run ID` link inside explain drawer → opens Runs detail drawer filtered by run ID. Show segmented progress SSE updates.
|
||||||
6. **Capture evidence:** In Runs drawer, download evidence bundle; note CLI parity `stella runs export --run <id>`. Mention offline fallback (download queue offline banner from runs doc §10).
|
6. **Capture evidence:** In Runs drawer, download evidence bundle; note CLI parity `stella runs export --run <id>`. Mention offline fallback (download queue offline banner from runs doc §10).
|
||||||
7. **Escalate / create ticket:** Use bulk action or comment (if configured) to demonstrate optional integration; mention Authority audit log tie-in.
|
7. **Escalate / create ticket:** Use bulk action or comment (if configured) to demonstrate optional integration; mention Authority audit log tie-in.
|
||||||
8. **Wrap with CLI:** Pop terminal and run `stella findings explain --policy <id> --finding <key> --format markdown` to show reproducibility.
|
8. **Wrap with CLI:** Pop terminal and run `stella findings explain --policy <id> --finding <key> --format markdown` to show reproducibility.
|
||||||
|
|
||||||
### 2.3 Capture checklist
|
### 2.3 Capture checklist
|
||||||
- `docs/assets/ui/tours/triage-step-01.png` — dashboard ticker highlighting new criticals.
|
- `docs/assets/ui/tours/triage-step-01.png` — dashboard ticker highlighting new criticals.
|
||||||

|

|
||||||
- `docs/assets/ui/tours/triage-step-03.png` — filter tray with severity/time window applied.
|
- `docs/assets/ui/tours/triage-step-03.png` — filter tray with severity/time window applied.
|
||||||

|

|
||||||
- `docs/assets/ui/tours/triage-step-04.png` — explain drawer evidence tab.
|
- `docs/assets/ui/tours/triage-step-04.png` — explain drawer evidence tab.
|
||||||

|

|
||||||
- `docs/assets/ui/tours/triage-flow.gif` — 20 s screen recording of steps 1–5 with annotations.
|
- `docs/assets/ui/tours/triage-flow.gif` — 20 s screen recording of steps 1–5 with annotations.
|
||||||

|

|
||||||
|
|
||||||
### 2.4 Talking points & callouts
|
### 2.4 Talking points & callouts
|
||||||
- Call out Aggregation-Only boundaries: findings reference Concelier/Excititor provenance, UI stays read-only.
|
- Call out Aggregation-Only boundaries: findings reference Concelier/Excititor provenance, UI stays read-only.
|
||||||
- Mention `ui_route_render_seconds` telemetry for demos (see [observability guide](../observability/ui-telemetry.md)).
|
- Mention `ui_route_render_seconds` telemetry for demos (see [observability guide](../observability/ui-telemetry.md)).
|
||||||
- Offline note: highlight offline banner that appears if `/console/status` heartbeat fails (§6 of console overview).
|
- Offline note: highlight offline banner that appears if `/console/status` heartbeat fails (§6 of console overview).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 3 · Tour B — Audit Evidence Export
|
## 3 · Tour B — Audit Evidence Export
|
||||||
|
|
||||||
**Persona:** Compliance lead compiling artefacts for an external audit.
|
**Persona:** Compliance lead compiling artefacts for an external audit.
|
||||||
**Goal:** Retrieve signed manifests, export run/finding evidence, and verify parity with Offline Kit.
|
**Goal:** Retrieve signed manifests, export run/finding evidence, and verify parity with Offline Kit.
|
||||||
|
|
||||||
### 3.1 Key references
|
### 3.1 Key references
|
||||||
- [Downloads workspace](../ui/downloads.md) – manifest, parity, export queue.
|
- [Downloads workspace](../ui/downloads.md) – manifest, parity, export queue.
|
||||||
- [Runs workspace](../ui/runs.md) – evidence panel.
|
- [Runs workspace](../ui/runs.md) – evidence panel.
|
||||||
- [Console security posture](../security/console-security.md) – evidence handling.
|
- [Console security posture](../security/console-security.md) – evidence handling.
|
||||||
- [CLI vs UI parity matrix](../cli-vs-ui-parity.md).
|
- [CLI vs UI parity matrix](../cli-vs-ui-parity.md).
|
||||||
|
|
||||||
### 3.2 Live walkthrough
|
### 3.2 Live walkthrough
|
||||||
1. **Open Downloads:** Use left rail or command palette to reach `/console/downloads`. Point out snapshot banner, cosign verification status.
|
1. **Open Downloads:** Use left rail or command palette to reach `/console/downloads`. Point out snapshot banner, cosign verification status.
|
||||||
2. **Verify manifest:** Click “Verify signature” quick action; narrate parity with `cosign verify --key <key> manifest.json` from downloads doc §3.
|
2. **Verify manifest:** Click “Verify signature” quick action; narrate parity with `cosign verify --key <key> manifest.json` from downloads doc §3.
|
||||||
3. **Compare Offline Kit:** Switch to “Offline Kits” tab, run parity check to ensure kit digest matches manifest. Demonstrate offline guidance (downloads doc §6).
|
3. **Compare Offline Kit:** Switch to “Offline Kits” tab, run parity check to ensure kit digest matches manifest. Demonstrate offline guidance (downloads doc §6).
|
||||||
4. **Queue evidence bundle:** Navigate to Runs workspace, choose relevant run, trigger “Bundle for offline” (runs doc §8).
|
4. **Queue evidence bundle:** Navigate to Runs workspace, choose relevant run, trigger “Bundle for offline” (runs doc §8).
|
||||||
5. **Return to Downloads → Exports tab:** Show newly generated evidence bundle with retention countdown.
|
5. **Return to Downloads → Exports tab:** Show newly generated evidence bundle with retention countdown.
|
||||||
6. **Download & inspect:** Open detail drawer, copy CLI command `stella runs export --run <id> --bundle`. Mention location for storing evidence.
|
6. **Download & inspect:** Open detail drawer, copy CLI command `stella runs export --run <id> --bundle`. Mention location for storing evidence.
|
||||||
7. **Log parity results:** Use notes or tags to flag audit package completion (if notifications configured).
|
7. **Log parity results:** Use notes or tags to flag audit package completion (if notifications configured).
|
||||||
8. **CLI parity close-out:** Run `stella downloads manifest --channel stable` to mirror UI manifest retrieval. Confirm digests match.
|
8. **CLI parity close-out:** Run `stella downloads manifest --channel stable` to mirror UI manifest retrieval. Confirm digests match.
|
||||||
|
|
||||||
### 3.3 Capture checklist
|
### 3.3 Capture checklist
|
||||||
- `docs/assets/ui/tours/audit-step-02.png` — manifest verification banner (green).
|
- `docs/assets/ui/tours/audit-step-02.png` — manifest verification banner (green).
|
||||||

|

|
||||||
- `docs/assets/ui/tours/audit-step-05.png` — exports tab showing evidence bundle ready.
|
- `docs/assets/ui/tours/audit-step-05.png` — exports tab showing evidence bundle ready.
|
||||||

|

|
||||||
- `docs/assets/ui/tours/audit-flow.gif` — 25 s capture from manifest view through export download.
|
- `docs/assets/ui/tours/audit-flow.gif` — 25 s capture from manifest view through export download.
|
||||||

|

|
||||||
|
|
||||||
### 3.4 Talking points & callouts
|
### 3.4 Talking points & callouts
|
||||||
- Stress deterministic manifests and Cosign signatures; reference deployment doc for TLS/CSP alignment.
|
- Stress deterministic manifests and Cosign signatures; reference deployment doc for TLS/CSP alignment.
|
||||||
- Highlight audit trail: downloads actions recorded via `ui.download.commandCopied` logs and Authority audit entries.
|
- Highlight audit trail: downloads actions recorded via `ui.download.commandCopied` logs and Authority audit entries.
|
||||||
- Offline note: show guidance when parity check detects stale manifest; mention CLI fallback for sealed networks.
|
- Offline note: show guidance when parity check detects stale manifest; mention CLI fallback for sealed networks.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 4 · Tour C — Policy Rollout & Promotion
|
## 4 · Tour C — Policy Rollout & Promotion
|
||||||
|
|
||||||
**Persona:** Policy owner preparing and promoting a new ruleset.
|
**Persona:** Policy owner preparing and promoting a new ruleset.
|
||||||
**Goal:** Draft review, simulation, approval, and promotion within Console, with CLI parity.
|
**Goal:** Draft review, simulation, approval, and promotion within Console, with CLI parity.
|
||||||
|
|
||||||
### 4.1 Key references
|
### 4.1 Key references
|
||||||
- [Policies workspace](../ui/policies.md) – simulations, approvals, promotion.
|
- [Policies workspace](../ui/policies.md) – simulations, approvals, promotion.
|
||||||
- [Policy editor](../ui/policy-editor.md) – Monaco editor, linting.
|
- [Policy editor](../ui/policy-editor.md) – Monaco editor, linting.
|
||||||
- [Runs workspace](../ui/runs.md) – policy run monitoring.
|
- [Runs workspace](../ui/runs.md) – policy run monitoring.
|
||||||
- [Security posture](../security/console-security.md) – fresh-auth and scopes.
|
- [Security posture](../security/console-security.md) – fresh-auth and scopes.
|
||||||
|
|
||||||
### 4.2 Live walkthrough
|
### 4.2 Live walkthrough
|
||||||
1. **Policy overview:** Open `/console/policies`, filter by “Staged” state. Highlight list columns (owners, pending approvals).
|
1. **Policy overview:** Open `/console/policies`, filter by “Staged” state. Highlight list columns (owners, pending approvals).
|
||||||
2. **Enter draft:** Select policy → open editor view. Show checklist sidebar (lint, simulation, determinism).
|
2. **Enter draft:** Select policy → open editor view. Show checklist sidebar (lint, simulation, determinism).
|
||||||
3. **Run lint & simulation:** Hit `Run lint`, then `Run simulation`. Narrate asynchronous progress with SSE ticker; reference CLI `stella policy simulate`.
|
3. **Run lint & simulation:** Hit `Run lint`, then `Run simulation`. Narrate asynchronous progress with SSE ticker; reference CLI `stella policy simulate`.
|
||||||
4. **Review diff:** Open simulation diff view to compare Active vs Staged; highlight severity up/down badges (§6 of policies doc).
|
4. **Review diff:** Open simulation diff view to compare Active vs Staged; highlight severity up/down badges (§6 of policies doc).
|
||||||
5. **Approval workflow:** Assign reviewer, show comment thread. Trigger fresh-auth prompt when clicking “Submit for review” (security doc §1.2).
|
5. **Approval workflow:** Assign reviewer, show comment thread. Trigger fresh-auth prompt when clicking “Submit for review” (security doc §1.2).
|
||||||
6. **Promote policy:** After approvals, open promotion dialog, choose “Full run”. Emphasise policy run scheduling and RBAC.
|
6. **Promote policy:** After approvals, open promotion dialog, choose “Full run”. Emphasise policy run scheduling and RBAC.
|
||||||
7. **Monitor run:** Jump to Runs workspace, filter by policy run; show progress segments and findings delta metrics.
|
7. **Monitor run:** Jump to Runs workspace, filter by policy run; show progress segments and findings delta metrics.
|
||||||
8. **Publish CLI parity:** Execute `stella policy promote --policy <id> --revision <rev> --run-mode full` to reinforce reproducibility.
|
8. **Publish CLI parity:** Execute `stella policy promote --policy <id> --revision <rev> --run-mode full` to reinforce reproducibility.
|
||||||
|
|
||||||
### 4.3 Capture checklist
|
### 4.3 Capture checklist
|
||||||
- `docs/assets/ui/tours/policy-step-02.png` — editor checklist with lint/simulation statuses.
|
- `docs/assets/ui/tours/policy-step-02.png` — editor checklist with lint/simulation statuses.
|
||||||

|

|
||||||
- `docs/assets/ui/tours/policy-step-04.png` — simulation diff comparing Active vs Staged.
|
- `docs/assets/ui/tours/policy-step-04.png` — simulation diff comparing Active vs Staged.
|
||||||

|

|
||||||
- `docs/assets/ui/tours/policy-flow.gif` — 30 s clip from draft view through promotion confirmation.
|
- `docs/assets/ui/tours/policy-flow.gif` — 30 s clip from draft view through promotion confirmation.
|
||||||

|

|
||||||
|
|
||||||
### 4.4 Talking points & callouts
|
### 4.4 Talking points & callouts
|
||||||
- Stress governance: approvals logged with correlation IDs, fresh-auth enforced.
|
- Stress governance: approvals logged with correlation IDs, fresh-auth enforced.
|
||||||
- Mention telemetry metrics (`ui_tenant_switch_total`, policy run charts) for monitoring adoption.
|
- Mention telemetry metrics (`ui_tenant_switch_total`, policy run charts) for monitoring adoption.
|
||||||
- Offline note: show how promotion dialog surfaces CLI script when in sealed mode; reference offline guidance in policies doc §10.
|
- Offline note: show how promotion dialog surfaces CLI script when in sealed mode; reference offline guidance in policies doc §10.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 5 · Production Tips & Media Hygiene
|
## 5 · Production Tips & Media Hygiene
|
||||||
|
|
||||||
- **Script timing:** Keep each tour ≤ 3 minutes live demo, ≤ 30 s GIF. Include captions for accessibility.
|
- **Script timing:** Keep each tour ≤ 3 minutes live demo, ≤ 30 s GIF. Include captions for accessibility.
|
||||||
- **Annotations:** Use consistent callouts (numbered badges, short labels) overlayed in post-processing; ensure final media compressed but legible (< 2 MB PNG, < 8 MB GIF). See `docs/assets/ui/tours/README.md` for shared template guidance.
|
- **Annotations:** Use consistent callouts (numbered badges, short labels) overlayed in post-processing; ensure final media compressed but legible (< 2 MB PNG, < 8 MB GIF). See `docs/assets/ui/tours/README.md` for shared template guidance.
|
||||||
- **Versioning:** Annotated assets should include Console build hash in metadata or caption (align with `/console/downloads` manifest version).
|
- **Versioning:** Annotated assets should include Console build hash in metadata or caption (align with `/console/downloads` manifest version).
|
||||||
- **Storage:** Commit final media under `docs/assets/ui/tours/` and update `.gitattributes` if smudge filters required. Note large GIFs may need Git LFS depending on repository policy.
|
- **Storage:** Commit final media under `docs/assets/ui/tours/` and update `.gitattributes` if smudge filters required. Note large GIFs may need Git LFS depending on repository policy.
|
||||||
- **Review cadence:** Re-run tours whenever workspaces change navigation or introduce new buttons; log updates in `docs/updates/<date>-console-tours.md` (create if absent).
|
- **Review cadence:** Re-run tours whenever workspaces change navigation or introduce new buttons; log updates in `docs/updates/<date>-console-tours.md` (create if absent).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 6 · Compliance Checklist
|
## 6 · Compliance Checklist
|
||||||
|
|
||||||
- [x] Tour scripts cover triage, audit evidence, and policy rollout scenarios requested in DOCS-CONSOLE-23-017.
|
- [x] Tour scripts cover triage, audit evidence, and policy rollout scenarios requested in DOCS-CONSOLE-23-017.
|
||||||
- [x] Each tour references authoritative workspace docs and CLI parity commands.
|
- [x] Each tour references authoritative workspace docs and CLI parity commands.
|
||||||
- [x] Capture checklist names align with `docs/assets/ui/tours/` convention.
|
- [x] Capture checklist names align with `docs/assets/ui/tours/` convention.
|
||||||
- [x] Offline and sealed-mode notes included for every flow.
|
- [x] Offline and sealed-mode notes included for every flow.
|
||||||
- [x] Security considerations (scopes, fresh-auth, evidence handling) highlighted.
|
- [x] Security considerations (scopes, fresh-auth, evidence handling) highlighted.
|
||||||
- [x] Observability/telemetry pointers surfaced to support Ops follow-up.
|
- [x] Observability/telemetry pointers surfaced to support Ops follow-up.
|
||||||
- [x] Media hygiene guidance documented (assets, compression, versioning).
|
- [x] Media hygiene guidance documented (assets, compression, versioning).
|
||||||
- [x] Document timestamp reflects Sprint 23 delivery.
|
- [x] Document timestamp reflects Sprint 23 delivery.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
*Last updated: 2025-10-27 (Sprint 23).*
|
*Last updated: 2025-10-27 (Sprint 23).*
|
||||||
|
|||||||
@@ -1,337 +1,337 @@
|
|||||||
# Export Center REST API
|
# Export Center REST API
|
||||||
|
|
||||||
> **Audience:** Platform integrators, Console/CLI developers, and automation engineers orchestrating export runs.
|
> **Audience:** Platform integrators, Console/CLI developers, and automation engineers orchestrating export runs.
|
||||||
> **Base route:** `/api/export/*` behind the StellaOps gateway; requires Authority-issued tokens with export scopes.
|
> **Base route:** `/api/export/*` behind the StellaOps gateway; requires Authority-issued tokens with export scopes.
|
||||||
|
|
||||||
This reference describes the Export Center API introduced in Export Center Phase 1 (Epic 10) and extended in Phase 2. Use it alongside the [Export Center Architecture](architecture.md) and [Profiles](profiles.md) guides for service-level semantics.
|
This reference describes the Export Center API introduced in Export Center Phase 1 (Epic 10) and extended in Phase 2. Use it alongside the [Export Center Architecture](architecture.md) and [Profiles](profiles.md) guides for service-level semantics.
|
||||||
|
|
||||||
> Status: Endpoint implementation lands with `EXPORT-SVC-35-006` (Sprint 35) and related follow-on tasks. As of the current build the WebService hosts only the template stub; use this contract for coordination and update once the API is wired.
|
> Status: Endpoint implementation lands with `EXPORT-SVC-35-006` (Sprint 35) and related follow-on tasks. As of the current build the WebService hosts only the template stub; use this contract for coordination and update once the API is wired.
|
||||||
|
|
||||||
## 1. Authentication and headers
|
## 1. Authentication and headers
|
||||||
|
|
||||||
- **Authorization:** Bearer tokens in `Authorization: Bearer <token>` paired with DPoP proof. Required scopes per endpoint:
|
- **Authorization:** Bearer tokens in `Authorization: Bearer <token>` paired with DPoP proof. Required scopes per endpoint:
|
||||||
- `export:profile:manage` for profile CRUD.
|
- `export:profile:manage` for profile CRUD.
|
||||||
- `export:run` to submit and cancel runs.
|
- `export:run` to submit and cancel runs.
|
||||||
- `export:read` to list and inspect runs.
|
- `export:read` to list and inspect runs.
|
||||||
- `export:download` for bundle downloads and manifests.
|
- `export:download` for bundle downloads and manifests.
|
||||||
- **Tenant context:** Provide `X-Stella-Tenant` when the token carries multiple tenants; defaults to token tenant otherwise.
|
- **Tenant context:** Provide `X-Stella-Tenant` when the token carries multiple tenants; defaults to token tenant otherwise.
|
||||||
- **Idempotency:** Mutating endpoints accept `Idempotency-Key` (UUID). Retrying with the same key returns the original result.
|
- **Idempotency:** Mutating endpoints accept `Idempotency-Key` (UUID). Retrying with the same key returns the original result.
|
||||||
- **Rate limits and quotas:** Responses include `X-Stella-Quota-Limit`, `X-Stella-Quota-Remaining`, and `X-Stella-Quota-Reset`. Exceeding quotas returns `429 Too Many Requests` with `ERR_EXPORT_QUOTA`.
|
- **Rate limits and quotas:** Responses include `X-Stella-Quota-Limit`, `X-Stella-Quota-Remaining`, and `X-Stella-Quota-Reset`. Exceeding quotas returns `429 Too Many Requests` with `ERR_EXPORT_QUOTA`.
|
||||||
- **Content negotiation:** Requests and responses use `application/json; charset=utf-8` unless otherwise stated. Downloads stream binary content with profile-specific media types.
|
- **Content negotiation:** Requests and responses use `application/json; charset=utf-8` unless otherwise stated. Downloads stream binary content with profile-specific media types.
|
||||||
- **SSE:** Event streams set `Content-Type: text/event-stream` and keep connections alive with comment heartbeats every 15 seconds.
|
- **SSE:** Event streams set `Content-Type: text/event-stream` and keep connections alive with comment heartbeats every 15 seconds.
|
||||||
|
|
||||||
## 2. Error model
|
## 2. Error model
|
||||||
|
|
||||||
Errors follow standard HTTP codes with structured payloads:
|
Errors follow standard HTTP codes with structured payloads:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"code": "ERR_EXPORT_002",
|
"code": "ERR_EXPORT_002",
|
||||||
"message": "Profile not found for tenant acme",
|
"message": "Profile not found for tenant acme",
|
||||||
"details": [],
|
"details": [],
|
||||||
"traceId": "01J9N4Y4K2XY8C5V7T2S",
|
"traceId": "01J9N4Y4K2XY8C5V7T2S",
|
||||||
"timestamp": "2025-10-29T13:42:11Z"
|
"timestamp": "2025-10-29T13:42:11Z"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
| Code | Description | Typical HTTP status | Notes |
|
| Code | Description | Typical HTTP status | Notes |
|
||||||
|------|-------------|---------------------|-------|
|
|------|-------------|---------------------|-------|
|
||||||
| `ERR_EXPORT_001` | Validation failure (selectors, configuration) | 400 | `details` enumerates offending fields. |
|
| `ERR_EXPORT_001` | Validation failure (selectors, configuration) | 400 | `details` enumerates offending fields. |
|
||||||
| `ERR_EXPORT_002` | Profile missing or not accessible for tenant | 404 | Returned on run submission or profile fetch. |
|
| `ERR_EXPORT_002` | Profile missing or not accessible for tenant | 404 | Returned on run submission or profile fetch. |
|
||||||
| `ERR_EXPORT_003` | Concurrency or quota exceeded | 429 | Includes `retryAfterSeconds` in `details`. |
|
| `ERR_EXPORT_003` | Concurrency or quota exceeded | 429 | Includes `retryAfterSeconds` in `details`. |
|
||||||
| `ERR_EXPORT_004` | Adapter failure (schema mismatch, upstream outage) | 502 | Worker logs contain adapter error reason. |
|
| `ERR_EXPORT_004` | Adapter failure (schema mismatch, upstream outage) | 502 | Worker logs contain adapter error reason. |
|
||||||
| `ERR_EXPORT_005` | Signing or KMS error | 500 | Run marked failed with `errorCode=signing`. |
|
| `ERR_EXPORT_005` | Signing or KMS error | 500 | Run marked failed with `errorCode=signing`. |
|
||||||
| `ERR_EXPORT_006` | Distribution failure (HTTP, OCI, object storage) | 502 | `details` lists failing distribution driver. |
|
| `ERR_EXPORT_006` | Distribution failure (HTTP, OCI, object storage) | 502 | `details` lists failing distribution driver. |
|
||||||
| `ERR_EXPORT_007` | Run canceled or expired | 409 | Includes cancel author and timestamp. |
|
| `ERR_EXPORT_007` | Run canceled or expired | 409 | Includes cancel author and timestamp. |
|
||||||
| `ERR_EXPORT_BASE_MISSING` | Base manifest for delta exports not found | 400 | Specific to `mirror:delta`. |
|
| `ERR_EXPORT_BASE_MISSING` | Base manifest for delta exports not found | 400 | Specific to `mirror:delta`. |
|
||||||
| `ERR_EXPORT_EMPTY` | No records matched selectors (when `allowEmpty=false`) | 422 | Useful for guard-railled automation. |
|
| `ERR_EXPORT_EMPTY` | No records matched selectors (when `allowEmpty=false`) | 422 | Useful for guard-railled automation. |
|
||||||
| `ERR_EXPORT_QUOTA` | Daily quota exhausted | 429 | Always paired with quota headers. |
|
| `ERR_EXPORT_QUOTA` | Daily quota exhausted | 429 | Always paired with quota headers. |
|
||||||
|
|
||||||
All responses include `traceId` for correlation with logs and metrics.
|
All responses include `traceId` for correlation with logs and metrics.
|
||||||
|
|
||||||
## 3. Profiles endpoints
|
## 3. Profiles endpoints
|
||||||
|
|
||||||
### 3.1 List profiles
|
### 3.1 List profiles
|
||||||
|
|
||||||
```
|
```
|
||||||
GET /api/export/profiles?kind=json&variant=raw&page=1&pageSize=20
|
GET /api/export/profiles?kind=json&variant=raw&page=1&pageSize=20
|
||||||
Scopes: export:read
|
Scopes: export:read
|
||||||
```
|
```
|
||||||
|
|
||||||
Returns tenant-scoped profiles. Response headers: `X-Total-Count`, `Link` for pagination.
|
Returns tenant-scoped profiles. Response headers: `X-Total-Count`, `Link` for pagination.
|
||||||
|
|
||||||
**Response**
|
**Response**
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"items": [
|
"items": [
|
||||||
{
|
{
|
||||||
"profileId": "prof-json-raw",
|
"profileId": "prof-json-raw",
|
||||||
"name": "Daily JSON Raw",
|
"name": "Daily JSON Raw",
|
||||||
"kind": "json",
|
"kind": "json",
|
||||||
"variant": "raw",
|
"variant": "raw",
|
||||||
"distribution": ["http", "object"],
|
"distribution": ["http", "object"],
|
||||||
"retention": {"mode": "days", "value": 14},
|
"retention": {"mode": "days", "value": 14},
|
||||||
"createdAt": "2025-10-23T08:00:00Z",
|
"createdAt": "2025-10-23T08:00:00Z",
|
||||||
"createdBy": "user:ops"
|
"createdBy": "user:ops"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"page": 1,
|
"page": 1,
|
||||||
"pageSize": 20
|
"pageSize": 20
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3.2 Get a profile
|
### 3.2 Get a profile
|
||||||
|
|
||||||
```
|
```
|
||||||
GET /api/export/profiles/{profileId}
|
GET /api/export/profiles/{profileId}
|
||||||
Scopes: export:read
|
Scopes: export:read
|
||||||
```
|
```
|
||||||
|
|
||||||
Returns full configuration, including `config` payload, distribution options, and metadata.
|
Returns full configuration, including `config` payload, distribution options, and metadata.
|
||||||
|
|
||||||
### 3.3 Create a profile
|
### 3.3 Create a profile
|
||||||
|
|
||||||
```
|
```
|
||||||
POST /api/export/profiles
|
POST /api/export/profiles
|
||||||
Scopes: export:profile:manage
|
Scopes: export:profile:manage
|
||||||
```
|
```
|
||||||
|
|
||||||
**Request**
|
**Request**
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"profileId": "prof-airgap-mirror",
|
"profileId": "prof-airgap-mirror",
|
||||||
"name": "Airgap Mirror Weekly",
|
"name": "Airgap Mirror Weekly",
|
||||||
"kind": "mirror",
|
"kind": "mirror",
|
||||||
"variant": "full",
|
"variant": "full",
|
||||||
"include": ["advisories", "vex", "sboms", "policy"],
|
"include": ["advisories", "vex", "sboms", "policy"],
|
||||||
"distribution": ["http", "object"],
|
"distribution": ["http", "object"],
|
||||||
"encryption": {
|
"encryption": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"recipientKeys": ["age1tenantkey..."],
|
"recipientKeys": ["age1tenantkey..."],
|
||||||
"strict": false
|
"strict": false
|
||||||
},
|
},
|
||||||
"retention": {"mode": "days", "value": 30}
|
"retention": {"mode": "days", "value": 30}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**Response 201**
|
**Response 201**
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"profileId": "prof-airgap-mirror",
|
"profileId": "prof-airgap-mirror",
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"createdAt": "2025-10-29T12:05:22Z",
|
"createdAt": "2025-10-29T12:05:22Z",
|
||||||
"createdBy": "user:ops",
|
"createdBy": "user:ops",
|
||||||
"status": "active"
|
"status": "active"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3.4 Update profile metadata
|
### 3.4 Update profile metadata
|
||||||
|
|
||||||
```
|
```
|
||||||
PATCH /api/export/profiles/{profileId}
|
PATCH /api/export/profiles/{profileId}
|
||||||
Scopes: export:profile:manage
|
Scopes: export:profile:manage
|
||||||
```
|
```
|
||||||
|
|
||||||
Allows renaming, toggling distribution switches, or updating retention. Structural configuration updates (kind/variant/include) create a new revision; the API returns `revisionCreated=true` and the new `profileId` (e.g., `prof-airgap-mirror@2`).
|
Allows renaming, toggling distribution switches, or updating retention. Structural configuration updates (kind/variant/include) create a new revision; the API returns `revisionCreated=true` and the new `profileId` (e.g., `prof-airgap-mirror@2`).
|
||||||
|
|
||||||
### 3.5 Archive profile
|
### 3.5 Archive profile
|
||||||
|
|
||||||
```
|
```
|
||||||
POST /api/export/profiles/{profileId}:archive
|
POST /api/export/profiles/{profileId}:archive
|
||||||
Scopes: export:profile:manage
|
Scopes: export:profile:manage
|
||||||
```
|
```
|
||||||
|
|
||||||
Marks profile as inactive; existing runs remain accessible. Use `:restore` to reactivate.
|
Marks profile as inactive; existing runs remain accessible. Use `:restore` to reactivate.
|
||||||
|
|
||||||
## 4. Run management
|
## 4. Run management
|
||||||
|
|
||||||
### 4.1 Submit an export run
|
### 4.1 Submit an export run
|
||||||
|
|
||||||
```
|
```
|
||||||
POST /api/export/runs
|
POST /api/export/runs
|
||||||
Scopes: export:run
|
Scopes: export:run
|
||||||
```
|
```
|
||||||
|
|
||||||
**Request**
|
**Request**
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"profileId": "prof-json-raw",
|
"profileId": "prof-json-raw",
|
||||||
"selectors": {
|
"selectors": {
|
||||||
"tenants": ["acme"],
|
"tenants": ["acme"],
|
||||||
"timeWindow": {
|
"timeWindow": {
|
||||||
"from": "2025-10-01T00:00:00Z",
|
"from": "2025-10-01T00:00:00Z",
|
||||||
"to": "2025-10-29T00:00:00Z"
|
"to": "2025-10-29T00:00:00Z"
|
||||||
},
|
},
|
||||||
"products": ["registry.example.com/app:*"],
|
"products": ["registry.example.com/app:*"],
|
||||||
"sboms": ["sbom:S-1001", "sbom:S-2004"]
|
"sboms": ["sbom:S-1001", "sbom:S-2004"]
|
||||||
},
|
},
|
||||||
"policySnapshotId": "policy-snap-42",
|
"policySnapshotId": "policy-snap-42",
|
||||||
"options": {
|
"options": {
|
||||||
"allowEmpty": false,
|
"allowEmpty": false,
|
||||||
"priority": "standard"
|
"priority": "standard"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**Response 202**
|
**Response 202**
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"runId": "run-20251029-01",
|
"runId": "run-20251029-01",
|
||||||
"status": "pending",
|
"status": "pending",
|
||||||
"profileId": "prof-json-raw",
|
"profileId": "prof-json-raw",
|
||||||
"createdAt": "2025-10-29T12:12:11Z",
|
"createdAt": "2025-10-29T12:12:11Z",
|
||||||
"createdBy": "user:ops",
|
"createdBy": "user:ops",
|
||||||
"selectors": { "...": "..." },
|
"selectors": { "...": "..." },
|
||||||
"links": {
|
"links": {
|
||||||
"self": "/api/export/runs/run-20251029-01",
|
"self": "/api/export/runs/run-20251029-01",
|
||||||
"events": "/api/export/runs/run-20251029-01/events"
|
"events": "/api/export/runs/run-20251029-01/events"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 4.2 List runs
|
### 4.2 List runs
|
||||||
|
|
||||||
```
|
```
|
||||||
GET /api/export/runs?status=active&profileId=prof-json-raw&page=1&pageSize=10
|
GET /api/export/runs?status=active&profileId=prof-json-raw&page=1&pageSize=10
|
||||||
Scopes: export:read
|
Scopes: export:read
|
||||||
```
|
```
|
||||||
|
|
||||||
Returns latest runs with pagination. Each item includes summary counts, duration, and last event.
|
Returns latest runs with pagination. Each item includes summary counts, duration, and last event.
|
||||||
|
|
||||||
### 4.3 Get run status
|
### 4.3 Get run status
|
||||||
|
|
||||||
```
|
```
|
||||||
GET /api/export/runs/{runId}
|
GET /api/export/runs/{runId}
|
||||||
Scopes: export:read
|
Scopes: export:read
|
||||||
```
|
```
|
||||||
|
|
||||||
Response fields:
|
Response fields:
|
||||||
|
|
||||||
| Field | Description |
|
| Field | Description |
|
||||||
|-------|-------------|
|
|-------|-------------|
|
||||||
| `status` | `pending`, `running`, `success`, `failed`, `canceled`. |
|
| `status` | `pending`, `running`, `success`, `failed`, `canceled`. |
|
||||||
| `progress` | Object with `adapters`, `bytesWritten`, `recordsProcessed`. |
|
| `progress` | Object with `adapters`, `bytesWritten`, `recordsProcessed`. |
|
||||||
| `errorCode` | Populated when `status=failed` (`signing`, `distribution`, etc). |
|
| `errorCode` | Populated when `status=failed` (`signing`, `distribution`, etc). |
|
||||||
| `policySnapshotId` | Returned for policy-aware profiles. |
|
| `policySnapshotId` | Returned for policy-aware profiles. |
|
||||||
| `distributions` | List of available distribution descriptors (type, location, sha256, expiresAt). |
|
| `distributions` | List of available distribution descriptors (type, location, sha256, expiresAt). |
|
||||||
|
|
||||||
### 4.4 Cancel a run
|
### 4.4 Cancel a run
|
||||||
|
|
||||||
```
|
```
|
||||||
POST /api/export/runs/{runId}:cancel
|
POST /api/export/runs/{runId}:cancel
|
||||||
Scopes: export:run
|
Scopes: export:run
|
||||||
```
|
```
|
||||||
|
|
||||||
Body optional (`{"reason": "Aborted due to incident INC-123"}`). Returns 202 and pushes `run.canceled` event.
|
Body optional (`{"reason": "Aborted due to incident INC-123"}`). Returns 202 and pushes `run.canceled` event.
|
||||||
|
|
||||||
## 5. Events and telemetry
|
## 5. Events and telemetry
|
||||||
|
|
||||||
### 5.1 Server-sent events
|
### 5.1 Server-sent events
|
||||||
|
|
||||||
```
|
```
|
||||||
GET /api/export/runs/{runId}/events
|
GET /api/export/runs/{runId}/events
|
||||||
Scopes: export:read
|
Scopes: export:read
|
||||||
Accept: text/event-stream
|
Accept: text/event-stream
|
||||||
```
|
```
|
||||||
|
|
||||||
Event payload example:
|
Event payload example:
|
||||||
|
|
||||||
```
|
```
|
||||||
event: run.progress
|
event: run.progress
|
||||||
data: {"runId":"run-20251029-01","phase":"adapter","adapter":"json","records":1024,"bytes":7340032,"timestamp":"2025-10-29T12:13:15Z"}
|
data: {"runId":"run-20251029-01","phase":"adapter","adapter":"json","records":1024,"bytes":7340032,"timestamp":"2025-10-29T12:13:15Z"}
|
||||||
```
|
```
|
||||||
|
|
||||||
Event types:
|
Event types:
|
||||||
|
|
||||||
| Event | Meaning |
|
| Event | Meaning |
|
||||||
|-------|---------|
|
|-------|---------|
|
||||||
| `run.accepted` | Planner accepted job and queued with Orchestrator. |
|
| `run.accepted` | Planner accepted job and queued with Orchestrator. |
|
||||||
| `run.progress` | Periodic updates with phase, adapter, counts. |
|
| `run.progress` | Periodic updates with phase, adapter, counts. |
|
||||||
| `run.distribution` | Distribution driver finished (includes descriptor). |
|
| `run.distribution` | Distribution driver finished (includes descriptor). |
|
||||||
| `run.signed` | Signing completed successfully. |
|
| `run.signed` | Signing completed successfully. |
|
||||||
| `run.succeeded` | Run marked `success`. |
|
| `run.succeeded` | Run marked `success`. |
|
||||||
| `run.failed` | Run failed; payload includes `errorCode`. |
|
| `run.failed` | Run failed; payload includes `errorCode`. |
|
||||||
| `run.canceled` | Run canceled; includes `canceledBy`. |
|
| `run.canceled` | Run canceled; includes `canceledBy`. |
|
||||||
|
|
||||||
SSE heartbeats (`: ping`) keep long-lived connections alive and should be ignored by clients.
|
SSE heartbeats (`: ping`) keep long-lived connections alive and should be ignored by clients.
|
||||||
|
|
||||||
### 5.2 Audit events
|
### 5.2 Audit events
|
||||||
|
|
||||||
`GET /api/export/runs/{runId}/events?format=audit` returns the same event stream in newline-delimited JSON for offline ingestion.
|
`GET /api/export/runs/{runId}/events?format=audit` returns the same event stream in newline-delimited JSON for offline ingestion.
|
||||||
|
|
||||||
## 6. Download endpoints
|
## 6. Download endpoints
|
||||||
|
|
||||||
### 6.1 Bundle download
|
### 6.1 Bundle download
|
||||||
|
|
||||||
```
|
```
|
||||||
GET /api/export/runs/{runId}/download
|
GET /api/export/runs/{runId}/download
|
||||||
Scopes: export:download
|
Scopes: export:download
|
||||||
```
|
```
|
||||||
|
|
||||||
Streams the primary bundle (tarball, zip, or profile-specific layout). Headers:
|
Streams the primary bundle (tarball, zip, or profile-specific layout). Headers:
|
||||||
|
|
||||||
- `Content-Disposition: attachment; filename="export-run-20251029-01.tar.zst"`
|
- `Content-Disposition: attachment; filename="export-run-20251029-01.tar.zst"`
|
||||||
- `X-Export-Digest: sha256:...`
|
- `X-Export-Digest: sha256:...`
|
||||||
- `X-Export-Size: 73482019`
|
- `X-Export-Size: 73482019`
|
||||||
- `X-Export-Encryption: age` (when mirror encryption enabled)
|
- `X-Export-Encryption: age` (when mirror encryption enabled)
|
||||||
|
|
||||||
Supports HTTP range requests for resume functionality. If no bundle exists yet, responds `409` with `ERR_EXPORT_007`.
|
Supports HTTP range requests for resume functionality. If no bundle exists yet, responds `409` with `ERR_EXPORT_007`.
|
||||||
|
|
||||||
### 6.2 Manifest download
|
### 6.2 Manifest download
|
||||||
|
|
||||||
```
|
```
|
||||||
GET /api/export/runs/{runId}/manifest
|
GET /api/export/runs/{runId}/manifest
|
||||||
Scopes: export:download
|
Scopes: export:download
|
||||||
```
|
```
|
||||||
|
|
||||||
Returns signed `export.json`. To fetch the detached signature, append `?signature=true`.
|
Returns signed `export.json`. To fetch the detached signature, append `?signature=true`.
|
||||||
|
|
||||||
### 6.3 Provenance download
|
### 6.3 Provenance download
|
||||||
|
|
||||||
```
|
```
|
||||||
GET /api/export/runs/{runId}/provenance
|
GET /api/export/runs/{runId}/provenance
|
||||||
Scopes: export:download
|
Scopes: export:download
|
||||||
```
|
```
|
||||||
|
|
||||||
Returns signed `provenance.json`. Supports `?signature=true`. Provenance includes attestation subject digests, policy snapshot ids, adapter versions, and KMS key identifiers.
|
Returns signed `provenance.json`. Supports `?signature=true`. Provenance includes attestation subject digests, policy snapshot ids, adapter versions, and KMS key identifiers.
|
||||||
|
|
||||||
### 6.4 Distribution descriptors
|
### 6.4 Distribution descriptors
|
||||||
|
|
||||||
```
|
```
|
||||||
GET /api/export/runs/{runId}/distributions
|
GET /api/export/runs/{runId}/distributions
|
||||||
Scopes: export:read
|
Scopes: export:read
|
||||||
```
|
```
|
||||||
|
|
||||||
Lists all registered distribution targets (HTTP, OCI, object storage). Each item includes `type`, `location`, `sha256`, `sizeBytes`, and `expiresAt`.
|
Lists all registered distribution targets (HTTP, OCI, object storage). Each item includes `type`, `location`, `sha256`, `sizeBytes`, and `expiresAt`.
|
||||||
|
|
||||||
## 7. Webhook hand-off
|
## 7. Webhook hand-off
|
||||||
|
|
||||||
Exports can notify external systems once a run succeeds by registering an HTTP webhook:
|
Exports can notify external systems once a run succeeds by registering an HTTP webhook:
|
||||||
|
|
||||||
```
|
```
|
||||||
POST /api/export/webhooks
|
POST /api/export/webhooks
|
||||||
Scopes: export:profile:manage
|
Scopes: export:profile:manage
|
||||||
```
|
```
|
||||||
|
|
||||||
Payload includes `targetUrl`, `events` (e.g., `run.succeeded`), and optional secret for HMAC signatures. Webhook deliveries sign payloads with `X-Stella-Signature` header (`sha256=...`). Retries follow exponential backoff with dead-letter capture in `export_events`.
|
Payload includes `targetUrl`, `events` (e.g., `run.succeeded`), and optional secret for HMAC signatures. Webhook deliveries sign payloads with `X-Stella-Signature` header (`sha256=...`). Retries follow exponential backoff with dead-letter capture in `export_events`.
|
||||||
|
|
||||||
## 8. Observability
|
## 8. Observability
|
||||||
|
|
||||||
- **Metrics endpoint:** `/metrics` (service-local) exposes Prometheus metrics listed in [Architecture](architecture.md#observability).
|
- **Metrics endpoint:** `/metrics` (service-local) exposes Prometheus metrics listed in [Architecture](architecture.md#observability).
|
||||||
- **Tracing:** When `traceparent` header is provided, worker spans join the calling trace.
|
- **Tracing:** When `traceparent` header is provided, worker spans join the calling trace.
|
||||||
- **Run lookup by trace:** Use `GET /api/export/runs?traceId={id}` when troubleshooting distributed traces.
|
- **Run lookup by trace:** Use `GET /api/export/runs?traceId={id}` when troubleshooting distributed traces.
|
||||||
|
|
||||||
## 9. Related documentation
|
## 9. Related documentation
|
||||||
|
|
||||||
- [Export Center Overview](overview.md)
|
- [Export Center Overview](overview.md)
|
||||||
- [Export Center Architecture](architecture.md)
|
- [Export Center Architecture](architecture.md)
|
||||||
- [Export Center Profiles](profiles.md)
|
- [Export Center Profiles](profiles.md)
|
||||||
- [Export Center CLI Guide](cli.md) *(companion document)*
|
- [Export Center CLI Guide](cli.md) *(companion document)*
|
||||||
- [Aggregation-Only Contract reference](../ingestion/aggregation-only-contract.md)
|
- [Aggregation-Only Contract reference](../ingestion/aggregation-only-contract.md)
|
||||||
|
|
||||||
> **Imposed rule:** Work of this type or tasks of this type on this component must also be applied everywhere else it should be applied.
|
> **Imposed rule:** Work of this type or tasks of this type on this component must also be applied everywhere else it should be applied.
|
||||||
|
|||||||
@@ -1,125 +1,125 @@
|
|||||||
# Export Center Architecture
|
# Export Center Architecture
|
||||||
|
|
||||||
The Export Center is the dedicated service layer that packages StellaOps evidence and policy overlays into reproducible bundles. It runs as a multi-surface API backed by asynchronous workers and format adapters, enforcing Aggregation-Only Contract (AOC) guardrails while providing deterministic manifests, signing, and distribution paths.
|
The Export Center is the dedicated service layer that packages StellaOps evidence and policy overlays into reproducible bundles. It runs as a multi-surface API backed by asynchronous workers and format adapters, enforcing Aggregation-Only Contract (AOC) guardrails while providing deterministic manifests, signing, and distribution paths.
|
||||||
|
|
||||||
## Runtime topology
|
## Runtime topology
|
||||||
- **Export Center API (`StellaOps.ExportCenter.WebService`).** Receives profile CRUD, export run requests, status queries, and download streams through the unified Web API gateway. Enforces tenant scopes, RBAC, quotas, and concurrency guards.
|
- **Export Center API (`StellaOps.ExportCenter.WebService`).** Receives profile CRUD, export run requests, status queries, and download streams through the unified Web API gateway. Enforces tenant scopes, RBAC, quotas, and concurrency guards.
|
||||||
- **Export Center Worker (`StellaOps.ExportCenter.Worker`).** Dequeues export jobs from the Orchestrator, resolves selectors, invokes adapters, and writes manifests and bundle artefacts. Stateless; scales horizontally.
|
- **Export Center Worker (`StellaOps.ExportCenter.Worker`).** Dequeues export jobs from the Orchestrator, resolves selectors, invokes adapters, and writes manifests and bundle artefacts. Stateless; scales horizontally.
|
||||||
- **Backing stores.**
|
- **Backing stores.**
|
||||||
- MongoDB collections: `export_profiles`, `export_runs`, `export_inputs`, `export_distributions`, `export_events`.
|
- MongoDB collections: `export_profiles`, `export_runs`, `export_inputs`, `export_distributions`, `export_events`.
|
||||||
- Object storage bucket or filesystem for staging bundle payloads.
|
- Object storage bucket or filesystem for staging bundle payloads.
|
||||||
- Optional registry/object storage credentials injected via Authority-scoped secrets.
|
- Optional registry/object storage credentials injected via Authority-scoped secrets.
|
||||||
- **Integration peers.**
|
- **Integration peers.**
|
||||||
- **Findings Ledger** for advisory, VEX, SBOM payload streaming.
|
- **Findings Ledger** for advisory, VEX, SBOM payload streaming.
|
||||||
- **Policy Engine** for deterministic policy snapshots and evaluated findings.
|
- **Policy Engine** for deterministic policy snapshots and evaluated findings.
|
||||||
- **Orchestrator** for job scheduling, quotas, and telemetry fan-out.
|
- **Orchestrator** for job scheduling, quotas, and telemetry fan-out.
|
||||||
- **Authority** for tenant-aware access tokens and KMS key references.
|
- **Authority** for tenant-aware access tokens and KMS key references.
|
||||||
- **Console & CLI** as presentation surfaces consuming the API.
|
- **Console & CLI** as presentation surfaces consuming the API.
|
||||||
|
|
||||||
## Job lifecycle
|
## Job lifecycle
|
||||||
1. **Profile selection.** Operator or automation picks a profile (`json:raw`, `json:policy`, `trivy:db`, `trivy:java-db`, `mirror:full`, `mirror:delta`) and submits scope selectors (tenant, time window, products, SBOM subjects, ecosystems). See `docs/export-center/profiles.md` for profile definitions and configuration fields.
|
1. **Profile selection.** Operator or automation picks a profile (`json:raw`, `json:policy`, `trivy:db`, `trivy:java-db`, `mirror:full`, `mirror:delta`) and submits scope selectors (tenant, time window, products, SBOM subjects, ecosystems). See `docs/export-center/profiles.md` for profile definitions and configuration fields.
|
||||||
2. **Planner resolution.** API validates selectors, expands include/exclude lists, and writes a pending `export_run` with immutable parameters and deterministic ordering hints.
|
2. **Planner resolution.** API validates selectors, expands include/exclude lists, and writes a pending `export_run` with immutable parameters and deterministic ordering hints.
|
||||||
3. **Orchestrator dispatch.** `export_run` triggers a job lease via Orchestrator with quotas per tenant/profile and concurrency caps (default 4 active per tenant).
|
3. **Orchestrator dispatch.** `export_run` triggers a job lease via Orchestrator with quotas per tenant/profile and concurrency caps (default 4 active per tenant).
|
||||||
4. **Worker execution.** Worker streams data from Findings Ledger and Policy Engine using pagination cursors. Adapters write canonical payloads to staging storage, compute checksums, and emit streaming progress events (SSE).
|
4. **Worker execution.** Worker streams data from Findings Ledger and Policy Engine using pagination cursors. Adapters write canonical payloads to staging storage, compute checksums, and emit streaming progress events (SSE).
|
||||||
5. **Manifest and provenance emission.** Worker writes `export.json` and `provenance.json`, signs them with configured KMS keys (cosign-compatible), and uploads signatures alongside content.
|
5. **Manifest and provenance emission.** Worker writes `export.json` and `provenance.json`, signs them with configured KMS keys (cosign-compatible), and uploads signatures alongside content.
|
||||||
6. **Distribution registration.** Worker records available distribution methods (download URL, OCI reference, object storage path), raises completion/failure events, and exposes metrics/logs.
|
6. **Distribution registration.** Worker records available distribution methods (download URL, OCI reference, object storage path), raises completion/failure events, and exposes metrics/logs.
|
||||||
7. **Download & verification.** Clients download bundles or pull OCI artefacts, verify signatures, and consume provenance to trace source artefacts.
|
7. **Download & verification.** Clients download bundles or pull OCI artefacts, verify signatures, and consume provenance to trace source artefacts.
|
||||||
|
|
||||||
Cancellation requests mark runs as `aborted` and cause workers to stop iterating sources; partially written files are destroyed and the run is marked with an audit entry.
|
Cancellation requests mark runs as `aborted` and cause workers to stop iterating sources; partially written files are destroyed and the run is marked with an audit entry.
|
||||||
|
|
||||||
## Core components
|
## Core components
|
||||||
### API surface
|
### API surface
|
||||||
- Detailed request and response payloads are catalogued in `docs/export-center/api.md`.
|
- Detailed request and response payloads are catalogued in `docs/export-center/api.md`.
|
||||||
- **Profiles API.**
|
- **Profiles API.**
|
||||||
- `GET /api/export/profiles`: list tenant-scoped profiles.
|
- `GET /api/export/profiles`: list tenant-scoped profiles.
|
||||||
- `POST /api/export/profiles`: create custom profiles (variants of JSON, Trivy, mirror) with validated configuration schema.
|
- `POST /api/export/profiles`: create custom profiles (variants of JSON, Trivy, mirror) with validated configuration schema.
|
||||||
- `PATCH /api/export/profiles/{id}`: update metadata; config changes clone new revision to preserve determinism.
|
- `PATCH /api/export/profiles/{id}`: update metadata; config changes clone new revision to preserve determinism.
|
||||||
- **Runs API.**
|
- **Runs API.**
|
||||||
- `POST /api/export/runs`: submit export run for a profile with selectors and options (policy snapshot id, mirror base manifest).
|
- `POST /api/export/runs`: submit export run for a profile with selectors and options (policy snapshot id, mirror base manifest).
|
||||||
- `GET /api/export/runs/{id}`: status, progress counters, provenance summary.
|
- `GET /api/export/runs/{id}`: status, progress counters, provenance summary.
|
||||||
- `GET /api/export/runs/{id}/events`: server-sent events with state transitions, adapter milestones, signing status.
|
- `GET /api/export/runs/{id}/events`: server-sent events with state transitions, adapter milestones, signing status.
|
||||||
- `POST /api/export/runs/{id}/cancel`: cooperative cancellation with audit logging.
|
- `POST /api/export/runs/{id}/cancel`: cooperative cancellation with audit logging.
|
||||||
- **Downloads API.**
|
- **Downloads API.**
|
||||||
- `GET /api/export/runs/{id}/download`: streaming download with range support and checksum trailers.
|
- `GET /api/export/runs/{id}/download`: streaming download with range support and checksum trailers.
|
||||||
- `GET /api/export/runs/{id}/manifest`: signed `export.json`.
|
- `GET /api/export/runs/{id}/manifest`: signed `export.json`.
|
||||||
- `GET /api/export/runs/{id}/provenance`: signed `provenance.json`.
|
- `GET /api/export/runs/{id}/provenance`: signed `provenance.json`.
|
||||||
|
|
||||||
All endpoints require Authority-issued JWT + DPoP tokens with scopes `export:run`, `export:read`, and tenant claim alignment. Rate-limiting and quotas surface via `X-Stella-Quota-*` headers.
|
All endpoints require Authority-issued JWT + DPoP tokens with scopes `export:run`, `export:read`, and tenant claim alignment. Rate-limiting and quotas surface via `X-Stella-Quota-*` headers.
|
||||||
|
|
||||||
### Worker pipeline
|
### Worker pipeline
|
||||||
- **Input resolvers.** Query Findings Ledger and Policy Engine using stable pagination (Mongo `_id` ascending, or resume tokens for change streams). Selector expressions compile into Mongo filter fragments and/or API query parameters.
|
- **Input resolvers.** Query Findings Ledger and Policy Engine using stable pagination (Mongo `_id` ascending, or resume tokens for change streams). Selector expressions compile into Mongo filter fragments and/or API query parameters.
|
||||||
- **Adapter host.** Adapter plugin loader (restart-time only) resolves profile variant to adapter implementation. Adapters present a deterministic `RunAsync(context)` contract with streaming writers and telemetry instrumentation.
|
- **Adapter host.** Adapter plugin loader (restart-time only) resolves profile variant to adapter implementation. Adapters present a deterministic `RunAsync(context)` contract with streaming writers and telemetry instrumentation.
|
||||||
- **Content writers.**
|
- **Content writers.**
|
||||||
- JSON adapters emit `.jsonl.zst` files with canonical ordering (tenant, subject, document id).
|
- JSON adapters emit `.jsonl.zst` files with canonical ordering (tenant, subject, document id).
|
||||||
- Trivy adapters materialise SQLite databases or tar archives matching Trivy DB expectations; schema version gates prevent unsupported outputs.
|
- Trivy adapters materialise SQLite databases or tar archives matching Trivy DB expectations; schema version gates prevent unsupported outputs.
|
||||||
- Mirror adapters assemble deterministic filesystem trees (manifests, indexes, payload subtrees) and, when configured, OCI artefact layers.
|
- Mirror adapters assemble deterministic filesystem trees (manifests, indexes, payload subtrees) and, when configured, OCI artefact layers.
|
||||||
- **Manifest generator.** Aggregates counts, bytes, hash digests (SHA-256), profile metadata, and input references. Writes `export.json` and `provenance.json` using canonical JSON (sorted keys, RFC3339 UTC timestamps).
|
- **Manifest generator.** Aggregates counts, bytes, hash digests (SHA-256), profile metadata, and input references. Writes `export.json` and `provenance.json` using canonical JSON (sorted keys, RFC3339 UTC timestamps).
|
||||||
- **Signing service.** Integrates with platform KMS via Authority (default cosign signer). Produces in-toto SLSA attestations when configured. Supports detached signatures and optional in-bundle signatures.
|
- **Signing service.** Integrates with platform KMS via Authority (default cosign signer). Produces in-toto SLSA attestations when configured. Supports detached signatures and optional in-bundle signatures.
|
||||||
- **Distribution drivers.** `dist-http` exposes staged files via download endpoint; `dist-oci` pushes artefacts to registries using ORAS with digest pinning; `dist-objstore` uploads to tenant-specific prefixes with immutability flags.
|
- **Distribution drivers.** `dist-http` exposes staged files via download endpoint; `dist-oci` pushes artefacts to registries using ORAS with digest pinning; `dist-objstore` uploads to tenant-specific prefixes with immutability flags.
|
||||||
|
|
||||||
## Data model snapshots
|
## Data model snapshots
|
||||||
|
|
||||||
| Collection | Purpose | Key fields | Notes |
|
| Collection | Purpose | Key fields | Notes |
|
||||||
|------------|---------|------------|-------|
|
|------------|---------|------------|-------|
|
||||||
| `export_profiles` | Profile definitions (kind, variant, config). | `_id`, `tenant`, `name`, `kind`, `variant`, `config_json`, `created_by`, `created_at`. | Config includes adapter parameters (included record types, compression, encryption). |
|
| `export_profiles` | Profile definitions (kind, variant, config). | `_id`, `tenant`, `name`, `kind`, `variant`, `config_json`, `created_by`, `created_at`. | Config includes adapter parameters (included record types, compression, encryption). |
|
||||||
| `export_runs` | Run state machine and audit info. | `_id`, `profile_id`, `tenant`, `status`, `requested_by`, `selectors`, `policy_snapshot_id`, `started_at`, `completed_at`, `duration_ms`, `error_code`. | Immutable selectors; status transitions recorded in `export_events`. |
|
| `export_runs` | Run state machine and audit info. | `_id`, `profile_id`, `tenant`, `status`, `requested_by`, `selectors`, `policy_snapshot_id`, `started_at`, `completed_at`, `duration_ms`, `error_code`. | Immutable selectors; status transitions recorded in `export_events`. |
|
||||||
| `export_inputs` | Resolved input ranges. | `run_id`, `source`, `cursor`, `count`, `hash`. | Enables resumable retries and audit. |
|
| `export_inputs` | Resolved input ranges. | `run_id`, `source`, `cursor`, `count`, `hash`. | Enables resumable retries and audit. |
|
||||||
| `export_distributions` | Distribution artefacts. | `run_id`, `type` (`http`, `oci`, `object`), `location`, `sha256`, `size_bytes`, `expires_at`. | `expires_at` used for retention policies and automatic pruning. |
|
| `export_distributions` | Distribution artefacts. | `run_id`, `type` (`http`, `oci`, `object`), `location`, `sha256`, `size_bytes`, `expires_at`. | `expires_at` used for retention policies and automatic pruning. |
|
||||||
| `export_events` | Timeline of state transitions and metrics. | `run_id`, `event_type`, `message`, `at`, `metrics`. | Feeds SSE stream and audit trails. |
|
| `export_events` | Timeline of state transitions and metrics. | `run_id`, `event_type`, `message`, `at`, `metrics`. | Feeds SSE stream and audit trails. |
|
||||||
|
|
||||||
## Adapter responsibilities
|
## Adapter responsibilities
|
||||||
- **JSON (`json:raw`, `json:policy`).**
|
- **JSON (`json:raw`, `json:policy`).**
|
||||||
- Ensures canonical casing, timezone normalization, and linkset preservation.
|
- Ensures canonical casing, timezone normalization, and linkset preservation.
|
||||||
- Policy variant embeds policy snapshot metadata (`policy_version`, `inputs_hash`, `decision_trace` fingerprint) and emits evaluated findings as separate files.
|
- Policy variant embeds policy snapshot metadata (`policy_version`, `inputs_hash`, `decision_trace` fingerprint) and emits evaluated findings as separate files.
|
||||||
- Enforces AOC guardrails: no derived modifications to raw evidence fields.
|
- Enforces AOC guardrails: no derived modifications to raw evidence fields.
|
||||||
- **Trivy (`trivy:db`, `trivy:java-db`).**
|
- **Trivy (`trivy:db`, `trivy:java-db`).**
|
||||||
- Maps StellaOps advisory schema to Trivy DB format, handling namespace collisions and ecosystem-specific ranges.
|
- Maps StellaOps advisory schema to Trivy DB format, handling namespace collisions and ecosystem-specific ranges.
|
||||||
- Validates compatibility against supported Trivy schema versions; run fails fast if mismatch.
|
- Validates compatibility against supported Trivy schema versions; run fails fast if mismatch.
|
||||||
- Emits optional manifest summarising package counts and severity distribution.
|
- Emits optional manifest summarising package counts and severity distribution.
|
||||||
- **Mirror (`mirror:full`, `mirror:delta`).**
|
- **Mirror (`mirror:full`, `mirror:delta`).**
|
||||||
- Builds self-contained filesystem layout (`/manifests`, `/data/raw`, `/data/policy`, `/indexes`).
|
- Builds self-contained filesystem layout (`/manifests`, `/data/raw`, `/data/policy`, `/indexes`).
|
||||||
- Delta variant compares against base manifest (`base_export_id`) to write only changed artefacts; records `removed` entries for cleanup.
|
- Delta variant compares against base manifest (`base_export_id`) to write only changed artefacts; records `removed` entries for cleanup.
|
||||||
- Supports optional encryption of `/data` subtree (age/AES-GCM) with key wrapping stored in `provenance.json`.
|
- Supports optional encryption of `/data` subtree (age/AES-GCM) with key wrapping stored in `provenance.json`.
|
||||||
|
|
||||||
Adapters expose structured telemetry events (`adapter.start`, `adapter.chunk`, `adapter.complete`) with record counts and byte totals per chunk. Failures emit `adapter.error` with reason codes.
|
Adapters expose structured telemetry events (`adapter.start`, `adapter.chunk`, `adapter.complete`) with record counts and byte totals per chunk. Failures emit `adapter.error` with reason codes.
|
||||||
|
|
||||||
## Signing and provenance
|
## Signing and provenance
|
||||||
- **Manifest schema.** `export.json` contains run metadata, profile descriptor, selector summary, counts, SHA-256 digests, compression hints, and distribution list. Deterministic field ordering and normalized timestamps.
|
- **Manifest schema.** `export.json` contains run metadata, profile descriptor, selector summary, counts, SHA-256 digests, compression hints, and distribution list. Deterministic field ordering and normalized timestamps.
|
||||||
- **Provenance schema.** `provenance.json` captures in-toto subject listing (bundle digest, manifest digest), referenced inputs (findings ledger queries, policy snapshot ids, SBOM identifiers), tool version (`exporter_version`, adapter versions), and KMS key identifiers.
|
- **Provenance schema.** `provenance.json` captures in-toto subject listing (bundle digest, manifest digest), referenced inputs (findings ledger queries, policy snapshot ids, SBOM identifiers), tool version (`exporter_version`, adapter versions), and KMS key identifiers.
|
||||||
- **Attestation.** Cosign SLSA Level 2 template by default; optional SLSA Level 3 when supply chain attestations are enabled. Detached signatures stored alongside manifests; CLI/Console encourage `cosign verify --key <tenant-key>` workflow.
|
- **Attestation.** Cosign SLSA Level 2 template by default; optional SLSA Level 3 when supply chain attestations are enabled. Detached signatures stored alongside manifests; CLI/Console encourage `cosign verify --key <tenant-key>` workflow.
|
||||||
- **Audit trail.** Each run stores success/failure status, signature identifiers, and verification hints for downstream automation (CI pipelines, offline verification scripts).
|
- **Audit trail.** Each run stores success/failure status, signature identifiers, and verification hints for downstream automation (CI pipelines, offline verification scripts).
|
||||||
|
|
||||||
## Distribution flows
|
## Distribution flows
|
||||||
- **HTTP download.** Console and CLI stream bundles via chunked transfer; supports range requests and resumable downloads. Response includes `X-Export-Digest`, `X-Export-Length`, and optional encryption metadata.
|
- **HTTP download.** Console and CLI stream bundles via chunked transfer; supports range requests and resumable downloads. Response includes `X-Export-Digest`, `X-Export-Length`, and optional encryption metadata.
|
||||||
- **OCI push.** Worker uses ORAS to publish bundles as OCI artefacts with annotations describing profile, tenant, manifest digest, and provenance reference. Supports multi-tenant registries with `repository-per-tenant` naming.
|
- **OCI push.** Worker uses ORAS to publish bundles as OCI artefacts with annotations describing profile, tenant, manifest digest, and provenance reference. Supports multi-tenant registries with `repository-per-tenant` naming.
|
||||||
- **Object storage.** Writes to tenant-prefixed paths (`s3://stella-exports/{tenant}/{run-id}/...`) with immutable retention policies. Retention scheduler purges expired runs based on profile configuration.
|
- **Object storage.** Writes to tenant-prefixed paths (`s3://stella-exports/{tenant}/{run-id}/...`) with immutable retention policies. Retention scheduler purges expired runs based on profile configuration.
|
||||||
- **Offline Kit seeding.** Mirror bundles optionally staged into Offline Kit assembly pipelines, inheriting the same manifests and signatures.
|
- **Offline Kit seeding.** Mirror bundles optionally staged into Offline Kit assembly pipelines, inheriting the same manifests and signatures.
|
||||||
|
|
||||||
## Observability
|
## Observability
|
||||||
- **Metrics.** Emits `exporter_run_duration_seconds`, `exporter_run_bytes_total{profile}`, `exporter_run_failures_total{error_code}`, `exporter_active_runs{tenant}`, `exporter_distribution_push_seconds{type}`.
|
- **Metrics.** Emits `exporter_run_duration_seconds`, `exporter_run_bytes_total{profile}`, `exporter_run_failures_total{error_code}`, `exporter_active_runs{tenant}`, `exporter_distribution_push_seconds{type}`.
|
||||||
- **Logs.** Structured logs with fields `run_id`, `tenant`, `profile_kind`, `adapter`, `phase`, `correlation_id`, `error_code`. Phases include `plan`, `resolve`, `adapter`, `manifest`, `sign`, `distribute`.
|
- **Logs.** Structured logs with fields `run_id`, `tenant`, `profile_kind`, `adapter`, `phase`, `correlation_id`, `error_code`. Phases include `plan`, `resolve`, `adapter`, `manifest`, `sign`, `distribute`.
|
||||||
- **Traces.** Optional OpenTelemetry spans (`export.plan`, `export.fetch`, `export.write`, `export.sign`, `export.distribute`) for cross-service correlation.
|
- **Traces.** Optional OpenTelemetry spans (`export.plan`, `export.fetch`, `export.write`, `export.sign`, `export.distribute`) for cross-service correlation.
|
||||||
- **Dashboards & alerts.** DevOps pipeline seeds Grafana dashboards summarising throughput, size, failure ratios, and distribution latency. Alert thresholds: failure rate >5% per profile, median run duration >p95 baseline, signature verification failures >0.
|
- **Dashboards & alerts.** DevOps pipeline seeds Grafana dashboards summarising throughput, size, failure ratios, and distribution latency. Alert thresholds: failure rate >5% per profile, median run duration >p95 baseline, signature verification failures >0.
|
||||||
|
|
||||||
## Security posture
|
## Security posture
|
||||||
- Tenant claim enforced at every query and distribution path; cross-tenant selectors rejected unless explicit cross-tenant mirror feature toggled with signed approval.
|
- Tenant claim enforced at every query and distribution path; cross-tenant selectors rejected unless explicit cross-tenant mirror feature toggled with signed approval.
|
||||||
- RBAC scopes: `export:profile:manage`, `export:run`, `export:read`, `export:download`. Console hides actions without scope; CLI returns `401/403`.
|
- RBAC scopes: `export:profile:manage`, `export:run`, `export:read`, `export:download`. Console hides actions without scope; CLI returns `401/403`.
|
||||||
- Encryption options configurable per profile; keys derived from Authority-managed KMS. Mirror encryption uses tenant-specific recipients; JSON/Trivy rely on transport security plus optional encryption at rest.
|
- Encryption options configurable per profile; keys derived from Authority-managed KMS. Mirror encryption uses tenant-specific recipients; JSON/Trivy rely on transport security plus optional encryption at rest.
|
||||||
- Restart-only plugin loading ensures adapters and distribution drivers are vetted at deployment time, reducing runtime injection risks.
|
- Restart-only plugin loading ensures adapters and distribution drivers are vetted at deployment time, reducing runtime injection risks.
|
||||||
- Deterministic output ensures tamper detection via content hashes; provenance links to source runs and policy snapshots to maintain auditability.
|
- Deterministic output ensures tamper detection via content hashes; provenance links to source runs and policy snapshots to maintain auditability.
|
||||||
|
|
||||||
## Deployment considerations
|
## Deployment considerations
|
||||||
- Packaged as separate API and worker containers. Helm chart and compose overlays define horizontal scaling, worker concurrency, queue leases, and object storage credentials.
|
- Packaged as separate API and worker containers. Helm chart and compose overlays define horizontal scaling, worker concurrency, queue leases, and object storage credentials.
|
||||||
- Requires Authority client credentials for KMS and optional registry credentials stored via sealed secrets.
|
- Requires Authority client credentials for KMS and optional registry credentials stored via sealed secrets.
|
||||||
- Offline-first deployments disable OCI distribution by default and provide local object storage endpoints; HTTP downloads served via internal gateway.
|
- Offline-first deployments disable OCI distribution by default and provide local object storage endpoints; HTTP downloads served via internal gateway.
|
||||||
- Health endpoints: `/health/ready` validates Mongo connectivity, object storage access, adapter registry integrity, and KMS signer readiness.
|
- Health endpoints: `/health/ready` validates Mongo connectivity, object storage access, adapter registry integrity, and KMS signer readiness.
|
||||||
|
|
||||||
## Compliance checklist
|
## Compliance checklist
|
||||||
- [ ] Profiles and runs enforce tenant scoping; cross-tenant exports disabled unless approved.
|
- [ ] Profiles and runs enforce tenant scoping; cross-tenant exports disabled unless approved.
|
||||||
- [ ] Manifests and provenance files are generated with deterministic hashes and signed via configured KMS.
|
- [ ] Manifests and provenance files are generated with deterministic hashes and signed via configured KMS.
|
||||||
- [ ] Adapters run with restart-time registration only; no runtime plugin loading.
|
- [ ] Adapters run with restart-time registration only; no runtime plugin loading.
|
||||||
- [ ] Distribution drivers respect allowlist; OCI push disabled when offline mode is active.
|
- [ ] Distribution drivers respect allowlist; OCI push disabled when offline mode is active.
|
||||||
- [ ] Metrics, logs, and traces follow observability guidelines; dashboards and alerts configured.
|
- [ ] Metrics, logs, and traces follow observability guidelines; dashboards and alerts configured.
|
||||||
- [ ] Retention policies and pruning jobs configured for staged bundles.
|
- [ ] Retention policies and pruning jobs configured for staged bundles.
|
||||||
|
|
||||||
> **Imposed rule:** Work of this type or tasks of this type on this component must also be applied everywhere else it should be applied.
|
> **Imposed rule:** Work of this type or tasks of this type on this component must also be applied everywhere else it should be applied.
|
||||||
|
|||||||
@@ -1,231 +1,231 @@
|
|||||||
# Stella CLI - Export Center Commands
|
# Stella CLI - Export Center Commands
|
||||||
|
|
||||||
> **Audience:** Operators, release engineers, and CI maintainers using the `stella` CLI to manage Export Center profiles and runs.
|
> **Audience:** Operators, release engineers, and CI maintainers using the `stella` CLI to manage Export Center profiles and runs.
|
||||||
> **Supported from:** `stella` CLI >= 0.22.0 (Export Center Phase 1).
|
> **Supported from:** `stella` CLI >= 0.22.0 (Export Center Phase 1).
|
||||||
> **Prerequisites:** Authority token with the scopes noted per command (`export:profile:manage`, `export:run`, `export:read`, `export:download`).
|
> **Prerequisites:** Authority token with the scopes noted per command (`export:profile:manage`, `export:run`, `export:read`, `export:download`).
|
||||||
|
|
||||||
Use this guide with the [Export Center API reference](api.md) and [Profiles](profiles.md) catalogue. The CLI wraps the same REST endpoints, preserving deterministic behaviour and guardrails.
|
Use this guide with the [Export Center API reference](api.md) and [Profiles](profiles.md) catalogue. The CLI wraps the same REST endpoints, preserving deterministic behaviour and guardrails.
|
||||||
|
|
||||||
> Status: CLI support is tracked under `CLI-EXPORT-35-001` and `CLI-EXPORT-36-001`. The current CLI build does not yet surface these commands; treat this guide as the target contract and adjust once implementations merge.
|
> Status: CLI support is tracked under `CLI-EXPORT-35-001` and `CLI-EXPORT-36-001`. The current CLI build does not yet surface these commands; treat this guide as the target contract and adjust once implementations merge.
|
||||||
|
|
||||||
## 1. Global options and configuration
|
## 1. Global options and configuration
|
||||||
|
|
||||||
| Flag | Default | Description |
|
| Flag | Default | Description |
|
||||||
|------|---------|-------------|
|
|------|---------|-------------|
|
||||||
| `--server <url>` | `https://stella.local` | Gateway root. Matches `STELLA_SERVER`. |
|
| `--server <url>` | `https://stella.local` | Gateway root. Matches `STELLA_SERVER`. |
|
||||||
| `--tenant <id>` | Token tenant | Override tenant for multi-tenant tokens. |
|
| `--tenant <id>` | Token tenant | Override tenant for multi-tenant tokens. |
|
||||||
| `--profile <name>` | none | Loads saved defaults from `~/.stella/profiles/<name>.toml`. |
|
| `--profile <name>` | none | Loads saved defaults from `~/.stella/profiles/<name>.toml`. |
|
||||||
| `--output <file>` | stdout | Redirect full JSON response. |
|
| `--output <file>` | stdout | Redirect full JSON response. |
|
||||||
| `--format <table|json|yaml>` | `table` on TTY | Controls table formatting for list commands. |
|
| `--format <table|json|yaml>` | `table` on TTY | Controls table formatting for list commands. |
|
||||||
| `--trace` | false | Emit request timing and correlation ids. |
|
| `--trace` | false | Emit request timing and correlation ids. |
|
||||||
|
|
||||||
Environment variables: `STELLA_TOKEN`, `STELLA_SERVER`, `STELLA_TENANT`, `STELLA_PROFILE`.
|
Environment variables: `STELLA_TOKEN`, `STELLA_SERVER`, `STELLA_TENANT`, `STELLA_PROFILE`.
|
||||||
|
|
||||||
Exit codes align with API error codes (see section 6).
|
Exit codes align with API error codes (see section 6).
|
||||||
|
|
||||||
## 2. Profile management commands
|
## 2. Profile management commands
|
||||||
|
|
||||||
### 2.1 `stella export profile list`
|
### 2.1 `stella export profile list`
|
||||||
|
|
||||||
List profiles for the current tenant.
|
List profiles for the current tenant.
|
||||||
|
|
||||||
```
|
```
|
||||||
stella export profile list --kind json --variant raw --format table
|
stella export profile list --kind json --variant raw --format table
|
||||||
```
|
```
|
||||||
|
|
||||||
Outputs columns `PROFILE`, `KIND`, `VARIANT`, `DISTRIBUTION`, `RETENTION`. Use `--format json` for automation.
|
Outputs columns `PROFILE`, `KIND`, `VARIANT`, `DISTRIBUTION`, `RETENTION`. Use `--format json` for automation.
|
||||||
|
|
||||||
### 2.2 `stella export profile show`
|
### 2.2 `stella export profile show`
|
||||||
|
|
||||||
```
|
```
|
||||||
stella export profile show prof-json-raw --output profile.json
|
stella export profile show prof-json-raw --output profile.json
|
||||||
```
|
```
|
||||||
|
|
||||||
Fetches full configuration and writes it to file.
|
Fetches full configuration and writes it to file.
|
||||||
|
|
||||||
### 2.3 `stella export profile create`
|
### 2.3 `stella export profile create`
|
||||||
|
|
||||||
```
|
```
|
||||||
stella export profile create --file profiles/prof-json-raw.json
|
stella export profile create --file profiles/prof-json-raw.json
|
||||||
```
|
```
|
||||||
|
|
||||||
JSON schema matches `POST /api/export/profiles`. CLI validates against built-in schema before submission. Requires `export:profile:manage`.
|
JSON schema matches `POST /api/export/profiles`. CLI validates against built-in schema before submission. Requires `export:profile:manage`.
|
||||||
|
|
||||||
### 2.4 `stella export profile update`
|
### 2.4 `stella export profile update`
|
||||||
|
|
||||||
```
|
```
|
||||||
stella export profile update prof-json-raw \
|
stella export profile update prof-json-raw \
|
||||||
--retention "days:21" \
|
--retention "days:21" \
|
||||||
--distribution http,object
|
--distribution http,object
|
||||||
```
|
```
|
||||||
|
|
||||||
Supports toggling retention, adding/removing distribution targets, and renaming. Structural changes (kind, variant, include set) require editing the JSON and using `--replace-file` to create a new revision.
|
Supports toggling retention, adding/removing distribution targets, and renaming. Structural changes (kind, variant, include set) require editing the JSON and using `--replace-file` to create a new revision.
|
||||||
|
|
||||||
### 2.5 `stella export profile archive`
|
### 2.5 `stella export profile archive`
|
||||||
|
|
||||||
```
|
```
|
||||||
stella export profile archive prof-json-raw --reason "Superseded by Phase 2 profile"
|
stella export profile archive prof-json-raw --reason "Superseded by Phase 2 profile"
|
||||||
```
|
```
|
||||||
|
|
||||||
Marks the profile inactive. Use `stella export profile restore` to re-activate.
|
Marks the profile inactive. Use `stella export profile restore` to re-activate.
|
||||||
|
|
||||||
## 3. Run lifecycle commands
|
## 3. Run lifecycle commands
|
||||||
|
|
||||||
### 3.1 `stella export run submit`
|
### 3.1 `stella export run submit`
|
||||||
|
|
||||||
```
|
```
|
||||||
stella export run submit prof-json-raw \
|
stella export run submit prof-json-raw \
|
||||||
--selector tenant=acme \
|
--selector tenant=acme \
|
||||||
--selector product=registry.example.com/app:* \
|
--selector product=registry.example.com/app:* \
|
||||||
--selector time=2025-10-01T00:00:00Z,2025-10-29T00:00:00Z \
|
--selector time=2025-10-01T00:00:00Z,2025-10-29T00:00:00Z \
|
||||||
--policy-snapshot policy-snap-42 \
|
--policy-snapshot policy-snap-42 \
|
||||||
--allow-empty=false
|
--allow-empty=false
|
||||||
```
|
```
|
||||||
|
|
||||||
Selectors accept `key=value` pairs; use `time=<from>,<to>` for windows. The command prints the `runId` and initial status.
|
Selectors accept `key=value` pairs; use `time=<from>,<to>` for windows. The command prints the `runId` and initial status.
|
||||||
|
|
||||||
### 3.2 `stella export run ls`
|
### 3.2 `stella export run ls`
|
||||||
|
|
||||||
```
|
```
|
||||||
stella export run ls --profile prof-json-raw --status active --tail 5
|
stella export run ls --profile prof-json-raw --status active --tail 5
|
||||||
```
|
```
|
||||||
|
|
||||||
Shows recent runs with columns `RUN`, `PROFILE`, `STATUS`, `PROGRESS`, `UPDATED`.
|
Shows recent runs with columns `RUN`, `PROFILE`, `STATUS`, `PROGRESS`, `UPDATED`.
|
||||||
|
|
||||||
### 3.3 `stella export run show`
|
### 3.3 `stella export run show`
|
||||||
|
|
||||||
```
|
```
|
||||||
stella export run show run-20251029-01 --format json
|
stella export run show run-20251029-01 --format json
|
||||||
```
|
```
|
||||||
|
|
||||||
Outputs full metadata, progress counters, distribution descriptors, and links.
|
Outputs full metadata, progress counters, distribution descriptors, and links.
|
||||||
|
|
||||||
### 3.4 `stella export run watch`
|
### 3.4 `stella export run watch`
|
||||||
|
|
||||||
```
|
```
|
||||||
stella export run watch run-20251029-01 --follow
|
stella export run watch run-20251029-01 --follow
|
||||||
```
|
```
|
||||||
|
|
||||||
Streams server-sent events and renders a live progress bar. `--json` prints raw events for scripting.
|
Streams server-sent events and renders a live progress bar. `--json` prints raw events for scripting.
|
||||||
|
|
||||||
### 3.5 `stella export run cancel`
|
### 3.5 `stella export run cancel`
|
||||||
|
|
||||||
```
|
```
|
||||||
stella export run cancel run-20251029-01 --reason "Replacing with refined selectors"
|
stella export run cancel run-20251029-01 --reason "Replacing with refined selectors"
|
||||||
```
|
```
|
||||||
|
|
||||||
Gracefully cancels the run; exit code `0` indicates cancellation request accepted.
|
Gracefully cancels the run; exit code `0` indicates cancellation request accepted.
|
||||||
|
|
||||||
## 4. Download and verification commands
|
## 4. Download and verification commands
|
||||||
|
|
||||||
### 4.1 `stella export download`
|
### 4.1 `stella export download`
|
||||||
|
|
||||||
```
|
```
|
||||||
stella export download run-20251029-01 \
|
stella export download run-20251029-01 \
|
||||||
--output out/exports/run-20251029-01.tar.zst \
|
--output out/exports/run-20251029-01.tar.zst \
|
||||||
--resume
|
--resume
|
||||||
```
|
```
|
||||||
|
|
||||||
Downloads the primary bundle. `--resume` enables HTTP range requests; the CLI checkpoints progress to `.part` files.
|
Downloads the primary bundle. `--resume` enables HTTP range requests; the CLI checkpoints progress to `.part` files.
|
||||||
|
|
||||||
### 4.2 `stella export manifest`
|
### 4.2 `stella export manifest`
|
||||||
|
|
||||||
```
|
```
|
||||||
stella export manifest run-20251029-01 --output manifests/export.json
|
stella export manifest run-20251029-01 --output manifests/export.json
|
||||||
```
|
```
|
||||||
|
|
||||||
Fetches the signed manifest. Use `--signature manifests/export.json.sig` to save the detached signature.
|
Fetches the signed manifest. Use `--signature manifests/export.json.sig` to save the detached signature.
|
||||||
|
|
||||||
### 4.3 `stella export provenance`
|
### 4.3 `stella export provenance`
|
||||||
|
|
||||||
```
|
```
|
||||||
stella export provenance run-20251029-01 --output manifests/provenance.json
|
stella export provenance run-20251029-01 --output manifests/provenance.json
|
||||||
```
|
```
|
||||||
|
|
||||||
Retrieves the signed provenance file. `--signature` behaves like the manifest command.
|
Retrieves the signed provenance file. `--signature` behaves like the manifest command.
|
||||||
|
|
||||||
### 4.4 `stella export verify`
|
### 4.4 `stella export verify`
|
||||||
|
|
||||||
```
|
```
|
||||||
stella export verify run-20251029-01 \
|
stella export verify run-20251029-01 \
|
||||||
--manifest manifests/export.json \
|
--manifest manifests/export.json \
|
||||||
--provenance manifests/provenance.json \
|
--provenance manifests/provenance.json \
|
||||||
--key keys/acme-export.pub
|
--key keys/acme-export.pub
|
||||||
```
|
```
|
||||||
|
|
||||||
Wrapper around `cosign verify`. Returns exit `0` when signatures and digests validate. Exit `20` when verification fails.
|
Wrapper around `cosign verify`. Returns exit `0` when signatures and digests validate. Exit `20` when verification fails.
|
||||||
|
|
||||||
## 5. CI recipe (GitHub Actions example)
|
## 5. CI recipe (GitHub Actions example)
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
name: Export Center Bundle
|
name: Export Center Bundle
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
jobs:
|
jobs:
|
||||||
export:
|
export:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Install Stella CLI
|
- name: Install Stella CLI
|
||||||
run: curl -sSfL https://downloads.stellaops.org/cli/install.sh | sh
|
run: curl -sSfL https://downloads.stellaops.org/cli/install.sh | sh
|
||||||
- name: Submit export run
|
- name: Submit export run
|
||||||
env:
|
env:
|
||||||
STELLA_TOKEN: ${{ secrets.STELLA_TOKEN }}
|
STELLA_TOKEN: ${{ secrets.STELLA_TOKEN }}
|
||||||
run: |
|
run: |
|
||||||
run_id=$(stella export run submit prof-json-raw \
|
run_id=$(stella export run submit prof-json-raw \
|
||||||
--selector tenant=acme \
|
--selector tenant=acme \
|
||||||
--selector product=registry.example.com/app:* \
|
--selector product=registry.example.com/app:* \
|
||||||
--allow-empty=false \
|
--allow-empty=false \
|
||||||
--format json | jq -r '.runId')
|
--format json | jq -r '.runId')
|
||||||
echo "RUN_ID=$run_id" >> $GITHUB_ENV
|
echo "RUN_ID=$run_id" >> $GITHUB_ENV
|
||||||
- name: Wait for completion
|
- name: Wait for completion
|
||||||
env:
|
env:
|
||||||
STELLA_TOKEN: ${{ secrets.STELLA_TOKEN }}
|
STELLA_TOKEN: ${{ secrets.STELLA_TOKEN }}
|
||||||
run: |
|
run: |
|
||||||
stella export run watch "$RUN_ID" --json \
|
stella export run watch "$RUN_ID" --json \
|
||||||
| tee artifacts/run.log \
|
| tee artifacts/run.log \
|
||||||
| jq -e 'select(.event == "run.succeeded")' > /dev/null
|
| jq -e 'select(.event == "run.succeeded")' > /dev/null
|
||||||
- name: Download bundle
|
- name: Download bundle
|
||||||
env:
|
env:
|
||||||
STELLA_TOKEN: ${{ secrets.STELLA_TOKEN }}
|
STELLA_TOKEN: ${{ secrets.STELLA_TOKEN }}
|
||||||
run: |
|
run: |
|
||||||
stella export download "$RUN_ID" --output artifacts/export.tar.zst --resume
|
stella export download "$RUN_ID" --output artifacts/export.tar.zst --resume
|
||||||
stella export manifest "$RUN_ID" --output artifacts/export.json --signature artifacts/export.json.sig
|
stella export manifest "$RUN_ID" --output artifacts/export.json --signature artifacts/export.json.sig
|
||||||
stella export provenance "$RUN_ID" --output artifacts/provenance.json --signature artifacts/provenance.json.sig
|
stella export provenance "$RUN_ID" --output artifacts/provenance.json --signature artifacts/provenance.json.sig
|
||||||
- name: Verify signatures
|
- name: Verify signatures
|
||||||
run: |
|
run: |
|
||||||
stella export verify "$RUN_ID" \
|
stella export verify "$RUN_ID" \
|
||||||
--manifest artifacts/export.json \
|
--manifest artifacts/export.json \
|
||||||
--provenance artifacts/provenance.json \
|
--provenance artifacts/provenance.json \
|
||||||
--key keys/acme-export.pub
|
--key keys/acme-export.pub
|
||||||
```
|
```
|
||||||
|
|
||||||
## 6. Exit codes
|
## 6. Exit codes
|
||||||
|
|
||||||
| Code | Meaning |
|
| Code | Meaning |
|
||||||
|------|---------|
|
|------|---------|
|
||||||
| `0` | Command succeeded. |
|
| `0` | Command succeeded. |
|
||||||
| `10` | Validation error (`ERR_EXPORT_001`). |
|
| `10` | Validation error (`ERR_EXPORT_001`). |
|
||||||
| `11` | Profile missing or inaccessible (`ERR_EXPORT_002`). |
|
| `11` | Profile missing or inaccessible (`ERR_EXPORT_002`). |
|
||||||
| `12` | Quota or concurrency exceeded (`ERR_EXPORT_003` or `ERR_EXPORT_QUOTA`). |
|
| `12` | Quota or concurrency exceeded (`ERR_EXPORT_003` or `ERR_EXPORT_QUOTA`). |
|
||||||
| `13` | Run failed due to adapter/signing/distribution error. |
|
| `13` | Run failed due to adapter/signing/distribution error. |
|
||||||
| `20` | Verification failure (`stella export verify`). |
|
| `20` | Verification failure (`stella export verify`). |
|
||||||
| `21` | Download incomplete after retries (network errors). |
|
| `21` | Download incomplete after retries (network errors). |
|
||||||
| `30` | CLI configuration error (missing token, invalid profile file). |
|
| `30` | CLI configuration error (missing token, invalid profile file). |
|
||||||
|
|
||||||
Exit codes above 100 are reserved for future profile-specific tooling.
|
Exit codes above 100 are reserved for future profile-specific tooling.
|
||||||
|
|
||||||
## 7. Offline usage notes
|
## 7. Offline usage notes
|
||||||
|
|
||||||
- Use profiles that enable `object` distribution with local object storage endpoints. CLI reads `STELLA_EXPORT_OBJECT_ENDPOINT` when provided (falls back to gateway).
|
- Use profiles that enable `object` distribution with local object storage endpoints. CLI reads `STELLA_EXPORT_OBJECT_ENDPOINT` when provided (falls back to gateway).
|
||||||
- Mirror bundles work offline by skipping OCI distribution. CLI adds `--offline` to bypass OCI checks.
|
- Mirror bundles work offline by skipping OCI distribution. CLI adds `--offline` to bypass OCI checks.
|
||||||
- `stella export verify` works fully offline when provided with tenant public keys (packaged in Offline Kit).
|
- `stella export verify` works fully offline when provided with tenant public keys (packaged in Offline Kit).
|
||||||
|
|
||||||
## 8. Related documentation
|
## 8. Related documentation
|
||||||
|
|
||||||
- [Export Center Profiles](profiles.md)
|
- [Export Center Profiles](profiles.md)
|
||||||
- [Export Center API reference](api.md)
|
- [Export Center API reference](api.md)
|
||||||
- [Export Center Architecture](architecture.md)
|
- [Export Center Architecture](architecture.md)
|
||||||
- [Aggregation-Only Contract reference](../ingestion/aggregation-only-contract.md)
|
- [Aggregation-Only Contract reference](../ingestion/aggregation-only-contract.md)
|
||||||
|
|
||||||
> **Imposed rule:** Work of this type or tasks of this type on this component must also be applied everywhere else it should be applied.
|
> **Imposed rule:** Work of this type or tasks of this type on this component must also be applied everywhere else it should be applied.
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user