stela ops usage fixes roles propagation and timoeut, one account to support multi tenants, migrations consolidation, search to support documentation, doctor and open api vector db search

This commit is contained in:
master
2026-02-22 19:27:54 +02:00
parent a29f438f53
commit bd8fee6ed8
373 changed files with 832097 additions and 3369 deletions

View File

@@ -71,6 +71,40 @@ Consolidated Docker Compose configuration for the StellaOps platform. All profil
## Usage Patterns
### Migration Workflow (Compose)
Use this sequence for deterministic migration handling in compose-based deployments:
```bash
# 1) Start stack (or restart after release image update)
docker compose -f docker-compose.stella-ops.yml up -d
# 2) Check migration status for CLI-registered modules
stella system migrations-status --module all
# 3) Verify checksums
stella system migrations-verify --module all
# 4) Preview release migrations
stella system migrations-run --module all --category release --dry-run
# 5) Execute release migrations when approved
stella system migrations-run --module all --category release --force
# 6) Re-check status
stella system migrations-status --module all
```
This sequence is the canonical migration gate for on-prem upgradeable deployments.
Current behavior details:
- `./postgres-init` scripts execute only during first PostgreSQL initialization (`/docker-entrypoint-initdb.d` mount).
- Some services run startup migrations via hosted services; others are currently CLI-only or not wired yet.
- Use `docs/db/MIGRATION_INVENTORY.md` as the authoritative current-state matrix before production upgrades.
- Consolidation target policy and module cutover waves are defined in `docs/db/MIGRATION_CONSOLIDATION_PLAN.md`.
- UI-driven migration execution must use Platform admin endpoints (`/api/v1/admin/migrations/*`) and never direct browser-to-PostgreSQL access.
### Basic Development
```bash
@@ -83,10 +117,37 @@ docker compose -f docker-compose.stella-ops.yml config
# Start the platform
docker compose -f docker-compose.stella-ops.yml up -d
# RustFS health probe (S3 mode)
curl -fsS http://127.1.1.3:8080/status
# View logs
docker compose -f docker-compose.stella-ops.yml logs -f scanner-web
```
### Router Mode Switching
`router-gateway` now supports a compose-driven route table switch via `ROUTER_GATEWAY_CONFIG`.
```bash
# Default mode: microservice routing over Valkey messaging
ROUTER_GATEWAY_CONFIG=./router-gateway-local.json \
docker compose -f docker-compose.stella-ops.yml up -d
# Reverse-proxy fallback mode (no route-table edits required)
ROUTER_GATEWAY_CONFIG=./router-gateway-local.reverseproxy.json \
docker compose -f docker-compose.stella-ops.yml up -d
```
Validation endpoints:
```bash
# Aggregated OpenAPI
curl -k https://127.1.0.1/openapi.json
# Timeline API schema (through router-gateway)
curl -k https://127.1.0.1/openapi.json | jq '.paths["/api/v1/timeline"]'
```
### With Observability
```bash
@@ -304,12 +365,23 @@ Only externally-reachable services (Authority, Signer, Attestor, Concelier, Scan
## Sigstore Tools
Enable Sigstore CLI tools (rekor-cli, cosign) with the `sigstore` profile:
Enable Sigstore CLI tools (`rekor-cli`, `cosign`) with the `sigstore` profile:
```bash
docker compose -f docker-compose.stella-ops.yml --profile sigstore up -d
```
Enable self-hosted Rekor v2 with the `sigstore-local` profile:
```bash
docker compose -f docker-compose.stella-ops.yml --profile sigstore-local up -d rekor-v2
```
`sigstore-local` requires:
- Rekor signer key mounted at `../../etc/authority/keys/signing-dev.pem`
- Tessera backend config: `REKOR_GCP_BUCKET` and `REKOR_GCP_SPANNER`
- GCP ADC credentials available to the container runtime
---
## GPU Support for Advisory AI
@@ -367,8 +439,8 @@ docker compose -f docker-compose.stella-ops.yml \
```
**Tile Proxy vs Rekor v2:**
- Use `--profile sigstore` when running your own Rekor transparency log locally
- Use `docker-compose.tile-proxy.yml` when caching tiles from public Sigstore (rekor.sigstore.dev)
- Use `--profile sigstore-local` when running your own Rekor transparency log (GCP Tessera backend required).
- Use `docker-compose.tile-proxy.yml` when caching tiles from public Sigstore (`rekor.sigstore.dev`).
**Configuration:**
| Variable | Default | Purpose |

View File

@@ -0,0 +1,26 @@
name: stellaops-advisoryai-knowledge-test
services:
advisoryai-knowledge-postgres:
image: postgres:18.1-alpine
container_name: stellaops-advisoryai-knowledge-postgres-test
restart: unless-stopped
environment:
POSTGRES_DB: advisoryai_knowledge_test
POSTGRES_USER: stellaops_knowledge
POSTGRES_PASSWORD: stellaops_knowledge
TZ: UTC
PGTZ: UTC
ports:
- "55432:5432"
volumes:
- advisoryai-knowledge-postgres-data:/var/lib/postgresql/data
- ./postgres-init/advisoryai-knowledge-test:/docker-entrypoint-initdb.d:ro
healthcheck:
test: ["CMD-SHELL", "pg_isready -U stellaops_knowledge -d advisoryai_knowledge_test"]
interval: 5s
timeout: 5s
retries: 20
volumes:
advisoryai-knowledge-postgres-data:

View File

@@ -13,7 +13,7 @@
# - PostgreSQL 18.1 on 127.1.1.1:5432 (db.stella-ops.local)
# - Valkey 9.0.1 on 127.1.1.2:6379 (cache.stella-ops.local)
# - SeaweedFS (S3) on 127.1.1.3:8333 (s3.stella-ops.local)
# - Rekor v2 (tiles) on 127.1.1.4:3322 (rekor.stella-ops.local, opt-in sigstore profile)
# - Rekor v2 (tiles) on 127.1.1.4:3322 (rekor.stella-ops.local, opt-in sigstore-local profile)
# - Zot (OCI registry) on 127.1.1.5:80 (registry.stella-ops.local)
# =============================================================================
@@ -70,14 +70,32 @@ services:
rekor-v2:
image: ${REKOR_TILES_IMAGE:-ghcr.io/sigstore/rekor-tiles:latest}
container_name: stellaops-dev-rekor
restart: unless-stopped
profiles: ["sigstore"]
restart: on-failure:5
command:
- rekor-server
- serve
- --http-address
- 0.0.0.0
- --http-port
- "3322"
- --grpc-address
- 0.0.0.0
- --grpc-port
- "3323"
- --signer-filepath
- /etc/rekor/signer.pem
- --gcp-bucket
- ${REKOR_GCP_BUCKET:-stellaops-rekor-dev}
- --gcp-spanner
- ${REKOR_GCP_SPANNER:-projects/stellaops-dev/instances/rekor/databases/rekor}
profiles: ["sigstore-local"]
volumes:
- rekor-tiles-data:/var/lib/rekor-tiles
- ../../etc/authority/keys/signing-dev.pem:/etc/rekor/signer.pem:ro
ports:
- "127.1.1.4:${REKOR_PORT:-3322}:3322"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3322/healthz"]
test: ["CMD", "curl", "-f", "http://localhost:3322/api/v1/log"]
interval: 30s
timeout: 10s
retries: 3

View File

@@ -42,6 +42,26 @@ x-plugin-tmpfs: &plugin-tmpfs
/app/plugins:
mode: "1777"
x-router-microservice-defaults: &router-microservice-defaults
Router__Region: "local"
Router__Gateways__0__Host: "router.stella-ops.local"
Router__Gateways__0__Port: "9100"
Router__Gateways__0__TransportType: "Messaging"
Router__OnMissingAuthorization: "${ROUTER_ON_MISSING_AUTHORIZATION:-WarnAndAllow}"
Router__TransportPlugins__Directory: "/app/plugins/router/transports"
Router__TransportPlugins__SearchPattern: "StellaOps.Router.Transport.*.dll"
Router__Messaging__Transport: "valkey"
Router__Messaging__PluginDirectory: "/app/plugins/messaging"
Router__Messaging__SearchPattern: "StellaOps.Messaging.Transport.*.dll"
Router__Messaging__RequestQueueTemplate: "router:requests:{service}"
Router__Messaging__ResponseQueueName: "router:responses"
Router__Messaging__RequestTimeout: "30s"
Router__Messaging__LeaseDuration: "5m"
Router__Messaging__BatchSize: "10"
Router__Messaging__HeartbeatInterval: "10s"
Router__Messaging__valkey__ConnectionString: "cache.stella-ops.local:6379"
Router__Messaging__valkey__Database: "0"
# ---------------------------------------------------------------------------
# Common anchors for the 60-service stack
# ---------------------------------------------------------------------------
@@ -151,7 +171,7 @@ services:
aliases:
- s3.stella-ops.local
healthcheck:
test: ["CMD", "wget", "-qO-", "http://127.0.0.1:8333/"]
test: ["CMD-SHELL", "wget -q --spider http://127.0.0.1:8333/status || exit 1"]
interval: 30s
timeout: 10s
retries: 3
@@ -177,16 +197,39 @@ services:
rekor-v2:
image: ${REKOR_TILES_IMAGE:-ghcr.io/sigstore/rekor-tiles:latest}
container_name: stellaops-rekor
restart: unless-stopped
restart: on-failure:5
command:
- rekor-server
- serve
- --http-address
- 0.0.0.0
- --http-port
- "3322"
- --grpc-address
- 0.0.0.0
- --grpc-port
- "3323"
- --signer-filepath
- /etc/rekor/signer.pem
- --gcp-bucket
- ${REKOR_GCP_BUCKET:-stellaops-rekor-dev}
- --gcp-spanner
- ${REKOR_GCP_SPANNER:-projects/stellaops-dev/instances/rekor/databases/rekor}
volumes:
- rekor-tiles-data:/var/lib/rekor-tiles
- ../../etc/authority/keys/signing-dev.pem:/etc/rekor/signer.pem:ro
ports:
- "127.1.1.4:${REKOR_PORT:-3322}:3322"
networks:
stellaops:
aliases:
- rekor.stella-ops.local
profiles: ["sigstore"]
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3322/api/v1/log"]
interval: 30s
timeout: 10s
retries: 3
profiles: ["sigstore-local"]
labels:
<<: *release-labels
com.stellaops.component: "rekor-v2"
@@ -242,6 +285,20 @@ services:
Gateway__Auth__Authority__Issuer: "https://authority.stella-ops.local/"
Gateway__Auth__Authority__RequireHttpsMetadata: "false"
Gateway__Auth__Authority__MetadataAddress: "https://authority.stella-ops.local/.well-known/openid-configuration"
Gateway__Auth__Authority__ClaimsOverridesUrl: "${ROUTER_AUTHORITY_CLAIMS_OVERRIDES_URL:-http://authority.stella-ops.local}"
Gateway__Transports__Messaging__Enabled: "${ROUTER_GATEWAY_MESSAGING_ENABLED:-true}"
Gateway__Transports__Messaging__transport: "valkey"
Gateway__Transports__Messaging__ConnectionString: "cache.stella-ops.local:6379"
Gateway__Transports__Messaging__Database: "0"
Gateway__Transports__Messaging__valkey__ConnectionString: "cache.stella-ops.local:6379"
Gateway__Transports__Messaging__valkey__Database: "0"
Gateway__Transports__Messaging__RequestQueueTemplate: "router:requests:{service}"
Gateway__Transports__Messaging__ResponseQueueName: "router:responses"
Gateway__Transports__Messaging__ConsumerGroup: "router-gateway"
Gateway__Transports__Messaging__RequestTimeout: "30s"
Gateway__Transports__Messaging__LeaseDuration: "5m"
Gateway__Transports__Messaging__BatchSize: "10"
Gateway__Transports__Messaging__HeartbeatInterval: "10s"
# Audience validation disabled until authority includes aud in access tokens
# Gateway__Auth__Authority__Audiences__0: "stella-ops-api"
Logging__LogLevel__Microsoft.AspNetCore.Authentication: "Debug"
@@ -250,7 +307,7 @@ services:
volumes:
- *cert-volume
- console-dist:/app/wwwroot:ro
- ./router-gateway-local.json:/app/appsettings.local.json:ro
- ${ROUTER_GATEWAY_CONFIG:-./router-gateway-local.json}:/app/appsettings.local.json:ro
- ./envsettings-override.json:/app/envsettings-override.json:ro
- ./gateway-ca-bundle.crt:/etc/ssl/certs/ca-certificates.crt:ro
ports:
@@ -274,7 +331,7 @@ services:
depends_on: *depends-infra
environment:
ASPNETCORE_URLS: "http://+:8080"
<<: *kestrel-cert
<<: [*kestrel-cert, *router-microservice-defaults]
ConnectionStrings__Default: *postgres-connection
ConnectionStrings__Redis: "cache.stella-ops.local:6379"
Platform__Authority__Issuer: "https://authority.stella-ops.local/"
@@ -329,6 +386,8 @@ services:
STELLAOPS_SIGNALS_URL: "http://signals.stella-ops.local"
STELLAOPS_ADVISORYAI_URL: "http://advisoryai.stella-ops.local"
STELLAOPS_UNKNOWNS_URL: "http://unknowns.stella-ops.local"
Router__Enabled: "${PLATFORM_ROUTER_ENABLED:-true}"
Router__Messaging__ConsumerGroup: "platform"
volumes:
- *cert-volume
- *ca-bundle
@@ -376,11 +435,15 @@ services:
STELLAOPS_AUTHORITY_AUTHORITY__PLUGINS__DESCRIPTORS__standard__Type: "standard"
STELLAOPS_AUTHORITY_AUTHORITY__PLUGINS__DESCRIPTORS__standard__AssemblyName: "StellaOps.Authority.Plugin.Standard"
STELLAOPS_AUTHORITY_AUTHORITY__PLUGINS__DESCRIPTORS__standard__Enabled: "true"
STELLAOPS_AUTHORITY_AUTHORITY__PLUGINS__DESCRIPTORS__standard__TenantId: "demo-prod"
STELLAOPS_AUTHORITY_AUTHORITY__PLUGINS__DESCRIPTORS__standard__BootstrapUser__Username: "admin"
STELLAOPS_AUTHORITY_AUTHORITY__PLUGINS__DESCRIPTORS__standard__BootstrapUser__Password: "password"
<<: *router-microservice-defaults
Router__Enabled: "${AUTHORITY_ROUTER_ENABLED:-true}"
Router__Messaging__ConsumerGroup: "authority"
volumes:
- ../../etc/authority:/app/etc/authority:ro
- ../../etc/certificates/trust-roots:/etc/ssl/certs/stellaops:ro
tmpfs:
- /app/plugins:mode=1777
ports:
- "127.1.0.4:80:80"
networks:
@@ -401,12 +464,14 @@ services:
depends_on: *depends-infra
environment:
ASPNETCORE_URLS: "http://+:80;http://+:8080"
<<: *kestrel-cert
<<: [*kestrel-cert, *router-microservice-defaults]
ConnectionStrings__Default: *postgres-connection
ConnectionStrings__Redis: "cache.stella-ops.local:6379"
Gateway__Auth__DpopEnabled: "false"
Gateway__Auth__Authority__Issuer: "https://authority.stella-ops.local/"
Gateway__Auth__Authority__RequireHttpsMetadata: "false"
Router__Enabled: "${GATEWAY_ROUTER_ENABLED:-true}"
Router__Messaging__ConsumerGroup: "gateway"
volumes:
- *cert-volume
- *ca-bundle
@@ -432,9 +497,12 @@ services:
- signer
environment:
ASPNETCORE_URLS: "http://+:8442"
<<: *kestrel-cert
<<: [*kestrel-cert, *router-microservice-defaults]
ATTESTOR_ATTESTOR__SIGNER__BASEURL: "http://signer.stella-ops.local"
ATTESTOR_ATTESTOR__POSTGRES__CONNECTIONSTRING: *postgres-connection
ConnectionStrings__Default: *postgres-connection
Router__Enabled: "${ATTESTOR_ROUTER_ENABLED:-true}"
Router__Messaging__ConsumerGroup: "attestor"
volumes:
- *cert-volume
- *ca-bundle
@@ -485,7 +553,7 @@ services:
depends_on: *depends-infra
environment:
ASPNETCORE_URLS: "http://+:8080"
<<: *kestrel-cert
<<: [*kestrel-cert, *router-microservice-defaults]
EvidenceLocker__Database__ConnectionString: *postgres-connection
EvidenceLocker__Database__ApplyMigrationsAtStartup: "true"
EvidenceLocker__ObjectStore__Kind: "FileSystem"
@@ -506,6 +574,8 @@ services:
Authority__ResourceServer__BypassNetworks__2: "::1/128"
Authority__ResourceServer__BypassNetworks__3: "0.0.0.0/0"
Authority__ResourceServer__BypassNetworks__4: "::/0"
Router__Enabled: "${EVIDENCELOCKER_ROUTER_ENABLED:-true}"
Router__Messaging__ConsumerGroup: "evidencelocker"
volumes:
- *cert-volume
- *ca-bundle
@@ -561,11 +631,11 @@ services:
valkey:
condition: service_healthy
rustfs:
condition: service_started
condition: service_healthy
environment:
ASPNETCORE_URLS: "http://+:8444"
<<: *kestrel-cert
SCANNER_SCANNER__PLUGINS__BASEDIRECTORY: "/app"
<<: [*kestrel-cert, *router-microservice-defaults]
SCANNER_SCANNER__PLUGINS__BASEDIRECTORY: "/tmp/stellaops"
SCANNER_SCANNER__STORAGE__DRIVER: "postgres"
SCANNER_SCANNER__STORAGE__DSN: *postgres-connection
SCANNER_SCANNER__STORAGE__COMMANDTIMEOUTSECONDS: "30"
@@ -595,6 +665,8 @@ services:
SCANNER_SURFACE_SECRETS_ROOT: "${SCANNER_SURFACE_SECRETS_ROOT:-/etc/stellaops/secrets}"
SCANNER_SURFACE_SECRETS_FALLBACK_PROVIDER: "${SCANNER_SURFACE_SECRETS_FALLBACK_PROVIDER:-}"
SCANNER_SURFACE_SECRETS_ALLOW_INLINE: "${SCANNER_SURFACE_SECRETS_ALLOW_INLINE:-false}"
Router__Enabled: "${SCANNER_ROUTER_ENABLED:-true}"
Router__Messaging__ConsumerGroup: "scanner"
volumes:
- ../../etc/scanner:/app/etc/scanner:ro
- ../../etc/certificates/trust-roots:/etc/ssl/certs/stellaops:ro
@@ -603,7 +675,6 @@ services:
- ${SCANNER_OFFLINEKIT_REKOR_SNAPSHOT_HOST_PATH:-./offline/rekor-snapshot}:${SCANNER_OFFLINEKIT_REKORSNAPSHOTDIRECTORY:-/var/lib/stellaops/rekor-snapshot}:ro
- *cert-volume
tmpfs:
- /app/plugins:mode=1777
- /var/lib/stellaops/surface:mode=1777
ports:
- "127.1.0.8:80:80"
@@ -627,7 +698,7 @@ services:
valkey:
condition: service_healthy
rustfs:
condition: service_started
condition: service_healthy
environment:
<<: *kestrel-cert
# Scanner worker options
@@ -672,23 +743,23 @@ services:
valkey:
condition: service_healthy
rustfs:
condition: service_started
condition: service_healthy
environment:
ASPNETCORE_URLS: "http://+:8080"
<<: *kestrel-cert
CONCELIER_PLUGINS__BASEDIRECTORY: "/app"
<<: [*kestrel-cert, *router-microservice-defaults]
CONCELIER_PLUGINS__BASEDIRECTORY: "/tmp/stellaops"
CONCELIER_POSTGRESSTORAGE__CONNECTIONSTRING: *postgres-connection
CONCELIER_POSTGRESSTORAGE__ENABLED: "true"
CONCELIER_S3__ENDPOINT: "http://s3.stella-ops.local:8333"
CONCELIER_AUTHORITY__BASEURL: "https://authority.stella-ops.local"
CONCELIER_AUTHORITY__RESILIENCE__ALLOWOFFLINECACHEFALLBACK: "true"
CONCELIER_AUTHORITY__RESILIENCE__OFFLINECACHETOLERANCE: "${AUTHORITY_OFFLINE_CACHE_TOLERANCE:-00:30:00}"
Router__Enabled: "${CONCELIER_ROUTER_ENABLED:-true}"
Router__Messaging__ConsumerGroup: "concelier"
volumes:
- concelier-jobs:/var/lib/concelier/jobs
- *cert-volume
- *ca-bundle
tmpfs:
- /app/plugins:mode=1777
ports:
- "127.1.0.9:80:80"
networks:
@@ -709,7 +780,7 @@ services:
depends_on: *depends-infra
environment:
ASPNETCORE_URLS: "http://+:8080"
<<: *kestrel-cert
<<: [*kestrel-cert, *router-microservice-defaults]
# Postgres options (section: Postgres:Excititor)
Postgres__Excititor__ConnectionString: *postgres-connection
Postgres__Excititor__SchemaName: "vex"
@@ -720,11 +791,11 @@ services:
Excititor__Authority__BaseUrls__default: "https://authority.stella-ops.local"
# IssuerDirectoryClientOptions.Validate() requires BaseAddress
IssuerDirectory__Client__BaseAddress: "http://issuerdirectory.stella-ops.local"
Router__Enabled: "${EXCITITOR_ROUTER_ENABLED:-true}"
Router__Messaging__ConsumerGroup: "excititor"
volumes:
- *cert-volume
- *ca-bundle
tmpfs:
- /app/plugins:mode=1777
ports:
- "127.1.0.10:80:80"
networks:
@@ -778,11 +849,13 @@ services:
depends_on: *depends-infra
environment:
ASPNETCORE_URLS: "http://+:8080"
<<: *kestrel-cert
<<: [*kestrel-cert, *router-microservice-defaults]
ConnectionStrings__Default: *postgres-connection
ConnectionStrings__Redis: "cache.stella-ops.local:6379"
Postgres__ConnectionString: *postgres-connection
Postgres__SchemaName: "vexhub"
Router__Enabled: "${VEXHUB_ROUTER_ENABLED:-true}"
Router__Messaging__ConsumerGroup: "vexhub"
volumes:
- *cert-volume
ports:
@@ -805,9 +878,11 @@ services:
depends_on: *depends-infra
environment:
ASPNETCORE_URLS: "http://+:8080"
<<: *kestrel-cert
<<: [*kestrel-cert, *router-microservice-defaults]
ConnectionStrings__Default: *postgres-connection
ConnectionStrings__Redis: "cache.stella-ops.local:6379"
Router__Enabled: "${VEXLENS_ROUTER_ENABLED:-true}"
Router__Messaging__ConsumerGroup: "vexlens"
volumes:
- *cert-volume
ports:
@@ -830,9 +905,11 @@ services:
depends_on: *depends-infra
environment:
ASPNETCORE_URLS: "http://+:8080"
<<: *kestrel-cert
<<: [*kestrel-cert, *router-microservice-defaults]
ConnectionStrings__Default: *postgres-connection
ConnectionStrings__Redis: "cache.stella-ops.local:6379"
Router__Enabled: "${VULNEXPLORER_ROUTER_ENABLED:-true}"
Router__Messaging__ConsumerGroup: "vulnexplorer"
volumes:
- *cert-volume
ports:
@@ -855,7 +932,7 @@ services:
depends_on: *depends-infra
environment:
ASPNETCORE_URLS: "http://+:8080"
<<: *kestrel-cert
<<: [*kestrel-cert, *router-microservice-defaults]
STELLAOPS_POLICY_ENGINE_Postgres__Policy__ConnectionString: *postgres-connection
STELLAOPS_POLICY_ENGINE_ConnectionStrings__Redis: "cache.stella-ops.local:6379"
STELLAOPS_POLICY_ENGINE_PolicyEngine__ResourceServer__Authority: "https://authority.stella-ops.local/"
@@ -877,6 +954,8 @@ services:
PolicyEngine__ResourceServer__BypassNetworks__2: "::1/128"
Logging__LogLevel__Microsoft.AspNetCore.Authentication: "Debug"
Logging__LogLevel__Microsoft.IdentityModel: "Debug"
Router__Enabled: "${POLICY_ENGINE_ROUTER_ENABLED:-true}"
Router__Messaging__ConsumerGroup: "policy-engine"
volumes:
- *cert-volume
- *ca-bundle
@@ -900,7 +979,7 @@ services:
depends_on: *depends-infra
environment:
ASPNETCORE_URLS: "http://+:8084"
<<: *kestrel-cert
<<: [*kestrel-cert, *router-microservice-defaults]
ConnectionStrings__Default: *postgres-connection
ConnectionStrings__Redis: "cache.stella-ops.local:6379"
Postgres__Policy__ConnectionString: *postgres-connection
@@ -919,6 +998,8 @@ services:
STELLAOPS_POLICY_GATEWAY_PolicyGateway__ResourceServer__RequiredScopes__0: "policy:read"
STELLAOPS_POLICY_GATEWAY_PolicyGateway__PolicyEngine__ClientCredentials__Enabled: "false"
STELLAOPS_POLICY_GATEWAY_Postgres__Policy__ConnectionString: *postgres-connection
Router__Enabled: "${POLICY_GATEWAY_ROUTER_ENABLED:-true}"
Router__Messaging__ConsumerGroup: "policy-gateway"
volumes:
- *cert-volume
- *ca-bundle
@@ -942,9 +1023,11 @@ services:
depends_on: *depends-infra
environment:
ASPNETCORE_URLS: "http://+:8080"
<<: *kestrel-cert
<<: [*kestrel-cert, *router-microservice-defaults]
ConnectionStrings__Default: *postgres-connection
ConnectionStrings__Redis: "cache.stella-ops.local:6379"
Router__Enabled: "${RISKENGINE_ROUTER_ENABLED:-true}"
Router__Messaging__ConsumerGroup: "riskengine"
volumes:
- *cert-volume
ports:
@@ -986,9 +1069,11 @@ services:
depends_on: *depends-infra
environment:
ASPNETCORE_URLS: "http://+:8080"
<<: *kestrel-cert
<<: [*kestrel-cert, *router-microservice-defaults]
ConnectionStrings__Default: *postgres-connection
ConnectionStrings__Redis: "cache.stella-ops.local:6379"
Router__Enabled: "${ORCHESTRATOR_ROUTER_ENABLED:-true}"
Router__Messaging__ConsumerGroup: "orchestrator"
volumes:
- *cert-volume
ports:
@@ -1030,9 +1115,11 @@ services:
depends_on: *depends-infra
environment:
ASPNETCORE_URLS: "http://+:8080"
<<: *kestrel-cert
<<: [*kestrel-cert, *router-microservice-defaults]
ConnectionStrings__Default: *postgres-connection
ConnectionStrings__Redis: "cache.stella-ops.local:6379"
Router__Enabled: "${TASKRUNNER_ROUTER_ENABLED:-true}"
Router__Messaging__ConsumerGroup: "taskrunner"
volumes:
- *cert-volume
ports:
@@ -1082,7 +1169,7 @@ services:
depends_on: *depends-infra
environment:
ASPNETCORE_URLS: "http://+:8080"
<<: *kestrel-cert
<<: [*kestrel-cert, *router-microservice-defaults]
ConnectionStrings__Default: *postgres-connection
ConnectionStrings__Redis: "cache.stella-ops.local:6379"
Scheduler__Authority__Enabled: "false"
@@ -1095,10 +1182,11 @@ services:
Scheduler__Worker__Graph__Cartographer__BaseAddress: "http://cartographer.stella-ops.local"
Scheduler__Worker__Graph__SchedulerApi__BaseAddress: "http://scheduler.stella-ops.local"
Scheduler__Worker__Policy__Api__BaseAddress: "http://policy.stella-ops.local"
Router__Enabled: "${SCHEDULER_ROUTER_ENABLED:-true}"
Router__Messaging__ConsumerGroup: "scheduler"
volumes:
- *cert-volume
tmpfs:
- /app/plugins:mode=1777
- /plugins:mode=1777
ports:
- "127.1.0.19:80:80"
@@ -1156,9 +1244,11 @@ services:
depends_on: *depends-infra
environment:
ASPNETCORE_URLS: "http://+:8080"
<<: *kestrel-cert
<<: [*kestrel-cert, *router-microservice-defaults]
ConnectionStrings__Default: *postgres-connection
ConnectionStrings__Redis: "cache.stella-ops.local:6379"
Router__Enabled: "${GRAPH_ROUTER_ENABLED:-true}"
Router__Messaging__ConsumerGroup: "graph"
volumes:
- *cert-volume
ports:
@@ -1181,9 +1271,11 @@ services:
depends_on: *depends-infra
environment:
ASPNETCORE_URLS: "http://+:8080"
<<: *kestrel-cert
<<: [*kestrel-cert, *router-microservice-defaults]
ConnectionStrings__Default: *postgres-connection
ConnectionStrings__Redis: "cache.stella-ops.local:6379"
Router__Enabled: "${CARTOGRAPHER_ROUTER_ENABLED:-true}"
Router__Messaging__ConsumerGroup: "cartographer"
volumes:
- *cert-volume
ports:
@@ -1206,9 +1298,11 @@ services:
depends_on: *depends-infra
environment:
ASPNETCORE_URLS: "http://+:8080"
<<: *kestrel-cert
<<: [*kestrel-cert, *router-microservice-defaults]
ConnectionStrings__Default: *postgres-connection
ConnectionStrings__Redis: "cache.stella-ops.local:6379"
Router__Enabled: "${REACHGRAPH_ROUTER_ENABLED:-true}"
Router__Messaging__ConsumerGroup: "reachgraph"
volumes:
- *cert-volume
ports:
@@ -1231,9 +1325,12 @@ services:
depends_on: *depends-infra
environment:
ASPNETCORE_URLS: "http://+:8080"
<<: *kestrel-cert
<<: [*kestrel-cert, *router-microservice-defaults]
ConnectionStrings__Default: *postgres-connection
ConnectionStrings__Redis: "cache.stella-ops.local:6379"
TIMELINE_Postgres__Timeline__ConnectionString: *postgres-connection
Router__Enabled: "${TIMELINE_ROUTER_ENABLED:-true}"
Router__Messaging__ConsumerGroup: "timelineindexer"
volumes:
- *cert-volume
ports:
@@ -1257,6 +1354,7 @@ services:
<<: *kestrel-cert
ConnectionStrings__Default: *postgres-connection
ConnectionStrings__Redis: "cache.stella-ops.local:6379"
TIMELINE_Postgres__Timeline__ConnectionString: *postgres-connection
volumes:
- *cert-volume
healthcheck:
@@ -1275,9 +1373,11 @@ services:
depends_on: *depends-infra
environment:
ASPNETCORE_URLS: "http://+:8080"
<<: *kestrel-cert
<<: [*kestrel-cert, *router-microservice-defaults]
ConnectionStrings__Default: *postgres-connection
ConnectionStrings__Redis: "cache.stella-ops.local:6379"
Router__Enabled: "${TIMELINE_SERVICE_ROUTER_ENABLED:-true}"
Router__Messaging__ConsumerGroup: "timeline"
volumes:
- *cert-volume
ports:
@@ -1300,7 +1400,7 @@ services:
depends_on: *depends-infra
environment:
ASPNETCORE_URLS: "http://+:8080"
<<: *kestrel-cert
<<: [*kestrel-cert, *router-microservice-defaults]
ConnectionStrings__Default: *postgres-connection
ConnectionStrings__FindingsLedger: *postgres-connection
ConnectionStrings__Redis: "cache.stella-ops.local:6379"
@@ -1318,6 +1418,8 @@ services:
findings__ledger__Attachments__SignedUrlSecret: "dev-signed-url-secret"
findings__ledger__Attachments__SignedUrlLifetime: "00:15:00"
findings__ledger__Attachments__RequireConsoleCsrf: "false"
Router__Enabled: "${FINDINGS_ROUTER_ENABLED:-true}"
Router__Messaging__ConsumerGroup: "findings-ledger"
volumes:
- *cert-volume
- *ca-bundle
@@ -1341,12 +1443,14 @@ services:
depends_on: *depends-infra
environment:
ASPNETCORE_URLS: "http://+:8080"
<<: *kestrel-cert
<<: [*kestrel-cert, *router-microservice-defaults]
ConnectionStrings__Default: *postgres-connection
ConnectionStrings__Redis: "cache.stella-ops.local:6379"
Doctor__Authority__Issuer: "https://authority.stella-ops.local/"
Doctor__Authority__RequireHttpsMetadata: "false"
Doctor__Authority__BypassNetworks__0: "172.19.0.0/16"
Router__Enabled: "${DOCTOR_ROUTER_ENABLED:-true}"
Router__Messaging__ConsumerGroup: "doctor"
volumes:
- *cert-volume
- *ca-bundle
@@ -1368,13 +1472,17 @@ services:
restart: unless-stopped
depends_on: *depends-infra
environment:
<<: *kestrel-cert
ASPNETCORE_URLS: "http://+:80"
<<: [*kestrel-cert, *router-microservice-defaults]
ConnectionStrings__Default: *postgres-connection
ConnectionStrings__Redis: "cache.stella-ops.local:6379"
Router__Enabled: "${DOCTOR_SCHEDULER_ROUTER_ENABLED:-true}"
Router__Messaging__ConsumerGroup: "doctor-scheduler"
volumes:
- *cert-volume
healthcheck:
<<: *healthcheck-worker
test: ["CMD-SHELL", "bash -c 'echo > /dev/tcp/$(hostname)/80'"]
<<: *healthcheck-tcp
networks:
stellaops:
aliases:
@@ -1389,9 +1497,11 @@ services:
depends_on: *depends-infra
environment:
ASPNETCORE_URLS: "http://+:8080"
<<: *kestrel-cert
<<: [*kestrel-cert, *router-microservice-defaults]
ConnectionStrings__Default: *postgres-connection
ConnectionStrings__Redis: "cache.stella-ops.local:6379"
Router__Enabled: "${OPSMEMORY_ROUTER_ENABLED:-true}"
Router__Messaging__ConsumerGroup: "opsmemory"
volumes:
- *cert-volume
ports:
@@ -1414,9 +1524,11 @@ services:
depends_on: *depends-infra
environment:
ASPNETCORE_URLS: "http://+:8080"
<<: *kestrel-cert
<<: [*kestrel-cert, *router-microservice-defaults]
ConnectionStrings__Default: *postgres-connection
ConnectionStrings__Redis: "cache.stella-ops.local:6379"
Router__Enabled: "${NOTIFIER_ROUTER_ENABLED:-true}"
Router__Messaging__ConsumerGroup: "notifier"
volumes:
- *cert-volume
ports:
@@ -1461,22 +1573,22 @@ services:
depends_on: *depends-infra
environment:
ASPNETCORE_URLS: "http://+:8080"
<<: *kestrel-cert
<<: [*kestrel-cert, *router-microservice-defaults]
DOTNET_ENVIRONMENT: Production
NOTIFY_NOTIFY__STORAGE__DRIVER: "postgres"
NOTIFY_NOTIFY__STORAGE__CONNECTIONSTRING: *postgres-connection
NOTIFY_NOTIFY__STORAGE__DATABASE: "notify"
NOTIFY_NOTIFY__PLUGINS__BASEDIRECTORY: "/app"
NOTIFY_NOTIFY__PLUGINS__BASEDIRECTORY: "/tmp/stellaops"
NOTIFY_NOTIFY__AUTHORITY__ENABLED: "false"
NOTIFY_NOTIFY__AUTHORITY__ALLOWANONYMOUSFALLBACK: "true"
NOTIFY_NOTIFY__AUTHORITY__DEVELOPMENTSIGNINGKEY: "StellaOps-Development-Key-NotifyService-2026!!"
NOTIFY_Postgres__Notify__ConnectionString: *postgres-connection
Postgres__Notify__ConnectionString: *postgres-connection
Router__Enabled: "${NOTIFY_ROUTER_ENABLED:-true}"
Router__Messaging__ConsumerGroup: "notify"
volumes:
- ../../etc/notify:/app/etc/notify:ro
- *cert-volume
tmpfs:
- /app/plugins:mode=1777
ports:
- "127.1.0.29:80:80"
networks:
@@ -1499,9 +1611,11 @@ services:
- valkey
environment:
ASPNETCORE_URLS: "http://+:8441"
<<: *kestrel-cert
<<: [*kestrel-cert, *router-microservice-defaults]
ConnectionStrings__KeyManagement: *postgres-connection
ConnectionStrings__Default: *postgres-connection
Router__Enabled: "${SIGNER_ROUTER_ENABLED:-true}"
Router__Messaging__ConsumerGroup: "signer"
volumes:
- *cert-volume
ports:
@@ -1524,9 +1638,11 @@ services:
depends_on: *depends-infra
environment:
ASPNETCORE_URLS: "http://+:8080"
<<: *kestrel-cert
<<: [*kestrel-cert, *router-microservice-defaults]
ConnectionStrings__Default: *postgres-connection
ConnectionStrings__Redis: "cache.stella-ops.local:6379"
Router__Enabled: "${SMREMOTE_ROUTER_ENABLED:-true}"
Router__Messaging__ConsumerGroup: "smremote"
volumes:
- *cert-volume
ports:
@@ -1549,9 +1665,11 @@ services:
depends_on: *depends-infra
environment:
ASPNETCORE_URLS: "http://+:8080"
<<: *kestrel-cert
<<: [*kestrel-cert, *router-microservice-defaults]
ConnectionStrings__Default: *postgres-connection
ConnectionStrings__Redis: "cache.stella-ops.local:6379"
Router__Enabled: "${AIRGAP_CONTROLLER_ROUTER_ENABLED:-true}"
Router__Messaging__ConsumerGroup: "airgap-controller"
volumes:
- *cert-volume
ports:
@@ -1575,8 +1693,10 @@ services:
depends_on: *depends-infra
environment:
ASPNETCORE_URLS: "http://+:8080"
<<: *kestrel-cert
<<: [*kestrel-cert, *router-microservice-defaults]
ConnectionStrings__Default: *postgres-connection
Router__Enabled: "${AIRGAP_TIME_ROUTER_ENABLED:-true}"
Router__Messaging__ConsumerGroup: "airgap-time"
volumes:
- *cert-volume
ports:
@@ -1599,9 +1719,11 @@ services:
depends_on: *depends-infra
environment:
ASPNETCORE_URLS: "http://+:8080"
<<: *kestrel-cert
<<: [*kestrel-cert, *router-microservice-defaults]
ConnectionStrings__Default: *postgres-connection
ConnectionStrings__Redis: "cache.stella-ops.local:6379"
Router__Enabled: "${PACKSREGISTRY_ROUTER_ENABLED:-true}"
Router__Messaging__ConsumerGroup: "packsregistry"
volumes:
- *cert-volume
ports:
@@ -1643,7 +1765,7 @@ services:
depends_on: *depends-infra
environment:
ASPNETCORE_URLS: "http://+:8080"
<<: *kestrel-cert
<<: [*kestrel-cert, *router-microservice-defaults]
ConnectionStrings__Default: *postgres-connection
RegistryTokenService__Signing__Issuer: "http://registry-token.stella-ops.local"
RegistryTokenService__Signing__KeyPath: "/app/etc/certs/kestrel-dev.pfx"
@@ -1656,6 +1778,8 @@ services:
RegistryTokenService__Plans__0__Repositories__0__Pattern: "*"
RegistryTokenService__Plans__0__Repositories__0__Actions__0: "pull"
RegistryTokenService__Plans__0__Repositories__0__Actions__1: "push"
Router__Enabled: "${REGISTRY_TOKEN_ROUTER_ENABLED:-true}"
Router__Messaging__ConsumerGroup: "registry-token"
volumes:
- *cert-volume
- *ca-bundle
@@ -1679,9 +1803,11 @@ services:
depends_on: *depends-infra
environment:
ASPNETCORE_URLS: "http://+:8080"
<<: *kestrel-cert
<<: [*kestrel-cert, *router-microservice-defaults]
ConnectionStrings__Default: *postgres-connection
ConnectionStrings__Redis: "cache.stella-ops.local:6379"
Router__Enabled: "${BINARYINDEX_ROUTER_ENABLED:-true}"
Router__Messaging__ConsumerGroup: "binaryindex"
volumes:
- *cert-volume
ports:
@@ -1706,7 +1832,7 @@ services:
- authority
environment:
ASPNETCORE_URLS: "http://+:8080"
<<: *kestrel-cert
<<: [*kestrel-cert, *router-microservice-defaults]
ISSUERDIRECTORY__AUTHORITY__ENABLED: "true"
ISSUERDIRECTORY__AUTHORITY__ISSUER: "${AUTHORITY_ISSUER:-http://authority.stella-ops.local}"
ISSUERDIRECTORY__AUTHORITY__AUDIENCES__0: "api://issuer-directory"
@@ -1714,6 +1840,8 @@ services:
ISSUERDIRECTORY__PERSISTENCE__PROVIDER: "Postgres"
ISSUERDIRECTORY__PERSISTENCE__POSTGRESCONNECTIONSTRING: *postgres-connection
ISSUERDIRECTORY__SEEDCSAFPUBLISHERS: "false"
Router__Enabled: "${ISSUERDIRECTORY_ROUTER_ENABLED:-true}"
Router__Messaging__ConsumerGroup: "issuerdirectory"
volumes:
- ../../etc/issuer-directory:/app/etc/issuer-directory:ro
- *cert-volume
@@ -1737,12 +1865,14 @@ services:
depends_on: *depends-infra
environment:
ASPNETCORE_URLS: "http://+:8080"
<<: *kestrel-cert
<<: [*kestrel-cert, *router-microservice-defaults]
ConnectionStrings__Default: *postgres-connection
ConnectionStrings__Redis: "cache.stella-ops.local:6379"
Authority__ResourceServer__Authority: "https://authority.stella-ops.local/"
Authority__ResourceServer__RequireHttpsMetadata: "false"
Authority__ResourceServer__BypassNetworks__0: "172.19.0.0/16"
Router__Enabled: "${SYMBOLS_ROUTER_ENABLED:-true}"
Router__Messaging__ConsumerGroup: "symbols"
volumes:
- *cert-volume
- *ca-bundle
@@ -1766,9 +1896,11 @@ services:
depends_on: *depends-infra
environment:
ASPNETCORE_URLS: "http://+:8080"
<<: *kestrel-cert
<<: [*kestrel-cert, *router-microservice-defaults]
ConnectionStrings__Default: *postgres-connection
ConnectionStrings__Redis: "cache.stella-ops.local:6379"
Router__Enabled: "${SBOMSERVICE_ROUTER_ENABLED:-true}"
Router__Messaging__ConsumerGroup: "sbomservice"
volumes:
- *cert-volume
ports:
@@ -1791,7 +1923,7 @@ services:
depends_on: *depends-infra
environment:
ASPNETCORE_URLS: "http://+:8080"
<<: *kestrel-cert
<<: [*kestrel-cert, *router-microservice-defaults]
ConnectionStrings__Default: *postgres-connection
ConnectionStrings__Redis: "cache.stella-ops.local:6379"
Export__AllowInMemoryRepositories: "true"
@@ -1804,6 +1936,8 @@ services:
Authority__ResourceServer__BypassNetworks__2: "::1/128"
Authority__ResourceServer__BypassNetworks__3: "0.0.0.0/0"
Authority__ResourceServer__BypassNetworks__4: "::/0"
Router__Enabled: "${EXPORTCENTER_ROUTER_ENABLED:-true}"
Router__Messaging__ConsumerGroup: "exportcenter"
volumes:
- *cert-volume
- *ca-bundle
@@ -1853,9 +1987,11 @@ services:
depends_on: *depends-infra
environment:
ASPNETCORE_URLS: "http://+:8080"
<<: *kestrel-cert
<<: [*kestrel-cert, *router-microservice-defaults]
ConnectionStrings__Default: *postgres-connection
ConnectionStrings__Redis: "cache.stella-ops.local:6379"
Router__Enabled: "${REPLAY_ROUTER_ENABLED:-true}"
Router__Messaging__ConsumerGroup: "replay"
volumes:
- *cert-volume
ports:
@@ -1878,13 +2014,14 @@ services:
depends_on: *depends-infra
environment:
ASPNETCORE_URLS: "http://+:8080"
<<: *kestrel-cert
<<: [*kestrel-cert, *router-microservice-defaults]
ConnectionStrings__IntegrationsDb: *postgres-connection
ConnectionStrings__Default: *postgres-connection
ConnectionStrings__Redis: "cache.stella-ops.local:6379"
Router__Enabled: "${INTEGRATIONS_ROUTER_ENABLED:-true}"
Router__Messaging__ConsumerGroup: "integrations"
volumes:
- *cert-volume
tmpfs:
- /app/plugins:mode=1777
ports:
- "127.1.0.42:80:80"
networks:
@@ -1947,9 +2084,11 @@ services:
depends_on: *depends-infra
environment:
ASPNETCORE_URLS: "http://+:8080"
<<: *kestrel-cert
<<: [*kestrel-cert, *router-microservice-defaults]
ConnectionStrings__Default: *postgres-connection
ConnectionStrings__Redis: "cache.stella-ops.local:6379"
Router__Enabled: "${SIGNALS_ROUTER_ENABLED:-true}"
Router__Messaging__ConsumerGroup: "signals"
volumes:
- *cert-volume
ports:
@@ -1973,14 +2112,18 @@ services:
- scanner-web
environment:
ASPNETCORE_URLS: "http://+:8080"
<<: *kestrel-cert
<<: [*kestrel-cert, *router-microservice-defaults]
ADVISORYAI__AdvisoryAI__SbomBaseAddress: "${ADVISORY_AI_SBOM_BASEADDRESS:-http://scanner.stella-ops.local}"
ADVISORYAI__AdvisoryAI__Queue__DirectoryPath: "/var/lib/advisory-ai/queue"
ADVISORYAI__AdvisoryAI__Storage__PlanCacheDirectory: "/var/lib/advisory-ai/plans"
ADVISORYAI__AdvisoryAI__Storage__OutputDirectory: "/var/lib/advisory-ai/outputs"
ADVISORYAI__AdvisoryAI__Adapters__Llm__Enabled: "${ADVISORY_AI_LLM_ADAPTERS_ENABLED:-true}"
ADVISORYAI__AdvisoryAI__LlmProviders__ConfigDirectory: "${ADVISORY_AI_LLM_PROVIDERS_DIRECTORY:-/app/etc/llm-providers}"
ADVISORYAI__AdvisoryAI__Inference__Mode: "${ADVISORY_AI_INFERENCE_MODE:-Local}"
ADVISORYAI__AdvisoryAI__Inference__Remote__BaseAddress: "${ADVISORY_AI_REMOTE_BASEADDRESS:-}"
ADVISORYAI__AdvisoryAI__Inference__Remote__ApiKey: "${ADVISORY_AI_REMOTE_APIKEY:-}"
Router__Enabled: "${ADVISORYAI_ROUTER_ENABLED:-true}"
Router__Messaging__ConsumerGroup: "advisoryai"
ports:
- "127.1.0.44:80:80"
volumes:
@@ -1989,8 +2132,6 @@ services:
- advisory-ai-queue:/var/lib/advisory-ai/queue
- advisory-ai-plans:/var/lib/advisory-ai/plans
- advisory-ai-outputs:/var/lib/advisory-ai/outputs
tmpfs:
- /app/plugins:mode=1777
networks:
stellaops:
aliases:
@@ -2034,10 +2175,12 @@ services:
depends_on: *depends-infra
environment:
ASPNETCORE_URLS: "http://+:8080"
<<: *kestrel-cert
<<: [*kestrel-cert, *router-microservice-defaults]
ConnectionStrings__Default: *postgres-connection
ConnectionStrings__UnknownsDb: *postgres-connection
ConnectionStrings__Redis: "cache.stella-ops.local:6379"
Router__Enabled: "${UNKNOWNS_ROUTER_ENABLED:-true}"
Router__Messaging__ConsumerGroup: "unknowns"
volumes:
- *cert-volume
ports:

