audit, advisories and doctors/setup work

This commit is contained in:
master
2026-01-13 18:53:39 +02:00
parent 9ca7cb183e
commit d7be6ba34b
811 changed files with 54242 additions and 4056 deletions

View File

@@ -0,0 +1,7 @@
# High Level Architecture (Legacy Index)
This file preserves the legacy numbering reference. The canonical high-level architecture lives in `docs/ARCHITECTURE_OVERVIEW.md`.
Related controlled conversational interface docs:
- `docs-archived/product/advisories/13-Jan-2026 - Controlled Conversational Interface.md`
- `docs/modules/advisory-ai/chat-interface.md`

View File

@@ -65,3 +65,106 @@ For the detailed contract, see `docs/api/overview.md`. The stable rules to keep
- Determinism: stable ordering, stable ids, UTC ISO-8601 timestamps, and canonical hashing where applicable.
- Streaming: some endpoints use NDJSON (`application/x-ndjson`) for deterministic, resumable tile/record streams.
- Offline-first: workflows must remain runnable in air-gapped mode using Offline Kit bundles and locally verifiable signatures.
## stella scan diff
Compare ELF binaries between two container images using section hashes.
### Synopsis
```bash
stella scan diff --base <image-ref> --target <image-ref> [options]
```
### Options
| Option | Description |
| --- | --- |
| `--base`, `-b` | Base image reference (tag or digest). |
| `--target`, `-t` | Target image reference (tag or digest). |
| `--mode`, `-m` | Analysis mode: `elf`, `pe`, `auto` (default: `auto`, currently uses ELF). |
| `--emit-dsse`, `-d` | Directory for DSSE attestation output. |
| `--signing-key` | Path to ECDSA private key (PEM) for DSSE signing. |
| `--format`, `-f` | Output format: `table`, `json`, `summary` (default: `table`). |
| `--platform`, `-p` | Platform filter (e.g., `linux/amd64`). |
| `--include-unchanged` | Include unchanged binaries in output. |
| `--sections` | Sections to analyze (comma-separated or repeatable). |
| `--registry-auth` | Path to Docker config for registry authentication. |
| `--timeout` | Timeout in seconds (default: 300). |
| `--verbose`, `-v` | Enable verbose output. |
Note: `--emit-dsse` requires `--signing-key` to sign the DSSE envelope.
### Examples
```bash
# Basic comparison
stella scan diff --base myapp:1.0.0 --target myapp:1.0.1
# DSSE output with signing key
stella scan diff --base myapp:1.0.0 --target myapp:1.0.1 \
--mode=elf --emit-dsse=./attestations --signing-key=./keys/binarydiff.pem
# JSON output for automation
stella scan diff --base myapp:1.0.0 --target myapp:1.0.1 --format=json > diff.json
# Specific platform
stella scan diff --base myapp:1.0.0 --target myapp:1.0.1 --platform=linux/amd64
```
### Output
DSSE output produces two files per platform:
```
attestations/
linux-amd64-binarydiff.dsse.json
linux-amd64-binarydiff.payload.json
```
See also: `docs/modules/scanner/binary-diff-attestation.md`.
## stella image inspect
Inspect OCI image manifests and layers.
### Synopsis
```bash
stella image inspect <reference> [options]
```
### Options
| Option | Description |
| --- | --- |
| `--resolve-index`, `-r` | Resolve multi-arch index to platform manifests (default: true). |
| `--print-layers`, `-l` | Include layer details in output (default: true). |
| `--platform`, `-p` | Platform filter (e.g., `linux/amd64`). |
| `--output`, `-o` | Output format: `table`, `json` (default: `table`). |
| `--timeout` | Timeout in seconds (default: 60). |
| `--verbose`, `-v` | Enable verbose output. |
### Examples
```bash
# Basic inspection
stella image inspect nginx:latest
# JSON output
stella image inspect nginx:latest --output json
# Filter to a single platform
stella image inspect nginx:latest --platform linux/amd64
# Local registry over HTTP
stella image inspect http://localhost:5000/myapp:1.0.0
```
### Exit codes
| Code | Meaning |
| --- | --- |
| `0` | Success |
| `1` | Image not found |
| `2` | Error (auth, network, invalid input, timeout) |

View File

@@ -165,3 +165,4 @@ Plugin types:
- `docs/API_CLI_REFERENCE.md` — API and CLI contracts
- `docs/modules/platform/architecture-overview.md` — Platform service design
- `docs/product/advisories/09-Jan-2026 - Stella Ops Orchestrator Architecture.md` — Full orchestrator specification
- `docs-archived/product/advisories/13-Jan-2026 - Controlled Conversational Interface.md` - Controlled conversational interface guardrails and audit log

View File

@@ -22,6 +22,7 @@ open a PR and append it alphabetically.*
| **AzurePipelines** | CI/CD service in Microsoft Azure DevOps. | Recipe in Pipeline Library |
| **BDU** | Russian (FSTEC) national vulnerability database: *База данных уязвимостей*. | Merged with NVD by Concelier (vulnerability ingest/merge/export service) |
| **BuildKit** | Modern Docker build engine with caching and concurrency. | Needed for layer cache patterns |
| **Binary diff** | Section-hash comparison between two binaries or images to detect changes without source. | Used by `stella scan diff` and BinaryDiffV1 predicates |
| **CI** | *Continuous Integration* automated build/test pipeline. | Stella integrates via CLI |
| **Cosign** | Opensource Sigstore tool that signs & verifies container images **and files**. | Images & OUK tarballs |
| **CWV / CLS** | *Core Web Vitals* metric Cumulative Layout Shift. | UI budget ≤0.1 |
@@ -34,6 +35,7 @@ open a PR and append it alphabetically.*
| Term | Definition | Notes |
|------|------------|-------|
| **Digest (image)** | SHA256 hash uniquely identifying a container image or layer. | Pin digests for reproducible builds |
| **DSSE envelope** | Signed DSSE v1 wrapper that binds payload bytes and signatures. | Used for binary diff attestations |
| **DockerinDocker (DinD)** | Running Docker daemon inside a CI container. | Used in GitHub / GitLab recipes |
| **DTO** | *Data Transfer Object* C# record serialised to JSON. | Schemas in doc 11 |
| **Concelier** | Vulnerability ingest/merge/export service consolidating OVN, GHSA, NVD 2.0, CNNVD, CNVD, ENISA, JVN and BDU feeds into the canonical PostgreSQL store and export artifacts. | Cron default `0 1 * * *` |
@@ -83,6 +85,7 @@ open a PR and append it alphabetically.*
| **Rekor** | Sigstore transparency log; future work for signature anchoring. | Roadmap P4 |
| **RPS** | *Requests Per Second*. | Backend perf budget 40rps |
| **SBOM** | *Software Bill of Materials* inventory of packages in an image. | Trivy JSON v2 |
| **Section hash** | Stable hash of a binary section (for example, .text or .rodata). | Used for binary diff and backport evidence |
| **Stella CLI** | Lightweight CLI that submits SBOMs for vulnerability scanning. | See CI recipes |
| **Seccomp** | Linux syscall filter JSON profile. | Backend shipped nonroot |
| **SLA** | *ServiceLevel Agreement* 24h / 1ticket for Pro. | SRE runbook |
@@ -98,6 +101,7 @@ open a PR and append it alphabetically.*
| **Trivy** | OSS CVE scanner powering the default `IScannerRunner`. | CLI pinned 0.64 |
| **Trivysrv** | Longrunning Trivy server exposing gRPC API; speeds up remote scans. | Variant A |
| **UI tile** | Dashboard element showing live metric (scans today, feed age, etc.). | Angular Signals |
| **Vendor backport** | Vendor patch applied without a version bump; diff evidence proves patch presence. | Key signal for VEX decisions |
| **WebSocket** | Fullduplex channel (`/ws/scan`, `/ws/stats`) for UI realtime. | Used by tiles |
| **Zastava** | Lightweight agent that inventories running containers and can enforce kills. | |

View File

@@ -0,0 +1,115 @@
apiVersion: stella.ops/doctor.v1
kind: DoctorPlugin
metadata:
name: doctor-release-orchestrator-gitlab
labels:
module: release-orchestrator
integration: gitlab
spec:
discovery:
when:
- env: GITLAB_URL
- fileExists: config/release-orchestrator/gitlab.yaml
checks:
- id: scm.webhook.reachability
description: "GitLab webhook is reachable and signed"
run:
exec: |
stella orchestrator scm test-webhook \
--url "$GITLAB_URL" \
--project "$(stella cfg get gitlab.project)" \
--secret-ref "vault:scm/webhook_secret"
parse:
expect:
- contains: "200 OK"
how_to_fix:
summary: "Create/repair webhook with correct secret and events."
commands:
- stella orchestrator scm create-webhook --events push,tag,release
- stella secrets put scm/webhook_secret --from-random 32
- id: scm.branch.protection
description: "Main branches are protected with required approvals and checks"
run:
exec: |
stella orchestrator scm audit-branch-policy --branches main,release/*
parse:
expectJson:
path: $.allCompliant
equals: true
how_to_fix:
summary: "Apply baseline branch policy"
commands:
- stella orchestrator scm apply-branch-policy --preset strict
- id: registry.pushpull
description: "Robot account can push/pull and read attestations"
run:
exec: |
stella registry selftest --repo "$REGISTRY_REPO" --attestations
parse:
expect:
- contains: "push: ok"
- contains: "pull: ok"
- contains: "attestations: ok"
how_to_fix:
summary: "Create robot, grant repo:write, enable attestations"
commands:
- stella registry robot create --name orchestrator
- stella registry repo grant --robot orchestrator --write
- stella registry attestation enable --repo "$REGISTRY_REPO"
- id: sbom.ingestion
description: "SBOM/VEX ingestion endpoint accepts CycloneDX 1.6 and SPDX 3.0.1"
run:
exec: |
stella sbom ingest --file samples/cdx-1.6.json --type cyclonedx
stella sbom ingest --file samples/spdx-3.0.1.json --type spdx
parse:
expect:
- contains: "ingested: 2"
how_to_fix:
summary: "Enable SBOM service and permissions"
commands:
- stella svc enable sbom
- stella auth grant sbom:ingest --role orchestrator
- id: vault.connectivity
description: "Vault connectivity, auth, and policy"
run:
exec: |
stella vault doctor --policy doctor-orchestrator
parse:
expect:
- contains: "policy: ok"
- contains: "login: ok"
how_to_fix:
summary: "Create policy and AppRole"
commands:
- stella vault bootstrap --role orchestrator --policy doctor-orchestrator
- id: ldap.authority.mapping
description: "LDAP binds and maps groups -> roles"
run:
exec: |
stella authority ldap test --user "$TEST_USER_EMAIL"
parse:
expect:
- contains: "role: Deployer"
how_to_fix:
summary: "Adjust group -> role mapping"
commands:
- stella authority map add --group ops-deploy --role Deployer
- id: migrations.pending
description: "All orchestrator DB migrations applied"
run:
exec: |
stella db migrate status --service orchestrator --json
parse:
expectJson:
path: $.pending
equals: 0
how_to_fix:
summary: "Apply migrations safely (dry-run first)"
commands:
- stella db migrate apply --service orchestrator --dry-run
- stella db migrate apply --service orchestrator --apply
attestations:
dsse:
enabled: true
outFile: artifacts/doctor/orchestrator-gitlab.dsse.json

View File

@@ -15,68 +15,38 @@ The binary analysis system is designed for extensibility. You can add support fo
### Core Interfaces
```
┌─────────────────────────────────────────────────────────────────┐
│ Binary Analysis Pipeline │
├─────────────────────────────────────────────────────────────────┤
│ │
│ IBinaryFormatDetector ──▶ ISectionHashExtractor<TConfig> │
│ │ │ │
│ ▼ ▼ │
│ BinaryFormat enum SectionHashSet │
│ (elf, pe, macho) (per-format) │
│ │ │
│ ▼ │
│ IVerdictClassifier │
│ │ │
│ ▼ │
│ BinaryDiffFinding │
│ │
└─────────────────────────────────────────────────────────────────┘
+---------------------------+ +----------------------+ +-------------------+
| IElfSectionHashExtractor |--->| BinaryDiffService |--->| BinaryDiffFinding |
+---------------------------+ +----------------------+ +-------------------+
```
### Key Interfaces
```csharp
/// <summary>
/// Detects binary format from file magic/headers.
/// Extracts section hashes from ELF binaries.
/// </summary>
public interface IBinaryFormatDetector
public interface IElfSectionHashExtractor
{
BinaryFormat Detect(ReadOnlySpan<byte> header);
BinaryFormat DetectFromPath(string filePath);
}
/// <summary>
/// Extracts section hashes for a specific binary format.
/// </summary>
public interface ISectionHashExtractor<TConfig> where TConfig : class
{
BinaryFormat SupportedFormat { get; }
Task<SectionHashSet?> ExtractAsync(
string filePath,
TConfig? config = null,
Task<ElfSectionHashSet?> ExtractAsync(
string elfPath,
CancellationToken cancellationToken = default);
Task<SectionHashSet?> ExtractFromBytesAsync(
ReadOnlyMemory<byte> bytes,
Task<ElfSectionHashSet?> ExtractFromBytesAsync(
ReadOnlyMemory<byte> elfBytes,
string virtualPath,
TConfig? config = null,
CancellationToken cancellationToken = default);
}
/// <summary>
/// Classifies binary changes as patched/vanilla/unknown.
/// </summary>
public interface IVerdictClassifier
{
Verdict Classify(SectionHashSet? baseHashes, SectionHashSet? targetHashes);
double ComputeConfidence(SectionHashSet? baseHashes, SectionHashSet? targetHashes);
}
```
Future multi-format support (PE, Mach-O) will introduce format detection and
dedicated extractors similar to the ELF interface above.
## Adding a New Binary Format
The current implementation is ELF-only. The steps below describe the intended
shape for adding PE or Mach-O support; adjust interfaces as they are introduced.
### Step 1: Define Configuration
```csharp

View File

@@ -20,7 +20,7 @@ public sealed class MyConnector : IFeedConnector
/// <summary>
/// Gets the unique identifier for this connector.
/// </summary>
public string Id => "my-connector";
public string SourceName => "my-connector";
/// <summary>
/// Gets the display name for this connector.
@@ -28,47 +28,34 @@ public sealed class MyConnector : IFeedConnector
public string DisplayName => "My Connector";
/// <inheritdoc />
public async Task<FetchResult> FetchAsync(FetchContext context, CancellationToken cancellationToken = default)
public async Task FetchAsync(IServiceProvider services, CancellationToken cancellationToken = default)
{
_logger.LogInformation("Fetching data from {ConnectorId}...", Id);
ArgumentNullException.ThrowIfNull(services);
_logger.LogInformation("Fetching data from {SourceName}...", SourceName);
// TODO: Implement your fetch logic here
// Example: Download data from an external source
await Task.Delay(100, cancellationToken); // Placeholder
return new FetchResult(
Success: true,
Data: Array.Empty<byte>(),
ContentType: "application/json",
ETag: null);
}
/// <inheritdoc />
public async Task<ParseResult> ParseAsync(byte[] data, CancellationToken cancellationToken = default)
public async Task ParseAsync(IServiceProvider services, CancellationToken cancellationToken = default)
{
_logger.LogInformation("Parsing data from {ConnectorId}...", Id);
ArgumentNullException.ThrowIfNull(services);
_logger.LogInformation("Parsing data from {SourceName}...", SourceName);
// TODO: Implement your parsing logic here
await Task.Yield();
return new ParseResult(
Success: true,
Items: Array.Empty<object>(),
Errors: Array.Empty<string>());
}
/// <inheritdoc />
public async Task<MapResult> MapAsync(object item, CancellationToken cancellationToken = default)
public async Task MapAsync(IServiceProvider services, CancellationToken cancellationToken = default)
{
_logger.LogInformation("Mapping item from {ConnectorId}...", Id);
ArgumentNullException.ThrowIfNull(services);
_logger.LogInformation("Mapping item from {SourceName}...", SourceName);
// TODO: Implement your mapping logic here
await Task.Yield();
return new MapResult(
Success: true,
MappedItem: item,
Errors: Array.Empty<string>());
}
}

View File

@@ -10,16 +10,21 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.0" />
<PackageReference Include="Microsoft.Extensions.Options" Version="10.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.1" />
<PackageReference Include="Microsoft.Extensions.Options" Version="10.0.1" />
</ItemGroup>
<!-- Reference StellaOps plugin infrastructure -->
<!-- Adjust paths based on your repository structure -->
<ItemGroup>
<ProjectReference Include="..\..\src\__Libraries\StellaOps.Plugin\StellaOps.Plugin.csproj" />
<ProjectReference Include="..\..\src\__Libraries\StellaOps.DependencyInjection\StellaOps.DependencyInjection.csproj" />
<ProjectReference Include="..\..\..\..\..\src\__Libraries\StellaOps.Plugin\StellaOps.Plugin.csproj" />
<ProjectReference Include="..\..\..\..\..\src\__Libraries\StellaOps.DependencyInjection\StellaOps.DependencyInjection.csproj" />
</ItemGroup>
<ItemGroup>
<Compile Remove="__Tests\\**\\*.cs" />
<None Remove="__Tests\\**\\*" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,44 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using StellaOps.Plugin.MyConnector;
using Xunit;
namespace StellaOps.Plugin.MyConnector.Tests;
public sealed class MyConnectorTests
{
[Fact]
public void MyConnector_ExposesIdentifiers()
{
var options = new MyConnectorOptions
{
BaseUrl = "https://example.com"
};
var connector = new MyConnector(NullLogger<MyConnector>.Instance, options);
Assert.Equal("my-connector", connector.SourceName);
Assert.Equal("My Connector", connector.DisplayName);
}
[Fact]
public void Plugin_Create_ReturnsConnector()
{
var services = new ServiceCollection();
services.AddSingleton<ILogger<MyConnector>>(NullLogger<MyConnector>.Instance);
services.AddSingleton<IOptions<MyConnectorOptions>>(Options.Create(new MyConnectorOptions
{
BaseUrl = "https://example.com"
}));
using var provider = services.BuildServiceProvider();
var plugin = new MyConnectorPlugin();
var connector = plugin.Create(provider);
Assert.NotNull(connector);
Assert.Equal("my-connector", connector.SourceName);
}
}

View File

@@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<IsPackable>false</IsPackable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\StellaOps.Plugin.MyConnector.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="10.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.1" />
<PackageReference Include="Microsoft.Extensions.Options" Version="10.0.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5" />
</ItemGroup>
</Project>

View File

@@ -10,16 +10,21 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.0" />
<PackageReference Include="Microsoft.Extensions.Options" Version="10.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.1" />
<PackageReference Include="Microsoft.Extensions.Options" Version="10.0.1" />
</ItemGroup>
<!-- Reference StellaOps plugin infrastructure -->
<!-- Adjust paths based on your repository structure -->
<ItemGroup>
<ProjectReference Include="..\..\src\__Libraries\StellaOps.Plugin\StellaOps.Plugin.csproj" />
<ProjectReference Include="..\..\src\__Libraries\StellaOps.DependencyInjection\StellaOps.DependencyInjection.csproj" />
<ProjectReference Include="..\..\..\..\..\src\__Libraries\StellaOps.Plugin\StellaOps.Plugin.csproj" />
<ProjectReference Include="..\..\..\..\..\src\__Libraries\StellaOps.DependencyInjection\StellaOps.DependencyInjection.csproj" />
</ItemGroup>
<ItemGroup>
<Compile Remove="__Tests\\**\\*.cs" />
<None Remove="__Tests\\**\\*" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,24 @@
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using StellaOps.Plugin.MyJob;
using Xunit;
namespace StellaOps.Plugin.MyJob.Tests;
public sealed class MyJobTests
{
[Fact]
public void MyJob_UsesConfiguredSchedule()
{
var options = Options.Create(new MyJobOptions
{
CronSchedule = "0 0 * * *"
});
var job = new MyJob(NullLogger<MyJob>.Instance, options);
Assert.Equal("my-job", job.JobId);
Assert.Equal("My Scheduled Job", job.DisplayName);
Assert.Equal("0 0 * * *", job.CronSchedule);
}
}

View File

@@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<IsPackable>false</IsPackable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\\..\\StellaOps.Plugin.MyJob.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="10.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.1" />
<PackageReference Include="Microsoft.Extensions.Options" Version="10.0.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5" />
</ItemGroup>
</Project>

View File

@@ -27,11 +27,15 @@ stella doctor --category database
# Export report for support
stella doctor export --output diagnostic-bundle.zip
# Apply safe fixes from a report (dry-run by default)
stella doctor fix --from doctor-report.json --apply
```
### UI
Navigate to `/ops/doctor` in the Stella Ops console to access the interactive Doctor Dashboard.
Fix actions are exposed in the UI and mirror CLI commands; destructive steps are never executed by Doctor.
### API

View File

@@ -16,9 +16,10 @@ stella doctor [options]
| Option | Short | Type | Default | Description |
|--------|-------|------|---------|-------------|
| `--format` | `-f` | enum | `text` | Output format: `text`, `json`, `markdown` |
| `--format` | `-f` | enum | `text` | Output format: `text`, `table`, `json`, `markdown` |
| `--quick` | `-q` | flag | false | Run only quick checks (tagged `quick`) |
| `--full` | | flag | false | Run all checks including slow/intensive |
| `--pack` | | string[] | all | Filter by pack name (manifest grouping) |
| `--category` | `-c` | string[] | all | Filter by category |
| `--plugin` | `-p` | string[] | all | Filter by plugin ID |
| `--check` | | string | | Run single check by ID |
@@ -71,6 +72,34 @@ stella doctor --verbose
stella doctor --timeout 60s --parallel 2
```
### stella doctor fix
Apply non-destructive fixes from a Doctor report.
```bash
stella doctor fix --from report.json [--apply]
```
#### Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `--from` | path | required | Path to JSON report with `how_to_fix` commands |
| `--apply` | flag | false | Execute fixes (default is dry-run preview) |
Doctor only executes non-destructive commands. If a fix requires a destructive
change, it is printed as manual guidance and not executed by Doctor.
#### Examples
```bash
# Preview fixes (dry-run)
stella doctor fix --from doctor-report.json
# Apply safe fixes
stella doctor fix --from doctor-report.json --apply
```
### stella doctor export
Generate a diagnostic bundle for support.

View File

@@ -48,6 +48,7 @@ The Doctor capability provides comprehensive self-service diagnostics for Stella
3. **Zero Docs Familiarity** - Users can diagnose and fix without reading documentation
4. **Evidence-Based Diagnostics** - All checks collect and report evidence
5. **Multi-Surface Consistency** - Same check engine powers CLI, UI, and API
6. **Non-Destructive Fixes** - Doctor never executes destructive actions; fix commands must be safe and idempotent
### 1.4 Surfaces
@@ -749,7 +750,32 @@ public class DoctorPluginLoader
}
```
### 4.5 Plugin Directory Structure
### 4.5 Declarative Doctor Packs (YAML)
Doctor packs provide declarative checks that wrap CLI commands and parsing rules.
They complement compiled plugins and are loaded from `plugins/doctor/*.yaml` (plus optional override directories).
Short example:
```yaml
apiVersion: stella.ops/doctor.v1
kind: DoctorPlugin
metadata:
name: doctor-release-orchestrator-gitlab
spec:
discovery:
when:
- env: GITLAB_URL
```
Full sample: `docs/benchmarks/doctor/doctor-plugin-release-orchestrator-gitlab.yaml`
Key fields:
- `spec.discovery.when`: env/file existence gates.
- `checks[].run.exec`: command to execute (must be deterministic).
- `checks[].parse.expect` or `checks[].parse.expectJson`: pass/fail rules.
- `checks[].how_to_fix.commands[]`: exact fix commands printed verbatim.
### 4.6 Plugin Directory Structure
```
src/
@@ -770,7 +796,7 @@ src/
│ └── StellaOps.Doctor.Plugin.Observability/
```
### 4.6 Plugin Configuration
### 4.7 Plugin Configuration
Plugins read configuration from the standard config hierarchy:
@@ -807,7 +833,7 @@ Doctor:
- "secret/data/stellaops/certificates"
```
### 4.7 Security Model
### 4.8 Security Model
#### Secret Redaction
@@ -853,7 +879,7 @@ Doctor checks require specific scopes:
| `doctor:export` | Export diagnostic reports |
| `admin:system` | Access system-level checks |
### 4.8 Versioning Strategy
### 4.9 Versioning Strategy
- **Engine version:** Semantic versioning (e.g., `1.0.0`)
- **Plugin version:** Independent semantic versioning
@@ -880,16 +906,24 @@ if (plugin.MinEngineVersion > DoctorEngine.Version)
**Proposed Location:** `src/Cli/StellaOps.Cli/Commands/DoctorCommandGroup.cs`
```bash
stella doctor [options]
stella doctor run [options]
stella doctor list [options]
stella doctor fix --from report.json [--apply]
```
Note: `stella doctor` remains shorthand for `stella doctor run` for compatibility.
`stella doctor fix` executes only non-destructive commands. Any destructive step
must be presented as manual guidance and is not eligible for `--apply`.
### 5.2 Options and Flags
| Option | Short | Type | Default | Description |
|--------|-------|------|---------|-------------|
| `--format` | `-f` | enum | `text` | Output format: `text`, `json`, `markdown` |
| `--format` | `-f` | enum | `text` | Output format: `text`, `table`, `json`, `markdown` |
| `--quick` | `-q` | flag | false | Run only quick checks (tagged `quick`) |
| `--full` | | flag | false | Run all checks including slow/intensive |
| `--pack` | | string[] | all | Filter by pack name (manifest grouping) |
| `--category` | `-c` | string[] | all | Filter by category: `core`, `database`, `service-graph`, `integration`, `security`, `observability` |
| `--plugin` | `-p` | string[] | all | Filter by plugin ID (e.g., `scm.github`) |
| `--check` | | string | | Run single check by ID |
@@ -901,6 +935,16 @@ stella doctor [options]
| `--verbose` | `-v` | flag | false | Include detailed evidence in output |
| `--tenant` | | string | | Tenant context for multi-tenant checks |
#### Fix Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `--from` | path | required | Path to JSON report with `how_to_fix` commands |
| `--apply` | flag | false | Execute fixes (default is dry-run preview) |
Only commands marked safe and non-destructive are eligible for `--apply`.
Destructive changes must be printed as manual steps and executed by the operator outside Doctor.
### 5.3 Exit Codes
| Code | Meaning |
@@ -915,9 +959,12 @@ stella doctor [options]
### 5.4 Usage Examples
```bash
# Quick health check (default)
# Quick health check (alias)
stella doctor
# Run all checks explicitly
stella doctor run
# Full diagnostic
stella doctor --full
@@ -933,6 +980,12 @@ stella doctor --check check.database.migrations.pending
# JSON output for CI/CD
stella doctor --format json --severity fail,warn
# Run orchestrator pack with table output
stella doctor run --pack orchestrator --format table
# Apply fixes from a JSON report (dry-run unless --apply)
stella doctor fix --from out.json --apply
# Export markdown report
stella doctor --full --format markdown --export doctor-report.md
@@ -1133,7 +1186,13 @@ src/app/features/doctor/
+------------------------------------------------------------------+
```
### 6.5 Real-Time Updates
### 6.5 Pack Navigation and Fix Actions
- Navigation hierarchy: packs -> plugins -> checks.
- Each check shows status, evidence, Copy Fix Commands, and Run Fix (disabled unless `doctor.fix.enabled=true`).
- Export actions: Download JSON and Download DSSE summary.
### 6.6 Real-Time Updates
- **Polling:** Auto-refresh option (every 30s/60s/5m)
- **SSE:** Live check progress during execution
@@ -1287,6 +1346,9 @@ GET /api/v1/doctor/run/dr_20260112_143052_abc123
}
```
Results also expose a `how_to_fix` object for automation. It is a simplified alias of
the richer `remediation` model and includes `commands[]` printed verbatim.
### 7.3 SSE Stream
```http
@@ -1311,10 +1373,28 @@ event: run-completed
data: {"runId":"dr_20260112_143052_abc123","summary":{"passed":44,"warnings":2,"failed":1}}
```
### 7.4 Evidence Logs and Attestations
Doctor runs emit a JSONL evidence log and optional DSSE summary for audit trails.
By default, JSONL is local only and deterministic; outbound telemetry is opt-in.
- JSONL path: `artifacts/doctor/doctor-run-<runId>.ndjson` (configurable).
- DSSE summary: `artifacts/doctor/doctor-run-<runId>.dsse.json` (optional).
- Evidence records include `doctor_command` to capture the operator-invoked command.
DSSE summaries assume operator execution and must include the same command note.
Example JSONL line:
```json
{"runId":"dr_20260112_143052_abc123","doctor_command":"stella doctor run --format json","checkId":"check.database.connectivity","severity":"pass","executedAt":"2026-01-12T14:30:52Z","how_to_fix":{"commands":[]}}
```
---
## 8. Remediation Command Patterns
Remediation should favor the best operator experience: short, copy/paste friendly
commands with minimal steps and clear verification guidance.
### 8.1 Standard Output Format
Every failed check produces remediation in this structure:
@@ -1345,6 +1425,20 @@ Every failed check produces remediation in this structure:
{command to re-run this specific check}
```
### 8.1.1 JSON Remediation Structure
The JSON output MUST include a `how_to_fix` object for agent consumption. It can be
derived from `remediation.steps` and preserves command order.
```json
"how_to_fix": {
"summary": "Apply baseline branch policy",
"commands": [
"stella orchestrator scm apply-branch-policy --preset strict"
]
}
```
### 8.2 Placeholder Conventions
When commands require user-specific values:
@@ -1363,10 +1457,12 @@ When commands require user-specific values:
### 8.3 Safety Notes
Commands that modify data include safety guidance:
Doctor fix executes only non-destructive commands. If a fix requires a change
that modifies data, Doctor must present it as manual guidance with explicit
safety notes and never execute it.
```
Fix Steps:
Manual Steps (not executed by Doctor):
# SAFETY: This operation modifies the database. Create a backup first.
# 1. Backup database (REQUIRED before proceeding)

View File

@@ -42,10 +42,19 @@ stella scan diff --base myapp:1.0.0 --target myapp:1.0.1
# Generate attestation
stella scan diff --base myapp:1.0.0 --target myapp:1.0.1 \
--mode=elf --emit-dsse=./attestations/
--mode=elf --emit-dsse=./attestations \
--signing-key=./keys/binarydiff.pem
# Verify attestation
stella verify attestation ./attestations/linux-amd64-binarydiff.dsse.json
# Attach attestation to the image
stella attest attach \
--image docker://myapp:1.0.1 \
--attestation ./attestations/linux-amd64-binarydiff.dsse.json
# Verify attestation (example with cosign)
cosign verify-attestation \
--type stellaops.binarydiff.v1 \
--key ./keys/binarydiff.pub \
docker://myapp:1.0.1
```
## Related Documentation

View File

@@ -30,15 +30,17 @@ Output:
```
Binary Diff: docker://registry.example.com/myapp:1.0.0 -> docker://registry.example.com/myapp:1.0.1
Platform: linux/amd64
Analysis Mode: ELF Section Hashes
Analysis Mode: ELF section hashes
PATH CHANGE VERDICT CONFIDENCE
--------------------------------------------------------------------------------
/usr/lib/libssl.so.3 modified patched 0.95
/usr/lib/libcrypto.so.3 modified patched 0.92
/app/bin/myapp modified vanilla 0.98
PATH CHANGE VERDICT CONFIDENCE SECTIONS CHANGED
-----------------------------------------------------------------------------------
/app/bin/myapp modified unknown 0.65 .rodata, .text
/usr/lib/libcrypto.so.3 modified unknown 0.70 .text
/usr/lib/libssl.so.3 modified unknown 0.75 .rodata, .text
Summary: 156 binaries analyzed, 3 modified, 153 unchanged
Added: 0, Removed: 0
Verdicts: unknown: 3, vanilla: 153
```
### JSON Output
@@ -65,12 +67,13 @@ Output:
```
Binary Diff Summary
-------------------
Base: docker://registry.example.com/myapp:1.0.0 (sha256:abc123...)
Target: docker://registry.example.com/myapp:1.0.1 (sha256:def456...)
Base: docker://registry.example.com/myapp:1.0.0
Target: docker://registry.example.com/myapp:1.0.1
Platform: linux/amd64
Binaries: 156 total, 3 modified, 153 unchanged
Verdicts: 2 patched, 1 vanilla
Added: 0, Removed: 0
Verdicts: unknown: 3, vanilla: 153
```
## Using Digest References
@@ -132,9 +135,8 @@ Output includes:
| Verdict | Meaning | Action |
|---------|---------|--------|
| `patched` | High confidence that a security patch was applied | Review changelog, consider safe to upgrade |
| `vanilla` | Standard code change, no backport evidence | Normal release update |
| `unknown` | Cannot determine patch status | Manual review recommended |
| `vanilla` | Unchanged binary | No action required |
| `unknown` | Diff detected but classifier is not yet applied | Manual review recommended |
## Next Steps

View File

@@ -20,7 +20,6 @@ jobs:
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write # For keyless signing
steps:
- name: Checkout
@@ -38,6 +37,12 @@ jobs:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Write Signing Key
run: |
mkdir -p keys
printf '%s' "${{ secrets.BINARYDIFF_SIGNING_KEY_PEM }}" > keys/binarydiff.pem
chmod 600 keys/binarydiff.pem
- name: Get Previous Tag
id: prev-tag
run: |
@@ -52,6 +57,7 @@ jobs:
--target ghcr.io/${{ github.repository }}:${{ github.ref_name }} \
--mode=elf \
--emit-dsse=./attestations/ \
--signing-key=./keys/binarydiff.pem \
--format=json > diff.json
- name: Upload Attestations
@@ -146,11 +152,16 @@ binary-diff:
PREV_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "")
if [ -n "$PREV_TAG" ]; then
mkdir -p keys
printf '%s' "$BINARYDIFF_SIGNING_KEY_PEM" > keys/binarydiff.pem
chmod 600 keys/binarydiff.pem
stella scan diff \
--base ${CI_REGISTRY_IMAGE}:${PREV_TAG} \
--target ${CI_REGISTRY_IMAGE}:${CI_COMMIT_TAG} \
--mode=elf \
--emit-dsse=attestations/ \
--signing-key=keys/binarydiff.pem \
--format=json > diff.json
# Upload to GitLab artifacts
@@ -214,14 +225,18 @@ pipeline {
).trim()
if (prevTag) {
sh """
stella scan diff \\
--base ${REGISTRY}/${IMAGE}:${prevTag} \\
--target ${REGISTRY}/${IMAGE}:${TAG} \\
--mode=elf \\
--emit-dsse=attestations/ \\
--format=json > diff.json
"""
withCredentials([string(credentialsId: 'binarydiff-signing-key-pem', variable: 'BINARYDIFF_SIGNING_KEY_PEM')]) {
sh 'mkdir -p keys && printf "%s" "$BINARYDIFF_SIGNING_KEY_PEM" > keys/binarydiff.pem && chmod 600 keys/binarydiff.pem'
sh """
stella scan diff \\
--base ${REGISTRY}/${IMAGE}:${prevTag} \\
--target ${REGISTRY}/${IMAGE}:${TAG} \\
--mode=elf \\
--emit-dsse=attestations/ \\
--signing-key=keys/binarydiff.pem \\
--format=json > diff.json
"""
}
archiveArtifacts artifacts: 'attestations/*, diff.json'
@@ -272,11 +287,16 @@ steps:
script: |
PREV_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "")
if [ -n "$PREV_TAG" ]; then
mkdir -p $(Build.SourcesDirectory)/keys
printf '%s' "$(BINARYDIFF_SIGNING_KEY_PEM)" > $(Build.SourcesDirectory)/keys/binarydiff.pem
chmod 600 $(Build.SourcesDirectory)/keys/binarydiff.pem
stella scan diff \
--base $(REGISTRY)/$(IMAGE):${PREV_TAG} \
--target $(REGISTRY)/$(IMAGE):$(Build.SourceBranchName) \
--mode=elf \
--emit-dsse=$(Build.ArtifactStagingDirectory)/attestations/ \
--signing-key=$(Build.SourcesDirectory)/keys/binarydiff.pem \
--format=json > $(Build.ArtifactStagingDirectory)/diff.json
fi

View File

@@ -0,0 +1,44 @@
# DSSE Attestation
This example shows how to emit DSSE envelopes from `stella scan diff` and verify them.
## Generate DSSE Output
```bash
stella scan diff \
--base docker://registry.example.com/myapp:1.0.0 \
--target docker://registry.example.com/myapp:1.0.1 \
--mode=elf \
--emit-dsse=./attestations \
--signing-key=./keys/binarydiff.pem
```
Output files:
```
attestations/
linux-amd64-binarydiff.dsse.json
linux-amd64-binarydiff.payload.json
```
## Attach Attestation
```bash
stella attest attach \
--image docker://registry.example.com/myapp:1.0.1 \
--attestation ./attestations/linux-amd64-binarydiff.dsse.json
```
## Verify with Cosign
```bash
cosign verify-attestation \
--type stellaops.binarydiff.v1 \
--key ./keys/binarydiff.pub \
docker://registry.example.com/myapp:1.0.1
```
## Notes
- DSSE signing requires an ECDSA private key (P-256/384/521) in PEM format.
- If the image is multi-arch, specify `--platform` to select the manifest.

View File

@@ -0,0 +1,32 @@
# Policy Integration
Binary diff output can be used as evidence in policy decisions. This example
shows a simple workflow using the JSON output from `stella scan diff`.
## Generate JSON Output
```bash
stella scan diff \
--base myapp:1.0.0 \
--target myapp:1.0.1 \
--format=json > diff.json
```
## Feed into Policy Evaluation
Use the JSON report as an input signal for policy rules that require evidence
of binary changes. Example (pseudo-rule):
```rego
package stella.policy
allow {
input.binaryDiff.summary.modified > 0
input.binaryDiff.findings[_].changeType == "modified"
}
```
## Notes
- The CLI currently emits `unknown` verdicts for modified binaries.
- Future classifier updates will populate `patched` and `vanilla` verdicts.

View File

@@ -6,12 +6,5 @@
"keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA",
"sig": "MEUCIQDKZokqnCjrRtw5EXP14JvsBwFDRPfCp9K0UoOlWGdlDQIgSNpOGPqKNLv5MNZLYc5iE7q5b3wW6K0cDpjNxBxCWdU="
}
],
"_note": "This is a sample DSSE envelope for documentation purposes. The payload is base64-encoded and contains an in-toto statement with a BinaryDiffV1 predicate. In production, the signature would be cryptographically valid.",
"_rekorMetadata": {
"logIndex": 12345678,
"entryUuid": "24296fb24b8ad77aa3e6b0d1b6e0e3a0c9f8d7e6b5a4c3d2e1f0a9b8c7d6e5f4",
"integratedTime": "2026-01-13T12:00:05Z",
"logUrl": "https://rekor.sigstore.dev"
}
]
}

View File

@@ -1,27 +1,13 @@
Binary Diff: docker://registry.example.com/app:1.0.0 -> docker://registry.example.com/app:1.0.1
Binary Diff: docker://registry.example.com/myapp:1.0.0 -> docker://registry.example.com/myapp:1.0.1
Platform: linux/amd64
Analysis Mode: ELF Section Hashes
Analyzed Sections: .text, .rodata, .data, .symtab, .dynsym
Analysis Mode: ELF section hashes
PATH CHANGE VERDICT CONFIDENCE SECTIONS CHANGED
--------------------------------------------------------------------------------------------------
/usr/lib/x86_64-linux-gnu/libssl.so.3 modified patched 0.95 .text, .rodata
/usr/lib/x86_64-linux-gnu/libcrypto.so.3 modified patched 0.92 .text
/usr/bin/openssl modified unknown 0.75 .text, .data, .symtab
/lib/x86_64-linux-gnu/libc.so.6 unchanged - - -
/lib/x86_64-linux-gnu/libpthread.so.0 unchanged - - -
/usr/lib/x86_64-linux-gnu/libz.so.1 unchanged - - -
/app/bin/myapp modified vanilla 0.98 .text, .rodata, .data
PATH CHANGE VERDICT CONFIDENCE SECTIONS CHANGED
-------------------------- -------- ------- ---------- ----------------
/app/bin/myapp modified unknown 0.65 .rodata, .text
/usr/lib/libcrypto.so.3 modified unknown 0.70 .text
/usr/lib/libssl.so.3 modified unknown 0.75 .rodata, .text
Summary
-------
Total binaries analyzed: 156
Modified: 4
Unchanged: 152
Verdicts:
Patched: 2 (high confidence backport detected)
Vanilla: 1 (standard update, no backport evidence)
Unknown: 1 (insufficient evidence for classification)
Analysis completed in 12.4s
Summary: 7 binaries analyzed, 3 modified, 4 unchanged
Added: 0, Removed: 0
Verdicts: unknown: 3, vanilla: 4

View File

@@ -1,179 +1,173 @@
{
"schemaVersion": "1.0.0",
"base": {
"reference": "docker://registry.example.com/app:1.0.0",
"digest": "sha256:abc123def456789012345678901234567890123456789012345678901234abcd",
"manifestDigest": "sha256:111222333444555666777888999000aaabbbcccdddeeefff000111222333444555"
},
"target": {
"reference": "docker://registry.example.com/app:1.0.1",
"digest": "sha256:def456abc789012345678901234567890123456789012345678901234567efgh",
"manifestDigest": "sha256:666777888999000aaabbbcccdddeeefff000111222333444555666777888999000"
},
"platform": {
"os": "linux",
"architecture": "amd64"
},
"analysisMode": "elf",
"timestamp": "2026-01-13T12:00:00.000000Z",
"base": {
"digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"reference": "docker://registry.example.com/myapp:1.0.0"
},
"findings": [
{
"path": "/usr/lib/x86_64-linux-gnu/libssl.so.3",
"changeType": "modified",
"binaryFormat": "elf",
"layerDigest": "sha256:aaa111bbb222ccc333ddd444eee555fff666777888999000aaabbbcccdddeeef",
"baseHashes": {
"buildId": "abc123def456789012345678",
"fileHash": "1111111111111111111111111111111111111111111111111111111111111111",
"fileHash": "1212121212121212121212121212121212121212121212121212121212121212",
"sections": {
".text": {
"sha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"size": 524288,
"offset": 4096
},
".rodata": {
"sha256": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"size": 131072,
"offset": 528384
"sha256": "3434343434343434343434343434343434343434343434343434343434343434",
"size": 4096
},
".text": {
"sha256": "5656565656565656565656565656565656565656565656565656565656565656",
"size": 65536
}
}
},
"binaryFormat": "elf",
"changeType": "modified",
"confidence": 0.65,
"layerDigest": "sha256:5555555555555555555555555555555555555555555555555555555555555555",
"path": "/app/bin/myapp",
"sectionDeltas": [
{
"baseSha256": "3434343434343434343434343434343434343434343434343434343434343434",
"section": ".rodata",
"sizeDelta": 64,
"status": "modified",
"targetSha256": "9090909090909090909090909090909090909090909090909090909090909090"
},
{
"baseSha256": "5656565656565656565656565656565656565656565656565656565656565656",
"section": ".text",
"sizeDelta": 256,
"status": "modified",
"targetSha256": "abababababababababababababababababababababababababababababababab"
}
],
"targetHashes": {
"buildId": "def789abc012345678901234",
"fileHash": "2222222222222222222222222222222222222222222222222222222222222222",
"fileHash": "7878787878787878787878787878787878787878787878787878787878787878",
"sections": {
".text": {
"sha256": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
"size": 524544,
"offset": 4096
},
".rodata": {
"sha256": "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
"size": 131200,
"offset": 528640
"sha256": "9090909090909090909090909090909090909090909090909090909090909090",
"size": 4160
},
".text": {
"sha256": "abababababababababababababababababababababababababababababababab",
"size": 65792
}
}
},
"sectionDeltas": [
{
"section": ".text",
"status": "modified",
"baseSha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"targetSha256": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
"sizeDelta": 256
},
{
"section": ".rodata",
"status": "modified",
"baseSha256": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"targetSha256": "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
"sizeDelta": 128
},
{
"section": ".data",
"status": "identical",
"baseSha256": "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
"targetSha256": "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
"sizeDelta": 0
},
{
"section": ".symtab",
"status": "identical",
"baseSha256": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"targetSha256": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"sizeDelta": 0
}
],
"confidence": 0.95,
"verdict": "patched"
},
{
"path": "/usr/lib/x86_64-linux-gnu/libcrypto.so.3",
"changeType": "modified",
"binaryFormat": "elf",
"layerDigest": "sha256:aaa111bbb222ccc333ddd444eee555fff666777888999000aaabbbcccdddeeef",
"sectionDeltas": [
{
"section": ".text",
"status": "modified",
"sizeDelta": 1024
},
{
"section": ".rodata",
"status": "identical",
"sizeDelta": 0
}
],
"confidence": 0.92,
"verdict": "patched"
},
{
"path": "/usr/bin/openssl",
"changeType": "modified",
"binaryFormat": "elf",
"sectionDeltas": [
{
"section": ".text",
"status": "modified",
"sizeDelta": 512
},
{
"section": ".data",
"status": "modified",
"sizeDelta": 64
},
{
"section": ".symtab",
"status": "modified",
"sizeDelta": 128
}
],
"confidence": 0.75,
"verdict": "unknown"
},
{
"path": "/app/bin/myapp",
"changeType": "modified",
"baseHashes": {
"fileHash": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"sections": {
".rodata": {
"sha256": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"size": 120000
},
".text": {
"sha256": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
"size": 600000
}
}
},
"binaryFormat": "elf",
"changeType": "modified",
"confidence": 0.7,
"layerDigest": "sha256:4444444444444444444444444444444444444444444444444444444444444444",
"path": "/usr/lib/libcrypto.so.3",
"sectionDeltas": [
{
"baseSha256": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
"section": ".text",
"sizeDelta": 512,
"status": "modified",
"sizeDelta": 2048
},
{
"section": ".rodata",
"status": "modified",
"sizeDelta": 512
},
{
"section": ".data",
"status": "modified",
"sizeDelta": 128
"targetSha256": "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"
}
],
"confidence": 0.98,
"verdict": "vanilla"
"targetHashes": {
"fileHash": "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
"sections": {
".rodata": {
"sha256": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"size": 120000
},
".text": {
"sha256": "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
"size": 600512
}
}
},
"verdict": "unknown"
},
{
"baseHashes": {
"fileHash": "4444444444444444444444444444444444444444444444444444444444444444",
"sections": {
".rodata": {
"sha256": "5555555555555555555555555555555555555555555555555555555555555555",
"size": 131072
},
".text": {
"sha256": "6666666666666666666666666666666666666666666666666666666666666666",
"size": 524288
}
}
},
"binaryFormat": "elf",
"changeType": "modified",
"confidence": 0.75,
"layerDigest": "sha256:3333333333333333333333333333333333333333333333333333333333333333",
"path": "/usr/lib/libssl.so.3",
"sectionDeltas": [
{
"baseSha256": "5555555555555555555555555555555555555555555555555555555555555555",
"section": ".rodata",
"sizeDelta": 128,
"status": "modified",
"targetSha256": "8888888888888888888888888888888888888888888888888888888888888888"
},
{
"baseSha256": "6666666666666666666666666666666666666666666666666666666666666666",
"section": ".text",
"sizeDelta": 256,
"status": "modified",
"targetSha256": "9999999999999999999999999999999999999999999999999999999999999999"
}
],
"targetHashes": {
"fileHash": "7777777777777777777777777777777777777777777777777777777777777777",
"sections": {
".rodata": {
"sha256": "8888888888888888888888888888888888888888888888888888888888888888",
"size": 131200
},
".text": {
"sha256": "9999999999999999999999999999999999999999999999999999999999999999",
"size": 524544
}
}
},
"verdict": "unknown"
}
],
"summary": {
"totalBinaries": 156,
"modified": 4,
"unchanged": 152,
"added": 0,
"removed": 0,
"verdicts": {
"patched": 2,
"vanilla": 1,
"unknown": 1,
"incompatible": 0
},
"sectionsAnalyzed": [".text", ".rodata", ".data", ".symtab", ".dynsym"],
"analysisDurationMs": 12400
"platform": {
"architecture": "amd64",
"os": "linux"
},
"metadata": {
"toolVersion": "1.0.0",
"analysisTimestamp": "2026-01-13T12:00:00.000000Z",
"configDigest": "sha256:config123456789abcdef0123456789abcdef0123456789abcdef0123456789ab"
}
"schemaVersion": "1.0.0",
"summary": {
"added": 0,
"modified": 3,
"removed": 0,
"totalBinaries": 7,
"unchanged": 4,
"verdicts": {
"unknown": 3,
"vanilla": 4
}
},
"target": {
"digest": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"reference": "docker://registry.example.com/myapp:1.0.1"
},
"timestamp": "2026-01-13T12:00:00+00:00"
}

View File

@@ -0,0 +1,54 @@
# Image Inspection Guide
## Overview
`stella image inspect` resolves an OCI image reference, enumerates platform manifests, and lists layers. Use it to confirm what is deployed where and to feed downstream verification workflows.
## Basic usage
```bash
stella image inspect nginx:latest
```
## JSON output for automation
```bash
stella image inspect nginx:latest --output json > image-inspect.json
```
## Platform filter
```bash
stella image inspect nginx:latest --platform linux/amd64
```
## Private registry (HTTP)
For local registries that use HTTP, include the scheme in the reference:
```bash
stella image inspect http://localhost:5000/myapp:1.0.0
```
If you need registry auth, configure the `OciRegistry` section in your CLI config (see `docs/modules/scanner/image-inspection.md`).
## CI usage example
```bash
stella image inspect ghcr.io/org/app:1.2.3 --output json \
| jq '.platforms[] | { os: .os, arch: .architecture, layers: (.layers | length) }'
```
## Troubleshooting
### Authentication required
- Symptom: `Authentication required` error.
- Fix: configure `OciRegistry.Auth` in your CLI config or use a registry that allows anonymous pulls.
### Rate limits
- Symptom: HTTP 429 or warnings about rate limits.
- Fix: retry later, use authenticated credentials, or mirror to a private registry.
### Unsupported media types
- Symptom: warnings about unknown manifest media types.
- Fix: confirm the registry serves OCI or Docker v2 manifests, and ensure the image reference is correct.

View File

@@ -31,31 +31,31 @@
| 6 | AUDIT-HOTLIST-SCANNER-NATIVE-0001 | DONE | Applied 2026-01-13; tracker updated | Guild - Scanner | Remediate hotlist findings for `src/Scanner/StellaOps.Scanner.Analyzers.Native/StellaOps.Scanner.Analyzers.Native.csproj`; apply fixes, add tests, update audit tracker. |
| 7 | AUDIT-HOTLIST-SCANNER-WEBSERVICE-0001 | DONE | Applied 2026-01-13; Hotlist S2/M2/Q2 | Guild - Scanner | Remediate hotlist findings for `src/Scanner/StellaOps.Scanner.WebService/StellaOps.Scanner.WebService.csproj`; apply fixes, add tests, update audit tracker. |
| 8 | AUDIT-HOTLIST-EXPORTCENTER-CORE-0001 | DOING | In progress 2026-01-13; Hotlist S2/M2/Q1 | Guild - ExportCenter | Remediate hotlist findings for `src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Core/StellaOps.ExportCenter.Core.csproj`; apply fixes, add tests, update audit tracker. |
| 9 | AUDIT-HOTLIST-SIGNALS-0001 | TODO | Approved 2026-01-12; Hotlist S2/M2/Q1 | Guild - Signals | Remediate hotlist findings for `src/Signals/StellaOps.Signals/StellaOps.Signals.csproj`; apply fixes, add tests, update audit tracker. |
| 9 | AUDIT-HOTLIST-SIGNALS-0001 | DONE | Applied 2026-01-13; audit tracker updated | Guild - Signals | Remediate hotlist findings for `src/Signals/StellaOps.Signals/StellaOps.Signals.csproj`; apply fixes, add tests, update audit tracker. |
| 10 | AUDIT-HOTLIST-SCANNER-LANG-DENO-0001 | DONE | Applied 2026-01-13; runtime hardening, determinism fixes, tests updated | Guild - Scanner | Remediate hotlist findings for `src/Scanner/__Libraries/StellaOps.Scanner.Analyzers.Lang.Deno/StellaOps.Scanner.Analyzers.Lang.Deno.csproj`; apply fixes, add tests, update audit tracker. |
| 11 | AUDIT-HOTLIST-VEXLENS-0001 | TODO | Approved 2026-01-12; Hotlist S1/M4/Q0 | Guild - VexLens | Remediate hotlist findings for `src/VexLens/StellaOps.VexLens/StellaOps.VexLens.csproj`; apply fixes, add tests, update audit tracker. |
| 12 | AUDIT-HOTLIST-CONCELIER-CORE-0001 | TODO | Approved 2026-01-12; Hotlist S1/M3/Q2 | Guild - Concelier | Remediate hotlist findings for `src/Concelier/__Libraries/StellaOps.Concelier.Core/StellaOps.Concelier.Core.csproj`; apply fixes, add tests, update audit tracker. |
| 11 | AUDIT-HOTLIST-VEXLENS-0001 | DONE | Applied 2026-01-13; audit tracker updated | Guild - VexLens | Remediate hotlist findings for `src/VexLens/StellaOps.VexLens/StellaOps.VexLens.csproj`; apply fixes, add tests, update audit tracker. |
| 12 | AUDIT-HOTLIST-CONCELIER-CORE-0001 | DONE | Applied 2026-01-13; audit tracker updated | Guild - Concelier | Remediate hotlist findings for `src/Concelier/__Libraries/StellaOps.Concelier.Core/StellaOps.Concelier.Core.csproj`; apply fixes, add tests, update audit tracker. |
| 13 | AUDIT-HOTLIST-SCANNER-REACHABILITY-0001 | DONE | Applied 2026-01-13; tracker updated | Guild - Scanner | Remediate hotlist findings for `src/Scanner/__Libraries/StellaOps.Scanner.Reachability/StellaOps.Scanner.Reachability.csproj`; apply fixes, add tests, update audit tracker. |
| 14 | AUDIT-HOTLIST-EVIDENCE-0001 | DONE | Applied 2026-01-13 | Guild - Core | Remediate hotlist findings for `src/__Libraries/StellaOps.Evidence/StellaOps.Evidence.csproj`; apply fixes, add tests, update audit tracker. |
| 15 | AUDIT-HOTLIST-ZASTAVA-OBSERVER-0001 | TODO | Approved 2026-01-12; Hotlist S1/M3/Q0 | Guild - Zastava | Remediate hotlist findings for `src/Zastava/StellaOps.Zastava.Observer/StellaOps.Zastava.Observer.csproj`; apply fixes, add tests, update audit tracker. |
| 16 | AUDIT-HOTLIST-TESTKIT-0001 | TODO | Approved 2026-01-12; Hotlist S0/M4/Q1 | Guild - Core | Remediate hotlist findings for `src/__Libraries/StellaOps.TestKit/StellaOps.TestKit.csproj`; apply fixes, add tests, update audit tracker. |
| 17 | AUDIT-HOTLIST-EXCITITOR-WORKER-0001 | TODO | Approved 2026-01-12; Hotlist S0/M4/Q1 | Guild - Excititor | Remediate hotlist findings for `src/Excititor/StellaOps.Excititor.Worker/StellaOps.Excititor.Worker.csproj`; apply fixes, add tests, update audit tracker. |
| 18 | AUDIT-HOTLIST-SCANNER-WORKER-0001 | TODO | Approved 2026-01-12; Hotlist S0/M4/Q1 | Guild - Scanner | Remediate hotlist findings for `src/Scanner/StellaOps.Scanner.Worker/StellaOps.Scanner.Worker.csproj`; apply fixes, add tests, update audit tracker. |
| 19 | AUDIT-HOTLIST-ROUTER-MICROSERVICE-0001 | TODO | Approved 2026-01-12; Hotlist S0/M4/Q0 | Guild - Router | Remediate hotlist findings for `src/Router/__Libraries/StellaOps.Microservice/StellaOps.Microservice.csproj`; apply fixes, add tests, update audit tracker. |
| 20 | AUDIT-HOTLIST-CONCELIER-WEBSERVICE-0001 | TODO | Approved 2026-01-12; Hotlist S0/M3/Q2 | Guild - Concelier | Remediate hotlist findings for `src/Concelier/StellaOps.Concelier.WebService/StellaOps.Concelier.WebService.csproj`; apply fixes, add tests, update audit tracker. |
| 21 | AUDIT-HOTLIST-PROVCACHE-0001 | TODO | Approved 2026-01-12; Hotlist S0/M3/Q1 | Guild - Core | Remediate hotlist findings for `src/__Libraries/StellaOps.Provcache/StellaOps.Provcache.csproj`; apply fixes, add tests, update audit tracker. |
| 22 | AUDIT-HOTLIST-EXCITITOR-CORE-0001 | TODO | Approved 2026-01-12; Hotlist Q2/S1/M2 | Guild - Excititor | Remediate hotlist findings for `src/Excititor/__Libraries/StellaOps.Excititor.Core/StellaOps.Excititor.Core.csproj`; apply fixes, add tests, update audit tracker. |
| 23 | AUDIT-HOTLIST-SBOMSERVICE-0001 | TODO | Approved 2026-01-12; Hotlist Q2/S1/M2 | Guild - SbomService | Remediate hotlist findings for `src/SbomService/StellaOps.SbomService/StellaOps.SbomService.csproj`; apply fixes, add tests, update audit tracker. |
| 15 | AUDIT-HOTLIST-ZASTAVA-OBSERVER-0001 | DONE | Applied 2026-01-13; tests updated | Guild - Zastava | Remediate hotlist findings for `src/Zastava/StellaOps.Zastava.Observer/StellaOps.Zastava.Observer.csproj`; apply fixes, add tests, update audit tracker. |
| 16 | AUDIT-HOTLIST-TESTKIT-0001 | DONE | Applied 2026-01-13; tests updated | Guild - Core | Remediate hotlist findings for `src/__Libraries/StellaOps.TestKit/StellaOps.TestKit.csproj`; apply fixes, add tests, update audit tracker. |
| 17 | AUDIT-HOTLIST-EXCITITOR-WORKER-0001 | DONE | Applied 2026-01-13; determinism, DI, tests | Guild - Excititor | Remediate hotlist findings for `src/Excititor/StellaOps.Excititor.Worker/StellaOps.Excititor.Worker.csproj`; apply fixes, add tests, update audit tracker. |
| 18 | AUDIT-HOTLIST-SCANNER-WORKER-0001 | DONE | Applied 2026-01-13; determinism, cancellation, DSSE | Guild - Scanner | Remediate hotlist findings for `src/Scanner/StellaOps.Scanner.Worker/StellaOps.Scanner.Worker.csproj`; apply fixes, add tests, update audit tracker. |
| 19 | AUDIT-HOTLIST-ROUTER-MICROSERVICE-0001 | DONE | Applied 2026-01-13; tracker updated | Guild - Router | Remediate hotlist findings for `src/Router/__Libraries/StellaOps.Microservice/StellaOps.Microservice.csproj`; apply fixes, add tests, update audit tracker. |
| 20 | AUDIT-HOTLIST-CONCELIER-WEBSERVICE-0001 | DONE | Applied 2026-01-13; TimeProvider defaults, ASCII cleanup, federation tests | Guild - Concelier | Remediate hotlist findings for `src/Concelier/StellaOps.Concelier.WebService/StellaOps.Concelier.WebService.csproj`; apply fixes, add tests, update audit tracker. |
| 21 | AUDIT-HOTLIST-PROVCACHE-0001 | DONE | Applied 2026-01-13; audit tracker updated | Guild - Core | Remediate hotlist findings for `src/__Libraries/StellaOps.Provcache/StellaOps.Provcache.csproj`; apply fixes, add tests, update audit tracker. |
| 22 | AUDIT-HOTLIST-EXCITITOR-CORE-0001 | BLOCKED | Blocked 2026-01-13; Excititor.Core files modified by another agent | Guild - Excititor | Remediate hotlist findings for `src/Excititor/__Libraries/StellaOps.Excititor.Core/StellaOps.Excititor.Core.csproj`; apply fixes, add tests, update audit tracker. |
| 23 | AUDIT-HOTLIST-SBOMSERVICE-0001 | BLOCKED | Blocked 2026-01-13; SbomService files modified by another agent | Guild - SbomService | Remediate hotlist findings for `src/SbomService/StellaOps.SbomService/StellaOps.SbomService.csproj`; apply fixes, add tests, update audit tracker. |
| 24 | AUDIT-HOTLIST-SCANNER-SBOMER-BUILDX-0001 | DONE | Applied 2026-01-13; Hotlist Q2/S1/M2 | Guild - Scanner | Remediate hotlist findings for `src/Scanner/StellaOps.Scanner.Sbomer.BuildXPlugin/StellaOps.Scanner.Sbomer.BuildXPlugin.csproj`; apply fixes, add tests, update audit tracker. |
| 25 | AUDIT-HOTLIST-ATTESTOR-WEBSERVICE-0001 | TODO | Approved 2026-01-12; Hotlist Q2/S0/M2 | Guild - Attestor | Remediate hotlist findings for `src/Attestor/StellaOps.Attestor/StellaOps.Attestor.WebService/StellaOps.Attestor.WebService.csproj`; apply fixes, add tests, update audit tracker. |
| 26 | AUDIT-HOTLIST-POLICY-TOOLS-0001 | TODO | Approved 2026-01-12; Hotlist Q2/S0/M1 | Guild - Policy | Remediate hotlist findings for `src/__Libraries/StellaOps.Policy.Tools/StellaOps.Policy.Tools.csproj`; apply fixes, add tests, update audit tracker. |
| 27 | AUDIT-HOTLIST-SCANNER-SOURCES-0001 | TODO | Approved 2026-01-12; Hotlist Q2/S0/M1 | Guild - Scanner | Remediate hotlist findings for `src/Scanner/__Libraries/StellaOps.Scanner.Sources/StellaOps.Scanner.Sources.csproj`; apply fixes, add tests, update audit tracker. |
| 28 | AUDIT-HOTLIST-BINARYINDEX-GOLDENSET-0001 | TODO | Approved 2026-01-12; Hotlist Q2/S0/M0 | Guild - BinaryIndex | Remediate hotlist findings for `src/BinaryIndex/__Libraries/StellaOps.BinaryIndex.GoldenSet/StellaOps.BinaryIndex.GoldenSet.csproj`; apply fixes, add tests, update audit tracker. |
| 29 | AUDIT-TESTGAP-DEVOPS-0001 | TODO | Approved 2026-01-12; Production Test Gap Inventory | Guild - DevOps | Add tests and references for:<br>`devops/services/crypto/sim-crypto-service/SimCryptoService.csproj`<br>`devops/services/crypto/sim-crypto-smoke/SimCryptoSmoke.csproj`<br>`devops/services/cryptopro/linux-csp-service/CryptoProLinuxApi.csproj`<br>`devops/tools/nuget-prime/nuget-prime.csproj`<br>`devops/tools/nuget-prime/nuget-prime-v9.csproj`. |
| 30 | AUDIT-TESTGAP-DOCS-0001 | TODO | Approved 2026-01-12; Production Test Gap Inventory | Guild - Docs | Add test scaffolding or formal waivers for:<br>`docs/dev/sdks/plugin-templates/StellaOps.Templates.csproj`<br>`docs/dev/sdks/plugin-templates/stellaops-plugin-connector/StellaOps.Plugin.MyConnector.csproj`<br>`docs/dev/sdks/plugin-templates/stellaops-plugin-scheduler/StellaOps.Plugin.MyJob.csproj`. |
| 25 | AUDIT-HOTLIST-ATTESTOR-WEBSERVICE-0001 | DONE | Applied 2026-01-13; feature gating + determinism + tests | Guild - Attestor | Remediate hotlist findings for `src/Attestor/StellaOps.Attestor/StellaOps.Attestor.WebService/StellaOps.Attestor.WebService.csproj`; apply fixes, add tests, update audit tracker. |
| 26 | AUDIT-HOTLIST-POLICY-TOOLS-0001 | DONE | Applied 2026-01-14; determinism + parsing guards + tests | Guild - Policy | Remediate hotlist findings for `src/__Libraries/StellaOps.Policy.Tools/StellaOps.Policy.Tools.csproj`; apply fixes, add tests, update audit tracker. |
| 27 | AUDIT-HOTLIST-SCANNER-SOURCES-0001 | DOING | Started 2026-01-14; Hotlist Q2/S0/M1 | Guild - Scanner | Remediate hotlist findings for `src/Scanner/__Libraries/StellaOps.Scanner.Sources/StellaOps.Scanner.Sources.csproj`; apply fixes, add tests, update audit tracker. |
| 28 | AUDIT-HOTLIST-BINARYINDEX-GOLDENSET-0001 | DONE | Applied 2026-01-13; tracker updated | Guild - BinaryIndex | Remediate hotlist findings for `src/BinaryIndex/__Libraries/StellaOps.BinaryIndex.GoldenSet/StellaOps.BinaryIndex.GoldenSet.csproj`; apply fixes, add tests, update audit tracker. |
| 29 | AUDIT-TESTGAP-DEVOPS-0001 | DONE | Applied 2026-01-13; tests added | Guild - DevOps | Add tests and references for:<br>`devops/services/crypto/sim-crypto-service/SimCryptoService.csproj`<br>`devops/services/crypto/sim-crypto-smoke/SimCryptoSmoke.csproj`<br>`devops/services/cryptopro/linux-csp-service/CryptoProLinuxApi.csproj`<br>`devops/tools/nuget-prime/nuget-prime.csproj`<br>`devops/tools/nuget-prime/nuget-prime-v9.csproj`. |
| 30 | AUDIT-TESTGAP-DOCS-0001 | DONE | Applied 2026-01-13; template tests added, template package waived | Guild - Docs | Add test scaffolding or formal waivers for:<br>`docs/dev/sdks/plugin-templates/StellaOps.Templates.csproj`<br>`docs/dev/sdks/plugin-templates/stellaops-plugin-connector/StellaOps.Plugin.MyConnector.csproj`<br>`docs/dev/sdks/plugin-templates/stellaops-plugin-scheduler/StellaOps.Plugin.MyJob.csproj`. |
| 31 | AUDIT-TESTGAP-CRYPTO-0001 | TODO | Approved 2026-01-12; Production Test Gap Inventory | Guild - Cryptography | Add tests for:<br>`src/__Libraries/StellaOps.Cryptography.Plugin.Pkcs11Gost/StellaOps.Cryptography.Plugin.Pkcs11Gost.csproj`<br>`src/__Libraries/StellaOps.Cryptography.Plugin.WineCsp/StellaOps.Cryptography.Plugin.WineCsp.csproj`<br>`src/__Libraries/StellaOps.Cryptography.Providers.OfflineVerification/StellaOps.Cryptography.Providers.OfflineVerification.csproj`<br>`src/Cryptography/StellaOps.Cryptography.Plugin.Eidas/StellaOps.Cryptography.Plugin.Eidas.csproj`<br>`src/Cryptography/StellaOps.Cryptography.Plugin.Fips/StellaOps.Cryptography.Plugin.Fips.csproj`<br>`src/Cryptography/StellaOps.Cryptography.Plugin.Gost/StellaOps.Cryptography.Plugin.Gost.csproj`<br>`src/Cryptography/StellaOps.Cryptography.Plugin.Hsm/StellaOps.Cryptography.Plugin.Hsm.csproj`<br>`src/Cryptography/StellaOps.Cryptography.Plugin.Sm/StellaOps.Cryptography.Plugin.Sm.csproj`<br>`src/Cryptography/StellaOps.Cryptography.Plugin/StellaOps.Cryptography.Plugin.csproj`<br>`src/Cryptography/StellaOps.Cryptography.Profiles.Ecdsa/StellaOps.Cryptography.Profiles.Ecdsa.csproj`<br>`src/Cryptography/StellaOps.Cryptography.Profiles.EdDsa/StellaOps.Cryptography.Profiles.EdDsa.csproj`<br>`src/Cryptography/StellaOps.Cryptography/StellaOps.Cryptography.csproj`. |
| 32 | AUDIT-TESTGAP-CORELIB-0001 | TODO | Approved 2026-01-12; Production Test Gap Inventory | Guild - Core | Add tests for:<br>`src/__Libraries/StellaOps.Infrastructure.EfCore/StellaOps.Infrastructure.EfCore.csproj`<br>`src/__Libraries/StellaOps.Interop/StellaOps.Interop.csproj`<br>`src/__Libraries/StellaOps.Orchestrator.Schemas/StellaOps.Orchestrator.Schemas.csproj`<br>`src/__Libraries/StellaOps.Policy.Tools/StellaOps.Policy.Tools.csproj`<br>`src/__Libraries/StellaOps.PolicyAuthoritySignals.Contracts/StellaOps.PolicyAuthoritySignals.Contracts.csproj`<br>`src/__Libraries/StellaOps.Provcache.Postgres/StellaOps.Provcache.Postgres.csproj`<br>`src/__Libraries/StellaOps.Provcache.Valkey/StellaOps.Provcache.Valkey.csproj`<br>`src/__Libraries/StellaOps.ReachGraph.Cache/StellaOps.ReachGraph.Cache.csproj`<br>`src/__Libraries/StellaOps.ReachGraph.Persistence/StellaOps.ReachGraph.Persistence.csproj`<br>`src/__Libraries/StellaOps.Signals.Contracts/StellaOps.Signals.Contracts.csproj`. |
| 33 | AUDIT-TESTGAP-ADVISORYAI-0001 | TODO | Approved 2026-01-12; Production Test Gap Inventory | Guild - AdvisoryAI | Add tests for:<br>`src/AdvisoryAI/StellaOps.AdvisoryAI.Plugin.Unified/StellaOps.AdvisoryAI.Plugin.Unified.csproj`<br>`src/AdvisoryAI/StellaOps.AdvisoryAI.Scm.Plugin.Unified/StellaOps.AdvisoryAI.Scm.Plugin.Unified.csproj`<br>`src/AdvisoryAI/StellaOps.AdvisoryAI.Worker/StellaOps.AdvisoryAI.Worker.csproj`. |
| 33 | AUDIT-TESTGAP-ADVISORYAI-0001 | DONE | Applied 2026-01-14; tests + deterministic jitter source | Guild - AdvisoryAI | Add tests for:<br>`src/AdvisoryAI/StellaOps.AdvisoryAI.Plugin.Unified/StellaOps.AdvisoryAI.Plugin.Unified.csproj`<br>`src/AdvisoryAI/StellaOps.AdvisoryAI.Scm.Plugin.Unified/StellaOps.AdvisoryAI.Scm.Plugin.Unified.csproj`<br>`src/AdvisoryAI/StellaOps.AdvisoryAI.Worker/StellaOps.AdvisoryAI.Worker.csproj`. |
| 34 | AUDIT-TESTGAP-AUTH-CONCELIER-ATTESTOR-0001 | TODO | Approved 2026-01-12; Production Test Gap Inventory | Guild - Module Leads | Add tests for:<br>`src/Attestor/StellaOps.Attestor.Types/Tools/StellaOps.Attestor.Types.Generator/StellaOps.Attestor.Types.Generator.csproj`<br>`src/Authority/StellaOps.Authority/StellaOps.Authority.Plugin.Unified/StellaOps.Authority.Plugin.Unified.csproj`<br>`src/Concelier/__Libraries/StellaOps.Concelier.ProofService/StellaOps.Concelier.ProofService.csproj`<br>`src/Concelier/StellaOps.Concelier.Plugin.Unified/StellaOps.Concelier.Plugin.Unified.csproj`. |
| 35 | AUDIT-TESTGAP-SERVICES-CORE-0001 | TODO | Approved 2026-01-12; Production Test Gap Inventory | Guild - Platform Services | Add tests for:<br>`src/EvidenceLocker/StellaOps.EvidenceLocker/StellaOps.EvidenceLocker.csproj`<br>`src/EvidenceLocker/StellaOps.EvidenceLocker/StellaOps.EvidenceLocker.Worker/StellaOps.EvidenceLocker.Worker.csproj`<br>`src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Worker/StellaOps.ExportCenter.Worker.csproj`<br>`src/Feedser/StellaOps.Feedser.BinaryAnalysis/StellaOps.Feedser.BinaryAnalysis.csproj`<br>`src/IssuerDirectory/StellaOps.IssuerDirectory/StellaOps.IssuerDirectory.Infrastructure/StellaOps.IssuerDirectory.Infrastructure.csproj`<br>`src/IssuerDirectory/StellaOps.IssuerDirectory/StellaOps.IssuerDirectory.WebService/StellaOps.IssuerDirectory.WebService.csproj`<br>`src/Notify/__Libraries/StellaOps.Notify.Storage.InMemory/StellaOps.Notify.Storage.InMemory.csproj`<br>`src/OpsMemory/StellaOps.OpsMemory.WebService/StellaOps.OpsMemory.WebService.csproj`<br>`src/Orchestrator/StellaOps.Orchestrator/StellaOps.Orchestrator.Worker/StellaOps.Orchestrator.Worker.csproj`<br>`src/PacksRegistry/StellaOps.PacksRegistry/StellaOps.PacksRegistry.Persistence.EfCore/StellaOps.PacksRegistry.Persistence.EfCore.csproj`<br>`src/PacksRegistry/StellaOps.PacksRegistry/StellaOps.PacksRegistry.Worker/StellaOps.PacksRegistry.Worker.csproj`. |
| 36 | AUDIT-TESTGAP-SERVICES-PLATFORM-0001 | TODO | Approved 2026-01-12; Production Test Gap Inventory | Guild - Platform Services | Add tests for:<br>`src/Policy/__Libraries/StellaOps.Policy.AuthSignals/StellaOps.Policy.AuthSignals.csproj`<br>`src/Policy/__Libraries/StellaOps.Policy.Explainability/StellaOps.Policy.Explainability.csproj`<br>`src/Policy/StellaOps.Policy.Registry/StellaOps.Policy.Registry.csproj`<br>`src/RiskEngine/StellaOps.RiskEngine/StellaOps.RiskEngine.Worker/StellaOps.RiskEngine.Worker.csproj`<br>`src/Scheduler/StellaOps.Scheduler.Worker.Host/StellaOps.Scheduler.Worker.Host.csproj`<br>`src/Signals/StellaOps.Signals.Scheduler/StellaOps.Signals.Scheduler.csproj`<br>`src/TaskRunner/StellaOps.TaskRunner/StellaOps.TaskRunner.Worker/StellaOps.TaskRunner.Worker.csproj`<br>`src/TimelineIndexer/StellaOps.TimelineIndexer/StellaOps.TimelineIndexer.WebService/StellaOps.TimelineIndexer.WebService.csproj`<br>`src/Unknowns/__Libraries/StellaOps.Unknowns.Persistence.EfCore/StellaOps.Unknowns.Persistence.EfCore.csproj`<br>`src/VexHub/__Libraries/StellaOps.VexHub.Persistence/StellaOps.VexHub.Persistence.csproj`<br>`src/VexLens/StellaOps.VexLens.Persistence/StellaOps.VexLens.Persistence.csproj`<br>`src/VexLens/StellaOps.VexLens.WebService/StellaOps.VexLens.WebService.csproj`. |
@@ -117,6 +117,34 @@
| 2026-01-13 | Started AUDIT-HOTLIST-EVIDENCE-0001 remediation work. | Project Mgmt |
| 2026-01-13 | Completed AUDIT-HOTLIST-EVIDENCE-0001 (determinism, schema validation, budgets, retention, tests). | Project Mgmt |
| 2026-01-13 | Started AUDIT-HOTLIST-EXPORTCENTER-CORE-0001 remediation work. | Project Mgmt |
| 2026-01-13 | Completed AUDIT-HOTLIST-CONCELIER-CORE-0001; determinism fixes and tests applied; audit trackers updated. | Project Mgmt |
| 2026-01-13 | Completed AUDIT-HOTLIST-SIGNALS-0001; revalidated fixes already in code, audit trackers updated. | Project Mgmt |
| 2026-01-13 | Completed AUDIT-HOTLIST-VEXLENS-0001; determinism defaults and tracker updates applied. | Project Mgmt |
| 2026-01-13 | Started AUDIT-HOTLIST-ZASTAVA-OBSERVER-0001 remediation work. | Project Mgmt |
| 2026-01-13 | Completed AUDIT-HOTLIST-ZASTAVA-OBSERVER-0001; TimeProvider retry-after, explicit timestamps, ASCII truncation, HttpClient injection, tests added, audit trackers updated. | Project Mgmt |
| 2026-01-13 | Started AUDIT-HOTLIST-TESTKIT-0001 remediation work. | Project Mgmt |
| 2026-01-13 | Completed AUDIT-HOTLIST-TESTKIT-0001; HttpClientFactory fixtures, TimeProvider request timestamps, ASCII cleanup, deterministic random, Task.Run removal, sync-over-async removal, tests added, audit trackers updated. | Project Mgmt |
| 2026-01-13 | Started AUDIT-HOTLIST-EXCITITOR-WORKER-0001 remediation work. | Project Mgmt |
| 2026-01-13 | Completed AUDIT-HOTLIST-EXCITITOR-WORKER-0001; determinism/DI fixes, plugin diagnostics, deterministic jitter/IDs, tests added; audit trackers updated. | Project Mgmt |
| 2026-01-13 | Completed AUDIT-HOTLIST-ROUTER-MICROSERVICE-0001; headers, request dispatch, schema direction, options validation, YAML parsing diagnostics, tests, and audit trackers updated. | Project Mgmt |
| 2026-01-13 | Completed AUDIT-HOTLIST-CONCELIER-WEBSERVICE-0001; TimeProvider defaults, ASCII cleanup, federation endpoint tests, audit trackers updated. | Project Mgmt |
| 2026-01-13 | Completed AUDIT-HOTLIST-BINARYINDEX-GOLDENSET-0001; newline determinism, TODO cleanup, and review workflow tests updated. | Project Mgmt |
| 2026-01-13 | Completed AUDIT-HOTLIST-SCANNER-WORKER-0001; determinism/cancellation, DSSE canon, test fixes; updated audit trackers and TASKS.md. | Project Mgmt |
| 2026-01-13 | Completed AUDIT-HOTLIST-PROVCACHE-0001; lazy fetch allowlist/timeout enforcement, canonical JSON signing, signature verification, options validation, and tests; audit trackers updated. | Project Mgmt |
| 2026-01-13 | Started AUDIT-TESTGAP-DEVOPS-0001 (devops service/tool test scaffolding). | Implementer |
| 2026-01-13 | Completed AUDIT-TESTGAP-DEVOPS-0001; added devops tests, AGENTS, and package versions. Tests: `dotnet test devops/services/crypto/sim-crypto-service/__Tests/SimCryptoService.Tests/SimCryptoService.Tests.csproj`, `dotnet test devops/services/crypto/sim-crypto-smoke/__Tests/SimCryptoSmoke.Tests/SimCryptoSmoke.Tests.csproj`, `dotnet test devops/services/cryptopro/linux-csp-service/__Tests/CryptoProLinuxApi.Tests/CryptoProLinuxApi.Tests.csproj`, `dotnet test devops/tools/nuget-prime/__Tests/NugetPrime.Tests/NugetPrime.Tests.csproj`. | Implementer |
| 2026-01-13 | Started AUDIT-TESTGAP-DOCS-0001 (plugin template test scaffolding). | Implementer |
| 2026-01-13 | Completed AUDIT-TESTGAP-DOCS-0001; added plugin template tests, waived template package, updated audit tracker. Tests: `dotnet test docs/dev/sdks/plugin-templates/stellaops-plugin-connector/__Tests/StellaOps.Plugin.MyConnector.Tests/StellaOps.Plugin.MyConnector.Tests.csproj`, `dotnet test docs/dev/sdks/plugin-templates/stellaops-plugin-scheduler/__Tests/StellaOps.Plugin.MyJob.Tests/StellaOps.Plugin.MyJob.Tests.csproj` (failed: template project references not present in repo). | Implementer |
| 2026-01-13 | Re-ran template tests after updating ProjectReference paths, package versions, and connector interface usage. Tests: `dotnet test docs/dev/sdks/plugin-templates/stellaops-plugin-connector/__Tests/StellaOps.Plugin.MyConnector.Tests/StellaOps.Plugin.MyConnector.Tests.csproj`, `dotnet test docs/dev/sdks/plugin-templates/stellaops-plugin-scheduler/__Tests/StellaOps.Plugin.MyJob.Tests/StellaOps.Plugin.MyJob.Tests.csproj`. | Implementer |
| 2026-01-13 | Blocked AUDIT-HOTLIST-EXCITITOR-CORE-0001; Excititor.Core files already modified by another agent. | Project Mgmt |
| 2026-01-13 | Blocked AUDIT-HOTLIST-SBOMSERVICE-0001; SbomService files already modified by another agent. | Project Mgmt |
| 2026-01-13 | Completed AUDIT-HOTLIST-ATTESTOR-WEBSERVICE-0001; feature gating filter, correlation ID provider, proof chain/verification summary fixes, tests updated. | Project Mgmt |
| 2026-01-13 | Started AUDIT-TESTGAP-ADVISORYAI-0001 (plugin/unified + worker tests, deterministic jitter source). | AdvisoryAI |
| 2026-01-14 | Completed AUDIT-TESTGAP-ADVISORYAI-0001; added adapter tests, worker cache tests, jitter source injection, and updated audit trackers. | AdvisoryAI |
| 2026-01-14 | Tests: `dotnet test src/AdvisoryAI/__Tests/StellaOps.AdvisoryAI.Tests/StellaOps.AdvisoryAI.Tests.csproj`. | AdvisoryAI |
| 2026-01-14 | Started AUDIT-HOTLIST-POLICY-TOOLS-0001 remediation work. | Project Mgmt |
| 2026-01-14 | Completed AUDIT-HOTLIST-POLICY-TOOLS-0001; LF schema output, fixed-time default, parsing guards, deterministic summary output, cancellation propagation, tests added. | Project Mgmt |
| 2026-01-14 | Started AUDIT-HOTLIST-SCANNER-SOURCES-0001 remediation work. | Project Mgmt |
## Decisions & Risks
- APPROVED 2026-01-12: All pending APPLY actions are approved for execution under module review gates.
@@ -125,6 +153,8 @@
- Backlog size (851 TODO APPLY items); mitigate by prioritizing hotlists then long-tail batches.
- Devops and docs items are in scope; cross-directory changes must be logged per sprint guidance.
- BLOCKED: AUDIT-HOTLIST-CLI-0001 requires edits in `src/Cli/__Tests/StellaOps.Cli.Tests` which are under active modification by another agent; defer until those changes land or ownership is coordinated.
- BLOCKED: AUDIT-HOTLIST-EXCITITOR-CORE-0001 is blocked because `src/Excititor/__Libraries/StellaOps.Excititor.Core` is under active modification by another agent.
- BLOCKED: AUDIT-HOTLIST-SBOMSERVICE-0001 is blocked because `src/SbomService/StellaOps.SbomService` is under active modification by another agent.
## Next Checkpoints
- TBD: Security hotlist remediation review.

View File

@@ -1,7 +1,12 @@
# Master Index 20260113 - OCI Layer-Level Binary Integrity Verification
# Sprint 20260113_000 - Master Index - OCI Binary Integrity
## Executive Summary
## Topic & Scope
- Coordinate four sprint batches implementing OCI layer-level image integrity verification with binary patch detection and evidence linking.
- Align Scanner, Attestor, Excititor, CLI, and Tools deliverables for DSSE attestations, VEX links, and validation corpus coverage.
- Provide a 25-30 point, 13-sprint plan with dependencies, metrics, and datasets for evidence-first security.
- **Working directory:** `docs/implplan`.
### Executive Summary
This master index coordinates four sprint batches implementing **OCI layer-level image integrity verification** with binary patch detection capabilities. The complete feature set enables:
1. **Multi-arch image inspection** with layer enumeration
@@ -13,10 +18,8 @@ This master index coordinates four sprint batches implementing **OCI layer-level
**Total Effort:** ~25-30 story points across 4 batches, 13 sprints
**Priority:** High (core differentiator for evidence-first security)
## Background
### Advisory Origin
### Background
#### Advisory Origin
The original product advisory specified requirements for:
> OCI layer-level image integrity verification that:
@@ -26,7 +29,7 @@ The original product advisory specified requirements for:
> - Maps findings to VEX with cryptographic evidence links
> - Validates against a curated "golden pairs" corpus
### Strategic Value
#### Strategic Value
| Capability | Business Value |
|------------|----------------|
@@ -35,19 +38,18 @@ The original product advisory specified requirements for:
| VEX evidence links | Deterministic, reproducible security decisions |
| Golden pairs validation | Confidence in detection accuracy |
## Sprint Batch Index
### Sprint Batch Index
| Batch | ID | Topic | Sprints | Status | Priority |
|-------|-----|-------|---------|--------|----------|
| 1 | 20260113_001 | ELF Section Hashes & Binary Diff Attestation | 4 | TODO | P0 |
| 2 | 20260113_002 | Image Index Resolution CLI | 3 | TODO | P1 |
| 3 | 20260113_003 | VEX Evidence Auto-Linking | 2 | TODO | P1 |
| 4 | 20260113_004 | Golden Pairs Pilot (Vendor Backport Corpus) | 3 | TODO | P2 |
| 1 | 20260113_001 | ELF Section Hashes and Binary Diff Attestation | 4 | DOING | P0 |
| 2 | 20260113_002 | Image Index Resolution CLI | 3 | DONE | P1 |
| 3 | 20260113_003 | VEX Evidence Auto-Linking | 2 | DONE | P1 |
| 4 | 20260113_004 | Golden Pairs Pilot (Vendor Backport Corpus) | 3 | BLOCKED | P2 |
## Batch Details
### Batch 001: ELF Section Hashes & Binary Diff Attestation
### Batch Details
#### Batch 001: ELF Section Hashes and Binary Diff Attestation
**Index:** [SPRINT_20260113_001_000_INDEX_binary_diff_attestation.md](SPRINT_20260113_001_000_INDEX_binary_diff_attestation.md)
**Scope:** Core binary analysis infrastructure
@@ -64,8 +66,7 @@ The original product advisory specified requirements for:
- `BinaryDiffV1` - In-toto predicate for diff attestations
- `SectionDelta` - Section comparison result
### Batch 002: Image Index Resolution CLI
#### Batch 002: Image Index Resolution CLI
**Index:** [SPRINT_20260113_002_000_INDEX_image_index_resolution.md](SPRINT_20260113_002_000_INDEX_image_index_resolution.md)
**Scope:** Multi-arch image inspection and layer enumeration
@@ -81,8 +82,7 @@ The original product advisory specified requirements for:
- `PlatformManifest` - Per-platform manifest info
- `LayerInfo` - Layer digest, size, media type
### Batch 003: VEX Evidence Auto-Linking
#### Batch 003: VEX Evidence Auto-Linking
**Index:** [SPRINT_20260113_003_000_INDEX_vex_evidence_linking.md](SPRINT_20260113_003_000_INDEX_vex_evidence_linking.md)
**Scope:** Automatic linking of VEX entries to binary diff evidence
@@ -96,8 +96,7 @@ The original product advisory specified requirements for:
- `VexEvidenceLink` - Link to evidence attestation
- `VexEvidenceLinkSet` - Multi-evidence aggregation
### Batch 004: Golden Pairs Pilot
#### Batch 004: Golden Pairs Pilot
**Index:** [SPRINT_20260113_004_000_INDEX_golden_pairs_pilot.md](SPRINT_20260113_004_000_INDEX_golden_pairs_pilot.md)
**Scope:** Validation dataset for binary patch detection
@@ -105,7 +104,7 @@ The original product advisory specified requirements for:
| Sprint | ID | Module | Topic | Key Deliverables |
|--------|-----|--------|-------|------------------|
| 1 | 004_001 | TOOLS | Golden Pairs Data Model | `GoldenPairMetadata`, JSON schema |
| 2 | 004_002 | TOOLS | Mirror & Diff Pipeline | Package mirror, diff validation |
| 2 | 004_002 | TOOLS | Mirror and Diff Pipeline | Package mirror, diff validation |
| 3 | 004_003 | TOOLS | Pilot CVE Corpus (3 CVEs) | Dirty Pipe, Baron Samedit, PrintNightmare |
**Target CVEs:**
@@ -113,45 +112,9 @@ The original product advisory specified requirements for:
- CVE-2021-3156 (Baron Samedit) - sudo
- CVE-2021-34527 (PrintNightmare) - Windows PE (conditional)
## Dependency Graph
```
+-----------------------------------------------------------------------------------+
| DEPENDENCY FLOW |
+-----------------------------------------------------------------------------------+
| |
| BATCH 001: Binary Diff Attestation |
| +------------------------------------------------------------------+ |
| | Sprint 001 (ELF Hashes) --> Sprint 002 (Predicate) --> Sprint 003 (CLI) |
| +------------------------------------------------------------------+ |
| | | |
| v v |
| BATCH 002: Image Index Resolution | |
| +--------------------------------+ | |
| | Sprint 001 --> Sprint 002 (CLI)| | |
| +--------------------------------+ | |
| | | |
| v v |
| BATCH 003: VEX Evidence Linking <------+ |
| +--------------------------------+ |
| | Sprint 001 (Linker) --> Sprint 002 (CLI) |
| +--------------------------------+ |
| |
| BATCH 004: Golden Pairs (Validation) - Can start in parallel with Batch 001 |
| +------------------------------------------------------------------+ |
| | Sprint 001 (Model) --> Sprint 002 (Pipeline) --> Sprint 003 (Corpus) |
| +------------------------------------------------------------------+ |
| | |
| v |
| Uses Batch 001 Sprint 001 (ELF Hashes) for validation |
| |
+-----------------------------------------------------------------------------------+
```
## Cross-Cutting Concerns
### Determinism Requirements
### Cross-Cutting Concerns
#### Determinism Requirements
All components must follow CLAUDE.md Section 8 determinism rules:
| Requirement | Implementation |
@@ -162,7 +125,7 @@ All components must follow CLAUDE.md Section 8 determinism rules:
| JSON | RFC 8785 canonical encoding for hashing |
| Hashes | SHA-256 lowercase hex, no prefix |
### DSSE/In-Toto Standards
#### DSSE and In-Toto Standards
| Standard | Version | Usage |
|----------|---------|-------|
@@ -171,7 +134,7 @@ All components must follow CLAUDE.md Section 8 determinism rules:
| BinaryDiffV1 | 1.0.0 | Custom predicate for binary diff attestations |
| Rekor | v1 | Optional transparency log integration |
### Test Requirements
#### Test Requirements
| Category | Coverage |
|----------|----------|
@@ -180,9 +143,9 @@ All components must follow CLAUDE.md Section 8 determinism rules:
| Determinism | Identical inputs produce identical outputs |
| Golden | Validation against known-good corpus |
## File Manifest
### File Manifest
### Sprint Files
#### Sprint Files
```
docs/implplan/
@@ -213,7 +176,7 @@ docs/implplan/
+-- SPRINT_20260113_004_003_TOOLS_pilot_corpus.md
```
### Schema Files
#### Schema Files
```
docs/schemas/
@@ -222,7 +185,7 @@ docs/schemas/
+-- golden-pairs-index.schema.json # Corpus index (Batch 004)
```
### Source Directories
#### Source Directories
```
src/
@@ -255,9 +218,9 @@ datasets/
+-- CVE-2021-3156/
```
## Success Metrics
### Success Metrics
### Functional Metrics
#### Functional Metrics
| Metric | Target |
|--------|--------|
@@ -266,7 +229,7 @@ datasets/
| Attestation verification | 100% pass Rekor/in-toto validation |
| VEX evidence link coverage | >= 90% of applicable entries |
### Performance Metrics
#### Performance Metrics
| Metric | Target |
|--------|--------|
@@ -274,7 +237,7 @@ datasets/
| Binary diff comparison | < 500ms per pair |
| Image index resolution | < 2s for multi-arch images |
## Risk Register
### Risk Register
| Risk | Likelihood | Impact | Mitigation |
|------|------------|--------|------------|
@@ -283,9 +246,9 @@ datasets/
| Package archive availability | Medium | High | Cache packages locally |
| Cross-platform DSSE signing | Low | Medium | Use portable signing libraries |
## Execution Schedule
### Execution Schedule
### Recommended Order
#### Recommended Order
1. **Week 1-2:** Batch 001 Sprints 1-2 (ELF hashes, predicate)
2. **Week 2-3:** Batch 002 Sprint 1 (image inspector) + Batch 004 Sprint 1 (data model)
@@ -293,22 +256,77 @@ datasets/
4. **Week 4-5:** Batch 003 (VEX linking) + Batch 004 Sprint 2 (pipeline)
5. **Week 5-6:** Documentation sprints + Batch 004 Sprint 3 (corpus)
### Parallelization Opportunities
#### Parallelization Opportunities
- Batch 004 Sprint 1 can start immediately (no dependencies)
- Documentation sprints can run in parallel with implementation
- Batch 002 Sprint 1 can start after Batch 001 Sprint 1
## Execution Log
## Dependencies & Concurrency
- Batch dependencies are captured in the batch index files; Batch 001 Sprint 001 is the earliest gating sprint.
- Batch 004 can start in parallel with Batch 001; documentation sprints can run in parallel with implementation work.
- Other 20260113_000 planning documents are index-only, so parallel edits remain safe.
```
+-----------------------------------------------------------------------------------+
| DEPENDENCY FLOW |
+-----------------------------------------------------------------------------------+
| |
| BATCH 001: Binary Diff Attestation |
| +------------------------------------------------------------------+ |
| | Sprint 001 (ELF Hashes) -> Sprint 002 (Predicate) -> Sprint 003 (CLI) |
| +------------------------------------------------------------------+ |
| | | |
| v v |
| BATCH 002: Image Index Resolution | |
| +--------------------------------+ | |
| | Sprint 001 -> Sprint 002 (CLI) | | |
| +--------------------------------+ | |
| | | |
| v v |
| BATCH 003: VEX Evidence Linking <------+ |
| +--------------------------------+ |
| | Sprint 001 (Linker) -> Sprint 002 (CLI) |
| +--------------------------------+ |
| |
| BATCH 004: Golden Pairs (Validation) - Can start in parallel with Batch 001 |
| +------------------------------------------------------------------+ |
| | Sprint 001 (Model) -> Sprint 002 (Pipeline) -> Sprint 003 (Corpus) |
| +------------------------------------------------------------------+ |
| | |
| v |
| Uses Batch 001 Sprint 001 (ELF Hashes) for validation |
| |
+-----------------------------------------------------------------------------------+
```
## Documentation Prerequisites
- `docs/README.md`
- `docs/07_HIGH_LEVEL_ARCHITECTURE.md`
- `docs/modules/platform/architecture-overview.md`
- `docs/modules/scanner/architecture.md`
- `docs/modules/attestor/architecture.md`
- `docs/modules/cli/architecture.md`
- `docs/modules/excititor/architecture.md`
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| 1 | INDEX-20260113-000-01 | DONE | None | Project Mgmt | Normalize master index to standard sprint template and ASCII-only formatting. |
| 2 | INDEX-20260113-000-02 | DONE | None | Project Mgmt | Verify batch index links and file manifest entries remain consistent. |
## Execution Log
| Date (UTC) | Update | Owner |
|------------|--------|-------|
| --- | --- | --- |
| 2026-01-13 | Master index created from product advisory analysis. | Project Mgmt |
| 2026-01-13 | Batch 001 INDEX already existed; added to master index. | Project Mgmt |
| 2026-01-13 | Batches 002, 003, 004 sprint files created. | Project Mgmt |
| 2026-01-13 | Normalized sprint file to standard template; ASCII-only cleanup; no semantic changes. | Project Mgmt |
| 2026-01-13 | Batch 001 CLI and Docs sprints completed; remaining batch work in progress. | CLI + Docs |
| 2026-01-13 | Batch 002 sprints completed (image inspection service, CLI, docs). | Scanner + CLI + Docs |
| 2026-01-13 | Batch 003 completed; Batch 004 data model and pipeline done; pilot corpus blocked. | Excititor + CLI + Tools |
## Decisions & Risks
- **APPROVED 2026-01-13**: Four-batch structure covering full advisory scope.
- **APPROVED 2026-01-13**: ELF-first approach; PE support conditional on Batch 001 progress.
- **APPROVED 2026-01-13**: Golden pairs stored in datasets/, not git LFS initially.
@@ -317,7 +335,6 @@ datasets/
- **RISK**: Kernel binaries are large; may need to extract specific modules.
## Next Checkpoints
- Batch 001 complete -> Core binary diff infrastructure operational
- Batch 002 complete -> Multi-arch image inspection available
- Batch 003 complete -> VEX entries include evidence links
@@ -325,7 +342,6 @@ datasets/
- All batches complete -> Full OCI layer-level integrity verification operational
## References
- [OCI Image Index Specification](https://github.com/opencontainers/image-spec/blob/main/image-index.md)
- [DSSE Specification](https://github.com/secure-systems-lab/dsse)
- [In-Toto Attestation Framework](https://github.com/in-toto/attestation)

View File

@@ -1,174 +0,0 @@
# Sprint Batch 20260113_001 - Binary Diff Attestation (ELF Section Hashes)
## Executive Summary
This sprint batch implements **targeted enhancements** for binary-level image integrity verification, focusing on ELF section-level hashing for vendor backport detection and DSSE-signed attestations for binary diffs. This addresses the genuine gaps identified in the OCI Layer-Level Image Integrity advisory analysis while avoiding redundant work on already-implemented capabilities.
**Scope:** ELF-only (PE/Mach-O deferred to M2+)
**Effort Estimate:** 5-7 story points across 4 sprints
**Priority:** Medium (enhancement, not blocking)
## Background
### Advisory Analysis Summary
The original product advisory proposed comprehensive OCI layer-level verification capabilities. Analysis revealed:
| Category | Coverage |
|----------|----------|
| **Already Implemented** | ~80% (OCI manifest parsing, layer SBOM fragmentation, DSSE pipeline, VEX emission) |
| **Partial Overlap** | ~15% (ELF symbols exist, section hashes missing) |
| **Genuine Gaps** | ~5% (section hashes, BinaryDiffV1 predicate, CLI diff verb) |
This batch addresses only the genuine gaps to maximize value while avoiding redundant effort.
### Existing Capabilities (No Work Needed)
- OCI manifest/index parsing with Docker & OCI media types
- Per-layer SBOM fragmentation with three-way diff
- DSSE envelope creation → Attestor → Rekor pipeline
- VEX emission with trust scoring and evidence links
- ELF Build-ID, symbol table parsing, link graph analysis
### New Capabilities (This Batch)
1. **ELF Section Hash Extractor** - SHA-256 per `.text`, `.rodata`, `.data`, `.symtab` sections
2. **BinaryDiffV1 In-Toto Predicate** - Schema for binary-level diff attestations
3. **CLI `stella scan diff --mode=elf`** - Binary-section-level diff with DSSE output
4. **Documentation** - Architecture docs and CLI reference updates
## Sprint Index
| Sprint | ID | Module | Topic | Status | Owner |
|--------|-----|--------|-------|--------|-------|
| 1 | SPRINT_20260113_001_001 | SCANNER | ELF Section Hash Extractor | TODO | Guild - Scanner |
| 2 | SPRINT_20260113_001_002 | ATTESTOR | BinaryDiffV1 In-Toto Predicate | TODO | Guild - Attestor |
| 3 | SPRINT_20260113_001_003 | CLI | Binary Diff Command Enhancement | TODO | Guild - CLI |
| 4 | SPRINT_20260113_001_004 | DOCS | Documentation & Architecture | TODO | Guild - Docs |
## Dependencies
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ Dependency Graph │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ Sprint 1 (ELF Section Hashes) │
│ │ │
│ ├──────────────────┐ │
│ ▼ ▼ │
│ Sprint 2 (Predicate) Sprint 4 (Docs) │
│ │ │ │
│ ▼ │ │
│ Sprint 3 (CLI) ─────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
```
- **Sprint 1** is foundational (no dependencies)
- **Sprint 2** depends on Sprint 1 (uses section hash models)
- **Sprint 3** depends on Sprint 1 & 2 (consumes extractor and predicate)
- **Sprint 4** can proceed in parallel with Sprints 2-3
## Acceptance Criteria (Batch-Level)
### Must Have
1. **Section Hash Extraction**
- Compute SHA-256 for `.text`, `.rodata`, `.data`, `.symtab` ELF sections
- Deterministic output (stable ordering, canonical JSON)
- Evidence properties in SBOM components
2. **BinaryDiffV1 Predicate**
- In-toto compliant predicate schema
- Subjects: image@digest, platform
- Inputs: base/target manifests
- Findings: per-path section deltas
3. **CLI Integration**
- `stella scan diff --mode=elf` produces binary-section-level diff
- `--emit-dsse=<dir>` outputs signed attestations
- Human-readable and JSON output formats
4. **Documentation**
- Architecture doc under `docs/modules/scanner/`
- CLI reference updates
- Predicate schema specification
### Should Have
- Confidence scoring for section hash matches (0.0-1.0)
- Integration with existing VEX evidence blocks
### Deferred (Out of Scope)
- PE/Mach-O section analysis (M2)
- Vendor backport corpus and 95% precision target (follow-up sprint)
- `ctr images export` integration (use existing OCI blob pull)
- Multi-platform diff in single invocation
## Technical Context
### Key Files to Extend
| Component | File | Purpose |
|-----------|------|---------|
| ELF Analysis | `src/Scanner/StellaOps.Scanner.Analyzers.Native/Hardening/ElfHardeningExtractor.cs` | Add section hash extraction |
| Native Models | `src/Scanner/__Libraries/StellaOps.Scanner.Contracts/CallGraphModels.cs` | Section hash models |
| DSSE Signing | `src/Scanner/__Libraries/StellaOps.Scanner.Reachability/Witnesses/WitnessDsseSigner.cs` | Pattern for BinaryDiffSigner |
| Predicates | `src/Attestor/__Libraries/StellaOps.Attestor.StandardPredicates/` | Add BinaryDiffV1 |
| CLI | `src/Cli/StellaOps.Cli/Commands/` | Add diff subcommand |
### Determinism Requirements
Per CLAUDE.md Section 8:
1. **TimeProvider injection** - No `DateTime.UtcNow` calls
2. **Stable ordering** - Section hashes sorted by section name
3. **Canonical JSON** - RFC 8785 for digest computation
4. **InvariantCulture** - All formatting/parsing
5. **DSSE PAE compliance** - Use shared `DsseHelper`
## Risk Assessment
| Risk | Likelihood | Impact | Mitigation |
|------|------------|--------|------------|
| Section hash instability across compilers | Medium | High | Document compiler/flag assumptions; use position-independent matching as fallback |
| ELF parsing edge cases | Low | Medium | Comprehensive test fixtures; existing ELF library handles most cases |
| CLI integration conflicts | Low | Low | CLI tests blocked by other agent; coordinate ownership |
## Success Metrics
- [ ] All unit tests pass (100% of new code covered)
- [ ] Integration tests with synthetic ELF fixtures pass
- [ ] CLI help and completions work
- [ ] Documentation builds without warnings
- [ ] No regressions in existing Scanner tests
## Documentation Prerequisites
Before starting implementation, reviewers must read:
- `docs/README.md`
- `docs/ARCHITECTURE_REFERENCE.md`
- `docs/modules/scanner/architecture.md` (if exists)
- `CLAUDE.md` Section 8 (Code Quality & Determinism Rules)
- `src/Scanner/StellaOps.Scanner.Analyzers.Native/AGENTS.md` (if exists)
## Execution Log
| Date (UTC) | Update | Owner |
|------------|--------|-------|
| 2026-01-13 | Sprint batch created from advisory analysis; 4 sprints defined. | Project Mgmt |
## Decisions & Risks
- **APPROVED 2026-01-13**: Scope limited to ELF-only; PE/Mach-O deferred to M2.
- **APPROVED 2026-01-13**: 80% precision target for initial release; 95% deferred to corpus sprint.
- **RISK**: CLI tests currently blocked by other agent work; Sprint 3 may need coordination.
## Next Checkpoints
- Sprint 1 completion → Sprint 2 & 4 can start
- Sprint 2 completion → Sprint 3 can start
- All sprints complete → Integration testing checkpoint

View File

@@ -1,234 +0,0 @@
# Sprint 20260113_001_001_SCANNER - ELF Section Hash Extractor
## Topic & Scope
- Implement per-section SHA-256 hash extraction for ELF binaries
- Target sections: `.text`, `.rodata`, `.data`, `.symtab`, `.dynsym`
- Integrate with existing `ElfHardeningExtractor` infrastructure
- Expose section hashes as SBOM component evidence properties
- **Working directory:** `src/Scanner/StellaOps.Scanner.Analyzers.Native/`
## Dependencies & Concurrency
- No blocking dependencies (foundational sprint)
- Parallel work safe within Scanner.Native module
- Sprint 2 (BinaryDiffV1 predicate) depends on this sprint's models
## Documentation Prerequisites
- `docs/README.md`
- `docs/ARCHITECTURE_REFERENCE.md`
- `CLAUDE.md` Section 8 (Determinism Rules)
- `src/Scanner/StellaOps.Scanner.Analyzers.Native/AGENTS.md` (if exists)
- ELF specification reference (https://refspecs.linuxfoundation.org/elf/elf.pdf)
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
|---|---------|--------|---------------------------|--------|-----------------|
| 1 | ELF-SECTION-MODELS-0001 | TODO | None | Guild - Scanner | Define `ElfSectionHash` and `ElfSectionHashSet` models in `src/Scanner/__Libraries/StellaOps.Scanner.Contracts/`. Include section name, offset, size, SHA-256 hash, and optional BLAKE3 hash. |
| 2 | ELF-SECTION-EXTRACTOR-0001 | TODO | Depends on ELF-SECTION-MODELS-0001 | Guild - Scanner | Implement `ElfSectionHashExtractor` class that reads ELF sections and computes per-section hashes. Integrate with existing ELF parsing in `ElfHardeningExtractor`. |
| 3 | ELF-SECTION-CONFIG-0001 | TODO | Depends on ELF-SECTION-EXTRACTOR-0001 | Guild - Scanner | Add configuration options for section hash extraction: enabled/disabled, section allowlist, hash algorithms. Use `IOptions<T>` with `ValidateOnStart`. |
| 4 | ELF-SECTION-EVIDENCE-0001 | TODO | Depends on ELF-SECTION-EXTRACTOR-0001 | Guild - Scanner | Emit section hashes as SBOM component `properties[]` with keys: `evidence:section:<name>:sha256`, `evidence:section:<name>:blake3`, `evidence:section:<name>:size`. |
| 5 | ELF-SECTION-DI-0001 | TODO | Depends on all above | Guild - Scanner | Register `ElfSectionHashExtractor` in `ServiceCollectionExtensions.cs`. Ensure `TimeProvider` and `IGuidGenerator` are injected for determinism. |
| 6 | ELF-SECTION-TESTS-0001 | TODO | Depends on all above | Guild - Scanner | Add unit tests in `src/Scanner/__Tests/StellaOps.Scanner.Analyzers.Native.Tests/` covering: valid ELF with all sections, stripped ELF (missing symtab), malformed ELF, empty sections, large binaries. |
| 7 | ELF-SECTION-FIXTURES-0001 | TODO | Depends on ELF-SECTION-TESTS-0001 | Guild - Scanner | Create synthetic ELF test fixtures under `src/Scanner/__Tests/__Datasets/elf-section-hashes/` with known section contents for golden hash verification. |
| 8 | ELF-SECTION-DETERMINISM-0001 | TODO | Depends on all above | Guild - Scanner | Add determinism regression test: same ELF input produces identical section hashes across runs. Use `FakeTimeProvider` and fixed GUID generator. |
## Technical Specification
### ElfSectionHash Model
```csharp
namespace StellaOps.Scanner.Contracts;
/// <summary>
/// Represents a cryptographic hash of an ELF section.
/// </summary>
public sealed record ElfSectionHash
{
/// <summary>Section name (e.g., ".text", ".rodata").</summary>
public required string Name { get; init; }
/// <summary>Section offset in file.</summary>
public required long Offset { get; init; }
/// <summary>Section size in bytes.</summary>
public required long Size { get; init; }
/// <summary>SHA-256 hash of section contents (lowercase hex).</summary>
public required string Sha256 { get; init; }
/// <summary>Optional BLAKE3-256 hash of section contents (lowercase hex).</summary>
public string? Blake3 { get; init; }
/// <summary>Section type from ELF header.</summary>
public required ElfSectionType SectionType { get; init; }
/// <summary>Section flags from ELF header.</summary>
public required ElfSectionFlags Flags { get; init; }
}
/// <summary>
/// Collection of section hashes for a single ELF binary.
/// </summary>
public sealed record ElfSectionHashSet
{
/// <summary>Path to the ELF binary.</summary>
public required string FilePath { get; init; }
/// <summary>SHA-256 hash of the entire file.</summary>
public required string FileHash { get; init; }
/// <summary>Build-ID from .note.gnu.build-id if present.</summary>
public string? BuildId { get; init; }
/// <summary>Section hashes, sorted by section name.</summary>
public required ImmutableArray<ElfSectionHash> Sections { get; init; }
/// <summary>Extraction timestamp (UTC ISO-8601).</summary>
public required DateTimeOffset ExtractedAt { get; init; }
/// <summary>Extractor version for reproducibility.</summary>
public required string ExtractorVersion { get; init; }
}
```
### Extractor Interface
```csharp
namespace StellaOps.Scanner.Analyzers.Native;
public interface IElfSectionHashExtractor
{
/// <summary>
/// Extracts section hashes from an ELF binary.
/// </summary>
/// <param name="elfPath">Path to the ELF file.</param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>Section hash set, or null if not a valid ELF.</returns>
Task<ElfSectionHashSet?> ExtractAsync(
string elfPath,
CancellationToken cancellationToken = default);
/// <summary>
/// Extracts section hashes from ELF bytes in memory.
/// </summary>
Task<ElfSectionHashSet?> ExtractFromBytesAsync(
ReadOnlyMemory<byte> elfBytes,
string virtualPath,
CancellationToken cancellationToken = default);
}
```
### Target Sections
| Section | Purpose | Backport Relevance |
|---------|---------|-------------------|
| `.text` | Executable code | **High** - patched functions change this |
| `.rodata` | Read-only data | Medium - string constants may change |
| `.data` | Initialized data | Low - rarely changes for patches |
| `.symtab` | Symbol table | **High** - function signatures |
| `.dynsym` | Dynamic symbols | **High** - exported API |
| `.gnu.hash` | GNU hash table | Low - derived from symbols |
### SBOM Evidence Properties
```json
{
"type": "library",
"name": "libssl.so.3",
"properties": [
{"name": "evidence:build-id", "value": "abc123..."},
{"name": "evidence:section:.text:sha256", "value": "e3b0c442..."},
{"name": "evidence:section:.text:size", "value": "1048576"},
{"name": "evidence:section:.rodata:sha256", "value": "d7a8fbb3..."},
{"name": "evidence:section:.symtab:sha256", "value": "9f86d081..."},
{"name": "evidence:section-set:sha256", "value": "combined_hash..."},
{"name": "evidence:extractor-version", "value": "1.0.0"}
]
}
```
### Determinism Requirements
1. **Ordering**: Sections sorted lexicographically by name
2. **Hash format**: Lowercase hexadecimal, no prefix
3. **Timestamps**: From injected `TimeProvider.GetUtcNow()`
4. **Version string**: Assembly version or build metadata
5. **JSON serialization**: RFC 8785 canonical for any digest computation
### Configuration Schema
```yaml
scanner:
native:
sectionHashes:
enabled: true
algorithms:
- sha256
- blake3 # optional
sections:
- .text
- .rodata
- .data
- .symtab
- .dynsym
maxSectionSize: 104857600 # 100MB limit per section
```
## Test Cases
### Unit Tests
| Test | Description | Expected |
|------|-------------|----------|
| `ExtractAsync_ValidElf_ReturnsAllSections` | Standard ELF with all target sections | All 5 sections extracted with valid hashes |
| `ExtractAsync_StrippedElf_OmitsSymtab` | Stripped binary without .symtab | Only .text, .rodata, .data returned |
| `ExtractAsync_InvalidElf_ReturnsNull` | Non-ELF file (PE, Mach-O, random) | Returns null, no exception |
| `ExtractAsync_EmptySection_ReturnsEmptyHash` | ELF with zero-size .data | Hash of empty content (`e3b0c442...`) |
| `ExtractAsync_LargeSection_RespectsLimit` | Section > maxSectionSize | Section skipped or truncated per config |
| `ExtractAsync_Deterministic_SameOutput` | Same ELF, multiple runs | Identical `ElfSectionHashSet` |
| `ExtractFromBytesAsync_SameAsFile` | Memory vs file extraction | Identical results |
### Integration Tests
| Test | Description | Expected |
|------|-------------|----------|
| `LayerAnalysis_ElfWithSections_EmitsEvidence` | Container layer with ELF binaries | SBOM components have section hash properties |
| `Diff_SameBinaryDifferentPatch_DetectsSectionChange` | Two builds with backport | `.text` hash differs, other sections same |
### Fixtures
Create under `src/Scanner/__Tests/__Datasets/elf-section-hashes/`:
```
elf-section-hashes/
├── README.md # Fixture documentation
├── standard-amd64.elf # Standard ELF with all sections
├── standard-amd64.golden.json # Expected section hashes
├── stripped-amd64.elf # Stripped binary
├── stripped-amd64.golden.json
├── minimal-arm64.elf # Minimal ELF (few sections)
├── minimal-arm64.golden.json
└── corrupt.bin # Invalid ELF magic
```
## Execution Log
| Date (UTC) | Update | Owner |
|------------|--------|-------|
| 2026-01-13 | Sprint created from advisory analysis. | Project Mgmt |
## Decisions & Risks
- **APPROVED**: SHA-256 as primary hash; BLAKE3 optional for performance.
- **APPROVED**: 100MB per-section limit to prevent memory exhaustion.
- **RISK**: Some ELF parsers may handle edge cases differently; use LibObjectFile or similar well-tested library.
- **RISK**: Section ordering may vary by toolchain; normalize by sorting.
## Next Checkpoints
- Task 1-2 complete → Models and extractor ready for integration
- Task 6-8 complete → Sprint can be marked DONE
- Unblock Sprint 2 (BinaryDiffV1 predicate)

View File

@@ -1,441 +0,0 @@
# Sprint 20260113_001_002_ATTESTOR - BinaryDiffV1 In-Toto Predicate
## Topic & Scope
- Define `BinaryDiffV1` in-toto predicate schema for binary-level diff attestations
- Implement predicate builder and serializer
- Integrate with existing DSSE signing infrastructure
- Support both ELF section diffs and future PE/Mach-O extensions
- **Working directory:** `src/Attestor/__Libraries/StellaOps.Attestor.StandardPredicates/`
## Dependencies & Concurrency
- **Depends on:** Sprint 001 (ELF Section Hash models)
- Parallel work safe within Attestor module
- Sprint 3 (CLI) depends on this sprint
## Documentation Prerequisites
- `docs/README.md`
- `docs/ARCHITECTURE_REFERENCE.md`
- `CLAUDE.md` Section 8 (Determinism Rules)
- in-toto attestation specification (https://github.com/in-toto/attestation/blob/main/spec/v1/statement.md)
- DSSE envelope specification (https://github.com/secure-systems-lab/dsse/blob/master/envelope.md)
- Existing predicates: `src/Attestor/__Libraries/StellaOps.Attestor.StandardPredicates/`
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
|---|---------|--------|---------------------------|--------|-----------------|
| 1 | BINARYDIFF-SCHEMA-0001 | TODO | Sprint 001 models | Guild - Attestor | Define `BinaryDiffV1` predicate schema with JSON Schema and C# models. Include subjects, inputs, findings, and verification materials. |
| 2 | BINARYDIFF-MODELS-0001 | TODO | Depends on BINARYDIFF-SCHEMA-0001 | Guild - Attestor | Implement C# record types for `BinaryDiffPredicate`, `BinaryDiffSubject`, `BinaryDiffInput`, `BinaryDiffFinding`, `SectionDelta`. |
| 3 | BINARYDIFF-BUILDER-0001 | TODO | Depends on BINARYDIFF-MODELS-0001 | Guild - Attestor | Implement `BinaryDiffPredicateBuilder` with fluent API for constructing predicates from section hash comparisons. |
| 4 | BINARYDIFF-SERIALIZER-0001 | TODO | Depends on BINARYDIFF-MODELS-0001 | Guild - Attestor | Implement canonical JSON serialization using RFC 8785. Register with existing `IPredicateSerializer` infrastructure. |
| 5 | BINARYDIFF-SIGNER-0001 | TODO | Depends on all above | Guild - Attestor | Implement `BinaryDiffDsseSigner` following `WitnessDsseSigner` pattern. Payload type: `stellaops.binarydiff.v1`. |
| 6 | BINARYDIFF-VERIFIER-0001 | TODO | Depends on BINARYDIFF-SIGNER-0001 | Guild - Attestor | Implement `BinaryDiffDsseVerifier` for signature and schema validation. |
| 7 | BINARYDIFF-DI-0001 | TODO | Depends on all above | Guild - Attestor | Register all services in DI. Add `IOptions<BinaryDiffOptions>` for configuration. |
| 8 | BINARYDIFF-TESTS-0001 | TODO | Depends on all above | Guild - Attestor | Add comprehensive unit tests covering: schema validation, serialization round-trip, signing/verification, edge cases (empty findings, large diffs). |
| 9 | BINARYDIFF-JSONSCHEMA-0001 | TODO | Depends on BINARYDIFF-SCHEMA-0001 | Guild - Attestor | Publish JSON Schema to `docs/schemas/binarydiff-v1.schema.json` for external validation. |
## Technical Specification
### Predicate Type
```
stellaops.binarydiff.v1
```
### BinaryDiffV1 Schema
```json
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://stellaops.io/schemas/binarydiff-v1.schema.json",
"title": "BinaryDiffV1",
"description": "In-toto predicate for binary-level diff attestations",
"type": "object",
"required": ["predicateType", "subjects", "inputs", "findings", "metadata"],
"properties": {
"predicateType": {
"const": "stellaops.binarydiff.v1"
},
"subjects": {
"type": "array",
"items": { "$ref": "#/$defs/BinaryDiffSubject" },
"minItems": 1
},
"inputs": {
"$ref": "#/$defs/BinaryDiffInputs"
},
"findings": {
"type": "array",
"items": { "$ref": "#/$defs/BinaryDiffFinding" }
},
"metadata": {
"$ref": "#/$defs/BinaryDiffMetadata"
}
},
"$defs": {
"BinaryDiffSubject": {
"type": "object",
"required": ["name", "digest"],
"properties": {
"name": {
"type": "string",
"description": "Image reference (e.g., docker://repo/app@sha256:...)"
},
"digest": {
"type": "object",
"additionalProperties": { "type": "string" }
},
"platform": {
"$ref": "#/$defs/Platform"
}
}
},
"BinaryDiffInputs": {
"type": "object",
"required": ["base", "target"],
"properties": {
"base": { "$ref": "#/$defs/ImageReference" },
"target": { "$ref": "#/$defs/ImageReference" }
}
},
"ImageReference": {
"type": "object",
"required": ["digest"],
"properties": {
"reference": { "type": "string" },
"digest": { "type": "string" },
"manifestDigest": { "type": "string" },
"platform": { "$ref": "#/$defs/Platform" }
}
},
"Platform": {
"type": "object",
"properties": {
"os": { "type": "string" },
"architecture": { "type": "string" },
"variant": { "type": "string" }
}
},
"BinaryDiffFinding": {
"type": "object",
"required": ["path", "changeType", "binaryFormat"],
"properties": {
"path": {
"type": "string",
"description": "File path within the image filesystem"
},
"changeType": {
"enum": ["added", "removed", "modified", "unchanged"]
},
"binaryFormat": {
"enum": ["elf", "pe", "macho", "unknown"]
},
"layerDigest": {
"type": "string",
"description": "Layer that introduced this change"
},
"baseHashes": {
"$ref": "#/$defs/SectionHashSet"
},
"targetHashes": {
"$ref": "#/$defs/SectionHashSet"
},
"sectionDeltas": {
"type": "array",
"items": { "$ref": "#/$defs/SectionDelta" }
},
"confidence": {
"type": "number",
"minimum": 0,
"maximum": 1
},
"verdict": {
"enum": ["patched", "vanilla", "unknown", "incompatible"]
}
}
},
"SectionHashSet": {
"type": "object",
"properties": {
"buildId": { "type": "string" },
"fileHash": { "type": "string" },
"sections": {
"type": "object",
"additionalProperties": {
"$ref": "#/$defs/SectionInfo"
}
}
}
},
"SectionInfo": {
"type": "object",
"required": ["sha256", "size"],
"properties": {
"sha256": { "type": "string" },
"blake3": { "type": "string" },
"size": { "type": "integer" }
}
},
"SectionDelta": {
"type": "object",
"required": ["section", "status"],
"properties": {
"section": {
"type": "string",
"description": "Section name (e.g., .text, .rodata)"
},
"status": {
"enum": ["identical", "modified", "added", "removed"]
},
"baseSha256": { "type": "string" },
"targetSha256": { "type": "string" },
"sizeDelta": { "type": "integer" }
}
},
"BinaryDiffMetadata": {
"type": "object",
"required": ["toolVersion", "analysisTimestamp"],
"properties": {
"toolVersion": { "type": "string" },
"analysisTimestamp": {
"type": "string",
"format": "date-time"
},
"configDigest": { "type": "string" },
"totalBinaries": { "type": "integer" },
"modifiedBinaries": { "type": "integer" },
"analyzedSections": {
"type": "array",
"items": { "type": "string" }
}
}
}
}
}
```
### C# Model Classes
```csharp
namespace StellaOps.Attestor.StandardPredicates.BinaryDiff;
/// <summary>
/// BinaryDiffV1 predicate for in-toto attestations.
/// </summary>
public sealed record BinaryDiffPredicate
{
public const string PredicateType = "stellaops.binarydiff.v1";
public required ImmutableArray<BinaryDiffSubject> Subjects { get; init; }
public required BinaryDiffInputs Inputs { get; init; }
public required ImmutableArray<BinaryDiffFinding> Findings { get; init; }
public required BinaryDiffMetadata Metadata { get; init; }
}
public sealed record BinaryDiffSubject
{
public required string Name { get; init; }
public required ImmutableDictionary<string, string> Digest { get; init; }
public Platform? Platform { get; init; }
}
public sealed record BinaryDiffInputs
{
public required ImageReference Base { get; init; }
public required ImageReference Target { get; init; }
}
public sealed record ImageReference
{
public string? Reference { get; init; }
public required string Digest { get; init; }
public string? ManifestDigest { get; init; }
public Platform? Platform { get; init; }
}
public sealed record Platform
{
public required string Os { get; init; }
public required string Architecture { get; init; }
public string? Variant { get; init; }
}
public sealed record BinaryDiffFinding
{
public required string Path { get; init; }
public required ChangeType ChangeType { get; init; }
public required BinaryFormat BinaryFormat { get; init; }
public string? LayerDigest { get; init; }
public SectionHashSet? BaseHashes { get; init; }
public SectionHashSet? TargetHashes { get; init; }
public ImmutableArray<SectionDelta> SectionDeltas { get; init; }
public double? Confidence { get; init; }
public Verdict? Verdict { get; init; }
}
public enum ChangeType { Added, Removed, Modified, Unchanged }
public enum BinaryFormat { Elf, Pe, Macho, Unknown }
public enum Verdict { Patched, Vanilla, Unknown, Incompatible }
public sealed record SectionHashSet
{
public string? BuildId { get; init; }
public required string FileHash { get; init; }
public required ImmutableDictionary<string, SectionInfo> Sections { get; init; }
}
public sealed record SectionInfo
{
public required string Sha256 { get; init; }
public string? Blake3 { get; init; }
public required long Size { get; init; }
}
public sealed record SectionDelta
{
public required string Section { get; init; }
public required SectionStatus Status { get; init; }
public string? BaseSha256 { get; init; }
public string? TargetSha256 { get; init; }
public long? SizeDelta { get; init; }
}
public enum SectionStatus { Identical, Modified, Added, Removed }
public sealed record BinaryDiffMetadata
{
public required string ToolVersion { get; init; }
public required DateTimeOffset AnalysisTimestamp { get; init; }
public string? ConfigDigest { get; init; }
public int TotalBinaries { get; init; }
public int ModifiedBinaries { get; init; }
public ImmutableArray<string> AnalyzedSections { get; init; }
}
```
### Builder API
```csharp
public interface IBinaryDiffPredicateBuilder
{
IBinaryDiffPredicateBuilder WithSubject(string name, string digest, Platform? platform = null);
IBinaryDiffPredicateBuilder WithInputs(ImageReference baseImage, ImageReference targetImage);
IBinaryDiffPredicateBuilder AddFinding(BinaryDiffFinding finding);
IBinaryDiffPredicateBuilder WithMetadata(Action<BinaryDiffMetadataBuilder> configure);
BinaryDiffPredicate Build();
}
```
### DSSE Integration
```csharp
public interface IBinaryDiffDsseSigner
{
Task<BinaryDiffDsseResult> SignAsync(
BinaryDiffPredicate predicate,
CancellationToken cancellationToken = default);
}
public sealed record BinaryDiffDsseResult
{
public required string PayloadType { get; init; } // stellaops.binarydiff.v1
public required byte[] Payload { get; init; }
public required ImmutableArray<DsseSignature> Signatures { get; init; }
public required string EnvelopeJson { get; init; }
public string? RekorLogIndex { get; init; }
public string? RekorEntryId { get; init; }
}
```
### In-Toto Statement Wrapper
```json
{
"_type": "https://in-toto.io/Statement/v1",
"subject": [
{
"name": "docker://registry.example.com/app@sha256:abc123...",
"digest": {
"sha256": "abc123..."
}
}
],
"predicateType": "stellaops.binarydiff.v1",
"predicate": {
"inputs": {
"base": { "digest": "sha256:old..." },
"target": { "digest": "sha256:new..." }
},
"findings": [
{
"path": "/usr/lib/libssl.so.3",
"changeType": "modified",
"binaryFormat": "elf",
"sectionDeltas": [
{ "section": ".text", "status": "modified", "baseSha256": "...", "targetSha256": "..." }
],
"confidence": 0.95,
"verdict": "patched"
}
],
"metadata": {
"toolVersion": "1.0.0",
"analysisTimestamp": "2026-01-13T12:00:00Z"
}
}
}
```
## Determinism Requirements
1. **Canonical JSON**: RFC 8785 for all serialization before signing
2. **Stable ordering**: Findings sorted by path; sections sorted by name
3. **Timestamps**: From injected `TimeProvider`
4. **Hash computation**: Use shared `CanonicalJsonSerializer`
5. **DSSE PAE**: Use shared `DsseHelper.ComputePreAuthenticationEncoding`
## Test Cases
### Unit Tests
| Test | Description | Expected |
|------|-------------|----------|
| `Serialize_RoundTrip_Identical` | Serialize then deserialize | Identical predicate |
| `Serialize_Canonical_DeterministicOutput` | Same predicate, multiple serializations | Byte-identical JSON |
| `Build_ValidInputs_CreatesPredicate` | Builder with all required fields | Valid predicate |
| `Build_MissingSubject_Throws` | Builder without subject | `ArgumentException` |
| `Sign_ValidPredicate_ReturnsEnvelope` | Sign with test key | Valid DSSE envelope |
| `Verify_ValidEnvelope_Succeeds` | Verify signed envelope | Verification passes |
| `Verify_TamperedPayload_Fails` | Modified payload | Verification fails |
| `Schema_ValidJson_Passes` | Valid JSON against schema | Schema validation passes |
| `Schema_InvalidJson_Fails` | Missing required field | Schema validation fails |
### Integration Tests
| Test | Description | Expected |
|------|-------------|----------|
| `SignAndSubmit_RekorIntegration` | Sign and submit to Rekor (test instance) | Log entry created |
| `EndToEnd_DiffToAttestation` | From image diff to signed attestation | Valid DSSE with findings |
## Execution Log
| Date (UTC) | Update | Owner |
|------------|--------|-------|
| 2026-01-13 | Sprint created from advisory analysis. | Project Mgmt |
## Decisions & Risks
- **APPROVED**: Predicate type `stellaops.binarydiff.v1` follows StellaOps naming convention.
- **APPROVED**: Support both ELF and future PE/Mach-O via `binaryFormat` discriminator.
- **RISK**: Schema evolution requires versioning strategy; defer to v2 if breaking changes needed.
- **RISK**: Large diffs may produce large attestations; consider summary mode for >1000 findings.
## Next Checkpoints
- Task 1-4 complete → Schema and models ready for integration
- Task 5-6 complete → Signing/verification operational
- Task 8 complete → Sprint can be marked DONE
- Unblock Sprint 3 (CLI)

View File

@@ -1,358 +0,0 @@
# Sprint 20260113_001_003_CLI - Binary Diff Command Enhancement
## Topic & Scope
- Implement `stella scan diff --mode=elf` for binary-section-level diff
- Add `--emit-dsse=<dir>` option for DSSE attestation output
- Support human-readable table and JSON output formats
- Integrate with existing scan infrastructure and OCI registry client
- **Working directory:** `src/Cli/StellaOps.Cli/Commands/`
## Dependencies & Concurrency
- **Depends on:** Sprint 001 (ELF Section Hash Extractor)
- **Depends on:** Sprint 002 (BinaryDiffV1 Predicate)
- **BLOCKED RISK:** CLI tests under active modification; coordinate before touching test files
- Parallel work safe for command implementation; test coordination required
## Documentation Prerequisites
- `docs/README.md`
- `docs/ARCHITECTURE_REFERENCE.md`
- `CLAUDE.md` Section 8 (Determinism Rules)
- `src/Cli/StellaOps.Cli/AGENTS.md` (if exists)
- Existing CLI commands: `src/Cli/StellaOps.Cli/Commands/`
- System.CommandLine documentation
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
|---|---------|--------|---------------------------|--------|-----------------|
| 1 | CLI-DIFF-COMMAND-0001 | TODO | Sprint 001 & 002 complete | Guild - CLI | Create `BinaryDiffCommand` class under `Commands/Scan/` implementing `stella scan diff` subcommand with required options. |
| 2 | CLI-DIFF-OPTIONS-0001 | TODO | Depends on CLI-DIFF-COMMAND-0001 | Guild - CLI | Define command options: `--base` (base image ref), `--target` (target image ref), `--mode` (elf/pe/auto), `--emit-dsse` (output dir), `--format` (table/json), `--platform` (os/arch). |
| 3 | CLI-DIFF-SERVICE-0001 | TODO | Depends on CLI-DIFF-OPTIONS-0001 | Guild - CLI | Implement `BinaryDiffService` that orchestrates: image pull, layer extraction, section hash computation, diff computation, predicate building. |
| 4 | CLI-DIFF-RENDERER-0001 | TODO | Depends on CLI-DIFF-SERVICE-0001 | Guild - CLI | Implement `BinaryDiffRenderer` for table and JSON output formats. Table shows path, change type, verdict, confidence. JSON outputs full diff structure. |
| 5 | CLI-DIFF-DSSE-OUTPUT-0001 | TODO | Depends on CLI-DIFF-SERVICE-0001 | Guild - CLI | Implement DSSE output: one envelope per platform manifest, written to `--emit-dsse` directory with naming convention `{platform}-binarydiff.dsse.json`. |
| 6 | CLI-DIFF-PROGRESS-0001 | TODO | Depends on CLI-DIFF-SERVICE-0001 | Guild - CLI | Add progress reporting for long-running operations: layer download progress, binary analysis progress, section hash computation. |
| 7 | CLI-DIFF-DI-0001 | TODO | Depends on all above | Guild - CLI | Register all services in `Program.cs` DI setup. Wire up `IHttpClientFactory`, `IElfSectionHashExtractor`, `IBinaryDiffDsseSigner`. |
| 8 | CLI-DIFF-HELP-0001 | TODO | Depends on CLI-DIFF-COMMAND-0001 | Guild - CLI | Add comprehensive help text, examples, and shell completions for the new command. |
| 9 | CLI-DIFF-TESTS-0001 | BLOCKED | Depends on all above; CLI tests under active modification | Guild - CLI | Add unit tests for command parsing, service logic, and output rendering. Coordinate with other agent before modifying test files. |
| 10 | CLI-DIFF-INTEGRATION-0001 | TODO | Depends on CLI-DIFF-TESTS-0001 | Guild - CLI | Add integration test with synthetic OCI images containing known ELF binaries. Verify end-to-end flow. |
## Technical Specification
### Command Syntax
```bash
# Basic usage
stella scan diff --base <image-ref> --target <image-ref>
# With binary mode
stella scan diff --base docker://repo/app:1.0.0 --target docker://repo/app:1.0.1 --mode=elf
# With DSSE output
stella scan diff --base @sha256:abc... --target @sha256:def... \
--mode=elf --emit-dsse=./attestations/
# JSON output
stella scan diff --base image1 --target image2 --format=json > diff.json
# Specific platform
stella scan diff --base image1 --target image2 --platform=linux/amd64
```
### Command Options
| Option | Short | Type | Required | Default | Description |
|--------|-------|------|----------|---------|-------------|
| `--base` | `-b` | string | Yes | - | Base image reference (tag or @digest) |
| `--target` | `-t` | string | Yes | - | Target image reference (tag or @digest) |
| `--mode` | `-m` | enum | No | `auto` | Analysis mode: `elf`, `pe`, `auto` |
| `--emit-dsse` | `-d` | path | No | - | Directory for DSSE attestation output |
| `--format` | `-f` | enum | No | `table` | Output format: `table`, `json`, `summary` |
| `--platform` | `-p` | string | No | - | Platform filter (e.g., `linux/amd64`) |
| `--include-unchanged` | - | bool | No | `false` | Include unchanged binaries in output |
| `--sections` | - | string[] | No | all | Sections to analyze (e.g., `.text,.rodata`) |
| `--registry-auth` | - | string | No | - | Path to Docker config for authentication |
| `--timeout` | - | int | No | `300` | Timeout in seconds for operations |
| `--verbose` | `-v` | bool | No | `false` | Enable verbose output |
### Output Formats
#### Table Format (Default)
```
Binary Diff: docker://repo/app:1.0.0 → docker://repo/app:1.0.1
Platform: linux/amd64
Analysis Mode: ELF Section Hashes
PATH CHANGE VERDICT CONFIDENCE SECTIONS CHANGED
────────────────────────────────────────────────────────────────────────────────
/usr/lib/libssl.so.3 modified patched 0.95 .text, .rodata
/usr/lib/libcrypto.so.3 modified patched 0.92 .text
/usr/bin/openssl modified unknown 0.75 .text, .data
/usr/lib/libc.so.6 unchanged - - -
Summary: 4 binaries analyzed, 3 modified, 1 unchanged
Patched: 2, Unknown: 1
```
#### JSON Format
```json
{
"schemaVersion": "1.0.0",
"base": {
"reference": "docker://repo/app:1.0.0",
"digest": "sha256:abc123..."
},
"target": {
"reference": "docker://repo/app:1.0.1",
"digest": "sha256:def456..."
},
"platform": {
"os": "linux",
"architecture": "amd64"
},
"analysisMode": "elf",
"timestamp": "2026-01-13T12:00:00Z",
"findings": [
{
"path": "/usr/lib/libssl.so.3",
"changeType": "modified",
"verdict": "patched",
"confidence": 0.95,
"sectionDeltas": [
{ "section": ".text", "status": "modified" },
{ "section": ".rodata", "status": "modified" }
]
}
],
"summary": {
"totalBinaries": 4,
"modified": 3,
"unchanged": 1,
"verdicts": {
"patched": 2,
"unknown": 1
}
}
}
```
#### Summary Format
```
Binary Diff Summary
───────────────────
Base: docker://repo/app:1.0.0 (sha256:abc123...)
Target: docker://repo/app:1.0.1 (sha256:def456...)
Platform: linux/amd64
Binaries: 4 total, 3 modified, 1 unchanged
Verdicts: 2 patched, 1 unknown
DSSE Attestation: ./attestations/linux-amd64-binarydiff.dsse.json
```
### DSSE Output Structure
```
attestations/
├── linux-amd64-binarydiff.dsse.json # DSSE envelope
├── linux-amd64-binarydiff.payload.json # Raw predicate (for inspection)
└── linux-arm64-binarydiff.dsse.json # (if multi-arch)
```
### Service Architecture
```csharp
namespace StellaOps.Cli.Services;
public interface IBinaryDiffService
{
Task<BinaryDiffResult> ComputeDiffAsync(
BinaryDiffRequest request,
IProgress<BinaryDiffProgress>? progress = null,
CancellationToken cancellationToken = default);
}
public sealed record BinaryDiffRequest
{
public required string BaseImageRef { get; init; }
public required string TargetImageRef { get; init; }
public required BinaryDiffMode Mode { get; init; }
public Platform? Platform { get; init; }
public ImmutableArray<string>? Sections { get; init; }
public bool IncludeUnchanged { get; init; }
public string? RegistryAuthPath { get; init; }
}
public sealed record BinaryDiffResult
{
public required ImageReference Base { get; init; }
public required ImageReference Target { get; init; }
public required Platform Platform { get; init; }
public required ImmutableArray<BinaryDiffFinding> Findings { get; init; }
public required BinaryDiffSummary Summary { get; init; }
public BinaryDiffPredicate? Predicate { get; init; }
}
public sealed record BinaryDiffProgress
{
public required string Phase { get; init; } // "pulling", "extracting", "analyzing", "diffing"
public required string CurrentItem { get; init; }
public required int Current { get; init; }
public required int Total { get; init; }
}
```
### Command Implementation Pattern
```csharp
namespace StellaOps.Cli.Commands.Scan;
public class BinaryDiffCommand : Command
{
public BinaryDiffCommand() : base("diff", "Compare binaries between two images")
{
AddOption(BaseOption);
AddOption(TargetOption);
AddOption(ModeOption);
AddOption(EmitDsseOption);
AddOption(FormatOption);
AddOption(PlatformOption);
// ... other options
}
public static Option<string> BaseOption { get; } = new(
aliases: ["--base", "-b"],
description: "Base image reference (tag or @digest)")
{
IsRequired = true
};
// ... other options
public new class Handler : ICommandHandler
{
private readonly IBinaryDiffService _diffService;
private readonly IBinaryDiffDsseSigner _signer;
private readonly IBinaryDiffRenderer _renderer;
private readonly IConsole _console;
public async Task<int> InvokeAsync(InvocationContext context)
{
var cancellationToken = context.GetCancellationToken();
// Parse options
var baseRef = context.ParseResult.GetValueForOption(BaseOption)!;
var targetRef = context.ParseResult.GetValueForOption(TargetOption)!;
// ...
// Execute diff
var progress = new Progress<BinaryDiffProgress>(p =>
_console.WriteLine($"[{p.Phase}] {p.CurrentItem} ({p.Current}/{p.Total})"));
var result = await _diffService.ComputeDiffAsync(
new BinaryDiffRequest { ... },
progress,
cancellationToken);
// Emit DSSE if requested
if (!string.IsNullOrEmpty(emitDssePath))
{
var dsseResult = await _signer.SignAsync(result.Predicate!, cancellationToken);
await WriteDsseAsync(emitDssePath, result.Platform, dsseResult, cancellationToken);
}
// Render output
await _renderer.RenderAsync(result, format, _console.Out, cancellationToken);
return 0;
}
}
}
```
### Error Handling
| Error | Exit Code | Message |
|-------|-----------|---------|
| Invalid base image | 1 | `Error: Unable to resolve base image '{ref}': {reason}` |
| Invalid target image | 1 | `Error: Unable to resolve target image '{ref}': {reason}` |
| Authentication failed | 2 | `Error: Registry authentication failed for '{registry}'` |
| Platform not found | 3 | `Error: Platform '{platform}' not found in image index` |
| No ELF binaries | 0 | `Warning: No ELF binaries found in images` (success with warning) |
| Timeout | 124 | `Error: Operation timed out after {timeout}s` |
| Network error | 5 | `Error: Network error: {message}` |
### Progress Reporting
```
[pulling] Fetching base manifest... (1/4)
[pulling] Fetching target manifest... (2/4)
[pulling] Downloading layers... (3/4)
└─ sha256:abc123... 45.2 MB/128.5 MB (35%)
[extracting] Extracting base layers... (1/8)
[extracting] Extracting target layers... (5/8)
[analyzing] Computing section hashes... (1/156)
└─ /usr/lib/libssl.so.3
[analyzing] Computing section hashes... (78/156)
└─ /usr/bin/python3.11
[diffing] Comparing binaries... (1/156)
[complete] Analysis complete.
```
## Determinism Requirements
1. **Output ordering**: Findings sorted by path
2. **Timestamps**: From injected `TimeProvider`
3. **Hash formats**: Lowercase hexadecimal
4. **JSON output**: RFC 8785 canonical when `--format=json`
5. **DSSE files**: Canonical JSON serialization
## Test Cases
### Unit Tests
| Test | Description | Expected |
|------|-------------|----------|
| `ParseOptions_ValidArgs_Succeeds` | All required options provided | Options parsed correctly |
| `ParseOptions_MissingBase_Fails` | Missing --base | Parse error |
| `ComputeDiff_IdenticalImages_NoChanges` | Same image for base and target | Empty findings, summary shows 0 modified |
| `ComputeDiff_ModifiedBinary_DetectsChange` | Binary with .text change | Finding with modified status |
| `ComputeDiff_AddedBinary_Detected` | Binary in target only | Finding with added status |
| `ComputeDiff_RemovedBinary_Detected` | Binary in base only | Finding with removed status |
| `RenderTable_ValidResult_FormatsCorrectly` | Result with findings | Properly formatted table |
| `RenderJson_ValidResult_CanonicalOutput` | Same result, multiple renders | Byte-identical JSON |
| `EmitDsse_ValidResult_CreatesFile` | With --emit-dsse | DSSE file created |
### Integration Tests
| Test | Description | Expected |
|------|-------------|----------|
| `EndToEnd_RealImages_ProducesOutput` | Two synthetic OCI images | Valid diff output |
| `EndToEnd_WithDsse_ValidAttestation` | Diff with --emit-dsse | Verifiable DSSE |
| `MultiArch_SpecificPlatform_FiltersCorrectly` | Multi-arch image with --platform | Only specified platform analyzed |
## Execution Log
| Date (UTC) | Update | Owner |
|------------|--------|-------|
| 2026-01-13 | Sprint created from advisory analysis. | Project Mgmt |
| 2026-01-13 | Task CLI-DIFF-TESTS-0001 marked BLOCKED: CLI tests under active modification. | Project Mgmt |
## Decisions & Risks
- **APPROVED**: Command placed under `stella scan diff` (not separate `stella-scan image diff` as in advisory).
- **APPROVED**: Support `--mode=elf` initially; `--mode=pe` and `--mode=auto` stubbed for future.
- **BLOCKED**: CLI tests require coordination with other agent work; tests deferred.
- **RISK**: Long-running operations need robust timeout and cancellation handling.
- **RISK**: Large images may cause memory pressure; consider streaming approach for layer extraction.
## Next Checkpoints
- Task 1-6 complete → Command implementation ready
- Task 7-8 complete → Help and DI wired up
- Task 9-10 complete (after unblock) → Sprint can be marked DONE

View File

@@ -1,351 +0,0 @@
# Sprint 20260113_001_004_DOCS - Binary Diff Attestation Documentation
## Topic & Scope
- Create architecture documentation for binary diff attestation feature
- Update CLI reference with new `stella scan diff` command
- Publish BinaryDiffV1 predicate JSON Schema
- Add developer guide for extending binary analysis
- **Working directory:** `docs/`
## Dependencies & Concurrency
- Can proceed in parallel with Sprints 2-3 (after Sprint 1 models stabilize)
- No blocking dependencies for initial documentation drafts
- Final documentation review after all implementation sprints complete
## Documentation Prerequisites
- `docs/README.md`
- `docs/ARCHITECTURE_REFERENCE.md`
- `CLAUDE.md` (for documentation standards)
- Existing module docs: `docs/modules/scanner/`
- Existing CLI docs: `docs/API_CLI_REFERENCE.md`
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
|---|---------|--------|---------------------------|--------|-----------------|
| 1 | DOCS-ARCH-0001 | TODO | Sprint 001 models | Guild - Docs | Create `docs/modules/scanner/binary-diff-attestation.md` architecture document covering ELF section hashing, diff computation, and DSSE attestation flow. |
| 2 | DOCS-CLI-0001 | TODO | Sprint 003 command spec | Guild - Docs | Update `docs/API_CLI_REFERENCE.md` with `stella scan diff` command documentation including all options, examples, and output formats. |
| 3 | DOCS-SCHEMA-0001 | TODO | Sprint 002 schema | Guild - Docs | Publish `docs/schemas/binarydiff-v1.schema.json` with full JSON Schema definition and validation examples. |
| 4 | DOCS-DEVGUIDE-0001 | TODO | All sprints | Guild - Docs | Create `docs/dev/extending-binary-analysis.md` developer guide for adding new binary formats (PE, Mach-O) and custom section extractors. |
| 5 | DOCS-EXAMPLES-0001 | TODO | Sprint 003 complete | Guild - Docs | Add usage examples to `docs/examples/binary-diff/` with sample commands, expected outputs, and DSSE verification steps. |
| 6 | DOCS-GLOSSARY-0001 | TODO | None | Guild - Docs | Update `docs/GLOSSARY.md` (if exists) or create glossary entries for: section hash, binary diff, vendor backport, DSSE envelope. |
| 7 | DOCS-CHANGELOG-0001 | TODO | All sprints complete | Guild - Docs | Add changelog entry for binary diff attestation feature in `CHANGELOG.md`. |
| 8 | DOCS-REVIEW-0001 | TODO | All above complete | Guild - Docs | Final documentation review: cross-link all docs, verify examples work, spell-check, ensure consistency with existing docs. |
## Documentation Deliverables
### 1. Architecture Document
**File:** `docs/modules/scanner/binary-diff-attestation.md`
**Outline:**
```markdown
# Binary Diff Attestation
## Overview
- Purpose and use cases
- Relationship to SBOM and VEX
## Architecture
### Component Diagram
- ElfSectionHashExtractor
- BinaryDiffService
- BinaryDiffPredicateBuilder
- BinaryDiffDsseSigner
### Data Flow
1. Image resolution
2. Layer extraction
3. Binary identification
4. Section hash computation
5. Diff computation
6. Predicate construction
7. DSSE signing
## ELF Section Hashing
### Target Sections
- .text (executable code)
- .rodata (read-only data)
- .data (initialized data)
- .symtab (symbol table)
- .dynsym (dynamic symbols)
### Hash Algorithm
- SHA-256 primary
- BLAKE3 optional
### Determinism Guarantees
- Stable ordering
- Canonical serialization
## BinaryDiffV1 Predicate
### Schema Overview
- Subjects (image references)
- Inputs (base/target)
- Findings (per-binary deltas)
- Metadata
### Evidence Properties
- Section hashes in SBOM
- Confidence scoring
- Verdict classification
## DSSE Attestation
### Envelope Structure
- Payload type: stellaops.binarydiff.v1
- Signature algorithm
- Rekor submission
### Verification
- cosign compatibility
- Offline verification
## Integration Points
### VEX Mapping
- Linking to vulnerability status
- Backport evidence
### Policy Engine
- Binary evidence rules
- Trust thresholds
## Configuration
### Options
- Section selection
- Hash algorithms
- Output formats
## Limitations and Future Work
### Current Limitations
- ELF only (PE/Mach-O planned)
- Single-platform per invocation
### Roadmap
- PE section analysis (M2)
- Mach-O section analysis (M2)
- Vendor backport corpus (M3)
```
### 2. CLI Reference Update
**File:** `docs/API_CLI_REFERENCE.md` (append to Scan section)
**Content:**
```markdown
### stella scan diff
Compare binaries between two container images at the section level.
#### Synopsis
```bash
stella scan diff --base <image-ref> --target <image-ref> [options]
```
#### Description
The `diff` command performs binary-level comparison between two container images,
analyzing ELF section hashes to detect changes and classify them as patches,
vanilla updates, or unknown modifications.
#### Options
| Option | Description |
|--------|-------------|
| `--base`, `-b` | Base image reference (required) |
| `--target`, `-t` | Target image reference (required) |
| `--mode`, `-m` | Analysis mode: `elf`, `pe`, `auto` (default: `auto`) |
| `--emit-dsse`, `-d` | Directory for DSSE attestation output |
| `--format`, `-f` | Output format: `table`, `json`, `summary` (default: `table`) |
| `--platform`, `-p` | Platform filter (e.g., `linux/amd64`) |
| `--include-unchanged` | Include unchanged binaries in output |
| `--sections` | Sections to analyze (comma-separated) |
| `--registry-auth` | Path to Docker config for authentication |
| `--timeout` | Timeout in seconds (default: 300) |
| `--verbose`, `-v` | Enable verbose output |
#### Examples
**Basic comparison:**
```bash
stella scan diff --base myapp:1.0.0 --target myapp:1.0.1
```
**With DSSE attestation output:**
```bash
stella scan diff -b myapp:1.0.0 -t myapp:1.0.1 \
--mode=elf --emit-dsse=./attestations/
```
**JSON output for automation:**
```bash
stella scan diff -b myapp:1.0.0 -t myapp:1.0.1 --format=json > diff.json
```
**Specific platform:**
```bash
stella scan diff -b myapp:1.0.0 -t myapp:1.0.1 --platform=linux/arm64
```
#### Output
**Table format** shows a summary of changes:
```
PATH CHANGE VERDICT CONFIDENCE
/usr/lib/libssl.so.3 modified patched 0.95
/usr/lib/libcrypto.so.3 modified patched 0.92
```
**JSON format** provides full diff details for programmatic consumption.
#### Exit Codes
| Code | Description |
|------|-------------|
| 0 | Success |
| 1 | Invalid image reference |
| 2 | Authentication failed |
| 3 | Platform not found |
| 124 | Timeout |
| 5 | Network error |
#### See Also
- `stella scan layers` - List layers in an image
- `stella scan sbom` - Generate SBOM for an image
- [Binary Diff Attestation Architecture](../modules/scanner/binary-diff-attestation.md)
```
### 3. JSON Schema
**File:** `docs/schemas/binarydiff-v1.schema.json`
(Full schema as defined in Sprint 002)
### 4. Developer Guide
**File:** `docs/dev/extending-binary-analysis.md`
**Outline:**
```markdown
# Extending Binary Analysis
## Overview
This guide explains how to add support for new binary formats (PE, Mach-O)
or custom section extractors to the binary diff attestation system.
## Architecture
### Extractor Interface
- ISectionHashExtractor<TConfig>
- Registration pattern
- Configuration binding
### Adding a New Format
#### Step 1: Define Models
- Section hash models
- Format-specific metadata
#### Step 2: Implement Extractor
- Parse binary format
- Extract sections
- Compute hashes
#### Step 3: Register Services
- DI registration
- Configuration binding
- Format detection
#### Step 4: Add Tests
- Unit test fixtures
- Golden file comparisons
- Edge cases
### Example: PE Section Extractor
```csharp
public class PeSectionHashExtractor : ISectionHashExtractor<PeConfig>
{
// Implementation example
}
```
## Best Practices
### Determinism
- Stable ordering
- Canonical hashing
- Injected dependencies
### Performance
- Streaming large binaries
- Caching strategies
- Parallel extraction
### Security
- Input validation
- Memory limits
- Malformed input handling
```
### 5. Usage Examples
**Directory:** `docs/examples/binary-diff/`
**Files:**
```
binary-diff/
├── README.md # Overview and prerequisites
├── basic-comparison.md # Simple diff example
├── dsse-attestation.md # DSSE output and verification
├── policy-integration.md # Using diffs in policy rules
├── ci-cd-integration.md # GitHub Actions / GitLab CI examples
└── sample-outputs/
├── diff-table.txt # Sample table output
├── diff.json # Sample JSON output
└── attestation.dsse.json # Sample DSSE envelope
```
## Quality Checklist
- [ ] All code examples compile/run
- [ ] All links are valid
- [ ] Consistent terminology with existing docs
- [ ] No spelling/grammar errors
- [ ] Screenshots/diagrams where helpful
- [ ] Cross-references to related docs
- [ ] Version compatibility noted
## Execution Log
| Date (UTC) | Update | Owner |
|------------|--------|-------|
| 2026-01-13 | Sprint created from advisory analysis. | Project Mgmt |
## Decisions & Risks
- **APPROVED**: Documentation follows existing StellaOps documentation patterns.
- **APPROVED**: JSON Schema published under `docs/schemas/` for external consumption.
- **RISK**: Documentation may need updates if implementation details change; defer final review until code complete.
## Next Checkpoints
- Task 1-3 complete → Core documentation in place
- Task 4-5 complete → Developer and user resources ready
- Task 8 complete → Sprint can be marked DONE

View File

@@ -1,197 +0,0 @@
# Sprint Batch 20260113_002 - Image Index Resolution CLI
## Executive Summary
This sprint batch implements **OCI multi-arch image inspection** capabilities, enabling users to enumerate image indices, platform manifests, and layer digests through CLI commands. This completes the "index -> manifests -> layers" flow requested in the OCI Layer-Level Image Integrity advisory.
**Scope:** OCI image index resolution with Docker & OCI media type support
**Effort Estimate:** 4-5 story points across 3 sprints
**Priority:** Medium (usability enhancement)
## Background
### Advisory Requirements
The original advisory specified:
> Resolve an image index (if present), list all platform manifests, then for each manifest list ordered layer digests and sizes. Accept Docker and OCI media types.
### Existing Capabilities
| Component | Status | Location |
|-----------|--------|----------|
| `OciIndex` record | EXISTS | `src/Concelier/__Libraries/.../OciIndex.cs` |
| `OciManifest` record | EXISTS | `src/Concelier/__Libraries/.../OciManifest.cs` |
| `OciRegistryClient` | EXISTS | `src/Excititor/__Libraries/.../Fetch/OciRegistryClient.cs` |
| `OciImageReferenceParser` | EXISTS | `src/Cli/StellaOps.Cli/Services/OciImageReferenceParser.cs` |
| `LayeredRootFileSystem` | EXISTS | `src/Scanner/__Libraries/.../FileSystem/LayeredRootFileSystem.cs` |
### Gap Analysis
| Capability | Status |
|------------|--------|
| Parse OCI image index from registry | Partial (records exist, no handler) |
| Walk index -> platform manifests | MISSING |
| CLI `image inspect` verb | MISSING |
| JSON output with canonical digests | MISSING |
## Sprint Index
| Sprint | ID | Module | Topic | Status | Owner |
|--------|-----|--------|-------|--------|-------|
| 1 | SPRINT_20260113_002_001 | SCANNER | OCI Image Index Inspector Service | TODO | Guild - Scanner |
| 2 | SPRINT_20260113_002_002 | CLI | Image Inspect Command | TODO | Guild - CLI |
| 3 | SPRINT_20260113_002_003 | DOCS | Image Inspection Documentation | TODO | Guild - Docs |
## Dependencies
```
+-----------------------------------------------------------------------+
| Dependency Graph |
+-----------------------------------------------------------------------+
| |
| Sprint 1 (Inspector Service) |
| | |
| +------------------+ |
| v v |
| Sprint 2 (CLI) Sprint 3 (Docs) |
| |
+-----------------------------------------------------------------------+
```
- **Sprint 1** is foundational (no dependencies)
- **Sprint 2** depends on Sprint 1 (uses inspector service)
- **Sprint 3** can proceed in parallel with Sprint 2
**Cross-Batch Dependencies:**
- None (this batch is independent of 001)
## Acceptance Criteria (Batch-Level)
### Must Have
1. **Image Index Resolution**
- Accept image reference (tag or digest)
- Detect and parse image index (multi-arch) vs single manifest
- Return platform manifest list with os/arch/variant
2. **Layer Enumeration**
- For each platform manifest: ordered layer digests
- Include layer sizes and media types
- Support both Docker and OCI media types
3. **CLI Command**
- `stella image inspect <reference>` with output formats
- `--resolve-index` flag to walk multi-arch structure
- `--print-layers` flag to include layer details
- JSON output with canonical ordering
4. **Documentation**
- CLI reference for new commands
- Architecture doc for inspector service
### Should Have
- Platform filtering (`--platform linux/amd64`)
- Config blob inspection (`--config` flag)
- Cache manifest responses (in-memory, session-scoped)
### Deferred (Out of Scope)
- `skopeo` or `ctr` CLI integration (use HTTP API)
- Offline image tar inspection (handled by existing LayeredRootFileSystem)
- Image pulling/export (out of scope)
## Technical Context
### Key Files to Create/Extend
| Component | File | Purpose |
|-----------|------|---------|
| Inspector Service | `src/Scanner/__Libraries/StellaOps.Scanner.Storage.Oci/OciImageInspector.cs` | NEW: Unified index/manifest inspection |
| Inspector Models | `src/Scanner/__Libraries/StellaOps.Scanner.Contracts/OciInspectionModels.cs` | NEW: Inspection result models |
| CLI Command | `src/Cli/StellaOps.Cli/Commands/ImageCommandGroup.cs` | NEW: `stella image` command group |
| CLI Handler | `src/Cli/StellaOps.Cli/Commands/CommandHandlers.Image.cs` | NEW: Image command handlers |
### Output Schema
```json
{
"reference": "docker.io/library/nginx:latest",
"resolvedDigest": "sha256:abc123...",
"mediaType": "application/vnd.oci.image.index.v1+json",
"isMultiArch": true,
"platforms": [
{
"os": "linux",
"architecture": "amd64",
"variant": null,
"manifestDigest": "sha256:def456...",
"configDigest": "sha256:ghi789...",
"layers": [
{
"order": 0,
"digest": "sha256:layer1...",
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
"size": 31457280
}
],
"totalSize": 157286400
}
],
"inspectedAt": "2026-01-13T12:00:00Z",
"inspectorVersion": "1.0.0"
}
```
### Determinism Requirements
Per CLAUDE.md Section 8:
1. **Ordering**: Platforms sorted by os/arch/variant; layers by order
2. **Timestamps**: From injected `TimeProvider`
3. **JSON serialization**: Canonical key ordering
4. **InvariantCulture**: All size/number formatting
## Risk Assessment
| Risk | Likelihood | Impact | Mitigation |
|------|------------|--------|------------|
| Registry auth complexity | Medium | Medium | Use existing `OciRegistryClient` auth handling |
| Rate limiting on public registries | Low | Low | Implement retry with backoff |
| Non-standard manifest schemas | Low | Medium | Graceful degradation with warnings |
## Success Metrics
- [ ] All unit tests pass
- [ ] Integration tests against Docker Hub, GHCR, and mock registry
- [ ] CLI completions and help work correctly
- [ ] JSON output is valid and deterministic
## Documentation Prerequisites
Before starting implementation, reviewers must read:
- `docs/README.md`
- `docs/ARCHITECTURE_REFERENCE.md`
- `CLAUDE.md` Section 8 (Code Quality & Determinism Rules)
- OCI Image Index Spec: https://github.com/opencontainers/image-spec/blob/main/image-index.md
- OCI Image Manifest Spec: https://specs.opencontainers.org/image-spec/manifest/
## Execution Log
| Date (UTC) | Update | Owner |
|------------|--------|-------|
| 2026-01-13 | Sprint batch created from advisory analysis. | Project Mgmt |
## Decisions & Risks
- **APPROVED 2026-01-13**: Use HTTP Registry API v2 only; no external CLI tool dependencies.
- **APPROVED 2026-01-13**: Single-manifest images return as degenerate case (1-element platform list).
- **RISK**: Some registries may not support OCI index; handle Docker manifest list as fallback.
## Next Checkpoints
- Sprint 1 completion -> Sprint 2 can start
- All sprints complete -> Integration testing checkpoint
- Integrate with Batch 001 CLI commands post-completion

View File

@@ -1,271 +0,0 @@
# Sprint 20260113_002_001_SCANNER - OCI Image Index Inspector Service
## Topic & Scope
- Implement unified OCI image inspection service
- Support image index (multi-arch) and single manifest resolution
- Walk index -> platform manifests -> ordered layers
- Support both Docker and OCI media types
- **Working directory:** `src/Scanner/__Libraries/StellaOps.Scanner.Storage.Oci/`
## Dependencies & Concurrency
- No blocking dependencies (foundational sprint)
- Uses existing `OciRegistryClient` for HTTP operations
- Sprint 2 (CLI) depends on this sprint
## Documentation Prerequisites
- `docs/README.md`
- `docs/ARCHITECTURE_REFERENCE.md`
- `CLAUDE.md` Section 8 (Determinism Rules)
- OCI Image Index Spec: https://github.com/opencontainers/image-spec/blob/main/image-index.md
- OCI Image Manifest Spec: https://specs.opencontainers.org/image-spec/manifest/
- Docker Manifest List: https://docs.docker.com/registry/spec/manifest-v2-2/
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
|---|---------|--------|---------------------------|--------|-----------------|
| 1 | IMG-INSPECT-MODELS-0001 | TODO | None | Guild - Scanner | Define `ImageInspectionResult`, `PlatformManifest`, `LayerInfo` models in `src/Scanner/__Libraries/StellaOps.Scanner.Contracts/OciInspectionModels.cs`. Include all OCI/Docker discriminators. |
| 2 | IMG-INSPECT-INTERFACE-0001 | TODO | Depends on MODELS-0001 | Guild - Scanner | Define `IOciImageInspector` interface with `InspectAsync(reference, options, ct)` signature. Options include: resolveIndex, includeLayers, platformFilter. |
| 3 | IMG-INSPECT-IMPL-0001 | TODO | Depends on INTERFACE-0001 | Guild - Scanner | Implement `OciImageInspector` class. Handle HEAD request for manifest detection, then GET for content. Detect index vs manifest by media type. |
| 4 | IMG-INSPECT-INDEX-0001 | TODO | Depends on IMPL-0001 | Guild - Scanner | Implement index resolution: parse `application/vnd.oci.image.index.v1+json` and `application/vnd.docker.distribution.manifest.list.v2+json`. Extract platform descriptors. |
| 5 | IMG-INSPECT-MANIFEST-0001 | TODO | Depends on IMPL-0001 | Guild - Scanner | Implement manifest parsing: `application/vnd.oci.image.manifest.v1+json` and `application/vnd.docker.distribution.manifest.v2+json`. Extract config and layers. |
| 6 | IMG-INSPECT-LAYERS-0001 | TODO | Depends on MANIFEST-0001 | Guild - Scanner | For each manifest, enumerate layers with: order (0-indexed), digest, mediaType, size. Support compressed and uncompressed variants. |
| 7 | IMG-INSPECT-AUTH-0001 | TODO | Depends on IMPL-0001 | Guild - Scanner | Integrate with existing registry auth: token-based, basic, anonymous. Handle 401 -> token refresh flow. |
| 8 | IMG-INSPECT-DI-0001 | TODO | Depends on all above | Guild - Scanner | Register `IOciImageInspector` in `ServiceCollectionExtensions.cs`. Inject `TimeProvider`, `IHttpClientFactory`, `ILogger`. |
| 9 | IMG-INSPECT-TESTS-0001 | TODO | Depends on all above | Guild - Scanner | Unit tests covering: single manifest, multi-arch index, Docker manifest list, missing manifest, auth errors, malformed responses. |
| 10 | IMG-INSPECT-INTEGRATION-0001 | TODO | Depends on TESTS-0001 | Guild - Scanner | Integration tests against mock OCI registry (testcontainers or in-memory). Test real Docker Hub and GHCR in CI. |
## Technical Specification
### Models
```csharp
namespace StellaOps.Scanner.Contracts;
/// <summary>
/// Result of inspecting an OCI image reference.
/// </summary>
public sealed record ImageInspectionResult
{
/// <summary>Original image reference provided.</summary>
public required string Reference { get; init; }
/// <summary>Resolved digest of the index or manifest.</summary>
public required string ResolvedDigest { get; init; }
/// <summary>Media type of the resolved artifact.</summary>
public required string MediaType { get; init; }
/// <summary>True if this is a multi-arch image index.</summary>
public required bool IsMultiArch { get; init; }
/// <summary>Platform manifests (1 for single-arch, N for multi-arch).</summary>
public required ImmutableArray<PlatformManifest> Platforms { get; init; }
/// <summary>Inspection timestamp (UTC).</summary>
public required DateTimeOffset InspectedAt { get; init; }
/// <summary>Inspector version for reproducibility.</summary>
public required string InspectorVersion { get; init; }
/// <summary>Registry that was queried.</summary>
public required string Registry { get; init; }
/// <summary>Repository name.</summary>
public required string Repository { get; init; }
/// <summary>Warnings encountered during inspection.</summary>
public ImmutableArray<string> Warnings { get; init; } = [];
}
/// <summary>
/// A platform-specific manifest within an image index.
/// </summary>
public sealed record PlatformManifest
{
/// <summary>Operating system (e.g., "linux", "windows").</summary>
public required string Os { get; init; }
/// <summary>CPU architecture (e.g., "amd64", "arm64").</summary>
public required string Architecture { get; init; }
/// <summary>Architecture variant (e.g., "v8" for arm64).</summary>
public string? Variant { get; init; }
/// <summary>OS version (mainly for Windows).</summary>
public string? OsVersion { get; init; }
/// <summary>Digest of this platform's manifest.</summary>
public required string ManifestDigest { get; init; }
/// <summary>Media type of the manifest.</summary>
public required string ManifestMediaType { get; init; }
/// <summary>Digest of the config blob.</summary>
public required string ConfigDigest { get; init; }
/// <summary>Ordered list of layers.</summary>
public required ImmutableArray<LayerInfo> Layers { get; init; }
/// <summary>Total size of all layers in bytes.</summary>
public required long TotalSize { get; init; }
/// <summary>Platform string (os/arch/variant).</summary>
public string PlatformString => Variant is null
? $"{Os}/{Architecture}"
: $"{Os}/{Architecture}/{Variant}";
}
/// <summary>
/// Information about a single layer.
/// </summary>
public sealed record LayerInfo
{
/// <summary>Layer order (0-indexed, application order).</summary>
public required int Order { get; init; }
/// <summary>Layer digest (sha256:...).</summary>
public required string Digest { get; init; }
/// <summary>Media type of the layer blob.</summary>
public required string MediaType { get; init; }
/// <summary>Compressed size in bytes.</summary>
public required long Size { get; init; }
/// <summary>Optional annotations from the manifest.</summary>
public ImmutableDictionary<string, string>? Annotations { get; init; }
}
```
### Interface
```csharp
namespace StellaOps.Scanner.Storage.Oci;
public interface IOciImageInspector
{
/// <summary>
/// Inspects an OCI image reference.
/// </summary>
/// <param name="reference">Image reference (e.g., "nginx:latest", "ghcr.io/org/app@sha256:...").</param>
/// <param name="options">Inspection options.</param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>Inspection result or null if not found.</returns>
Task<ImageInspectionResult?> InspectAsync(
string reference,
ImageInspectionOptions? options = null,
CancellationToken cancellationToken = default);
}
public sealed record ImageInspectionOptions
{
/// <summary>Resolve multi-arch index to platform manifests (default: true).</summary>
public bool ResolveIndex { get; init; } = true;
/// <summary>Include layer details (default: true).</summary>
public bool IncludeLayers { get; init; } = true;
/// <summary>Filter to specific platform (e.g., "linux/amd64").</summary>
public string? PlatformFilter { get; init; }
/// <summary>Maximum platforms to inspect (default: unlimited).</summary>
public int? MaxPlatforms { get; init; }
/// <summary>Request timeout.</summary>
public TimeSpan? Timeout { get; init; }
}
```
### Media Type Handling
| Media Type | Type | Handling |
|------------|------|----------|
| `application/vnd.oci.image.index.v1+json` | OCI Index | Parse as index, enumerate manifests |
| `application/vnd.docker.distribution.manifest.list.v2+json` | Docker List | Parse as index (compatible) |
| `application/vnd.oci.image.manifest.v1+json` | OCI Manifest | Parse as manifest, extract layers |
| `application/vnd.docker.distribution.manifest.v2+json` | Docker Manifest | Parse as manifest (compatible) |
| Other | Unknown | Return warning, skip or fail per config |
### Algorithm
```pseudo
function InspectAsync(reference, options):
parsed = ParseReference(reference) // registry, repo, tag/digest
// Step 1: Resolve to digest
digest = HEAD(registry, repo, parsed.tagOrDigest)
mediaType = response.headers["Content-Type"]
// Step 2: Get manifest content
body = GET(registry, repo, digest, Accept: mediaType)
// Step 3: Classify and parse
if mediaType in [OCI_INDEX, DOCKER_MANIFEST_LIST]:
index = ParseIndex(body)
platforms = []
for descriptor in index.manifests:
if options.platformFilter and not matches(descriptor, filter):
continue
manifest = await InspectManifest(registry, repo, descriptor.digest)
platforms.append(manifest)
return Result(isMultiArch=true, platforms)
else:
manifest = ParseManifest(body)
platform = ExtractPlatform(manifest.config)
layers = ExtractLayers(manifest)
return Result(isMultiArch=false, [platform])
```
### Determinism Requirements
1. **Platform ordering**: Sort by os ASC, architecture ASC, variant ASC
2. **Layer ordering**: Preserve manifest order (0-indexed)
3. **Timestamps**: From injected `TimeProvider`
4. **JSON**: Canonical serialization for any digest computation
5. **Warnings**: Sorted lexicographically
## Test Cases
### Unit Tests
| Test | Description | Expected |
|------|-------------|----------|
| `Inspect_SingleManifest_ReturnsSinglePlatform` | Image without index | 1 platform, layers present |
| `Inspect_MultiArchIndex_ReturnsAllPlatforms` | Image with 5 platforms | 5 platforms, each with layers |
| `Inspect_DockerManifestList_Parses` | Legacy Docker format | Correctly parsed as index |
| `Inspect_PlatformFilter_ReturnsFiltered` | Filter to linux/amd64 | Only matching platform returned |
| `Inspect_NotFound_ReturnsNull` | 404 response | Returns null, no exception |
| `Inspect_AuthRequired_RefreshesToken` | 401 -> token refresh | Successful after refresh |
| `Inspect_Deterministic_SameOutput` | Same image, multiple calls | Identical result (ignoring timestamp) |
### Integration Tests
| Test | Description | Expected |
|------|-------------|----------|
| `Inspect_DockerHub_NginxLatest` | Public Docker Hub image | Multi-arch result with linux/amd64, linux/arm64 |
| `Inspect_GHCR_PublicImage` | GitHub Container Registry | Valid result |
| `Inspect_MockRegistry_AllScenarios` | Testcontainers registry | All edge cases covered |
## Execution Log
| Date (UTC) | Update | Owner |
|------------|--------|-------|
| 2026-01-13 | Sprint created from advisory analysis. | Project Mgmt |
## Decisions & Risks
- **APPROVED**: Single manifest images return as 1-element platforms array for API consistency.
- **APPROVED**: Use existing `OciRegistryClient` for HTTP operations where compatible.
- **RISK**: Some registries return incorrect Content-Type; handle by sniffing JSON structure.
- **RISK**: Large multi-arch images (10+ platforms) may be slow; add max_platforms limit.
## Next Checkpoints
- Task 1-3 complete -> Basic inspection working
- Task 4-6 complete -> Full index/manifest/layer resolution
- Task 9-10 complete -> Sprint can be marked DONE
- Unblock Sprint 2 (CLI)

View File

@@ -1,283 +0,0 @@
# Sprint 20260113_002_002_CLI - Image Inspect Command
## Topic & Scope
- Implement `stella image inspect` CLI command
- Support `--resolve-index`, `--print-layers`, `--platform` flags
- JSON and human-readable output formats
- Integrate with OCI Image Inspector service
- **Working directory:** `src/Cli/StellaOps.Cli/Commands/`
## Dependencies & Concurrency
- **Depends on:** Sprint 002_001 (OCI Image Inspector Service)
- Parallel work safe within CLI module
- Sprint 3 (Docs) can proceed in parallel
## Documentation Prerequisites
- `docs/README.md`
- `CLAUDE.md` Section 8 (Determinism Rules)
- `src/Cli/StellaOps.Cli/AGENTS.md` (if exists)
- Existing CLI patterns in `LayerSbomCommandGroup.cs`
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
|---|---------|--------|---------------------------|--------|-----------------|
| 1 | CLI-IMAGE-GROUP-0001 | TODO | None | Guild - CLI | Create `ImageCommandGroup.cs` with `stella image` root command and subcommand registration. |
| 2 | CLI-IMAGE-INSPECT-0001 | TODO | Depends on GROUP-0001 | Guild - CLI | Implement `stella image inspect <reference>` command with options: `--resolve-index`, `--print-layers`, `--platform`, `--output`. |
| 3 | CLI-IMAGE-HANDLER-0001 | TODO | Depends on INSPECT-0001, Sprint 001 service | Guild - CLI | Implement `CommandHandlers.Image.cs` with `HandleInspectImageAsync` that calls `IOciImageInspector`. |
| 4 | CLI-IMAGE-OUTPUT-TABLE-0001 | TODO | Depends on HANDLER-0001 | Guild - CLI | Implement table output for human-readable display using Spectre.Console. Show platforms, layers, sizes. |
| 5 | CLI-IMAGE-OUTPUT-JSON-0001 | TODO | Depends on HANDLER-0001 | Guild - CLI | Implement JSON output with canonical ordering. Match schema from Sprint 001 models. |
| 6 | CLI-IMAGE-REGISTER-0001 | TODO | Depends on all above | Guild - CLI | Register `ImageCommandGroup` in `CommandFactory.cs`. Wire DI for `IOciImageInspector`. |
| 7 | CLI-IMAGE-TESTS-0001 | TODO | Depends on all above | Guild - CLI | Unit tests covering: successful inspect, not found, auth error, invalid reference, output formats. |
| 8 | CLI-IMAGE-GOLDEN-0001 | TODO | Depends on TESTS-0001 | Guild - CLI | Golden output tests for determinism: same input produces identical output across runs. |
## Technical Specification
### Command Structure
```
stella image <subcommand>
Subcommands:
inspect Inspect OCI image manifest and layers
```
### `stella image inspect` Command
```
stella image inspect <reference> [options]
Arguments:
<reference> Image reference (e.g., nginx:latest, ghcr.io/org/app@sha256:...)
Options:
--resolve-index, -r Resolve multi-arch index to platform manifests (default: true)
--print-layers, -l Include layer details in output (default: true)
--platform, -p Filter to specific platform (e.g., linux/amd64)
--output, -o Output format: table (default), json
--verbose, -v Show detailed information including warnings
--timeout Request timeout in seconds (default: 60)
Examples:
stella image inspect nginx:latest
stella image inspect nginx:latest --output json
stella image inspect nginx:latest --platform linux/arm64
stella image inspect ghcr.io/org/app@sha256:abc123... --print-layers
```
### Output Examples
#### Table Output (Default)
```
Image: nginx:latest
Resolved Digest: sha256:abc123...
Media Type: application/vnd.oci.image.index.v1+json
Multi-Arch: Yes (5 platforms)
Platforms:
+-------+--------------+----------+---------+---------------+------------+
| OS | Architecture | Variant | Layers | Total Size | Manifest |
+-------+--------------+----------+---------+---------------+------------+
| linux | amd64 | - | 7 | 142.3 MB | sha256:... |
| linux | arm64 | v8 | 7 | 138.1 MB | sha256:... |
| linux | arm | v7 | 7 | 135.2 MB | sha256:... |
| linux | 386 | - | 7 | 145.8 MB | sha256:... |
| linux | ppc64le | - | 7 | 148.5 MB | sha256:... |
+-------+--------------+----------+---------+---------------+------------+
Layers (linux/amd64):
+-------+------------------+------------------------------------------------+----------+
| Order | Size | Digest | Type |
+-------+------------------+------------------------------------------------+----------+
| 0 | 31.4 MB | sha256:a803e7c4b030... | tar+gzip |
| 1 | 62.5 MB | sha256:8a6e7b1c9d2e... | tar+gzip |
| ... | ... | ... | ... |
+-------+------------------+------------------------------------------------+----------+
Inspected at: 2026-01-13T12:00:00Z
```
#### JSON Output
```json
{
"reference": "nginx:latest",
"resolvedDigest": "sha256:abc123...",
"mediaType": "application/vnd.oci.image.index.v1+json",
"isMultiArch": true,
"registry": "docker.io",
"repository": "library/nginx",
"platforms": [
{
"os": "linux",
"architecture": "amd64",
"variant": null,
"manifestDigest": "sha256:def456...",
"configDigest": "sha256:ghi789...",
"layers": [
{
"order": 0,
"digest": "sha256:layer1...",
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
"size": 31457280
}
],
"totalSize": 157286400
}
],
"inspectedAt": "2026-01-13T12:00:00Z",
"inspectorVersion": "1.0.0"
}
```
### Implementation
```csharp
// ImageCommandGroup.cs
namespace StellaOps.Cli.Commands;
public static class ImageCommandGroup
{
public static Command Build(
IServiceProvider services,
StellaOpsCliOptions options,
Option<bool> verboseOption,
CancellationToken cancellationToken)
{
var imageCommand = new Command("image", "OCI image operations");
imageCommand.AddCommand(BuildInspectCommand(services, options, verboseOption, cancellationToken));
return imageCommand;
}
private static Command BuildInspectCommand(
IServiceProvider services,
StellaOpsCliOptions options,
Option<bool> verboseOption,
CancellationToken cancellationToken)
{
var referenceArg = new Argument<string>("reference")
{
Description = "Image reference (e.g., nginx:latest, ghcr.io/org/app@sha256:...)"
};
var resolveIndexOption = new Option<bool>("--resolve-index", new[] { "-r" })
{
Description = "Resolve multi-arch index to platform manifests",
DefaultValue = true
};
var printLayersOption = new Option<bool>("--print-layers", new[] { "-l" })
{
Description = "Include layer details in output",
DefaultValue = true
};
var platformOption = new Option<string?>("--platform", new[] { "-p" })
{
Description = "Filter to specific platform (e.g., linux/amd64)"
};
var outputOption = new Option<string>("--output", new[] { "-o" })
{
Description = "Output format: table (default), json"
};
var timeoutOption = new Option<int>("--timeout")
{
Description = "Request timeout in seconds",
DefaultValue = 60
};
var inspect = new Command("inspect", "Inspect OCI image manifest and layers")
{
referenceArg,
resolveIndexOption,
printLayersOption,
platformOption,
outputOption,
timeoutOption,
verboseOption
};
inspect.SetAction(async (parseResult, _) =>
{
var reference = parseResult.GetValue(referenceArg) ?? string.Empty;
var resolveIndex = parseResult.GetValue(resolveIndexOption);
var printLayers = parseResult.GetValue(printLayersOption);
var platform = parseResult.GetValue(platformOption);
var output = parseResult.GetValue(outputOption) ?? "table";
var timeout = parseResult.GetValue(timeoutOption);
var verbose = parseResult.GetValue(verboseOption);
return await CommandHandlers.HandleInspectImageAsync(
services, reference, resolveIndex, printLayers,
platform, output, timeout, verbose, cancellationToken);
});
return inspect;
}
}
```
### Error Handling
| Scenario | Exit Code | Message |
|----------|-----------|---------|
| Success | 0 | (output) |
| Image not found | 1 | `Error: Image not found: <reference>` |
| Auth required | 2 | `Error: Authentication required for <registry>` |
| Invalid reference | 2 | `Error: Invalid image reference: <reference>` |
| Network error | 2 | `Error: Network error: <message>` |
| Timeout | 2 | `Error: Request timed out` |
### Determinism Requirements
1. **Ordering**: JSON keys sorted; platforms sorted by os/arch/variant
2. **Size formatting**: Use InvariantCulture for all numbers
3. **Timestamps**: Display as UTC ISO-8601
4. **Digest truncation**: Consistent truncation (e.g., first 12 chars for display)
## Test Cases
### Unit Tests
| Test | Description | Expected |
|------|-------------|----------|
| `Inspect_ValidReference_ReturnsSuccess` | Mock successful inspection | Exit code 0, valid output |
| `Inspect_NotFound_ReturnsError` | 404 from registry | Exit code 1, error message |
| `Inspect_InvalidReference_ReturnsError` | Malformed reference | Exit code 2, validation error |
| `Inspect_JsonOutput_ValidJson` | Request JSON format | Parseable JSON output |
| `Inspect_TableOutput_FormatsCorrectly` | Default table format | Table with headers and rows |
| `Inspect_PlatformFilter_FiltersResults` | Filter to linux/amd64 | Only matching platform in output |
### Golden Output Tests
| Test | Description | Expected |
|------|-------------|----------|
| `Inspect_Json_Deterministic` | Same input, multiple runs | Byte-identical JSON |
| `Inspect_Table_Deterministic` | Same input, multiple runs | Identical table output |
## Execution Log
| Date (UTC) | Update | Owner |
|------------|--------|-------|
| 2026-01-13 | Sprint created from advisory analysis. | Project Mgmt |
## Decisions & Risks
- **APPROVED**: Table output as default (more user-friendly).
- **APPROVED**: JSON output matches service model exactly (no transformation).
- **RISK**: CLI tests may conflict with other agent work; coordinate ownership.
- **RISK**: Table formatting may truncate long digests; use consistent truncation.
## Next Checkpoints
- Task 1-3 complete -> Basic command working
- Task 4-5 complete -> Both output formats working
- Task 7-8 complete -> Sprint can be marked DONE

View File

@@ -1,102 +0,0 @@
# Sprint 20260113_002_003_DOCS - Image Inspection Documentation
## Topic & Scope
- Document OCI Image Inspector architecture
- Create CLI reference for `stella image inspect`
- Add usage examples and troubleshooting guide
- **Working directory:** `docs/`
## Dependencies & Concurrency
- Can proceed in parallel with Sprint 002_002
- Should finalize after Sprint 002_001 models are stable
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
|---|---------|--------|---------------------------|--------|-----------------|
| 1 | DOCS-IMAGE-ARCH-0001 | TODO | Sprint 001 complete | Guild - Docs | Create `docs/modules/scanner/image-inspection.md` documenting the OCI Image Inspector service architecture, supported media types, and integration points. |
| 2 | DOCS-IMAGE-CLI-0001 | TODO | Sprint 002 complete | Guild - Docs | Add `stella image inspect` to CLI reference in `docs/API_CLI_REFERENCE.md`. Include all options, examples, and exit codes. |
| 3 | DOCS-IMAGE-EXAMPLES-0001 | TODO | Depends on CLI-0001 | Guild - Docs | Create practical usage examples in `docs/guides/image-inspection-guide.md` covering Docker Hub, GHCR, private registries, and CI/CD integration. |
| 4 | DOCS-IMAGE-TROUBLESHOOT-0001 | TODO | Depends on EXAMPLES-0001 | Guild - Docs | Add troubleshooting section for common issues: auth failures, rate limits, unsupported media types. |
## Technical Specification
### Architecture Documentation Outline
```markdown
# OCI Image Inspection
## Overview
- Purpose and use cases
- Supported registries and media types
## Architecture
- IOciImageInspector interface
- Index vs manifest resolution flow
- Platform enumeration algorithm
## Media Type Support
| Media Type | Description | Support |
|------------|-------------|---------|
| ... | ... | ... |
## Integration Points
- CLI integration
- Programmatic usage
- Webhook/CI integration
## Configuration
- Registry authentication
- Timeout and retry settings
## Determinism
- Output ordering guarantees
- Reproducibility considerations
```
### CLI Reference Addition
```markdown
## stella image inspect
Inspect OCI image manifest and layers.
### Synopsis
stella image inspect <reference> [options]
### Arguments
| Argument | Description |
|----------|-------------|
| reference | Image reference (tag or digest) |
### Options
| Option | Description | Default |
|--------|-------------|---------|
| --resolve-index, -r | Resolve multi-arch index | true |
| --print-layers, -l | Include layer details | true |
| --platform, -p | Platform filter | (all) |
| --output, -o | Output format (table, json) | table |
### Examples
...
### Exit Codes
| Code | Meaning |
|------|---------|
| 0 | Success |
| 1 | Image not found |
| 2 | Error (auth, network, invalid input) |
```
## Execution Log
| Date (UTC) | Update | Owner |
|------------|--------|-------|
| 2026-01-13 | Sprint created from advisory analysis. | Project Mgmt |
## Next Checkpoints
- All tasks complete -> Sprint can be marked DONE
- Coordinate with Sprint 002_001/002 for accuracy

View File

@@ -1,233 +0,0 @@
# Sprint Batch 20260113_003 - VEX Evidence Auto-Linking
## Executive Summary
This sprint batch implements **automatic linking** between VEX exploitability status and DSSE binary-diff evidence bundles. When a binary analysis determines a vulnerability is "not_affected" due to a vendor backport, the system automatically links the VEX assertion to the cryptographic evidence that proves the claim.
**Scope:** VEX-to-evidence linking for binary-diff attestations
**Effort Estimate:** 3-4 story points across 2 sprints
**Priority:** Medium (completes evidence chain)
## Background
### Advisory Requirements
The original advisory specified:
> Surface exploitability conclusions via CycloneDX VEX (e.g., "CVE-X.Y not affected due to backported fix; evidence -> DSSE bundle link").
> For each CVE in SBOM components, attach exploitability status with `analysis.justification` ("component_not_present", "vulnerable_code_not_in_execute_path", "fixed", etc.) and `analysis.detail` linking the DSSE evidence URI.
### Existing Capabilities
| Component | Status | Location |
|-----------|--------|----------|
| `VexPredicate` | EXISTS | `src/Attestor/__Libraries/.../Predicates/VexPredicate.cs` |
| `VexDeltaEntity` | EXISTS | `src/Excititor/__Libraries/.../Observations/VexDeltaModels.cs` |
| `CycloneDxExporter` | EXISTS | `src/Excititor/__Libraries/.../CycloneDxExporter.cs` |
| `BinaryDiffV1 Predicate` | IN PROGRESS | Batch 001 Sprint 002 |
| `BinaryDiffDsseSigner` | IN PROGRESS | Batch 001 Sprint 002 |
### Gap Analysis
| Capability | Status |
|------------|--------|
| Store DSSE bundle URIs with VEX assertions | MISSING |
| Auto-link binary-diff evidence to VEX | MISSING |
| Emit `analysis.detail` with evidence URI in CycloneDX VEX | MISSING |
| CLI `stella vex gen` with evidence links | PARTIAL |
## Sprint Index
| Sprint | ID | Module | Topic | Status | Owner |
|--------|-----|--------|-------|--------|-------|
| 1 | SPRINT_20260113_003_001 | EXCITITOR | VEX Evidence Linker Service | TODO | Guild - Excititor |
| 2 | SPRINT_20260113_003_002 | CLI | VEX Generation with Evidence Links | TODO | Guild - CLI |
## Dependencies
```
+-----------------------------------------------------------------------+
| Dependency Graph |
+-----------------------------------------------------------------------+
| |
| Batch 001 (Binary Diff Attestation) |
| | |
| v |
| Sprint 1 (VEX Evidence Linker) |
| | |
| v |
| Sprint 2 (CLI Integration) |
| |
+-----------------------------------------------------------------------+
```
**Cross-Batch Dependencies:**
- Batch 001 Sprint 002 (BinaryDiffV1 predicate) must be complete
- VEX Evidence Linker consumes DSSE bundle URIs from binary diff
## Acceptance Criteria (Batch-Level)
### Must Have
1. **Evidence URI Storage**
- Store DSSE bundle URIs alongside VEX assertions
- Support multiple evidence sources per VEX entry
- URIs point to OCI artifact digests or CAS addresses
2. **Auto-Link on Binary Diff**
- When binary diff detects "patched" verdict, create VEX link
- Link includes: DSSE envelope digest, predicate type, confidence score
- Justification auto-set to "vulnerable_code_not_in_execute_path" or "code_not_reachable"
3. **CycloneDX VEX Output**
- `analysis.detail` contains evidence URI
- `analysis.response` includes evidence metadata
- Compatible with CycloneDX VEX 1.5+ schema
4. **CLI Integration**
- `stella vex gen` includes `--link-evidence` flag
- JSON output contains evidence links
- Human-readable output shows evidence summary
### Should Have
- Confidence threshold filtering (only link if confidence >= X)
- Evidence chain validation (verify DSSE before linking)
### Deferred (Out of Scope)
- UI for evidence visualization (follow-up sprint)
- Evidence refresh/update workflow
- Third-party evidence import
## Technical Context
### Key Files to Create/Extend
| Component | File | Purpose |
|-----------|------|---------|
| Evidence Linker | `src/Excititor/__Libraries/StellaOps.Excititor.Core/Evidence/VexEvidenceLinker.cs` | NEW: Service to link VEX -> DSSE |
| Evidence Models | `src/Excititor/__Libraries/StellaOps.Excititor.Core/Evidence/VexEvidenceLinkModels.cs` | NEW: Link models |
| CycloneDX Mapper | `src/Excititor/__Libraries/.../CycloneDxVexMapper.cs` | EXTEND: Add evidence links |
| CLI Handler | `src/Cli/StellaOps.Cli/Commands/VexGenCommandGroup.cs` | EXTEND: Add evidence option |
### VEX with Evidence Link Schema (CycloneDX)
```json
{
"bomFormat": "CycloneDX",
"specVersion": "1.6",
"vulnerabilities": [
{
"id": "CVE-2023-12345",
"source": { "name": "NVD" },
"analysis": {
"state": "not_affected",
"justification": "code_not_reachable",
"detail": "Binary analysis confirms vendor backport applied. Evidence: oci://registry.example.com/evidence@sha256:abc123",
"response": ["update"],
"firstIssued": "2026-01-13T12:00:00Z"
},
"affects": [
{
"ref": "urn:cdx:stellaops/app@1.0.0/libssl.so.3",
"versions": [{ "version": "3.0.2", "status": "unaffected" }]
}
],
"properties": [
{
"name": "stellaops:evidence:type",
"value": "binary-diff"
},
{
"name": "stellaops:evidence:uri",
"value": "oci://registry.example.com/evidence@sha256:abc123..."
},
{
"name": "stellaops:evidence:confidence",
"value": "0.95"
},
{
"name": "stellaops:evidence:predicate-type",
"value": "stellaops.binarydiff.v1"
}
]
}
]
}
```
### Evidence Link Model
```csharp
public sealed record VexEvidenceLink
{
/// <summary>Type of evidence (binary-diff, reachability, runtime, etc.).</summary>
public required string EvidenceType { get; init; }
/// <summary>URI to the DSSE bundle (oci://, cas://, file://).</summary>
public required string EvidenceUri { get; init; }
/// <summary>Digest of the DSSE envelope.</summary>
public required string EnvelopeDigest { get; init; }
/// <summary>Predicate type in the DSSE envelope.</summary>
public required string PredicateType { get; init; }
/// <summary>Confidence score (0.0-1.0).</summary>
public required double Confidence { get; init; }
/// <summary>When the evidence was created.</summary>
public required DateTimeOffset CreatedAt { get; init; }
/// <summary>Signer identity (key ID or certificate subject).</summary>
public string? SignerIdentity { get; init; }
/// <summary>Rekor log index if submitted to transparency log.</summary>
public string? RekorLogIndex { get; init; }
}
```
## Risk Assessment
| Risk | Likelihood | Impact | Mitigation |
|------|------------|--------|------------|
| Evidence URI format inconsistency | Medium | Medium | Define URI schema spec; validate on link |
| Stale evidence links | Medium | Low | Include evidence timestamp; optional refresh |
| Large evidence bundles | Low | Medium | Link to bundle, don't embed content |
## Success Metrics
- [ ] VEX output includes evidence links when available
- [ ] Evidence URIs resolve to valid DSSE bundles
- [ ] CLI shows evidence in human-readable format
- [ ] CycloneDX VEX validates against schema
## Documentation Prerequisites
Before starting implementation, reviewers must read:
- `docs/README.md`
- `docs/ARCHITECTURE_REFERENCE.md`
- `CLAUDE.md` Section 8 (Code Quality & Determinism Rules)
- CycloneDX VEX specification: https://cyclonedx.org/capabilities/vex/
- Batch 001 BinaryDiffV1 predicate schema
## Execution Log
| Date (UTC) | Update | Owner |
|------------|--------|-------|
| 2026-01-13 | Sprint batch created from advisory analysis. | Project Mgmt |
## Decisions & Risks
- **APPROVED 2026-01-13**: Evidence stored as URI references, not embedded content.
- **APPROVED 2026-01-13**: Use CycloneDX `properties[]` for Stella-specific evidence metadata.
- **RISK**: CycloneDX `analysis.detail` has length limits; use URI not full content.
## Next Checkpoints
- Batch 001 Sprint 002 complete -> Sprint 1 can start
- Sprint 1 complete -> Sprint 2 can start
- All sprints complete -> Integration testing checkpoint

View File

@@ -1,377 +0,0 @@
# Sprint 20260113_003_001_EXCITITOR - VEX Evidence Linker Service
## Topic & Scope
- Implement VEX-to-evidence linking service
- Auto-link binary-diff attestations to VEX assertions
- Store evidence URIs alongside VEX entries
- Emit evidence metadata in CycloneDX VEX output
- **Working directory:** `src/Excititor/__Libraries/StellaOps.Excititor.Core/`
## Dependencies & Concurrency
- **Depends on:** Batch 001 Sprint 002 (BinaryDiffV1 predicate)
- Parallel work safe within Excititor module
- Sprint 2 (CLI) depends on this sprint
## Documentation Prerequisites
- `docs/README.md`
- `CLAUDE.md` Section 8 (Determinism Rules)
- CycloneDX VEX specification: https://cyclonedx.org/capabilities/vex/
- Batch 001 BinaryDiffV1 predicate schema
- Existing VEX models in `src/Excititor/__Libraries/.../VexDeltaModels.cs`
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
|---|---------|--------|---------------------------|--------|-----------------|
| 1 | VEX-LINK-MODELS-0001 | TODO | None | Guild - Excititor | Define `VexEvidenceLink`, `VexEvidenceLinkSet`, and `EvidenceType` enum in `Evidence/VexEvidenceLinkModels.cs`. Include URI, digest, predicate type, confidence, timestamps. |
| 2 | VEX-LINK-INTERFACE-0001 | TODO | Depends on MODELS-0001 | Guild - Excititor | Define `IVexEvidenceLinker` interface with `LinkAsync(vexEntry, evidenceSource, ct)` and `GetLinksAsync(vexEntryId, ct)` methods. |
| 3 | VEX-LINK-BINARYDIFF-0001 | TODO | Depends on INTERFACE-0001, Batch 001 | Guild - Excititor | Implement `BinaryDiffEvidenceLinker` that extracts evidence from `BinaryDiffPredicate` findings and creates `VexEvidenceLink` entries. |
| 4 | VEX-LINK-STORE-0001 | TODO | Depends on MODELS-0001 | Guild - Excititor | Implement `IVexEvidenceLinkStore` interface and in-memory implementation. Define PostgreSQL schema for persistent storage. |
| 5 | VEX-LINK-AUTOLINK-0001 | TODO | Depends on BINARYDIFF-0001 | Guild - Excititor | Implement auto-linking pipeline: when binary-diff produces "patched" verdict, create VEX link with appropriate justification. |
| 6 | VEX-LINK-CYCLONEDX-0001 | TODO | Depends on AUTOLINK-0001 | Guild - Excititor | Extend `CycloneDxVexMapper` to emit `analysis.detail` with evidence URI and `properties[]` with evidence metadata. |
| 7 | VEX-LINK-VALIDATION-0001 | TODO | Depends on all above | Guild - Excititor | Implement evidence validation: verify DSSE signature before accepting link. Optional: verify Rekor inclusion. |
| 8 | VEX-LINK-DI-0001 | TODO | Depends on all above | Guild - Excititor | Register all services in DI. Add `IOptions<VexEvidenceLinkOptions>` for configuration (confidence threshold, validation mode). |
| 9 | VEX-LINK-TESTS-0001 | TODO | Depends on all above | Guild - Excititor | Unit tests covering: link creation, storage, auto-linking, CycloneDX output, validation success/failure. |
## Technical Specification
### Models
```csharp
namespace StellaOps.Excititor.Core.Evidence;
/// <summary>
/// Link between a VEX assertion and supporting evidence.
/// </summary>
public sealed record VexEvidenceLink
{
/// <summary>Unique link identifier.</summary>
public required string LinkId { get; init; }
/// <summary>VEX entry this evidence supports.</summary>
public required string VexEntryId { get; init; }
/// <summary>Type of evidence.</summary>
public required EvidenceType EvidenceType { get; init; }
/// <summary>URI to the evidence artifact (oci://, cas://, https://).</summary>
public required string EvidenceUri { get; init; }
/// <summary>Digest of the DSSE envelope (sha256:...).</summary>
public required string EnvelopeDigest { get; init; }
/// <summary>Predicate type in the DSSE envelope.</summary>
public required string PredicateType { get; init; }
/// <summary>Confidence score from the evidence (0.0-1.0).</summary>
public required double Confidence { get; init; }
/// <summary>Justification derived from evidence.</summary>
public required VexJustification Justification { get; init; }
/// <summary>When the evidence was created.</summary>
public required DateTimeOffset EvidenceCreatedAt { get; init; }
/// <summary>When the link was created.</summary>
public required DateTimeOffset LinkedAt { get; init; }
/// <summary>Signer identity (key ID or certificate subject).</summary>
public string? SignerIdentity { get; init; }
/// <summary>Rekor log index if submitted to transparency log.</summary>
public string? RekorLogIndex { get; init; }
/// <summary>Whether the evidence signature was validated.</summary>
public bool SignatureValidated { get; init; }
/// <summary>Additional metadata as key-value pairs.</summary>
public ImmutableDictionary<string, string> Metadata { get; init; }
= ImmutableDictionary<string, string>.Empty;
}
/// <summary>
/// Types of evidence that can support VEX assertions.
/// </summary>
public enum EvidenceType
{
/// <summary>Binary-level diff showing patch applied.</summary>
BinaryDiff,
/// <summary>Call graph analysis showing code not reachable.</summary>
ReachabilityAnalysis,
/// <summary>Runtime analysis showing code not executed.</summary>
RuntimeAnalysis,
/// <summary>Human attestation (manual review).</summary>
HumanAttestation,
/// <summary>Vendor advisory or statement.</summary>
VendorAdvisory,
/// <summary>Other/custom evidence type.</summary>
Other
}
/// <summary>
/// VEX justification codes (CycloneDX compatible).
/// </summary>
public enum VexJustification
{
CodeNotPresent,
CodeNotReachable,
RequiresConfiguration,
RequiresDependency,
RequiresEnvironment,
ProtectedByCompiler,
ProtectedAtRuntime,
ProtectedAtPerimeter,
ProtectedByMitigatingControl
}
/// <summary>
/// Collection of evidence links for a VEX entry.
/// </summary>
public sealed record VexEvidenceLinkSet
{
/// <summary>VEX entry ID.</summary>
public required string VexEntryId { get; init; }
/// <summary>All evidence links, sorted by confidence descending.</summary>
public required ImmutableArray<VexEvidenceLink> Links { get; init; }
/// <summary>Highest confidence among all links.</summary>
public double MaxConfidence => Links.IsEmpty ? 0 : Links.Max(l => l.Confidence);
/// <summary>Primary link (highest confidence).</summary>
public VexEvidenceLink? PrimaryLink => Links.IsEmpty ? null : Links[0];
}
```
### Interfaces
```csharp
namespace StellaOps.Excititor.Core.Evidence;
/// <summary>
/// Service for linking VEX assertions to supporting evidence.
/// </summary>
public interface IVexEvidenceLinker
{
/// <summary>
/// Creates a link between a VEX entry and evidence.
/// </summary>
Task<VexEvidenceLink> LinkAsync(
string vexEntryId,
EvidenceSource source,
CancellationToken cancellationToken = default);
/// <summary>
/// Gets all evidence links for a VEX entry.
/// </summary>
Task<VexEvidenceLinkSet> GetLinksAsync(
string vexEntryId,
CancellationToken cancellationToken = default);
/// <summary>
/// Auto-links evidence from a binary diff result.
/// </summary>
Task<ImmutableArray<VexEvidenceLink>> AutoLinkFromBinaryDiffAsync(
BinaryDiffPredicate diff,
string dsseEnvelopeUri,
CancellationToken cancellationToken = default);
}
/// <summary>
/// Source of evidence for linking.
/// </summary>
public sealed record EvidenceSource
{
/// <summary>Evidence type.</summary>
public required EvidenceType Type { get; init; }
/// <summary>URI to the evidence artifact.</summary>
public required string Uri { get; init; }
/// <summary>Digest of the artifact.</summary>
public required string Digest { get; init; }
/// <summary>Predicate type if DSSE/in-toto.</summary>
public string? PredicateType { get; init; }
/// <summary>Confidence score.</summary>
public double Confidence { get; init; } = 1.0;
/// <summary>DSSE envelope bytes for validation.</summary>
public byte[]? EnvelopeBytes { get; init; }
}
/// <summary>
/// Storage for evidence links.
/// </summary>
public interface IVexEvidenceLinkStore
{
Task SaveAsync(VexEvidenceLink link, CancellationToken ct = default);
Task<VexEvidenceLink?> GetAsync(string linkId, CancellationToken ct = default);
Task<ImmutableArray<VexEvidenceLink>> GetByVexEntryAsync(string vexEntryId, CancellationToken ct = default);
Task DeleteAsync(string linkId, CancellationToken ct = default);
}
```
### Auto-Link Algorithm
```pseudo
function AutoLinkFromBinaryDiff(diff, dsseUri):
links = []
for finding in diff.findings where finding.verdict == Patched:
// Determine affected VEX entry
vexEntryId = LookupVexEntry(finding.path, diff.inputs.target)
if vexEntryId is null:
continue // No matching VEX entry
// Determine justification from finding
justification = DetermineJustification(finding)
// Create link
link = VexEvidenceLink {
linkId: GenerateId(vexEntryId, dsseUri),
vexEntryId: vexEntryId,
evidenceType: BinaryDiff,
evidenceUri: dsseUri,
envelopeDigest: ComputeDigest(diff),
predicateType: "stellaops.binarydiff.v1",
confidence: finding.confidence ?? 0.9,
justification: justification,
evidenceCreatedAt: diff.metadata.analysisTimestamp,
linkedAt: timeProvider.GetUtcNow()
}
links.append(link)
return links
function DetermineJustification(finding):
// If .text section changed -> code was patched
if finding.sectionDeltas.any(d => d.section == ".text" && d.status == Modified):
return CodeNotPresent // Vulnerable code removed/replaced
// If only .rodata changed -> data patched
if finding.sectionDeltas.all(d => d.section != ".text"):
return ProtectedAtRuntime // Runtime behavior changed
return CodeNotReachable // Default for verified patches
```
### CycloneDX Output Enhancement
```csharp
// In CycloneDxVexMapper
private void MapEvidenceLinks(VulnerabilityAnalysis analysis, VexEvidenceLinkSet links)
{
if (links.PrimaryLink is null) return;
var primary = links.PrimaryLink;
// Set analysis.detail with evidence URI
analysis.Detail = $"Evidence: {primary.EvidenceUri}";
// Add evidence properties
analysis.Properties ??= [];
analysis.Properties.Add(new Property
{
Name = "stellaops:evidence:type",
Value = primary.EvidenceType.ToString().ToLowerInvariant()
});
analysis.Properties.Add(new Property
{
Name = "stellaops:evidence:uri",
Value = primary.EvidenceUri
});
analysis.Properties.Add(new Property
{
Name = "stellaops:evidence:confidence",
Value = primary.Confidence.ToString("F2", CultureInfo.InvariantCulture)
});
analysis.Properties.Add(new Property
{
Name = "stellaops:evidence:predicate-type",
Value = primary.PredicateType
});
if (primary.RekorLogIndex is not null)
{
analysis.Properties.Add(new Property
{
Name = "stellaops:evidence:rekor-index",
Value = primary.RekorLogIndex
});
}
}
```
### Configuration
```yaml
excititor:
evidence:
linking:
enabled: true
autoLinkOnBinaryDiff: true
confidenceThreshold: 0.8
validateSignatures: true
validateRekorInclusion: false
maxLinksPerEntry: 10
```
## Determinism Requirements
1. **Link ID generation**: Deterministic from vexEntryId + evidenceUri
2. **Ordering**: Links sorted by confidence DESC, then by linkedAt ASC
3. **Timestamps**: From injected `TimeProvider`
4. **Confidence formatting**: Two decimal places, InvariantCulture
## Test Cases
### Unit Tests
| Test | Description | Expected |
|------|-------------|----------|
| `Link_ValidSource_CreatesLink` | Link with valid evidence | Link created with correct fields |
| `Link_DuplicateSource_Deduplicates` | Same source linked twice | Single link returned |
| `AutoLink_PatchedFinding_CreatesLinks` | Binary diff with patched verdict | Links created for affected entries |
| `AutoLink_VanillaFinding_NoLinks` | Binary diff with vanilla verdict | No links created |
| `GetLinks_ExistingEntry_ReturnsSet` | Query by VEX entry ID | All links returned, sorted |
| `MapCycloneDx_WithLinks_IncludesEvidence` | CycloneDX export with links | Properties contain evidence metadata |
| `Validate_ValidSignature_Succeeds` | DSSE with valid signature | Validation passes |
| `Validate_InvalidSignature_Rejects` | DSSE with bad signature | Validation fails, link rejected |
### Integration Tests
| Test | Description | Expected |
|------|-------------|----------|
| `EndToEnd_BinaryDiffToVex_LinksEvidence` | Full pipeline from diff to VEX | VEX output contains evidence links |
## Execution Log
| Date (UTC) | Update | Owner |
|------------|--------|-------|
| 2026-01-13 | Sprint created from advisory analysis. | Project Mgmt |
## Decisions & Risks
- **APPROVED**: Evidence stored as URIs, not embedded content.
- **APPROVED**: Auto-link only for high-confidence findings (>= threshold).
- **RISK**: Signature validation may fail for offline evidence; add bypass option.
- **RISK**: VEX entry lookup requires correlation logic; may need component PURL matching.
## Next Checkpoints
- Task 1-4 complete -> Core linking operational
- Task 5-6 complete -> Auto-link and CycloneDX working
- Task 9 complete -> Sprint can be marked DONE
- Unblock Sprint 2 (CLI)

View File

@@ -1,132 +0,0 @@
# Sprint 20260113_003_002_CLI - VEX Generation with Evidence Links
## Topic & Scope
- Extend `stella vex gen` command with evidence linking
- Add `--link-evidence` flag to include binary-diff evidence
- Display evidence summary in human-readable output
- Emit evidence metadata in JSON output
- **Working directory:** `src/Cli/StellaOps.Cli/Commands/`
## Dependencies & Concurrency
- **Depends on:** Sprint 003_001 (VEX Evidence Linker)
- Extends existing `VexGenCommandGroup.cs`
## Documentation Prerequisites
- `docs/README.md`
- `CLAUDE.md` Section 8 (Determinism Rules)
- Existing VEX CLI in `src/Cli/StellaOps.Cli/Commands/VexGenCommandGroup.cs`
- Sprint 003_001 models and interfaces
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
|---|---------|--------|---------------------------|--------|-----------------|
| 1 | CLI-VEX-EVIDENCE-OPT-0001 | TODO | None | Guild - CLI | Add `--link-evidence` option to `stella vex gen` command. Default: true if evidence available. |
| 2 | CLI-VEX-EVIDENCE-HANDLER-0001 | TODO | Depends on OPT-0001, Sprint 001 | Guild - CLI | Extend VEX generation handler to call `IVexEvidenceLinker.GetLinksAsync()` and include in output. |
| 3 | CLI-VEX-EVIDENCE-JSON-0001 | TODO | Depends on HANDLER-0001 | Guild - CLI | Emit evidence links in JSON output under `evidence` key per vulnerability. |
| 4 | CLI-VEX-EVIDENCE-TABLE-0001 | TODO | Depends on HANDLER-0001 | Guild - CLI | Show evidence summary in table output: type, confidence, URI (truncated). |
| 5 | CLI-VEX-EVIDENCE-TESTS-0001 | TODO | Depends on all above | Guild - CLI | Unit tests for evidence flag, output formats, missing evidence handling. |
## Technical Specification
### Command Enhancement
```
stella vex gen <scan-id> [options]
Existing options:
--output, -o Output format (json, table, cyclonedx)
--format, -f VEX format (openvex, cyclonedx)
New options:
--link-evidence Include evidence links in output (default: true)
--evidence-threshold Minimum confidence for evidence (default: 0.8)
--show-evidence-uri Show full evidence URIs (default: truncated)
```
### Output Examples
#### Table Output with Evidence
```
VEX Report for scan abc123
+----------------+-------------+----------------+------------+------------------+
| CVE | Component | Status | Confidence | Evidence |
+----------------+-------------+----------------+------------+------------------+
| CVE-2023-12345 | libssl.so.3 | not_affected | 0.95 | binary-diff [OK] |
| CVE-2023-67890 | libcrypto | affected | - | (none) |
| CVE-2024-11111 | nginx | not_affected | 0.88 | reachability |
+----------------+-------------+----------------+------------+------------------+
Evidence Details:
CVE-2023-12345: oci://registry/evidence@sha256:abc123...
Type: binary-diff, Predicate: stellaops.binarydiff.v1
Signer: CN=StellaOps Signing Key
```
#### JSON Output with Evidence
```json
{
"scanId": "abc123",
"generatedAt": "2026-01-13T12:00:00Z",
"vulnerabilities": [
{
"id": "CVE-2023-12345",
"component": "libssl.so.3",
"status": "not_affected",
"justification": "code_not_present",
"evidence": {
"type": "binary-diff",
"uri": "oci://registry/evidence@sha256:abc123...",
"confidence": 0.95,
"predicateType": "stellaops.binarydiff.v1",
"validatedSignature": true,
"rekorIndex": "12345678"
}
}
]
}
```
### Implementation Notes
```csharp
// Extend HandleVexGenAsync
if (linkEvidence)
{
var linker = services.GetRequiredService<IVexEvidenceLinker>();
foreach (var entry in vexEntries)
{
var links = await linker.GetLinksAsync(entry.Id, ct);
if (links.PrimaryLink is not null && links.MaxConfidence >= evidenceThreshold)
{
entry.Evidence = links.PrimaryLink;
}
}
}
```
## Test Cases
| Test | Description | Expected |
|------|-------------|----------|
| `VexGen_WithEvidence_IncludesLinks` | Evidence available | Links in output |
| `VexGen_NoEvidence_OmitsField` | No evidence | `evidence: null` |
| `VexGen_BelowThreshold_Filtered` | Low confidence evidence | Evidence omitted |
| `VexGen_TableFormat_ShowsSummary` | Table output | Evidence column populated |
## Execution Log
| Date (UTC) | Update | Owner |
|------------|--------|-------|
| 2026-01-13 | Sprint created from advisory analysis. | Project Mgmt |
## Next Checkpoints
- All tasks complete -> Sprint can be marked DONE
- Batch 003 complete -> Evidence chain operational

View File

@@ -1,17 +1,20 @@
# Sprint Batch 20260113_004 - Golden Pairs Pilot (Vendor Backport Corpus)
# Sprint 20260113_004_000 - Index - Golden Pairs Pilot
## Executive Summary
## Topic & Scope
- Build the curated golden pairs dataset infrastructure to validate binary diff accuracy against real backports.
- Define data models, mirroring pipeline, and a three-CVE pilot corpus for regression testing.
- Align Tools implementation with the Scanner binary diff features for deterministic validation.
- **Working directory:** `docs/implplan`.
### Executive Summary
This sprint batch implements a **curated dataset infrastructure** for binary patch verification. "Golden pairs" are matched sets of stock (upstream) vs vendor-patched binaries tied to specific CVEs, enabling validation of the binary diff system's ability to detect vendor backports.
**Scope:** Pilot corpus with 3 CVEs (Dirty Pipe, sudo Baron Samedit, PrintNightmare)
**Effort Estimate:** 5-6 story points across 3 sprints
**Priority:** Medium (validation infrastructure)
## Background
### Advisory Requirements
### Background
#### Advisory Requirements
The original advisory specified:
> A curated dataset of **stock vs vendor-patched binaries** tied to authoritative **CVE + patch evidence** lets Stella Ops prove (with bytes) that a fix is present, powering deterministic VEX and "evidence-first" decisions.
@@ -19,16 +22,15 @@ The original advisory specified:
> **Starter CVEs (tiny pilot):**
> - **Linux:** Dirty Pipe (CVE-2022-0847) - kernel backport showcase
> - **Unix userland:** sudo "Baron Samedit" (CVE-2021-3156) - classic multi-distro patch
> - **Windows:** PrintNightmare (CVE-2021-34527) - PE + KB workflow
### Why Golden Pairs Matter
> - **Windows:** PrintNightmare (CVE-2021-34527) - PE and KB workflow
#### Why Golden Pairs Matter
1. **Validation**: Ground truth for testing binary diff accuracy
2. **Regression Testing**: Detect if changes break patch detection
3. **Precision Metrics**: Measure actual false positive/negative rates
3. **Precision Metrics**: Measure actual false positive and false negative rates
4. **Documentation**: Examples of vendor backport patterns
### Existing Capabilities
#### Existing Capabilities
| Component | Status | Location |
|-----------|--------|----------|
@@ -37,7 +39,7 @@ The original advisory specified:
| Function Fingerprinting | EXISTS | `src/BinaryIndex/__Libraries/.../FingerprintModels.cs` |
| Build-ID Index | EXISTS | `src/Scanner/.../Index/OfflineBuildIdIndex.cs` |
### Gap Analysis
#### Gap Analysis
| Capability | Status |
|------------|--------|
@@ -46,59 +48,33 @@ The original advisory specified:
| Diff pipeline for corpus | MISSING |
| Validation harness | MISSING |
## Sprint Index
### Sprint Index
| Sprint | ID | Module | Topic | Status | Owner |
|--------|-----|--------|-------|--------|-------|
| 1 | SPRINT_20260113_004_001 | TOOLS | Golden Pairs Data Model & Schema | TODO | Guild - Tools |
| 2 | SPRINT_20260113_004_002 | TOOLS | Mirror & Diff Pipeline | TODO | Guild - Tools |
| 3 | SPRINT_20260113_004_003 | TOOLS | Pilot CVE Corpus (3 CVEs) | TODO | Guild - Tools |
| 1 | SPRINT_20260113_004_001 | TOOLS | Golden Pairs Data Model and Schema | DONE | Guild - Tools |
| 2 | SPRINT_20260113_004_002 | TOOLS | Mirror and Diff Pipeline | DONE | Guild - Tools |
| 3 | SPRINT_20260113_004_003 | TOOLS | Pilot CVE Corpus (3 CVEs) | BLOCKED | Guild - Tools |
## Dependencies
```
+-----------------------------------------------------------------------+
| Dependency Graph |
+-----------------------------------------------------------------------+
| |
| Batch 001 (ELF Section Hashes) |
| | |
| v |
| Sprint 1 (Data Model) |
| | |
| v |
| Sprint 2 (Mirror & Diff Pipeline) |
| | |
| v |
| Sprint 3 (Pilot Corpus) |
| |
+-----------------------------------------------------------------------+
```
**Cross-Batch Dependencies:**
- Batch 001 Sprint 001 (ELF Section Hashes) should be complete for validation
- Pipeline uses section hashes for diff validation
## Acceptance Criteria (Batch-Level)
### Must Have
### Acceptance Criteria (Batch-Level)
#### Must Have
1. **Data Model**
- Schema for golden pair metadata (CVE, package, distro, versions)
- Support for ELF (Linux) and PE (Windows) binaries
- Storage for original + patched binaries with hashes
- Storage for original and patched binaries with hashes
- Links to vendor advisories and patch commits
2. **Mirror Scripts**
- Fetch pre-patch and post-patch package versions
- Support Debian/Ubuntu apt repos
- Support Debian and Ubuntu apt repos
- Hash verification on download
- Deterministic mirroring (reproducible)
3. **Diff Pipeline**
- Run section hash extraction on pairs
- Produce comparison JSON report
- Compute match/mismatch metrics
- Compute match and mismatch metrics
- Validate against expected outcomes
4. **Pilot Corpus (3 CVEs)**
@@ -106,21 +82,19 @@ The original advisory specified:
- CVE-2021-3156 (Baron Samedit): sudo binary pair
- CVE-2021-34527 (PrintNightmare): Windows spoolsv.dll pair (if PE ready)
### Should Have
#### Should Have
- Debug symbol extraction (dbgsym packages)
- Function-level diff report
- CI integration for regression testing
### Deferred (Out of Scope)
- Ghidra/Diaphora integration (separate sprint)
#### Deferred (Out of Scope)
- Ghidra and Diaphora integration (separate sprint)
- Full multi-distro coverage
- Automated corpus updates
## Technical Context
### Technical Context
### Repository Layout
#### Repository Layout
```
src/Tools/GoldenPairs/
@@ -157,7 +131,7 @@ datasets/golden-pairs/
+-- README.md
```
### Metadata Schema
#### Metadata Schema
```json
{
@@ -207,7 +181,7 @@ datasets/golden-pairs/
}
```
### Diff Report Schema
#### Diff Report Schema
```json
{
@@ -227,7 +201,7 @@ datasets/golden-pairs/
}
```
## Risk Assessment
### Risk Assessment
| Risk | Likelihood | Impact | Mitigation |
|------|------------|--------|------------|
@@ -236,38 +210,55 @@ datasets/golden-pairs/
| Windows PE complexity | High | Medium | Defer PrintNightmare if PE support not ready |
| Hash instability | Low | Medium | Pin to specific package versions |
## Success Metrics
### Success Metrics
- [ ] 3 CVE pairs with complete metadata
- [ ] Mirror scripts fetch correct versions
- [ ] Diff pipeline produces expected verdicts
- [ ] CI regression test passes
- [ ] Documentation complete
## Documentation Prerequisites
## Dependencies & Concurrency
- Batch 001 Sprint 001 (ELF Section Hashes) should be complete for validation.
- Sprint 1 is foundational; Sprint 2 depends on the data model, Sprint 3 depends on the pipeline.
- Other 20260113_004_000 planning artifacts are index-only, so parallel edits remain safe.
```
Batch 001 Sprint 001 (ELF Hashes)
-> Sprint 1 (Data Model)
Sprint 1 (Data Model)
-> Sprint 2 (Mirror and Diff Pipeline)
Sprint 2 (Mirror and Diff Pipeline)
-> Sprint 3 (Pilot Corpus)
```
## Documentation Prerequisites
Before starting implementation, reviewers must read:
- `docs/README.md`
- `CLAUDE.md` Section 8 (Code Quality & Determinism Rules)
- `CLAUDE.md` Section 8 (Code Quality and Determinism Rules)
- Batch 001 ELF section hash schema
- ELF specification for section analysis
## Execution Log
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| 1 | INDEX-20260113-004-000-01 | DONE | None | Project Mgmt | Normalize sprint batch index to standard template and ASCII-only formatting. |
| 2 | INDEX-20260113-004-000-02 | DONE | None | Project Mgmt | Clarify dependency flow and checkpoint wording without changing scope. |
## Execution Log
| Date (UTC) | Update | Owner |
|------------|--------|-------|
| 2026-01-13 | Sprint batch created from advisory analysis. | Project Mgmt |
| 2026-01-13 | Normalized sprint file to standard template; ASCII-only cleanup; no semantic changes. | Project Mgmt |
| 2026-01-13 | Updated sprint statuses (004_001 DONE, 004_002 DONE, 004_003 BLOCKED). | Tools |
## Decisions & Risks
- **APPROVED 2026-01-13**: Pilot with 3 CVEs; expand corpus in follow-up sprint.
- **APPROVED 2026-01-13**: Focus on ELF first; PE support conditional on Batch 001 progress.
- **APPROVED 2026-01-13**: Store binaries in datasets/, not in git LFS initially.
- **RISK**: Kernel binaries are large; consider extracting specific .ko modules instead.
## Next Checkpoints
- Sprint 1 complete -> Data model ready for population
- Sprint 2 complete -> Pipeline can process pairs
- Sprint 3 complete -> Pilot corpus validated, CI integrated

View File

@@ -25,14 +25,14 @@
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
|---|---------|--------|---------------------------|--------|-----------------|
| 1 | GP-MODEL-METADATA-0001 | TODO | None | Guild - Tools | Define `GoldenPairMetadata` record with CVE, artifact, original/patched refs, patch info, advisories, expected diff. |
| 2 | GP-MODEL-ARTIFACT-0001 | TODO | None | Guild - Tools | Define `BinaryArtifact` record with package, version, distro, source, hashes, buildId, symbols availability. |
| 3 | GP-MODEL-DIFF-0001 | TODO | None | Guild - Tools | Define `GoldenDiffReport` record with section comparison, verdict, confidence, tool version. |
| 4 | GP-SCHEMA-JSON-0001 | TODO | Depends on MODEL-* | Guild - Tools | Create JSON Schema `golden-pair-v1.schema.json` for metadata validation. Publish to `docs/schemas/`. |
| 5 | GP-SCHEMA-INDEX-0001 | TODO | Depends on SCHEMA-JSON | Guild - Tools | Create corpus index schema `golden-pairs-index.schema.json` for dataset manifest. |
| 6 | GP-STORAGE-LAYOUT-0001 | TODO | Depends on MODEL-* | Guild - Tools | Document storage layout in `datasets/golden-pairs/README.md`. Include artifact naming conventions. |
| 7 | GP-MODEL-LOADER-0001 | TODO | Depends on all models | Guild - Tools | Implement `GoldenPairLoader` service to read/validate metadata from filesystem. |
| 8 | GP-MODEL-TESTS-0001 | TODO | Depends on all above | Guild - Tools | Unit tests for model serialization, schema validation, loader functionality. |
| 1 | GP-MODEL-METADATA-0001 | DONE | None | Guild - Tools | Define `GoldenPairMetadata` record with CVE, artifact, original/patched refs, patch info, advisories, expected diff. |
| 2 | GP-MODEL-ARTIFACT-0001 | DONE | None | Guild - Tools | Define `BinaryArtifact` record with package, version, distro, source, hashes, buildId, symbols availability. |
| 3 | GP-MODEL-DIFF-0001 | DONE | None | Guild - Tools | Define `GoldenDiffReport` record with section comparison, verdict, confidence, tool version. |
| 4 | GP-SCHEMA-JSON-0001 | DONE | Depends on MODEL-* | Guild - Tools | Create JSON Schema `golden-pair-v1.schema.json` for metadata validation. Publish to `docs/schemas/`. |
| 5 | GP-SCHEMA-INDEX-0001 | DONE | Depends on SCHEMA-JSON | Guild - Tools | Create corpus index schema `golden-pairs-index.schema.json` for dataset manifest. |
| 6 | GP-STORAGE-LAYOUT-0001 | DONE | Depends on MODEL-* | Guild - Tools | Document storage layout in `datasets/golden-pairs/README.md`. Include artifact naming conventions. |
| 7 | GP-MODEL-LOADER-0001 | DONE | Depends on all models | Guild - Tools | Implement `GoldenPairLoader` service to read/validate metadata from filesystem. |
| 8 | GP-MODEL-TESTS-0001 | DONE | Depends on all above | Guild - Tools | Unit tests for model serialization, schema validation, loader functionality. |
## Technical Specification
@@ -332,6 +332,7 @@ datasets/golden-pairs/
| Date (UTC) | Update | Owner |
|------------|--------|-------|
| 2026-01-13 | Sprint created from advisory analysis. | Project Mgmt |
| 2026-01-13 | Implemented models, schemas, loader, and tests; documented corpus layout. | Tools |
## Decisions & Risks

View File

@@ -26,16 +26,16 @@
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
|---|---------|--------|---------------------------|--------|-----------------|
| 1 | GP-MIRROR-INTERFACE-0001 | TODO | None | Guild - Tools | Define `IPackageMirrorService` interface with `FetchAsync(artifact, destination, ct)` signature. Support verification and resume. |
| 2 | GP-MIRROR-APT-0001 | TODO | Depends on INTERFACE | Guild - Tools | Implement `AptPackageMirrorService` for Debian/Ubuntu. Parse Packages.gz, download .deb, extract target binary. |
| 3 | GP-MIRROR-VERIFY-0001 | TODO | Depends on APT | Guild - Tools | Implement hash verification: compare downloaded SHA-256 with metadata. Fail if mismatch. |
| 4 | GP-DIFF-INTERFACE-0001 | TODO | Sprint 001 models | Guild - Tools | Define `IDiffPipelineService` interface with `DiffAsync(pair, ct)` returning `GoldenDiffReport`. |
| 5 | GP-DIFF-IMPL-0001 | TODO | Depends on INTERFACE, Batch 001 | Guild - Tools | Implement `DiffPipelineService` that: loads metadata, extracts section hashes, compares, produces report. |
| 6 | GP-DIFF-VALIDATE-0001 | TODO | Depends on IMPL | Guild - Tools | Implement validation against `expectedDiff`: check sections changed/identical, verdict, confidence threshold. |
| 7 | GP-CLI-MIRROR-0001 | TODO | Depends on MIRROR-* | Guild - Tools | Add `golden-pairs mirror <cve>` CLI command to fetch artifacts for a pair. |
| 8 | GP-CLI-DIFF-0001 | TODO | Depends on DIFF-* | Guild - Tools | Add `golden-pairs diff <cve>` CLI command to run diff and validation. |
| 9 | GP-CLI-VALIDATE-0001 | TODO | Depends on all above | Guild - Tools | Add `golden-pairs validate` CLI command to run all pairs and produce summary. |
| 10 | GP-TESTS-0001 | TODO | Depends on all above | Guild - Tools | Unit and integration tests for mirror, diff, validation services. |
| 1 | GP-MIRROR-INTERFACE-0001 | DONE | None | Guild - Tools | Define `IPackageMirrorService` interface with `FetchAsync(artifact, destination, ct)` signature. Support verification and resume. |
| 2 | GP-MIRROR-APT-0001 | DONE | Depends on INTERFACE | Guild - Tools | Implement `AptPackageMirrorService` for Debian/Ubuntu. Parse Packages.gz, download .deb, extract target binary. |
| 3 | GP-MIRROR-VERIFY-0001 | DONE | Depends on APT | Guild - Tools | Implement hash verification: compare downloaded SHA-256 with metadata. Fail if mismatch. |
| 4 | GP-DIFF-INTERFACE-0001 | DONE | Sprint 001 models | Guild - Tools | Define `IDiffPipelineService` interface with `DiffAsync(pair, ct)` returning `GoldenDiffReport`. |
| 5 | GP-DIFF-IMPL-0001 | DONE | Depends on INTERFACE, Batch 001 | Guild - Tools | Implement `DiffPipelineService` that: loads metadata, extracts section hashes, compares, produces report. |
| 6 | GP-DIFF-VALIDATE-0001 | DONE | Depends on IMPL | Guild - Tools | Implement validation against `expectedDiff`: check sections changed/identical, verdict, confidence threshold. |
| 7 | GP-CLI-MIRROR-0001 | DONE | Depends on MIRROR-* | Guild - Tools | Add `golden-pairs mirror <cve>` CLI command to fetch artifacts for a pair. |
| 8 | GP-CLI-DIFF-0001 | DONE | Depends on DIFF-* | Guild - Tools | Add `golden-pairs diff <cve>` CLI command to run diff and validation. |
| 9 | GP-CLI-VALIDATE-0001 | DONE | Depends on all above | Guild - Tools | Add `golden-pairs validate` CLI command to run all pairs and produce summary. |
| 10 | GP-TESTS-0001 | DONE | Depends on all above | Guild - Tools | Unit and integration tests for mirror, diff, validation services. |
## Technical Specification
@@ -314,6 +314,7 @@ jobs:
| Date (UTC) | Update | Owner |
|------------|--------|-------|
| 2026-01-13 | Sprint created from advisory analysis. | Project Mgmt |
| 2026-01-13 | Implemented mirror, diff pipeline, CLI commands, and tests. | Tools |
## Decisions & Risks
@@ -321,6 +322,7 @@ jobs:
- **APPROVED**: Cache downloaded packages locally to avoid re-fetch.
- **RISK**: Apt repository structure may vary; handle exceptions gracefully.
- **RISK**: Some packages may be removed from mirrors; document fallbacks.
- **NOTE**: Apt mirror expects direct package URLs; Packages.gz lookup deferred.
## Next Checkpoints

View File

@@ -27,18 +27,18 @@
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
|---|---------|--------|---------------------------|--------|-----------------|
| 1 | GP-CORPUS-DIRTYPIPE-META-0001 | TODO | None | Guild - Tools | Create `CVE-2022-0847/metadata.json` with full golden pair metadata. Identify Ubuntu 22.04 kernel package versions. |
| 2 | GP-CORPUS-DIRTYPIPE-FETCH-0001 | TODO | Depends on META, Sprint 002 | Guild - Tools | Fetch vmlinux binaries for pre-patch (5.16.11) and post-patch (5.16.12) versions using mirror service. |
| 3 | GP-CORPUS-DIRTYPIPE-DIFF-0001 | TODO | Depends on FETCH | Guild - Tools | Run diff pipeline, validate .text section change, verify verdict matches expected. |
| 4 | GP-CORPUS-DIRTYPIPE-DOCS-0001 | TODO | Depends on all above | Guild - Tools | Document advisory links, patch commit, functions changed. Archive advisory PDFs. |
| 5 | GP-CORPUS-BARON-META-0001 | TODO | None | Guild - Tools | Create `CVE-2021-3156/metadata.json`. Identify Debian 11 sudo package versions. |
| 6 | GP-CORPUS-BARON-FETCH-0001 | TODO | Depends on META, Sprint 002 | Guild - Tools | Fetch sudo binaries for pre-patch and post-patch versions. |
| 7 | GP-CORPUS-BARON-DIFF-0001 | TODO | Depends on FETCH | Guild - Tools | Run diff pipeline, validate, verify verdict. |
| 8 | GP-CORPUS-BARON-DOCS-0001 | TODO | Depends on all above | Guild - Tools | Document advisory links, patch commit. |
| 9 | GP-CORPUS-PRINT-META-0001 | TODO (CONDITIONAL) | PE support ready | Guild - Tools | Create `CVE-2021-34527/metadata.json` if PE section hashing available. |
| 10 | GP-CORPUS-INDEX-0001 | TODO | Depends on all pairs | Guild - Tools | Create `index.json` corpus manifest listing all pairs with summary. |
| 11 | GP-CORPUS-README-0001 | TODO | Depends on INDEX | Guild - Tools | Create `README.md` with corpus documentation, usage instructions, extension guide. |
| 12 | GP-CORPUS-CI-0001 | TODO | Depends on all above | Guild - Tools | Add CI workflow to validate corpus on changes. Integrate with test reporting. |
| 1 | GP-CORPUS-DIRTYPIPE-META-0001 | BLOCKED | None | Guild - Tools | Create `CVE-2022-0847/metadata.json` with full golden pair metadata. Identify Ubuntu 22.04 kernel package versions. |
| 2 | GP-CORPUS-DIRTYPIPE-FETCH-0001 | BLOCKED | Depends on META, Sprint 002 | Guild - Tools | Fetch vmlinux binaries for pre-patch (5.16.11) and post-patch (5.16.12) versions using mirror service. |
| 3 | GP-CORPUS-DIRTYPIPE-DIFF-0001 | BLOCKED | Depends on FETCH | Guild - Tools | Run diff pipeline, validate .text section change, verify verdict matches expected. |
| 4 | GP-CORPUS-DIRTYPIPE-DOCS-0001 | BLOCKED | Depends on all above | Guild - Tools | Document advisory links, patch commit, functions changed. Archive advisory PDFs. |
| 5 | GP-CORPUS-BARON-META-0001 | BLOCKED | None | Guild - Tools | Create `CVE-2021-3156/metadata.json`. Identify Debian 11 sudo package versions. |
| 6 | GP-CORPUS-BARON-FETCH-0001 | BLOCKED | Depends on META, Sprint 002 | Guild - Tools | Fetch sudo binaries for pre-patch and post-patch versions. |
| 7 | GP-CORPUS-BARON-DIFF-0001 | BLOCKED | Depends on FETCH | Guild - Tools | Run diff pipeline, validate, verify verdict. |
| 8 | GP-CORPUS-BARON-DOCS-0001 | BLOCKED | Depends on all above | Guild - Tools | Document advisory links, patch commit. |
| 9 | GP-CORPUS-PRINT-META-0001 | BLOCKED (CONDITIONAL) | PE support ready | Guild - Tools | Create `CVE-2021-34527/metadata.json` if PE section hashing available. |
| 10 | GP-CORPUS-INDEX-0001 | BLOCKED | Depends on all pairs | Guild - Tools | Create `index.json` corpus manifest listing all pairs with summary. |
| 11 | GP-CORPUS-README-0001 | BLOCKED | Depends on INDEX | Guild - Tools | Create `README.md` with corpus documentation, usage instructions, extension guide. |
| 12 | GP-CORPUS-CI-0001 | BLOCKED | Depends on all above | Guild - Tools | Add CI workflow to validate corpus on changes. Integrate with test reporting. |
## Technical Specification
@@ -243,6 +243,7 @@ golden-pairs validate --all
| Date (UTC) | Update | Owner |
|------------|--------|-------|
| 2026-01-13 | Sprint created from advisory analysis. | Project Mgmt |
| 2026-01-13 | Marked corpus tasks blocked pending confirmed package sources, hashes, and artifacts. | Tools |
## Decisions & Risks
@@ -250,6 +251,7 @@ golden-pairs validate --all
- **APPROVED**: Use Debian snapshot archive for reproducible sudo packages.
- **RISK**: Kernel binaries are very large; consider extracting specific .ko modules.
- **RISK**: Package removal from archives; cache locally after first fetch.
- **BLOCKER**: Requires confirmed package URLs, hashes, and binaries before metadata and corpus can be generated.
## Next Checkpoints

View File

@@ -0,0 +1,64 @@
# Sprint 20260113_005_ADVISORYAI_controlled_conversational_interface - Controlled Conversational Interface (AdvisoryAI)
## Topic & Scope
- Add Chat Gateway guardrails (quotas, budgets, scrubber) to the AdvisoryAI chat pipeline.
- Enforce sanctioned tool registry (read-only default) with policy checks for tool use.
- Persist immutable audit logs for prompts, redactions, tool calls, and model identifiers.
- **Working directory:** `src/AdvisoryAI/`.
## Dependencies & Concurrency
- Depends on policy tool lattice sprint for allow/deny evaluation.
- UI and CLI sprints can proceed in parallel once chat API schema is stable.
## Documentation Prerequisites
- `docs/README.md`
- `docs/ARCHITECTURE_OVERVIEW.md`
- `docs/modules/advisory-ai/architecture.md`
- `docs/modules/advisory-ai/chat-interface.md`
- `docs/security/assistant-guardrails.md`
- `docs-archived/product/advisories/13-Jan-2026 - Controlled Conversational Interface.md`
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| 1 | AIAI-CHAT-DOCS-0001 | DONE | None | Guild - AdvisoryAI | Update `docs/modules/advisory-ai/architecture.md` and `docs/modules/advisory-ai/chat-interface.md` with Chat Gateway guardrails and audit log details. |
| 2 | AIAI-CHAT-GW-0001 | DONE | Policy lattice sprint | Guild - AdvisoryAI | Implement Chat Gateway quotas and token budgets with deterministic counters and rejection codes; use settings overrides with env defaults. |
| 3 | AIAI-CHAT-SCRUB-0001 | DONE | AIAI-CHAT-GW-0001 | Guild - AdvisoryAI | Add PII/secret scrubber (regex + entropy + allowlist) for input/output with test vectors. |
| 4 | AIAI-CHAT-TOOLS-0001 | DONE | Policy lattice sprint | Guild - AdvisoryAI | Implement sanctioned tool registry with schema-bound invocation and read-only defaults; enforce per-tenant allowlist. |
| 5 | AIAI-CHAT-AUDIT-0001 | DONE | AIAI-CHAT-TOOLS-0001 | Guild - AdvisoryAI | Persist audit log tables (prompts, tool invocations, policy decisions, evidence links) with content hashes; optional DSSE capture. |
| 6 | AIAI-CHAT-PLUGIN-0001 | BLOCKED | AIAI-CHAT-TOOLS-0001 | Guild - AdvisoryAI | Build adapters for `vex.query`, `sbom.read`, and `scanner.findings.topk`. |
| 7 | AIAI-CHAT-TEST-0001 | BLOCKED | AIAI-CHAT-AUDIT-0001 | Guild - AdvisoryAI | Add integration tests for quotas, scrubber blocks, policy denies, and audit log persistence. |
| 8 | AIAI-CHAT-SETTINGS-0001 | DONE | AIAI-CHAT-GW-0001 | Guild - AdvisoryAI | Add chat settings store and API for quota/allowlist overrides (UI/CLI), with env defaults. |
| 9 | AIAI-CHAT-DOCTOR-0001 | DONE | AIAI-CHAT-SETTINGS-0001 | Guild - AdvisoryAI | Add chat doctor endpoint to diagnose quota/tool limitations and last deny reasons. |
| 10 | AIAI-CHAT-ENDPOINTS-0002 | DONE | None | Guild - AdvisoryAI | Fix chat endpoints: register determinism GUID provider, allow role-based auth headers, and add SSE streaming for conversation turns. |
## Execution Log
| Date (UTC) | Update | Owner |
| --- | --- | --- |
| 2026-01-13 | Sprint created from controlled conversational interface advisory; docs updated. | Product Mgmt |
| 2026-01-13 | Added settings/doctor tasks for quota and allowlist overrides. | Product Mgmt |
| 2026-01-13 | Started AIAI-CHAT-GW-0001, AIAI-CHAT-TOOLS-0001, AIAI-CHAT-SETTINGS-0001, AIAI-CHAT-DOCTOR-0001. | AdvisoryAI |
| 2026-01-13 | Completed AIAI-CHAT-GW-0001, AIAI-CHAT-TOOLS-0001, AIAI-CHAT-SETTINGS-0001, AIAI-CHAT-DOCTOR-0001; tests blocked by `src/__Libraries/StellaOps.TestKit/Connectors/ConnectorHttpFixture.cs` compile error (IServiceProvider missing Dispose). | AdvisoryAI |
| 2026-01-13 | Marked remaining AdvisoryAI tasks blocked to avoid conflicting parallel changes; pending ownership handoff. | AdvisoryAI |
| 2026-01-13 | Fixed chat endpoint binding/auth/streaming (AIAI-CHAT-ENDPOINTS-0002); tests run with `dotnet test --no-build` due to external build failure in `src/Router/__Libraries/StellaOps.Microservice/ServiceCollectionExtensions.cs`. | AdvisoryAI |
| 2026-01-13 | Cleared duplicate `using` in `src/Router/__Libraries/StellaOps.Microservice/ServiceCollectionExtensions.cs`; `dotnet build` now succeeds. | AdvisoryAI |
| 2026-01-13 | Resumed AIAI-CHAT-SCRUB-0001 for entropy/allowlist scrubber updates. | AdvisoryAI |
| 2026-01-13 | Completed AIAI-CHAT-SCRUB-0001; tuned guardrail redaction pre-checks and performance scenarios; AdvisoryAI tests pass. | AdvisoryAI |
| 2026-01-13 | Started AIAI-CHAT-AUDIT-0001 for chat audit persistence. | AdvisoryAI |
| 2026-01-13 | Completed AIAI-CHAT-AUDIT-0001; added Postgres audit logger + migration, docs, and tests; ran `dotnet test src/AdvisoryAI/__Tests/StellaOps.AdvisoryAI.Tests/StellaOps.AdvisoryAI.Tests.csproj -v minimal`. | AdvisoryAI |
| 2026-01-13 | Reaffirmed UI/CLI settings overrides (env defaults) and doctor action expectations in assistant-parameters guidance. | AdvisoryAI |
## Decisions & Risks
- Decision: Use existing conversation storage and chat endpoints as the base; extend with Chat Gateway controls.
- Decision: Guardrail and audit expectations are captured in `docs/modules/advisory-ai/chat-interface.md` and `docs/security/assistant-guardrails.md`.
- Decision: Quotas and tool allowlists are configurable via UI/CLI settings with env defaults.
- Decision: Chat endpoints accept scopes or role headers (`chat:user`, `chat:admin`) for authorization.
- Risk: Tool schemas may shift across modules; require a shared contract before enabling more tools.
- Risk: Settings persistence needs Postgres-backed store; in-memory defaults are not durable.
- Risk: Audit log storage growth; define retention windows and offline export procedures.
- Risk: Full build previously failed due to duplicate using in `src/Router/__Libraries/StellaOps.Microservice/ServiceCollectionExtensions.cs`; resolved locally, re-run baseline builds as needed.
## Next Checkpoints
- API schema review for tool invocation and audit log payloads.
- Guardrail test vectors approved by Security Guild.
- Demo: read-only advisor flow with citations.

View File

@@ -0,0 +1,47 @@
# Sprint 20260113_005_CLI_advise_chat - Advise Chat CLI
## Topic & Scope
- Add `stella advise ask` for controlled conversational queries with evidence refs.
- Default to read-only output; expose flags for evidence and action suppression.
- Align output with Advisor UI evidence chips and citations.
- **Working directory:** `src/Cli/`.
## Dependencies & Concurrency
- Depends on AdvisoryAI chat API schema and policy tool lattice decisions.
- Can run in parallel with UI once API contracts are stable.
## Documentation Prerequisites
- `docs/README.md`
- `docs/modules/cli/architecture.md`
- `docs/modules/advisory-ai/chat-interface.md`
- `docs/security/assistant-guardrails.md`
- `docs-archived/product/advisories/13-Jan-2026 - Controlled Conversational Interface.md`
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| 1 | CLI-CHAT-DOCS-0001 | DONE | None | Guild - CLI | Update `docs/modules/cli/architecture.md` with `advise ask` command details. |
| 2 | CLI-CHAT-CMD-0001 | BLOCKED | AdvisoryAI chat API | Guild - CLI | Add `advise ask` command and route to chat query endpoint. |
| 3 | CLI-CHAT-FLAGS-0001 | BLOCKED | CLI-CHAT-CMD-0001 | Guild - CLI | Implement `--no-action` and `--evidence` flags with safe defaults. |
| 4 | CLI-CHAT-OUTPUT-0001 | BLOCKED | CLI-CHAT-CMD-0001 | Guild - CLI | Render citations and evidence refs in JSON and table output. |
| 5 | CLI-CHAT-TEST-0001 | BLOCKED | CLI-CHAT-CMD-0001 | Guild - CLI | Add unit tests for flags, output formats, and policy deny handling. |
| 6 | CLI-CHAT-SETTINGS-0001 | BLOCKED | AdvisoryAI settings API | Guild - CLI | Add `advise settings` for chat quotas/allowlist overrides. |
| 7 | CLI-CHAT-DOCTOR-0001 | BLOCKED | AdvisoryAI doctor API | Guild - CLI | Add `advise doctor` to show chat quota/tool limitations. |
## Execution Log
| Date (UTC) | Update | Owner |
| --- | --- | --- |
| 2026-01-13 | Sprint created from controlled conversational interface advisory; docs updated. | Product Mgmt |
| 2026-01-13 | Added settings and doctor tasks for quota/allowlist overrides. | Product Mgmt |
| 2026-01-13 | Marked CLI advise tasks blocked pending AdvisoryAI API stability and parallel module ownership. | CLI |
## Decisions & Risks
- Decision: Default to read-only responses; action suppression is explicit.
- Decision: CLI command details documented in `docs/modules/cli/architecture.md`.
- Risk: Long responses may exceed token budgets; keep output truncation deterministic.
- Risk: Settings updates require scope-gated access; align with Authority scopes.
- BLOCKED: AdvisoryAI chat/settings/doctor APIs pending stable contract and active parallel changes.
## Next Checkpoints
- CLI UX review for evidence output format.
- API contract validation for chat queries and error codes.

View File

@@ -0,0 +1,43 @@
# Sprint 20260113_005_DOCS_controlled_conversational_interface - Controlled Conversational Interface Docs
## Topic & Scope
- Capture the controlled conversational interface advisory and archive it for long-term reference.
- Update high-level docs to reflect the evidence-first advisor capability and cross-links.
- Extend guardrail and assistant parameter docs to cover quotas, scrubber, and tool gating.
- **Working directory:** `docs/`.
## Dependencies & Concurrency
- No upstream dependencies; doc updates can run in parallel with implementation sprints.
## Documentation Prerequisites
- `docs/README.md`
- `docs/ARCHITECTURE_OVERVIEW.md`
- `docs/modules/platform/architecture-overview.md`
- `docs/security/assistant-guardrails.md`
- `docs/modules/policy/guides/assistant-parameters.md`
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| 1 | DOCS-CCI-0001 | DONE | None | Guild - Docs | Create and archive the advisory: `docs-archived/product/advisories/13-Jan-2026 - Controlled Conversational Interface.md`. |
| 2 | DOCS-CCI-0002 | DONE | DOCS-CCI-0001 | Guild - Docs | Update `docs/key-features.md`, `docs/ARCHITECTURE_OVERVIEW.md`, and add `docs/07_HIGH_LEVEL_ARCHITECTURE.md` references. |
| 3 | DOCS-CCI-0003 | DONE | DOCS-CCI-0001 | Guild - Docs | Update `docs/security/assistant-guardrails.md` for scrubber, budgets, and audit trail notes. |
| 4 | DOCS-CCI-0004 | DONE | DOCS-CCI-0001 | Guild - Docs | Update `docs/modules/policy/guides/assistant-parameters.md` with chat quotas and tool gating. |
| 5 | DOCS-CCI-0005 | DONE | DOCS-CCI-0001 | Guild - Docs | Update module AGENTS to reflect advisor guardrails (`docs/modules/advisory-ai/AGENTS.md`, `docs/modules/ui/AGENTS.md`, `docs/modules/cli/AGENTS.md`, `docs/modules/policy/AGENTS.md`). |
## Execution Log
| Date (UTC) | Update | Owner |
| --- | --- | --- |
| 2026-01-13 | Sprint created from controlled conversational interface advisory; doc updates completed and advisory archived. | Product Mgmt |
| 2026-01-13 | Updated AdvisoryAI, UI, CLI, and Policy AGENTS to reflect advisor guardrails. | Docs |
## Decisions & Risks
- Decision: Use `docs/ARCHITECTURE_OVERVIEW.md` as the canonical high-level doc; add `docs/07_HIGH_LEVEL_ARCHITECTURE.md` as a legacy pointer.
- Decision: AGENTS updates recorded in this sprint to keep module guardrails aligned.
- Risk: Links to archived advisories must be maintained for traceability; validate docs links after merges.
- Risk: `docs/implplan/SPRINT_0301_0001_0001_docs_md_i.md` is referenced in `docs/AGENTS.md` but is not present in the repo.
- Risk: `docs/implplan/archived/all-tasks.md` referenced by advisory workflow is missing; historical task cross-check was limited.
## Next Checkpoints
- Docs Guild review of updated advisory, guardrail, and parameter docs.
- Link validation sweep for docs references.

View File

@@ -0,0 +1,69 @@
# Sprint 20260113-005-DOCTOR · Orchestrator Doctor Self Service
## Topic & Scope
- Define Doctor packs for Release Orchestrator integrations with deterministic checks and verbatim fix commands.
- Add JSONL evidence logs and optional DSSE summaries for audit-grade Doctor runs.
- Align CLI and UI with a shared `how_to_fix` command contract for self-service remediation.
- Expected evidence: updated specs in `docs/doctor/doctor-capabilities.md`, updated module doc in `docs/modules/release-orchestrator/modules/integration-hub.md`, and sample manifest in `docs/benchmarks/doctor/doctor-plugin-release-orchestrator-gitlab.yaml`.
- **Working directory:** `src/Doctor`.
- **Allowed cross-module paths:** `src/__Libraries/StellaOps.Doctor/**`, `src/Cli/**`, `src/Web/**`, `src/ReleaseOrchestrator/**`, `plugins/doctor/**`, `samples/**`.
## Dependencies & Concurrency
- Depends on Doctor engine/library and CLI command group integration.
- No known conflicts with other 20260113 sprints; safe to run in parallel with CC peers.
## Documentation Prerequisites
- `docs/README.md`
- `docs/technical/architecture/07_HIGH_LEVEL_ARCHITECTURE.md`
- `docs/modules/release-orchestrator/architecture.md`
- `docs/modules/release-orchestrator/modules/integration-hub.md`
- `docs/doctor/doctor-capabilities.md`
- `docs/modules/platform/architecture-overview.md`
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| 1 | DOCS-DR-0001 | DONE | Advisory sync | Product · Docs | Sync Doctor advisory into docs and add sample manifest (`docs-archived/product/advisories/13-Jan-2026 - Release Orchestrator Doctor Self Service.md`, `docs/doctor/doctor-capabilities.md`, `docs/modules/release-orchestrator/modules/integration-hub.md`, `docs/key-features.md`, `docs/benchmarks/doctor/doctor-plugin-release-orchestrator-gitlab.yaml`). |
| 2 | DOCTOR-DR-0002 | DONE | Pack schema + loader | Backend · Doctor | Implement YAML pack loader for `plugins/doctor/*.yaml` with discovery gating, exec runner, and parse expectations. |
| 2.1 | AGENTS-DOCTOR-0001 | DONE | Module charter | Project · Doctor | Create `src/Doctor/AGENTS.md` with module constraints, test strategy, and allowed shared libs. |
| 3 | PACKS-DR-0003 | DONE | DOCTOR-DR-0002 | Backend · Doctor | Add first-party Doctor packs for GitLab, GitHub, Gitea, Harbor/OCI, Vault, LDAP under `plugins/doctor/`. |
| 4 | CLI-DR-0004 | DONE | DOCTOR-DR-0002 | CLI · Platform | Add `stella doctor run` alias and `stella doctor fix` pipeline with dry-run by default and `--apply` gating. |
| 5 | ORCH-DR-0005 | BLOCKED | DOCTOR-DR-0002 | Backend · Release Orchestrator | Implement orchestrator checks for webhooks, branch policy, registry push/pull, SBOM ingestion, vault, LDAP, migrations, and policy pack verification. |
| 6 | DOCTOR-DR-0006 | DONE | DOCTOR-DR-0002 | Backend · Doctor | Emit JSONL evidence logs and optional DSSE summaries with deterministic ordering and offline-safe defaults. |
| 7 | UI-DR-0007 | DONE | DOCTOR-DR-0002 | Frontend · Web | Build Doctor UI page with packs -> plugins -> checks, copy fix commands, run fix gating, and JSON/DSSE export. |
| 8 | SAMPLES-DR-0008 | DONE | None | Docs · QA | Add sample SBOMs (CycloneDX 1.6 and SPDX 3.0.1) under `samples/` for ingestion tests. |
## Execution Log
| Date (UTC) | Update | Owner |
| --- | --- | --- |
| 2026-01-13 | Sprint created; advisory synced into docs and sample manifest added. | Product |
| 2026-01-13 | Recorded fix exposure, non-destructive execution, and DSSE command note decisions in docs. | Product |
| 2026-01-13 | Added `src/Doctor/AGENTS.md`, updated scope to allow cross-module edits, and started DOCTOR-DR-0002. | Implementer |
| 2026-01-13 | Implemented YAML pack loader, exec runner, parse expectations, and unit tests. | Implementer |
| 2026-01-13 | Added first-party Doctor packs for GitLab, GitHub, Gitea, Harbor, Vault, and LDAP. | Implementer |
| 2026-01-13 | Added sample CycloneDX 1.6 and SPDX 3.0.1 SBOMs under `samples/`. | Implementer |
| 2026-01-13 | Started DOCTOR-DR-0006 evidence log and DSSE summary output. | Implementer |
| 2026-01-13 | Completed DOCTOR-DR-0006 evidence log and DSSE summary output. | Implementer |
| 2026-01-13 | Marked CLI/UI/orchestrator tasks blocked pending parallel module ownership. | Implementer |
| 2026-01-13 | Started CLI-DR-0004 (doctor run alias and doctor fix pipeline). | Implementer |
| 2026-01-13 | Completed CLI-DR-0004; added doctor fix command and run alias. | Implementer |
| 2026-01-13 | Tests: `dotnet test src/Cli/__Tests/StellaOps.Cli.Tests` failed due to existing compile errors in `src/Cli/StellaOps.Cli/Commands/Scan/BinaryDiffRenderer.cs`, `src/Cli/StellaOps.Cli/Commands/CommandHandlers.Image.cs`, and `src/Cli/StellaOps.Cli/Commands/CommandHandlers.VerdictVerify.cs`. | Implementer |
| 2026-01-13 | Fixed CLI compile errors in `src/Cli/StellaOps.Cli/Commands/Scan/BinaryDiffRenderer.cs`, `src/Cli/StellaOps.Cli/Commands/CommandHandlers.Image.cs`, `src/Cli/StellaOps.Cli/Commands/Scan/BinaryDiffKeyLoader.cs`, and `src/Cli/StellaOps.Cli/Commands/Scan/BinaryDiffService.cs`. | Implementer |
| 2026-01-13 | Tests: `dotnet test src/Cli/__Tests/StellaOps.Cli.Tests -v minimal` failed with MSB9008 warning (missing `StellaOps.Scanner.Storage.Oci.csproj`) and CS2012 file lock on `src/Cli/__Tests/StellaOps.Cli.Tests/obj/Debug/net10.0/StellaOps.Cli.Tests.dll`. | Implementer |
| 2026-01-13 | Tests: rerun with custom `BaseIntermediateOutputPath` failed with duplicate assembly attribute errors in `src/__Libraries/StellaOps.Infrastructure.EfCore` (CS0579). | Implementer |
| 2026-01-13 | Fixed DSSE PAE usage in offline import test and routed JSON output to Console.Out for stable JSON; tests: `dotnet test src/Cli/__Tests/StellaOps.Cli.Tests -v minimal` (pass). | Implementer |
| 2026-01-13 | Started UI-DR-0007 (Doctor pack list, fix gating, DSSE export). | Implementer |
| 2026-01-13 | Completed UI-DR-0007; tests: `npx ng test --watch=false --include "src/app/features/doctor/**/*.spec.ts"` failed due to pre-existing TS errors in advisory-ai, vex-hub, policy, and shared component specs. | Implementer |
## Decisions & Risks
- Decision: UI and CLI must expose fix actions; CLI uses `stella doctor fix` and UI mirrors commands. See `docs/doctor/doctor-capabilities.md` and `docs/doctor/cli-reference.md`.
- Decision: Remediation UX should favor concise copy/paste commands; `how_to_fix` is the agent-facing alias of `remediation`. See `docs/doctor/doctor-capabilities.md` and `docs/modules/release-orchestrator/modules/integration-hub.md`.
- Decision: Doctor fix executes only non-destructive commands; destructive steps are manual and never executed by Doctor. See `docs/doctor/doctor-capabilities.md`.
- Decision: DSSE summaries include `doctor_command` and assume operator execution. See `docs/doctor/doctor-capabilities.md` and `docs/modules/release-orchestrator/modules/integration-hub.md`.
- Risk: Pack execution safety. YAML packs execute CLI commands and must be sandboxed/allowlisted to avoid unsafe actions.
- Risk: DSSE signing flow. Define signer/key ownership and offline key distribution for Doctor summary artifacts.
- BLOCKED: UI/Release Orchestrator tasks paused to avoid conflicts with parallel work in those modules.
## Next Checkpoints
- 2026-01-20: Design review for pack schema, CLI contract, and UI wiring.
- 2026-01-27: Prototype demo with JSONL evidence log and fix command rendering.

View File

@@ -0,0 +1,46 @@
# Sprint 20260113_005_POLICY_assistant_tool_lattice - Assistant Tool Lattice
## Topic & Scope
- Define policy lattice rules for assistant tool access (read-only vs action).
- Provide a policy evaluation surface for Chat Gateway allow/deny checks.
- Align tool access with Authority scopes and tenant constraints.
- **Working directory:** `src/Policy/`.
## Dependencies & Concurrency
- AdvisoryAI sprint depends on this policy evaluation for tool gating.
- Can run in parallel with UI/CLI work once rule schema is agreed.
## Documentation Prerequisites
- `docs/README.md`
- `docs/ARCHITECTURE_OVERVIEW.md`
- `docs/modules/policy/architecture.md`
- `docs/modules/policy/guides/assistant-parameters.md`
- `docs-archived/product/advisories/13-Jan-2026 - Controlled Conversational Interface.md`
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| 1 | POL-CHAT-DOCS-0001 | DONE | None | Guild - Policy | Update `docs/modules/policy/guides/assistant-parameters.md` with chat quotas, scrubber, and tool gating settings. |
| 2 | POL-CHAT-SCHEMA-0001 | DONE | None | Guild - Policy | Define tool access schema or DSL rules (tool name, scope, tenant, role, resource). |
| 3 | POL-CHAT-EVAL-0001 | DONE | POL-CHAT-SCHEMA-0001 | Guild - Policy | Implement policy evaluation endpoint for Chat Gateway allow/deny checks. |
| 4 | POL-CHAT-SCOPE-0001 | DONE | POL-CHAT-SCHEMA-0001 | Guild - Policy | Map Authority scopes to tool lattice rules and document default deny behavior. |
| 5 | POL-CHAT-TEST-0001 | DONE | POL-CHAT-EVAL-0001 | Guild - Policy | Add determinism and authorization tests for tool lattice evaluation. |
## Execution Log
| Date (UTC) | Update | Owner |
| --- | --- | --- |
| 2026-01-13 | Sprint created from controlled conversational interface advisory; docs updated. | Product Mgmt |
| 2026-01-13 | Noted UI/CLI-configurable allowlist defaults for tool lattice alignment. | Product Mgmt |
| 2026-01-13 | Marked remaining policy tasks blocked pending schema decisions and parallel module ownership. | Policy |
| 2026-01-13 | Implemented tool lattice schema, evaluator, gateway endpoint, and tests; documented default scope mapping. | Policy |
## Decisions & Risks
- Decision: Default deny for tool actions; allow read-only tools via explicit rules.
- Decision: Tool lattice parameters are documented in `docs/modules/policy/guides/assistant-parameters.md`.
- Decision: Tool lattice must align with settings-based allowlists (env defaults, UI/CLI overrides).
- Risk: Policy evaluation latency may impact chat UX; ensure caching and deterministic ordering.
- Decision: Default scope mapping documented in `docs/modules/policy/guides/assistant-tool-lattice.md`.
## Next Checkpoints
- DSL/schema review with Policy Guild.
- Contract review with AdvisoryAI for tool allow/deny payloads.

View File

@@ -0,0 +1,48 @@
# Sprint 20260113_005_UI_advisor_chat_panel - Advisor Chat Panel
## Topic & Scope
- Deliver the Advisor chat panel with evidence citations and action confirmation.
- Provide UI parity for controlled conversational interface (read-only by default).
- Surface quota/budget feedback for chat requests.
- **Working directory:** `src/Web/StellaOps.Web/`.
## Dependencies & Concurrency
- Depends on AdvisoryAI chat endpoints and tool schema stability.
- Can run in parallel with CLI work once API contracts are set.
## Documentation Prerequisites
- `docs/README.md`
- `docs/modules/ui/architecture.md`
- `docs/modules/advisory-ai/chat-interface.md`
- `docs/security/assistant-guardrails.md`
- `docs-archived/product/advisories/13-Jan-2026 - Controlled Conversational Interface.md`
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| 1 | UI-CHAT-DOCS-0001 | DONE | None | Guild - UI | Update `docs/modules/ui/architecture.md` with Advisor chat panel and evidence drawer notes. |
| 2 | UI-CHAT-PANEL-0001 | BLOCKED | AdvisoryAI chat API | Guild - UI | Build chat panel with conversation list, streaming responses, and input controls. |
| 3 | UI-CHAT-CITATIONS-0001 | BLOCKED | UI-CHAT-PANEL-0001 | Guild - UI | Implement citations and evidence chips with object ref links. |
| 4 | UI-CHAT-ACTIONS-0001 | BLOCKED | Policy tool lattice | Guild - UI | Add action confirmation modal and policy-deny display states. |
| 5 | UI-CHAT-QUOTA-0001 | BLOCKED | UI-CHAT-PANEL-0001 | Guild - UI | Surface quota/budget exhaustion and retry hints (doctor output). |
| 6 | UI-CHAT-TEST-0001 | BLOCKED | UI-CHAT-PANEL-0001 | Guild - UI | Add unit and e2e coverage for chat panel, citations, and actions. |
| 7 | UI-CHAT-SETTINGS-0001 | BLOCKED | AdvisoryAI settings API | Guild - UI | Add settings view for chat quotas and tool allowlist (env defaults + overrides). |
| 8 | UI-CHAT-DOCTOR-0001 | BLOCKED | UI-CHAT-PANEL-0001 | Guild - UI | Add doctor action to show chat limit status and last denial reasons. |
## Execution Log
| Date (UTC) | Update | Owner |
| --- | --- | --- |
| 2026-01-13 | Sprint created from controlled conversational interface advisory; docs updated. | Product Mgmt |
| 2026-01-13 | Added settings and doctor tasks for quota/allowlist overrides. | Product Mgmt |
| 2026-01-13 | Marked UI chat tasks blocked pending API/tool lattice stability and parallel module ownership. | UI |
## Decisions & Risks
- Decision: Advisor UI defaults to read-only; actions are opt-in and confirmed.
- Decision: Advisor UI surface documented in `docs/modules/ui/architecture.md`.
- Decision: Settings UI must show env defaults and saved overrides for quotas/allowlist.
- Risk: Streaming UI performance; ensure backpressure and log scrubbing on client.
- BLOCKED: AdvisoryAI API and policy lattice contracts pending; avoid parallel changes without coordination.
## Next Checkpoints
- UI design review with citations panel mock.
- API contract validation for streaming chat events.

View File

@@ -130,11 +130,20 @@ Components:
**Modules (planned):** `PluginRegistry`, `PluginLoader`, `PluginSandbox`, `PluginSDK`
### 6. Doctor Self Service Diagnostics (Planned)
**Operators can self-diagnose integrations and services.** Doctor auto-discovers installed packs,
runs deterministic checks, and prints exact CLI fixes for every failure. Output includes JSONL
evidence logs and optional DSSE summaries for audits.
**Modules (planned):** `Doctor`, `IntegrationHub`, `CLI`, `Web`
**Spec:** `docs/doctor/doctor-capabilities.md`
---
## Security Capabilities (Operational)
### 6. Decision Capsules — Audit-Grade Evidence Bundles
### 7. Decision Capsules — Audit-Grade Evidence Bundles
**Every scan and release decision is sealed.** A Decision Capsule is a content-addressed bundle containing everything needed to reproduce and verify the decision.
@@ -149,7 +158,7 @@ Components:
**Modules:** `EvidenceLocker`, `Attestor`, `Replay`
### 7. Lattice Policy + OpenVEX (K4 Logic)
### 8. Lattice Policy + OpenVEX (K4 Logic)
**VEX as a logical claim system, not a suppression file.** The policy engine uses Belnap K4 four-valued logic.
@@ -164,7 +173,7 @@ Components:
**Modules:** `VexLens`, `TrustLatticeEngine`, `Policy`
### 8. Signed Reachability Proofs
### 9. Signed Reachability Proofs
**Proof of exploitability, not just a badge.** Every reachability graph is sealed with DSSE.
@@ -178,7 +187,7 @@ Components:
**Modules:** `ReachGraph`, `PathWitnessBuilder`
### 9. Deterministic Replay
### 10. Deterministic Replay
**The audit-grade guarantee.** Every scan produces a DSSE + SRM bundle that can be replayed.
@@ -192,7 +201,7 @@ stella replay srm.yaml --assert-digest sha256:abc123...
**Modules:** `Replay`, `Scanner`, `Policy`
### 10. Sovereign Crypto Profiles
### 11. Sovereign Crypto Profiles
**Regional compliance without code changes.** FIPS, eIDAS, GOST, SM, and PQC profiles are configuration toggles.
@@ -206,7 +215,7 @@ stella replay srm.yaml --assert-digest sha256:abc123...
**Modules:** `Cryptography`, `CryptoProfile`
### 11. Offline Operations (Air-Gap Parity)
### 12. Offline Operations (Air-Gap Parity)
**Full functionality without network.** Offline Update Kits bundle everything needed.
@@ -218,11 +227,22 @@ stella replay srm.yaml --assert-digest sha256:abc123...
**Modules:** `AirGap.Controller`, `TrustStore`
### 13. Controlled Conversational Advisor
**Ask Stella with guardrails.** Operators can query evidence and receive cited answers while tool actions remain policy-gated and audited.
Key controls:
- Chat Gateway quotas and token budgets per user/org.
- Scrubber for secrets/PII and allowlisted tool calls only.
- Immutable audit log for prompts, redactions, tool calls, and model fingerprints.
**Modules:** `AdvisoryAI`, `Policy`, `Authority`, `CLI`, `Web`, `Gateway`
---
## Competitive Moats Summary
**Six capabilities no competitor offers together:**
**Seven capabilities no competitor offers together:**
| # | Capability | Category |
|---|-----------|----------|
@@ -232,6 +252,7 @@ stella replay srm.yaml --assert-digest sha256:abc123...
| 4 | **Signed Reachability Proofs** | Security |
| 5 | **Deterministic Replay** | Security |
| 6 | **Sovereign + Offline Operation** | Operations |
| 7 | **Controlled Conversational Advisor** | Security |
**Pricing moat:** No per-seat, per-project, or per-deployment tax. Limits are environments + new digests/day.
@@ -247,3 +268,4 @@ stella replay srm.yaml --assert-digest sha256:abc123...
- **Competitive Landscape**: [`docs/product/competitive-landscape.md`](product/competitive-landscape.md)
- **Quickstart**: [`docs/quickstart.md`](quickstart.md)
- **Feature Matrix**: [`docs/FEATURE_MATRIX.md`](FEATURE_MATRIX.md)
- **Controlled Conversational Interface Advisory**: [`docs-archived/product/advisories/13-Jan-2026 - Controlled Conversational Interface.md`](../docs-archived/product/advisories/13-Jan-2026%20-%20Controlled%20Conversational%20Interface.md)

View File

@@ -20,6 +20,7 @@ Advisory AI is the retrieval-augmented assistant that synthesizes advisory and V
- Preserve determinism and provenance in all derived outputs.
- Document offline/air-gap pathways for any new feature.
- Update telemetry/observability assets alongside feature work.
- Chat gateway must enforce quotas, scrubber rules, tool allowlists, and audit logging.
## Required Reading
- `docs/modules/advisory-ai/README.md`

View File

@@ -153,3 +153,13 @@ All endpoints accept `profile` parameter (default `fips-local`) and return `outp
- **Remote inference toggle.** Set `AdvisoryAI:Inference:Mode` (env: `ADVISORYAI__AdvisoryAI__Inference__Mode`) to `Remote` when you want prompts to be executed by an external inference tier. Provide `AdvisoryAI:Inference:Remote:BaseAddress` and, optionally, `...:ApiKey`. When remote calls fail the executor falls back to the sanitized prompt and sets `inference.fallback_*` metadata so CLI/Console surface a warning.
- **Scalability.** Start with 1 web replica + 1 worker for up to ~10 requests/minute. For higher throughput, scale `advisory-ai-worker` horizontally; each worker is CPU-bound (2 vCPU / 4GiB RAM recommended) while the web front end is I/O-bound (1 vCPU / 1GiB). Because the queue/plan/output stores are content-addressed files, ensure the shared volume delivers ≥500IOPS and <5ms latency; otherwise queue depth will lag.
- **Offline & air-gapped stance.** The Compose/Helm manifests avoid external network calls by default and the Offline Kit now publishes the `advisory-ai-web` and `advisory-ai-worker` images alongside their SBOMs/provenance. Operators can rehydrate the RWX volume from the kit to pre-prime cache directories before enabling the service.
## 14) Controlled conversational interface and tool gating
- **Chat Gateway controls.** Chat endpoints enforce Authority auth, per-tenant/user quotas, token budgets, and PII/secret scrubbing before any model invocation.
- **Sanctioned tools only.** Tool calls are schema-bound and allowlisted (read-only by default). Action tools require explicit user confirmation plus policy allow.
- **Policy lattice.** Tool permissions are evaluated against policy rules (scope, tenant, role, resource) before invocation.
- **Audit log.** Persist prompt hash, redaction metadata, tool calls, policy decisions, and model identifiers to Postgres; optional DSSE signatures capture evidence integrity.
- **Offline parity.** Local model profiles are the default; remote inference is opt-in and blocked in sealed mode.
See `docs/modules/advisory-ai/chat-interface.md` and `docs-archived/product/advisories/13-Jan-2026 - Controlled Conversational Interface.md`.

View File

@@ -2,7 +2,7 @@
> **Sprint:** SPRINT_20260107_006_003 Task CH-016
> **Status:** Active
> **Last Updated:** 2026-01-09
> **Last Updated:** 2026-01-13
The AdvisoryAI Chat Interface provides a conversational experience for security operators to investigate vulnerabilities, understand findings, and take remediation actions—all grounded in internal evidence with citations.
@@ -14,6 +14,17 @@ The chat interface enables:
- **Action proposals** for risk approval, quarantine, and VEX creation
- **Streaming responses** for real-time feedback
## Controlled Gateway and Budgets
- **Chat Gateway** enforces Authority auth, quotas, and token budgets per user/org.
- **Settings overrides**: quotas and tool allowlists are configurable via UI/CLI settings; env values are defaults.
- **Doctor action** reports quota/tool limits and last denial for troubleshooting.
- **Scrubber** removes secrets and PII using regex + entropy filters + allowlists.
- **Tool gating** runs policy checks before any tool invocation; read-only by default.
## Sanctioned Tools (v1)
- Read-only: `vex.query`, `sbom.read`, `scanner.findings.topk`.
- Action tools require explicit confirmation plus policy allow.
---
## API Reference
@@ -22,18 +33,23 @@ The chat interface enables:
Creates a new conversation session.
Required headers: `X-StellaOps-User`, `X-StellaOps-Client`, and either `X-StellaOps-Roles` (`chat:user` or `chat:admin`) or `X-StellaOps-Scopes` (`advisory:chat` or `advisory:run`).
```http
POST /api/v1/advisory-ai/conversations
POST /v1/advisory-ai/conversations
Content-Type: application/json
Authorization: Bearer <token>
X-StellaOps-User: user-xyz
X-StellaOps-Roles: chat:user
X-StellaOps-Client: ui
{
"tenantId": "tenant-123",
"context": {
"findingId": "f-456",
"currentCveId": "CVE-2023-44487",
"currentComponent": "pkg:npm/lodash@4.17.21",
"currentImageDigest": "sha256:abc123",
"scanId": "s-789",
"cveId": "CVE-2023-44487",
"component": "pkg:npm/lodash@4.17.21"
"sbomId": "sbom-123"
},
"metadata": {
"source": "ui",
@@ -50,11 +66,7 @@ Authorization: Bearer <token>
"userId": "user-xyz",
"createdAt": "2026-01-09T12:00:00Z",
"updatedAt": "2026-01-09T12:00:00Z",
"context": {
"currentCveId": "CVE-2023-44487",
"currentComponent": "pkg:npm/lodash@4.17.21"
},
"turnCount": 0
"turns": []
}
```
@@ -63,13 +75,16 @@ Authorization: Bearer <token>
Sends a user message and streams the AI response.
```http
POST /api/v1/advisory-ai/conversations/{conversationId}/turns
POST /v1/advisory-ai/conversations/{conversationId}/turns
Content-Type: application/json
Accept: text/event-stream
Authorization: Bearer <token>
X-StellaOps-User: user-xyz
X-StellaOps-Roles: chat:user
X-StellaOps-Client: ui
{
"message": "Is CVE-2023-44487 exploitable in our environment?"
"content": "Is CVE-2023-44487 exploitable in our environment?",
"stream": true
}
```
@@ -155,6 +170,24 @@ DELETE /api/v1/advisory-ai/conversations/{conversationId}
Authorization: Bearer <token>
```
### Chat Settings
Read or update chat quota/tool settings (defaults come from env).
```http
GET /api/v1/chat/settings
PUT /api/v1/chat/settings?scope=tenant
DELETE /api/v1/chat/settings?scope=tenant
```
### Chat Doctor
Returns quota and tool access status to diagnose limits.
```http
GET /api/v1/chat/doctor
```
---
## Object Link Format
@@ -225,10 +258,11 @@ You may want to accept this risk: [Accept Risk]{action:approve,cve_id=CVE-2023-4
1. **Parsing**: ActionProposalParser extracts actions from model output
2. **Permission Check**: User roles are validated against required role
3. **Display**: Allowed actions render as buttons; blocked actions show disabled with reason
4. **Confirmation**: User clicks button and confirms in modal
5. **Execution**: Backend executes action with audit trail
6. **Result**: Success/failure displayed in chat
3. **Policy Check**: Tool lattice rules allow/deny the action in this context
4. **Display**: Allowed actions render as buttons; blocked actions show disabled with reason
5. **Confirmation**: User clicks button and confirms in modal
6. **Execution**: Backend executes action with audit trail
7. **Result**: Success/failure displayed in chat
### Blocked Actions
@@ -244,6 +278,20 @@ When a user lacks permission for an action:
---
## Audit Log
Every chat session records an immutable audit trail:
- Prompt hash, redaction metadata, and model identifier
- Tool calls (inputs/outputs hashes) and policy decisions
- Evidence links surfaced in responses
- Action confirmations and results
Audit records live in Postgres with optional DSSE signatures for evidence export.
Apply `src/AdvisoryAI/StellaOps.AdvisoryAI/Storage/Migrations/001_chat_audit.sql`
to create the tables (adjust schema if needed).
---
## Grounding System
All AI responses are validated for proper grounding—ensuring claims are backed by evidence.
@@ -333,17 +381,40 @@ Assistant: I will create a VEX statement with the following details:
```yaml
AdvisoryAI:
Guardrails:
EntropyThreshold: 3.5
EntropyMinLength: 20
AllowlistFile: "data/advisory-ai/allowlist.txt"
Chat:
ConversationRetention: '7.00:00:00' # 7 days
MaxTurnsPerConversation: 50
TokenBudget: 8192
StreamingEnabled: true
Quotas:
RequestsPerMinute: 60
RequestsPerDay: 500
TokensPerDay: 100000
ToolCallsPerDay: 10000
Tools:
AllowAll: false
AllowedTools:
- "vex.query"
- "sbom.read"
- "scanner.findings.topk"
Audit:
Enabled: true
ConnectionString: "Host=localhost;Database=stellaops;Username=stellaops;Password=changeme"
SchemaName: "advisoryai"
IncludeEvidenceBundle: false
RetentionPeriod: '90.00:00:00'
Grounding:
MinGroundingScore: 0.5
MaxLinkDistance: 200
Actions:
RequireConfirmation: true
AuditAllExecutions: true```n
RequirePolicyAllow: true
AuditAllExecutions: true
```
---
## Error Handling
@@ -364,4 +435,5 @@ AdvisoryAI:
- [AdvisoryAI Architecture](architecture.md)
- [Deployment Guide](deployment.md)
- [Security Guardrails](/docs/security/assistant-guardrails.md)
- [Controlled Conversational Interface Advisory](../../../docs-archived/product/advisories/13-Jan-2026%20-%20Controlled%20Conversational%20Interface.md)

View File

@@ -20,6 +20,7 @@ The `stella` CLI is the operator-facing Swiss army knife for scans, exports, pol
- Preserve determinism: sort outputs, normalise timestamps (UTC ISO-8601), and avoid machine-specific artefacts.
- Keep Offline Kit parity in mind—document air-gapped workflows for any new feature.
- Update runbooks/observability assets when operational characteristics change.
- Advisory commands must default to read-only and display evidence refs with citations.
## Required Reading
- `docs/modules/cli/README.md`
- `docs/modules/cli/architecture.md`

View File

@@ -174,7 +174,12 @@ Both subcommands honour offline-first expectations (no network access) and norma
* Uses `STELLAOPS_ADVISORYAI_URL` when configured; otherwise it reuses the backend base address and adds `X-StellaOps-Scopes` (`advisory:run` + task scope) per request.
* `--timeout 0` performs a single cache lookup (for CI flows that only want cached artefacts).
### 2.12 Decision evidence (new)
* `advise ask "<question>" [--evidence] [--no-action] [--conversation-id <id>] [--context <cve|scan|image>]`
* Calls advisory chat endpoints, returns a cited answer with evidence refs.
* `--no-action` disables action proposals; `--evidence` forces evidence chips in output.
### 2.12 Decision evidence (new)
- `decision export`

View File

@@ -22,6 +22,7 @@ Policy Engine compiles and evaluates Stella DSL policies deterministically, prod
- Preserve determinism: sort outputs, normalise timestamps (UTC ISO-8601), and avoid machine-specific artefacts.
- Keep Offline Kit parity in mind—document air-gapped workflows for any new feature.
- Update runbooks/observability assets when operational characteristics change.
- Assistant tool lattice rules must be deterministic and policy-auditable.
## Required Reading
- `docs/modules/policy/README.md`
- `docs/modules/policy/architecture.md`

View File

@@ -1,20 +1,36 @@
# Advisory AI Assistant Parameters
# Advisory AI Assistant Parameters
_Primary audience: platform operators & policy authors Updated: 2025-11-24_
_Primary audience: platform operators & policy authors • Updated: 2026-01-13_
This note centralises the tunable knobs that control Advisory AIs planner, retrieval stack, inference clients, and guardrails. All options live under the `AdvisoryAI` configuration section and can be set via `appsettings.*` files or environment variables using ASP.NET Cores double-underscore convention (`ADVISORYAI__Inference__Mode`, etc.).
This note centralises the tunable knobs that control Advisory AI’s planner, retrieval stack, inference clients, and guardrails. All options live under the `AdvisoryAI` configuration section and can be set via `appsettings.*` files or environment variables using ASP.NET Core’s double-underscore convention (`ADVISORYAI__Inference__Mode`, etc.). Chat quotas and tool allowlists can also be overridden per tenant/user via the chat settings endpoints; appsettings/env values are defaults.
**Policy/version pin** For Sprint 0111, use the policy bundle hash shipped on 2025-11-19 (same drop as `CLI-VULN-29-001` / `CLI-VEX-30-001`). Set `AdvisoryAI:PolicyVersion` or `ADVISORYAI__POLICYVERSION=2025.11.19` in deployments; include the hash in DSSE metadata for Offline Kits.
**Policy/version pin** — For Sprint 0111, use the policy bundle hash shipped on 2025-11-19 (same drop as `CLI-VULN-29-001` / `CLI-VEX-30-001`). Set `AdvisoryAI:PolicyVersion` or `ADVISORYAI__POLICYVERSION=2025.11.19` in deployments; include the hash in DSSE metadata for Offline Kits.
| Area | Key(s) | Environment variable | Default | Notes |
| --- | --- | --- | --- | --- |
| Inference mode | `AdvisoryAI:Inference:Mode` | `ADVISORYAI__INFERENCE__MODE` | `Local` | `Local` runs the deterministic pipeline only; `Remote` posts sanitized prompts to `Remote.BaseAddress`. |
| Remote base URI | `AdvisoryAI:Inference:Remote:BaseAddress` | `ADVISORYAI__INFERENCE__REMOTE__BASEADDRESS` | | Required when `Mode=Remote`. HTTPS strongly recommended. |
| Remote API key | `AdvisoryAI:Inference:Remote:ApiKey` | `ADVISORYAI__INFERENCE__REMOTE__APIKEY` | | Injected as `Authorization: Bearer <key>` when present. |
| Remote base URI | `AdvisoryAI:Inference:Remote:BaseAddress` | `ADVISORYAI__INFERENCE__REMOTE__BASEADDRESS` | — | Required when `Mode=Remote`. HTTPS strongly recommended. |
| Remote API key | `AdvisoryAI:Inference:Remote:ApiKey` | `ADVISORYAI__INFERENCE__REMOTE__APIKEY` | — | Injected as `Authorization: Bearer <key>` when present. |
| Remote timeout | `AdvisoryAI:Inference:Remote:TimeoutSeconds` | `ADVISORYAI__INFERENCE__REMOTE__TIMEOUTSECONDS` | `30` | Failing requests fall back to the sanitized prompt with `inference.fallback_reason=remote_timeout`. |
| Guardrail prompt cap | `AdvisoryAI:Guardrails:MaxPromptLength` | `ADVISORYAI__GUARDRAILS__MAXPROMPTLENGTH` | `16000` | Prompts longer than the cap are blocked with `prompt_too_long`. |
| Guardrail citations | `AdvisoryAI:Guardrails:RequireCitations` | `ADVISORYAI__GUARDRAILS__REQUIRECITATIONS` | `true` | When `true`, at least one citation must accompany every prompt. |
| Guardrail phrase seeds | `AdvisoryAI:Guardrails:BlockedPhrases[]`<br>`AdvisoryAI:Guardrails:BlockedPhraseFile` | `ADVISORYAI__GUARDRAILS__BLOCKEDPHRASES__0`<br>`ADVISORYAI__GUARDRAILS__BLOCKEDPHRASEFILE` | See defaults below | File paths are resolved relative to the content root; phrases are merged, de-duped, and lower-cased. |
| Chat request quota | `AdvisoryAI:Chat:Quotas:RequestsPerMinute` | `ADVISORYAI__CHAT__QUOTAS__REQUESTSPERMINUTE` | `60` | Requests per minute per user/org. |
| Chat daily request quota | `AdvisoryAI:Chat:Quotas:RequestsPerDay` | `ADVISORYAI__CHAT__QUOTAS__REQUESTSPERDAY` | `500` | Requests per day per user/org. |
| Chat token budget | `AdvisoryAI:Chat:Quotas:TokensPerDay` | `ADVISORYAI__CHAT__QUOTAS__TOKENSPERDAY` | `100000` | Tokens per day per user/org. |
| Chat tool budget | `AdvisoryAI:Chat:Quotas:ToolCallsPerDay` | `ADVISORYAI__CHAT__QUOTAS__TOOLCALLSPERDAY` | `10000` | Tool calls per day per user/org. |
| Guardrail scrubber entropy | `AdvisoryAI:Guardrails:EntropyThreshold` | `ADVISORYAI__GUARDRAILS__ENTROPYTHRESHOLD` | `3.5` | Entropy threshold for high-risk token redaction. |
| Guardrail scrubber min length | `AdvisoryAI:Guardrails:EntropyMinLength` | `ADVISORYAI__GUARDRAILS__ENTROPYMINLENGTH` | `20` | Minimum token length for entropy checks. |
| Guardrail scrubber allowlist file | `AdvisoryAI:Guardrails:AllowlistFile` | `ADVISORYAI__GUARDRAILS__ALLOWLISTFILE` | `data/advisory-ai/allowlist.txt` | Allowlisted patterns bypass redaction. |
| Guardrail scrubber allowlist patterns | `AdvisoryAI:Guardrails:AllowlistPatterns` | `ADVISORYAI__GUARDRAILS__ALLOWLISTPATTERNS__0` | See defaults | Additional allowlist patterns appended to defaults. |
| Chat tools allow all | `AdvisoryAI:Chat:Tools:AllowAll` | `ADVISORYAI__CHAT__TOOLS__ALLOWALL` | `true` | When true, allow all tools with enabled providers. |
| Chat tool allowlist | `AdvisoryAI:Chat:Tools:AllowedTools` | `ADVISORYAI__CHAT__TOOLS__ALLOWEDTOOLS__0` | See defaults | Allowed tools when `AllowAll=false`. |
| Chat audit enabled | `AdvisoryAI:Chat:Audit:Enabled` | `ADVISORYAI__CHAT__AUDIT__ENABLED` | `true` | Toggles chat audit persistence. |
| Chat audit connection string | `AdvisoryAI:Chat:Audit:ConnectionString` | `ADVISORYAI__CHAT__AUDIT__CONNECTIONSTRING` | --- | Postgres connection string for chat audit logs. |
| Chat audit schema | `AdvisoryAI:Chat:Audit:SchemaName` | `ADVISORYAI__CHAT__AUDIT__SCHEMANAME` | `advisoryai` | Schema for chat audit tables. |
| Chat audit evidence bundle | `AdvisoryAI:Chat:Audit:IncludeEvidenceBundle` | `ADVISORYAI__CHAT__AUDIT__INCLUDEEVIDENCEBUNDLE` | `false` | Store full evidence bundle JSON in audit log. |
| Chat audit retention | `AdvisoryAI:Chat:Audit:RetentionPeriod` | `ADVISORYAI__CHAT__AUDIT__RETENTIONPERIOD` | `90.00:00:00` | Retention period for audit logs. |
| Chat action policy allow | `AdvisoryAI:Chat:Actions:RequirePolicyAllow` | `ADVISORYAI__CHAT__ACTIONS__REQUIREPOLICYALLOW` | `true` | Require policy lattice approval before actions. |
| Plan cache TTL | `AdvisoryAI:PlanCache:DefaultTimeToLive`* | `ADVISORYAI__PLANCACHE__DEFAULTTIMETOLIVE` | `00:10:00` | Controls how long cached plans are reused. (`CleanupInterval` defaults to `00:05:00`). |
| Queue capacity | `AdvisoryAI:Queue:Capacity` | `ADVISORYAI__QUEUE__CAPACITY` | `1024` | Upper bound on in-memory tasks when using the default queue. |
| Queue wait interval | `AdvisoryAI:Queue:DequeueWaitInterval` | `ADVISORYAI__QUEUE__DEQUEUEWAITINTERVAL` | `00:00:01` | Back-off between queue polls when empty. |
@@ -23,12 +39,12 @@ This note centralises the tunable knobs that control Advisory AIs planner, re
---
## 1. Inference knobs & temperature
## 1. Inference knobs & “temperature”
Advisory AI supports two inference modes:
- **Local (default)** The orchestrator emits deterministic prompts and the worker returns the sanitized prompt verbatim. This mode is offline-friendly and does **not** call any external LLMs. There is no stochastic temperature herethe pipeline is purely rule-based.
- **Remote** Sanitized prompts, citations, and metadata are POSTed to `Remote.BaseAddress + Remote.Endpoint` (default `/v1/inference`). Remote providers control sampling temperature on their side. StellaOps treats remote responses deterministically: we record the providers `modelId`, token usage, and any metadata they return. If your remote tier exposes a temperature knob, set it there; Advisory AI simply forwards the prompt.
- **Local (default)** – The orchestrator emits deterministic prompts and the worker returns the sanitized prompt verbatim. This mode is offline-friendly and does **not** call any external LLMs. There is no stochastic “temperature” here—the pipeline is purely rule-based.
- **Remote** – Sanitized prompts, citations, and metadata are POSTed to `Remote.BaseAddress + Remote.Endpoint` (default `/v1/inference`). Remote providers control sampling temperature on their side. StellaOps treats remote responses deterministically: we record the provider’s `modelId`, token usage, and any metadata they return. If your remote tier exposes a temperature knob, set it there; Advisory AI simply forwards the prompt.
### Remote inference quick sample
@@ -52,22 +68,36 @@ Advisory AI supports two inference modes:
| Setting | Default | Explanation |
| --- | --- | --- |
| `MaxPromptLength` | 16000 chars | Upper bound enforced after redaction. Increase cautiouslyremote providers typically cap prompts at 32k tokens. |
| `MaxPromptLength` | 16000 chars | Upper bound enforced after redaction. Increase cautiously—remote providers typically cap prompts at 32k tokens. |
| `RequireCitations` | `true` | Forces each prompt to include at least one citation. Disable only when testing synthetic prompts. |
| `BlockedPhrases[]` | `ignore previous instructions`, `disregard earlier instructions`, `you are now the system`, `override the system prompt`, `please jailbreak` | Inline list merged with the optional file. Comparisons are case-insensitive. |
| `BlockedPhraseFile` | | Points to a newline-delimited list. Relative paths resolve against the content root (`AdvisoryAI.Hosting` sticks to AppContext base). |
| `BlockedPhraseFile` | — | Points to a newline-delimited list. Relative paths resolve against the content root (`AdvisoryAI.Hosting` sticks to AppContext base). |
| `EntropyThreshold` | `3.5` | Shannon entropy threshold for high-risk token redaction. Set to `0` to disable entropy checks. |
| `EntropyMinLength` | `20` | Minimum token length evaluated by the entropy scrubber. |
| `AllowlistPatterns` | Defaults (sha256/sha1/sha384/sha512) | Regex patterns that bypass entropy redaction for known-safe identifiers. |
| `AllowlistFile` | — | Optional allowlist file (JSON array or newline-delimited). Paths resolve against the content root. |
Violations surface in the response metadata (`guardrail.violations[*]`) and increment `advisory_ai_guardrail_blocks_total`. Console consumes the same payload for its ribbon state.
## 2.1 Tool policy lattice (chat)
Chat tool calls are allowed only when policy rules permit. Scope is evaluated on tenant, role, tool name, and resource.
Example (pseudo):
```text
allow_tool("vex.query") if role in ["analyst"] and namespace in ["team-a"]
deny_tool("vault.secrets.get") always
```
## 3. Retrieval & ranking weights (per-task)
Each task type (Summary, Conflict, Remediation) inherits the defaults below. Override any value via `AdvisoryAI:Tasks:<TaskType>:<Property>`.
| Task | `StructuredMaxChunks` | `VectorTopK` | `VectorQueries` (default) | `SbomMaxTimelineEntries` | `SbomMaxDependencyPaths` | `IncludeBlastRadius` |
| --- | --- | --- | --- | --- | --- | --- |
| Summary | 25 | 5 | `Summarize key facts`, `What is impacted?` | 10 | 20 | |
| Conflict | 30 | 6 | `Highlight conflicting statements`, `Where do sources disagree?` | 8 | 15 | |
| Remediation | 35 | 6 | `Provide remediation steps`, `Outline mitigations and fixes` | 12 | 25 | |
| Summary | 25 | 5 | `Summarize key facts`, `What is impacted?` | 10 | 20 | ✔ |
| Conflict | 30 | 6 | `Highlight conflicting statements`, `Where do sources disagree?` | 8 | 15 | ✖ |
| Remediation | 35 | 6 | `Provide remediation steps`, `Outline mitigations and fixes` | 12 | 25 | ✔ |
These knobs act as weighting levers: lower `VectorTopK` emphasises deterministic evidence; higher values favor breadth. `StructuredMaxChunks` bounds how many CSAF/OSV/VEX chunks reach the prompt, keeping token budgets predictable.
@@ -77,17 +107,17 @@ These knobs act as weighting levers: lower `VectorTopK` emphasises deterministic
| Task | Prompt tokens | Completion tokens |
| --- | --- | --- |
| Summary | 2048 | 512 |
| Conflict | 2048 | 512 |
| Remediation | 2048 | 640 |
| Summary | 2 048 | 512 |
| Conflict | 2 048 | 512 |
| Remediation | 2 048 | 640 |
Overwrite via `AdvisoryAI:Tasks:Summary:Budget:PromptTokens`, etc. The worker records actual consumption in the response metadata (`inference.prompt_tokens`, `inference.completion_tokens`).
## 5. Cache TTLs & queue directories
- **Plan cache TTLs** In-memory and file-system caches honour `AdvisoryAI:PlanCache:DefaultTimeToLive` (default 10 minutes) and `CleanupInterval` (default 5 minutes). Shorten the TTL to reduce stale plans or increase it to favour offline reuse. Both values accept ISO 8601 or `hh:mm:ss` time spans.
- **Queue & storage paths** `AdvisoryAI:Queue:DirectoryPath`, `AdvisoryAI:Storage:PlanCacheDirectory`, and `AdvisoryAI:Storage:OutputDirectory` default to `data/advisory-ai/{queue,plans,outputs}` under the content root; override these when mounting RWX volumes in sovereign clusters.
- **Output TTLs** Output artefacts inherit the host file-system retention policies. Combine `DefaultTimeToLive` with a cron or systemd timer to prune `outputs/` periodically when operating in remote-inference-heavy environments.
- **Plan cache TTLs** – In-memory and file-system caches honour `AdvisoryAI:PlanCache:DefaultTimeToLive` (default 10 minutes) and `CleanupInterval` (default 5 minutes). Shorten the TTL to reduce stale plans or increase it to favour offline reuse. Both values accept ISO 8601 or `hh:mm:ss` time spans.
- **Queue & storage paths** – `AdvisoryAI:Queue:DirectoryPath`, `AdvisoryAI:Storage:PlanCacheDirectory`, and `AdvisoryAI:Storage:OutputDirectory` default to `data/advisory-ai/{queue,plans,outputs}` under the content root; override these when mounting RWX volumes in sovereign clusters.
- **Output TTLs** – Output artefacts inherit the host file-system retention policies. Combine `DefaultTimeToLive` with a cron or systemd timer to prune `outputs/` periodically when operating in remote-inference-heavy environments.
### Example: raised TTL & custom queue path
@@ -108,5 +138,6 @@ Overwrite via `AdvisoryAI:Tasks:Summary:Budget:PromptTokens`, etc. The worker re
## 6. Operational notes
- Updating **guardrail phrases** triggers only on host reload. When distributing blocked-phrase files via Offline Kits, keep filenames stable and version them through Git so QA can diff changes.
- **Temperature / sampling** remains a remote-provider concern. StellaOps records the providers `modelId` and exposes fallback metadata so policy authors can audit when sanitized prompts were returned instead of model output.
- **Temperature / sampling** remains a remote-provider concern. StellaOps records the provider’s `modelId` and exposes fallback metadata so policy authors can audit when sanitized prompts were returned instead of model output.
- Always track changes in `docs/implplan/SPRINT_0111_0001_0001_advisoryai.md` (task `DOCS-AIAI-31-006`) when promoting this document so the guild can trace which parameters were added per sprint.

View File

@@ -0,0 +1,29 @@
# Assistant Tool Lattice Policy Mapping
This guide defines the tool lattice rule schema and default scope mapping for assistant tool calls.
The lattice is evaluated by Policy Gateway and returns allow or deny decisions for each tool request.
## Default deny behavior
- If no rule matches a tool request, the decision is deny.
- A rule must match tool name, action, and any configured tenant, role, scope, or resource filters to allow access.
## Rule fields
- tool: Tool name or wildcard pattern (for example, "vex.query" or "scanner.*").
- action: Read or action discriminator (for example, "read" or "action").
- scopes: Required Authority scopes (one or more).
- roles: Optional role filters (one or more).
- tenants: Optional tenant filters (one or more).
- resource: Optional resource pattern (for example, "sbom:component:*").
- effect: allow or deny.
- priority: Integer priority; higher values evaluate first.
## Default scope mapping
| Tool | Action | Required scopes |
| --- | --- | --- |
| vex.query | read | vex:read |
| sbom.read | read | sbom:read |
| scanner.findings.topk | read | scanner:read or findings:read |
## Override guidance
- Use priority to override default rules.
- Keep rules deterministic by using stable patterns and avoiding ambiguous overlaps.

View File

@@ -169,12 +169,18 @@ message ResolveResponse {
**Doctor Check Output**:
```typescript
interface DoctorHowToFix {
summary: string;
commands: string[];
}
interface DoctorCheckResult {
checkType: string;
status: "pass" | "warn" | "fail";
message: string;
details: Record<string, any>;
suggestions: string[];
howToFix?: DoctorHowToFix;
runAt: DateTime;
durationMs: number;
}
@@ -183,10 +189,33 @@ interface DoctorReport {
integrationId: UUID;
overallStatus: "healthy" | "degraded" | "unhealthy";
checks: DoctorCheckResult[];
evidenceLog?: {
jsonlPath: string;
dssePath?: string;
};
generatedAt: DateTime;
}
```
Doctor JSON output for CLI/agents uses `how_to_fix` (snake case) as the alias of
`howToFix` to preserve verbatim fix commands.
Doctor fix executes only non-destructive commands; destructive steps are manual
and never executed by Doctor.
Evidence logs include `doctor_command`, and DSSE summaries include the same
operator-invoked command note.
**Declarative Packs (YAML)**:
- Packs live in `plugins/doctor/*.yaml` and are discoverable by env/file gating.
- `checks[].run.exec` executes CLI commands; `checks[].parse` defines pass/fail.
- `checks[].how_to_fix.commands[]` must be printed verbatim and remain deterministic.
Sample manifest:
- `docs/benchmarks/doctor/doctor-plugin-release-orchestrator-gitlab.yaml`
**Evidence Artifacts**:
- JSONL evidence log per run (local by default).
- Optional DSSE summary for audit export.
---
## Cache Eviction Policies

View File

@@ -26,36 +26,14 @@ The attestation provides the *evidence* that supports VEX claims. For example, a
### Component Diagram
```
┌──────────────────────────────────────────────────────────────────────────────┐
│ Binary Diff Attestation Flow │
├──────────────────────────────────────────────────────────────────────────────┤
│ │
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ OCI │ │ Layer │ │ Binary │ │ Section │ │
│ │ Registry │───▶│ Extraction │───▶│ Detection │───▶│ Hash
│ │ Client │ │ │ │ │ │ Extractor │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ └──────┬──────┘ │
│ │ │
│ Base Image ─────────────────────────────────────┐ │ │
│ Target Image ───────────────────────────────────┤ ▼ │
│ │ ┌─────────────┐ │
│ └─▶│ Diff │ │
│ │ Computation │ │
│ └──────┬──────┘ │
│ │ │
│ ▼ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ DSSE │◀───│ Predicate │◀───│ Finding │◀───│ Verdict │ │
│ │ Signer │ │ Builder │ │ Aggregation │ │ Classifier │ │
│ └──────┬──────┘ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ Rekor │ │ File │ │
│ │ Submission │ │ Output │ │
│ └─────────────┘ └─────────────┘ │
│ │
└──────────────────────────────────────────────────────────────────────────────┘
+-------------------+ +--------------------+ +--------------------+ +----------------------+
| OCI Registry |-->| Layer Extraction |-->| ELF Detection |-->| Section Hash Extract |
+-------------------+ +--------------------+ +--------------------+ +----------------------+
| base + target images
v
+-------------------+ +--------------------+ +------------------+ +------------------+
| Diff Computation |-->| Predicate Builder |-->| DSSE Signer |-->| Output Files |
+-------------------+ +--------------------+ +------------------+ +------------------+
```
### Key Components
@@ -63,8 +41,8 @@ The attestation provides the *evidence* that supports VEX claims. For example, a
| Component | Location | Responsibility |
|-----------|----------|----------------|
| `ElfSectionHashExtractor` | `Scanner.Analyzers.Native` | Extract per-section SHA-256 hashes from ELF binaries |
| `BinaryDiffService` | `Cli.Services` | Orchestrate diff computation between two images |
| `BinaryDiffPredicateBuilder` | `Attestor.StandardPredicates` | Construct BinaryDiffV1 in-toto predicates |
| `BinaryDiffService` | `Cli.Commands.Scan` | Orchestrate diff computation between two images |
| `BinaryDiffPredicateBuilder` | `Attestor.StandardPredicates` | Construct BinaryDiffV1 predicate payloads |
| `BinaryDiffDsseSigner` | `Attestor.StandardPredicates` | Sign predicates with DSSE envelopes |
### Data Flow
@@ -74,9 +52,9 @@ The attestation provides the *evidence* that supports VEX claims. For example, a
3. **Binary Identification**: Identify ELF binaries in both filesystems
4. **Section Hash Computation**: Compute SHA-256 for each target section in each binary
5. **Diff Computation**: Compare section hashes between base and target
6. **Verdict Classification**: Classify changes as patched/vanilla/unknown
6. **Verdict Classification**: Basic classification of unchanged vs modified binaries
7. **Predicate Construction**: Build BinaryDiffV1 predicate with findings
8. **DSSE Signing**: Sign predicate and optionally submit to Rekor
8. **DSSE Signing**: Sign predicate; optional transparency log submission is handled by attestor tooling
## ELF Section Hashing
@@ -131,26 +109,24 @@ All operations produce deterministic output:
### Schema Overview
The `BinaryDiffV1` predicate follows in-toto attestation format:
The `BinaryDiffV1` predicate payload uses the following structure:
```json
{
"_type": "https://in-toto.io/Statement/v1",
"subject": [
"predicateType": "stellaops.binarydiff.v1",
"subjects": [
{
"name": "docker://repo/app@sha256:target...",
"digest": { "sha256": "target..." }
"digest": { "sha256": "target..." },
"platform": { "os": "linux", "architecture": "amd64" }
}
],
"predicateType": "stellaops.binarydiff.v1",
"predicate": {
"inputs": {
"base": { "digest": "sha256:base..." },
"target": { "digest": "sha256:target..." }
},
"findings": [...],
"metadata": {...}
}
"inputs": {
"base": { "digest": "sha256:base..." },
"target": { "digest": "sha256:target..." }
},
"findings": [...],
"metadata": { ... }
}
```
@@ -175,15 +151,18 @@ Each finding represents a binary comparison:
"binaryFormat": "elf",
"sectionDeltas": [
{ "section": ".text", "status": "modified" },
{ "section": ".rodata", "status": "identical" }
{ "section": ".rodata", "status": "added" }
],
"confidence": 0.95,
"verdict": "patched"
"confidence": 0.50,
"verdict": "unknown"
}
```
### Verdicts
Current CLI output uses `vanilla` for unchanged binaries and `unknown` for modified binaries.
Advanced verdict classification (patched/vanilla) is planned for follow-up work.
| Verdict | Meaning | Confidence Threshold |
|---------|---------|---------------------|
| `patched` | Binary shows evidence of security patch | >= 0.90 |
@@ -210,13 +189,12 @@ Each finding represents a binary comparison:
### Signature Algorithm
- **Default**: Ed25519
- **Alternative**: ECDSA P-256, RSA-PSS (via `ICryptoProviderRegistry`)
- **Keyless**: Sigstore Fulcio certificate chain
- **CLI output**: ECDSA (P-256/384/521) with operator-provided PEM key
- **Library support**: Ed25519 available via `EnvelopeSignatureService`
### Rekor Submission
When Rekor is enabled:
When Rekor is enabled in attestor tooling:
1. DSSE envelope is submitted to Rekor transparency log
2. Inclusion proof is retrieved
@@ -229,22 +207,28 @@ When Rekor is enabled:
"integratedTime": "2026-01-13T12:00:00Z"
}
```
Note: `stella scan diff` does not submit to Rekor; it only emits local DSSE outputs.
### Verification
Binary diff attestations can be verified with:
```bash
# Using cosign
# Attach the DSSE envelope to the image
stella attest attach \
--image docker://repo/app:1.0.1 \
--attestation ./binarydiff.dsse.json
# Verify with cosign (key-based)
cosign verify-attestation \
--type stellaops.binarydiff.v1 \
--certificate-identity-regexp '.*' \
--certificate-oidc-issuer-regexp '.*' \
--key ./keys/binarydiff.pub \
docker://repo/app:1.0.1
# Using stella CLI
stella verify attestation ./binarydiff.dsse.json \
--type stellaops.binarydiff.v1
# Verify with stella CLI
stella attest verify \
--image docker://repo/app:1.0.1 \
--predicate-type stellaops.binarydiff.v1
```
## Integration Points
@@ -335,7 +319,7 @@ See [CLI Reference](../../API_CLI_REFERENCE.md#stella-scan-diff) for full option
1. **ELF only**: PE and Mach-O support planned for M2
2. **Single platform**: Multi-platform diff requires multiple invocations
3. **No function-level analysis**: Section-level granularity only
4. **Confidence scoring**: Based on section changes, not semantic analysis
4. **Confidence scoring**: Placeholder scoring only; verdict classifier is minimal
### Roadmap

View File

@@ -0,0 +1,84 @@
# OCI Image Inspection
## Overview
OCI image inspection resolves an image reference to its manifest or index, enumerates platform manifests, and returns ordered layer metadata. The inspector is used by CLI workflows that need deterministic image metadata without pulling layers.
## Architecture
### Components
| Component | Location | Responsibility |
| --- | --- | --- |
| `IOciImageInspector` | `Scanner.Storage.Oci` | Public interface for image inspection |
| `OciImageInspector` | `Scanner.Storage.Oci` | Implements manifest/index resolution, auth flow, and ordering |
| `ImageInspectionResult` | `Scanner.Contracts` | Output model for index, platform, and layer data |
### Data flow
1. Parse the image reference into registry, repository, tag or digest.
2. HEAD the manifest to obtain media type and digest.
3. GET the manifest payload.
4. If media type is index, enumerate platform manifests and optionally resolve each manifest.
5. For each manifest, fetch config (for platform metadata) and list layers in manifest order.
6. Return ordered results with warnings and a deterministic inspection timestamp.
## Media type support
| Media type | Type | Handling |
| --- | --- | --- |
| `application/vnd.oci.image.index.v1+json` | OCI index | Parse as index and enumerate manifests |
| `application/vnd.docker.distribution.manifest.list.v2+json` | Docker list | Parse as index |
| `application/vnd.oci.image.manifest.v1+json` | OCI manifest | Parse as manifest |
| `application/vnd.docker.distribution.manifest.v2+json` | Docker manifest | Parse as manifest |
## Configuration
The inspector uses `OciRegistryOptions`:
| Field | Purpose |
| --- | --- |
| `DefaultRegistry` | Registry to use when no registry is specified |
| `AllowInsecure` | Allow HTTP and insecure TLS for registry calls |
| `Auth.Username` / `Auth.Password` | Basic auth credentials |
| `Auth.Token` | Bearer token |
| `Auth.AllowAnonymousFallback` | Allow retry without auth after 401 |
CLI configuration binding uses the `OciRegistry` section (example):
```json
{
"OciRegistry": {
"DefaultRegistry": "docker.io",
"AllowInsecure": false,
"Auth": {
"Username": "registry-user",
"Password": "registry-pass",
"AllowAnonymousFallback": true
}
}
}
```
## Output model
`ImageInspectionResult` returns:
- Resolved digest and media type
- Multi-arch indicator
- Ordered platform manifests (os, arch, variant)
- Ordered layer list with size and media type
- UTC inspection timestamp from `TimeProvider`
- Deterministic, sorted warnings
## Determinism
- Platforms sorted by `os`, `architecture`, `variant`.
- Layers preserve manifest order (0-indexed).
- Warnings sorted lexicographically and de-duplicated.
- Timestamps come from injected `TimeProvider`.
## Integration points
- CLI: `stella image inspect` consumes the inspector result for table and JSON output.
- Scanner services can reuse the inspector for registry resolution without pulling layers.

View File

@@ -26,6 +26,7 @@ The Console presents operator dashboards for scans, policies, VEX evidence, runt
- Preserve determinism: sort outputs, normalise timestamps (UTC ISO-8601), and avoid machine-specific artefacts.
- Keep Offline Kit parity in mind—document air-gapped workflows for any new feature.
- Update runbooks/observability assets when operational characteristics change.
- Advisor surfaces must be evidence-first and require confirmation for any actions.
## Required Reading
- `docs/modules/ui/README.md`
- `docs/modules/ui/architecture.md`

View File

@@ -178,11 +178,18 @@ Each feature folder builds as a **standalone route** (lazy loaded). All HTTP sha
- Kernel/privilege preflight checks for eBPF/ETW observers.
- Helm and systemd install templates.
- Agent download and registration flow.
* **Models**: `integration.models.ts` defines `IntegrationDraft`, `IntegrationProvider`, `WizardStep`, `PreflightCheck`, `AuthMethod`, and provider constants.
---
## 4) Auth, sessions & RBAC
* **Models**: `integration.models.ts` defines `IntegrationDraft`, `IntegrationProvider`, `WizardStep`, `PreflightCheck`, `AuthMethod`, and provider constants.
### 3.12 Advisor (Ask Stella)
* **Chat panel** scoped to the current artifact, CVE, or release, with citations and evidence chips.
* **Citations and Evidence** drawer lists object refs (SBOM, VEX, scan IDs) and hashes.
* **Action confirmation** modal required for any tool action; disabled when policy denies.
* **Budget indicators** show quota or token budget exhaustion with retry hints.
---
## 4) Auth, sessions & RBAC
### 4.1 OIDC flow

View File

@@ -2,343 +2,166 @@
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://stellaops.io/schemas/binarydiff-v1.schema.json",
"title": "BinaryDiffV1",
"description": "In-toto predicate schema for binary-level diff attestations between container images",
"description": "In-toto predicate for binary-level diff attestations",
"type": "object",
"required": ["predicateType", "inputs", "findings", "metadata"],
"additionalProperties": false,
"required": ["predicateType", "subjects", "inputs", "findings", "metadata"],
"properties": {
"predicateType": {
"const": "stellaops.binarydiff.v1",
"description": "Predicate type identifier"
"const": "stellaops.binarydiff.v1"
},
"subjects": {
"type": "array",
"items": { "$ref": "#/$defs/BinaryDiffSubject" },
"minItems": 1
},
"inputs": {
"$ref": "#/$defs/BinaryDiffInputs",
"description": "Base and target image references"
"$ref": "#/$defs/BinaryDiffInputs"
},
"findings": {
"type": "array",
"items": {
"$ref": "#/$defs/BinaryDiffFinding"
},
"description": "Per-binary diff findings"
"items": { "$ref": "#/$defs/BinaryDiffFinding" }
},
"metadata": {
"$ref": "#/$defs/BinaryDiffMetadata",
"description": "Analysis metadata"
"$ref": "#/$defs/BinaryDiffMetadata"
}
},
"$defs": {
"BinaryDiffInputs": {
"BinaryDiffSubject": {
"type": "object",
"required": ["base", "target"],
"additionalProperties": false,
"required": ["name", "digest"],
"properties": {
"base": {
"$ref": "#/$defs/ImageReference",
"description": "Base image reference"
},
"target": {
"$ref": "#/$defs/ImageReference",
"description": "Target image reference"
}
}
},
"ImageReference": {
"type": "object",
"required": ["digest"],
"additionalProperties": false,
"properties": {
"reference": {
"name": {
"type": "string",
"description": "Full image reference (e.g., docker://repo/image:tag)",
"examples": ["docker://registry.example.com/app:1.0.0"]
"description": "Image reference (e.g., docker://repo/app@sha256:...)"
},
"digest": {
"type": "string",
"pattern": "^sha256:[a-f0-9]{64}$",
"description": "Image digest in sha256:hex format"
},
"manifestDigest": {
"type": "string",
"pattern": "^sha256:[a-f0-9]{64}$",
"description": "Platform-specific manifest digest"
"type": "object",
"additionalProperties": { "type": "string" }
},
"platform": {
"$ref": "#/$defs/Platform"
}
}
},
"BinaryDiffInputs": {
"type": "object",
"required": ["base", "target"],
"properties": {
"base": { "$ref": "#/$defs/ImageReference" },
"target": { "$ref": "#/$defs/ImageReference" }
}
},
"ImageReference": {
"type": "object",
"required": ["digest"],
"properties": {
"reference": { "type": "string" },
"digest": { "type": "string" },
"manifestDigest": { "type": "string" },
"platform": { "$ref": "#/$defs/Platform" }
}
},
"Platform": {
"type": "object",
"required": ["os", "architecture"],
"additionalProperties": false,
"properties": {
"os": {
"type": "string",
"description": "Operating system (e.g., linux, windows)",
"examples": ["linux", "windows"]
},
"architecture": {
"type": "string",
"description": "CPU architecture (e.g., amd64, arm64)",
"examples": ["amd64", "arm64", "386"]
},
"variant": {
"type": "string",
"description": "Architecture variant (e.g., v8 for arm64)",
"examples": ["v7", "v8"]
}
"os": { "type": "string" },
"architecture": { "type": "string" },
"variant": { "type": "string" }
}
},
"BinaryDiffFinding": {
"type": "object",
"required": ["path", "changeType", "binaryFormat"],
"additionalProperties": false,
"properties": {
"path": {
"type": "string",
"description": "File path within the container filesystem",
"examples": ["/usr/lib/libssl.so.3", "/usr/bin/openssl"]
"description": "File path within the image filesystem"
},
"changeType": {
"type": "string",
"enum": ["added", "removed", "modified", "unchanged"],
"description": "Type of change detected"
"enum": ["added", "removed", "modified", "unchanged"]
},
"binaryFormat": {
"type": "string",
"enum": ["elf", "pe", "macho", "unknown"],
"description": "Binary format detected"
"enum": ["elf", "pe", "macho", "unknown"]
},
"layerDigest": {
"type": "string",
"pattern": "^sha256:[a-f0-9]{64}$",
"description": "Layer digest that introduced this file/change"
"description": "Layer that introduced this change"
},
"baseHashes": {
"$ref": "#/$defs/SectionHashSet",
"description": "Section hashes from base image binary"
"$ref": "#/$defs/SectionHashSet"
},
"targetHashes": {
"$ref": "#/$defs/SectionHashSet",
"description": "Section hashes from target image binary"
"$ref": "#/$defs/SectionHashSet"
},
"sectionDeltas": {
"type": "array",
"items": {
"$ref": "#/$defs/SectionDelta"
},
"description": "Per-section comparison results"
"items": { "$ref": "#/$defs/SectionDelta" }
},
"confidence": {
"type": "number",
"minimum": 0,
"maximum": 1,
"description": "Confidence score for verdict (0.0-1.0)"
"maximum": 1
},
"verdict": {
"type": "string",
"enum": ["patched", "vanilla", "unknown", "incompatible"],
"description": "Classification of the binary change"
"enum": ["patched", "vanilla", "unknown", "incompatible"]
}
}
},
"SectionHashSet": {
"type": "object",
"additionalProperties": false,
"properties": {
"buildId": {
"type": "string",
"pattern": "^[a-f0-9]+$",
"description": "GNU Build-ID from .note.gnu.build-id section"
},
"fileHash": {
"type": "string",
"pattern": "^[a-f0-9]{64}$",
"description": "SHA-256 hash of the entire file"
},
"extractorVersion": {
"type": "string",
"description": "Version of the section hash extractor"
},
"buildId": { "type": "string" },
"fileHash": { "type": "string" },
"sections": {
"type": "object",
"additionalProperties": {
"$ref": "#/$defs/SectionInfo"
},
"description": "Map of section name to section info"
}
}
}
},
"SectionInfo": {
"type": "object",
"required": ["sha256", "size"],
"additionalProperties": false,
"properties": {
"sha256": {
"type": "string",
"pattern": "^[a-f0-9]{64}$",
"description": "SHA-256 hash of section contents"
},
"blake3": {
"type": "string",
"pattern": "^[a-f0-9]{64}$",
"description": "Optional BLAKE3-256 hash of section contents"
},
"size": {
"type": "integer",
"minimum": 0,
"description": "Section size in bytes"
},
"offset": {
"type": "integer",
"minimum": 0,
"description": "Section offset in file"
},
"type": {
"type": "string",
"description": "ELF section type (e.g., SHT_PROGBITS)"
},
"flags": {
"type": "string",
"description": "ELF section flags (e.g., SHF_ALLOC | SHF_EXECINSTR)"
}
"sha256": { "type": "string" },
"blake3": { "type": "string" },
"size": { "type": "integer" }
}
},
"SectionDelta": {
"type": "object",
"required": ["section", "status"],
"additionalProperties": false,
"properties": {
"section": {
"type": "string",
"description": "Section name (e.g., .text, .rodata)",
"examples": [".text", ".rodata", ".data", ".symtab", ".dynsym"]
"description": "Section name (e.g., .text, .rodata)"
},
"status": {
"type": "string",
"enum": ["identical", "modified", "added", "removed"],
"description": "Section comparison status"
"enum": ["identical", "modified", "added", "removed"]
},
"baseSha256": {
"type": "string",
"pattern": "^[a-f0-9]{64}$",
"description": "SHA-256 of section in base binary"
},
"targetSha256": {
"type": "string",
"pattern": "^[a-f0-9]{64}$",
"description": "SHA-256 of section in target binary"
},
"sizeDelta": {
"type": "integer",
"description": "Size difference (target - base) in bytes"
}
"baseSha256": { "type": "string" },
"targetSha256": { "type": "string" },
"sizeDelta": { "type": "integer" }
}
},
"BinaryDiffMetadata": {
"type": "object",
"required": ["toolVersion", "analysisTimestamp"],
"additionalProperties": false,
"properties": {
"toolVersion": {
"type": "string",
"description": "Version of the binary diff tool",
"examples": ["1.0.0", "2026.01.0"]
},
"toolVersion": { "type": "string" },
"analysisTimestamp": {
"type": "string",
"format": "date-time",
"description": "UTC timestamp of analysis (ISO-8601)"
},
"configDigest": {
"type": "string",
"pattern": "^sha256:[a-f0-9]{64}$",
"description": "SHA-256 of analysis configuration for reproducibility"
},
"totalBinaries": {
"type": "integer",
"minimum": 0,
"description": "Total number of binaries analyzed"
},
"modifiedBinaries": {
"type": "integer",
"minimum": 0,
"description": "Number of binaries with modifications"
"format": "date-time"
},
"configDigest": { "type": "string" },
"totalBinaries": { "type": "integer" },
"modifiedBinaries": { "type": "integer" },
"analyzedSections": {
"type": "array",
"items": {
"type": "string"
},
"description": "List of section names analyzed",
"examples": [[".text", ".rodata", ".data", ".symtab", ".dynsym"]]
},
"hashAlgorithms": {
"type": "array",
"items": {
"type": "string",
"enum": ["sha256", "blake3"]
},
"description": "Hash algorithms used"
"items": { "type": "string" }
}
}
}
},
"examples": [
{
"predicateType": "stellaops.binarydiff.v1",
"inputs": {
"base": {
"reference": "docker://registry.example.com/app:1.0.0",
"digest": "sha256:abc123def456789012345678901234567890123456789012345678901234abcd",
"platform": {
"os": "linux",
"architecture": "amd64"
}
},
"target": {
"reference": "docker://registry.example.com/app:1.0.1",
"digest": "sha256:def456abc789012345678901234567890123456789012345678901234567efgh",
"platform": {
"os": "linux",
"architecture": "amd64"
}
}
},
"findings": [
{
"path": "/usr/lib/libssl.so.3",
"changeType": "modified",
"binaryFormat": "elf",
"sectionDeltas": [
{
"section": ".text",
"status": "modified",
"baseSha256": "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
"targetSha256": "fedcba0987654321fedcba0987654321fedcba0987654321fedcba0987654321",
"sizeDelta": 256
},
{
"section": ".rodata",
"status": "identical",
"baseSha256": "abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890",
"targetSha256": "abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890",
"sizeDelta": 0
}
],
"confidence": 0.95,
"verdict": "patched"
}
],
"metadata": {
"toolVersion": "1.0.0",
"analysisTimestamp": "2026-01-13T12:00:00Z",
"totalBinaries": 156,
"modifiedBinaries": 3,
"analyzedSections": [".text", ".rodata", ".data", ".symtab", ".dynsym"],
"hashAlgorithms": ["sha256"]
}
}
]
}
}

View File

@@ -0,0 +1,218 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://stellaops.io/schemas/golden-pair-v1.schema.json",
"title": "GoldenPairMetadata",
"type": "object",
"additionalProperties": false,
"required": [
"cve",
"name",
"severity",
"artifact",
"original",
"patched",
"patch",
"expectedDiff",
"createdAt",
"createdBy"
],
"properties": {
"cve": {
"type": "string",
"pattern": "^CVE-\\d{4}-\\d{4,}$"
},
"name": {
"type": "string",
"minLength": 1
},
"description": {
"type": "string"
},
"severity": {
"type": "string",
"enum": ["critical", "high", "medium", "low"]
},
"artifact": {
"$ref": "#/$defs/artifactInfo"
},
"original": {
"$ref": "#/$defs/binaryArtifact"
},
"patched": {
"$ref": "#/$defs/binaryArtifact"
},
"patch": {
"$ref": "#/$defs/patchInfo"
},
"advisories": {
"type": "array",
"items": {
"$ref": "#/$defs/advisoryRef"
},
"default": []
},
"expectedDiff": {
"$ref": "#/$defs/expectedDiff"
},
"createdAt": {
"type": "string",
"format": "date-time"
},
"createdBy": {
"type": "string",
"minLength": 1
}
},
"$defs": {
"artifactInfo": {
"type": "object",
"additionalProperties": false,
"required": ["name", "format", "architecture"],
"properties": {
"name": {
"type": "string",
"minLength": 1
},
"format": {
"type": "string",
"enum": ["elf", "pe", "macho"]
},
"architecture": {
"type": "string",
"minLength": 1
},
"os": {
"type": "string",
"minLength": 1
}
}
},
"binaryArtifact": {
"type": "object",
"additionalProperties": false,
"required": ["package", "version", "distro", "source", "sha256"],
"properties": {
"package": {
"type": "string",
"minLength": 1
},
"version": {
"type": "string",
"minLength": 1
},
"distro": {
"type": "string",
"minLength": 1
},
"source": {
"type": "string",
"minLength": 1
},
"sha256": {
"type": "string",
"pattern": "^[a-f0-9]{64}$"
},
"buildId": {
"type": "string",
"minLength": 1
},
"hasDebugSymbols": {
"type": "boolean"
},
"debugSymbolsSource": {
"type": "string",
"minLength": 1
},
"pathInPackage": {
"type": "string",
"minLength": 1
}
}
},
"patchInfo": {
"type": "object",
"additionalProperties": false,
"required": ["commit"],
"properties": {
"commit": {
"type": "string",
"minLength": 6
},
"upstream": {
"type": "string",
"minLength": 1
},
"functionsChanged": {
"type": "array",
"items": {
"type": "string",
"minLength": 1
},
"default": []
},
"filesChanged": {
"type": "array",
"items": {
"type": "string",
"minLength": 1
},
"default": []
},
"summary": {
"type": "string"
}
}
},
"advisoryRef": {
"type": "object",
"additionalProperties": false,
"required": ["source", "id", "url"],
"properties": {
"source": {
"type": "string",
"minLength": 1
},
"id": {
"type": "string",
"minLength": 1
},
"url": {
"type": "string",
"minLength": 1
}
}
},
"expectedDiff": {
"type": "object",
"additionalProperties": false,
"required": ["verdict"],
"properties": {
"sectionsChanged": {
"type": "array",
"items": {
"type": "string",
"minLength": 1
},
"default": []
},
"sectionsIdentical": {
"type": "array",
"items": {
"type": "string",
"minLength": 1
},
"default": []
},
"verdict": {
"type": "string",
"enum": ["patched", "vanilla", "unknown"]
},
"confidenceMin": {
"type": "number",
"minimum": 0,
"maximum": 1
}
}
}
}
}

View File

@@ -0,0 +1,87 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://stellaops.io/schemas/golden-pairs-index.schema.json",
"title": "GoldenPairsIndex",
"type": "object",
"additionalProperties": false,
"required": ["version", "generatedAt", "pairs", "summary"],
"properties": {
"version": {
"type": "string",
"minLength": 1
},
"generatedAt": {
"type": "string",
"format": "date-time"
},
"pairs": {
"type": "array",
"items": {
"$ref": "#/$defs/pairSummary"
}
},
"summary": {
"$ref": "#/$defs/summary"
}
},
"$defs": {
"pairSummary": {
"type": "object",
"additionalProperties": false,
"required": ["cve", "name", "severity", "format", "status"],
"properties": {
"cve": {
"type": "string",
"pattern": "^CVE-\\d{4}-\\d{4,}$"
},
"name": {
"type": "string",
"minLength": 1
},
"severity": {
"type": "string",
"enum": ["critical", "high", "medium", "low"]
},
"format": {
"type": "string",
"enum": ["elf", "pe", "macho"]
},
"status": {
"type": "string",
"enum": ["pending", "validated", "failed", "draft"]
},
"lastValidated": {
"type": "string",
"format": "date-time"
},
"path": {
"type": "string",
"minLength": 1
}
}
},
"summary": {
"type": "object",
"additionalProperties": false,
"required": ["total", "validated", "failed", "pending"],
"properties": {
"total": {
"type": "integer",
"minimum": 0
},
"validated": {
"type": "integer",
"minimum": 0
},
"failed": {
"type": "integer",
"minimum": 0
},
"pending": {
"type": "integer",
"minimum": 0
}
}
}
}
}

View File

@@ -12,9 +12,10 @@ Advisory AI accepts structured evidence from Concelier/Excititor and assembles p
Advisory prompts are rejected when any of the following checks fail:
1. **Citation coverage** every prompt must carry at least one citation with an index, document id, and chunk id. Missing or malformed citations raise the `citation_missing` / `citation_invalid` violations.
2. **Prompt length** `AdvisoryGuardrailOptions.MaxPromptLength` defaults to 16000 characters. Longer payloads raise `prompt_too_long`.
2. **Prompt length** `AdvisoryGuardrailOptions.MaxPromptLength` defaults to 16000 characters. Longer payloads raise `prompt_too_long`.
3. **Blocked phrases** the guardrail pipeline lowercases the prompt and searches for the blocked phrase cache (`ignore previous instructions`, `disregard earlier instructions`, `you are now the system`, `override the system prompt`, `please jailbreak`). Each hit raises `prompt_injection` and increments `blocked_phrase_count` metadata.
4. **Optional per-profile rules** when additional phrases are configured via configuration, they are appended to the cache at startup and evaluated with the same logic.
5. **Token and rate budgets** - per user/org budgets cap prompt size, requests/min, and tool calls/day; overages raise `quota_exceeded`.
Any validation failure stops the pipeline before inference and emits `guardrail_blocked = true` in the persisted output as well as the corresponding metric counter.
@@ -26,10 +27,17 @@ Redactions are deterministic so caches remain stable. The current rule set (in o
|------|-------|-------------|
| AWS secret access keys | `(?i)(aws_secret_access_key\s*[:=]\s*)([A-Za-z0-9/+=]{40,})` | `$1[REDACTED_AWS_SECRET]` |
| Credentials/tokens | `(?i)(token|apikey|password)\s*[:=]\s*([A-Za-z0-9\-_/]{16,})` | `$1: [REDACTED_CREDENTIAL]` |
| High entropy strings | `entropy >= threshold` | `[REDACTED_HIGH_ENTROPY]` |
| PEM private keys | `(?is)-----BEGIN [^-]+ PRIVATE KEY-----.*?-----END [^-]+ PRIVATE KEY-----` | `[REDACTED_PRIVATE_KEY]` |
Redaction counts are surfaced via `guardrailResult.Metadata["redaction_count"]` and emitted as log fields to simplify threat hunting.
### Allowlist and entropy tuning
- Allowlist patterns bypass redaction for known-safe identifiers (scan IDs, digest prefixes, evidence refs).
- Entropy thresholds are configurable per profile to reduce false positives in long hex IDs.
- Configure scrubber knobs via `AdvisoryAI:Guardrails:EntropyThreshold`, `AdvisoryAI:Guardrails:EntropyMinLength`, `AdvisoryAI:Guardrails:AllowlistFile`, and `AdvisoryAI:Guardrails:AllowlistPatterns`.
## 3 · Telemetry, logs, and traces
Advisory AI now exposes the following metrics (all tagged with `task_type` and, where applicable, cache/citation metadata):
@@ -67,7 +75,10 @@ All alerts should route to `#advisory-ai-ops` with the tenant, task type, and re
- **When an alert fires:** capture the guardrail log entry, relevant metrics sample, and the cached plan from the worker output store. Attach them to the incident timeline entry.
- **Tenant overrides:** any request to loosen guardrails or blocked phrase lists requires a signed change request and security approval. Update `AdvisoryGuardrailOptions` via configuration bundles and document the reason in the change log.
- **Chat settings overrides:** quotas and tool allowlists can be adjusted via the chat settings endpoints; env values remain defaults.
- **Doctor check:** use `/api/v1/chat/doctor` to confirm quota/tool limits when chat requests are rejected.
- **Offline kit checks:** ensure the offline inference bundle uses the same guardrail configuration file as production; mismatches should fail the bundle validation step.
- **Forensics:** persisted outputs now contain `guardrail_blocked`, `plan_cache_hit`, and `citation_coverage` metadata. Include these fields when exporting evidence bundles to prove guardrail enforcement.
- **Chat audit trail:** retain prompt hashes, redaction metadata, tool call hashes, and policy decisions for post-incident review.
Keep this document synced whenever guardrail rules, telemetry names, or alert targets change.

View File

@@ -0,0 +1,583 @@
# Setup Wizard - Capability Specification
This document defines the functional requirements for the Stella Ops Setup Wizard, covering both CLI and UI implementations.
## 1. Overview
The Setup Wizard provides a guided, step-by-step configuration experience that:
- Validates infrastructure dependencies (PostgreSQL, Valkey)
- Runs database migrations
- Configures required integrations
- Sets up environments and agents
- Verifies each step via Doctor checks
---
## 2. Completion Thresholds
### 2.1 Operational (Minimum Required)
The system enters "Operational" state when:
| Requirement | Description | Doctor Check |
|-------------|-------------|--------------|
| Database connected | PostgreSQL is reachable and authenticated | `check.database.connectivity` |
| Migrations applied | All startup migrations complete, no pending release migrations | `check.database.migrations.applied` |
| Core services healthy | Gateway, Router, Authority respond to health probes | `check.services.core.healthy` |
| Admin user exists | At least one admin user with `admin:*` scope | `check.auth.admin.exists` |
| Crypto profile valid | At least one signing key configured | `check.crypto.profile.valid` |
**Gating Behavior:** UI blocks access to operational features until Operational threshold met.
### 2.2 Production-Ready (Recommended)
The system reaches "Production-Ready" state when:
| Requirement | Description | Doctor Check |
|-------------|-------------|--------------|
| OIDC/LDAP configured | External identity provider integrated | `check.security.identity.configured` |
| Vault connected | At least one secrets provider | `check.integration.vault.connected` |
| SCM integrated | At least one SCM (GitHub/GitLab) | `check.integration.scm.connected` |
| Notifications configured | At least one notification channel | `check.notify.channel.configured` |
| Feed sync enabled | Vulnerability feed mirroring active | `check.feeds.sync.enabled` |
| Environment defined | At least one environment created | `check.orchestrator.environment.exists` |
| Agent registered | At least one healthy agent | `check.orchestrator.agent.healthy` |
| TLS hardened | All endpoints using TLS 1.2+ | `check.security.tls.hardened` |
---
## 3. Step Catalog
### 3.1 Core Steps
| Step ID | Name | Required | Skippable | Category |
|---------|------|----------|-----------|----------|
| `database` | Database Setup | Yes | No | Infrastructure |
| `valkey` | Valkey/Redis Setup | Yes | No | Infrastructure |
| `migrations` | Database Migrations | Yes | No | Infrastructure |
| `admin` | Admin Bootstrap | Yes | No | Security |
| `crypto` | Crypto Profile | Yes | No | Security |
### 3.2 Integration Steps
| Step ID | Name | Required | Skippable | Category |
|---------|------|----------|-----------|----------|
| `vault` | Secrets Provider | No | Yes | Integration |
| `settingsstore` | Settings Store | No | Yes | Integration |
| `scm` | Source Control | No | Yes | Integration |
| `registry` | Container Registry | No | Yes | Integration |
| `notifications` | Notification Channels | No | Yes | Integration |
| `identity` | Identity Provider (OIDC/LDAP) | No | Yes | Security |
### 3.3 Orchestration Steps
| Step ID | Name | Required | Skippable | Category |
|---------|------|----------|-----------|----------|
| `environments` | Environment Definition | No | Yes | Orchestration |
| `agents` | Agent Registration | No | Yes | Orchestration |
| `feeds` | Vulnerability Feeds | No | Yes | Data |
---
## 4. Step Specifications
### 4.1 Database Setup (`database`)
**Purpose:** Configure PostgreSQL connection and verify accessibility.
**Inputs:**
| Field | Type | Required | Default | Description |
|-------|------|----------|---------|-------------|
| `host` | string | Yes | `localhost` | PostgreSQL host |
| `port` | number | Yes | `5432` | PostgreSQL port |
| `database` | string | Yes | `stellaops` | Database name |
| `username` | string | Yes | - | Database user |
| `password` | secret | Yes | - | Database password |
| `sslMode` | enum | No | `prefer` | SSL mode (disable, prefer, require, verify-ca, verify-full) |
| `poolSize` | number | No | `100` | Connection pool size |
**Outputs:**
- Connection string stored in settings store
- Connection verified via `SELECT 1`
- Schema creation permissions validated
**Validation:**
- TCP connectivity to host:port
- Authentication with credentials
- `CREATE SCHEMA` permission check
**Doctor Checks:**
- `check.database.connectivity`
- `check.database.permissions`
- `check.database.version` (PostgreSQL >= 16)
**Persistence:**
- Environment: `STELLAOPS_POSTGRES_CONNECTION`
- Config: `Storage:ConnectionString` in Authority options
- Encrypted storage of password via configured Vault or local keyring
---
### 4.2 Valkey/Redis Setup (`valkey`)
**Purpose:** Configure Valkey/Redis for caching, queues, and session storage.
**Inputs:**
| Field | Type | Required | Default | Description |
|-------|------|----------|---------|-------------|
| `host` | string | Yes | `localhost` | Valkey host |
| `port` | number | Yes | `6379` | Valkey port |
| `password` | secret | No | - | Valkey password |
| `database` | number | No | `0` | Database index (0-15) |
| `useTls` | boolean | No | `false` | Enable TLS |
| `abortOnConnectFail` | boolean | No | `false` | Fail fast on connection error |
**Outputs:**
- Connection string stored in settings
- PING response verified
**Validation:**
- TCP connectivity
- AUTH if password provided
- PING response within 5 seconds
**Doctor Checks:**
- `check.services.valkey.connectivity`
- `check.services.valkey.ping`
---
### 4.3 Database Migrations (`migrations`)
**Purpose:** Apply pending database migrations across all modules.
**Inputs:**
| Field | Type | Required | Default | Description |
|-------|------|----------|---------|-------------|
| `modules` | string[] | No | `["all"]` | Modules to migrate |
| `dryRun` | boolean | No | `false` | Preview without applying |
| `force` | boolean | No | `false` | Allow release migrations |
**Outputs:**
- List of applied migrations per module
- Schema version recorded in `schema_migrations` table
- Checksum verification results
**Validation:**
- Advisory lock acquisition
- Checksum match for already-applied migrations
- No pending release migrations (unless force=true)
**Doctor Checks:**
- `check.database.migrations.applied`
- `check.database.migrations.checksums`
- `check.database.schema.version`
---
### 4.4 Admin Bootstrap (`admin`)
**Purpose:** Create initial administrator account.
**Inputs:**
| Field | Type | Required | Default | Description |
|-------|------|----------|---------|-------------|
| `username` | string | Yes | `admin` | Admin username |
| `email` | string | Yes | - | Admin email |
| `password` | secret | Yes | - | Admin password |
| `displayName` | string | No | - | Display name |
**Validation:**
- Password complexity (min 12 chars, mixed case, numbers, symbols)
- Email format
- Username uniqueness
**Doctor Checks:**
- `check.auth.admin.exists`
- `check.auth.password.policy`
---
### 4.5 Crypto Profile (`crypto`)
**Purpose:** Configure cryptographic signing keys for attestations.
**Inputs:**
| Field | Type | Required | Default | Description |
|-------|------|----------|---------|-------------|
| `profileType` | enum | Yes | - | `local`, `kms`, `hsm`, `sigstore` |
| `keyAlgorithm` | enum | No | `ecdsa-p256` | Key algorithm |
| `keyId` | string | Conditional | - | KMS/HSM key identifier |
| `certificatePath` | string | Conditional | - | Path to signing certificate |
| `privateKeyPath` | string | Conditional | - | Path to private key |
**Validation:**
- Key material accessible
- Algorithm supported
- Certificate chain valid (if provided)
**Doctor Checks:**
- `check.crypto.profile.valid`
- `check.crypto.signing.test`
---
### 4.6 Vault Integration (`vault`)
**Purpose:** Configure secrets management provider.
**Multi-Connector Support:** Yes - users can add multiple vault integrations.
**Connector Options:**
| Connector | Default | Description |
|-----------|---------|-------------|
| **HashiCorp Vault** | Yes (if detected) | KV v2 secrets engine |
| **Azure Key Vault** | Yes (if Azure env) | Azure-native secrets |
| **AWS Secrets Manager** | Yes (if AWS env) | AWS-native secrets |
| **File Provider** | Fallback | Local file-based secrets |
**Inputs (HashiCorp Vault):**
| Field | Type | Required | Default | Description |
|-------|------|----------|---------|-------------|
| `address` | string | Yes | - | Vault server URL |
| `authMethod` | enum | Yes | `token` | token, approle, kubernetes |
| `mountPoint` | string | No | `secret` | KV mount point |
| `token` | secret | Conditional | - | Vault token |
| `roleId` | string | Conditional | - | AppRole role ID |
| `secretId` | secret | Conditional | - | AppRole secret ID |
**Default Selection Logic:**
1. If `VAULT_ADDR` env var set → HashiCorp Vault
2. If Azure IMDS available → Azure Key Vault
3. If AWS metadata available → AWS Secrets Manager
4. Otherwise → Prompt user
**Doctor Checks:**
- `check.integration.vault.connected`
- `check.integration.vault.auth`
- `check.integration.vault.secrets.access`
---
### 4.7 Settings Store Integration (`settingsstore`)
**Purpose:** Configure application settings and feature flag providers.
**Multi-Connector Support:** Yes - users can add multiple settings stores for different purposes.
**Connector Options:**
| Connector | Priority | Write | Watch | Feature Flags | Labels |
|-----------|----------|-------|-------|---------------|--------|
| **Consul KV** | P0 | Configurable | Yes | No | No |
| **etcd** | P0 | Configurable | Yes | No | No |
| **Azure App Configuration** | P1 | Read-only | Yes | Yes (native) | Yes |
| **AWS Parameter Store** | P1 | Configurable | No | No | Via path |
| **AWS AppConfig** | P2 | Read-only | Yes | Yes (native) | Yes |
| **ZooKeeper** | P2 | Configurable | Yes | No | No |
| **GCP Runtime Config** | P2 | Read-only | Yes | No | No |
**Inputs (Consul KV):**
| Field | Type | Required | Default | Description |
|-------|------|----------|---------|-------------|
| `address` | string | Yes | - | Consul server URL |
| `token` | secret | No | - | ACL token |
| `tokenSecretRef` | string | No | - | Vault path to ACL token |
| `writeEnabled` | boolean | No | `false` | Enable write operations |
**Inputs (etcd):**
| Field | Type | Required | Default | Description |
|-------|------|----------|---------|-------------|
| `address` | string | Conditional | - | Single endpoint URL |
| `endpoints` | string[] | Conditional | - | Multiple endpoint URLs |
| `username` | string | No | - | Authentication username |
| `password` | secret | No | - | Authentication password |
| `passwordSecretRef` | string | No | - | Vault path to password |
| `writeEnabled` | boolean | No | `false` | Enable write operations |
**Default Selection Logic:**
1. If `CONSUL_HTTP_ADDR` env var set -> Consul KV
2. If `ETCD_ENDPOINTS` env var set -> etcd
3. If Azure IMDS + App Config connection available -> Azure App Configuration
4. If AWS metadata + `/stellaops/` path exists -> AWS Parameter Store
5. Otherwise -> Prompt user
**Doctor Checks:**
- `check.integration.settingsstore.connectivity`
- `check.integration.settingsstore.auth`
- `check.integration.settingsstore.read`
- `check.integration.settingsstore.write` (if write enabled)
- `check.integration.settingsstore.latency`
---
### 4.8 SCM Integration (`scm`)
**Purpose:** Configure source control management integrations.
**Multi-Connector Support:** Yes - users can add GitHub AND GitLab simultaneously.
**Connector Options:**
| Connector | Description |
|-----------|-------------|
| **GitHub App** | GitHub.com or GHES via App installation |
| **GitLab Server** | GitLab.com or self-hosted |
| **Bitbucket** | Bitbucket Cloud or Server |
| **Gitea** | Self-hosted Gitea |
| **Azure DevOps** | Azure Repos |
**Inputs (GitHub App):**
| Field | Type | Required | Default | Description |
|-------|------|----------|---------|-------------|
| `appId` | string | Yes | - | GitHub App ID |
| `installationId` | string | Yes | - | Installation ID |
| `privateKey` | secret | Yes | - | App private key (PEM) |
| `apiUrl` | string | No | `https://api.github.com` | API endpoint |
**Doctor Checks:**
- `check.integration.scm.github.auth`
- `check.integration.scm.github.permissions`
---
### 4.9 Notification Channels (`notifications`)
**Purpose:** Configure notification delivery channels.
**Multi-Connector Support:** Yes - multiple channels per type allowed.
**Channel Options:**
| Channel | Description |
|---------|-------------|
| **Slack** | Incoming webhook |
| **Teams** | Incoming webhook |
| **Email** | SMTP server |
| **Webhook** | Generic HTTP POST |
| **PagerDuty** | Incident alerts |
**Inputs (Slack):**
| Field | Type | Required | Default | Description |
|-------|------|----------|---------|-------------|
| `name` | string | Yes | - | Channel display name |
| `webhookUrl` | secret | Yes | - | Slack incoming webhook URL |
| `channel` | string | No | - | Default channel override |
| `username` | string | No | `StellaOps` | Bot username |
| `iconEmoji` | string | No | `:shield:` | Bot icon |
**Doctor Checks:**
- `check.notify.channel.configured`
- `check.notify.slack.webhook`
- `check.notify.delivery.test`
---
### 4.10 Environment Definition (`environments`)
**Purpose:** Define deployment environments (dev, staging, prod).
**Inputs:**
| Field | Type | Required | Default | Description |
|-------|------|----------|---------|-------------|
| `name` | string | Yes | - | Environment slug (lowercase) |
| `displayName` | string | Yes | - | Display name |
| `orderIndex` | number | Yes | - | Pipeline position (0=first) |
| `isProduction` | boolean | No | `false` | Production flag |
| `requiredApprovals` | number | No | `0` | Approval count |
| `requireSeparationOfDuties` | boolean | No | `false` | SoD enforcement |
| `autoPromoteFrom` | string | No | - | Auto-promote source |
**Validation:**
- Production environments require `requiredApprovals >= 1`
- `autoPromoteFrom` must reference existing environment with lower orderIndex
- Name must match `^[a-z][a-z0-9-]{1,31}$`
**Doctor Checks:**
- `check.orchestrator.environment.exists`
- `check.orchestrator.environment.valid`
---
### 4.11 Agent Registration (`agents`)
**Purpose:** Register deployment agents with the orchestrator.
**Inputs:**
| Field | Type | Required | Default | Description |
|-------|------|----------|---------|-------------|
| `name` | string | Yes | - | Agent name |
| `capabilities` | string[] | Yes | - | `docker`, `compose`, `ssh`, `winrm` |
| `labels` | map | No | `{}` | Agent labels for selection |
**Outputs:**
- Registration token (one-time, 24-hour expiry)
- Agent installation command
**Generated Command:**
```bash
stella-agent register --token <token> --name <name> --orchestrator-url <url>
```
**Doctor Checks:**
- `check.orchestrator.agent.registered`
- `check.orchestrator.agent.healthy`
- `check.orchestrator.agent.certificate`
---
## 5. Multi-Connector Model
### 5.1 Connector Categories
Each integration category supports multiple instances:
| Category | Max Instances | Use Case |
|----------|---------------|----------|
| **Vault** | 5 | Separate vaults per environment |
| **Settings Store** | 5 | Config from Azure App Config + feature flags from Consul |
| **SCM** | 10 | GitHub + GitLab + internal Gitea |
| **Registry** | 10 | ECR + Harbor + internal registry |
| **Notifications** | 20 | Slack per team + email + PagerDuty |
### 5.2 Default Connector Selection
The wizard suggests a default connector based on:
1. **Environment Detection:**
- `VAULT_ADDR` -> HashiCorp Vault
- `CONSUL_HTTP_ADDR` -> Consul KV
- `ETCD_ENDPOINTS` -> etcd
- Azure IMDS -> Azure Key Vault / Azure App Configuration
- AWS metadata -> AWS Secrets Manager / AWS Parameter Store
- `GITHUB_TOKEN` -> GitHub
- `GITLAB_TOKEN` -> GitLab
2. **Configuration Files:**
- Existing `etc/*.yaml` samples
- Docker Compose environment files
3. **Repository Defaults:**
- Harbor (most commonly used registry)
- Slack (most common notification)
### 5.3 Last Selected Connector Persistence
The wizard stores user preferences in the settings store:
```json
{
"setupWizard": {
"lastConnectors": {
"vault": "hashicorp-vault",
"settingsstore": "consul-kv",
"scm": "github-app",
"registry": "harbor",
"notifications": "slack"
},
"completedAt": "2026-01-13T10:30:00Z",
"skippedSteps": ["identity", "feeds"]
}
}
```
---
## 6. Resume/Re-run Behavior
### 6.1 Idempotency Requirements
All steps must be safe to re-run:
| Step | Re-run Behavior |
|------|-----------------|
| `database` | Verify connection; no changes if already configured |
| `migrations` | Skip already-applied; apply only pending |
| `admin` | Skip if admin exists; offer password reset |
| `vault` | Add new integration; don't duplicate |
| `settingsstore` | Add new integration; don't duplicate |
| `scm` | Add new integration; don't duplicate |
### 6.2 Configuration Pane Access
After initial setup, the wizard is available from:
- **CLI:** `stella setup --reconfigure`
- **UI:** Settings > Configuration Wizard
Pre-populated with:
- Current configuration values
- Last selected connector per category
- Health status from Doctor checks
---
## 7. Security Posture
### 7.1 Secret Storage
| Secret Type | Storage Location |
|-------------|------------------|
| Database password | Vault (if configured) or local keyring |
| Valkey password | Vault (if configured) or local keyring |
| API tokens | Vault integration |
| Private keys | File system with 0600 permissions |
### 7.2 Redaction Rules
The wizard must never display:
- Full passwords
- API tokens
- Private key contents
- Vault tokens
Display format for sensitive fields:
- Masked: `********`
- Partial: `ghp_****1234` (first 4 + last 4)
### 7.3 Audit Trail
All wizard actions are logged to:
- Timeline service with HLC timestamps
- Authority audit log for admin operations
- Doctor run history for check results
---
## 8. Error Handling
### 8.1 Validation Errors
| Error Type | Behavior |
|------------|----------|
| Invalid input | Inline error message; prevent progression |
| Connection failure | Show error; offer retry with different params |
| Permission denied | Show required permissions; offer skip (if skippable) |
| Timeout | Show timeout; offer retry with increased timeout |
### 8.2 Partial Completion
If wizard exits mid-flow:
- Completed steps are persisted
- Resume shows current state
- Doctor checks identify incomplete setup
---
## 9. Exit Criteria
### 9.1 Successful Completion
The wizard completes successfully when:
- All required steps pass Doctor checks
- User has explicitly skipped or completed all steps
- Operational threshold is met
### 9.2 Completion Actions
On completion:
1. Run full Doctor diagnostic
2. Generate setup report (Markdown)
3. Emit `setup.completed` timeline event
4. Clear first-run flag
5. Redirect to dashboard (UI) or exit with success (CLI)

View File

@@ -0,0 +1,608 @@
# Setup Wizard - Doctor Integration Contract
This document defines how the Setup Wizard integrates with the Doctor diagnostic system to validate each step and provide actionable remediation guidance.
## 1. Overview
The Setup Wizard relies on Doctor checks to:
1. **Validate** each configuration step
2. **Detect** existing configuration (for resume/reconfigure)
3. **Generate** runtime-specific fix commands
4. **Verify** that fixes were applied correctly
---
## 2. Step-to-Check Mapping
### 2.1 Required Steps
| Step ID | Doctor Check ID | Severity | Blocks Progression |
|---------|-----------------|----------|-------------------|
| `database` | `check.database.connectivity` | Critical | Yes |
| `database` | `check.database.permissions` | Critical | Yes |
| `database` | `check.database.version` | Warning | No |
| `valkey` | `check.services.valkey.connectivity` | Critical | Yes |
| `valkey` | `check.services.valkey.ping` | Critical | Yes |
| `migrations` | `check.database.migrations.applied` | Critical | Yes |
| `migrations` | `check.database.migrations.checksums` | Critical | Yes |
| `migrations` | `check.database.schema.version` | Info | No |
| `admin` | `check.auth.admin.exists` | Critical | Yes |
| `admin` | `check.auth.password.policy` | Warning | No |
| `crypto` | `check.crypto.profile.valid` | Critical | Yes |
| `crypto` | `check.crypto.signing.test` | Warning | No |
### 2.2 Optional Steps
| Step ID | Doctor Check ID | Severity | Blocks Progression |
|---------|-----------------|----------|-------------------|
| `vault` | `check.integration.vault.connected` | Warning | No |
| `vault` | `check.integration.vault.auth` | Warning | No |
| `vault` | `check.integration.vault.secrets.access` | Info | No |
| `scm` | `check.integration.scm.github.auth` | Info | No |
| `scm` | `check.integration.scm.github.permissions` | Info | No |
| `scm` | `check.integration.scm.gitlab.auth` | Info | No |
| `registry` | `check.integration.registry.connected` | Info | No |
| `notifications` | `check.notify.channel.configured` | Info | No |
| `notifications` | `check.notify.slack.webhook` | Info | No |
| `notifications` | `check.notify.email.smtp` | Info | No |
| `identity` | `check.security.identity.configured` | Info | No |
| `identity` | `check.security.oidc.provider` | Info | No |
| `environments` | `check.orchestrator.environment.exists` | Info | No |
| `environments` | `check.orchestrator.environment.valid` | Info | No |
| `agents` | `check.orchestrator.agent.registered` | Info | No |
| `agents` | `check.orchestrator.agent.healthy` | Info | No |
| `feeds` | `check.feeds.sync.enabled` | Info | No |
---
## 3. Check Output Model
### 3.1 CheckResult Schema
```csharp
public sealed record CheckResult
{
public required string CheckId { get; init; }
public required CheckStatus Status { get; init; } // Pass, Warn, Fail
public required string Message { get; init; }
public required TimeSpan Duration { get; init; }
public ImmutableDictionary<string, object> Evidence { get; init; }
public ImmutableArray<LikelyCause> LikelyCauses { get; init; }
public ImmutableArray<RemediationCommand> Remediations { get; init; }
public string? VerificationCommand { get; init; }
}
public enum CheckStatus { Pass, Warn, Fail }
public sealed record LikelyCause
{
public required int Priority { get; init; } // 1 = most likely
public required string Description { get; init; }
public string? DocumentationUrl { get; init; }
}
public sealed record RemediationCommand
{
public required RuntimeEnvironment Runtime { get; init; }
public required string Command { get; init; }
public required string Description { get; init; }
public bool RequiresSudo { get; init; }
public bool IsDangerous { get; init; } // Requires confirmation
public ImmutableDictionary<string, string> Placeholders { get; init; }
}
public enum RuntimeEnvironment
{
DockerCompose,
Kubernetes,
Systemd,
WindowsService,
Bare,
Any
}
```
### 3.2 Evidence Dictionary
The `Evidence` dictionary contains check-specific data:
| Check Category | Evidence Keys |
|----------------|---------------|
| **Database** | `host`, `port`, `database`, `version`, `user`, `sslMode` |
| **Valkey** | `host`, `port`, `version`, `usedMemory`, `maxMemory` |
| **Migrations** | `pendingCount`, `appliedCount`, `lastMigration`, `failedMigrations` |
| **Auth** | `adminCount`, `adminUsername`, `passwordLastChanged` |
| **Vault** | `provider`, `version`, `mountPoints`, `authMethod` |
| **SCM** | `provider`, `rateLimit`, `remainingCalls`, `organization` |
---
## 4. Remediation Command Generation
### 4.1 Runtime Detection
The wizard detects the runtime environment via:
```csharp
public interface IRuntimeDetector
{
RuntimeEnvironment Detect();
bool IsDockerAvailable();
bool IsKubernetesContext();
bool IsSystemdManaged(string serviceName);
string GetComposeProjectPath();
string GetKubernetesNamespace();
}
```
Detection logic:
1. Check for `/.dockerenv` file → Docker container
2. Check for `KUBERNETES_SERVICE_HOST` → Kubernetes
3. Check for `docker compose` command → Docker Compose
4. Check for `systemctl` command → systemd
5. Check for Windows services → Windows Service
6. Default → Bare (manual)
### 4.2 Command Templates
#### Database Connection Failure
```yaml
check.database.connectivity:
likelyCauses:
- priority: 1
description: "PostgreSQL is not running"
- priority: 2
description: "Firewall blocking port 5432"
- priority: 3
description: "Incorrect host or port"
- priority: 4
description: "Network connectivity issue"
remediations:
- runtime: DockerCompose
description: "Start PostgreSQL container"
command: "docker compose -f {{COMPOSE_FILE}} up -d postgres"
placeholders:
COMPOSE_FILE: "devops/compose/docker-compose.yml"
- runtime: Kubernetes
description: "Check PostgreSQL pod status"
command: "kubectl get pods -n {{NAMESPACE}} -l app=postgres"
placeholders:
NAMESPACE: "stellaops"
- runtime: Systemd
description: "Start PostgreSQL service"
command: "sudo systemctl start postgresql"
requiresSudo: true
- runtime: Any
description: "Verify PostgreSQL is listening"
command: "pg_isready -h {{HOST}} -p {{PORT}}"
placeholders:
HOST: "localhost"
PORT: "5432"
verificationCommand: "pg_isready -h {{HOST}} -p {{PORT}}"
```
#### Valkey Connection Failure
```yaml
check.services.valkey.connectivity:
likelyCauses:
- priority: 1
description: "Valkey/Redis is not running"
- priority: 2
description: "Firewall blocking port 6379"
- priority: 3
description: "Authentication required but not configured"
remediations:
- runtime: DockerCompose
description: "Start Valkey container"
command: "docker compose -f {{COMPOSE_FILE}} up -d valkey"
placeholders:
COMPOSE_FILE: "devops/compose/docker-compose.yml"
- runtime: Kubernetes
description: "Check Valkey pod status"
command: "kubectl get pods -n {{NAMESPACE}} -l app=valkey"
placeholders:
NAMESPACE: "stellaops"
- runtime: Systemd
description: "Start Valkey service"
command: "sudo systemctl start valkey"
requiresSudo: true
- runtime: Any
description: "Test Valkey connection"
command: "redis-cli -h {{HOST}} -p {{PORT}} PING"
placeholders:
HOST: "localhost"
PORT: "6379"
verificationCommand: "redis-cli -h {{HOST}} -p {{PORT}} PING"
```
#### Pending Migrations
```yaml
check.database.migrations.applied:
likelyCauses:
- priority: 1
description: "Pending release migrations require manual execution"
- priority: 2
description: "Startup migrations not yet applied"
remediations:
- runtime: Any
description: "Run pending migrations (dry-run first)"
command: "stella migrations-run --module all --dry-run"
- runtime: Any
description: "Apply all pending migrations"
command: "stella migrations-run --module all"
isDangerous: true
- runtime: DockerCompose
description: "Run migrations in container"
command: "docker compose exec api stella migrations-run --module all"
- runtime: Kubernetes
description: "Run migrations job"
command: "kubectl apply -f devops/k8s/jobs/migrations.yaml"
verificationCommand: "stella migrations-run --module all --dry-run"
```
#### Vault Authentication Failure
```yaml
check.integration.vault.auth:
likelyCauses:
- priority: 1
description: "Vault token expired or revoked"
- priority: 2
description: "AppRole credentials invalid"
- priority: 3
description: "Kubernetes service account not configured"
- priority: 4
description: "Vault server unreachable"
remediations:
- runtime: Any
description: "Test Vault connectivity"
command: "curl -s {{VAULT_ADDR}}/v1/sys/health"
placeholders:
VAULT_ADDR: "https://vault.example.com:8200"
- runtime: Any
description: "Verify token validity"
command: "vault token lookup"
- runtime: Kubernetes
description: "Check Kubernetes auth configuration"
command: "kubectl get serviceaccount -n {{NAMESPACE}} stellaops-vault-auth"
placeholders:
NAMESPACE: "stellaops"
verificationCommand: "vault token lookup"
```
---
## 5. Placeholder Resolution
### 5.1 Placeholder Sources
Placeholders in commands are resolved from:
| Source | Priority | Example |
|--------|----------|---------|
| User input | 1 (highest) | `{{HOST}}` from form field |
| Environment | 2 | `{{VAULT_ADDR}}` from env |
| Detection | 3 | `{{NAMESPACE}}` from context |
| Default | 4 (lowest) | Fallback value |
### 5.2 Placeholder Syntax
```
{{PLACEHOLDER_NAME}}
{{PLACEHOLDER_NAME:-default_value}}
```
Examples:
- `{{HOST}}` - Required placeholder
- `{{PORT:-5432}}` - Optional with default
- `{{COMPOSE_FILE:-docker-compose.yml}}` - File path default
### 5.3 Secret Redaction
Commands containing secrets are never displayed with actual values:
| Placeholder | Display | Actual |
|-------------|---------|--------|
| `{{PASSWORD}}` | `{{PASSWORD}}` | Never resolved in display |
| `{{TOKEN}}` | `{{TOKEN}}` | Never resolved in display |
| `{{SECRET_KEY}}` | `{{SECRET_KEY}}` | Never resolved in display |
The user must copy and manually substitute secrets.
---
## 6. Verification Flow
### 6.1 Post-Fix Verification
After the user applies a fix, the wizard:
1. **Wait** - Pause for user confirmation ("I've run this command")
2. **Verify** - Run the verification command
3. **Re-check** - Run the original Doctor check
4. **Report** - Show success or next steps
### 6.2 Verification Command Execution
```csharp
public interface IVerificationExecutor
{
Task<VerificationResult> ExecuteAsync(
string command,
TimeSpan timeout,
CancellationToken ct);
}
public sealed record VerificationResult
{
public required bool Success { get; init; }
public required int ExitCode { get; init; }
public required string Output { get; init; }
public required TimeSpan Duration { get; init; }
}
```
### 6.3 Re-Check Behavior
```
[FAIL] check.database.connectivity
Suggested fix applied. Verifying...
[RUN] pg_isready -h localhost -p 5432
localhost:5432 - accepting connections
Re-running check...
[PASS] check.database.connectivity
PostgreSQL connection successful
```
---
## 7. Check Aggregation
### 7.1 Step Completion Criteria
A step is complete when:
- All **Critical** checks pass
- No **Fail** status on any check
- User has acknowledged all **Warning** checks
### 7.2 Aggregated Status
```csharp
public enum StepValidationStatus
{
NotStarted, // No checks run
InProgress, // Checks running
Passed, // All critical pass, no failures
PassedWithWarns, // All critical pass, some warnings
Failed, // Any critical failure
Skipped // User explicitly skipped
}
```
### 7.3 Status Rollup for Thresholds
```
Operational Threshold:
[x] check.database.connectivity PASS
[x] check.database.permissions PASS
[x] check.database.migrations.applied PASS
[x] check.services.valkey.connectivity PASS
[x] check.auth.admin.exists PASS
[x] check.crypto.profile.valid PASS
Status: OPERATIONAL (6/6 required checks passed)
Production-Ready Threshold:
[x] check.security.identity.configured PASS
[x] check.integration.vault.connected PASS
[x] check.integration.scm.connected PASS
[x] check.notify.channel.configured PASS
[ ] check.orchestrator.agent.healthy SKIP
[ ] check.feeds.sync.enabled SKIP
Status: NOT PRODUCTION-READY (4/6 recommended, 2 skipped)
```
---
## 8. Doctor Engine Integration
### 8.1 Wizard-Specific Check Context
The wizard provides context to Doctor checks:
```csharp
public sealed record WizardCheckContext
{
public required string StepId { get; init; }
public required RuntimeEnvironment DetectedRuntime { get; init; }
public required ImmutableDictionary<string, string> UserInputs { get; init; }
public bool GenerateRemediations { get; init; } = true;
public bool IncludePlaceholders { get; init; } = true;
}
```
### 8.2 Check Invocation
```csharp
public interface IWizardDoctorClient
{
Task<ImmutableArray<CheckResult>> RunStepChecksAsync(
string stepId,
WizardCheckContext context,
CancellationToken ct);
Task<CheckResult> RunSingleCheckAsync(
string checkId,
WizardCheckContext context,
CancellationToken ct);
Task<VerificationResult> RunVerificationAsync(
string command,
WizardCheckContext context,
CancellationToken ct);
}
```
### 8.3 Check Timeout
| Check Category | Default Timeout | Max Timeout |
|----------------|-----------------|-------------|
| Connectivity | 10 seconds | 30 seconds |
| Authentication | 15 seconds | 60 seconds |
| Migrations | 60 seconds | 300 seconds |
| Full validation | 30 seconds | 120 seconds |
---
## 9. Remediation Safety
### 9.1 Dangerous Commands
Commands marked `isDangerous: true` require user confirmation:
```
WARNING: This command will modify your database schema.
Command:
stella migrations-run --module all
This action:
- Applies 5 pending migrations
- Cannot be automatically rolled back
- May take several minutes
Type 'apply' to confirm: _
```
### 9.2 Sudo Requirements
Commands requiring `sudo` show a notice:
```
This command requires administrator privileges.
Command:
sudo systemctl start postgresql
[Copy Command]
Note: You may be prompted for your password.
```
### 9.3 Secret Substitution Notice
```
This command contains placeholders for sensitive values.
Command:
vault write auth/approle/login role_id={{ROLE_ID}} secret_id={{SECRET_ID}}
Before running:
1. Replace {{ROLE_ID}} with your AppRole Role ID
2. Replace {{SECRET_ID}} with your AppRole Secret ID
[Copy Command]
```
---
## 10. Check Plugin Requirements
### 10.1 New Checks for Setup Wizard
The following checks may need to be added to existing plugins:
| Plugin | New Check ID | Purpose |
|--------|--------------|---------|
| Core | `check.auth.admin.exists` | Verify admin user exists |
| Core | `check.auth.password.policy` | Verify password complexity |
| Core | `check.crypto.signing.test` | Test signing operation |
| Database | `check.database.migrations.checksums` | Verify migration integrity |
| Integration | `check.integration.vault.secrets.access` | Test secret retrieval |
| Integration | `check.orchestrator.environment.valid` | Validate environment config |
| Notify | `check.notify.delivery.test` | Test notification delivery |
### 10.2 Check Implementation Contract
Each check must implement:
```csharp
public interface ISetupWizardAwareCheck : IDoctorCheck
{
// Standard check execution
Task<CheckResult> ExecuteAsync(CheckContext context, CancellationToken ct);
// Generate runtime-specific remediations
ImmutableArray<RemediationCommand> GetRemediations(
CheckResult result,
RuntimeEnvironment runtime);
// Verification command for this check
string? GetVerificationCommand(RuntimeEnvironment runtime);
}
```
---
## 11. Audit Trail
### 11.1 Setup Event Logging
All wizard actions are logged to the Timeline service:
```csharp
public sealed record SetupWizardEvent
{
public required string EventType { get; init; } // step.started, step.completed, check.failed, etc.
public required string StepId { get; init; }
public required string? CheckId { get; init; }
public required CheckStatus? Status { get; init; }
public required DateTimeOffset OccurredAt { get; init; }
public required string? UserId { get; init; }
public ImmutableDictionary<string, string> Metadata { get; init; }
}
```
### 11.2 Event Types
| Event Type | Description |
|------------|-------------|
| `setup.started` | Wizard initiated |
| `setup.completed` | Wizard finished successfully |
| `setup.aborted` | Wizard cancelled |
| `step.started` | Step configuration began |
| `step.completed` | Step passed all checks |
| `step.failed` | Step failed validation |
| `step.skipped` | User skipped optional step |
| `check.passed` | Individual check passed |
| `check.failed` | Individual check failed |
| `check.warned` | Individual check warned |
| `remediation.copied` | User copied fix command |
| `remediation.verified` | Fix verification succeeded |

View File

@@ -0,0 +1,458 @@
# Setup Wizard - Repository Inventory
This document captures the current state of setup-related components in the Stella Ops codebase, providing evidence for the Setup Wizard design.
## 1. CLI Architecture
### 1.1 Framework & Entry Points
| Component | Path | Description |
|-----------|------|-------------|
| **CLI Entry** | `src/Cli/StellaOps.Cli/Program.cs` | Main entry point using System.CommandLine |
| **Command Factory** | `src/Cli/StellaOps.Cli/Commands/CommandFactory.cs` | Central command registration (53+ command groups) |
| **Bootstrapper** | `src/Cli/StellaOps.Cli/Configuration/CliBootstrapper.cs` | Configuration loading and DI setup |
| **Options** | `src/Cli/StellaOps.Cli/Configuration/StellaOpsCliOptions.cs` | CLI configuration POCOs |
| **Profile Manager** | `src/Cli/StellaOps.Cli/Configuration/CliProfile.cs` | Multi-profile support |
### 1.2 Existing Admin Commands
**File:** `src/Cli/StellaOps.Cli/Commands/Admin/AdminCommandGroup.cs`
Current `stella admin` subcommands:
- `admin policy export|import|validate|list` - Policy management
- `admin users list|add|revoke|update` - User management
- `admin feeds list|status|refresh|history` - Feed management
- `admin system status|info` - System health and info
### 1.3 Doctor Commands
**File:** `src/Cli/StellaOps.Cli/Commands/DoctorCommandGroup.cs`
```bash
stella doctor run [--mode quick|normal|full] [--category <cat>] [--format text|json|markdown]
stella doctor list [--category <cat>] [--verbose]
stella doctor export --output <path>.zip [--include-logs]
```
### 1.4 Configuration System
**Priority Resolution (CliBootstrapper.cs):**
1. Command-line arguments (highest)
2. Environment variables (`STELLAOPS_*` prefix)
3. Configuration files (`appsettings.json`, `appsettings.yaml`)
4. Code defaults (lowest)
**Key Environment Variables:**
- `STELLAOPS_BACKEND_URL` - Backend API URL
- `STELLAOPS_AUTHORITY_URL` - Authority service URL
- `STELLAOPS_POSTGRES_CONNECTION` - Database connection
- `STELLAOPS_OFFLINE_KITS_DIRECTORY` - Offline kit path
---
## 2. Doctor System (Diagnostic Framework)
### 2.1 Core Engine
| Component | Path |
|-----------|------|
| **Engine** | `src/__Libraries/StellaOps.Doctor/Engine/DoctorEngine.cs` |
| **Registry** | `src/__Libraries/StellaOps.Doctor/Engine/CheckRegistry.cs` |
| **Executor** | `src/__Libraries/StellaOps.Doctor/Engine/CheckExecutor.cs` |
| **Models** | `src/__Libraries/StellaOps.Doctor/Models/` |
### 2.2 Plugin System (9 Plugins, 48+ Checks)
| Plugin | Path | Category | Checks |
|--------|------|----------|--------|
| **Core** | `StellaOps.Doctor.Plugins.Core` | Core | 9 checks (config, disk, memory, crypto) |
| **Database** | `StellaOps.Doctor.Plugins.Database` | Database | 8 checks (connectivity, migrations, schema) |
| **ServiceGraph** | `StellaOps.Doctor.Plugins.ServiceGraph` | ServiceGraph | 6 checks (gateway, Valkey) |
| **Security** | `StellaOps.Doctor.Plugins.Security` | Security | 9 checks (OIDC, TLS, Vault) |
| **Integration** | `StellaOps.Doctor.Plugins.Integration` | Integration | 8+ checks (GitHub, GitLab, registries) |
| **Observability** | `StellaOps.Doctor.Plugins.Observability` | Observability | 4 checks (OTLP, metrics) |
| **Cryptography** | `StellaOps.Doctor.Plugins.Cryptography` | Cryptography | 8+ checks (FIPS, eIDAS, HSM) |
| **Docker** | `StellaOps.Doctor.Plugins.Docker` | Docker | 5 checks (daemon, network) |
| **AI** | `StellaOps.Doctor.Plugins.AI` | AI | 4+ checks (LLM providers) |
| **Notify** | `StellaOps.Doctor.Plugin.Notify` | Notify | 5 checks (email, Slack, webhooks) |
### 2.3 Doctor Web Service
| Component | Path |
|-----------|------|
| **Web Service** | `src/Doctor/StellaOps.Doctor.WebService/` |
| **Endpoints** | `src/Doctor/StellaOps.Doctor.WebService/Endpoints/DoctorEndpoints.cs` |
| **Angular UI** | `src/Web/StellaOps.Web/src/app/features/doctor/` |
**REST API:**
- `POST /api/v1/doctor/run` - Start diagnostic run
- `GET /api/v1/doctor/run/{runId}` - Get run results
- `GET /api/v1/doctor/checks` - List available checks
- `WebSocket /api/v1/doctor/stream` - Real-time streaming
### 2.4 Check ID Convention
```
check.{category}.{subcategory}.{specific}
```
Examples:
- `check.config.required`
- `check.database.migrations.pending`
- `check.integration.scm.github.auth`
- `check.services.valkey.connectivity`
---
## 3. Database & Migrations
### 3.1 Migration Framework
| Component | Path |
|-----------|------|
| **Runner** | `src/__Libraries/StellaOps.Infrastructure.Postgres/Migrations/MigrationRunner.cs` |
| **Startup Host** | `src/__Libraries/StellaOps.Infrastructure.Postgres/Migrations/StartupMigrationHost.cs` |
| **Categories** | `src/__Libraries/StellaOps.Infrastructure.Postgres/Migrations/MigrationCategory.cs` |
| **CLI Service** | `src/Cli/StellaOps.Cli/Services/MigrationCommandService.cs` |
### 3.2 Migration Categories
| Category | Prefix | Execution | Purpose |
|----------|--------|-----------|---------|
| **Startup** | 001-099 | Automatic at boot | Schema creation (idempotent) |
| **Release** | 100-199 | Manual CLI | Breaking changes (blocks boot if pending) |
| **Seed** | S001-S999 | Automatic at boot | Initial data (idempotent) |
| **Data** | DM001-DM999 | Background jobs | Data migrations |
### 3.3 Schema Isolation (Per-Module)
| Module | Schema | Migration Path |
|--------|--------|----------------|
| Authority | `authority` | `src/Authority/__Libraries/StellaOps.Authority.Persistence/Migrations/` |
| Concelier | `vuln` | `src/Concelier/__Libraries/StellaOps.Concelier.Persistence/Migrations/` |
| Scheduler | `scheduler` | `src/Scheduler/__Libraries/StellaOps.Scheduler.Persistence/Migrations/` |
| Notify | `notify` | `src/Notify/__Libraries/StellaOps.Notify.Persistence/Migrations/` |
| Scanner | `scanner` | `src/Scanner/__Libraries/StellaOps.Scanner.Storage/Postgres/Migrations/` |
| Attestor | `attestor` | `src/Attestor/__Libraries/StellaOps.Attestor.Persistence/Migrations/` |
| Policy | `policy` | `src/Policy/__Libraries/StellaOps.Policy.Persistence/Migrations/` |
| ReleaseOrchestrator | `release` | `src/ReleaseOrchestrator/__Libraries/.../Persistence/Migrations/` |
### 3.4 Existing CLI Commands
```bash
stella migrations-run --module <Module> --category <Category> [--dry-run] [--force]
```
---
## 4. Redis/Valkey Infrastructure
### 4.1 Connection Configuration
| Component | Path |
|-----------|------|
| **Primary Factory** | `src/Router/__Libraries/StellaOps.Messaging.Transport.Valkey/ValkeyConnectionFactory.cs` |
| **Options** | `src/Router/__Libraries/StellaOps.Messaging.Transport.Valkey/Options/ValkeyTransportOptions.cs` |
| **Transport Plugin** | `src/Router/__Libraries/StellaOps.Messaging.Transport.Valkey/ValkeyTransportPlugin.cs` |
### 4.2 Usage Patterns
| Usage | Component | Purpose |
|-------|-----------|---------|
| **Message Queues** | `ValkeyMessageQueue` | Redis Streams with consumer groups |
| **Distributed Cache** | `ValkeyCacheStore` | TTL-based caching |
| **Rate Limiting** | `ValkeyRateLimitStore` | Token bucket algorithm |
| **Idempotency** | `ValkeyIdempotencyStore` | Duplicate prevention |
| **DPoP Nonces** | `RedisDpopNonceStore` | Auth token security |
### 4.3 Health Checks
**File:** `src/__Libraries/StellaOps.Doctor.Plugins.ServiceGraph/Checks/ValkeyConnectivityCheck.cs`
Configuration sources checked:
- `Valkey:ConnectionString`
- `Redis:ConnectionString`
- `ConnectionStrings:Valkey`
- `ConnectionStrings:Redis`
---
## 5. Integrations System
### 5.1 Core Architecture
| Component | Path |
|-----------|------|
| **Web Service** | `src/Integrations/StellaOps.Integrations.WebService/` |
| **Core Models** | `src/Integrations/__Libraries/StellaOps.Integrations.Core/` |
| **Contracts** | `src/Integrations/__Libraries/StellaOps.Integrations.Contracts/` |
| **Persistence** | `src/Integrations/__Libraries/StellaOps.Integrations.Persistence/` |
### 5.2 Integration Types
**File:** `src/Integrations/__Libraries/StellaOps.Integrations.Core/IntegrationEnums.cs`
| Type | Range | Examples |
|------|-------|----------|
| **Registry** | 100-109 | Harbor, ECR, GCR, ACR, Docker Hub, Quay |
| **SCM** | 200-204 | GitHub App, GitLab Server, Bitbucket, Gitea |
| **CI/CD** | 300-306 | GitHub Actions, GitLab CI, Jenkins, Argo |
| **RepoSource** | 400-405 | npm, PyPI, Maven, NuGet, Crates.io |
| **RuntimeHost** | 500-502 | eBPF Agent, ETW Agent |
| **FeedMirror** | 600-602 | StellaOps Mirror, NVD, OSV |
### 5.3 Plugin Contract
**File:** `src/Integrations/__Libraries/StellaOps.Integrations.Contracts/IIntegrationConnectorPlugin.cs`
```csharp
public interface IIntegrationConnectorPlugin : IAvailabilityPlugin
{
IntegrationType Type { get; }
IntegrationProvider Provider { get; }
Task<TestConnectionResult> TestConnectionAsync(IntegrationConfig config, CancellationToken ct);
Task<HealthCheckResult> CheckHealthAsync(IntegrationConfig config, CancellationToken ct);
}
```
### 5.4 Existing Plugins
| Plugin | Path |
|--------|------|
| **GitHub App** | `src/Integrations/__Plugins/StellaOps.Integrations.Plugin.GitHubApp/` |
| **Harbor** | `src/Integrations/__Plugins/StellaOps.Integrations.Plugin.Harbor/` |
| **InMemory** | `src/Integrations/__Plugins/StellaOps.Integrations.Plugin.InMemory/` |
---
## 6. Notification System
### 6.1 Core Components
| Component | Path |
|-----------|------|
| **Web Service** | `src/Notify/StellaOps.Notify.WebService/` |
| **Engine** | `src/Notify/__Libraries/StellaOps.Notify.Engine/` |
| **Models** | `src/Notify/__Libraries/StellaOps.Notify.Models/` |
| **Queue** | `src/Notify/__Libraries/StellaOps.Notify.Queue/` |
### 6.2 Channel Types
**File:** `src/Notify/__Libraries/StellaOps.Notify.Models/NotifyChannel.cs`
- **Slack** - Incoming webhooks
- **Teams** - Incoming webhooks
- **Email** - SMTP
- **Webhook** - Generic HTTP POST
- **PagerDuty** / **OpsGenie** - Incident management
- **InApp** - In-application inbox
### 6.3 Channel Configuration
```csharp
public sealed record NotifyChannelConfig
{
public string SecretRef { get; } // authref:// URI
public string? Target { get; } // Channel/email list
public string? Endpoint { get; } // Webhook URL
public ImmutableDictionary<string, string> Properties { get; }
}
```
---
## 7. Vault/Secrets System
### 7.1 Vault Connectors
| Connector | Path |
|-----------|------|
| **HashiCorp Vault** | `src/ReleaseOrchestrator/__Libraries/.../Connectors/Vault/HashiCorpVaultConnector.cs` |
| **Azure Key Vault** | `src/ReleaseOrchestrator/__Libraries/.../Connectors/Vault/AzureKeyVaultConnector.cs` |
| **AWS Secrets Manager** | `src/ReleaseOrchestrator/__Libraries/.../Connectors/Vault/AwsSecretsManagerConnector.cs` |
### 7.2 Secret Resolution
**File:** `src/ReleaseOrchestrator/__Libraries/.../Plugin/Integration/ITenantSecretResolver.cs`
```csharp
public interface ITenantSecretResolver : ISecretResolver
{
ITenantSecretResolver ForTenant(Guid tenantId);
Task<string?> ResolveFromVaultAsync(Guid integrationId, string secretPath, CancellationToken ct);
}
```
### 7.3 Credential Provider Schemes
**File:** `src/ReleaseOrchestrator/__Agents/StellaOps.Agent.Core/Credentials/CredentialResolver.cs`
- `env://VAR_NAME` - Environment variable
- `file:///path/to/secret` - File system
- `vault://integration-id/path` - Vault lookup
---
## 8. Environment & Agent System
### 8.1 Environment Model
**File:** `src/ReleaseOrchestrator/__Libraries/StellaOps.ReleaseOrchestrator.Environment/Models/Environment.cs`
```csharp
public sealed record Environment
{
public Guid Id { get; init; }
public Guid TenantId { get; init; }
public string Name { get; set; } // "dev", "staging", "prod"
public string DisplayName { get; set; }
public int OrderIndex { get; init; } // Pipeline order
public bool IsProduction { get; init; }
public int RequiredApprovals { get; set; }
public bool RequireSeparationOfDuties { get; set; }
public Guid? AutoPromoteFrom { get; set; }
}
```
### 8.2 Target Model (Deployment Target)
**File:** `src/ReleaseOrchestrator/__Libraries/.../Environment/Models/Target.cs`
| Target Type | Description |
|-------------|-------------|
| **DockerHost** | Docker Engine |
| **ComposeHost** | Docker Compose project |
| **EcsService** | AWS ECS service |
| **NomadJob** | HashiCorp Nomad job |
### 8.3 Agent Model
**File:** `src/ReleaseOrchestrator/__Libraries/StellaOps.ReleaseOrchestrator.Agent/Models/Agent.cs`
```csharp
public sealed record Agent
{
public Guid Id { get; init; }
public string Name { get; init; }
public AgentStatus Status { get; set; } // Pending, Active, Inactive, Stale, Revoked
public AgentCapability[] Capabilities { get; init; } // Docker, Compose, Ssh, WinRm
public string? CertificateThumbprint { get; set; } // mTLS
public DateTimeOffset? LastHeartbeatAt { get; set; }
}
```
### 8.4 Agent Registration
**File:** `src/ReleaseOrchestrator/__Libraries/.../Agent/Registration/RegistrationTokenService.cs`
- One-time tokens with 24-hour expiry
- mTLS certificate issuance on registration
- Heartbeat monitoring (30-second intervals, 90-second stale timeout)
---
## 9. Existing Onboarding System
### 9.1 Platform Onboarding Service
**File:** `src/Platform/StellaOps.Platform.WebService/Services/PlatformOnboardingService.cs`
**Default Steps:**
1. `connect-scanner`
2. `configure-policy`
3. `first-scan`
4. `review-findings`
5. `invite-team`
**Endpoints:**
- `GET /api/v1/platform/onboarding/status`
- `POST /api/v1/platform/onboarding/complete/{step}`
- `POST /api/v1/platform/onboarding/skip`
### 9.2 Quickstart Documentation
| Document | Path |
|----------|------|
| **Quickstart** | `docs/quickstart.md` |
| **CLI Quickstart** | `docs/CONCELIER_CLI_QUICKSTART.md` |
| **Install Guide** | `docs/INSTALL_GUIDE.md` |
| **Developer Onboarding** | `docs/DEVELOPER_ONBOARDING.md` |
---
## 10. UI Architecture
### 10.1 Angular Application
| Component | Path |
|-----------|------|
| **Root** | `src/Web/StellaOps.Web/src/app/app.component.ts` |
| **Routes** | `src/Web/StellaOps.Web/src/app/app.routes.ts` |
| **Config** | `src/Web/StellaOps.Web/src/app/app.config.ts` |
### 10.2 Existing Settings Pages
| Page | Path |
|------|------|
| **AI Preferences** | `src/Web/StellaOps.Web/src/app/features/settings/ai-preferences.component.ts` |
| **Environment Settings** | `src/Web/StellaOps.Web/src/app/features/release-orchestrator/environments/components/environment-settings/` |
| **Trivy DB Settings** | `src/Web/StellaOps.Web/src/app/features/trivy-db-settings/` |
### 10.3 Wizard Reference Implementation
**SBOM Source Wizard** (6-step multi-form wizard):
**File:** `src/Web/StellaOps.Web/src/app/features/sbom-sources/components/source-wizard/source-wizard.component.ts`
Features:
- Signal-based state management
- Step-by-step validation
- Connection testing
- Multi-form with conditional rendering
- TypeScript 1204 lines
---
## 11. Configuration Samples
| Sample | Path |
|--------|------|
| **Concelier** | `etc/concelier.yaml.sample` |
| **Authority** | `etc/authority.yaml.sample` |
| **Docker Compose** | `devops/compose/dev.env.example` |
| **Air-gap** | `devops/compose/airgap.env.example` |
---
## 12. Gaps Identified
### 12.1 Missing Components
| Gap | Description |
|-----|-------------|
| **`stella setup` command** | No dedicated interactive setup command exists |
| **First-run detection** | No blocking wizard on first launch |
| **Wizard UI entry** | No configuration wizard in Angular UI |
| **Admin bootstrap** | Admin creation via env vars only, not interactive |
| **Integration wizard** | No guided multi-connector setup |
### 12.2 Partial Implementations
| Component | Current State | Gap |
|-----------|---------------|-----|
| **Onboarding Service** | In-memory, 5-step user flow | No infrastructure setup steps |
| **Doctor checks** | 48+ checks exist | No wizard integration for fix commands |
| **Migrations** | Automatic at startup | No interactive verification step |
| **Integrations** | Plugin architecture exists | No default suggestion logic |
---
## 13. Key Architectural Patterns to Follow
1. **System.CommandLine** for CLI commands
2. **Signal-based state** in Angular components
3. **IOptions<T> with validation** for configuration
4. **Plugin contracts** for extensibility
5. **Doctor checks** for health validation
6. **ITenantSecretResolver** for secret access
7. **HLC timestamps** for audit ordering

View File

@@ -0,0 +1,811 @@
# Setup Wizard - Sprint Plan
This document defines the implementation plan for the Stella Ops Setup Wizard feature.
## 1. Epic Overview
| Epic ID | Name | Description | Priority |
|---------|------|-------------|----------|
| **E1** | Doctor Remediation Engine | Extend Doctor to generate runtime-specific fix commands | P0 |
| **E2** | CLI Setup Command | Implement `stella setup` interactive command | P0 |
| **E3** | UI Setup Wizard | Angular wizard component with first-run blocking | P1 |
| **E4** | Integration Connectors | Multi-connector support with default suggestions | P1 |
| **E5** | Configuration Pane | Post-setup reconfiguration UI | P2 |
---
## 2. Sprint Sequence
### Sprint 1: Foundation (E1)
**Focus:** Doctor remediation engine and runtime detection
### Sprint 2: CLI Core (E2)
**Focus:** CLI setup command with infrastructure steps
### Sprint 3: CLI Integrations (E2, E4)
**Focus:** CLI integration steps and multi-connector support
### Sprint 4: UI Wizard (E3)
**Focus:** Angular wizard component and first-run blocking
### Sprint 5: UI Integrations (E3, E4)
**Focus:** UI integration steps with connector management
### Sprint 6: Polish (E5)
**Focus:** Configuration pane and documentation
---
## 3. Epic 1: Doctor Remediation Engine
### 3.1 Features
| Feature | Description |
|---------|-------------|
| F1.1 | Runtime environment detection |
| F1.2 | Remediation command templates |
| F1.3 | Placeholder resolution system |
| F1.4 | Verification command execution |
| F1.5 | Secret redaction |
### 3.2 User Stories
#### F1.1 Runtime Detection
**US-1.1.1: Detect Docker Compose environment**
```
As a setup wizard
I need to detect Docker Compose environments
So that I can suggest Docker Compose-specific fix commands
Acceptance Criteria:
- Detect presence of docker compose command
- Detect docker-compose.yml in standard locations
- Detect COMPOSE_PROJECT_NAME environment variable
- Return DockerCompose runtime type
Files to modify:
- src/__Libraries/StellaOps.Doctor/Detection/RuntimeDetector.cs (new)
- src/__Libraries/StellaOps.Doctor/Detection/IRuntimeDetector.cs (new)
```
**US-1.1.2: Detect Kubernetes context**
```
As a setup wizard
I need to detect Kubernetes environments
So that I can suggest kubectl-based fix commands
Acceptance Criteria:
- Detect KUBERNETES_SERVICE_HOST environment variable
- Detect kubeconfig file presence
- Extract current namespace from context
- Return Kubernetes runtime type
```
**US-1.1.3: Detect systemd-managed services**
```
As a setup wizard
I need to detect systemd-managed PostgreSQL/Valkey
So that I can suggest systemctl commands
Acceptance Criteria:
- Detect systemctl command availability
- Check if postgresql.service exists
- Check if valkey.service or redis.service exists
- Return Systemd runtime type
```
#### F1.2 Remediation Templates
**US-1.2.1: Define remediation command model**
```
As a setup wizard
I need a data model for remediation commands
So that checks can return actionable fixes
Acceptance Criteria:
- RemediationCommand record with runtime, command, description
- Support for placeholders in commands
- Support for sudo flag
- Support for dangerous flag
Files to modify:
- src/__Libraries/StellaOps.Doctor/Models/RemediationCommand.cs (new)
- src/__Libraries/StellaOps.Doctor/Models/CheckResult.cs (extend)
```
**US-1.2.2: Implement database connectivity remediations**
```
As a user with database connection failure
I need runtime-specific fix commands
So that I can quickly resolve the issue
Acceptance Criteria:
- Docker Compose: docker compose up -d postgres
- Kubernetes: kubectl get pods -l app=postgres
- Systemd: sudo systemctl start postgresql
- Bare: pg_isready verification command
```
**US-1.2.3: Implement Valkey connectivity remediations**
```
As a user with Valkey connection failure
I need runtime-specific fix commands
So that I can quickly resolve the issue
Acceptance Criteria:
- Docker Compose: docker compose up -d valkey
- Kubernetes: kubectl get pods -l app=valkey
- Systemd: sudo systemctl start valkey
- Bare: redis-cli PING verification
```
#### F1.3 Placeholder Resolution
**US-1.3.1: Implement placeholder resolver**
```
As a setup wizard
I need to resolve placeholders in commands
So that users see contextual values
Acceptance Criteria:
- Resolve {{HOST}}, {{PORT}} from user input
- Resolve {{NAMESPACE}} from Kubernetes context
- Resolve {{COMPOSE_FILE}} from detection
- Support default values with {{VAR:-default}} syntax
Files to modify:
- src/__Libraries/StellaOps.Doctor/Remediation/PlaceholderResolver.cs (new)
```
#### F1.4 Verification Execution
**US-1.4.1: Execute verification commands**
```
As a setup wizard
I need to run verification commands
So that I can confirm fixes were applied
Acceptance Criteria:
- Execute shell command with timeout
- Capture exit code and output
- Return success/failure result
- Handle command not found gracefully
```
#### F1.5 Secret Redaction
**US-1.5.1: Redact secrets in displayed commands**
```
As a setup wizard
I must never display actual secret values
So that secrets are not exposed in logs or UI
Acceptance Criteria:
- PASSWORD, TOKEN, SECRET_KEY placeholders never resolved for display
- Display shows placeholder syntax
- Copy-to-clipboard preserves placeholders
- Log output redacts secrets
```
---
## 4. Epic 2: CLI Setup Command
### 4.1 Features
| Feature | Description |
|---------|-------------|
| F2.1 | Command registration and structure |
| F2.2 | Interactive prompts for each step |
| F2.3 | Non-interactive mode with config file |
| F2.4 | Resume and reconfigure support |
| F2.5 | Step validation with Doctor checks |
### 4.2 User Stories
#### F2.1 Command Registration
**US-2.1.1: Register stella setup command**
```
As a CLI user
I need a stella setup command
So that I can configure Stella Ops interactively
Acceptance Criteria:
- Command registered in CommandFactory
- Global options: --config, --non-interactive, --resume, --reconfigure
- Step selection options: --step, --skip
- Help text describes all options
Files to modify:
- src/Cli/StellaOps.Cli/Commands/Setup/SetupCommandGroup.cs (new)
- src/Cli/StellaOps.Cli/Commands/CommandFactory.cs
```
**US-2.1.2: Implement setup command handler**
```
As a CLI user
I need the setup command to orchestrate all steps
So that I can complete configuration end-to-end
Acceptance Criteria:
- Detect first-run vs reconfigure mode
- Load existing configuration if present
- Execute steps in sequence
- Save progress after each step
Files to modify:
- src/Cli/StellaOps.Cli/Commands/Setup/SetupCommandHandler.cs (new)
```
#### F2.2 Interactive Prompts
**US-2.2.1: Implement database setup prompts**
```
As a CLI user
I need interactive prompts for database configuration
So that I can enter connection details
Acceptance Criteria:
- Prompt for host, port, database, username, password
- Password input masked
- Default values shown in brackets
- Input validation before proceeding
```
**US-2.2.2: Implement Valkey setup prompts**
```
As a CLI user
I need interactive prompts for Valkey configuration
So that I can enter connection details
Acceptance Criteria:
- Prompt for host, port, password (optional)
- TLS toggle option
- Database index selection
```
**US-2.2.3: Implement admin bootstrap prompts**
```
As a CLI user
I need prompts to create admin user
So that I can access the system after setup
Acceptance Criteria:
- Prompt for username, email, password
- Password confirmation
- Password complexity validation
- Display created user info
```
**US-2.2.4: Implement vault integration prompts**
```
As a CLI user
I need prompts to configure vault integration
So that I can set up secrets management
Acceptance Criteria:
- Show detected vault (if any)
- Prompt for vault type selection
- Type-specific prompts (token, AppRole, etc.)
- Test connection before saving
```
**US-2.2.5: Implement SCM integration prompts**
```
As a CLI user
I need prompts to configure SCM integration
So that I can connect source control
Acceptance Criteria:
- Provider selection (GitHub, GitLab, etc.)
- Provider-specific prompts
- Support for adding multiple providers
- Test connection before saving
```
#### F2.3 Non-Interactive Mode
**US-2.3.1: Parse YAML configuration file**
```
As a DevOps engineer
I need to provide configuration via YAML file
So that I can automate setup in CI/CD
Acceptance Criteria:
- Parse setup.yaml with all step configurations
- Support environment variable substitution
- Validate required fields present
- Fail on missing required values
Files to modify:
- src/Cli/StellaOps.Cli/Commands/Setup/SetupConfigParser.cs (new)
```
**US-2.3.2: Execute non-interactive setup**
```
As a DevOps engineer
I need non-interactive mode to fail on missing input
So that automated setups don't hang
Acceptance Criteria:
- --non-interactive flag enables mode
- Exit with error if required input missing
- Progress output shows step completion
- Final status summary
```
#### F2.4 Resume Support
**US-2.4.1: Save setup progress**
```
As a CLI user
I need my progress saved automatically
So that I can resume if interrupted
Acceptance Criteria:
- Save completed steps to ~/.stellaops/setup-state.json
- Save step-specific configuration
- Track skipped steps with reasons
- Save timestamp of last update
Files to modify:
- src/Cli/StellaOps.Cli/Commands/Setup/SetupStateStore.cs (new)
```
**US-2.4.2: Resume interrupted setup**
```
As a CLI user
I need to resume from where I left off
So that I don't repeat completed steps
Acceptance Criteria:
- --resume flag loads previous state
- Show completed steps as already done
- Start from first incomplete step
- Allow going back to previous steps
```
#### F2.5 Step Validation
**US-2.5.1: Run Doctor checks after each step**
```
As a CLI user
I need validation after configuration
So that I know if setup succeeded
Acceptance Criteria:
- Run step-specific Doctor checks
- Display pass/warn/fail for each check
- On failure, show remediations
- Block progression on critical failures
```
**US-2.5.2: Display remediation commands**
```
As a CLI user
I need to see fix commands when checks fail
So that I can resolve issues
Acceptance Criteria:
- Display likely causes numbered by priority
- Show runtime-specific commands
- Include copy-pasteable command text
- Prompt for retry after fix
```
---
## 5. Epic 3: UI Setup Wizard
### 5.1 Features
| Feature | Description |
|---------|-------------|
| F3.1 | First-run detection and blocking |
| F3.2 | Wizard component with stepper |
| F3.3 | Step form components |
| F3.4 | Connection testing UI |
| F3.5 | Doctor check results panel |
| F3.6 | Remediation display with copy |
### 5.2 User Stories
#### F3.1 First-Run Blocking
**US-3.1.1: Detect first-run state**
```
As the UI application
I need to detect if setup is incomplete
So that I can redirect to the wizard
Acceptance Criteria:
- Call backend setup status endpoint
- Check for Operational threshold met
- Store state in session
Files to modify:
- src/Web/StellaOps.Web/src/app/core/services/setup-status.service.ts (new)
```
**US-3.1.2: Implement first-run route guard**
```
As the UI application
I need to block access to main app until setup complete
So that users configure before using
Acceptance Criteria:
- CanActivate guard on main routes
- Redirect to /setup if not Operational
- Allow /setup route always
- Clear guard after setup complete
```
#### F3.2 Wizard Component
**US-3.2.1: Create wizard container component**
```
As a UI user
I need a wizard interface
So that I can complete setup step by step
Acceptance Criteria:
- Stepper showing all steps
- Current step highlighted
- Completed steps show checkmark
- Skipped steps show dash
- Click to navigate (completed steps only)
Files to modify:
- src/Web/StellaOps.Web/src/app/features/setup-wizard/setup-wizard.component.ts (new)
- src/Web/StellaOps.Web/src/app/features/setup-wizard/setup-wizard.routes.ts (new)
```
**US-3.2.2: Implement step navigation**
```
As a UI user
I need navigation controls
So that I can move between steps
Acceptance Criteria:
- Continue button proceeds to next step
- Skip button (optional steps) moves forward
- Back button returns to previous step
- Keyboard navigation support
```
#### F3.3 Step Forms
**US-3.3.1: Database setup form component**
```
As a UI user
I need a form to configure database connection
So that I can set up PostgreSQL
Acceptance Criteria:
- Form fields for host, port, database, username, password
- SSL mode dropdown
- Password field with show/hide toggle
- Field validation
- Test Connection button
Files to modify:
- src/Web/StellaOps.Web/src/app/features/setup-wizard/steps/database-step.component.ts (new)
```
**US-3.3.2: Valkey setup form component**
```
As a UI user
I need a form to configure Valkey connection
So that I can set up caching and queues
Acceptance Criteria:
- Form fields for host, port, password
- TLS toggle
- Database index selector
- Test Connection button
```
**US-3.3.3: Admin bootstrap form component**
```
As a UI user
I need a form to create admin account
So that I can access the system
Acceptance Criteria:
- Form fields for username, email, password, confirm password
- Password strength indicator
- Validation messages
```
**US-3.3.4: Vault integration form component**
```
As a UI user
I need a form to configure vault
So that I can set up secrets management
Acceptance Criteria:
- Provider type selector (cards)
- Dynamic form based on provider
- Add another provider button
- List of configured providers
```
**US-3.3.5: SCM integration form component**
```
As a UI user
I need a form to configure SCM
So that I can connect source control
Acceptance Criteria:
- Provider type selector
- Dynamic form based on provider
- Multiple providers support
- Test connection for each
```
#### F3.4 Connection Testing
**US-3.4.1: Connection test component**
```
As a UI user
I need visual feedback during connection tests
So that I know the status
Acceptance Criteria:
- Loading spinner during test
- Progress steps shown
- Success state with details
- Failure state with error message
```
#### F3.5 Doctor Results Panel
**US-3.5.1: Check results display**
```
As a UI user
I need to see validation results
So that I know if configuration is correct
Acceptance Criteria:
- List of checks with pass/warn/fail icons
- Expandable details per check
- Evidence data shown
- Filter by status
```
#### F3.6 Remediation Display
**US-3.6.1: Remediation command display**
```
As a UI user
I need to see fix commands when checks fail
So that I can resolve issues
Acceptance Criteria:
- Likely causes listed
- Commands in code blocks
- Copy button per command
- Runtime-specific tabs
- Retry button after applying fix
```
---
## 6. Epic 4: Integration Connectors
### 6.1 Features
| Feature | Description |
|---------|-------------|
| F4.1 | Default connector detection |
| F4.2 | Multi-connector management |
| F4.3 | Connector preference persistence |
### 6.2 User Stories
**US-4.1.1: Detect default vault provider**
```
As a setup wizard
I need to detect the most likely vault provider
So that I can suggest it to the user
Acceptance Criteria:
- Check VAULT_ADDR environment variable
- Check Azure IMDS endpoint
- Check AWS metadata endpoint
- Return detected provider or null
```
**US-4.2.1: Support multiple vault integrations**
```
As a user
I need to configure multiple vault providers
So that I can use different vaults for different purposes
Acceptance Criteria:
- Add up to 5 vault integrations
- Each has unique name
- List shows all configured
- Edit/remove individual integrations
```
**US-4.3.1: Persist connector preferences**
```
As a user
I need my last selected connector saved
So that reconfiguration shows my preferences
Acceptance Criteria:
- Save last used connector per category
- Load preferences on reconfigure
- Pre-select last used connector
```
---
## 7. Epic 5: Configuration Pane
### 7.1 Features
| Feature | Description |
|---------|-------------|
| F5.1 | Configuration pane route and component |
| F5.2 | Health status display |
| F5.3 | Reconfigure individual steps |
### 7.2 User Stories
**US-5.1.1: Configuration pane component**
```
As a user
I need a configuration pane in settings
So that I can reconfigure after initial setup
Acceptance Criteria:
- Route: /settings/configuration
- Menu entry in Settings
- Show all configuration categories
- Last configured timestamp
```
**US-5.2.1: Display current health status**
```
As a user
I need to see health status per configuration
So that I know if anything needs attention
Acceptance Criteria:
- Health badge per category (Healthy, Degraded, Unhealthy)
- Click to see Doctor check details
- Refresh button to re-run checks
```
**US-5.3.1: Reconfigure individual step**
```
As a user
I need to reconfigure a specific step
So that I can update settings without full wizard
Acceptance Criteria:
- Manage button per category
- Opens step form pre-populated
- Test and save functionality
- Run Doctor checks after save
```
---
## 8. Technical Spikes
| Spike | Question | Output |
|-------|----------|--------|
| **TS-1** | How should setup state be persisted across CLI sessions? | Design doc for state storage |
| **TS-2** | How to share validation logic between CLI and UI? | Shared library design |
| **TS-3** | How to handle long-running migrations in wizard? | Progress reporting design |
| **TS-4** | How to test runtime detection across platforms? | Test strategy doc |
---
## 9. Definition of Done
### 9.1 Code Quality
- [ ] All new code has unit tests (>80% coverage)
- [ ] Integration tests for Doctor check integration
- [ ] E2E tests for CLI interactive flow (Playwright)
- [ ] E2E tests for UI wizard (Playwright)
- [ ] No new compiler warnings
- [ ] Code reviewed and approved
### 9.2 Documentation
- [ ] CLI help text complete and accurate
- [ ] Quickstart guide updated with wizard
- [ ] API documentation for new endpoints
- [ ] Architecture doc updated
### 9.3 Accessibility
- [ ] UI meets WCAG 2.1 AA
- [ ] Keyboard navigation works
- [ ] Screen reader tested
### 9.4 Feature Flags
- [ ] Wizard behind feature flag initially
- [ ] Flag documented in operations guide
- [ ] Rollout plan defined
---
## 10. Test Strategy
### 10.1 Unit Tests
| Component | Test Focus |
|-----------|------------|
| RuntimeDetector | Mock file system and environment |
| PlaceholderResolver | Various placeholder patterns |
| SetupStateStore | State persistence and loading |
| SetupConfigParser | YAML parsing and validation |
### 10.2 Integration Tests
| Scenario | Setup |
|----------|-------|
| Database check flow | Testcontainers PostgreSQL |
| Valkey check flow | Testcontainers Valkey |
| Migration execution | In-memory database |
| Vault integration | Mock vault server |
### 10.3 E2E Tests
| Flow | Tool |
|------|------|
| CLI interactive setup | Bash script with expect |
| CLI non-interactive | YAML config files |
| UI wizard complete | Playwright |
| UI first-run blocking | Playwright |
---
## 11. Rollout Strategy
### Phase 1: Internal Testing
- Feature flag enabled for dev team
- Dogfooding in internal environments
- Bug fixes and polish
### Phase 2: Beta
- Feature flag enabled for opt-in users
- Documentation available
- Feedback collection
### Phase 3: General Availability
- Feature flag removed
- Default wizard enabled
- Migration guide for existing installations
---
## 12. Dependencies
| Dependency | Status | Owner |
|------------|--------|-------|
| Doctor Plugin API stable | Done | Platform team |
| Authority admin bootstrap API | In progress | Auth team |
| Integration connectors API | Done | Integration team |
| Notify channel test endpoint | Needed | Notify team |
---
## 13. Risks and Mitigations
| Risk | Likelihood | Impact | Mitigation |
|------|------------|--------|------------|
| Runtime detection unreliable | Medium | High | Fallback to "Bare" with manual commands |
| Long migration blocking UI | Medium | Medium | Background job with progress |
| Secret handling complexity | Low | High | Strict redaction policy, security review |
| Cross-platform CLI issues | Medium | Medium | CI matrix testing on all platforms |

View File

@@ -0,0 +1,693 @@
# Setup Wizard - UX Flow Specification
This document defines the user experience flows for both CLI and UI implementations of the Setup Wizard, ensuring feature parity across surfaces.
## 1. Design Principles
### 1.1 Core UX Goals
1. **Self-serve clarity** - Users should complete setup without reading external documentation
2. **Progressive disclosure** - Show only relevant options at each step
3. **Fail-forward** - Guide users through errors with actionable fixes
4. **Parity** - CLI and UI offer identical capabilities
5. **Resume-friendly** - Support interruption and resumption
### 1.2 Terminology
| Term | Definition |
|------|------------|
| **Step** | A discrete configuration unit (e.g., "Database Setup") |
| **Check** | A Doctor diagnostic that validates a step |
| **Fix** | A remediation command generated by Doctor |
| **Connector** | A specific integration provider (e.g., "HashiCorp Vault") |
---
## 2. CLI Flow
### 2.1 Command Structure
```bash
# Interactive setup (default)
stella setup
# Non-interactive with config file
stella setup --config setup.yaml
# Reconfigure existing installation
stella setup --reconfigure
# Resume interrupted setup
stella setup --resume
# Specific step only
stella setup --step database
# Skip optional steps
stella setup --skip vault,scm
```
### 2.2 Global Options
| Option | Type | Description |
|--------|------|-------------|
| `--config` | path | YAML configuration file |
| `--non-interactive` | flag | Fail on missing required input |
| `--reconfigure` | flag | Re-run on existing installation |
| `--resume` | flag | Continue from last incomplete step |
| `--step <id>` | string | Run specific step only |
| `--skip <ids>` | string | Comma-separated steps to skip |
| `--verbose` | flag | Show detailed progress |
| `--output <format>` | enum | `text`, `json`, `yaml` |
### 2.3 Interactive Flow
```
$ stella setup
____ _ _ _ ___
/ ___|| |_ ___| | | __ _ / _ \ _ __ ___
\___ \| __/ _ \ | |/ _` | | | | '_ \/ __|
___) | || __/ | | (_| | |_| | |_) \__ \
|____/ \__\___|_|_|\__,_|\___/| .__/|___/
|_|
Setup Wizard v2026.01
This wizard will guide you through the initial configuration.
Press Ctrl+C at any time to exit. Progress is saved automatically.
Detected environment:
- Platform: linux-x64
- Docker: available
- PostgreSQL: not detected
- Valkey: not detected
[1/10] Database Setup
----------------------
? PostgreSQL host: localhost
? PostgreSQL port: [5432]
? Database name: [stellaops]
? Username: stellaops_admin
? Password: ********
Testing connection...
[OK] Connected to PostgreSQL 16.2
[OK] User has CREATE SCHEMA permission
[OK] Database 'stellaops' accessible
Running Doctor checks...
[PASS] check.database.connectivity
[PASS] check.database.permissions
[PASS] check.database.version
Database setup complete.
[2/10] Valkey/Redis Setup
-------------------------
...
```
### 2.4 Error Handling Flow
```
Testing connection...
[FAIL] Could not connect to PostgreSQL
Likely causes:
1. PostgreSQL is not running
2. Firewall blocking port 5432
3. Incorrect host/port
Suggested fixes:
# If using Docker Compose:
docker compose -f devops/compose/docker-compose.yml up -d postgres
# If using systemd:
sudo systemctl start postgresql
sudo systemctl enable postgresql
# Verify connectivity:
pg_isready -h localhost -p 5432
? Retry connection? [Y/n]
```
### 2.5 Multi-Connector Flow
```
[6/10] Vault Integration (Optional)
-----------------------------------
? Configure a secrets provider? [Y/n] Y
Detected: VAULT_ADDR=https://vault.example.com:8200
? Use detected HashiCorp Vault? [Y/n] Y
? Vault address: [https://vault.example.com:8200]
? Authentication method:
> Token
AppRole
Kubernetes
? Vault token: ********
Testing connection...
[OK] Vault connected (version 1.15.0)
[OK] KV v2 mount 'secret' accessible
? Add another secrets provider? [y/N] y
? Select provider:
HashiCorp Vault
> Azure Key Vault
AWS Secrets Manager
File Provider
...
```
### 2.6 Skip Flow
```
[7/10] SCM Integration (Optional)
---------------------------------
? Configure source control integration? [Y/n] n
Skipping SCM integration.
Note: You can configure this later via 'stella setup --step scm'
Skipped steps can be completed from:
- CLI: stella setup --reconfigure
- UI: Settings > Configuration Wizard
```
### 2.7 Non-Interactive Mode
```yaml
# setup.yaml
database:
host: postgres.example.com
port: 5432
database: stellaops
username: stellaops_admin
password: ${POSTGRES_PASSWORD} # Environment variable
valkey:
host: valkey.example.com
port: 6379
password: ${VALKEY_PASSWORD}
vault:
- type: hashicorp
address: https://vault.example.com:8200
authMethod: kubernetes
role: stellaops
scm:
- type: github-app
appId: "123456"
installationId: "789012"
privateKeyPath: /etc/stellaops/github-app.pem
notifications:
- type: slack
name: engineering
webhookUrl: ${SLACK_WEBHOOK_URL}
environments:
- name: dev
displayName: Development
orderIndex: 0
- name: staging
displayName: Staging
orderIndex: 1
- name: prod
displayName: Production
orderIndex: 2
isProduction: true
requiredApprovals: 2
```
```bash
$ stella setup --config setup.yaml --non-interactive
[1/10] Database Setup.............. [OK]
[2/10] Valkey/Redis Setup.......... [OK]
[3/10] Database Migrations......... [OK]
[4/10] Admin Bootstrap............. [OK]
[5/10] Crypto Profile.............. [OK]
[6/10] Vault Integration........... [OK]
[7/10] SCM Integration............. [OK]
[8/10] Notification Channels....... [OK]
[9/10] Environment Definition...... [OK]
[10/10] Agent Registration......... [SKIP] (no agents defined)
Setup complete. System status: Operational
Run 'stella doctor run' for full diagnostics.
```
### 2.8 Completion Output
```
Setup Complete!
===============
Status: Operational
Completed steps:
[x] Database Setup
[x] Valkey/Redis Setup
[x] Database Migrations
[x] Admin Bootstrap
[x] Crypto Profile
[x] Vault Integration
[x] SCM Integration
[x] Notification Channels
Skipped steps:
[ ] Identity Provider (OIDC/LDAP)
[ ] Environment Definition
[ ] Agent Registration
[ ] Vulnerability Feeds
To reach Production-Ready status, configure:
- Identity Provider: stella setup --step identity
- Environments: stella setup --step environments
- Agents: stella setup --step agents
Next steps:
1. Run first scan: stella scan image --image <digest>
2. View dashboard: https://localhost:8080
3. Full diagnostics: stella doctor run --mode full
Setup report saved to: ~/.stellaops/setup-report-2026-01-13.md
```
---
## 3. UI Flow
### 3.1 First-Run Blocking
When the system detects first-run (no database connection or admin user):
1. **Intercept all routes** - Redirect to `/setup`
2. **Show blocking modal** - Cannot dismiss without completing required steps
3. **Progress indicator** - Show completion percentage
### 3.2 Wizard Layout
```
+------------------------------------------------------------------+
| [StellaOps Logo] [?] Help [X] Exit |
+------------------------------------------------------------------+
| |
| SETUP WIZARD Step 1 of 10|
| |
| +------------+ +------------+ +------------+ +------------+ |
| | Database | | Valkey | | Migrations | | Admin | |
| | [1] | | [2] | | [3] | | [4] | |
| | [CURRENT] | | [PENDING] | | [PENDING] | | [PENDING] | |
| +------------+ +------------+ +------------+ +------------+ |
| |
| +------------+ +------------+ +------------+ +------------+ |
| | Crypto | | Vault | | SCM | | Notify | |
| | [5] | | [6] | | [7] | | [8] | |
| | [PENDING] | | [OPTIONAL] | | [OPTIONAL] | | [OPTIONAL] | |
| +------------+ +------------+ +------------+ +------------+ |
| |
| +------------+ +------------+ |
| | Environments| | Agents | |
| | [9] | | [10] | |
| | [OPTIONAL] | | [OPTIONAL] | |
| +------------+ +------------+ |
| |
+------------------------------------------------------------------+
| |
| DATABASE SETUP |
| --------------- |
| |
| Configure PostgreSQL connection for Stella Ops data storage. |
| |
| +----------------------------------------------------------+ |
| | Host [localhost ] | |
| | Port [5432 ] | |
| | Database [stellaops ] | |
| | Username [ ] | |
| | Password [ ] | |
| | SSL Mode [prefer v ] | |
| +----------------------------------------------------------+ |
| |
| [Test Connection] |
| |
| Connection Status: Not tested |
| |
+------------------------------------------------------------------+
| [Skip] [Continue] |
+------------------------------------------------------------------+
```
### 3.3 Step States
| State | Icon | Color | Description |
|-------|------|-------|-------------|
| **PENDING** | Circle | Gray | Not yet started |
| **CURRENT** | Circle+Ring | Blue | Currently active |
| **PASSED** | Checkmark | Green | Completed successfully |
| **FAILED** | X | Red | Failed validation |
| **SKIPPED** | Dash | Orange | Explicitly skipped |
| **OPTIONAL** | Circle+O | Gray | Can be skipped |
### 3.4 Connection Test Flow
```
+------------------------------------------------------------------+
| |
| [Test Connection] |
| |
| +----------------------------------------------------------+ |
| | Testing connection... | |
| | [=========> ] 30% | |
| | | |
| | [OK] TCP connection to localhost:5432 | |
| | [ ] Authenticating... | |
| | [ ] Checking permissions... | |
| +----------------------------------------------------------+ |
| |
+------------------------------------------------------------------+
```
### 3.5 Error State with Fixes
```
+------------------------------------------------------------------+
| |
| CONNECTION FAILED |
| |
| +----------------------------------------------------------+ |
| | [!] Could not connect to PostgreSQL | |
| | | |
| | Error: Connection refused (ECONNREFUSED) | |
| | | |
| | LIKELY CAUSES: | |
| | 1. PostgreSQL is not running | |
| | 2. Firewall blocking port 5432 | |
| | 3. Incorrect host or port | |
| | | |
| | SUGGESTED FIXES: | |
| | | |
| | If using Docker Compose: | |
| | +------------------------------------------------------+ | |
| | | docker compose up -d postgres [Copy]| | |
| | +------------------------------------------------------+ | |
| | | |
| | If using systemd: | |
| | +------------------------------------------------------+ | |
| | | sudo systemctl start postgresql [Copy]| | |
| | +------------------------------------------------------+ | |
| | | |
| | Verify connectivity: | |
| | +------------------------------------------------------+ | |
| | | pg_isready -h localhost -p 5432 [Copy]| | |
| | +------------------------------------------------------+ | |
| +----------------------------------------------------------+ |
| |
| [Retry] [Edit Configuration] |
+------------------------------------------------------------------+
```
### 3.6 Multi-Connector Interface
```
+------------------------------------------------------------------+
| |
| VAULT INTEGRATION (Optional) |
| --------------------------- |
| |
| Configure secrets management providers. |
| |
| CONFIGURED PROVIDERS: |
| +----------------------------------------------------------+ |
| | [V] HashiCorp Vault [Edit] [X] | |
| | https://vault.example.com:8200 | |
| | Status: Connected | |
| +----------------------------------------------------------+ |
| |
| [+ Add Another Provider] |
| |
| +----------------------------------------------------------+ |
| | SELECT PROVIDER TYPE: | |
| | | |
| | [HashiCorp Vault] [Azure Key Vault] | |
| | [AWS Secrets Mgr] [File Provider] | |
| +----------------------------------------------------------+ |
| |
| Note: You can add up to 5 vault integrations. |
| |
+------------------------------------------------------------------+
| [Skip] [Continue] |
+------------------------------------------------------------------+
```
### 3.7 Doctor Check Results Panel
```
+------------------------------------------------------------------+
| |
| VALIDATION RESULTS |
| ------------------ |
| |
| +----------------------------------------------------------+ |
| | [PASS] check.database.connectivity | |
| | PostgreSQL connection successful | |
| | | |
| | [PASS] check.database.permissions | |
| | User has required permissions | |
| | | |
| | [PASS] check.database.version | |
| | PostgreSQL 16.2 (minimum: 16.0) | |
| | | |
| | [WARN] check.database.poolsize | |
| | Pool size 10 is below recommended 50 | |
| | [Show Fix] | |
| +----------------------------------------------------------+ |
| |
| All required checks passed. |
| |
+------------------------------------------------------------------+
```
### 3.8 Skip Confirmation Dialog
```
+------------------------------------------------------------------+
| |
| +----------------------------------------------------------+ |
| | | |
| | SKIP VAULT INTEGRATION? | |
| | ----------------------- | |
| | | |
| | Without a secrets provider: | |
| | - Credentials stored in local keyring | |
| | - Air-gap deployments may require manual setup | |
| | - Production deployments not recommended | |
| | | |
| | You can configure this later from: | |
| | Settings > Configuration Wizard > Vault | |
| | | |
| | +----------------------------------------------------+ | |
| | | Reason for skipping (optional): | | |
| | | [Will configure after infrastructure ready ] | | |
| | +----------------------------------------------------+ | |
| | | |
| | [Cancel] [Skip This Step] | |
| +----------------------------------------------------------+ |
| |
+------------------------------------------------------------------+
```
### 3.9 Completion Screen
```
+------------------------------------------------------------------+
| |
| +----------------------------------------------------------+ |
| | | |
| | [Checkmark Icon] | |
| | | |
| | SETUP COMPLETE | |
| | | |
| | Status: OPERATIONAL | |
| | | |
| +----------------------------------------------------------+ |
| |
| COMPLETED STEPS: |
| +----------------------------------------------------------+ |
| | [x] Database Setup | |
| | [x] Valkey/Redis Setup | |
| | [x] Database Migrations | |
| | [x] Admin Bootstrap | |
| | [x] Crypto Profile | |
| | [x] Vault Integration | |
| | [x] SCM Integration | |
| | [x] Notification Channels | |
| +----------------------------------------------------------+ |
| |
| SKIPPED STEPS: |
| +----------------------------------------------------------+ |
| | [ ] Identity Provider (OIDC/LDAP) | |
| | [ ] Environment Definition | |
| | [ ] Agent Registration | |
| +----------------------------------------------------------+ |
| |
| NEXT STEPS: |
| +----------------------------------------------------------+ |
| | 1. Run your first scan | |
| | 2. Configure identity provider for SSO | |
| | 3. Set up environments for deployments | |
| +----------------------------------------------------------+ |
| |
| [Download Setup Report] [Go to Dashboard] |
| |
+------------------------------------------------------------------+
```
---
## 4. Configuration Pane (Post-Setup)
### 4.1 Access Points
| Surface | Path | Menu Location |
|---------|------|---------------|
| **UI** | `/settings/configuration` | Settings > Configuration Wizard |
| **CLI** | `stella setup --reconfigure` | N/A |
### 4.2 Configuration Pane Layout
```
+------------------------------------------------------------------+
| CONFIGURATION WIZARD |
+------------------------------------------------------------------+
| |
| Last configured: January 13, 2026 at 10:30 AM |
| Status: Production-Ready |
| |
| INFRASTRUCTURE |
| +----------------------------------------------------------+ |
| | Database Setup [Healthy] [Reconfigure] | |
| | PostgreSQL 16.2 at localhost:5432 | |
| +----------------------------------------------------------+ |
| +----------------------------------------------------------+ |
| | Valkey/Redis Setup [Healthy] [Reconfigure] | |
| | Valkey at localhost:6379 | |
| +----------------------------------------------------------+ |
| |
| INTEGRATIONS |
| +----------------------------------------------------------+ |
| | Vault (2 providers) [Healthy] [Manage] | |
| | HashiCorp Vault, Azure Key Vault | |
| +----------------------------------------------------------+ |
| +----------------------------------------------------------+ |
| | SCM (1 provider) [Healthy] [Manage] | |
| | GitHub App | |
| +----------------------------------------------------------+ |
| +----------------------------------------------------------+ |
| | Notifications (3 channels) [Healthy] [Manage] | |
| | Slack, Email, PagerDuty | |
| +----------------------------------------------------------+ |
| |
| ORCHESTRATION |
| +----------------------------------------------------------+ |
| | Environments (3) [Healthy] [Manage] | |
| | dev, staging, prod | |
| +----------------------------------------------------------+ |
| +----------------------------------------------------------+ |
| | Agents (2) [1 Stale] [Manage] | |
| | docker-prod-01, docker-prod-02 | |
| +----------------------------------------------------------+ |
| |
| [Run Diagnostics] [Export Configuration] |
+------------------------------------------------------------------+
```
---
## 5. Wording Guidelines
### 5.1 Step Titles
| Step | Title | Subtitle |
|------|-------|----------|
| `database` | Database Setup | Configure PostgreSQL connection |
| `valkey` | Valkey/Redis Setup | Configure caching and message queue |
| `migrations` | Database Migrations | Apply schema updates |
| `admin` | Admin Bootstrap | Create administrator account |
| `crypto` | Crypto Profile | Configure signing keys |
| `vault` | Vault Integration | Configure secrets management |
| `scm` | SCM Integration | Connect source control |
| `notifications` | Notification Channels | Configure alerts and notifications |
| `environments` | Environment Definition | Define deployment environments |
| `agents` | Agent Registration | Register deployment agents |
### 5.2 Button Labels
| Action | Label |
|--------|-------|
| Proceed to next step | Continue |
| Skip optional step | Skip |
| Test configuration | Test Connection |
| Retry after failure | Retry |
| Add another connector | + Add Another |
| Edit existing | Edit |
| Remove | Remove |
| Complete wizard | Finish Setup |
### 5.3 Status Messages
| Status | Message |
|--------|---------|
| Testing | Testing connection... |
| Success | Connection successful |
| Failure | Could not connect |
| Timeout | Connection timed out |
| Permission denied | Permission denied |
### 5.4 Error Messages
Format: `[What happened]. [Why it matters]. [What to do]`
Example:
> Could not connect to PostgreSQL. The database is required for all Stella Ops operations. Check that PostgreSQL is running and the connection details are correct.
---
## 6. Keyboard Navigation (UI)
| Key | Action |
|-----|--------|
| `Tab` | Move to next field |
| `Shift+Tab` | Move to previous field |
| `Enter` | Submit form / Continue |
| `Escape` | Cancel / Close dialog |
| `Ctrl+C` | Copy command to clipboard |
| `1-9` | Jump to step number |
---
## 7. Accessibility Requirements
1. **Screen reader support** - All form fields have labels
2. **Focus indicators** - Visible focus rings on all interactive elements
3. **Color contrast** - WCAG 2.1 AA compliance
4. **Keyboard navigation** - Full functionality without mouse
5. **Error announcements** - Errors announced to screen readers

View File

@@ -3,3 +3,4 @@
This file is retained to keep older references working.
For the current high-level architecture overview, see `docs/ARCHITECTURE_OVERVIEW.md`.
For the detailed reference map, see `docs/ARCHITECTURE_REFERENCE.md`.
For Doctor self service diagnostics, see `docs/doctor/doctor-capabilities.md`.