View File

@@ -26,6 +26,18 @@ VALKEY_PORT=6379
# RustFS Object Storage
RUSTFS_HTTP_PORT=8333
# =============================================================================
# ROUTER GATEWAY MODE
# =============================================================================
# Router route table file mounted to /app/appsettings.local.json
# Microservice + Valkey mode (default):
ROUTER_GATEWAY_CONFIG=./router-gateway-local.json
# Reverse-proxy fallback mode:
# ROUTER_GATEWAY_CONFIG=./router-gateway-local.reverseproxy.json
# Authority claims override endpoint base URL consumed by router-gateway.
ROUTER_AUTHORITY_CLAIMS_OVERRIDES_URL=http://authority.stella-ops.local
# =============================================================================
# CORE SERVICES
# =============================================================================
@@ -109,12 +121,16 @@ SCHEDULER_SCANNER_BASEADDRESS=http://scanner.stella-ops.local
# REKOR / SIGSTORE CONFIGURATION
# =============================================================================
# Rekor server URL (default: public Sigstore, use http://rekor-v2:3000 for local)
# Rekor server URL (default: public Sigstore, use http://rekor-v2:3322 for local)
REKOR_SERVER_URL=https://rekor.sigstore.dev
REKOR_VERSION=V2
REKOR_TILE_BASE_URL=
REKOR_LOG_ID=c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d
REKOR_TILES_IMAGE=ghcr.io/sigstore/rekor-tiles:latest
# Local Rekor v2 (`--profile sigstore-local`) uses Tessera GCP backend.
# Override these with your actual GCP bucket/database identifiers.
REKOR_GCP_BUCKET=stellaops-rekor-dev
REKOR_GCP_SPANNER=projects/stellaops-dev/instances/rekor/databases/rekor
# =============================================================================
# ADVISORY AI CONFIGURATION

View File

@@ -6,7 +6,7 @@
"tokenEndpoint": "https://authority.stella-ops.local/connect/token",
"redirectUri": "https://stella-ops.local/auth/callback",
"postLogoutRedirectUri": "https://stella-ops.local/",
"scope": "openid profile email offline_access ui.read ui.admin authority:tenants.read authority:users.read authority:roles.read authority:clients.read authority:tokens.read authority:branding.read authority.audit.read graph:read sbom:read scanner:read policy:read policy:simulate policy:author policy:review policy:approve orch:read analytics.read advisory:read vex:read exceptions:read exceptions:approve aoc:verify findings:read release:read scheduler:read scheduler:operate notify.viewer notify.operator notify.admin notify.escalate evidence:read export.viewer export.operator export.admin vuln:view vuln:investigate vuln:operate vuln:audit",
"scope": "openid profile email offline_access ui.read ui.admin authority:tenants.read authority:users.read authority:roles.read authority:clients.read authority:tokens.read authority:branding.read authority.audit.read graph:read sbom:read scanner:read policy:read policy:simulate policy:author policy:review policy:approve orch:read analytics.read advisory:read vex:read exceptions:read exceptions:approve aoc:verify findings:read release:read scheduler:read scheduler:operate notify.viewer notify.operator notify.admin notify.escalate evidence:read export.viewer export.operator export.admin vuln:view vuln:investigate vuln:operate vuln:audit platform.context.read platform.context.write doctor:run doctor:admin",
"audience": "stella-ops-api",
"dpopAlgorithms": [
"ES256"

View File

View File

View File

@@ -0,0 +1,37 @@
[
{
"Path": "/platform/envsettings.json",
"Type": "StaticFile",
"TranslatesTo": "/app/envsettings-override.json"
},
{
"Path": "/platform",
"Type": "ReverseProxy",
"TranslatesTo": "http://platform.stella-ops.local/platform"
},
{
"Path": "/rekor",
"Type": "ReverseProxy",
"TranslatesTo": "http://rekor.stella-ops.local:3322"
},
{
"Path": "/envsettings.json",
"Type": "ReverseProxy",
"TranslatesTo": "http://platform.stella-ops.local/platform/envsettings.json"
},
{
"Path": "/",
"Type": "StaticFiles",
"TranslatesTo": "/app/wwwroot"
},
{
"Path": "/_error/404",
"Type": "NotFoundPage",
"TranslatesTo": "/app/wwwroot/index.html"
},
{
"Path": "/_error/500",
"Type": "ServerErrorPage",
"TranslatesTo": "/app/wwwroot/index.html"
}
]

View File

@@ -0,0 +1,4 @@
[
"/api/v1/advisory-ai/adapters/llm/providers",
"/api/v1/advisory-ai/adapters/llm/{providerId}/chat/completions"
]

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,14 @@
{
"generatedUtc": "2026-02-22T15:58:47.8552877Z",
"operationsTotal": 2190,
"missingSummary": 0,
"missingDescription": 1417,
"missingSecurity": 1935,
"missingTimeoutExtension": 0,
"missingGatewayAuthExtension": 0,
"timelineOperations": 4,
"timelineMissingSummary": 0,
"timelineMissingDescription": 0,
"timelineMissingTimeoutExtension": 0,
"timelineMissingGatewayAuthExtension": 0
}

View File

@@ -0,0 +1,14 @@
{
"generatedUtc": "2026-02-22T15:56:44.2132655Z",
"operationsTotal": 1758,
"missingSummary": 0,
"missingDescription": 1230,
"missingSecurity": 1532,
"missingTimeoutExtension": 0,
"missingGatewayAuthExtension": 0,
"timelineOperations": 13,
"timelineMissingSummary": 0,
"timelineMissingDescription": 0,
"timelineMissingTimeoutExtension": 0,
"timelineMissingGatewayAuthExtension": 0
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,116 @@
"RouteType","RoutePath","RouteTarget","SelectedOpenApiPath","StatusCode"
"Microservice","/api/v1/release-orchestrator","http://orchestrator.stella-ops.local/api/v1/release-orchestrator","/api/v1/release-orchestrator/releases","200"
"Microservice","/api/v1/vex","https://vexhub.stella-ops.local/api/v1/vex","/api/v1/vex/index","200"
"Microservice","/api/v1/vexlens","http://vexlens.stella-ops.local/api/v1/vexlens","/api/v1/vexlens/stats","200"
"Microservice","/api/v1/notify","http://notify.stella-ops.local/api/v1/notify","/api/v1/notify/audit","400"
"Microservice","/api/v1/notifier","http://notifier.stella-ops.local/api/v1/notifier",,
"Microservice","/api/v1/concelier","http://concelier.stella-ops.local/api/v1/concelier","/api/v1/concelier/bundles","200"
"Microservice","/api/v1/platform","http://platform.stella-ops.local/api/v1/platform","/api/v1/platform/search","400"
"Microservice","/api/v1/scanner","http://scanner.stella-ops.local/api/v1/scanner",,
"Microservice","/api/v1/findings","http://findings.stella-ops.local/api/v1/findings","/api/v1/findings/summaries","200"
"Microservice","/api/v1/integrations","http://integrations.stella-ops.local/api/v1/integrations","/api/v1/integrations","401"
"Microservice","/api/v1/policy","http://policy-gateway.stella-ops.local/api/v1/policy","/api/v1/policy/gate/health","200"
"Microservice","/api/v1/reachability","http://reachgraph.stella-ops.local/api/v1/reachability",,
"Microservice","/api/v1/attestor","http://attestor.stella-ops.local/api/v1/attestor","/api/v1/attestor/predicates","200"
"Microservice","/api/v1/attestations","http://attestor.stella-ops.local/api/v1/attestations","/api/v1/attestations","200"
"Microservice","/api/v1/sbom","http://sbomservice.stella-ops.local/api/v1/sbom",,
"Microservice","/api/v1/signals","http://signals.stella-ops.local/api/v1/signals",,
"Microservice","/api/v1/orchestrator","http://orchestrator.stella-ops.local/api/v1/orchestrator","/api/v1/orchestrator/jobs","400"
"Microservice","/api/v1/authority/quotas","http://platform.stella-ops.local/api/v1/authority/quotas","/api/v1/authority/quotas","400"
"Microservice","/api/v1/authority","https://authority.stella-ops.local/api/v1/authority","/api/v1/authority/quotas","400"
"Microservice","/api/v1/trust","https://authority.stella-ops.local/api/v1/trust",,
"Microservice","/api/v1/evidence","https://evidencelocker.stella-ops.local/api/v1/evidence","/api/v1/evidence","200"
"Microservice","/api/v1/proofs","https://evidencelocker.stella-ops.local/api/v1/proofs",,
"Microservice","/api/v1/timeline","http://timelineindexer.stella-ops.local/api/v1/timeline","/api/v1/timeline","401"
"Microservice","/api/v1/advisory-ai/adapters","http://advisoryai.stella-ops.local/v1/advisory-ai/adapters","/","200"
"Microservice","/api/v1/advisory-ai","http://advisoryai.stella-ops.local/api/v1/advisory-ai","/","200"
"Microservice","/api/v1/advisory","http://advisoryai.stella-ops.local/api/v1/advisory","/","200"
"Microservice","/api/v1/vulnerabilities","http://scanner.stella-ops.local/api/v1/vulnerabilities",,
"Microservice","/api/v1/watchlist","http://scanner.stella-ops.local/api/v1/watchlist",,
"Microservice","/api/v1/resolve","http://binaryindex.stella-ops.local/api/v1/resolve",,
"Microservice","/api/v1/ops/binaryindex","http://binaryindex.stella-ops.local/api/v1/ops/binaryindex","/api/v1/ops/binaryindex/cache","200"
"Microservice","/api/v1/verdicts","https://evidencelocker.stella-ops.local/api/v1/verdicts","/api/v1/verdicts/{verdictId}","404"
"Microservice","/api/v1/lineage","http://sbomservice.stella-ops.local/api/v1/lineage","/api/v1/lineage/diff","400"
"Microservice","/api/v1/export","https://exportcenter.stella-ops.local/api/v1/export",,
"Microservice","/api/v1/triage","http://scanner.stella-ops.local/api/v1/triage","/api/v1/triage/inbox","401"
"Microservice","/api/v1/governance","http://policy-gateway.stella-ops.local/api/v1/governance","/api/v1/governance/audit/events","400"
"Microservice","/api/v1/determinization","http://policy-engine.stella-ops.local/api/v1/determinization",,
"Microservice","/api/v1/opsmemory","http://opsmemory.stella-ops.local/api/v1/opsmemory","/api/v1/opsmemory/stats","400"
"Microservice","/api/v1/secrets","http://scanner.stella-ops.local/api/v1/secrets","/api/v1/secrets/config/rules/categories","401"
"Microservice","/api/v1/sources","http://sbomservice.stella-ops.local/api/v1/sources",,
"Microservice","/api/v1/workflows","http://orchestrator.stella-ops.local/api/v1/workflows",,
"Microservice","/api/v1/witnesses","http://attestor.stella-ops.local/api/v1/witnesses",,
"Microservice","/v1/evidence-packs","https://evidencelocker.stella-ops.local/v1/evidence-packs",,
"Microservice","/v1/runs","http://orchestrator.stella-ops.local/v1/runs","/v1/runs/{id}","404"
"Microservice","/v1/advisory-ai/adapters","http://advisoryai.stella-ops.local/v1/advisory-ai/adapters","/","200"
"Microservice","/v1/advisory-ai","http://advisoryai.stella-ops.local/v1/advisory-ai","/v1/advisory-ai/consent","200"
"Microservice","/v1/audit-bundles","https://exportcenter.stella-ops.local/v1/audit-bundles","/v1/audit-bundles","200"
"Microservice","/policy","http://policy-gateway.stella-ops.local","/policyEngine","302"
"Microservice","/api/cvss","http://policy-gateway.stella-ops.local/api/cvss","/api/cvss/policies","401"
"Microservice","/api/policy","http://policy-gateway.stella-ops.local/api/policy","/api/policy/packs","401"
"Microservice","/api/risk","http://policy-engine.stella-ops.local/api/risk","/api/risk/events","400"
"Microservice","/api/analytics","http://platform.stella-ops.local/api/analytics","/api/analytics/backlog","400"
"Microservice","/api/release-orchestrator","http://orchestrator.stella-ops.local/api/release-orchestrator","/api/release-orchestrator/releases","200"
"Microservice","/api/releases","http://orchestrator.stella-ops.local/api/releases",,
"Microservice","/api/approvals","http://orchestrator.stella-ops.local/api/approvals",,
"Microservice","/api/gate","http://policy-gateway.stella-ops.local/api/gate",,
"Microservice","/api/risk-budget","http://policy-engine.stella-ops.local/api/risk-budget",,
"Microservice","/api/fix-verification","http://scanner.stella-ops.local/api/fix-verification",,
"Microservice","/api/compare","http://sbomservice.stella-ops.local/api/compare",,
"Microservice","/api/change-traces","http://sbomservice.stella-ops.local/api/change-traces",,
"Microservice","/api/exceptions","http://policy-gateway.stella-ops.local/api/exceptions",,
"Microservice","/api/verdicts","https://evidencelocker.stella-ops.local/api/verdicts",,
"Microservice","/api/orchestrator","http://orchestrator.stella-ops.local/api/orchestrator",,
"Microservice","/api/v1/gateway/rate-limits","http://platform.stella-ops.local/api/v1/gateway/rate-limits","/api/v1/gateway/rate-limits","400"
"Microservice","/api/sbomservice","http://sbomservice.stella-ops.local/api/sbomservice",,
"Microservice","/api/vuln-explorer","http://vulnexplorer.stella-ops.local/api/vuln-explorer",,
"Microservice","/api/vex","https://vexhub.stella-ops.local/api/vex",,
"Microservice","/api/admin","http://platform.stella-ops.local/api/admin",,
"Microservice","/api/scheduler","http://scheduler.stella-ops.local/api/scheduler",,
"Microservice","/api/v1/doctor/scheduler","http://doctor-scheduler.stella-ops.local/api/v1/doctor/scheduler","/api/v1/doctor/scheduler/trends","200"
"Microservice","/api/doctor","http://doctor.stella-ops.local/api/doctor",,
"Microservice","/api","http://platform.stella-ops.local/api","/api/v1/search","400"
"Microservice","/connect","https://authority.stella-ops.local/connect","/","200"
"Microservice","/.well-known","https://authority.stella-ops.local/well-known","/","200"
"Microservice","/jwks","https://authority.stella-ops.local/jwks","/","200"
"Microservice","/authority","https://authority.stella-ops.local/authority","/authority/audit/airgap","401"
"Microservice","/console","https://authority.stella-ops.local/console","/console/filters","401"
"Microservice","/gateway","http://gateway.stella-ops.local",,
"Microservice","/scanner","http://scanner.stella-ops.local","/scanner/api/v1/agents","401"
"Microservice","/policyGateway","http://policy-gateway.stella-ops.local","/policyGateway","302"
"Microservice","/policyEngine","http://policy-engine.stella-ops.local","/policyEngine","302"
"Microservice","/concelier","http://concelier.stella-ops.local","/concelier/jobs","200"
"Microservice","/attestor","http://attestor.stella-ops.local","/attestor/api/v1/bundles","400"
"Microservice","/notify","http://notify.stella-ops.local","/notify/api/v1/notify/audit","400"
"Microservice","/notifier","http://notifier.stella-ops.local","/notifier/api/v2/ack","400"
"Microservice","/scheduler","http://scheduler.stella-ops.local","/scheduler/graphs/jobs","401"
"Microservice","/signals","http://signals.stella-ops.local","/signals/signals/ping","403"
"Microservice","/excititor","http://excititor.stella-ops.local","/excititor/vex/raw","400"
"Microservice","/findingsLedger","http://findings.stella-ops.local","/findingsLedger/v1/alerts","400"
"Microservice","/vexhub","https://vexhub.stella-ops.local","/vexhub/api/v1/vex/index","200"
"Microservice","/vexlens","http://vexlens.stella-ops.local","/vexlens/api/v1/vexlens/stats","200"
"Microservice","/orchestrator","http://orchestrator.stella-ops.local","/orchestrator/scale/load","200"
"Microservice","/taskrunner","http://taskrunner.stella-ops.local","/taskrunner","302"
"Microservice","/cartographer","http://cartographer.stella-ops.local",,
"Microservice","/reachgraph","http://reachgraph.stella-ops.local","/reachgraph/v1/cve-mappings/stats","400"
"Microservice","/doctor","http://doctor.stella-ops.local","/doctor/api/v1/doctor/checks","401"
"Microservice","/integrations","http://integrations.stella-ops.local","/integrations/api/v1/integrations","401"
"Microservice","/replay","http://replay.stella-ops.local","/replay/v1/pit/advisory/{cveId}","400"
"Microservice","/exportcenter","https://exportcenter.stella-ops.local","/exportcenter/exports","410"
"Microservice","/evidencelocker","https://evidencelocker.stella-ops.local","/evidencelocker/evidence/score","400"
"Microservice","/signer","http://signer.stella-ops.local","/signer","200"
"Microservice","/binaryindex","http://binaryindex.stella-ops.local","/binaryindex/api/v1/golden-sets","200"
"Microservice","/riskengine","http://riskengine.stella-ops.local","/riskengine/risk-scores/providers","200"
"Microservice","/vulnexplorer","http://vulnexplorer.stella-ops.local","/vulnexplorer/v1/vulns","400"
"Microservice","/sbomservice","http://sbomservice.stella-ops.local","/sbomservice/sbom/paths","400"
"Microservice","/advisoryai","http://advisoryai.stella-ops.local","/advisoryai/v1/evidence-packs","401"
"Microservice","/unknowns","http://unknowns.stella-ops.local","/unknowns/api/unknowns","400"
"Microservice","/timelineindexer","http://timelineindexer.stella-ops.local","/timelineindexer/timeline","401"
"Microservice","/opsmemory","http://opsmemory.stella-ops.local","/opsmemory/api/v1/opsmemory/stats","400"
"Microservice","/issuerdirectory","http://issuerdirectory.stella-ops.local","/issuerdirectory/issuer-directory/issuers","400"
"Microservice","/symbols","http://symbols.stella-ops.local","/symbols/v1/symbols/manifests","404"
"Microservice","/packsregistry","http://packsregistry.stella-ops.local","/packsregistry/api/v1/packs","403"
"Microservice","/registryTokenservice","http://registry-token.stella-ops.local",,
"Microservice","/airgapController","http://airgap-controller.stella-ops.local","/","200"
"Microservice","/airgapTime","http://airgap-time.stella-ops.local",,
"Microservice","/smremote","http://smremote.stella-ops.local","/","200"
1 RouteType RoutePath RouteTarget SelectedOpenApiPath StatusCode
2 Microservice /api/v1/release-orchestrator http://orchestrator.stella-ops.local/api/v1/release-orchestrator /api/v1/release-orchestrator/releases 200
3 Microservice /api/v1/vex https://vexhub.stella-ops.local/api/v1/vex /api/v1/vex/index 200
4 Microservice /api/v1/vexlens http://vexlens.stella-ops.local/api/v1/vexlens /api/v1/vexlens/stats 200
5 Microservice /api/v1/notify http://notify.stella-ops.local/api/v1/notify /api/v1/notify/audit 400
6 Microservice /api/v1/notifier http://notifier.stella-ops.local/api/v1/notifier
7 Microservice /api/v1/concelier http://concelier.stella-ops.local/api/v1/concelier /api/v1/concelier/bundles 200
8 Microservice /api/v1/platform http://platform.stella-ops.local/api/v1/platform /api/v1/platform/search 400
9 Microservice /api/v1/scanner http://scanner.stella-ops.local/api/v1/scanner
10 Microservice /api/v1/findings http://findings.stella-ops.local/api/v1/findings /api/v1/findings/summaries 200
11 Microservice /api/v1/integrations http://integrations.stella-ops.local/api/v1/integrations /api/v1/integrations 401
12 Microservice /api/v1/policy http://policy-gateway.stella-ops.local/api/v1/policy /api/v1/policy/gate/health 200
13 Microservice /api/v1/reachability http://reachgraph.stella-ops.local/api/v1/reachability
14 Microservice /api/v1/attestor http://attestor.stella-ops.local/api/v1/attestor /api/v1/attestor/predicates 200
15 Microservice /api/v1/attestations http://attestor.stella-ops.local/api/v1/attestations /api/v1/attestations 200
16 Microservice /api/v1/sbom http://sbomservice.stella-ops.local/api/v1/sbom
17 Microservice /api/v1/signals http://signals.stella-ops.local/api/v1/signals
18 Microservice /api/v1/orchestrator http://orchestrator.stella-ops.local/api/v1/orchestrator /api/v1/orchestrator/jobs 400
19 Microservice /api/v1/authority/quotas http://platform.stella-ops.local/api/v1/authority/quotas /api/v1/authority/quotas 400
20 Microservice /api/v1/authority https://authority.stella-ops.local/api/v1/authority /api/v1/authority/quotas 400
21 Microservice /api/v1/trust https://authority.stella-ops.local/api/v1/trust
22 Microservice /api/v1/evidence https://evidencelocker.stella-ops.local/api/v1/evidence /api/v1/evidence 200
23 Microservice /api/v1/proofs https://evidencelocker.stella-ops.local/api/v1/proofs
24 Microservice /api/v1/timeline http://timelineindexer.stella-ops.local/api/v1/timeline /api/v1/timeline 401
25 Microservice /api/v1/advisory-ai/adapters http://advisoryai.stella-ops.local/v1/advisory-ai/adapters / 200
26 Microservice /api/v1/advisory-ai http://advisoryai.stella-ops.local/api/v1/advisory-ai / 200
27 Microservice /api/v1/advisory http://advisoryai.stella-ops.local/api/v1/advisory / 200
28 Microservice /api/v1/vulnerabilities http://scanner.stella-ops.local/api/v1/vulnerabilities
29 Microservice /api/v1/watchlist http://scanner.stella-ops.local/api/v1/watchlist
30 Microservice /api/v1/resolve http://binaryindex.stella-ops.local/api/v1/resolve
31 Microservice /api/v1/ops/binaryindex http://binaryindex.stella-ops.local/api/v1/ops/binaryindex /api/v1/ops/binaryindex/cache 200
32 Microservice /api/v1/verdicts https://evidencelocker.stella-ops.local/api/v1/verdicts /api/v1/verdicts/{verdictId} 404
33 Microservice /api/v1/lineage http://sbomservice.stella-ops.local/api/v1/lineage /api/v1/lineage/diff 400
34 Microservice /api/v1/export https://exportcenter.stella-ops.local/api/v1/export
35 Microservice /api/v1/triage http://scanner.stella-ops.local/api/v1/triage /api/v1/triage/inbox 401
36 Microservice /api/v1/governance http://policy-gateway.stella-ops.local/api/v1/governance /api/v1/governance/audit/events 400
37 Microservice /api/v1/determinization http://policy-engine.stella-ops.local/api/v1/determinization
38 Microservice /api/v1/opsmemory http://opsmemory.stella-ops.local/api/v1/opsmemory /api/v1/opsmemory/stats 400
39 Microservice /api/v1/secrets http://scanner.stella-ops.local/api/v1/secrets /api/v1/secrets/config/rules/categories 401
40 Microservice /api/v1/sources http://sbomservice.stella-ops.local/api/v1/sources
41 Microservice /api/v1/workflows http://orchestrator.stella-ops.local/api/v1/workflows
42 Microservice /api/v1/witnesses http://attestor.stella-ops.local/api/v1/witnesses
43 Microservice /v1/evidence-packs https://evidencelocker.stella-ops.local/v1/evidence-packs
44 Microservice /v1/runs http://orchestrator.stella-ops.local/v1/runs /v1/runs/{id} 404
45 Microservice /v1/advisory-ai/adapters http://advisoryai.stella-ops.local/v1/advisory-ai/adapters / 200
46 Microservice /v1/advisory-ai http://advisoryai.stella-ops.local/v1/advisory-ai /v1/advisory-ai/consent 200
47 Microservice /v1/audit-bundles https://exportcenter.stella-ops.local/v1/audit-bundles /v1/audit-bundles 200
48 Microservice /policy http://policy-gateway.stella-ops.local /policyEngine 302
49 Microservice /api/cvss http://policy-gateway.stella-ops.local/api/cvss /api/cvss/policies 401
50 Microservice /api/policy http://policy-gateway.stella-ops.local/api/policy /api/policy/packs 401
51 Microservice /api/risk http://policy-engine.stella-ops.local/api/risk /api/risk/events 400
52 Microservice /api/analytics http://platform.stella-ops.local/api/analytics /api/analytics/backlog 400
53 Microservice /api/release-orchestrator http://orchestrator.stella-ops.local/api/release-orchestrator /api/release-orchestrator/releases 200
54 Microservice /api/releases http://orchestrator.stella-ops.local/api/releases
55 Microservice /api/approvals http://orchestrator.stella-ops.local/api/approvals
56 Microservice /api/gate http://policy-gateway.stella-ops.local/api/gate
57 Microservice /api/risk-budget http://policy-engine.stella-ops.local/api/risk-budget
58 Microservice /api/fix-verification http://scanner.stella-ops.local/api/fix-verification
59 Microservice /api/compare http://sbomservice.stella-ops.local/api/compare
60 Microservice /api/change-traces http://sbomservice.stella-ops.local/api/change-traces
61 Microservice /api/exceptions http://policy-gateway.stella-ops.local/api/exceptions
62 Microservice /api/verdicts https://evidencelocker.stella-ops.local/api/verdicts
63 Microservice /api/orchestrator http://orchestrator.stella-ops.local/api/orchestrator
64 Microservice /api/v1/gateway/rate-limits http://platform.stella-ops.local/api/v1/gateway/rate-limits /api/v1/gateway/rate-limits 400
65 Microservice /api/sbomservice http://sbomservice.stella-ops.local/api/sbomservice
66 Microservice /api/vuln-explorer http://vulnexplorer.stella-ops.local/api/vuln-explorer
67 Microservice /api/vex https://vexhub.stella-ops.local/api/vex
68 Microservice /api/admin http://platform.stella-ops.local/api/admin
69 Microservice /api/scheduler http://scheduler.stella-ops.local/api/scheduler
70 Microservice /api/v1/doctor/scheduler http://doctor-scheduler.stella-ops.local/api/v1/doctor/scheduler /api/v1/doctor/scheduler/trends 200
71 Microservice /api/doctor http://doctor.stella-ops.local/api/doctor
72 Microservice /api http://platform.stella-ops.local/api /api/v1/search 400
73 Microservice /connect https://authority.stella-ops.local/connect / 200
74 Microservice /.well-known https://authority.stella-ops.local/well-known / 200
75 Microservice /jwks https://authority.stella-ops.local/jwks / 200
76 Microservice /authority https://authority.stella-ops.local/authority /authority/audit/airgap 401
77 Microservice /console https://authority.stella-ops.local/console /console/filters 401
78 Microservice /gateway http://gateway.stella-ops.local
79 Microservice /scanner http://scanner.stella-ops.local /scanner/api/v1/agents 401
80 Microservice /policyGateway http://policy-gateway.stella-ops.local /policyGateway 302
81 Microservice /policyEngine http://policy-engine.stella-ops.local /policyEngine 302
82 Microservice /concelier http://concelier.stella-ops.local /concelier/jobs 200
83 Microservice /attestor http://attestor.stella-ops.local /attestor/api/v1/bundles 400
84 Microservice /notify http://notify.stella-ops.local /notify/api/v1/notify/audit 400
85 Microservice /notifier http://notifier.stella-ops.local /notifier/api/v2/ack 400
86 Microservice /scheduler http://scheduler.stella-ops.local /scheduler/graphs/jobs 401
87 Microservice /signals http://signals.stella-ops.local /signals/signals/ping 403
88 Microservice /excititor http://excititor.stella-ops.local /excititor/vex/raw 400
89 Microservice /findingsLedger http://findings.stella-ops.local /findingsLedger/v1/alerts 400
90 Microservice /vexhub https://vexhub.stella-ops.local /vexhub/api/v1/vex/index 200
91 Microservice /vexlens http://vexlens.stella-ops.local /vexlens/api/v1/vexlens/stats 200
92 Microservice /orchestrator http://orchestrator.stella-ops.local /orchestrator/scale/load 200
93 Microservice /taskrunner http://taskrunner.stella-ops.local /taskrunner 302
94 Microservice /cartographer http://cartographer.stella-ops.local
95 Microservice /reachgraph http://reachgraph.stella-ops.local /reachgraph/v1/cve-mappings/stats 400
96 Microservice /doctor http://doctor.stella-ops.local /doctor/api/v1/doctor/checks 401
97 Microservice /integrations http://integrations.stella-ops.local /integrations/api/v1/integrations 401
98 Microservice /replay http://replay.stella-ops.local /replay/v1/pit/advisory/{cveId} 400
99 Microservice /exportcenter https://exportcenter.stella-ops.local /exportcenter/exports 410
100 Microservice /evidencelocker https://evidencelocker.stella-ops.local /evidencelocker/evidence/score 400
101 Microservice /signer http://signer.stella-ops.local /signer 200
102 Microservice /binaryindex http://binaryindex.stella-ops.local /binaryindex/api/v1/golden-sets 200
103 Microservice /riskengine http://riskengine.stella-ops.local /riskengine/risk-scores/providers 200
104 Microservice /vulnexplorer http://vulnexplorer.stella-ops.local /vulnexplorer/v1/vulns 400
105 Microservice /sbomservice http://sbomservice.stella-ops.local /sbomservice/sbom/paths 400
106 Microservice /advisoryai http://advisoryai.stella-ops.local /advisoryai/v1/evidence-packs 401
107 Microservice /unknowns http://unknowns.stella-ops.local /unknowns/api/unknowns 400
108 Microservice /timelineindexer http://timelineindexer.stella-ops.local /timelineindexer/timeline 401
109 Microservice /opsmemory http://opsmemory.stella-ops.local /opsmemory/api/v1/opsmemory/stats 400
110 Microservice /issuerdirectory http://issuerdirectory.stella-ops.local /issuerdirectory/issuer-directory/issuers 400
111 Microservice /symbols http://symbols.stella-ops.local /symbols/v1/symbols/manifests 404
112 Microservice /packsregistry http://packsregistry.stella-ops.local /packsregistry/api/v1/packs 403
113 Microservice /registryTokenservice http://registry-token.stella-ops.local
114 Microservice /airgapController http://airgap-controller.stella-ops.local / 200
115 Microservice /airgapTime http://airgap-time.stella-ops.local
116 Microservice /smremote http://smremote.stella-ops.local / 200

View File

@@ -0,0 +1,119 @@
"RouteType","RoutePath","RouteTarget","SelectedOpenApiPath","StatusCode"
"ReverseProxy","/api/v1/release-orchestrator","http://orchestrator.stella-ops.local/api/v1/release-orchestrator","/api/v1/release-orchestrator/releases","200"
"ReverseProxy","/api/v1/vex","https://vexhub.stella-ops.local/api/v1/vex","/api/v1/vex/index","200"
"ReverseProxy","/api/v1/vexlens","http://vexlens.stella-ops.local/api/v1/vexlens","/api/v1/vexlens/stats","200"
"ReverseProxy","/api/v1/notify","http://notify.stella-ops.local/api/v1/notify","/api/v1/notify/audit","400"
"ReverseProxy","/api/v1/notifier","http://notifier.stella-ops.local/api/v1/notifier",,
"ReverseProxy","/api/v1/concelier","http://concelier.stella-ops.local/api/v1/concelier","/api/v1/concelier/bundles","200"
"ReverseProxy","/api/v1/platform","http://platform.stella-ops.local/api/v1/platform","/api/v1/platform/search","401"
"ReverseProxy","/api/v1/scanner","http://scanner.stella-ops.local/api/v1/scanner",,
"ReverseProxy","/api/v1/findings","http://findings.stella-ops.local/api/v1/findings","/api/v1/findings/summaries","401"
"ReverseProxy","/api/v1/integrations","http://integrations.stella-ops.local/api/v1/integrations","/api/v1/integrations","200"
"ReverseProxy","/api/v1/policy","http://policy-gateway.stella-ops.local/api/v1/policy","/api/v1/policy/schema","404"
"ReverseProxy","/api/v1/reachability","http://reachgraph.stella-ops.local/api/v1/reachability",,
"ReverseProxy","/api/v1/attestor","http://attestor.stella-ops.local/api/v1/attestor","/api/v1/attestor/policies","404"
"ReverseProxy","/api/v1/attestations","http://attestor.stella-ops.local/api/v1/attestations","/api/v1/attestations","401"
"ReverseProxy","/api/v1/sbom","http://sbomservice.stella-ops.local/api/v1/sbom","/api/v1/sbom/hot-lookup/components","404"
"ReverseProxy","/api/v1/signals","http://signals.stella-ops.local/api/v1/signals","/api/v1/signals/hot-symbols","404"
"ReverseProxy","/api/v1/orchestrator","http://orchestrator.stella-ops.local/api/v1/orchestrator","/api/v1/orchestrator/jobs","400"
"ReverseProxy","/api/v1/authority/quotas","http://platform.stella-ops.local/api/v1/authority/quotas","/api/v1/authority/quotas","401"
"ReverseProxy","/api/v1/authority","https://authority.stella-ops.local/api/v1/authority","/api/v1/authority/quotas","401"
"ReverseProxy","/api/v1/trust","https://authority.stella-ops.local/api/v1/trust",,
"ReverseProxy","/api/v1/evidence","https://evidencelocker.stella-ops.local/api/v1/evidence","/api/v1/evidence","401"
"ReverseProxy","/api/v1/proofs","https://evidencelocker.stella-ops.local/api/v1/proofs","/api/v1/proofs/id/{proofId}","401"
"ReverseProxy","/api/v1/timeline","http://timelineindexer.stella-ops.local/api/v1/timeline","/api/v1/timeline","401"
"ReverseProxy","/api/v1/advisory-ai/adapters","http://advisoryai.stella-ops.local/v1/advisory-ai/adapters",,
"ReverseProxy","/api/v1/advisory-ai","http://advisoryai.stella-ops.local/api/v1/advisory-ai",,
"ReverseProxy","/api/v1/advisory","http://advisoryai.stella-ops.local/api/v1/advisory","/api/v1/advisory-sources","404"
"ReverseProxy","/api/v1/vulnerabilities","http://scanner.stella-ops.local/api/v1/vulnerabilities",,
"ReverseProxy","/api/v1/watchlist","http://scanner.stella-ops.local/api/v1/watchlist","/api/v1/watchlist","404"
"ReverseProxy","/api/v1/resolve","http://binaryindex.stella-ops.local/api/v1/resolve",,
"ReverseProxy","/api/v1/ops/binaryindex","http://binaryindex.stella-ops.local/api/v1/ops/binaryindex","/api/v1/ops/binaryindex/cache","200"
"ReverseProxy","/api/v1/verdicts","https://evidencelocker.stella-ops.local/api/v1/verdicts","/api/v1/verdicts/{verdictId}","401"
"ReverseProxy","/api/v1/lineage","http://sbomservice.stella-ops.local/api/v1/lineage","/api/v1/lineage/diff","400"
"ReverseProxy","/api/v1/export","https://exportcenter.stella-ops.local/api/v1/export","/api/v1/export/jobs","401"
"ReverseProxy","/api/v1/triage","http://scanner.stella-ops.local/api/v1/triage","/api/v1/triage/inbox","400"
"ReverseProxy","/api/v1/governance","http://policy-gateway.stella-ops.local/api/v1/governance","/api/v1/governance/audit/events","400"
"ReverseProxy","/api/v1/determinization","http://policy-engine.stella-ops.local/api/v1/determinization",,
"ReverseProxy","/api/v1/opsmemory","http://opsmemory.stella-ops.local/api/v1/opsmemory","/api/v1/opsmemory/stats","400"
"ReverseProxy","/api/v1/secrets","http://scanner.stella-ops.local/api/v1/secrets","/api/v1/secrets/config/rules/categories","200"
"ReverseProxy","/api/v1/sources","http://sbomservice.stella-ops.local/api/v1/sources",,
"ReverseProxy","/api/v1/workflows","http://orchestrator.stella-ops.local/api/v1/workflows",,
"ReverseProxy","/api/v1/witnesses","http://attestor.stella-ops.local/api/v1/witnesses","/api/v1/witnesses","404"
"ReverseProxy","/v1/evidence-packs","https://evidencelocker.stella-ops.local/v1/evidence-packs","/v1/evidence-packs","401"
"ReverseProxy","/v1/runs","http://orchestrator.stella-ops.local/v1/runs","/v1/runs/{id}","404"
"ReverseProxy","/v1/advisory-ai/adapters","http://advisoryai.stella-ops.local/v1/advisory-ai/adapters","/","200"
"ReverseProxy","/v1/advisory-ai","http://advisoryai.stella-ops.local/v1/advisory-ai","/v1/advisory-ai/consent","200"
"ReverseProxy","/v1/audit-bundles","https://exportcenter.stella-ops.local/v1/audit-bundles","/v1/audit-bundles","200"
"ReverseProxy","/policy","http://policy-gateway.stella-ops.local","/policy/snapshots","404"
"ReverseProxy","/api/cvss","http://policy-gateway.stella-ops.local/api/cvss","/api/cvss/policies","401"
"ReverseProxy","/api/policy","http://policy-gateway.stella-ops.local/api/policy","/api/policy/packs","401"
"ReverseProxy","/api/risk","http://policy-engine.stella-ops.local/api/risk","/api/risk/events","401"
"ReverseProxy","/api/analytics","http://platform.stella-ops.local/api/analytics","/api/analytics/backlog","401"
"ReverseProxy","/api/release-orchestrator","http://orchestrator.stella-ops.local/api/release-orchestrator","/api/release-orchestrator/releases","200"
"ReverseProxy","/api/releases","http://orchestrator.stella-ops.local/api/releases",,
"ReverseProxy","/api/approvals","http://orchestrator.stella-ops.local/api/approvals",,
"ReverseProxy","/api/gate","http://policy-gateway.stella-ops.local/api/gate",,
"ReverseProxy","/api/risk-budget","http://policy-engine.stella-ops.local/api/risk-budget",,
"ReverseProxy","/api/fix-verification","http://scanner.stella-ops.local/api/fix-verification",,
"ReverseProxy","/api/compare","http://sbomservice.stella-ops.local/api/compare",,
"ReverseProxy","/api/change-traces","http://sbomservice.stella-ops.local/api/change-traces",,
"ReverseProxy","/api/exceptions","http://policy-gateway.stella-ops.local/api/exceptions",,
"ReverseProxy","/api/verdicts","https://evidencelocker.stella-ops.local/api/verdicts",,
"ReverseProxy","/api/orchestrator","http://orchestrator.stella-ops.local/api/orchestrator",,
"ReverseProxy","/api/v1/gateway/rate-limits","http://platform.stella-ops.local/api/v1/gateway/rate-limits","/api/v1/gateway/rate-limits","401"
"ReverseProxy","/api/sbomservice","http://sbomservice.stella-ops.local/api/sbomservice",,
"ReverseProxy","/api/vuln-explorer","http://vulnexplorer.stella-ops.local/api/vuln-explorer",,
"ReverseProxy","/api/vex","https://vexhub.stella-ops.local/api/vex",,
"ReverseProxy","/api/admin","http://platform.stella-ops.local/api/admin","/api/admin/plans","404"
"ReverseProxy","/api/scheduler","http://scheduler.stella-ops.local/api/scheduler",,
"ReverseProxy","/api/v1/doctor/scheduler","http://doctor-scheduler.stella-ops.local/api/v1/doctor/scheduler","/api/v1/doctor/scheduler/trends","200"
"ReverseProxy","/api/doctor","http://doctor.stella-ops.local/api/doctor",,
"ReverseProxy","/api","http://platform.stella-ops.local/api","/api/v2/ack","404"
"ReverseProxy","/platform","http://platform.stella-ops.local/platform","/platform/envsettings/db","401"
"ReverseProxy","/connect","https://authority.stella-ops.local/connect","/","200"
"ReverseProxy","/.well-known","https://authority.stella-ops.local/well-known",,
"ReverseProxy","/jwks","https://authority.stella-ops.local/jwks","/","200"
"ReverseProxy","/authority","https://authority.stella-ops.local/authority","/authority/audit/airgap","401"
"ReverseProxy","/console","https://authority.stella-ops.local/console","/console/vex","404"
"ReverseProxy","/rekor","http://rekor.stella-ops.local:3322",,
"ReverseProxy","/envsettings.json","http://platform.stella-ops.local/platform/envsettings.json","/","200"
"ReverseProxy","/gateway","http://gateway.stella-ops.local",,
"ReverseProxy","/scanner","http://scanner.stella-ops.local",,
"ReverseProxy","/policyGateway","http://policy-gateway.stella-ops.local",,
"ReverseProxy","/policyEngine","http://policy-engine.stella-ops.local",,
"ReverseProxy","/concelier","http://concelier.stella-ops.local","/concelier/observations","404"
"ReverseProxy","/attestor","http://attestor.stella-ops.local",,
"ReverseProxy","/notify","http://notify.stella-ops.local",,
"ReverseProxy","/notifier","http://notifier.stella-ops.local",,
"ReverseProxy","/scheduler","http://scheduler.stella-ops.local",,
"ReverseProxy","/signals","http://signals.stella-ops.local","/signals/ping","404"
"ReverseProxy","/excititor","http://excititor.stella-ops.local","/excititor/status","404"
"ReverseProxy","/findingsLedger","http://findings.stella-ops.local",,
"ReverseProxy","/vexhub","https://vexhub.stella-ops.local",,
"ReverseProxy","/vexlens","http://vexlens.stella-ops.local",,
"ReverseProxy","/orchestrator","http://orchestrator.stella-ops.local",,
"ReverseProxy","/taskrunner","http://taskrunner.stella-ops.local",,
"ReverseProxy","/cartographer","http://cartographer.stella-ops.local",,
"ReverseProxy","/reachgraph","http://reachgraph.stella-ops.local",,
"ReverseProxy","/doctor","http://doctor.stella-ops.local",,
"ReverseProxy","/integrations","http://integrations.stella-ops.local",,
"ReverseProxy","/replay","http://replay.stella-ops.local",,
"ReverseProxy","/exportcenter","https://exportcenter.stella-ops.local",,
"ReverseProxy","/evidencelocker","https://evidencelocker.stella-ops.local",,
"ReverseProxy","/signer","http://signer.stella-ops.local",,
"ReverseProxy","/binaryindex","http://binaryindex.stella-ops.local",,
"ReverseProxy","/riskengine","http://riskengine.stella-ops.local",,
"ReverseProxy","/vulnexplorer","http://vulnexplorer.stella-ops.local",,
"ReverseProxy","/sbomservice","http://sbomservice.stella-ops.local",,
"ReverseProxy","/advisoryai","http://advisoryai.stella-ops.local",,
"ReverseProxy","/unknowns","http://unknowns.stella-ops.local",,
"ReverseProxy","/timelineindexer","http://timelineindexer.stella-ops.local",,
"ReverseProxy","/opsmemory","http://opsmemory.stella-ops.local",,
"ReverseProxy","/issuerdirectory","http://issuerdirectory.stella-ops.local",,
"ReverseProxy","/symbols","http://symbols.stella-ops.local",,
"ReverseProxy","/packsregistry","http://packsregistry.stella-ops.local",,
"ReverseProxy","/registryTokenservice","http://registry-token.stella-ops.local",,
"ReverseProxy","/airgapController","http://airgap-controller.stella-ops.local",,
"ReverseProxy","/airgapTime","http://airgap-time.stella-ops.local",,
"ReverseProxy","/smremote","http://smremote.stella-ops.local",,
1 RouteType RoutePath RouteTarget SelectedOpenApiPath StatusCode
2 ReverseProxy /api/v1/release-orchestrator http://orchestrator.stella-ops.local/api/v1/release-orchestrator /api/v1/release-orchestrator/releases 200
3 ReverseProxy /api/v1/vex https://vexhub.stella-ops.local/api/v1/vex /api/v1/vex/index 200
4 ReverseProxy /api/v1/vexlens http://vexlens.stella-ops.local/api/v1/vexlens /api/v1/vexlens/stats 200
5 ReverseProxy /api/v1/notify http://notify.stella-ops.local/api/v1/notify /api/v1/notify/audit 400
6 ReverseProxy /api/v1/notifier http://notifier.stella-ops.local/api/v1/notifier
7 ReverseProxy /api/v1/concelier http://concelier.stella-ops.local/api/v1/concelier /api/v1/concelier/bundles 200
8 ReverseProxy /api/v1/platform http://platform.stella-ops.local/api/v1/platform /api/v1/platform/search 401
9 ReverseProxy /api/v1/scanner http://scanner.stella-ops.local/api/v1/scanner
10 ReverseProxy /api/v1/findings http://findings.stella-ops.local/api/v1/findings /api/v1/findings/summaries 401
11 ReverseProxy /api/v1/integrations http://integrations.stella-ops.local/api/v1/integrations /api/v1/integrations 200
12 ReverseProxy /api/v1/policy http://policy-gateway.stella-ops.local/api/v1/policy /api/v1/policy/schema 404
13 ReverseProxy /api/v1/reachability http://reachgraph.stella-ops.local/api/v1/reachability
14 ReverseProxy /api/v1/attestor http://attestor.stella-ops.local/api/v1/attestor /api/v1/attestor/policies 404
15 ReverseProxy /api/v1/attestations http://attestor.stella-ops.local/api/v1/attestations /api/v1/attestations 401
16 ReverseProxy /api/v1/sbom http://sbomservice.stella-ops.local/api/v1/sbom /api/v1/sbom/hot-lookup/components 404
17 ReverseProxy /api/v1/signals http://signals.stella-ops.local/api/v1/signals /api/v1/signals/hot-symbols 404
18 ReverseProxy /api/v1/orchestrator http://orchestrator.stella-ops.local/api/v1/orchestrator /api/v1/orchestrator/jobs 400
19 ReverseProxy /api/v1/authority/quotas http://platform.stella-ops.local/api/v1/authority/quotas /api/v1/authority/quotas 401
20 ReverseProxy /api/v1/authority https://authority.stella-ops.local/api/v1/authority /api/v1/authority/quotas 401
21 ReverseProxy /api/v1/trust https://authority.stella-ops.local/api/v1/trust
22 ReverseProxy /api/v1/evidence https://evidencelocker.stella-ops.local/api/v1/evidence /api/v1/evidence 401
23 ReverseProxy /api/v1/proofs https://evidencelocker.stella-ops.local/api/v1/proofs /api/v1/proofs/id/{proofId} 401
24 ReverseProxy /api/v1/timeline http://timelineindexer.stella-ops.local/api/v1/timeline /api/v1/timeline 401
25 ReverseProxy /api/v1/advisory-ai/adapters http://advisoryai.stella-ops.local/v1/advisory-ai/adapters
26 ReverseProxy /api/v1/advisory-ai http://advisoryai.stella-ops.local/api/v1/advisory-ai
27 ReverseProxy /api/v1/advisory http://advisoryai.stella-ops.local/api/v1/advisory /api/v1/advisory-sources 404
28 ReverseProxy /api/v1/vulnerabilities http://scanner.stella-ops.local/api/v1/vulnerabilities
29 ReverseProxy /api/v1/watchlist http://scanner.stella-ops.local/api/v1/watchlist /api/v1/watchlist 404
30 ReverseProxy /api/v1/resolve http://binaryindex.stella-ops.local/api/v1/resolve
31 ReverseProxy /api/v1/ops/binaryindex http://binaryindex.stella-ops.local/api/v1/ops/binaryindex /api/v1/ops/binaryindex/cache 200
32 ReverseProxy /api/v1/verdicts https://evidencelocker.stella-ops.local/api/v1/verdicts /api/v1/verdicts/{verdictId} 401
33 ReverseProxy /api/v1/lineage http://sbomservice.stella-ops.local/api/v1/lineage /api/v1/lineage/diff 400
34 ReverseProxy /api/v1/export https://exportcenter.stella-ops.local/api/v1/export /api/v1/export/jobs 401
35 ReverseProxy /api/v1/triage http://scanner.stella-ops.local/api/v1/triage /api/v1/triage/inbox 400
36 ReverseProxy /api/v1/governance http://policy-gateway.stella-ops.local/api/v1/governance /api/v1/governance/audit/events 400
37 ReverseProxy /api/v1/determinization http://policy-engine.stella-ops.local/api/v1/determinization
38 ReverseProxy /api/v1/opsmemory http://opsmemory.stella-ops.local/api/v1/opsmemory /api/v1/opsmemory/stats 400
39 ReverseProxy /api/v1/secrets http://scanner.stella-ops.local/api/v1/secrets /api/v1/secrets/config/rules/categories 200
40 ReverseProxy /api/v1/sources http://sbomservice.stella-ops.local/api/v1/sources
41 ReverseProxy /api/v1/workflows http://orchestrator.stella-ops.local/api/v1/workflows
42 ReverseProxy /api/v1/witnesses http://attestor.stella-ops.local/api/v1/witnesses /api/v1/witnesses 404
43 ReverseProxy /v1/evidence-packs https://evidencelocker.stella-ops.local/v1/evidence-packs /v1/evidence-packs 401
44 ReverseProxy /v1/runs http://orchestrator.stella-ops.local/v1/runs /v1/runs/{id} 404
45 ReverseProxy /v1/advisory-ai/adapters http://advisoryai.stella-ops.local/v1/advisory-ai/adapters / 200
46 ReverseProxy /v1/advisory-ai http://advisoryai.stella-ops.local/v1/advisory-ai /v1/advisory-ai/consent 200
47 ReverseProxy /v1/audit-bundles https://exportcenter.stella-ops.local/v1/audit-bundles /v1/audit-bundles 200
48 ReverseProxy /policy http://policy-gateway.stella-ops.local /policy/snapshots 404
49 ReverseProxy /api/cvss http://policy-gateway.stella-ops.local/api/cvss /api/cvss/policies 401
50 ReverseProxy /api/policy http://policy-gateway.stella-ops.local/api/policy /api/policy/packs 401
51 ReverseProxy /api/risk http://policy-engine.stella-ops.local/api/risk /api/risk/events 401
52 ReverseProxy /api/analytics http://platform.stella-ops.local/api/analytics /api/analytics/backlog 401
53 ReverseProxy /api/release-orchestrator http://orchestrator.stella-ops.local/api/release-orchestrator /api/release-orchestrator/releases 200
54 ReverseProxy /api/releases http://orchestrator.stella-ops.local/api/releases
55 ReverseProxy /api/approvals http://orchestrator.stella-ops.local/api/approvals
56 ReverseProxy /api/gate http://policy-gateway.stella-ops.local/api/gate
57 ReverseProxy /api/risk-budget http://policy-engine.stella-ops.local/api/risk-budget
58 ReverseProxy /api/fix-verification http://scanner.stella-ops.local/api/fix-verification
59 ReverseProxy /api/compare http://sbomservice.stella-ops.local/api/compare
60 ReverseProxy /api/change-traces http://sbomservice.stella-ops.local/api/change-traces
61 ReverseProxy /api/exceptions http://policy-gateway.stella-ops.local/api/exceptions
62 ReverseProxy /api/verdicts https://evidencelocker.stella-ops.local/api/verdicts
63 ReverseProxy /api/orchestrator http://orchestrator.stella-ops.local/api/orchestrator
64 ReverseProxy /api/v1/gateway/rate-limits http://platform.stella-ops.local/api/v1/gateway/rate-limits /api/v1/gateway/rate-limits 401
65 ReverseProxy /api/sbomservice http://sbomservice.stella-ops.local/api/sbomservice
66 ReverseProxy /api/vuln-explorer http://vulnexplorer.stella-ops.local/api/vuln-explorer
67 ReverseProxy /api/vex https://vexhub.stella-ops.local/api/vex
68 ReverseProxy /api/admin http://platform.stella-ops.local/api/admin /api/admin/plans 404
69 ReverseProxy /api/scheduler http://scheduler.stella-ops.local/api/scheduler
70 ReverseProxy /api/v1/doctor/scheduler http://doctor-scheduler.stella-ops.local/api/v1/doctor/scheduler /api/v1/doctor/scheduler/trends 200
71 ReverseProxy /api/doctor http://doctor.stella-ops.local/api/doctor
72 ReverseProxy /api http://platform.stella-ops.local/api /api/v2/ack 404
73 ReverseProxy /platform http://platform.stella-ops.local/platform /platform/envsettings/db 401
74 ReverseProxy /connect https://authority.stella-ops.local/connect / 200
75 ReverseProxy /.well-known https://authority.stella-ops.local/well-known
76 ReverseProxy /jwks https://authority.stella-ops.local/jwks / 200
77 ReverseProxy /authority https://authority.stella-ops.local/authority /authority/audit/airgap 401
78 ReverseProxy /console https://authority.stella-ops.local/console /console/vex 404
79 ReverseProxy /rekor http://rekor.stella-ops.local:3322
80 ReverseProxy /envsettings.json http://platform.stella-ops.local/platform/envsettings.json / 200
81 ReverseProxy /gateway http://gateway.stella-ops.local
82 ReverseProxy /scanner http://scanner.stella-ops.local
83 ReverseProxy /policyGateway http://policy-gateway.stella-ops.local
84 ReverseProxy /policyEngine http://policy-engine.stella-ops.local
85 ReverseProxy /concelier http://concelier.stella-ops.local /concelier/observations 404
86 ReverseProxy /attestor http://attestor.stella-ops.local
87 ReverseProxy /notify http://notify.stella-ops.local
88 ReverseProxy /notifier http://notifier.stella-ops.local
89 ReverseProxy /scheduler http://scheduler.stella-ops.local
90 ReverseProxy /signals http://signals.stella-ops.local /signals/ping 404
91 ReverseProxy /excititor http://excititor.stella-ops.local /excititor/status 404
92 ReverseProxy /findingsLedger http://findings.stella-ops.local
93 ReverseProxy /vexhub https://vexhub.stella-ops.local
94 ReverseProxy /vexlens http://vexlens.stella-ops.local
95 ReverseProxy /orchestrator http://orchestrator.stella-ops.local
96 ReverseProxy /taskrunner http://taskrunner.stella-ops.local
97 ReverseProxy /cartographer http://cartographer.stella-ops.local
98 ReverseProxy /reachgraph http://reachgraph.stella-ops.local
99 ReverseProxy /doctor http://doctor.stella-ops.local
100 ReverseProxy /integrations http://integrations.stella-ops.local
101 ReverseProxy /replay http://replay.stella-ops.local
102 ReverseProxy /exportcenter https://exportcenter.stella-ops.local
103 ReverseProxy /evidencelocker https://evidencelocker.stella-ops.local
104 ReverseProxy /signer http://signer.stella-ops.local
105 ReverseProxy /binaryindex http://binaryindex.stella-ops.local
106 ReverseProxy /riskengine http://riskengine.stella-ops.local
107 ReverseProxy /vulnexplorer http://vulnexplorer.stella-ops.local
108 ReverseProxy /sbomservice http://sbomservice.stella-ops.local
109 ReverseProxy /advisoryai http://advisoryai.stella-ops.local
110 ReverseProxy /unknowns http://unknowns.stella-ops.local
111 ReverseProxy /timelineindexer http://timelineindexer.stella-ops.local
112 ReverseProxy /opsmemory http://opsmemory.stella-ops.local
113 ReverseProxy /issuerdirectory http://issuerdirectory.stella-ops.local
114 ReverseProxy /symbols http://symbols.stella-ops.local
115 ReverseProxy /packsregistry http://packsregistry.stella-ops.local
116 ReverseProxy /registryTokenservice http://registry-token.stella-ops.local
117 ReverseProxy /airgapController http://airgap-controller.stella-ops.local
118 ReverseProxy /airgapTime http://airgap-time.stella-ops.local
119 ReverseProxy /smremote http://smremote.stella-ops.local

View File

@@ -0,0 +1,2 @@
"RouteType","RoutePath","RouteTarget","SelectedOpenApiPath","StatusCode"
"StaticFiles","/","/app/wwwroot","/jwks","401"
1 RouteType RoutePath RouteTarget SelectedOpenApiPath StatusCode
2 StaticFiles / /app/wwwroot /jwks 401

View File

@@ -0,0 +1,2 @@
"RouteType","RoutePath","RouteTarget","SelectedOpenApiPath","StatusCode"
"StaticFiles","/","/app/wwwroot","/","200"
1 RouteType RoutePath RouteTarget SelectedOpenApiPath StatusCode
2 StaticFiles / /app/wwwroot / 200

View File

@@ -0,0 +1,33 @@
{
"generatedUtc": "2026-02-22T15:58:47.9702451Z",
"mode": "microservice",
"targets": [
{
"url": "https://127.1.0.1/openapi.json",
"samples": 15,
"p50Ms": 54.8,
"p95Ms": 69.98,
"minMs": 45.37,
"maxMs": 86.82,
"statusCodes": "200=15"
},
{
"url": "https://127.1.0.1/api/v1/timeline/events?limit=1",
"samples": 15,
"p50Ms": 18.39,
"p95Ms": 33.66,
"minMs": 17.16,
"maxMs": 41.44,
"statusCodes": "401=15"
},
{
"url": "https://127.1.0.1/api/v1/advisory-ai/adapters/llm/providers",
"samples": 15,
"p50Ms": 185.37,
"p95Ms": 189.69,
"minMs": 84.44,
"maxMs": 189.8,
"statusCodes": "403=15"
}
]
}

View File

@@ -0,0 +1,40 @@
{
"generatedUtc": "2026-02-22T15:58:52.2066363Z",
"baseline": "reverseproxy",
"candidate": "microservice",
"deltas": [
{
"url": "https://127.1.0.1/openapi.json",
"reverse_p50_ms": 71.57,
"micro_p50_ms": 54.8,
"delta_p50_ms": -16.77,
"reverse_p95_ms": 85.53,
"micro_p95_ms": 69.98,
"delta_p95_ms": -15.55,
"reverse_status_codes": "200=15",
"micro_status_codes": "200=15"
},
{
"url": "https://127.1.0.1/api/v1/timeline/events?limit=1",
"reverse_p50_ms": 16.51,
"micro_p50_ms": 18.39,
"delta_p50_ms": 1.88,
"reverse_p95_ms": 18.67,
"micro_p95_ms": 33.66,
"delta_p95_ms": 14.99,
"reverse_status_codes": "401=15",
"micro_status_codes": "401=15"
},
{
"url": "https://127.1.0.1/api/v1/advisory-ai/adapters/llm/providers",
"reverse_p50_ms": 16.03,
"micro_p50_ms": 185.37,
"delta_p50_ms": 169.34,
"reverse_p95_ms": 17.49,
"micro_p95_ms": 189.69,
"delta_p95_ms": 172.20,
"reverse_status_codes": "403=15",
"micro_status_codes": "403=15"
}
]
}

View File

@@ -0,0 +1,33 @@
{
"generatedUtc": "2026-02-22T15:56:44.2272953Z",
"mode": "reverseproxy",
"targets": [
{
"url": "https://127.1.0.1/openapi.json",
"samples": 15,
"p50Ms": 71.57,
"p95Ms": 85.53,
"minMs": 63,
"maxMs": 88.26,
"statusCodes": "200=15"
},
{
"url": "https://127.1.0.1/api/v1/timeline/events?limit=1",
"samples": 15,
"p50Ms": 16.51,
"p95Ms": 18.67,
"minMs": 14.32,
"maxMs": 24.53,
"statusCodes": "401=15"
},
{
"url": "https://127.1.0.1/api/v1/advisory-ai/adapters/llm/providers",
"samples": 15,
"p50Ms": 16.03,
"p95Ms": 17.49,
"minMs": 13.59,
"maxMs": 98.31,
"statusCodes": "403=15"
}
]
}

View File

@@ -0,0 +1,611 @@
-- Authority Schema: Consolidated Initial Schema
-- Consolidated from migrations 001-005 (pre_1.0 archived)
-- Creates the complete authority schema for IAM, tenants, users, tokens, RLS, and audit
-- ============================================================================
-- SECTION 1: Schema Creation
-- ============================================================================
CREATE SCHEMA IF NOT EXISTS authority;
CREATE SCHEMA IF NOT EXISTS authority_app;
-- ============================================================================
-- SECTION 2: Helper Functions
-- ============================================================================
-- Function to update updated_at timestamp
CREATE OR REPLACE FUNCTION authority.update_updated_at()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- Tenant context helper function for RLS
CREATE OR REPLACE FUNCTION authority_app.require_current_tenant()
RETURNS TEXT
LANGUAGE plpgsql STABLE SECURITY DEFINER
AS $$
DECLARE
v_tenant TEXT;
BEGIN
v_tenant := current_setting('app.tenant_id', true);
IF v_tenant IS NULL OR v_tenant = '' THEN
RAISE EXCEPTION 'app.tenant_id session variable not set'
USING HINT = 'Set via: SELECT set_config(''app.tenant_id'', ''<tenant>'', false)',
ERRCODE = 'P0001';
END IF;
RETURN v_tenant;
END;
$$;
REVOKE ALL ON FUNCTION authority_app.require_current_tenant() FROM PUBLIC;
-- ============================================================================
-- SECTION 3: Core Tables
-- ============================================================================
-- Tenants table (NOT RLS-protected - defines tenant boundaries)
CREATE TABLE IF NOT EXISTS authority.tenants (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id TEXT NOT NULL UNIQUE,
name TEXT NOT NULL,
display_name TEXT,
status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'suspended', 'deleted')),
settings JSONB NOT NULL DEFAULT '{}',
metadata JSONB NOT NULL DEFAULT '{}',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
created_by TEXT,
updated_by TEXT
);
CREATE INDEX idx_tenants_status ON authority.tenants(status);
CREATE INDEX idx_tenants_created_at ON authority.tenants(created_at);
COMMENT ON TABLE authority.tenants IS
'Tenant registry. Not RLS-protected - defines tenant boundaries for the system.';
-- Users table
CREATE TABLE IF NOT EXISTS authority.users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id TEXT NOT NULL REFERENCES authority.tenants(tenant_id),
username TEXT NOT NULL,
email TEXT,
display_name TEXT,
password_hash TEXT,
password_salt TEXT,
enabled BOOLEAN NOT NULL DEFAULT TRUE,
password_algorithm TEXT DEFAULT 'argon2id',
status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'inactive', 'locked', 'deleted')),
email_verified BOOLEAN NOT NULL DEFAULT FALSE,
mfa_enabled BOOLEAN NOT NULL DEFAULT FALSE,
mfa_secret TEXT,
mfa_backup_codes TEXT,
failed_login_attempts INT NOT NULL DEFAULT 0,
locked_until TIMESTAMPTZ,
last_login_at TIMESTAMPTZ,
password_changed_at TIMESTAMPTZ,
last_password_change_at TIMESTAMPTZ,
password_expires_at TIMESTAMPTZ,
settings JSONB NOT NULL DEFAULT '{}',
metadata JSONB NOT NULL DEFAULT '{}',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
created_by TEXT,
updated_by TEXT,
UNIQUE(tenant_id, username),
UNIQUE(tenant_id, email)
);
CREATE INDEX idx_users_tenant_id ON authority.users(tenant_id);
CREATE INDEX idx_users_status ON authority.users(tenant_id, status);
CREATE INDEX idx_users_email ON authority.users(tenant_id, email);
-- Roles table
CREATE TABLE IF NOT EXISTS authority.roles (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id TEXT NOT NULL REFERENCES authority.tenants(tenant_id),
name TEXT NOT NULL,
display_name TEXT,
description TEXT,
is_system BOOLEAN NOT NULL DEFAULT FALSE,
metadata JSONB NOT NULL DEFAULT '{}',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE(tenant_id, name)
);
CREATE INDEX idx_roles_tenant_id ON authority.roles(tenant_id);
-- Permissions table
CREATE TABLE IF NOT EXISTS authority.permissions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id TEXT NOT NULL REFERENCES authority.tenants(tenant_id),
name TEXT NOT NULL,
resource TEXT NOT NULL,
action TEXT NOT NULL,
description TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE(tenant_id, name)
);
CREATE INDEX idx_permissions_tenant_id ON authority.permissions(tenant_id);
CREATE INDEX idx_permissions_resource ON authority.permissions(tenant_id, resource);
-- Role-Permission assignments
CREATE TABLE IF NOT EXISTS authority.role_permissions (
role_id UUID NOT NULL REFERENCES authority.roles(id) ON DELETE CASCADE,
permission_id UUID NOT NULL REFERENCES authority.permissions(id) ON DELETE CASCADE,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
PRIMARY KEY (role_id, permission_id)
);
-- User-Role assignments
CREATE TABLE IF NOT EXISTS authority.user_roles (
user_id UUID NOT NULL REFERENCES authority.users(id) ON DELETE CASCADE,
role_id UUID NOT NULL REFERENCES authority.roles(id) ON DELETE CASCADE,
granted_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
granted_by TEXT,
expires_at TIMESTAMPTZ,
PRIMARY KEY (user_id, role_id)
);
-- API Keys table
CREATE TABLE IF NOT EXISTS authority.api_keys (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id TEXT NOT NULL REFERENCES authority.tenants(tenant_id),
user_id UUID REFERENCES authority.users(id) ON DELETE CASCADE,
name TEXT NOT NULL,
key_hash TEXT NOT NULL,
key_prefix TEXT NOT NULL,
scopes TEXT[] NOT NULL DEFAULT '{}',
status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'revoked', 'expired')),
last_used_at TIMESTAMPTZ,
expires_at TIMESTAMPTZ,
metadata JSONB NOT NULL DEFAULT '{}',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
revoked_at TIMESTAMPTZ,
revoked_by TEXT
);
CREATE INDEX idx_api_keys_tenant_id ON authority.api_keys(tenant_id);
CREATE INDEX idx_api_keys_key_prefix ON authority.api_keys(key_prefix);
CREATE INDEX idx_api_keys_user_id ON authority.api_keys(user_id);
CREATE INDEX idx_api_keys_status ON authority.api_keys(tenant_id, status);
-- Tokens table (access tokens)
CREATE TABLE IF NOT EXISTS authority.tokens (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id TEXT NOT NULL REFERENCES authority.tenants(tenant_id),
user_id UUID REFERENCES authority.users(id) ON DELETE CASCADE,
token_hash TEXT NOT NULL UNIQUE,
token_type TEXT NOT NULL DEFAULT 'access' CHECK (token_type IN ('access', 'refresh', 'api')),
scopes TEXT[] NOT NULL DEFAULT '{}',
client_id TEXT,
issued_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
expires_at TIMESTAMPTZ NOT NULL,
revoked_at TIMESTAMPTZ,
revoked_by TEXT,
metadata JSONB NOT NULL DEFAULT '{}'
);
CREATE INDEX idx_tokens_tenant_id ON authority.tokens(tenant_id);
CREATE INDEX idx_tokens_user_id ON authority.tokens(user_id);
CREATE INDEX idx_tokens_expires_at ON authority.tokens(expires_at);
CREATE INDEX idx_tokens_token_hash ON authority.tokens(token_hash);
-- Refresh Tokens table
CREATE TABLE IF NOT EXISTS authority.refresh_tokens (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id TEXT NOT NULL REFERENCES authority.tenants(tenant_id),
user_id UUID NOT NULL REFERENCES authority.users(id) ON DELETE CASCADE,
token_hash TEXT NOT NULL UNIQUE,
access_token_id UUID REFERENCES authority.tokens(id) ON DELETE SET NULL,
client_id TEXT,
issued_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
expires_at TIMESTAMPTZ NOT NULL,
revoked_at TIMESTAMPTZ,
revoked_by TEXT,
replaced_by UUID,
metadata JSONB NOT NULL DEFAULT '{}'
);
CREATE INDEX idx_refresh_tokens_tenant_id ON authority.refresh_tokens(tenant_id);
CREATE INDEX idx_refresh_tokens_user_id ON authority.refresh_tokens(user_id);
CREATE INDEX idx_refresh_tokens_expires_at ON authority.refresh_tokens(expires_at);
-- Sessions table
CREATE TABLE IF NOT EXISTS authority.sessions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id TEXT NOT NULL REFERENCES authority.tenants(tenant_id),
user_id UUID NOT NULL REFERENCES authority.users(id) ON DELETE CASCADE,
session_token_hash TEXT NOT NULL UNIQUE,
ip_address TEXT,
user_agent TEXT,
started_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
last_activity_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
expires_at TIMESTAMPTZ NOT NULL,
ended_at TIMESTAMPTZ,
end_reason TEXT,
metadata JSONB NOT NULL DEFAULT '{}'
);
CREATE INDEX idx_sessions_tenant_id ON authority.sessions(tenant_id);
CREATE INDEX idx_sessions_user_id ON authority.sessions(user_id);
CREATE INDEX idx_sessions_expires_at ON authority.sessions(expires_at);
-- Audit log table
CREATE TABLE IF NOT EXISTS authority.audit (
id BIGSERIAL PRIMARY KEY,
tenant_id TEXT NOT NULL,
user_id UUID,
action TEXT NOT NULL,
resource_type TEXT NOT NULL,
resource_id TEXT,
old_value JSONB,
new_value JSONB,
ip_address TEXT,
user_agent TEXT,
correlation_id TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_audit_tenant_id ON authority.audit(tenant_id);
CREATE INDEX idx_audit_user_id ON authority.audit(user_id);
CREATE INDEX idx_audit_action ON authority.audit(action);
CREATE INDEX idx_audit_resource ON authority.audit(resource_type, resource_id);
CREATE INDEX idx_audit_created_at ON authority.audit(created_at);
CREATE INDEX idx_audit_correlation_id ON authority.audit(correlation_id);
-- ============================================================================
-- SECTION 4: OIDC and Mongo Store Equivalent Tables
-- ============================================================================
-- Bootstrap invites
CREATE TABLE IF NOT EXISTS authority.bootstrap_invites (
id TEXT PRIMARY KEY,
token TEXT NOT NULL UNIQUE,
type TEXT NOT NULL,
provider TEXT,
target TEXT,
expires_at TIMESTAMPTZ NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
issued_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
issued_by TEXT,
reserved_until TIMESTAMPTZ,
reserved_by TEXT,
consumed BOOLEAN NOT NULL DEFAULT FALSE,
status TEXT NOT NULL DEFAULT 'pending',
metadata JSONB NOT NULL DEFAULT '{}'
);
-- Service accounts
CREATE TABLE IF NOT EXISTS authority.service_accounts (
id TEXT PRIMARY KEY,
account_id TEXT NOT NULL UNIQUE,
tenant TEXT NOT NULL,
display_name TEXT NOT NULL,
description TEXT,
enabled BOOLEAN NOT NULL DEFAULT TRUE,
allowed_scopes TEXT[] NOT NULL DEFAULT '{}',
authorized_clients TEXT[] NOT NULL DEFAULT '{}',
attributes JSONB NOT NULL DEFAULT '{}',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_service_accounts_tenant ON authority.service_accounts(tenant);
-- Clients
CREATE TABLE IF NOT EXISTS authority.clients (
id TEXT PRIMARY KEY,
client_id TEXT NOT NULL UNIQUE,
client_secret TEXT,
secret_hash TEXT,
display_name TEXT,
description TEXT,
plugin TEXT,
sender_constraint TEXT,
enabled BOOLEAN NOT NULL DEFAULT TRUE,
redirect_uris TEXT[] NOT NULL DEFAULT '{}',
post_logout_redirect_uris TEXT[] NOT NULL DEFAULT '{}',
allowed_scopes TEXT[] NOT NULL DEFAULT '{}',
allowed_grant_types TEXT[] NOT NULL DEFAULT '{}',
require_client_secret BOOLEAN NOT NULL DEFAULT TRUE,
require_pkce BOOLEAN NOT NULL DEFAULT FALSE,
allow_plain_text_pkce BOOLEAN NOT NULL DEFAULT FALSE,
client_type TEXT,
properties JSONB NOT NULL DEFAULT '{}',
certificate_bindings JSONB NOT NULL DEFAULT '[]',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- Revocations
CREATE TABLE IF NOT EXISTS authority.revocations (
id TEXT PRIMARY KEY,
category TEXT NOT NULL,
revocation_id TEXT NOT NULL,
subject_id TEXT,
client_id TEXT,
token_id TEXT,
reason TEXT NOT NULL,
reason_description TEXT,
revoked_at TIMESTAMPTZ NOT NULL,
effective_at TIMESTAMPTZ NOT NULL,
expires_at TIMESTAMPTZ,
metadata JSONB NOT NULL DEFAULT '{}'
);
CREATE UNIQUE INDEX IF NOT EXISTS idx_revocations_category_revocation_id
ON authority.revocations(category, revocation_id);
-- Login attempts
CREATE TABLE IF NOT EXISTS authority.login_attempts (
id TEXT PRIMARY KEY,
subject_id TEXT,
client_id TEXT,
event_type TEXT NOT NULL,
outcome TEXT NOT NULL,
reason TEXT,
ip_address TEXT,
user_agent TEXT,
occurred_at TIMESTAMPTZ NOT NULL,
properties JSONB NOT NULL DEFAULT '[]'
);
CREATE INDEX IF NOT EXISTS idx_login_attempts_subject ON authority.login_attempts(subject_id, occurred_at DESC);
-- OIDC tokens
CREATE TABLE IF NOT EXISTS authority.oidc_tokens (
id TEXT PRIMARY KEY,
token_id TEXT NOT NULL UNIQUE,
subject_id TEXT,
client_id TEXT,
token_type TEXT NOT NULL,
reference_id TEXT,
created_at TIMESTAMPTZ NOT NULL,
expires_at TIMESTAMPTZ,
redeemed_at TIMESTAMPTZ,
payload TEXT,
properties JSONB NOT NULL DEFAULT '{}'
);
CREATE INDEX IF NOT EXISTS idx_oidc_tokens_subject ON authority.oidc_tokens(subject_id);
CREATE INDEX IF NOT EXISTS idx_oidc_tokens_client ON authority.oidc_tokens(client_id);
CREATE INDEX IF NOT EXISTS idx_oidc_tokens_reference ON authority.oidc_tokens(reference_id);
-- OIDC refresh tokens
CREATE TABLE IF NOT EXISTS authority.oidc_refresh_tokens (
id TEXT PRIMARY KEY,
token_id TEXT NOT NULL UNIQUE,
subject_id TEXT,
client_id TEXT,
handle TEXT,
created_at TIMESTAMPTZ NOT NULL,
expires_at TIMESTAMPTZ,
consumed_at TIMESTAMPTZ,
payload TEXT
);
CREATE INDEX IF NOT EXISTS idx_oidc_refresh_tokens_subject ON authority.oidc_refresh_tokens(subject_id);
CREATE INDEX IF NOT EXISTS idx_oidc_refresh_tokens_handle ON authority.oidc_refresh_tokens(handle);
-- Airgap audit
CREATE TABLE IF NOT EXISTS authority.airgap_audit (
id TEXT PRIMARY KEY,
event_type TEXT NOT NULL,
operator_id TEXT,
component_id TEXT,
outcome TEXT NOT NULL,
reason TEXT,
occurred_at TIMESTAMPTZ NOT NULL,
properties JSONB NOT NULL DEFAULT '[]'
);
CREATE INDEX IF NOT EXISTS idx_airgap_audit_occurred_at ON authority.airgap_audit(occurred_at DESC);
-- Revocation export state (singleton row with optimistic concurrency)
CREATE TABLE IF NOT EXISTS authority.revocation_export_state (
id INT PRIMARY KEY DEFAULT 1,
sequence BIGINT NOT NULL DEFAULT 0,
bundle_id TEXT,
issued_at TIMESTAMPTZ
);
-- Offline Kit Audit
CREATE TABLE IF NOT EXISTS authority.offline_kit_audit (
event_id UUID PRIMARY KEY,
tenant_id TEXT NOT NULL,
event_type TEXT NOT NULL,
timestamp TIMESTAMPTZ NOT NULL,
actor TEXT NOT NULL,
details JSONB NOT NULL,
result TEXT NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_offline_kit_audit_ts ON authority.offline_kit_audit(timestamp DESC);
CREATE INDEX IF NOT EXISTS idx_offline_kit_audit_type ON authority.offline_kit_audit(event_type);
CREATE INDEX IF NOT EXISTS idx_offline_kit_audit_tenant_ts ON authority.offline_kit_audit(tenant_id, timestamp DESC);
CREATE INDEX IF NOT EXISTS idx_offline_kit_audit_result ON authority.offline_kit_audit(tenant_id, result, timestamp DESC);
-- Verdict manifests table
CREATE TABLE IF NOT EXISTS authority.verdict_manifests (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
manifest_id TEXT NOT NULL,
tenant TEXT NOT NULL,
asset_digest TEXT NOT NULL,
vulnerability_id TEXT NOT NULL,
inputs_json JSONB NOT NULL,
status TEXT NOT NULL CHECK (status IN ('affected', 'not_affected', 'fixed', 'under_investigation')),
confidence DOUBLE PRECISION NOT NULL CHECK (confidence >= 0 AND confidence <= 1),
result_json JSONB NOT NULL,
policy_hash TEXT NOT NULL,
lattice_version TEXT NOT NULL,
evaluated_at TIMESTAMPTZ NOT NULL,
manifest_digest TEXT NOT NULL,
signature_base64 TEXT,
rekor_log_id TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
CONSTRAINT uq_verdict_manifest_id UNIQUE (tenant, manifest_id)
);
CREATE INDEX IF NOT EXISTS idx_verdict_asset_vuln
ON authority.verdict_manifests(tenant, asset_digest, vulnerability_id);
CREATE INDEX IF NOT EXISTS idx_verdict_policy
ON authority.verdict_manifests(tenant, policy_hash, lattice_version);
CREATE INDEX IF NOT EXISTS idx_verdict_time
ON authority.verdict_manifests USING BRIN (evaluated_at);
CREATE UNIQUE INDEX IF NOT EXISTS idx_verdict_replay
ON authority.verdict_manifests(tenant, asset_digest, vulnerability_id, policy_hash, lattice_version);
CREATE INDEX IF NOT EXISTS idx_verdict_digest
ON authority.verdict_manifests(manifest_digest);
COMMENT ON TABLE authority.verdict_manifests IS 'VEX verdict manifests for deterministic replay verification';
-- ============================================================================
-- SECTION 5: Triggers
-- ============================================================================
CREATE TRIGGER trg_tenants_updated_at
BEFORE UPDATE ON authority.tenants
FOR EACH ROW EXECUTE FUNCTION authority.update_updated_at();
CREATE TRIGGER trg_users_updated_at
BEFORE UPDATE ON authority.users
FOR EACH ROW EXECUTE FUNCTION authority.update_updated_at();
CREATE TRIGGER trg_roles_updated_at
BEFORE UPDATE ON authority.roles
FOR EACH ROW EXECUTE FUNCTION authority.update_updated_at();
-- ============================================================================
-- SECTION 6: Row-Level Security
-- ============================================================================
-- authority.users
ALTER TABLE authority.users ENABLE ROW LEVEL SECURITY;
ALTER TABLE authority.users FORCE ROW LEVEL SECURITY;
CREATE POLICY users_tenant_isolation ON authority.users
FOR ALL
USING (tenant_id = authority_app.require_current_tenant())
WITH CHECK (tenant_id = authority_app.require_current_tenant());
-- authority.roles
ALTER TABLE authority.roles ENABLE ROW LEVEL SECURITY;
ALTER TABLE authority.roles FORCE ROW LEVEL SECURITY;
CREATE POLICY roles_tenant_isolation ON authority.roles
FOR ALL
USING (tenant_id = authority_app.require_current_tenant())
WITH CHECK (tenant_id = authority_app.require_current_tenant());
-- authority.permissions
ALTER TABLE authority.permissions ENABLE ROW LEVEL SECURITY;
ALTER TABLE authority.permissions FORCE ROW LEVEL SECURITY;
CREATE POLICY permissions_tenant_isolation ON authority.permissions
FOR ALL
USING (tenant_id = authority_app.require_current_tenant())
WITH CHECK (tenant_id = authority_app.require_current_tenant());
-- authority.role_permissions (FK-based, inherits from roles)
ALTER TABLE authority.role_permissions ENABLE ROW LEVEL SECURITY;
ALTER TABLE authority.role_permissions FORCE ROW LEVEL SECURITY;
CREATE POLICY role_permissions_tenant_isolation ON authority.role_permissions
FOR ALL
USING (
role_id IN (
SELECT id FROM authority.roles
WHERE tenant_id = authority_app.require_current_tenant()
)
);
-- authority.user_roles (FK-based, inherits from users)
ALTER TABLE authority.user_roles ENABLE ROW LEVEL SECURITY;
ALTER TABLE authority.user_roles FORCE ROW LEVEL SECURITY;
CREATE POLICY user_roles_tenant_isolation ON authority.user_roles
FOR ALL
USING (
user_id IN (
SELECT id FROM authority.users
WHERE tenant_id = authority_app.require_current_tenant()
)
);
-- authority.api_keys
ALTER TABLE authority.api_keys ENABLE ROW LEVEL SECURITY;
ALTER TABLE authority.api_keys FORCE ROW LEVEL SECURITY;
CREATE POLICY api_keys_tenant_isolation ON authority.api_keys
FOR ALL
USING (tenant_id = authority_app.require_current_tenant())
WITH CHECK (tenant_id = authority_app.require_current_tenant());
-- authority.tokens
ALTER TABLE authority.tokens ENABLE ROW LEVEL SECURITY;
ALTER TABLE authority.tokens FORCE ROW LEVEL SECURITY;
CREATE POLICY tokens_tenant_isolation ON authority.tokens
FOR ALL
USING (tenant_id = authority_app.require_current_tenant())
WITH CHECK (tenant_id = authority_app.require_current_tenant());
-- authority.refresh_tokens
ALTER TABLE authority.refresh_tokens ENABLE ROW LEVEL SECURITY;
ALTER TABLE authority.refresh_tokens FORCE ROW LEVEL SECURITY;
CREATE POLICY refresh_tokens_tenant_isolation ON authority.refresh_tokens
FOR ALL
USING (tenant_id = authority_app.require_current_tenant())
WITH CHECK (tenant_id = authority_app.require_current_tenant());
-- authority.sessions
ALTER TABLE authority.sessions ENABLE ROW LEVEL SECURITY;
ALTER TABLE authority.sessions FORCE ROW LEVEL SECURITY;
CREATE POLICY sessions_tenant_isolation ON authority.sessions
FOR ALL
USING (tenant_id = authority_app.require_current_tenant())
WITH CHECK (tenant_id = authority_app.require_current_tenant());
-- authority.audit
ALTER TABLE authority.audit ENABLE ROW LEVEL SECURITY;
ALTER TABLE authority.audit FORCE ROW LEVEL SECURITY;
CREATE POLICY audit_tenant_isolation ON authority.audit
FOR ALL
USING (tenant_id = authority_app.require_current_tenant())
WITH CHECK (tenant_id = authority_app.require_current_tenant());
-- authority.offline_kit_audit
ALTER TABLE authority.offline_kit_audit ENABLE ROW LEVEL SECURITY;
ALTER TABLE authority.offline_kit_audit FORCE ROW LEVEL SECURITY;
CREATE POLICY offline_kit_audit_tenant_isolation ON authority.offline_kit_audit
FOR ALL
USING (tenant_id = authority_app.require_current_tenant())
WITH CHECK (tenant_id = authority_app.require_current_tenant());
-- authority.verdict_manifests
ALTER TABLE authority.verdict_manifests ENABLE ROW LEVEL SECURITY;
CREATE POLICY verdict_tenant_isolation ON authority.verdict_manifests
USING (tenant = current_setting('app.current_tenant', true))
WITH CHECK (tenant = current_setting('app.current_tenant', true));
-- ============================================================================
-- SECTION 7: Roles and Permissions
-- ============================================================================
DO $$
BEGIN
IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'authority_admin') THEN
CREATE ROLE authority_admin WITH NOLOGIN BYPASSRLS;
END IF;
END
$$;
-- Grant permissions (if role exists)
DO $$
BEGIN
IF EXISTS (SELECT FROM pg_roles WHERE rolname = 'stellaops_app') THEN
GRANT SELECT, INSERT, UPDATE, DELETE ON authority.verdict_manifests TO stellaops_app;
GRANT USAGE ON SCHEMA authority TO stellaops_app;
END IF;
END
$$;

View File

@@ -0,0 +1,114 @@
-- Policy exceptions schema bootstrap for compose environments.
-- Ensures exception endpoints can start against a clean database.
CREATE EXTENSION IF NOT EXISTS pgcrypto;
CREATE SCHEMA IF NOT EXISTS policy;
CREATE TABLE IF NOT EXISTS policy.recheck_policies (
policy_id TEXT PRIMARY KEY,
tenant_id TEXT NOT NULL,
name TEXT NOT NULL,
conditions JSONB NOT NULL,
default_action TEXT NOT NULL,
is_active BOOLEAN NOT NULL DEFAULT TRUE,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_recheck_policies_tenant
ON policy.recheck_policies (tenant_id, is_active);
CREATE TABLE IF NOT EXISTS policy.exceptions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id TEXT NOT NULL,
name TEXT NOT NULL,
description TEXT,
rule_pattern TEXT,
resource_pattern TEXT,
artifact_pattern TEXT,
project_id TEXT,
reason TEXT NOT NULL,
status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('proposed', 'approved', 'active', 'expired', 'revoked')),
expires_at TIMESTAMPTZ,
approved_by TEXT,
approved_at TIMESTAMPTZ,
revoked_by TEXT,
revoked_at TIMESTAMPTZ,
metadata JSONB NOT NULL DEFAULT '{}',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
created_by TEXT,
exception_id TEXT NOT NULL UNIQUE,
version INTEGER NOT NULL DEFAULT 1,
type TEXT NOT NULL DEFAULT 'policy' CHECK (type IN ('vulnerability', 'policy', 'unknown', 'component')),
artifact_digest TEXT,
purl_pattern TEXT,
vulnerability_id TEXT,
policy_rule_id TEXT,
environments TEXT[] NOT NULL DEFAULT '{}',
owner_id TEXT,
requester_id TEXT,
approver_ids TEXT[] NOT NULL DEFAULT '{}',
reason_code TEXT DEFAULT 'other' CHECK (reason_code IN (
'false_positive',
'accepted_risk',
'compensating_control',
'test_only',
'vendor_not_affected',
'scheduled_fix',
'deprecation_in_progress',
'runtime_mitigation',
'network_isolation',
'other'
)),
rationale TEXT,
evidence_refs JSONB NOT NULL DEFAULT '[]',
compensating_controls JSONB NOT NULL DEFAULT '[]',
ticket_ref TEXT,
recheck_policy_id TEXT REFERENCES policy.recheck_policies(policy_id),
last_recheck_result JSONB,
last_recheck_at TIMESTAMPTZ,
UNIQUE (tenant_id, name)
);
CREATE INDEX IF NOT EXISTS idx_exceptions_tenant ON policy.exceptions(tenant_id);
CREATE INDEX IF NOT EXISTS idx_exceptions_status ON policy.exceptions(tenant_id, status);
CREATE INDEX IF NOT EXISTS idx_exceptions_expires ON policy.exceptions(expires_at) WHERE status = 'active';
CREATE INDEX IF NOT EXISTS idx_exceptions_project ON policy.exceptions(tenant_id, project_id);
CREATE INDEX IF NOT EXISTS idx_exceptions_vuln_id ON policy.exceptions(vulnerability_id) WHERE vulnerability_id IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_exceptions_purl ON policy.exceptions(purl_pattern) WHERE purl_pattern IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_exceptions_artifact ON policy.exceptions(artifact_digest) WHERE artifact_digest IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_exceptions_policy_rule ON policy.exceptions(policy_rule_id) WHERE policy_rule_id IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_exceptions_owner ON policy.exceptions(owner_id) WHERE owner_id IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_exceptions_recheck_policy ON policy.exceptions(tenant_id, recheck_policy_id) WHERE recheck_policy_id IS NOT NULL;
CREATE TABLE IF NOT EXISTS policy.exception_events (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
exception_id TEXT NOT NULL REFERENCES policy.exceptions(exception_id) ON DELETE CASCADE,
sequence_number INTEGER NOT NULL,
event_type TEXT NOT NULL CHECK (event_type IN (
'created',
'updated',
'approved',
'activated',
'extended',
'revoked',
'expired',
'evidence_attached',
'compensating_control_added',
'rejected'
)),
actor_id TEXT NOT NULL,
occurred_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
previous_status TEXT,
new_status TEXT NOT NULL,
new_version INTEGER NOT NULL,
description TEXT,
details JSONB NOT NULL DEFAULT '{}',
client_info TEXT,
UNIQUE (exception_id, sequence_number)
);
CREATE INDEX IF NOT EXISTS idx_exception_events_exception ON policy.exception_events(exception_id);
CREATE INDEX IF NOT EXISTS idx_exception_events_time ON policy.exception_events USING BRIN (occurred_at);

View File

@@ -0,0 +1,245 @@
-- Attestor Schema Migration 001: Initial Schema (Compacted)
-- Consolidated from 20251214000001_AddProofChainSchema.sql and 20251216_001_create_rekor_submission_queue.sql
-- for 1.0.0 release
-- Creates the proofchain schema for proof chain persistence and attestor schema for Rekor queue
-- ============================================================================
-- Extensions
-- ============================================================================
CREATE EXTENSION IF NOT EXISTS pgcrypto;
-- ============================================================================
-- Schema Creation
-- ============================================================================
CREATE SCHEMA IF NOT EXISTS proofchain;
CREATE SCHEMA IF NOT EXISTS attestor;
-- ============================================================================
-- Enum Types
-- ============================================================================
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'verification_result' AND typnamespace = 'proofchain'::regnamespace) THEN
CREATE TYPE proofchain.verification_result AS ENUM ('pass', 'fail', 'pending');
END IF;
END $$;
-- ============================================================================
-- ProofChain Schema Tables
-- ============================================================================
-- Trust anchors table (create first - no dependencies)
CREATE TABLE IF NOT EXISTS proofchain.trust_anchors (
anchor_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
purl_pattern TEXT NOT NULL,
allowed_keyids TEXT[] NOT NULL,
allowed_predicate_types TEXT[],
policy_ref TEXT,
policy_version TEXT,
revoked_keys TEXT[] DEFAULT '{}',
is_active BOOLEAN NOT NULL DEFAULT TRUE,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_trust_anchors_pattern ON proofchain.trust_anchors(purl_pattern);
CREATE INDEX IF NOT EXISTS idx_trust_anchors_active ON proofchain.trust_anchors(is_active) WHERE is_active = TRUE;
COMMENT ON TABLE proofchain.trust_anchors IS 'Trust anchor configurations for dependency verification';
COMMENT ON COLUMN proofchain.trust_anchors.purl_pattern IS 'PURL glob pattern (e.g., pkg:npm/*)';
COMMENT ON COLUMN proofchain.trust_anchors.revoked_keys IS 'Key IDs that have been revoked but may appear in old proofs';
-- SBOM entries table
CREATE TABLE IF NOT EXISTS proofchain.sbom_entries (
entry_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
bom_digest VARCHAR(64) NOT NULL,
purl TEXT NOT NULL,
version TEXT,
artifact_digest VARCHAR(64),
trust_anchor_id UUID REFERENCES proofchain.trust_anchors(anchor_id) ON DELETE SET NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
CONSTRAINT uq_sbom_entry UNIQUE (bom_digest, purl, version)
);
CREATE INDEX IF NOT EXISTS idx_sbom_entries_bom_digest ON proofchain.sbom_entries(bom_digest);
CREATE INDEX IF NOT EXISTS idx_sbom_entries_purl ON proofchain.sbom_entries(purl);
CREATE INDEX IF NOT EXISTS idx_sbom_entries_artifact ON proofchain.sbom_entries(artifact_digest);
CREATE INDEX IF NOT EXISTS idx_sbom_entries_anchor ON proofchain.sbom_entries(trust_anchor_id);
COMMENT ON TABLE proofchain.sbom_entries IS 'SBOM component entries with content-addressed identifiers';
COMMENT ON COLUMN proofchain.sbom_entries.bom_digest IS 'SHA-256 hash of the parent SBOM document';
COMMENT ON COLUMN proofchain.sbom_entries.purl IS 'Package URL (PURL) of the component';
COMMENT ON COLUMN proofchain.sbom_entries.artifact_digest IS 'SHA-256 hash of the component artifact if available';
-- DSSE envelopes table
CREATE TABLE IF NOT EXISTS proofchain.dsse_envelopes (
env_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
entry_id UUID NOT NULL REFERENCES proofchain.sbom_entries(entry_id) ON DELETE CASCADE,
predicate_type TEXT NOT NULL,
signer_keyid TEXT NOT NULL,
body_hash VARCHAR(64) NOT NULL,
envelope_blob_ref TEXT NOT NULL,
signed_at TIMESTAMPTZ NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
CONSTRAINT uq_dsse_envelope UNIQUE (entry_id, predicate_type, body_hash)
);
CREATE INDEX IF NOT EXISTS idx_dsse_entry_predicate ON proofchain.dsse_envelopes(entry_id, predicate_type);
CREATE INDEX IF NOT EXISTS idx_dsse_signer ON proofchain.dsse_envelopes(signer_keyid);
CREATE INDEX IF NOT EXISTS idx_dsse_body_hash ON proofchain.dsse_envelopes(body_hash);
COMMENT ON TABLE proofchain.dsse_envelopes IS 'Signed DSSE envelopes for proof chain statements';
COMMENT ON COLUMN proofchain.dsse_envelopes.predicate_type IS 'Predicate type URI (e.g., evidence.stella/v1)';
COMMENT ON COLUMN proofchain.dsse_envelopes.envelope_blob_ref IS 'Reference to blob storage (OCI, S3, file)';
-- Spines table
CREATE TABLE IF NOT EXISTS proofchain.spines (
entry_id UUID PRIMARY KEY REFERENCES proofchain.sbom_entries(entry_id) ON DELETE CASCADE,
bundle_id VARCHAR(64) NOT NULL,
evidence_ids TEXT[] NOT NULL,
reasoning_id VARCHAR(64) NOT NULL,
vex_id VARCHAR(64) NOT NULL,
anchor_id UUID REFERENCES proofchain.trust_anchors(anchor_id) ON DELETE SET NULL,
policy_version TEXT NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
CONSTRAINT uq_spine_bundle UNIQUE (bundle_id)
);
CREATE INDEX IF NOT EXISTS idx_spines_bundle ON proofchain.spines(bundle_id);
CREATE INDEX IF NOT EXISTS idx_spines_anchor ON proofchain.spines(anchor_id);
CREATE INDEX IF NOT EXISTS idx_spines_policy ON proofchain.spines(policy_version);
COMMENT ON TABLE proofchain.spines IS 'Proof spines linking evidence to verdicts via merkle aggregation';
COMMENT ON COLUMN proofchain.spines.bundle_id IS 'ProofBundleID (merkle root of all components)';
COMMENT ON COLUMN proofchain.spines.evidence_ids IS 'Array of EvidenceIDs in sorted order';
-- Rekor entries table
CREATE TABLE IF NOT EXISTS proofchain.rekor_entries (
dsse_sha256 VARCHAR(64) PRIMARY KEY,
log_index BIGINT NOT NULL,
log_id TEXT NOT NULL,
uuid TEXT NOT NULL,
integrated_time BIGINT NOT NULL,
inclusion_proof JSONB NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
env_id UUID REFERENCES proofchain.dsse_envelopes(env_id) ON DELETE SET NULL
);
CREATE INDEX IF NOT EXISTS idx_rekor_log_index ON proofchain.rekor_entries(log_index);
CREATE INDEX IF NOT EXISTS idx_rekor_log_id ON proofchain.rekor_entries(log_id);
CREATE INDEX IF NOT EXISTS idx_rekor_uuid ON proofchain.rekor_entries(uuid);
CREATE INDEX IF NOT EXISTS idx_rekor_env ON proofchain.rekor_entries(env_id);
COMMENT ON TABLE proofchain.rekor_entries IS 'Rekor transparency log entries for verification';
COMMENT ON COLUMN proofchain.rekor_entries.inclusion_proof IS 'Merkle inclusion proof from Rekor';
-- Audit log table
CREATE TABLE IF NOT EXISTS proofchain.audit_log (
log_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
operation TEXT NOT NULL,
entity_type TEXT NOT NULL,
entity_id TEXT NOT NULL,
actor TEXT,
details JSONB,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_audit_entity ON proofchain.audit_log(entity_type, entity_id);
CREATE INDEX IF NOT EXISTS idx_audit_created ON proofchain.audit_log(created_at DESC);
COMMENT ON TABLE proofchain.audit_log IS 'Audit log for proof chain operations';
-- ============================================================================
-- Attestor Schema Tables
-- ============================================================================
-- Rekor submission queue table
CREATE TABLE IF NOT EXISTS attestor.rekor_submission_queue (
id UUID PRIMARY KEY,
tenant_id TEXT NOT NULL,
bundle_sha256 TEXT NOT NULL,
dsse_payload BYTEA NOT NULL,
backend TEXT NOT NULL DEFAULT 'primary',
-- Status lifecycle: pending -> submitting -> submitted | retrying -> dead_letter
status TEXT NOT NULL DEFAULT 'pending'
CHECK (status IN ('pending', 'submitting', 'retrying', 'submitted', 'dead_letter')),
attempt_count INTEGER NOT NULL DEFAULT 0,
max_attempts INTEGER NOT NULL DEFAULT 5,
next_retry_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
-- Populated on success
rekor_uuid TEXT,
rekor_index BIGINT,
-- Populated on failure
last_error TEXT
);
COMMENT ON TABLE attestor.rekor_submission_queue IS
'Durable retry queue for Rekor transparency log submissions';
COMMENT ON COLUMN attestor.rekor_submission_queue.status IS
'Submission lifecycle: pending -> submitting -> (submitted | retrying -> dead_letter)';
COMMENT ON COLUMN attestor.rekor_submission_queue.backend IS
'Target Rekor backend (primary or mirror)';
COMMENT ON COLUMN attestor.rekor_submission_queue.dsse_payload IS
'Serialized DSSE envelope to submit';
-- Index for dequeue operations (status + next_retry_at for SKIP LOCKED queries)
CREATE INDEX IF NOT EXISTS idx_rekor_queue_dequeue
ON attestor.rekor_submission_queue (status, next_retry_at)
WHERE status IN ('pending', 'retrying');
-- Index for tenant-scoped queries
CREATE INDEX IF NOT EXISTS idx_rekor_queue_tenant
ON attestor.rekor_submission_queue (tenant_id);
-- Index for bundle lookup (deduplication check)
CREATE INDEX IF NOT EXISTS idx_rekor_queue_bundle
ON attestor.rekor_submission_queue (tenant_id, bundle_sha256);
-- Index for dead letter management
CREATE INDEX IF NOT EXISTS idx_rekor_queue_dead_letter
ON attestor.rekor_submission_queue (status, updated_at)
WHERE status = 'dead_letter';
-- Index for cleanup of completed submissions
CREATE INDEX IF NOT EXISTS idx_rekor_queue_completed
ON attestor.rekor_submission_queue (status, updated_at)
WHERE status = 'submitted';
-- ============================================================================
-- Trigger Functions
-- ============================================================================
CREATE OR REPLACE FUNCTION proofchain.update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- Apply updated_at trigger to trust_anchors
DROP TRIGGER IF EXISTS update_trust_anchors_updated_at ON proofchain.trust_anchors;
CREATE TRIGGER update_trust_anchors_updated_at
BEFORE UPDATE ON proofchain.trust_anchors
FOR EACH ROW
EXECUTE FUNCTION proofchain.update_updated_at_column();
-- Apply updated_at trigger to rekor_submission_queue
DROP TRIGGER IF EXISTS update_rekor_queue_updated_at ON attestor.rekor_submission_queue;
CREATE TRIGGER update_rekor_queue_updated_at
BEFORE UPDATE ON attestor.rekor_submission_queue
FOR EACH ROW
EXECUTE FUNCTION proofchain.update_updated_at_column();

View File

@@ -0,0 +1,95 @@
-- -----------------------------------------------------------------------------
-- Migration: 20260129_001_create_identity_watchlist
-- Sprint: SPRINT_0129_001_ATTESTOR_identity_watchlist_alerting
-- Task: WATCH-004
-- Description: Creates identity watchlist and alert deduplication tables.
-- -----------------------------------------------------------------------------
-- Watchlist entries table
CREATE TABLE IF NOT EXISTS attestor.identity_watchlist (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id TEXT NOT NULL,
scope TEXT NOT NULL DEFAULT 'Tenant',
display_name TEXT NOT NULL,
description TEXT,
-- Identity matching fields (at least one required)
issuer TEXT,
subject_alternative_name TEXT,
key_id TEXT,
match_mode TEXT NOT NULL DEFAULT 'Exact',
-- Alert configuration
severity TEXT NOT NULL DEFAULT 'Warning',
enabled BOOLEAN NOT NULL DEFAULT TRUE,
channel_overrides JSONB,
suppress_duplicates_minutes INT NOT NULL DEFAULT 60,
-- Metadata
tags TEXT[],
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
created_by TEXT NOT NULL,
updated_by TEXT NOT NULL,
-- Constraints
CONSTRAINT chk_at_least_one_identity CHECK (
issuer IS NOT NULL OR
subject_alternative_name IS NOT NULL OR
key_id IS NOT NULL
),
CONSTRAINT chk_scope_valid CHECK (scope IN ('Tenant', 'Global', 'System')),
CONSTRAINT chk_match_mode_valid CHECK (match_mode IN ('Exact', 'Prefix', 'Glob', 'Regex')),
CONSTRAINT chk_severity_valid CHECK (severity IN ('Info', 'Warning', 'Critical')),
CONSTRAINT chk_suppress_duplicates_positive CHECK (suppress_duplicates_minutes >= 1)
);
-- Performance indexes for active entry lookup
CREATE INDEX IF NOT EXISTS idx_watchlist_tenant_enabled
ON attestor.identity_watchlist(tenant_id)
WHERE enabled = TRUE;
CREATE INDEX IF NOT EXISTS idx_watchlist_scope_enabled
ON attestor.identity_watchlist(scope)
WHERE enabled = TRUE;
CREATE INDEX IF NOT EXISTS idx_watchlist_issuer
ON attestor.identity_watchlist(issuer)
WHERE enabled = TRUE AND issuer IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_watchlist_san
ON attestor.identity_watchlist(subject_alternative_name)
WHERE enabled = TRUE AND subject_alternative_name IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_watchlist_keyid
ON attestor.identity_watchlist(key_id)
WHERE enabled = TRUE AND key_id IS NOT NULL;
-- Alert deduplication table
CREATE TABLE IF NOT EXISTS attestor.identity_alert_dedup (
watchlist_id UUID NOT NULL,
identity_hash TEXT NOT NULL,
last_alert_at TIMESTAMPTZ NOT NULL,
alert_count INT NOT NULL DEFAULT 0,
PRIMARY KEY (watchlist_id, identity_hash)
);
-- Index for cleanup
CREATE INDEX IF NOT EXISTS idx_alert_dedup_last_alert
ON attestor.identity_alert_dedup(last_alert_at);
-- Comment documentation
COMMENT ON TABLE attestor.identity_watchlist IS
'Watchlist entries for monitoring signing identity appearances in transparency logs.';
COMMENT ON COLUMN attestor.identity_watchlist.scope IS
'Visibility scope: Tenant (owning tenant only), Global (all tenants), System (read-only).';
COMMENT ON COLUMN attestor.identity_watchlist.match_mode IS
'Pattern matching mode: Exact, Prefix, Glob, or Regex.';
COMMENT ON COLUMN attestor.identity_watchlist.suppress_duplicates_minutes IS
'Deduplication window in minutes. Alerts for same identity within window are suppressed.';
COMMENT ON TABLE attestor.identity_alert_dedup IS
'Tracks alert deduplication state to prevent alert storms.';

View File

@@ -0,0 +1,113 @@
-- Attestor Schema Migration 002: Predicate Type Registry
-- Sprint: SPRINT_20260219_010 (PSR-01)
-- Creates discoverable, versioned registry for all predicate types
-- ============================================================================
-- Predicate Type Registry Table
-- ============================================================================
CREATE TABLE IF NOT EXISTS proofchain.predicate_type_registry (
registry_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
predicate_type_uri TEXT NOT NULL,
display_name TEXT NOT NULL,
version TEXT NOT NULL DEFAULT '1.0.0',
category TEXT NOT NULL DEFAULT 'stella-core'
CHECK (category IN ('stella-core', 'stella-proof', 'stella-delta', 'ecosystem', 'intoto', 'custom')),
json_schema JSONB,
description TEXT,
is_active BOOLEAN NOT NULL DEFAULT TRUE,
validation_mode TEXT NOT NULL DEFAULT 'log-only'
CHECK (validation_mode IN ('log-only', 'warn', 'reject')),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
CONSTRAINT uq_predicate_type_version UNIQUE (predicate_type_uri, version)
);
CREATE INDEX IF NOT EXISTS idx_predicate_registry_uri
ON proofchain.predicate_type_registry(predicate_type_uri);
CREATE INDEX IF NOT EXISTS idx_predicate_registry_category
ON proofchain.predicate_type_registry(category);
CREATE INDEX IF NOT EXISTS idx_predicate_registry_active
ON proofchain.predicate_type_registry(is_active) WHERE is_active = TRUE;
-- Apply updated_at trigger
DROP TRIGGER IF EXISTS update_predicate_registry_updated_at ON proofchain.predicate_type_registry;
CREATE TRIGGER update_predicate_registry_updated_at
BEFORE UPDATE ON proofchain.predicate_type_registry
FOR EACH ROW
EXECUTE FUNCTION proofchain.update_updated_at_column();
COMMENT ON TABLE proofchain.predicate_type_registry IS 'Discoverable registry of all predicate types accepted by the Attestor';
COMMENT ON COLUMN proofchain.predicate_type_registry.predicate_type_uri IS 'Canonical URI for the predicate type (e.g., https://stella-ops.org/predicates/evidence/v1)';
COMMENT ON COLUMN proofchain.predicate_type_registry.validation_mode IS 'How mismatches are handled: log-only (default), warn, or reject';
-- ============================================================================
-- Seed: stella-core predicates
-- ============================================================================
INSERT INTO proofchain.predicate_type_registry (predicate_type_uri, display_name, version, category, description) VALUES
('https://stella-ops.org/predicates/sbom-linkage/v1', 'SBOM Linkage', '1.0.0', 'stella-core', 'Links SBOM components to evidence and proof spines'),
('https://stella-ops.org/predicates/vex-verdict/v1', 'VEX Verdict', '1.0.0', 'stella-core', 'VEX consensus verdict for an artifact+advisory tuple'),
('https://stella-ops.org/predicates/evidence/v1', 'Evidence', '1.0.0', 'stella-core', 'Generic evidence attestation linking scan results to artifacts'),
('https://stella-ops.org/predicates/reasoning/v1', 'Reasoning', '1.0.0', 'stella-core', 'Policy reasoning chain for a release decision'),
('https://stella-ops.org/predicates/proof-spine/v1', 'Proof Spine', '1.0.0', 'stella-core', 'Merkle-aggregated proof spine linking evidence to verdicts'),
('https://stella-ops.org/predicates/reachability-drift/v1', 'Reachability Drift', '1.0.0', 'stella-core', 'Reachability state changes between consecutive scans'),
('https://stella-ops.org/predicates/reachability-subgraph/v1', 'Reachability Subgraph', '1.0.0', 'stella-core', 'Call graph subgraph for a specific vulnerability path'),
('https://stella-ops.org/predicates/delta-verdict/v1', 'Delta Verdict', '1.0.0', 'stella-core', 'Verdict differences between two scan runs'),
('https://stella-ops.org/predicates/policy-decision/v1', 'Policy Decision', '1.0.0', 'stella-core', 'Policy engine evaluation result for a release gate'),
('https://stella-ops.org/predicates/unknowns-budget/v1', 'Unknowns Budget', '1.0.0', 'stella-core', 'Budget check for unknown reachability components'),
('https://stella-ops.org/predicates/ai-code-guard/v1', 'AI Code Guard', '1.0.0', 'stella-core', 'AI-assisted code security analysis results'),
('https://stella-ops.org/predicates/fix-chain/v1', 'Fix Chain', '1.0.0', 'stella-core', 'Linked chain of fix commits from vulnerability to resolution'),
('https://stella-ops.org/attestation/graph-root/v1', 'Graph Root', '1.0.0', 'stella-core', 'Root attestation for a complete call graph')
ON CONFLICT (predicate_type_uri, version) DO NOTHING;
-- ============================================================================
-- Seed: stella-proof predicates (ProofChain)
-- ============================================================================
INSERT INTO proofchain.predicate_type_registry (predicate_type_uri, display_name, version, category, description) VALUES
('https://stella.ops/predicates/path-witness/v1', 'Path Witness', '1.0.0', 'stella-proof', 'Entrypoint-to-sink call path witness with gate detection'),
('https://stella.ops/predicates/runtime-witness/v1', 'Runtime Witness', '1.0.0', 'stella-proof', 'Runtime micro-witness from eBPF/ETW observations'),
('https://stella.ops/predicates/policy-decision@v2', 'Policy Decision v2', '2.0.0', 'stella-proof', 'Enhanced policy decision with reachability context'),
('https://stellaops.dev/predicates/binary-micro-witness@v1', 'Binary Micro-Witness', '1.0.0', 'stella-proof', 'Binary-level micro-witness with build ID correlation'),
('https://stellaops.dev/predicates/binary-fingerprint-evidence@v1', 'Binary Fingerprint', '1.0.0', 'stella-proof', 'Binary fingerprint evidence for patch detection'),
('https://stellaops.io/attestation/budget-check/v1', 'Budget Check', '1.0.0', 'stella-proof', 'Unknowns budget check attestation'),
('https://stellaops.dev/attestation/vex/v1', 'VEX Attestation', '1.0.0', 'stella-proof', 'DSSE-signed VEX statement attestation'),
('https://stellaops.dev/attestations/vex-override/v1', 'VEX Override', '1.0.0', 'stella-proof', 'Manual VEX override decision with justification'),
('https://stellaops.dev/predicates/trust-verdict@v1', 'Trust Verdict', '1.0.0', 'stella-proof', 'Trust lattice verdict combining P/C/R vectors'),
('https://stellaops.io/attestation/v1/signed-exception', 'Signed Exception', '1.0.0', 'stella-proof', 'Manually approved exception with expiry'),
('https://stellaops.dev/attestation/verification-report/v1', 'Verification Report', '1.0.0', 'stella-proof', 'QA verification report attestation')
ON CONFLICT (predicate_type_uri, version) DO NOTHING;
-- ============================================================================
-- Seed: stella-delta predicates
-- ============================================================================
INSERT INTO proofchain.predicate_type_registry (predicate_type_uri, display_name, version, category, description) VALUES
('stella.ops/changetrace@v1', 'Change Trace', '1.0.0', 'stella-delta', 'File-level change trace between SBOM versions'),
('stella.ops/vex-delta@v1', 'VEX Delta', '1.0.0', 'stella-delta', 'VEX statement differences between consecutive ingestions'),
('stella.ops/sbom-delta@v1', 'SBOM Delta', '1.0.0', 'stella-delta', 'Component differences between two SBOM versions'),
('stella.ops/verdict-delta@v1', 'Verdict Delta', '1.0.0', 'stella-delta', 'Verdict changes between policy evaluations'),
('stellaops.binarydiff.v1', 'Binary Diff', '1.0.0', 'stella-delta', 'Binary diff signatures for patch detection')
ON CONFLICT (predicate_type_uri, version) DO NOTHING;
-- ============================================================================
-- Seed: ecosystem predicates
-- ============================================================================
INSERT INTO proofchain.predicate_type_registry (predicate_type_uri, display_name, version, category, description) VALUES
('https://spdx.dev/Document', 'SPDX Document', '2.3.0', 'ecosystem', 'SPDX 2.x document attestation'),
('https://cyclonedx.org/bom', 'CycloneDX BOM', '1.7.0', 'ecosystem', 'CycloneDX BOM attestation'),
('https://slsa.dev/provenance', 'SLSA Provenance', '1.0.0', 'ecosystem', 'SLSA v1.0 build provenance')
ON CONFLICT (predicate_type_uri, version) DO NOTHING;
-- ============================================================================
-- Seed: in-toto standard predicates
-- ============================================================================
INSERT INTO proofchain.predicate_type_registry (predicate_type_uri, display_name, version, category, description) VALUES
('https://in-toto.io/Statement/v1', 'In-Toto Statement', '1.0.0', 'intoto', 'In-toto attestation statement wrapper'),
('https://in-toto.io/Link/v1', 'In-Toto Link', '1.0.0', 'intoto', 'In-toto supply chain link'),
('https://in-toto.io/Layout/v1', 'In-Toto Layout', '1.0.0', 'intoto', 'In-toto supply chain layout')
ON CONFLICT (predicate_type_uri, version) DO NOTHING;

View File

@@ -0,0 +1,42 @@
-- Migration 003: Artifact Canonical Record materialized view
-- Sprint: SPRINT_20260219_009 (CID-04)
-- Purpose: Unified read projection joining sbom_entries + dsse_envelopes + rekor_entries
-- for the Evidence Thread API (GET /api/v1/evidence/thread/{canonical_id}).
-- Materialized view: one row per canonical_id with aggregated attestation evidence.
CREATE MATERIALIZED VIEW IF NOT EXISTS proofchain.artifact_canonical_records AS
SELECT
se.bom_digest AS canonical_id,
'cyclonedx-jcs:1'::text AS format,
se.artifact_digest,
se.purl,
se.created_at,
COALESCE(
jsonb_agg(
DISTINCT jsonb_build_object(
'predicate_type', de.predicate_type,
'dsse_digest', de.body_hash,
'signer_keyid', de.signer_keyid,
'rekor_entry_id', re.uuid,
'rekor_tile', re.log_id,
'signed_at', de.signed_at
)
) FILTER (WHERE de.env_id IS NOT NULL),
'[]'::jsonb
) AS attestations
FROM proofchain.sbom_entries se
LEFT JOIN proofchain.dsse_envelopes de ON de.entry_id = se.entry_id
LEFT JOIN proofchain.rekor_entries re ON re.env_id = de.env_id
GROUP BY se.entry_id, se.bom_digest, se.artifact_digest, se.purl, se.created_at;
-- Unique index for CONCURRENTLY refresh and fast lookup.
CREATE UNIQUE INDEX IF NOT EXISTS idx_acr_canonical_id
ON proofchain.artifact_canonical_records (canonical_id);
-- Index for PURL-based lookup (Evidence Thread by PURL).
CREATE INDEX IF NOT EXISTS idx_acr_purl
ON proofchain.artifact_canonical_records (purl)
WHERE purl IS NOT NULL;
COMMENT ON MATERIALIZED VIEW proofchain.artifact_canonical_records IS
'Unified read projection for the Evidence Thread API. Joins SBOM entries, DSSE envelopes, and Rekor entries into one row per canonical_id. Refresh via REFRESH MATERIALIZED VIEW CONCURRENTLY.';

View File

@@ -0,0 +1,83 @@
-- -----------------------------------------------------------------------------
-- 001_verdict_ledger_initial.sql
-- Sprint: SPRINT_20260118_015_Attestor_verdict_ledger_foundation
-- Task: VL-001 - Create VerdictLedger database schema
-- Description: Append-only verdict ledger with SHA-256 hash chaining
-- -----------------------------------------------------------------------------
-- Create verdict decision enum
DO $$ BEGIN
CREATE TYPE verdict_decision AS ENUM ('unknown', 'approve', 'reject', 'pending');
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
-- Create the verdict_ledger table
CREATE TABLE IF NOT EXISTS verdict_ledger (
ledger_id UUID PRIMARY KEY,
bom_ref VARCHAR(2048) NOT NULL,
cyclonedx_serial VARCHAR(512),
rekor_uuid VARCHAR(128),
decision verdict_decision NOT NULL DEFAULT 'unknown',
reason TEXT NOT NULL,
policy_bundle_id VARCHAR(256) NOT NULL,
policy_bundle_hash VARCHAR(64) NOT NULL,
verifier_image_digest VARCHAR(256) NOT NULL,
signer_keyid VARCHAR(512) NOT NULL,
prev_hash VARCHAR(64), -- SHA-256 hex, null for genesis entry
verdict_hash VARCHAR(64) NOT NULL UNIQUE,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
tenant_id UUID NOT NULL,
-- Constraints
CONSTRAINT verdict_hash_format CHECK (verdict_hash ~ '^[a-f0-9]{64}$'),
CONSTRAINT prev_hash_format CHECK (prev_hash IS NULL OR prev_hash ~ '^[a-f0-9]{64}$'),
CONSTRAINT policy_hash_format CHECK (policy_bundle_hash ~ '^[a-f0-9]{64}$')
);
-- Indexes for common query patterns
CREATE INDEX IF NOT EXISTS idx_verdict_ledger_bom_ref
ON verdict_ledger (bom_ref);
CREATE INDEX IF NOT EXISTS idx_verdict_ledger_rekor_uuid
ON verdict_ledger (rekor_uuid)
WHERE rekor_uuid IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_verdict_ledger_created_at
ON verdict_ledger (created_at DESC);
CREATE INDEX IF NOT EXISTS idx_verdict_ledger_tenant_created
ON verdict_ledger (tenant_id, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_verdict_ledger_prev_hash
ON verdict_ledger (prev_hash)
WHERE prev_hash IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_verdict_ledger_decision
ON verdict_ledger (decision);
-- Composite index for chain walking
CREATE INDEX IF NOT EXISTS idx_verdict_ledger_chain
ON verdict_ledger (tenant_id, verdict_hash);
-- Comments
COMMENT ON TABLE verdict_ledger IS 'Append-only ledger of release verdicts with SHA-256 hash chaining for cryptographic audit trail';
COMMENT ON COLUMN verdict_ledger.ledger_id IS 'Unique identifier for this ledger entry';
COMMENT ON COLUMN verdict_ledger.bom_ref IS 'Package URL (purl) or container digest reference';
COMMENT ON COLUMN verdict_ledger.cyclonedx_serial IS 'CycloneDX serialNumber URN linking to SBOM';
COMMENT ON COLUMN verdict_ledger.rekor_uuid IS 'Transparency log entry UUID for external verification';
COMMENT ON COLUMN verdict_ledger.decision IS 'The release decision: unknown, approve, reject, or pending';
COMMENT ON COLUMN verdict_ledger.reason IS 'Human-readable explanation for the decision';
COMMENT ON COLUMN verdict_ledger.policy_bundle_id IS 'Reference to the policy configuration used';
COMMENT ON COLUMN verdict_ledger.policy_bundle_hash IS 'SHA-256 hash of the policy bundle for reproducibility';
COMMENT ON COLUMN verdict_ledger.verifier_image_digest IS 'Container digest of the verifier service';
COMMENT ON COLUMN verdict_ledger.signer_keyid IS 'Key ID that signed this verdict';
COMMENT ON COLUMN verdict_ledger.prev_hash IS 'SHA-256 hash of previous entry (null for genesis)';
COMMENT ON COLUMN verdict_ledger.verdict_hash IS 'SHA-256 hash of this entry canonical JSON form';
COMMENT ON COLUMN verdict_ledger.created_at IS 'Timestamp when this verdict was recorded';
COMMENT ON COLUMN verdict_ledger.tenant_id IS 'Tenant identifier for multi-tenancy';
-- Revoke UPDATE and DELETE for application role (append-only enforcement)
-- This should be run after creating the appropriate role
-- REVOKE UPDATE, DELETE ON verdict_ledger FROM stellaops_app;
-- GRANT INSERT, SELECT ON verdict_ledger TO stellaops_app;

View File

@@ -0,0 +1,107 @@
-- Migration: 001_CreateVerdictAttestations
-- Description: Create verdict_attestations table for storing signed policy verdict attestations
-- Author: Evidence Locker Guild
-- Date: 2025-12-23
-- Create schema if not exists
CREATE SCHEMA IF NOT EXISTS evidence_locker;
-- Create verdict_attestations table
CREATE TABLE IF NOT EXISTS evidence_locker.verdict_attestations (
verdict_id TEXT PRIMARY KEY,
tenant_id TEXT NOT NULL,
run_id TEXT NOT NULL,
policy_id TEXT NOT NULL,
policy_version INTEGER NOT NULL,
finding_id TEXT NOT NULL,
verdict_status TEXT NOT NULL CHECK (verdict_status IN ('passed', 'warned', 'blocked', 'quieted', 'ignored')),
verdict_severity TEXT NOT NULL CHECK (verdict_severity IN ('critical', 'high', 'medium', 'low', 'info', 'none')),
verdict_score NUMERIC(5, 2) NOT NULL CHECK (verdict_score >= 0 AND verdict_score <= 100),
evaluated_at TIMESTAMPTZ NOT NULL,
envelope JSONB NOT NULL,
predicate_digest TEXT NOT NULL,
determinism_hash TEXT,
rekor_log_index BIGINT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- Create indexes for common query patterns
CREATE INDEX IF NOT EXISTS idx_verdict_attestations_run
ON evidence_locker.verdict_attestations(run_id);
CREATE INDEX IF NOT EXISTS idx_verdict_attestations_finding
ON evidence_locker.verdict_attestations(finding_id);
CREATE INDEX IF NOT EXISTS idx_verdict_attestations_tenant_evaluated
ON evidence_locker.verdict_attestations(tenant_id, evaluated_at DESC);
CREATE INDEX IF NOT EXISTS idx_verdict_attestations_tenant_status
ON evidence_locker.verdict_attestations(tenant_id, verdict_status);
CREATE INDEX IF NOT EXISTS idx_verdict_attestations_tenant_severity
ON evidence_locker.verdict_attestations(tenant_id, verdict_severity);
CREATE INDEX IF NOT EXISTS idx_verdict_attestations_policy
ON evidence_locker.verdict_attestations(policy_id, policy_version);
-- Create GIN index for JSONB envelope queries
CREATE INDEX IF NOT EXISTS idx_verdict_attestations_envelope
ON evidence_locker.verdict_attestations USING gin(envelope);
-- Create function for updating updated_at timestamp
CREATE OR REPLACE FUNCTION evidence_locker.update_verdict_attestations_updated_at()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- Create trigger to auto-update updated_at
CREATE TRIGGER trigger_verdict_attestations_updated_at
BEFORE UPDATE ON evidence_locker.verdict_attestations
FOR EACH ROW
EXECUTE FUNCTION evidence_locker.update_verdict_attestations_updated_at();
-- Create view for verdict summary (without full envelope)
CREATE OR REPLACE VIEW evidence_locker.verdict_attestations_summary AS
SELECT
verdict_id,
tenant_id,
run_id,
policy_id,
policy_version,
finding_id,
verdict_status,
verdict_severity,
verdict_score,
evaluated_at,
predicate_digest,
determinism_hash,
rekor_log_index,
created_at
FROM evidence_locker.verdict_attestations;
-- Grant permissions (adjust as needed)
-- GRANT SELECT, INSERT ON evidence_locker.verdict_attestations TO evidence_locker_app;
-- GRANT SELECT ON evidence_locker.verdict_attestations_summary TO evidence_locker_app;
-- Add comments for documentation
COMMENT ON TABLE evidence_locker.verdict_attestations IS
'Stores DSSE-signed policy verdict attestations for audit and verification';
COMMENT ON COLUMN evidence_locker.verdict_attestations.verdict_id IS
'Unique verdict identifier (format: verdict:run:{runId}:finding:{findingId})';
COMMENT ON COLUMN evidence_locker.verdict_attestations.envelope IS
'DSSE envelope containing signed verdict predicate';
COMMENT ON COLUMN evidence_locker.verdict_attestations.predicate_digest IS
'SHA256 digest of the canonical JSON predicate payload';
COMMENT ON COLUMN evidence_locker.verdict_attestations.determinism_hash IS
'Determinism hash computed from sorted evidence digests and verdict components';
COMMENT ON COLUMN evidence_locker.verdict_attestations.rekor_log_index IS
'Rekor transparency log index (if anchored), null for offline/air-gap deployments';

View File

@@ -0,0 +1,41 @@
-- Integrations catalog bootstrap schema for compose environments.
-- Creates the EF-backed integrations table when running without EF migrations.
CREATE TABLE IF NOT EXISTS integrations
(
id UUID PRIMARY KEY,
name VARCHAR(256) NOT NULL,
description VARCHAR(1024),
type INTEGER NOT NULL,
provider INTEGER NOT NULL,
status INTEGER NOT NULL,
endpoint VARCHAR(2048) NOT NULL,
auth_ref_uri VARCHAR(1024),
organization_id VARCHAR(256),
config_json JSONB,
last_health_status INTEGER NOT NULL DEFAULT 0,
last_health_check_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL,
updated_at TIMESTAMPTZ NOT NULL,
created_by VARCHAR(256),
updated_by VARCHAR(256),
tenant_id VARCHAR(128),
tags JSONB,
is_deleted BOOLEAN NOT NULL DEFAULT FALSE
);
CREATE INDEX IF NOT EXISTS ix_integrations_type
ON integrations (type);
CREATE INDEX IF NOT EXISTS ix_integrations_provider
ON integrations (provider);
CREATE INDEX IF NOT EXISTS ix_integrations_status
ON integrations (status);
CREATE INDEX IF NOT EXISTS ix_integrations_tenant
ON integrations (tenant_id);
CREATE UNIQUE INDEX IF NOT EXISTS ix_integrations_tenant_name_active
ON integrations (tenant_id, name)
WHERE is_deleted = FALSE;

View File

@@ -0,0 +1,10 @@
CREATE SCHEMA IF NOT EXISTS advisoryai;
DO $$
BEGIN
CREATE EXTENSION IF NOT EXISTS vector;
EXCEPTION
WHEN OTHERS THEN
RAISE NOTICE 'pgvector extension unavailable in test DB image; AKS falls back to array embeddings.';
END
$$;

View File

View File

@@ -0,0 +1,5 @@
{
"Path": "/rekor",
"Type": "ReverseProxy",
"TranslatesTo": "http://rekor.stella-ops.local:3322"
}

View File

@@ -0,0 +1 @@
{"type":"https://stellaops.org/problems/internal-error","title":"Unexpected server error","status":500,"detail":"The AuthorizationPolicy named: 'scanner.secrets.settings.read' was not found.","instance":"/api/v1/secrets/config/rules/categories","traceId":"41e58f34254db08289098df447d10f7c"}

View File

@@ -1,143 +1,717 @@
{
"Gateway": {
"Auth": {
"DpopEnabled": false,
"AllowAnonymous": true,
"EnableLegacyHeaders": true,
"AllowScopeHeader": false,
"Authority": {
"Issuer": "https://authority.stella-ops.local/",
"RequireHttpsMetadata": false,
"MetadataAddress": "https://authority.stella-ops.local/.well-known/openid-configuration",
"Audiences": []
}
},
"Routes": [
{ "Type": "ReverseProxy", "Path": "/api/v1/release-orchestrator", "TranslatesTo": "http://orchestrator.stella-ops.local/api/v1/release-orchestrator" },
{ "Type": "ReverseProxy", "Path": "/api/v1/vex", "TranslatesTo": "https://vexhub.stella-ops.local/api/v1/vex" },
{ "Type": "ReverseProxy", "Path": "/api/v1/vexlens", "TranslatesTo": "http://vexlens.stella-ops.local/api/v1/vexlens" },
{ "Type": "ReverseProxy", "Path": "/api/v1/notify", "TranslatesTo": "http://notify.stella-ops.local/api/v1/notify" },
{ "Type": "ReverseProxy", "Path": "/api/v1/notifier", "TranslatesTo": "http://notifier.stella-ops.local/api/v1/notifier" },
{ "Type": "ReverseProxy", "Path": "/api/v1/concelier", "TranslatesTo": "http://concelier.stella-ops.local/api/v1/concelier" },
{ "Type": "ReverseProxy", "Path": "/api/v1/platform", "TranslatesTo": "http://platform.stella-ops.local/api/v1/platform" },
{ "Type": "ReverseProxy", "Path": "/api/v1/scanner", "TranslatesTo": "http://scanner.stella-ops.local/api/v1/scanner" },
{ "Type": "ReverseProxy", "Path": "/api/v1/findings", "TranslatesTo": "http://findings.stella-ops.local/api/v1/findings", "PreserveAuthHeaders": true },
{ "Type": "ReverseProxy", "Path": "/api/v1/integrations", "TranslatesTo": "http://integrations.stella-ops.local/api/v1/integrations", "PreserveAuthHeaders": true },
{ "Type": "ReverseProxy", "Path": "/api/v1/policy", "TranslatesTo": "http://policy-gateway.stella-ops.local/api/v1/policy" },
{ "Type": "ReverseProxy", "Path": "/api/v1/reachability", "TranslatesTo": "http://reachgraph.stella-ops.local/api/v1/reachability" },
{ "Type": "ReverseProxy", "Path": "/api/v1/attestor", "TranslatesTo": "http://attestor.stella-ops.local/api/v1/attestor" },
{ "Type": "ReverseProxy", "Path": "/api/v1/attestations", "TranslatesTo": "http://attestor.stella-ops.local/api/v1/attestations" },
{ "Type": "ReverseProxy", "Path": "/api/v1/sbom", "TranslatesTo": "http://sbomservice.stella-ops.local/api/v1/sbom" },
{ "Type": "ReverseProxy", "Path": "/api/v1/signals", "TranslatesTo": "http://signals.stella-ops.local/api/v1/signals" },
{ "Type": "ReverseProxy", "Path": "/api/v1/orchestrator", "TranslatesTo": "http://orchestrator.stella-ops.local/api/v1/orchestrator" },
{ "Type": "ReverseProxy", "Path": "/api/v1/authority/quotas", "TranslatesTo": "http://platform.stella-ops.local/api/v1/authority/quotas", "PreserveAuthHeaders": true },
{ "Type": "ReverseProxy", "Path": "/api/v1/authority", "TranslatesTo": "https://authority.stella-ops.local/api/v1/authority", "PreserveAuthHeaders": true },
{ "Type": "ReverseProxy", "Path": "/api/v1/trust", "TranslatesTo": "https://authority.stella-ops.local/api/v1/trust", "PreserveAuthHeaders": true },
{ "Type": "ReverseProxy", "Path": "/api/v1/evidence", "TranslatesTo": "https://evidencelocker.stella-ops.local/api/v1/evidence" },
{ "Type": "ReverseProxy", "Path": "/api/v1/proofs", "TranslatesTo": "https://evidencelocker.stella-ops.local/api/v1/proofs" },
{ "Type": "ReverseProxy", "Path": "/api/v1/timeline", "TranslatesTo": "http://timelineindexer.stella-ops.local/api/v1/timeline" },
{ "Type": "ReverseProxy", "Path": "/api/v1/advisory-ai", "TranslatesTo": "http://advisoryai.stella-ops.local/api/v1/advisory-ai" },
{ "Type": "ReverseProxy", "Path": "/api/v1/advisory", "TranslatesTo": "http://advisoryai.stella-ops.local/api/v1/advisory" },
{ "Type": "ReverseProxy", "Path": "/api/v1/vulnerabilities", "TranslatesTo": "http://scanner.stella-ops.local/api/v1/vulnerabilities" },
{ "Type": "ReverseProxy", "Path": "/api/v1/watchlist", "TranslatesTo": "http://scanner.stella-ops.local/api/v1/watchlist" },
{ "Type": "ReverseProxy", "Path": "/api/v1/resolve", "TranslatesTo": "http://binaryindex.stella-ops.local/api/v1/resolve" },
{ "Type": "ReverseProxy", "Path": "/api/v1/ops/binaryindex", "TranslatesTo": "http://binaryindex.stella-ops.local/api/v1/ops/binaryindex" },
{ "Type": "ReverseProxy", "Path": "/api/v1/verdicts", "TranslatesTo": "https://evidencelocker.stella-ops.local/api/v1/verdicts" },
{ "Type": "ReverseProxy", "Path": "/api/v1/lineage", "TranslatesTo": "http://sbomservice.stella-ops.local/api/v1/lineage" },
{ "Type": "ReverseProxy", "Path": "/api/v1/export", "TranslatesTo": "https://exportcenter.stella-ops.local/api/v1/export" },
{ "Type": "ReverseProxy", "Path": "/api/v1/triage", "TranslatesTo": "http://scanner.stella-ops.local/api/v1/triage" },
{ "Type": "ReverseProxy", "Path": "/api/v1/governance", "TranslatesTo": "http://policy-gateway.stella-ops.local/api/v1/governance" },
{ "Type": "ReverseProxy", "Path": "/api/v1/determinization", "TranslatesTo": "http://policy-engine.stella-ops.local/api/v1/determinization" },
{ "Type": "ReverseProxy", "Path": "/api/v1/opsmemory", "TranslatesTo": "http://opsmemory.stella-ops.local/api/v1/opsmemory" },
{ "Type": "ReverseProxy", "Path": "/api/v1/secrets", "TranslatesTo": "http://scanner.stella-ops.local/api/v1/secrets" },
{ "Type": "ReverseProxy", "Path": "/api/v1/sources", "TranslatesTo": "http://sbomservice.stella-ops.local/api/v1/sources" },
{ "Type": "ReverseProxy", "Path": "/api/v1/workflows", "TranslatesTo": "http://orchestrator.stella-ops.local/api/v1/workflows" },
{ "Type": "ReverseProxy", "Path": "/api/v1/witnesses", "TranslatesTo": "http://attestor.stella-ops.local/api/v1/witnesses" },
{ "Type": "ReverseProxy", "Path": "/v1/evidence-packs", "TranslatesTo": "https://evidencelocker.stella-ops.local/v1/evidence-packs" },
{ "Type": "ReverseProxy", "Path": "/v1/runs", "TranslatesTo": "http://orchestrator.stella-ops.local/v1/runs" },
{ "Type": "ReverseProxy", "Path": "/v1/advisory-ai", "TranslatesTo": "http://advisoryai.stella-ops.local/v1/advisory-ai" },
{ "Type": "ReverseProxy", "Path": "/v1/audit-bundles", "TranslatesTo": "https://exportcenter.stella-ops.local/v1/audit-bundles" },
{ "Type": "ReverseProxy", "Path": "/policy", "TranslatesTo": "http://policy-gateway.stella-ops.local" },
{ "Type": "ReverseProxy", "Path": "/api/cvss", "TranslatesTo": "http://policy-gateway.stella-ops.local/api/cvss", "PreserveAuthHeaders": true },
{ "Type": "ReverseProxy", "Path": "/api/policy", "TranslatesTo": "http://policy-gateway.stella-ops.local/api/policy", "PreserveAuthHeaders": true },
{ "Type": "ReverseProxy", "Path": "/api/risk", "TranslatesTo": "http://policy-engine.stella-ops.local/api/risk", "PreserveAuthHeaders": true },
{ "Type": "ReverseProxy", "Path": "/api/analytics", "TranslatesTo": "http://platform.stella-ops.local/api/analytics" },
{ "Type": "ReverseProxy", "Path": "/api/release-orchestrator", "TranslatesTo": "http://orchestrator.stella-ops.local/api/release-orchestrator" },
{ "Type": "ReverseProxy", "Path": "/api/releases", "TranslatesTo": "http://orchestrator.stella-ops.local/api/releases" },
{ "Type": "ReverseProxy", "Path": "/api/approvals", "TranslatesTo": "http://orchestrator.stella-ops.local/api/approvals" },
{ "Type": "ReverseProxy", "Path": "/api/gate", "TranslatesTo": "http://policy-gateway.stella-ops.local/api/gate", "PreserveAuthHeaders": true },
{ "Type": "ReverseProxy", "Path": "/api/risk-budget", "TranslatesTo": "http://policy-engine.stella-ops.local/api/risk-budget" },
{ "Type": "ReverseProxy", "Path": "/api/fix-verification", "TranslatesTo": "http://scanner.stella-ops.local/api/fix-verification" },
{ "Type": "ReverseProxy", "Path": "/api/compare", "TranslatesTo": "http://sbomservice.stella-ops.local/api/compare" },
{ "Type": "ReverseProxy", "Path": "/api/change-traces", "TranslatesTo": "http://sbomservice.stella-ops.local/api/change-traces" },
{ "Type": "ReverseProxy", "Path": "/api/exceptions", "TranslatesTo": "http://policy-gateway.stella-ops.local/api/exceptions", "PreserveAuthHeaders": true },
{ "Type": "ReverseProxy", "Path": "/api/verdicts", "TranslatesTo": "https://evidencelocker.stella-ops.local/api/verdicts" },
{ "Type": "ReverseProxy", "Path": "/api/orchestrator", "TranslatesTo": "http://orchestrator.stella-ops.local/api/orchestrator" },
{ "Type": "ReverseProxy", "Path": "/api/v1/gateway/rate-limits", "TranslatesTo": "http://platform.stella-ops.local/api/v1/gateway/rate-limits", "PreserveAuthHeaders": true },
{ "Type": "ReverseProxy", "Path": "/api/sbomservice", "TranslatesTo": "http://sbomservice.stella-ops.local/api/sbomservice" },
{ "Type": "ReverseProxy", "Path": "/api/vuln-explorer", "TranslatesTo": "http://vulnexplorer.stella-ops.local/api/vuln-explorer" },
{ "Type": "ReverseProxy", "Path": "/api/vex", "TranslatesTo": "https://vexhub.stella-ops.local/api/vex" },
{ "Type": "ReverseProxy", "Path": "/api/admin", "TranslatesTo": "http://platform.stella-ops.local/api/admin" },
{ "Type": "ReverseProxy", "Path": "/api/scheduler", "TranslatesTo": "http://scheduler.stella-ops.local/api/scheduler" },
{ "Type": "ReverseProxy", "Path": "/api/doctor", "TranslatesTo": "http://doctor.stella-ops.local/api/doctor" },
{ "Type": "ReverseProxy", "Path": "/api", "TranslatesTo": "http://platform.stella-ops.local/api" },
{ "Type": "StaticFile", "Path": "/platform/envsettings.json", "TranslatesTo": "/app/envsettings-override.json" },
{ "Type": "ReverseProxy", "Path": "/platform", "TranslatesTo": "http://platform.stella-ops.local/platform" },
{ "Type": "ReverseProxy", "Path": "/connect", "TranslatesTo": "https://authority.stella-ops.local", "PreserveAuthHeaders": true },
{ "Type": "ReverseProxy", "Path": "/.well-known", "TranslatesTo": "https://authority.stella-ops.local/.well-known", "PreserveAuthHeaders": true },
{ "Type": "ReverseProxy", "Path": "/jwks", "TranslatesTo": "https://authority.stella-ops.local/jwks", "PreserveAuthHeaders": true },
{ "Type": "ReverseProxy", "Path": "/authority", "TranslatesTo": "https://authority.stella-ops.local/authority", "PreserveAuthHeaders": true },
{ "Type": "ReverseProxy", "Path": "/console", "TranslatesTo": "https://authority.stella-ops.local/console", "PreserveAuthHeaders": true },
{ "Type": "ReverseProxy", "Path": "/envsettings.json", "TranslatesTo": "http://platform.stella-ops.local/platform/envsettings.json" },
{ "Type": "ReverseProxy", "Path": "/gateway", "TranslatesTo": "http://gateway.stella-ops.local" },
{ "Type": "ReverseProxy", "Path": "/scanner", "TranslatesTo": "http://scanner.stella-ops.local" },
{ "Type": "ReverseProxy", "Path": "/policyGateway", "TranslatesTo": "http://policy-gateway.stella-ops.local" },
{ "Type": "ReverseProxy", "Path": "/policyEngine", "TranslatesTo": "http://policy-engine.stella-ops.local" },
{ "Type": "ReverseProxy", "Path": "/concelier", "TranslatesTo": "http://concelier.stella-ops.local" },
{ "Type": "ReverseProxy", "Path": "/attestor", "TranslatesTo": "http://attestor.stella-ops.local" },
{ "Type": "ReverseProxy", "Path": "/notify", "TranslatesTo": "http://notify.stella-ops.local" },
{ "Type": "ReverseProxy", "Path": "/notifier", "TranslatesTo": "http://notifier.stella-ops.local" },
{ "Type": "ReverseProxy", "Path": "/scheduler", "TranslatesTo": "http://scheduler.stella-ops.local" },
{ "Type": "ReverseProxy", "Path": "/signals", "TranslatesTo": "http://signals.stella-ops.local" },
{ "Type": "ReverseProxy", "Path": "/excititor", "TranslatesTo": "http://excititor.stella-ops.local" },
{ "Type": "ReverseProxy", "Path": "/findingsLedger", "TranslatesTo": "http://findings.stella-ops.local" },
{ "Type": "ReverseProxy", "Path": "/vexhub", "TranslatesTo": "https://vexhub.stella-ops.local" },
{ "Type": "ReverseProxy", "Path": "/vexlens", "TranslatesTo": "http://vexlens.stella-ops.local" },
{ "Type": "ReverseProxy", "Path": "/orchestrator", "TranslatesTo": "http://orchestrator.stella-ops.local" },
{ "Type": "ReverseProxy", "Path": "/taskrunner", "TranslatesTo": "http://taskrunner.stella-ops.local" },
{ "Type": "ReverseProxy", "Path": "/cartographer", "TranslatesTo": "http://cartographer.stella-ops.local" },
{ "Type": "ReverseProxy", "Path": "/reachgraph", "TranslatesTo": "http://reachgraph.stella-ops.local" },
{ "Type": "ReverseProxy", "Path": "/doctor", "TranslatesTo": "http://doctor.stella-ops.local" },
{ "Type": "ReverseProxy", "Path": "/integrations", "TranslatesTo": "http://integrations.stella-ops.local" },
{ "Type": "ReverseProxy", "Path": "/replay", "TranslatesTo": "http://replay.stella-ops.local" },
{ "Type": "ReverseProxy", "Path": "/exportcenter", "TranslatesTo": "https://exportcenter.stella-ops.local" },
{ "Type": "ReverseProxy", "Path": "/evidencelocker", "TranslatesTo": "https://evidencelocker.stella-ops.local" },
{ "Type": "ReverseProxy", "Path": "/signer", "TranslatesTo": "http://signer.stella-ops.local" },
{ "Type": "ReverseProxy", "Path": "/binaryindex", "TranslatesTo": "http://binaryindex.stella-ops.local" },
{ "Type": "ReverseProxy", "Path": "/riskengine", "TranslatesTo": "http://riskengine.stella-ops.local" },
{ "Type": "ReverseProxy", "Path": "/vulnexplorer", "TranslatesTo": "http://vulnexplorer.stella-ops.local" },
{ "Type": "ReverseProxy", "Path": "/sbomservice", "TranslatesTo": "http://sbomservice.stella-ops.local" },
{ "Type": "ReverseProxy", "Path": "/advisoryai", "TranslatesTo": "http://advisoryai.stella-ops.local" },
{ "Type": "ReverseProxy", "Path": "/unknowns", "TranslatesTo": "http://unknowns.stella-ops.local" },
{ "Type": "ReverseProxy", "Path": "/timelineindexer", "TranslatesTo": "http://timelineindexer.stella-ops.local" },
{ "Type": "ReverseProxy", "Path": "/opsmemory", "TranslatesTo": "http://opsmemory.stella-ops.local" },
{ "Type": "ReverseProxy", "Path": "/issuerdirectory", "TranslatesTo": "http://issuerdirectory.stella-ops.local" },
{ "Type": "ReverseProxy", "Path": "/symbols", "TranslatesTo": "http://symbols.stella-ops.local" },
{ "Type": "ReverseProxy", "Path": "/packsregistry", "TranslatesTo": "http://packsregistry.stella-ops.local" },
{ "Type": "ReverseProxy", "Path": "/registryTokenservice", "TranslatesTo": "http://registry-token.stella-ops.local" },
{ "Type": "ReverseProxy", "Path": "/airgapController", "TranslatesTo": "http://airgap-controller.stella-ops.local" },
{ "Type": "ReverseProxy", "Path": "/airgapTime", "TranslatesTo": "http://airgap-time.stella-ops.local" },
{ "Type": "ReverseProxy", "Path": "/smremote", "TranslatesTo": "http://smremote.stella-ops.local" },
{ "Type": "StaticFiles", "Path": "/", "TranslatesTo": "/app/wwwroot", "Headers": { "x-spa-fallback": "true" } },
{ "Type": "NotFoundPage", "Path": "/_error/404", "TranslatesTo": "/app/wwwroot/index.html" },
{ "Type": "ServerErrorPage", "Path": "/_error/500", "TranslatesTo": "/app/wwwroot/index.html" }
]
},
"Logging": {
"LogLevel": {
"Microsoft.AspNetCore.Authentication": "Debug",
"Microsoft.IdentityModel": "Debug",
"StellaOps": "Debug"
}
}
{
"Gateway": {
"Auth": {
"DpopEnabled": false,
"AllowAnonymous": true,
"EnableLegacyHeaders": true,
"AllowScopeHeader": false,
"Authority": {
"Issuer": "https://authority.stella-ops.local/",
"RequireHttpsMetadata": false,
"MetadataAddress": "https://authority.stella-ops.local/.well-known/openid-configuration",
"Audiences": [
]
}
},
"Routes": [
{
"Type": "Microservice",
"Path": "/api/v1/release-orchestrator",
"TranslatesTo": "http://orchestrator.stella-ops.local/api/v1/release-orchestrator",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/v1/vex",
"TranslatesTo": "https://vexhub.stella-ops.local/api/v1/vex",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/v1/vexlens",
"TranslatesTo": "http://vexlens.stella-ops.local/api/v1/vexlens",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/v1/notify",
"TranslatesTo": "http://notify.stella-ops.local/api/v1/notify",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/v1/notifier",
"TranslatesTo": "http://notifier.stella-ops.local/api/v1/notifier",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/v1/concelier",
"TranslatesTo": "http://concelier.stella-ops.local/api/v1/concelier",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/v1/platform",
"TranslatesTo": "http://platform.stella-ops.local/api/v1/platform",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/v1/scanner",
"TranslatesTo": "http://scanner.stella-ops.local/api/v1/scanner",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/v1/findings",
"TranslatesTo": "http://findings.stella-ops.local/api/v1/findings",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/v1/integrations",
"TranslatesTo": "http://integrations.stella-ops.local/api/v1/integrations",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/v1/policy",
"TranslatesTo": "http://policy-gateway.stella-ops.local/api/v1/policy",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/v1/reachability",
"TranslatesTo": "http://reachgraph.stella-ops.local/api/v1/reachability",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/v1/attestor",
"TranslatesTo": "http://attestor.stella-ops.local/api/v1/attestor",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/v1/attestations",
"TranslatesTo": "http://attestor.stella-ops.local/api/v1/attestations",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/v1/sbom",
"TranslatesTo": "http://sbomservice.stella-ops.local/api/v1/sbom",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/v1/signals",
"TranslatesTo": "http://signals.stella-ops.local/api/v1/signals",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/v1/orchestrator",
"TranslatesTo": "http://orchestrator.stella-ops.local/api/v1/orchestrator",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/v1/authority/quotas",
"TranslatesTo": "http://platform.stella-ops.local/api/v1/authority/quotas",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/v1/authority",
"TranslatesTo": "https://authority.stella-ops.local/api/v1/authority",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/v1/trust",
"TranslatesTo": "https://authority.stella-ops.local/api/v1/trust",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/v1/evidence",
"TranslatesTo": "https://evidencelocker.stella-ops.local/api/v1/evidence",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/v1/proofs",
"TranslatesTo": "https://evidencelocker.stella-ops.local/api/v1/proofs",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/v1/timeline",
"TranslatesTo": "http://timelineindexer.stella-ops.local/api/v1/timeline",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/v1/advisory-ai/adapters",
"TranslatesTo": "http://advisoryai.stella-ops.local/v1/advisory-ai/adapters",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/v1/advisory-ai",
"TranslatesTo": "http://advisoryai.stella-ops.local/api/v1/advisory-ai",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/v1/advisory",
"TranslatesTo": "http://advisoryai.stella-ops.local/api/v1/advisory",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/v1/vulnerabilities",
"TranslatesTo": "http://scanner.stella-ops.local/api/v1/vulnerabilities",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/v1/watchlist",
"TranslatesTo": "http://scanner.stella-ops.local/api/v1/watchlist",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/v1/resolve",
"TranslatesTo": "http://binaryindex.stella-ops.local/api/v1/resolve",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/v1/ops/binaryindex",
"TranslatesTo": "http://binaryindex.stella-ops.local/api/v1/ops/binaryindex",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/v1/verdicts",
"TranslatesTo": "https://evidencelocker.stella-ops.local/api/v1/verdicts",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/v1/lineage",
"TranslatesTo": "http://sbomservice.stella-ops.local/api/v1/lineage",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/v1/export",
"TranslatesTo": "https://exportcenter.stella-ops.local/api/v1/export",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/v1/triage",
"TranslatesTo": "http://scanner.stella-ops.local/api/v1/triage",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/v1/governance",
"TranslatesTo": "http://policy-gateway.stella-ops.local/api/v1/governance",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/v1/determinization",
"TranslatesTo": "http://policy-engine.stella-ops.local/api/v1/determinization",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/v1/opsmemory",
"TranslatesTo": "http://opsmemory.stella-ops.local/api/v1/opsmemory",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/v1/secrets",
"TranslatesTo": "http://scanner.stella-ops.local/api/v1/secrets",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/v1/sources",
"TranslatesTo": "http://sbomservice.stella-ops.local/api/v1/sources",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/v1/workflows",
"TranslatesTo": "http://orchestrator.stella-ops.local/api/v1/workflows",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/v1/witnesses",
"TranslatesTo": "http://attestor.stella-ops.local/api/v1/witnesses",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/v1/evidence-packs",
"TranslatesTo": "https://evidencelocker.stella-ops.local/v1/evidence-packs",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/v1/runs",
"TranslatesTo": "http://orchestrator.stella-ops.local/v1/runs",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/v1/advisory-ai/adapters",
"TranslatesTo": "http://advisoryai.stella-ops.local/v1/advisory-ai/adapters",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/v1/advisory-ai",
"TranslatesTo": "http://advisoryai.stella-ops.local/v1/advisory-ai",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/v1/audit-bundles",
"TranslatesTo": "https://exportcenter.stella-ops.local/v1/audit-bundles",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/policy",
"TranslatesTo": "http://policy-gateway.stella-ops.local",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/cvss",
"TranslatesTo": "http://policy-gateway.stella-ops.local/api/cvss",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/policy",
"TranslatesTo": "http://policy-gateway.stella-ops.local/api/policy",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/risk",
"TranslatesTo": "http://policy-engine.stella-ops.local/api/risk",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/analytics",
"TranslatesTo": "http://platform.stella-ops.local/api/analytics",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/release-orchestrator",
"TranslatesTo": "http://orchestrator.stella-ops.local/api/release-orchestrator",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/releases",
"TranslatesTo": "http://orchestrator.stella-ops.local/api/releases",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/approvals",
"TranslatesTo": "http://orchestrator.stella-ops.local/api/approvals",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/gate",
"TranslatesTo": "http://policy-gateway.stella-ops.local/api/gate",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/risk-budget",
"TranslatesTo": "http://policy-engine.stella-ops.local/api/risk-budget",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/fix-verification",
"TranslatesTo": "http://scanner.stella-ops.local/api/fix-verification",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/compare",
"TranslatesTo": "http://sbomservice.stella-ops.local/api/compare",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/change-traces",
"TranslatesTo": "http://sbomservice.stella-ops.local/api/change-traces",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/exceptions",
"TranslatesTo": "http://policy-gateway.stella-ops.local/api/exceptions",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/verdicts",
"TranslatesTo": "https://evidencelocker.stella-ops.local/api/verdicts",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/orchestrator",
"TranslatesTo": "http://orchestrator.stella-ops.local/api/orchestrator",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/v1/gateway/rate-limits",
"TranslatesTo": "http://platform.stella-ops.local/api/v1/gateway/rate-limits",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/sbomservice",
"TranslatesTo": "http://sbomservice.stella-ops.local/api/sbomservice",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/vuln-explorer",
"TranslatesTo": "http://vulnexplorer.stella-ops.local/api/vuln-explorer",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/vex",
"TranslatesTo": "https://vexhub.stella-ops.local/api/vex",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/admin",
"TranslatesTo": "http://platform.stella-ops.local/api/admin",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/scheduler",
"TranslatesTo": "http://scheduler.stella-ops.local/api/scheduler",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/v1/doctor/scheduler",
"TranslatesTo": "http://doctor-scheduler.stella-ops.local/api/v1/doctor/scheduler",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api/doctor",
"TranslatesTo": "http://doctor.stella-ops.local/api/doctor",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/api",
"TranslatesTo": "http://platform.stella-ops.local/api",
"PreserveAuthHeaders": true
},
{
"Type": "StaticFile",
"Path": "/platform/envsettings.json",
"TranslatesTo": "/app/envsettings-override.json"
},
{
"Type": "ReverseProxy",
"Path": "/platform",
"TranslatesTo": "http://platform.stella-ops.local/platform"
},
{
"Type": "Microservice",
"Path": "/connect",
"TranslatesTo": "https://authority.stella-ops.local/connect",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/.well-known",
"TranslatesTo": "https://authority.stella-ops.local/well-known",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/jwks",
"TranslatesTo": "https://authority.stella-ops.local/jwks",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/authority",
"TranslatesTo": "https://authority.stella-ops.local/authority",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/console",
"TranslatesTo": "https://authority.stella-ops.local/console",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/rekor",
"TranslatesTo": "http://rekor.stella-ops.local:3322"
},
{
"Type": "ReverseProxy",
"Path": "/envsettings.json",
"TranslatesTo": "http://platform.stella-ops.local/platform/envsettings.json"
},
{
"Type": "Microservice",
"Path": "/gateway",
"TranslatesTo": "http://gateway.stella-ops.local"
},
{
"Type": "Microservice",
"Path": "/scanner",
"TranslatesTo": "http://scanner.stella-ops.local"
},
{
"Type": "Microservice",
"Path": "/policyGateway",
"TranslatesTo": "http://policy-gateway.stella-ops.local"
},
{
"Type": "Microservice",
"Path": "/policyEngine",
"TranslatesTo": "http://policy-engine.stella-ops.local"
},
{
"Type": "Microservice",
"Path": "/concelier",
"TranslatesTo": "http://concelier.stella-ops.local"
},
{
"Type": "Microservice",
"Path": "/attestor",
"TranslatesTo": "http://attestor.stella-ops.local"
},
{
"Type": "Microservice",
"Path": "/notify",
"TranslatesTo": "http://notify.stella-ops.local"
},
{
"Type": "Microservice",
"Path": "/notifier",
"TranslatesTo": "http://notifier.stella-ops.local"
},
{
"Type": "Microservice",
"Path": "/scheduler",
"TranslatesTo": "http://scheduler.stella-ops.local"
},
{
"Type": "Microservice",
"Path": "/signals",
"TranslatesTo": "http://signals.stella-ops.local"
},
{
"Type": "Microservice",
"Path": "/excititor",
"TranslatesTo": "http://excititor.stella-ops.local"
},
{
"Type": "Microservice",
"Path": "/findingsLedger",
"TranslatesTo": "http://findings.stella-ops.local"
},
{
"Type": "Microservice",
"Path": "/vexhub",
"TranslatesTo": "https://vexhub.stella-ops.local"
},
{
"Type": "Microservice",
"Path": "/vexlens",
"TranslatesTo": "http://vexlens.stella-ops.local"
},
{
"Type": "Microservice",
"Path": "/orchestrator",
"TranslatesTo": "http://orchestrator.stella-ops.local"
},
{
"Type": "Microservice",
"Path": "/taskrunner",
"TranslatesTo": "http://taskrunner.stella-ops.local"
},
{
"Type": "Microservice",
"Path": "/cartographer",
"TranslatesTo": "http://cartographer.stella-ops.local"
},
{
"Type": "Microservice",
"Path": "/reachgraph",
"TranslatesTo": "http://reachgraph.stella-ops.local"
},
{
"Type": "Microservice",
"Path": "/doctor",
"TranslatesTo": "http://doctor.stella-ops.local",
"PreserveAuthHeaders": true
},
{
"Type": "Microservice",
"Path": "/integrations",
"TranslatesTo": "http://integrations.stella-ops.local"
},
{
"Type": "Microservice",
"Path": "/replay",
"TranslatesTo": "http://replay.stella-ops.local"
},
{
"Type": "Microservice",
"Path": "/exportcenter",
"TranslatesTo": "https://exportcenter.stella-ops.local"
},
{
"Type": "Microservice",
"Path": "/evidencelocker",
"TranslatesTo": "https://evidencelocker.stella-ops.local"
},
{
"Type": "Microservice",
"Path": "/signer",
"TranslatesTo": "http://signer.stella-ops.local"
},
{
"Type": "Microservice",
"Path": "/binaryindex",
"TranslatesTo": "http://binaryindex.stella-ops.local"
},
{
"Type": "Microservice",
"Path": "/riskengine",
"TranslatesTo": "http://riskengine.stella-ops.local"
},
{
"Type": "Microservice",
"Path": "/vulnexplorer",
"TranslatesTo": "http://vulnexplorer.stella-ops.local"
},
{
"Type": "Microservice",
"Path": "/sbomservice",
"TranslatesTo": "http://sbomservice.stella-ops.local"
},
{
"Type": "Microservice",
"Path": "/advisoryai",
"TranslatesTo": "http://advisoryai.stella-ops.local"
},
{
"Type": "Microservice",
"Path": "/unknowns",
"TranslatesTo": "http://unknowns.stella-ops.local"
},
{
"Type": "Microservice",
"Path": "/timelineindexer",
"TranslatesTo": "http://timelineindexer.stella-ops.local"
},
{
"Type": "Microservice",
"Path": "/opsmemory",
"TranslatesTo": "http://opsmemory.stella-ops.local"
},
{
"Type": "Microservice",
"Path": "/issuerdirectory",
"TranslatesTo": "http://issuerdirectory.stella-ops.local"
},
{
"Type": "Microservice",
"Path": "/symbols",
"TranslatesTo": "http://symbols.stella-ops.local"
},
{
"Type": "Microservice",
"Path": "/packsregistry",
"TranslatesTo": "http://packsregistry.stella-ops.local"
},
{
"Type": "Microservice",
"Path": "/registryTokenservice",
"TranslatesTo": "http://registry-token.stella-ops.local"
},
{
"Type": "Microservice",
"Path": "/airgapController",
"TranslatesTo": "http://airgap-controller.stella-ops.local"
},
{
"Type": "Microservice",
"Path": "/airgapTime",
"TranslatesTo": "http://airgap-time.stella-ops.local"
},
{
"Type": "Microservice",
"Path": "/smremote",
"TranslatesTo": "http://smremote.stella-ops.local"
},
{
"Type": "StaticFiles",
"Path": "/",
"TranslatesTo": "/app/wwwroot",
"Headers": {
"x-spa-fallback": "true"
}
},
{
"Type": "NotFoundPage",
"Path": "/_error/404",
"TranslatesTo": "/app/wwwroot/index.html"
},
{
"Type": "ServerErrorPage",
"Path": "/_error/500",
"TranslatesTo": "/app/wwwroot/index.html"
}
]
},
"Logging": {
"LogLevel": {
"Microsoft.AspNetCore.Authentication": "Debug",
"Microsoft.IdentityModel": "Debug",
"StellaOps": "Debug"
}
}
}

View File

@@ -0,0 +1,717 @@
{
"Gateway": {
"Auth": {
"DpopEnabled": false,
"AllowAnonymous": true,
"EnableLegacyHeaders": true,
"AllowScopeHeader": false,
"Authority": {
"Issuer": "https://authority.stella-ops.local/",
"RequireHttpsMetadata": false,
"MetadataAddress": "https://authority.stella-ops.local/.well-known/openid-configuration",
"Audiences": [
]
}
},
"Routes": [
{
"Type": "ReverseProxy",
"Path": "/api/v1/release-orchestrator",
"TranslatesTo": "http://orchestrator.stella-ops.local/api/v1/release-orchestrator",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/v1/vex",
"TranslatesTo": "https://vexhub.stella-ops.local/api/v1/vex",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/v1/vexlens",
"TranslatesTo": "http://vexlens.stella-ops.local/api/v1/vexlens",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/v1/notify",
"TranslatesTo": "http://notify.stella-ops.local/api/v1/notify",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/v1/notifier",
"TranslatesTo": "http://notifier.stella-ops.local/api/v1/notifier",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/v1/concelier",
"TranslatesTo": "http://concelier.stella-ops.local/api/v1/concelier",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/v1/platform",
"TranslatesTo": "http://platform.stella-ops.local/api/v1/platform",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/v1/scanner",
"TranslatesTo": "http://scanner.stella-ops.local/api/v1/scanner",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/v1/findings",
"TranslatesTo": "http://findings.stella-ops.local/api/v1/findings",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/v1/integrations",
"TranslatesTo": "http://integrations.stella-ops.local/api/v1/integrations",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/v1/policy",
"TranslatesTo": "http://policy-gateway.stella-ops.local/api/v1/policy",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/v1/reachability",
"TranslatesTo": "http://reachgraph.stella-ops.local/api/v1/reachability",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/v1/attestor",
"TranslatesTo": "http://attestor.stella-ops.local/api/v1/attestor",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/v1/attestations",
"TranslatesTo": "http://attestor.stella-ops.local/api/v1/attestations",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/v1/sbom",
"TranslatesTo": "http://sbomservice.stella-ops.local/api/v1/sbom",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/v1/signals",
"TranslatesTo": "http://signals.stella-ops.local/api/v1/signals",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/v1/orchestrator",
"TranslatesTo": "http://orchestrator.stella-ops.local/api/v1/orchestrator",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/v1/authority/quotas",
"TranslatesTo": "http://platform.stella-ops.local/api/v1/authority/quotas",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/v1/authority",
"TranslatesTo": "https://authority.stella-ops.local/api/v1/authority",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/v1/trust",
"TranslatesTo": "https://authority.stella-ops.local/api/v1/trust",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/v1/evidence",
"TranslatesTo": "https://evidencelocker.stella-ops.local/api/v1/evidence",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/v1/proofs",
"TranslatesTo": "https://evidencelocker.stella-ops.local/api/v1/proofs",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/v1/timeline",
"TranslatesTo": "http://timelineindexer.stella-ops.local/api/v1/timeline",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/v1/advisory-ai/adapters",
"TranslatesTo": "http://advisoryai.stella-ops.local/v1/advisory-ai/adapters",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/v1/advisory-ai",
"TranslatesTo": "http://advisoryai.stella-ops.local/api/v1/advisory-ai",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/v1/advisory",
"TranslatesTo": "http://advisoryai.stella-ops.local/api/v1/advisory",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/v1/vulnerabilities",
"TranslatesTo": "http://scanner.stella-ops.local/api/v1/vulnerabilities",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/v1/watchlist",
"TranslatesTo": "http://scanner.stella-ops.local/api/v1/watchlist",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/v1/resolve",
"TranslatesTo": "http://binaryindex.stella-ops.local/api/v1/resolve",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/v1/ops/binaryindex",
"TranslatesTo": "http://binaryindex.stella-ops.local/api/v1/ops/binaryindex",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/v1/verdicts",
"TranslatesTo": "https://evidencelocker.stella-ops.local/api/v1/verdicts",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/v1/lineage",
"TranslatesTo": "http://sbomservice.stella-ops.local/api/v1/lineage",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/v1/export",
"TranslatesTo": "https://exportcenter.stella-ops.local/api/v1/export",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/v1/triage",
"TranslatesTo": "http://scanner.stella-ops.local/api/v1/triage",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/v1/governance",
"TranslatesTo": "http://policy-gateway.stella-ops.local/api/v1/governance",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/v1/determinization",
"TranslatesTo": "http://policy-engine.stella-ops.local/api/v1/determinization",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/v1/opsmemory",
"TranslatesTo": "http://opsmemory.stella-ops.local/api/v1/opsmemory",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/v1/secrets",
"TranslatesTo": "http://scanner.stella-ops.local/api/v1/secrets",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/v1/sources",
"TranslatesTo": "http://sbomservice.stella-ops.local/api/v1/sources",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/v1/workflows",
"TranslatesTo": "http://orchestrator.stella-ops.local/api/v1/workflows",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/v1/witnesses",
"TranslatesTo": "http://attestor.stella-ops.local/api/v1/witnesses",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/v1/evidence-packs",
"TranslatesTo": "https://evidencelocker.stella-ops.local/v1/evidence-packs",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/v1/runs",
"TranslatesTo": "http://orchestrator.stella-ops.local/v1/runs",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/v1/advisory-ai/adapters",
"TranslatesTo": "http://advisoryai.stella-ops.local/v1/advisory-ai/adapters",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/v1/advisory-ai",
"TranslatesTo": "http://advisoryai.stella-ops.local/v1/advisory-ai",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/v1/audit-bundles",
"TranslatesTo": "https://exportcenter.stella-ops.local/v1/audit-bundles",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/policy",
"TranslatesTo": "http://policy-gateway.stella-ops.local",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/cvss",
"TranslatesTo": "http://policy-gateway.stella-ops.local/api/cvss",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/policy",
"TranslatesTo": "http://policy-gateway.stella-ops.local/api/policy",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/risk",
"TranslatesTo": "http://policy-engine.stella-ops.local/api/risk",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/analytics",
"TranslatesTo": "http://platform.stella-ops.local/api/analytics",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/release-orchestrator",
"TranslatesTo": "http://orchestrator.stella-ops.local/api/release-orchestrator",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/releases",
"TranslatesTo": "http://orchestrator.stella-ops.local/api/releases",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/approvals",
"TranslatesTo": "http://orchestrator.stella-ops.local/api/approvals",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/gate",
"TranslatesTo": "http://policy-gateway.stella-ops.local/api/gate",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/risk-budget",
"TranslatesTo": "http://policy-engine.stella-ops.local/api/risk-budget",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/fix-verification",
"TranslatesTo": "http://scanner.stella-ops.local/api/fix-verification",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/compare",
"TranslatesTo": "http://sbomservice.stella-ops.local/api/compare",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/change-traces",
"TranslatesTo": "http://sbomservice.stella-ops.local/api/change-traces",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/exceptions",
"TranslatesTo": "http://policy-gateway.stella-ops.local/api/exceptions",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/verdicts",
"TranslatesTo": "https://evidencelocker.stella-ops.local/api/verdicts",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/orchestrator",
"TranslatesTo": "http://orchestrator.stella-ops.local/api/orchestrator",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/v1/gateway/rate-limits",
"TranslatesTo": "http://platform.stella-ops.local/api/v1/gateway/rate-limits",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/sbomservice",
"TranslatesTo": "http://sbomservice.stella-ops.local/api/sbomservice",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/vuln-explorer",
"TranslatesTo": "http://vulnexplorer.stella-ops.local/api/vuln-explorer",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/vex",
"TranslatesTo": "https://vexhub.stella-ops.local/api/vex",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/admin",
"TranslatesTo": "http://platform.stella-ops.local/api/admin",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/scheduler",
"TranslatesTo": "http://scheduler.stella-ops.local/api/scheduler",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/v1/doctor/scheduler",
"TranslatesTo": "http://doctor-scheduler.stella-ops.local/api/v1/doctor/scheduler",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api/doctor",
"TranslatesTo": "http://doctor.stella-ops.local/api/doctor",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/api",
"TranslatesTo": "http://platform.stella-ops.local/api",
"PreserveAuthHeaders": true
},
{
"Type": "StaticFile",
"Path": "/platform/envsettings.json",
"TranslatesTo": "/app/envsettings-override.json"
},
{
"Type": "ReverseProxy",
"Path": "/platform",
"TranslatesTo": "http://platform.stella-ops.local/platform"
},
{
"Type": "ReverseProxy",
"Path": "/connect",
"TranslatesTo": "https://authority.stella-ops.local/connect",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/.well-known",
"TranslatesTo": "https://authority.stella-ops.local/well-known",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/jwks",
"TranslatesTo": "https://authority.stella-ops.local/jwks",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/authority",
"TranslatesTo": "https://authority.stella-ops.local/authority",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/console",
"TranslatesTo": "https://authority.stella-ops.local/console",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/rekor",
"TranslatesTo": "http://rekor.stella-ops.local:3322"
},
{
"Type": "ReverseProxy",
"Path": "/envsettings.json",
"TranslatesTo": "http://platform.stella-ops.local/platform/envsettings.json"
},
{
"Type": "ReverseProxy",
"Path": "/gateway",
"TranslatesTo": "http://gateway.stella-ops.local"
},
{
"Type": "ReverseProxy",
"Path": "/scanner",
"TranslatesTo": "http://scanner.stella-ops.local"
},
{
"Type": "ReverseProxy",
"Path": "/policyGateway",
"TranslatesTo": "http://policy-gateway.stella-ops.local"
},
{
"Type": "ReverseProxy",
"Path": "/policyEngine",
"TranslatesTo": "http://policy-engine.stella-ops.local"
},
{
"Type": "ReverseProxy",
"Path": "/concelier",
"TranslatesTo": "http://concelier.stella-ops.local"
},
{
"Type": "ReverseProxy",
"Path": "/attestor",
"TranslatesTo": "http://attestor.stella-ops.local"
},
{
"Type": "ReverseProxy",
"Path": "/notify",
"TranslatesTo": "http://notify.stella-ops.local"
},
{
"Type": "ReverseProxy",
"Path": "/notifier",
"TranslatesTo": "http://notifier.stella-ops.local"
},
{
"Type": "ReverseProxy",
"Path": "/scheduler",
"TranslatesTo": "http://scheduler.stella-ops.local"
},
{
"Type": "ReverseProxy",
"Path": "/signals",
"TranslatesTo": "http://signals.stella-ops.local"
},
{
"Type": "ReverseProxy",
"Path": "/excititor",
"TranslatesTo": "http://excititor.stella-ops.local"
},
{
"Type": "ReverseProxy",
"Path": "/findingsLedger",
"TranslatesTo": "http://findings.stella-ops.local"
},
{
"Type": "ReverseProxy",
"Path": "/vexhub",
"TranslatesTo": "https://vexhub.stella-ops.local"
},
{
"Type": "ReverseProxy",
"Path": "/vexlens",
"TranslatesTo": "http://vexlens.stella-ops.local"
},
{
"Type": "ReverseProxy",
"Path": "/orchestrator",
"TranslatesTo": "http://orchestrator.stella-ops.local"
},
{
"Type": "ReverseProxy",
"Path": "/taskrunner",
"TranslatesTo": "http://taskrunner.stella-ops.local"
},
{
"Type": "ReverseProxy",
"Path": "/cartographer",
"TranslatesTo": "http://cartographer.stella-ops.local"
},
{
"Type": "ReverseProxy",
"Path": "/reachgraph",
"TranslatesTo": "http://reachgraph.stella-ops.local"
},
{
"Type": "ReverseProxy",
"Path": "/doctor",
"TranslatesTo": "http://doctor.stella-ops.local",
"PreserveAuthHeaders": true
},
{
"Type": "ReverseProxy",
"Path": "/integrations",
"TranslatesTo": "http://integrations.stella-ops.local"
},
{
"Type": "ReverseProxy",
"Path": "/replay",
"TranslatesTo": "http://replay.stella-ops.local"
},
{
"Type": "ReverseProxy",
"Path": "/exportcenter",
"TranslatesTo": "https://exportcenter.stella-ops.local"
},
{
"Type": "ReverseProxy",
"Path": "/evidencelocker",
"TranslatesTo": "https://evidencelocker.stella-ops.local"
},
{
"Type": "ReverseProxy",
"Path": "/signer",
"TranslatesTo": "http://signer.stella-ops.local"
},
{
"Type": "ReverseProxy",
"Path": "/binaryindex",
"TranslatesTo": "http://binaryindex.stella-ops.local"
},
{
"Type": "ReverseProxy",
"Path": "/riskengine",
"TranslatesTo": "http://riskengine.stella-ops.local"
},
{
"Type": "ReverseProxy",
"Path": "/vulnexplorer",
"TranslatesTo": "http://vulnexplorer.stella-ops.local"
},
{
"Type": "ReverseProxy",
"Path": "/sbomservice",
"TranslatesTo": "http://sbomservice.stella-ops.local"
},
{
"Type": "ReverseProxy",
"Path": "/advisoryai",
"TranslatesTo": "http://advisoryai.stella-ops.local"
},
{
"Type": "ReverseProxy",
"Path": "/unknowns",
"TranslatesTo": "http://unknowns.stella-ops.local"
},
{
"Type": "ReverseProxy",
"Path": "/timelineindexer",
"TranslatesTo": "http://timelineindexer.stella-ops.local"
},
{
"Type": "ReverseProxy",
"Path": "/opsmemory",
"TranslatesTo": "http://opsmemory.stella-ops.local"
},
{
"Type": "ReverseProxy",
"Path": "/issuerdirectory",
"TranslatesTo": "http://issuerdirectory.stella-ops.local"
},
{
"Type": "ReverseProxy",
"Path": "/symbols",
"TranslatesTo": "http://symbols.stella-ops.local"
},
{
"Type": "ReverseProxy",
"Path": "/packsregistry",
"TranslatesTo": "http://packsregistry.stella-ops.local"
},
{
"Type": "ReverseProxy",
"Path": "/registryTokenservice",
"TranslatesTo": "http://registry-token.stella-ops.local"
},
{
"Type": "ReverseProxy",
"Path": "/airgapController",
"TranslatesTo": "http://airgap-controller.stella-ops.local"
},
{
"Type": "ReverseProxy",
"Path": "/airgapTime",
"TranslatesTo": "http://airgap-time.stella-ops.local"
},
{
"Type": "ReverseProxy",
"Path": "/smremote",
"TranslatesTo": "http://smremote.stella-ops.local"
},
{
"Type": "StaticFiles",
"Path": "/",
"TranslatesTo": "/app/wwwroot",
"Headers": {
"x-spa-fallback": "true"
}
},
{
"Type": "NotFoundPage",
"Path": "/_error/404",
"TranslatesTo": "/app/wwwroot/index.html"
},
{
"Type": "ServerErrorPage",
"Path": "/_error/500",
"TranslatesTo": "/app/wwwroot/index.html"
}
]
},
"Logging": {
"LogLevel": {
"Microsoft.AspNetCore.Authentication": "Debug",
"Microsoft.IdentityModel": "Debug",
"StellaOps": "Debug"
}
}
}

View File

@@ -0,0 +1,129 @@
param(
[ValidateSet("microservice", "reverseproxy")]
[string]$Mode = "microservice",
[string]$ComposeFile = "docker-compose.stella-ops.yml",
[int]$WaitTimeoutSeconds = 1200,
[int]$RecoveryAttempts = 2,
[int]$RecoveryWaitSeconds = 180
)
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
$ProgressPreference = "SilentlyContinue"
$configPath = switch ($Mode) {
"microservice" { "./router-gateway-local.json" }
"reverseproxy" { "./router-gateway-local.reverseproxy.json" }
default { throw "Unsupported mode: $Mode" }
}
Write-Host "Redeploy mode: $Mode"
Write-Host "Gateway config: $configPath"
Write-Host "Compose file: $ComposeFile"
$env:ROUTER_GATEWAY_CONFIG = $configPath
function Invoke-Compose {
param(
[Parameter(Mandatory = $true)]
[string[]]$Args,
[switch]$IgnoreExitCode
)
& docker compose -f $ComposeFile @Args
$exitCode = $LASTEXITCODE
if (-not $IgnoreExitCode -and $exitCode -ne 0) {
throw "docker compose $($Args -join ' ') failed with exit code $exitCode."
}
return $exitCode
}
function Get-UnhealthyContainers {
$containers = & docker ps --filter "health=unhealthy" --format "{{.Names}}"
if ($LASTEXITCODE -ne 0) {
throw "Failed to query unhealthy containers."
}
$filtered = @($containers | Where-Object { -not [string]::IsNullOrWhiteSpace($_) -and $_ -like "stellaops-*" })
return [string[]]$filtered
}
function Get-ComposeServiceName {
param(
[Parameter(Mandatory = $true)]
[string]$ContainerName
)
$service = & docker inspect --format "{{ index .Config.Labels \"com.docker.compose.service\" }}" $ContainerName 2>$null
if ($LASTEXITCODE -ne 0 -or [string]::IsNullOrWhiteSpace($service)) {
return $null
}
return $service.Trim()
}
function Wait-ForContainerHealth {
param(
[Parameter(Mandatory = $true)]
[string]$ContainerName,
[Parameter(Mandatory = $true)]
[int]$TimeoutSeconds
)
$deadline = (Get-Date).AddSeconds($TimeoutSeconds)
while ((Get-Date) -lt $deadline) {
$status = (& docker inspect --format "{{if .State.Health}}{{.State.Health.Status}}{{else}}none{{end}}" $ContainerName 2>$null).Trim()
if ($LASTEXITCODE -ne 0) {
return $false
}
if ($status -eq "healthy" -or $status -eq "none") {
return $true
}
Start-Sleep -Seconds 5
}
return $false
}
Invoke-Compose -Args @("down", "-v", "--remove-orphans") | Out-Null
$upExitCode = Invoke-Compose -Args @("up", "-d", "--wait", "--wait-timeout", $WaitTimeoutSeconds.ToString()) -IgnoreExitCode
if ($upExitCode -ne 0) {
Write-Warning "docker compose up returned exit code $upExitCode. Running unhealthy-service recovery."
}
for ($attempt = 1; $attempt -le $RecoveryAttempts; $attempt++) {
$unhealthyContainers = @(Get-UnhealthyContainers)
if ($unhealthyContainers.Count -eq 0) {
break
}
Write-Warning "Recovery attempt ${attempt}: unhealthy containers detected: $($unhealthyContainers -join ', ')"
$services = New-Object System.Collections.Generic.HashSet[string]([System.StringComparer]::OrdinalIgnoreCase)
foreach ($containerName in $unhealthyContainers) {
$serviceName = Get-ComposeServiceName -ContainerName $containerName
if (-not [string]::IsNullOrWhiteSpace($serviceName)) {
[void]$services.Add($serviceName)
}
}
foreach ($serviceName in $services) {
Write-Host "Recreating service: $serviceName"
Invoke-Compose -Args @("up", "-d", "--force-recreate", "--no-deps", $serviceName) | Out-Null
}
foreach ($containerName in $unhealthyContainers) {
[void](Wait-ForContainerHealth -ContainerName $containerName -TimeoutSeconds $RecoveryWaitSeconds)
}
}
$remainingUnhealthy = @(Get-UnhealthyContainers)
if ($remainingUnhealthy.Count -gt 0) {
throw "Redeploy completed with unresolved unhealthy containers: $($remainingUnhealthy -join ', ')"
}
Write-Host "Redeploy complete for mode '$Mode'."

View File

@@ -0,0 +1,102 @@
param(
[string]$RouterConfigPath = "devops/compose/router-gateway-local.json",
[string]$OpenApiPath = "devops/compose/openapi_current.json",
[string]$GatewayBaseUrl = "https://127.1.0.1",
[ValidateSet("Microservice", "ReverseProxy", "StaticFiles")]
[string]$RouteType = "Microservice",
[string]$OutputCsv = "devops/compose/openapi_routeprefix_smoke.csv"
)
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
$ProgressPreference = "SilentlyContinue"
function Get-JsonFromFile {
param([Parameter(Mandatory = $true)][string]$Path)
if (-not (Test-Path -LiteralPath $Path)) {
throw "File not found: $Path"
}
return Get-Content -LiteralPath $Path -Raw | ConvertFrom-Json
}
function Get-OpenApiPathMap {
param([Parameter(Mandatory = $true)]$OpenApi)
$map = @{}
foreach ($prop in $OpenApi.paths.PSObject.Properties) {
$map[$prop.Name] = $prop.Value
}
return $map
}
function Get-HttpStatusCode {
param(
[Parameter(Mandatory = $true)][string]$Url
)
$statusText = (& curl.exe -k -s -o NUL -w "%{http_code}" $Url).Trim()
if ($statusText -match "^\d{3}$") {
return [int]$statusText
}
return -1
}
$routerConfig = Get-JsonFromFile -Path $RouterConfigPath
$openApi = Get-JsonFromFile -Path $OpenApiPath
$openApiPathMap = Get-OpenApiPathMap -OpenApi $openApi
$openApiPaths = @($openApiPathMap.Keys)
$routes = @($routerConfig.Gateway.Routes | Where-Object { $_.Type -eq $RouteType })
$rows = New-Object System.Collections.Generic.List[object]
foreach ($route in $routes) {
$prefix = [string]$route.Path
$matches = @()
foreach ($candidate in $openApiPaths) {
if ($candidate.StartsWith($prefix, [System.StringComparison]::OrdinalIgnoreCase)) {
$operation = $openApiPathMap[$candidate]
if ($null -ne $operation -and $operation.PSObject.Properties.Match("get").Count -gt 0) {
$matches += $candidate
}
}
}
$selectedPath = $null
if ($matches.Count -gt 0) {
$selectedPath = ($matches | Sort-Object `
@{ Expression = { $_ -match '\{[^}]+\}' } }, `
@{ Expression = { $_ -match '(^|/)(startupz|readyz|livez)$' } }, `
@{ Expression = { $_.Length } }, `
@{ Expression = { $_ } })[0]
}
$status = $null
if ($null -ne $selectedPath) {
$url = "$GatewayBaseUrl$selectedPath"
$status = Get-HttpStatusCode -Url $url
}
$rows.Add([pscustomobject]@{
RouteType = $RouteType
RoutePath = $prefix
RouteTarget = [string]$route.TranslatesTo
SelectedOpenApiPath = $selectedPath
StatusCode = $status
})
}
$rows | Export-Csv -LiteralPath $OutputCsv -NoTypeInformation -Encoding UTF8
$statusSummary = $rows |
Where-Object { $null -ne $_.StatusCode } |
Group-Object -Property StatusCode |
Sort-Object { [int]$_.Name } |
ForEach-Object { "$($_.Name)=$($_.Count)" }
Write-Host "routes_total=$($routes.Count)"
Write-Host "routes_with_selected_get=$(@($rows | Where-Object { $_.SelectedOpenApiPath }).Count)"
Write-Host "status_summary=$($statusSummary -join ',')"
Write-Host "output_csv=$OutputCsv"

View File

@@ -0,0 +1,326 @@
{
"/api/v1/timeline": {
"get": {
"operationId": "timelineindexer_api_v1_timeline_GET",
"tags": [
"timeline"
],
"summary": "List timeline events",
"description": "Returns timeline events filtered by tenant and optional query parameters.",
"security": [
{
"BearerAuth": [
],
"OAuth2": [
"timeline:read"
]
}
],
"x-stellaops-gateway-auth": {
"allowAnonymous": false,
"requiresAuthentication": true,
"source": "AspNetMetadata",
"policies": [
"timeline:read"
],
"claimRequirements": [
{
"type": "scope",
"value": "timeline:read"
}
]
},
"x-stellaops-timeout": {
"effectiveSeconds": 30,
"source": "endpoint",
"precedence": [
"endpointOverride",
"serviceDefault",
"gatewayRouteDefault",
"gatewayGlobalCap"
],
"endpointSeconds": 30,
"gatewayRouteDefaultSeconds": 30,
"gatewayGlobalCapSeconds": 120
},
"x-stellaops-timeout-seconds": 30,
"responses": {
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/timelineindexer_System_Collections_Generic_IReadOnlyList_1_StellaOps_TimelineIndexer_Core_Models_TimelineEventView_StellaOps_TimelineIndexer_Core_Version_1_0_0_0_Culture_neutral_PublicKeyToken_null"
}
}
}
},
"400": {
"description": "Bad Request"
},
"401": {
"description": "Unauthorized"
},
"403": {
"description": "Forbidden"
},
"404": {
"description": "Not Found"
},
"422": {
"description": "Validation Error"
},
"504": {
"description": "Gateway timeout"
},
"500": {
"description": "Internal Server Error"
}
}
}
},
"/api/v1/timeline/events": {
"post": {
"operationId": "timelineindexer_api_v1_timeline_events_POST",
"tags": [
"timeline"
],
"summary": "Ingest timeline event",
"description": "Queues an event ingestion request for asynchronous timeline indexing.",
"security": [
{
"BearerAuth": [
],
"OAuth2": [
"timeline:write"
]
}
],
"x-stellaops-gateway-auth": {
"allowAnonymous": false,
"requiresAuthentication": true,
"source": "AspNetMetadata",
"policies": [
"timeline:write"
],
"claimRequirements": [
{
"type": "scope",
"value": "timeline:write"
}
]
},
"x-stellaops-timeout": {
"effectiveSeconds": 30,
"source": "endpoint",
"precedence": [
"endpointOverride",
"serviceDefault",
"gatewayRouteDefault",
"gatewayGlobalCap"
],
"endpointSeconds": 30,
"gatewayRouteDefaultSeconds": 30,
"gatewayGlobalCapSeconds": 120
},
"x-stellaops-timeout-seconds": 30,
"responses": {
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/timelineindexer_TimelineIngestAcceptedResponse"
}
}
}
},
"400": {
"description": "Bad Request"
},
"401": {
"description": "Unauthorized"
},
"403": {
"description": "Forbidden"
},
"404": {
"description": "Not Found"
},
"422": {
"description": "Validation Error"
},
"504": {
"description": "Gateway timeout"
},
"500": {
"description": "Internal Server Error"
}
}
}
},
"/api/v1/timeline/{eventId}": {
"get": {
"operationId": "timelineindexer_api_v1_timeline_{eventId}_GET",
"tags": [
"timeline"
],
"summary": "Get timeline event",
"description": "Returns a single timeline event by event identifier for the current tenant.",
"security": [
{
"BearerAuth": [
],
"OAuth2": [
"timeline:read"
]
}
],
"x-stellaops-gateway-auth": {
"allowAnonymous": false,
"requiresAuthentication": true,
"source": "AspNetMetadata",
"policies": [
"timeline:read"
],
"claimRequirements": [
{
"type": "scope",
"value": "timeline:read"
}
]
},
"x-stellaops-timeout": {
"effectiveSeconds": 30,
"source": "endpoint",
"precedence": [
"endpointOverride",
"serviceDefault",
"gatewayRouteDefault",
"gatewayGlobalCap"
],
"endpointSeconds": 30,
"gatewayRouteDefaultSeconds": 30,
"gatewayGlobalCapSeconds": 120
},
"x-stellaops-timeout-seconds": 30,
"responses": {
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/timelineindexer_StellaOps_TimelineIndexer_Core_Models_TimelineEventView"
}
}
}
},
"400": {
"description": "Bad Request"
},
"401": {
"description": "Unauthorized"
},
"403": {
"description": "Forbidden"
},
"404": {
"description": "Not Found"
},
"422": {
"description": "Validation Error"
},
"504": {
"description": "Gateway timeout"
},
"500": {
"description": "Internal Server Error"
}
}
}
},
"/api/v1/timeline/{eventId}/evidence": {
"get": {
"operationId": "timelineindexer_api_v1_timeline_{eventId}_evidence_GET",
"tags": [
"timeline"
],
"summary": "Get event evidence",
"description": "Returns evidence linkage for a timeline event, including bundle and attestation references.",
"security": [
{
"BearerAuth": [
],
"OAuth2": [
"timeline:read"
]
}
],
"x-stellaops-gateway-auth": {
"allowAnonymous": false,
"requiresAuthentication": true,
"source": "AspNetMetadata",
"policies": [
"timeline:read"
],
"claimRequirements": [
{
"type": "scope",
"value": "timeline:read"
}
]
},
"x-stellaops-timeout": {
"effectiveSeconds": 30,
"source": "endpoint",
"precedence": [
"endpointOverride",
"serviceDefault",
"gatewayRouteDefault",
"gatewayGlobalCap"
],
"endpointSeconds": 30,
"gatewayRouteDefaultSeconds": 30,
"gatewayGlobalCapSeconds": 120
},
"x-stellaops-timeout-seconds": 30,
"responses": {
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/timelineindexer_StellaOps_TimelineIndexer_Core_Models_TimelineEvidenceView"
}
}
}
},
"400": {
"description": "Bad Request"
},
"401": {
"description": "Unauthorized"
},
"403": {
"description": "Forbidden"
},
"404": {
"description": "Not Found"
},
"422": {
"description": "Validation Error"
},
"504": {
"description": "Gateway timeout"
},
"500": {
"description": "Internal Server Error"
}
}
}
}
}

View File

@@ -0,0 +1,14 @@
[
"/api/v1/timeline",
"/api/v1/timeline/events",
"/api/v1/timeline/export/{exportId}",
"/api/v1/timeline/export/{exportId}/download",
"/api/v1/timeline/replay/{replayId}",
"/api/v1/timeline/replay/{replayId}/cancel",
"/api/v1/timeline/{correlationId}",
"/api/v1/timeline/{correlationId}/critical-path",
"/api/v1/timeline/{correlationId}/export",
"/api/v1/timeline/{correlationId}/replay",
"/api/v1/timeline/{eventId}",
"/api/v1/timeline/{eventId}/evidence"
]

View File

@@ -0,0 +1,253 @@
{
"refs": [
"#/components/schemas/timelineindexer_System_Collections_Generic_IReadOnlyList_1_StellaOps_TimelineIndexer_Core_Models_TimelineEventView_StellaOps_TimelineIndexer_Core_Version_1_0_0_0_Culture_neutral_PublicKeyToken_null",
"#/components/schemas/timelineindexer_TimelineIngestAcceptedResponse",
"#/components/schemas/timelineindexer_StellaOps_TimelineIndexer_Core_Models_TimelineEventView",
"#/components/schemas/timelineindexer_StellaOps_TimelineIndexer_Core_Models_TimelineEvidenceView"
],
"components": {
"schemas": {
"timelineindexer_System_Collections_Generic_IReadOnlyList_1_StellaOps_TimelineIndexer_Core_Models_TimelineEventView_StellaOps_TimelineIndexer_Core_Version_1_0_0_0_Culture_neutral_PublicKeyToken_null": {
"type": "array",
"items": {
"type": "object",
"properties": {
"actor": {
"type": "string"
},
"attestationDigest": {
"type": "string"
},
"attestationSubject": {
"type": "string"
},
"attributes": {
"type": "array",
"items": {
"type": "object",
"properties": {
"key": {
"type": "string"
},
"value": {
"type": "string"
}
}
}
},
"bundleDigest": {
"type": "string"
},
"bundleId": {
"type": [
"string",
"null"
],
"format": "uuid"
},
"correlationId": {
"type": "string"
},
"eventId": {
"type": "string"
},
"eventSeq": {
"type": "integer"
},
"eventType": {
"type": "string"
},
"manifestUri": {
"type": "string"
},
"normalizedPayloadJson": {
"type": "string"
},
"occurredAt": {
"type": "string",
"format": "date-time"
},
"payloadHash": {
"type": "string"
},
"rawPayloadJson": {
"type": "string"
},
"receivedAt": {
"type": "string",
"format": "date-time"
},
"severity": {
"type": "string"
},
"source": {
"type": "string"
},
"tenantId": {
"type": "string"
},
"traceId": {
"type": "string"
}
},
"required": [
"eventId",
"eventSeq",
"eventType",
"occurredAt",
"receivedAt",
"severity",
"source",
"tenantId"
]
},
"$schema": "https://json-schema.org/draft/2020-12/schema"
},
"timelineindexer_TimelineIngestAcceptedResponse": {
"type": "object",
"properties": {
"status": {
"type": "string"
}
},
"required": [
"status"
],
"$schema": "https://json-schema.org/draft/2020-12/schema"
},
"timelineindexer_StellaOps_TimelineIndexer_Core_Models_TimelineEventView": {
"type": "object",
"properties": {
"actor": {
"type": "string"
},
"attestationDigest": {
"type": "string"
},
"attestationSubject": {
"type": "string"
},
"attributes": {
"type": "array",
"items": {
"type": "object",
"properties": {
"key": {
"type": "string"
},
"value": {
"type": "string"
}
}
}
},
"bundleDigest": {
"type": "string"
},
"bundleId": {
"type": [
"string",
"null"
],
"format": "uuid"
},
"correlationId": {
"type": "string"
},
"eventId": {
"type": "string"
},
"eventSeq": {
"type": "integer"
},
"eventType": {
"type": "string"
},
"manifestUri": {
"type": "string"
},
"normalizedPayloadJson": {
"type": "string"
},
"occurredAt": {
"type": "string",
"format": "date-time"
},
"payloadHash": {
"type": "string"
},
"rawPayloadJson": {
"type": "string"
},
"receivedAt": {
"type": "string",
"format": "date-time"
},
"severity": {
"type": "string"
},
"source": {
"type": "string"
},
"tenantId": {
"type": "string"
},
"traceId": {
"type": "string"
}
},
"required": [
"eventId",
"eventSeq",
"eventType",
"occurredAt",
"receivedAt",
"severity",
"source",
"tenantId"
],
"$schema": "https://json-schema.org/draft/2020-12/schema"
},
"timelineindexer_StellaOps_TimelineIndexer_Core_Models_TimelineEvidenceView": {
"type": "object",
"properties": {
"attestationDigest": {
"type": "string"
},
"attestationSubject": {
"type": "string"
},
"bundleDigest": {
"type": "string"
},
"bundleId": {
"type": [
"string",
"null"
],
"format": "uuid"
},
"createdAt": {
"type": "string",
"format": "date-time"
},
"eventId": {
"type": "string"
},
"manifestUri": {
"type": "string"
},
"tenantId": {
"type": "string"
}
},
"required": [
"createdAt",
"eventId",
"tenantId"
],
"$schema": "https://json-schema.org/draft/2020-12/schema"
}
}
}
}