This commit is contained in:
master
2026-02-04 19:59:20 +02:00
parent 557feefdc3
commit 5548cf83bf
1479 changed files with 53557 additions and 40339 deletions

171
devops/compose/.env Normal file
View File

@@ -0,0 +1,171 @@
# =============================================================================
# STELLA OPS ENVIRONMENT CONFIGURATION
# =============================================================================
# Main environment template for docker-compose.stella-ops.yml
# Copy to .env and customize for your deployment.
#
# Usage:
# cp env/stellaops.env.example .env
# docker compose -f docker-compose.stella-ops.yml up -d
#
# =============================================================================
# =============================================================================
# INFRASTRUCTURE
# =============================================================================
# PostgreSQL Database
POSTGRES_USER=stellaops
POSTGRES_PASSWORD=stellaops
POSTGRES_DB=stellaops_platform
POSTGRES_PORT=5432
# Valkey (Redis-compatible cache and messaging)
VALKEY_PORT=6379
# RustFS Object Storage
RUSTFS_HTTP_PORT=8080
# =============================================================================
# CORE SERVICES
# =============================================================================
# Authority (OAuth2/OIDC)
AUTHORITY_ISSUER=https://authority.stella-ops.local
AUTHORITY_PORT=8440
AUTHORITY_OFFLINE_CACHE_TOLERANCE=00:30:00
# Signer
SIGNER_POE_INTROSPECT_URL=http://authority.stella-ops.local/.well-known/openid-configuration
SIGNER_PORT=8441
# Attestor
ATTESTOR_PORT=8442
# Issuer Directory
ISSUER_DIRECTORY_PORT=8447
ISSUER_DIRECTORY_SEED_CSAF=true
# Concelier
CONCELIER_PORT=8445
# Notify
NOTIFY_WEB_PORT=8446
# Web UI
UI_PORT=8443
# =============================================================================
# SCANNER CONFIGURATION
# =============================================================================
SCANNER_WEB_PORT=8444
# Queue configuration (Valkey only - NATS removed)
SCANNER__QUEUE__BROKER=valkey://cache.stella-ops.local:6379
# Event streaming
SCANNER_EVENTS_ENABLED=false
SCANNER_EVENTS_DRIVER=valkey
SCANNER_EVENTS_DSN=cache.stella-ops.local:6379
SCANNER_EVENTS_STREAM=stella.events
SCANNER_EVENTS_PUBLISH_TIMEOUT_SECONDS=5
SCANNER_EVENTS_MAX_STREAM_LENGTH=10000
# Surface cache configuration
SCANNER_SURFACE_FS_ENDPOINT=http://s3.stella-ops.local
SCANNER_SURFACE_FS_BUCKET=surface-cache
SCANNER_SURFACE_CACHE_ROOT=/var/lib/stellaops/surface
SCANNER_SURFACE_CACHE_QUOTA_MB=4096
SCANNER_SURFACE_PREFETCH_ENABLED=false
SCANNER_SURFACE_TENANT=default
SCANNER_SURFACE_FEATURES=
SCANNER_SURFACE_SECRETS_PROVIDER=file
SCANNER_SURFACE_SECRETS_NAMESPACE=
SCANNER_SURFACE_SECRETS_ROOT=/etc/stellaops/secrets
SCANNER_SURFACE_SECRETS_FALLBACK_PROVIDER=
SCANNER_SURFACE_SECRETS_ALLOW_INLINE=false
SURFACE_SECRETS_HOST_PATH=./offline/surface-secrets
# Offline Kit configuration
SCANNER_OFFLINEKIT_ENABLED=false
SCANNER_OFFLINEKIT_REQUIREDSSE=true
SCANNER_OFFLINEKIT_REKOROFFLINEMODE=true
SCANNER_OFFLINEKIT_TRUSTROOTDIRECTORY=/etc/stellaops/trust-roots
SCANNER_OFFLINEKIT_REKORSNAPSHOTDIRECTORY=/var/lib/stellaops/rekor-snapshot
SCANNER_OFFLINEKIT_TRUSTROOTS_HOST_PATH=./offline/trust-roots
SCANNER_OFFLINEKIT_REKOR_SNAPSHOT_HOST_PATH=./offline/rekor-snapshot
# =============================================================================
# SCHEDULER CONFIGURATION
# =============================================================================
# Queue configuration (Valkey only - NATS removed)
SCHEDULER__QUEUE__KIND=Valkey
SCHEDULER__QUEUE__VALKEY__URL=cache.stella-ops.local:6379
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=https://rekor.sigstore.dev
REKOR_VERSION=V2
REKOR_TILE_BASE_URL=
REKOR_LOG_ID=c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d
REKOR_TILES_IMAGE=ghcr.io/sigstore/rekor-tiles:latest
# =============================================================================
# ADVISORY AI CONFIGURATION
# =============================================================================
ADVISORY_AI_WEB_PORT=8448
ADVISORY_AI_SBOM_BASEADDRESS=http://scanner.stella-ops.local
ADVISORY_AI_INFERENCE_MODE=Local
ADVISORY_AI_REMOTE_BASEADDRESS=
ADVISORY_AI_REMOTE_APIKEY=
# =============================================================================
# CRYPTO CONFIGURATION
# =============================================================================
# Crypto profile: default, china, russia, eu
STELLAOPS_CRYPTO_PROFILE=default
# Enable crypto simulation (for testing)
STELLAOPS_CRYPTO_ENABLE_SIM=0
STELLAOPS_CRYPTO_SIM_URL=http://sim-crypto:8080
# CryptoPro (Russia only) - requires EULA acceptance
CRYPTOPRO_PORT=18080
CRYPTOPRO_ACCEPT_EULA=0
CRYPTOPRO_CONTAINER_NAME=stellaops-signing
CRYPTOPRO_USE_MACHINE_STORE=true
CRYPTOPRO_PROVIDER_TYPE=80
# SM Remote (China only)
SM_REMOTE_PORT=56080
SM_SOFT_ALLOWED=1
SM_REMOTE_HSM_URL=
SM_REMOTE_HSM_API_KEY=
SM_REMOTE_HSM_TIMEOUT=30000
# =============================================================================
# NETWORKING
# =============================================================================
# External reverse proxy network (Traefik, Envoy, etc.)
FRONTDOOR_NETWORK=stellaops_frontdoor
# =============================================================================
# TELEMETRY (optional)
# =============================================================================
OTEL_GRPC_PORT=4317
OTEL_HTTP_PORT=4318
OTEL_PROMETHEUS_PORT=9464
PROMETHEUS_PORT=9090
TEMPO_PORT=3200
LOKI_PORT=3100
PROMETHEUS_RETENTION=15d

View File

@@ -10,9 +10,11 @@
# docker compose -f docker-compose.dev.yml up -d
#
# This provides:
# - PostgreSQL 18.1 on port 5432
# - Valkey 9.0.1 on port 6379
# - RustFS on port 8080
# - 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:8080 (s3.stella-ops.local)
# - Rekor v2 (tiles) on 127.1.1.4:3322 (rekor.stella-ops.local)
# - Zot (OCI registry) on 127.1.1.5:80 (registry.stella-ops.local)
# =============================================================================
services:
@@ -27,7 +29,7 @@ services:
volumes:
- postgres-data:/var/lib/postgresql/data
ports:
- "${POSTGRES_PORT:-5432}:5432"
- "127.1.1.1:${POSTGRES_PORT:-5432}:5432"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-stellaops}"]
interval: 10s
@@ -42,7 +44,7 @@ services:
volumes:
- valkey-data:/data
ports:
- "${VALKEY_PORT:-6379}:6379"
- "127.1.1.2:${VALKEY_PORT:-6379}:6379"
healthcheck:
test: ["CMD", "valkey-cli", "ping"]
interval: 10s
@@ -50,24 +52,52 @@ services:
retries: 5
rustfs:
image: registry.stella-ops.org/stellaops/rustfs:2025.09.2
image: chrislusf/seaweedfs:latest
container_name: stellaops-dev-rustfs
restart: unless-stopped
command: ["serve", "--listen", "0.0.0.0:8080", "--root", "/data"]
environment:
RUSTFS__LOG__LEVEL: info
RUSTFS__STORAGE__PATH: /data
command: ["server", "-s3", "-s3.port=8080", "-dir=/data"]
volumes:
- rustfs-data:/data
ports:
- "${RUSTFS_PORT:-8080}:8080"
- "127.1.1.3:${RUSTFS_PORT:-8080}:8080"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
test: ["CMD", "wget", "-qO-", "http://localhost:8080/status"]
interval: 30s
timeout: 10s
retries: 3
rekor-v2:
image: ${REKOR_TILES_IMAGE:-ghcr.io/sigstore/rekor-tiles:latest}
container_name: stellaops-dev-rekor
restart: unless-stopped
volumes:
- rekor-tiles-data:/var/lib/rekor-tiles
ports:
- "127.1.1.4:${REKOR_PORT:-3322}:3322"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3322/healthz"]
interval: 30s
timeout: 10s
retries: 3
registry:
image: ghcr.io/project-zot/zot-linux-amd64:v2.1.3
container_name: stellaops-dev-registry
restart: unless-stopped
volumes:
- registry-data:/var/lib/registry
- ./zot-config.json:/etc/zot/config.json:ro
ports:
- "127.1.1.5:80:5000"
healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost:5000/v2/"]
interval: 30s
timeout: 5s
retries: 3
volumes:
postgres-data:
valkey-data:
rustfs-data:
rekor-tiles-data:
registry-data:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,14 @@
-- Pre-create schemas referenced by Stella Ops services.
-- Runs once on first PostgreSQL container start via docker-entrypoint-initdb.d.
CREATE SCHEMA IF NOT EXISTS scanner;
CREATE SCHEMA IF NOT EXISTS vex;
CREATE SCHEMA IF NOT EXISTS scheduler;
CREATE SCHEMA IF NOT EXISTS policy;
CREATE SCHEMA IF NOT EXISTS notify;
CREATE SCHEMA IF NOT EXISTS notifier;
CREATE SCHEMA IF NOT EXISTS evidence;
CREATE SCHEMA IF NOT EXISTS findings;
CREATE SCHEMA IF NOT EXISTS timeline;
CREATE SCHEMA IF NOT EXISTS doctor;
CREATE SCHEMA IF NOT EXISTS issuer_directory;

View File

@@ -0,0 +1,16 @@
{
"distSpecVersion": "1.1.0",
"storage": {
"rootDirectory": "/var/lib/registry",
"gc": true,
"gcDelay": "1h",
"gcInterval": "24h"
},
"http": {
"address": "0.0.0.0",
"port": "5000"
},
"log": {
"level": "info"
}
}

View File

@@ -1,26 +1,29 @@
# syntax=docker/dockerfile:1.7
# Multi-stage Angular console image with non-root runtime (DOCKER-44-001)
ARG NODE_IMAGE=node:20-bullseye-slim
ARG NODE_IMAGE=node:20-bookworm-slim
ARG NGINX_IMAGE=nginxinc/nginx-unprivileged:1.27-alpine
ARG APP_DIR=src/Web/StellaOps.Web
ARG DIST_DIR=dist
ARG APP_PORT=8080
FROM ${NODE_IMAGE} AS build
ARG APP_DIR
ARG DIST_DIR
ENV npm_config_fund=false npm_config_audit=false SOURCE_DATE_EPOCH=1704067200
WORKDIR /app
COPY ${APP_DIR}/package*.json ./
RUN npm ci --prefer-offline --no-progress --cache .npm
RUN npm install --no-progress
COPY ${APP_DIR}/ ./
RUN npm run build -- --configuration=production --output-path=${DIST_DIR}
FROM ${NGINX_IMAGE} AS runtime
ARG APP_PORT
ARG APP_PORT=8080
ARG DIST_DIR=dist
ENV APP_PORT=${APP_PORT}
USER 101
WORKDIR /
COPY --from=build /app/${DIST_DIR}/ /usr/share/nginx/html/
COPY ops/devops/docker/healthcheck-frontend.sh /usr/local/bin/healthcheck-frontend.sh
COPY devops/docker/healthcheck-frontend.sh /usr/local/bin/healthcheck-frontend.sh
RUN rm -f /etc/nginx/conf.d/default.conf && \
cat > /etc/nginx/conf.d/default.conf <<CONF
server {
@@ -29,7 +32,7 @@ server {
server_name _;
root /usr/share/nginx/html;
location / {
try_files $$uri $$uri/ /index.html;
try_files \$uri \$uri/ /index.html;
}
}
CONF

View File

@@ -2,8 +2,8 @@
# Hardened multi-stage template for StellaOps services
# Parameters are build-time ARGs so this file can be re-used across services.
ARG SDK_IMAGE=mcr.microsoft.com/dotnet/sdk:10.0-bookworm-slim
ARG RUNTIME_IMAGE=mcr.microsoft.com/dotnet/aspnet:10.0-bookworm-slim
ARG SDK_IMAGE=mcr.microsoft.com/dotnet/sdk:10.0-noble
ARG RUNTIME_IMAGE=mcr.microsoft.com/dotnet/aspnet:10.0-noble
ARG APP_PROJECT=src/Service/Service.csproj
ARG CONFIGURATION=Release
ARG PUBLISH_DIR=/app/publish
@@ -14,17 +14,26 @@ ARG APP_GID=10001
ARG APP_PORT=8080
FROM ${SDK_IMAGE} AS build
ARG APP_PROJECT
ARG CONFIGURATION
ARG PUBLISH_DIR
ENV DOTNET_CLI_TELEMETRY_OPTOUT=1 \
DOTNET_NOLOGO=1 \
SOURCE_DATE_EPOCH=1704067200
WORKDIR /src
# Expect restore sources to be available offline via /.nuget/
COPY . .
RUN dotnet restore ${APP_PROJECT} --packages /.nuget/packages && \
RUN dotnet restore ${APP_PROJECT} && \
dotnet publish ${APP_PROJECT} -c ${CONFIGURATION} -o ${PUBLISH_DIR} \
/p:UseAppHost=true /p:PublishTrimmed=false
FROM ${RUNTIME_IMAGE} AS runtime
ARG APP_USER=stella
ARG APP_UID=10001
ARG APP_GID=10001
ARG APP_PORT=8080
ARG APP_BINARY=StellaOps.Service
ARG PUBLISH_DIR=/app/publish
# Create non-root user/group with stable ids for auditability
RUN groupadd -r -g ${APP_GID} ${APP_USER} && \
useradd -r -u ${APP_UID} -g ${APP_GID} -d /var/lib/${APP_USER} ${APP_USER} && \
@@ -34,23 +43,27 @@ RUN groupadd -r -g ${APP_GID} ${APP_USER} && \
WORKDIR /app
COPY --from=build --chown=${APP_UID}:${APP_GID} ${PUBLISH_DIR}/ ./
# Ship healthcheck helper; callers may override with their own script
COPY --chown=${APP_UID}:${APP_GID} ops/devops/docker/healthcheck.sh /usr/local/bin/healthcheck.sh
COPY --chown=${APP_UID}:${APP_GID} devops/docker/healthcheck.sh /usr/local/bin/healthcheck.sh
ENV ASPNETCORE_URLS=http://+:${APP_PORT} \
DOTNET_EnableDiagnostics=0 \
DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1 \
COMPlus_EnableDiagnostics=0 \
APP_BINARY=${APP_BINARY}
# Harden filesystem; deploys should also set readOnlyRootFilesystem true
# Keep the native AppHost binary (+x) and DLLs read-only (400)
RUN chmod 500 /app && \
chmod +x /usr/local/bin/healthcheck.sh && \
find /app -maxdepth 1 -type f -name '*.dll' -exec chmod 400 {} \; && \
find /app -maxdepth 1 -type f -name '*.json' -exec chmod 400 {} \; && \
find /app -maxdepth 1 -type f -name '*.pdb' -exec chmod 400 {} \; && \
find /app -maxdepth 1 -type d -exec chmod 500 {} \; && \
chmod 500 /app/${APP_BINARY} 2>/dev/null || true
USER ${APP_UID}:${APP_GID}
EXPOSE ${APP_PORT}
HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \
CMD /usr/local/bin/healthcheck.sh
# Harden filesystem; deploys should also set readOnlyRootFilesystem true
RUN chmod 500 /app && \
find /app -maxdepth 1 -type f -exec chmod 400 {} \; && \
find /app -maxdepth 1 -type d -exec chmod 500 {} \;
# Use shell form so APP_BINARY env can be expanded without duplicating the template per service
ENTRYPOINT ["sh","-c","exec ./\"$APP_BINARY\""]

106
devops/docker/build-all.ps1 Normal file
View File

@@ -0,0 +1,106 @@
#!/usr/bin/env pwsh
<#
.SYNOPSIS
Build hardened Docker images for all Stella Ops services using the shared template/matrix.
.DESCRIPTION
PowerShell port of build-all.sh. Reads services-matrix.env (pipe-delimited) and builds
each service image using Dockerfile.hardened.template (or Dockerfile.console for Angular).
.PARAMETER Registry
Docker image registry prefix. Default: stellaops
.PARAMETER TagSuffix
Tag suffix for built images. Default: dev
.PARAMETER SdkImage
.NET SDK base image. Default: mcr.microsoft.com/dotnet/sdk:10.0-noble
.PARAMETER RuntimeImage
.NET runtime base image. Default: mcr.microsoft.com/dotnet/aspnet:10.0-noble
#>
[CmdletBinding()]
param(
[string]$Registry = $env:REGISTRY ?? 'stellaops',
[string]$TagSuffix = $env:TAG_SUFFIX ?? 'dev',
[string]$SdkImage = $env:SDK_IMAGE ?? 'mcr.microsoft.com/dotnet/sdk:10.0-noble',
[string]$RuntimeImage = $env:RUNTIME_IMAGE ?? 'mcr.microsoft.com/dotnet/aspnet:10.0-noble'
)
$ErrorActionPreference = 'Continue'
$Root = git rev-parse --show-toplevel 2>$null
if (-not $Root) {
Write-Error 'Not inside a git repository.'
exit 1
}
$Root = $Root.Trim()
$MatrixPath = Join-Path $Root 'devops/docker/services-matrix.env'
if (-not (Test-Path $MatrixPath)) {
Write-Error "Matrix file not found: $MatrixPath"
exit 1
}
Write-Host "Building services from $MatrixPath -> ${Registry}/<service>:${TagSuffix}" -ForegroundColor Cyan
$succeeded = @()
$failed = @()
foreach ($line in Get-Content $MatrixPath) {
$line = $line.Trim()
if (-not $line -or $line.StartsWith('#')) { continue }
$parts = $line -split '\|'
if ($parts.Count -lt 5) { continue }
$service = $parts[0]
$dockerfile = $parts[1]
$project = $parts[2]
$binary = $parts[3]
$port = $parts[4]
$image = "${Registry}/${service}:${TagSuffix}"
$dfPath = Join-Path $Root $dockerfile
if (-not (Test-Path $dfPath)) {
Write-Warning "Skipping ${service}: dockerfile missing ($dfPath)"
continue
}
if ($dockerfile -like '*Dockerfile.console*') {
Write-Host "[console] $service -> $image" -ForegroundColor Yellow
docker build `
-f $dfPath $Root `
--build-arg "APP_DIR=$project" `
--build-arg "APP_PORT=$port" `
-t $image
}
else {
Write-Host "[service] $service -> $image" -ForegroundColor Green
docker build `
-f $dfPath $Root `
--build-arg "SDK_IMAGE=$SdkImage" `
--build-arg "RUNTIME_IMAGE=$RuntimeImage" `
--build-arg "APP_PROJECT=$project" `
--build-arg "APP_BINARY=$binary" `
--build-arg "APP_PORT=$port" `
-t $image
}
if ($LASTEXITCODE -eq 0) {
$succeeded += $service
}
else {
$failed += $service
Write-Host "FAILED: $service" -ForegroundColor Red
}
}
Write-Host ''
Write-Host '=== BUILD RESULTS ===' -ForegroundColor Cyan
Write-Host "Succeeded ($($succeeded.Count)): $($succeeded -join ', ')" -ForegroundColor Green
Write-Host "Failed ($($failed.Count)): $($failed -join ', ')" -ForegroundColor $(if ($failed.Count -gt 0) { 'Red' } else { 'Green' })
Write-Host ''
if ($failed.Count -gt 0) {
Write-Error 'Some builds failed. Fix the issues and re-run.'
exit 1
}
Write-Host 'Build complete. Remember to enforce readOnlyRootFilesystem at deploy time and run sbom_attest.sh (DOCKER-44-002).' -ForegroundColor Cyan

View File

@@ -1,13 +1,15 @@
#!/usr/bin/env bash
# Build hardened images for the core services using the shared template/matrix (DOCKER-44-001)
set -euo pipefail
set -uo pipefail
FAILED=()
SUCCEEDED=()
ROOT=${ROOT:-"$(git rev-parse --show-toplevel)"}
MATRIX=${MATRIX:-"${ROOT}/ops/devops/docker/services-matrix.env"}
MATRIX=${MATRIX:-"${ROOT}/devops/docker/services-matrix.env"}
REGISTRY=${REGISTRY:-"stellaops"}
TAG_SUFFIX=${TAG_SUFFIX:-"dev"}
SDK_IMAGE=${SDK_IMAGE:-"mcr.microsoft.com/dotnet/sdk:10.0-bookworm-slim"}
RUNTIME_IMAGE=${RUNTIME_IMAGE:-"mcr.microsoft.com/dotnet/aspnet:10.0-bookworm-slim"}
SDK_IMAGE=${SDK_IMAGE:-"mcr.microsoft.com/dotnet/sdk:10.0-noble"}
RUNTIME_IMAGE=${RUNTIME_IMAGE:-"mcr.microsoft.com/dotnet/aspnet:10.0-noble"}
if [[ ! -f "${MATRIX}" ]]; then
echo "matrix file not found: ${MATRIX}" >&2
@@ -45,6 +47,22 @@ while IFS='|' read -r service dockerfile project binary port; do
-t "${image}"
fi
if [[ $? -eq 0 ]]; then
SUCCEEDED+=("${service}")
else
FAILED+=("${service}")
echo "FAILED: ${service}" >&2
fi
done < "${MATRIX}"
echo "" >&2
echo "=== BUILD RESULTS ===" >&2
echo "Succeeded (${#SUCCEEDED[@]}): ${SUCCEEDED[*]:-none}" >&2
echo "Failed (${#FAILED[@]}): ${FAILED[*]:-none}" >&2
echo "" >&2
if [[ ${#FAILED[@]} -gt 0 ]]; then
echo "Some builds failed. Fix the issues and re-run." >&2
exit 1
fi
echo "Build complete. Remember to enforce readOnlyRootFilesystem at deploy time and run sbom_attest.sh (DOCKER-44-002)." >&2

View File

@@ -1,12 +1,112 @@
# service|dockerfile|project|binary|port
# Paths are relative to repo root; dockerfile is usually the shared hardened template.
api|ops/devops/docker/Dockerfile.hardened.template|src/VulnExplorer/StellaOps.VulnExplorer.Api/StellaOps.VulnExplorer.Api.csproj|StellaOps.VulnExplorer.Api|8080
orchestrator|ops/devops/docker/Dockerfile.hardened.template|src/Orchestrator/StellaOps.Orchestrator.WebService/StellaOps.Orchestrator.WebService.csproj|StellaOps.Orchestrator.WebService|8080
task-runner|ops/devops/docker/Dockerfile.hardened.template|src/Orchestrator/StellaOps.Orchestrator.Worker/StellaOps.Orchestrator.Worker.csproj|StellaOps.Orchestrator.Worker|8081
concelier|ops/devops/docker/Dockerfile.hardened.template|src/Concelier/StellaOps.Concelier.WebService/StellaOps.Concelier.WebService.csproj|StellaOps.Concelier.WebService|8080
excititor|ops/devops/docker/Dockerfile.hardened.template|src/Excititor/StellaOps.Excititor.WebService/StellaOps.Excititor.WebService.csproj|StellaOps.Excititor.WebService|8080
policy|ops/devops/docker/Dockerfile.hardened.template|src/Policy/StellaOps.Policy.Gateway/StellaOps.Policy.Gateway.csproj|StellaOps.Policy.Gateway|8084
notify|ops/devops/docker/Dockerfile.hardened.template|src/Notify/StellaOps.Notify.WebService/StellaOps.Notify.WebService.csproj|StellaOps.Notify.WebService|8080
export|ops/devops/docker/Dockerfile.hardened.template|src/ExportCenter/StellaOps.ExportCenter.WebService/StellaOps.ExportCenter.WebService.csproj|StellaOps.ExportCenter.WebService|8080
advisoryai|ops/devops/docker/Dockerfile.hardened.template|src/AdvisoryAI/StellaOps.AdvisoryAI.WebService/StellaOps.AdvisoryAI.WebService.csproj|StellaOps.AdvisoryAI.WebService|8080
console|ops/devops/docker/Dockerfile.console|src/Web/StellaOps.Web|StellaOps.Web|8080
# Ordered by port-registry slot number. All services use port 8080 internally
# unless they have a legacy port assignment (authority=8440, signer=8441, etc.).
#
# ── Slot 0: Router Gateway ──────────────────────────────────────────────────────
router-gateway|devops/docker/Dockerfile.hardened.template|src/Router/StellaOps.Gateway.WebService/StellaOps.Gateway.WebService.csproj|StellaOps.Gateway.WebService|8080
# ── Slot 1: Platform ────────────────────────────────────────────────────────────
platform|devops/docker/Dockerfile.hardened.template|src/Platform/StellaOps.Platform.WebService/StellaOps.Platform.WebService.csproj|StellaOps.Platform.WebService|8080
# ── Slot 2: Authority ───────────────────────────────────────────────────────────
authority|devops/docker/Dockerfile.hardened.template|src/Authority/StellaOps.Authority/StellaOps.Authority/StellaOps.Authority.csproj|StellaOps.Authority|8440
# ── Slot 3: Gateway ─────────────────────────────────────────────────────────────
gateway|devops/docker/Dockerfile.hardened.template|src/Gateway/StellaOps.Gateway.WebService/StellaOps.Gateway.WebService.csproj|StellaOps.Gateway.WebService|8080
# ── Slot 4: Attestor ────────────────────────────────────────────────────────────
attestor|devops/docker/Dockerfile.hardened.template|src/Attestor/StellaOps.Attestor/StellaOps.Attestor.WebService/StellaOps.Attestor.WebService.csproj|StellaOps.Attestor.WebService|8442
# ── Slot 5: Attestor TileProxy ──────────────────────────────────────────────────
attestor-tileproxy|devops/docker/Dockerfile.hardened.template|src/Attestor/StellaOps.Attestor.TileProxy/StellaOps.Attestor.TileProxy.csproj|StellaOps.Attestor.TileProxy|8080
# ── Slot 6: Evidence Locker ─────────────────────────────────────────────────────
evidence-locker-web|devops/docker/Dockerfile.hardened.template|src/EvidenceLocker/StellaOps.EvidenceLocker/StellaOps.EvidenceLocker.WebService/StellaOps.EvidenceLocker.WebService.csproj|StellaOps.EvidenceLocker.WebService|8080
evidence-locker-worker|devops/docker/Dockerfile.hardened.template|src/EvidenceLocker/StellaOps.EvidenceLocker/StellaOps.EvidenceLocker.Worker/StellaOps.EvidenceLocker.Worker.csproj|StellaOps.EvidenceLocker.Worker|8080
# ── Slot 8: Scanner ─────────────────────────────────────────────────────────────
scanner-web|devops/docker/Dockerfile.hardened.template|src/Scanner/StellaOps.Scanner.WebService/StellaOps.Scanner.WebService.csproj|StellaOps.Scanner.WebService|8444
scanner-worker|devops/docker/Dockerfile.hardened.template|src/Scanner/StellaOps.Scanner.Worker/StellaOps.Scanner.Worker.csproj|StellaOps.Scanner.Worker|8080
# ── Slot 9: Concelier ───────────────────────────────────────────────────────────
concelier|devops/docker/Dockerfile.hardened.template|src/Concelier/StellaOps.Concelier.WebService/StellaOps.Concelier.WebService.csproj|StellaOps.Concelier.WebService|8080
# ── Slot 10: Excititor ──────────────────────────────────────────────────────────
excititor|devops/docker/Dockerfile.hardened.template|src/Excititor/StellaOps.Excititor.WebService/StellaOps.Excititor.WebService.csproj|StellaOps.Excititor.WebService|8080
excititor-worker|devops/docker/Dockerfile.hardened.template|src/Excititor/StellaOps.Excititor.Worker/StellaOps.Excititor.Worker.csproj|StellaOps.Excititor.Worker|8080
# ── Slot 11: VexHub ─────────────────────────────────────────────────────────────
vexhub-web|devops/docker/Dockerfile.hardened.template|src/VexHub/StellaOps.VexHub.WebService/StellaOps.VexHub.WebService.csproj|StellaOps.VexHub.WebService|8080
# ── Slot 12: VexLens ────────────────────────────────────────────────────────────
vexlens-web|devops/docker/Dockerfile.hardened.template|src/VexLens/StellaOps.VexLens.WebService/StellaOps.VexLens.WebService.csproj|StellaOps.VexLens.WebService|8080
# ── Slot 13: VulnExplorer (api) ─────────────────────────────────────────────────
api|devops/docker/Dockerfile.hardened.template|src/VulnExplorer/StellaOps.VulnExplorer.Api/StellaOps.VulnExplorer.Api.csproj|StellaOps.VulnExplorer.Api|8080
# ── Slot 14: Policy Engine ──────────────────────────────────────────────────────
policy-engine|devops/docker/Dockerfile.hardened.template|src/Policy/StellaOps.Policy.Engine/StellaOps.Policy.Engine.csproj|StellaOps.Policy.Engine|8080
# ── Slot 15: Policy Gateway ─────────────────────────────────────────────────────
policy|devops/docker/Dockerfile.hardened.template|src/Policy/StellaOps.Policy.Gateway/StellaOps.Policy.Gateway.csproj|StellaOps.Policy.Gateway|8084
# ── Slot 16: RiskEngine ─────────────────────────────────────────────────────────
riskengine-web|devops/docker/Dockerfile.hardened.template|src/RiskEngine/StellaOps.RiskEngine/StellaOps.RiskEngine.WebService/StellaOps.RiskEngine.WebService.csproj|StellaOps.RiskEngine.WebService|8080
riskengine-worker|devops/docker/Dockerfile.hardened.template|src/RiskEngine/StellaOps.RiskEngine/StellaOps.RiskEngine.Worker/StellaOps.RiskEngine.Worker.csproj|StellaOps.RiskEngine.Worker|8080
# ── Slot 17: Orchestrator ───────────────────────────────────────────────────────
orchestrator|devops/docker/Dockerfile.hardened.template|src/Orchestrator/StellaOps.Orchestrator/StellaOps.Orchestrator.WebService/StellaOps.Orchestrator.WebService.csproj|StellaOps.Orchestrator.WebService|8080
orchestrator-worker|devops/docker/Dockerfile.hardened.template|src/Orchestrator/StellaOps.Orchestrator/StellaOps.Orchestrator.Worker/StellaOps.Orchestrator.Worker.csproj|StellaOps.Orchestrator.Worker|8080
# ── Slot 18: TaskRunner ─────────────────────────────────────────────────────────
taskrunner-web|devops/docker/Dockerfile.hardened.template|src/TaskRunner/StellaOps.TaskRunner/StellaOps.TaskRunner.WebService/StellaOps.TaskRunner.WebService.csproj|StellaOps.TaskRunner.WebService|8080
taskrunner-worker|devops/docker/Dockerfile.hardened.template|src/TaskRunner/StellaOps.TaskRunner/StellaOps.TaskRunner.Worker/StellaOps.TaskRunner.Worker.csproj|StellaOps.TaskRunner.Worker|8080
# ── Slot 19: Scheduler ──────────────────────────────────────────────────────────
scheduler-web|devops/docker/Dockerfile.hardened.template|src/Scheduler/StellaOps.Scheduler.WebService/StellaOps.Scheduler.WebService.csproj|StellaOps.Scheduler.WebService|8080
scheduler-worker|devops/docker/Dockerfile.hardened.template|src/Scheduler/StellaOps.Scheduler.Worker.Host/StellaOps.Scheduler.Worker.Host.csproj|StellaOps.Scheduler.Worker.Host|8080
# ── Slot 20: Graph ──────────────────────────────────────────────────────────────
graph-api|devops/docker/Dockerfile.hardened.template|src/Graph/StellaOps.Graph.Api/StellaOps.Graph.Api.csproj|StellaOps.Graph.Api|8080
# ── Slot 21: Cartographer ───────────────────────────────────────────────────────
cartographer|devops/docker/Dockerfile.hardened.template|src/Cartographer/StellaOps.Cartographer/StellaOps.Cartographer.csproj|StellaOps.Cartographer|8080
# ── Slot 22: ReachGraph ─────────────────────────────────────────────────────────
reachgraph-web|devops/docker/Dockerfile.hardened.template|src/ReachGraph/StellaOps.ReachGraph.WebService/StellaOps.ReachGraph.WebService.csproj|StellaOps.ReachGraph.WebService|8080
# ── Slot 23: Timeline Indexer ───────────────────────────────────────────────────
timeline-indexer-web|devops/docker/Dockerfile.hardened.template|src/TimelineIndexer/StellaOps.TimelineIndexer/StellaOps.TimelineIndexer.WebService/StellaOps.TimelineIndexer.WebService.csproj|StellaOps.TimelineIndexer.WebService|8080
timeline-indexer-worker|devops/docker/Dockerfile.hardened.template|src/TimelineIndexer/StellaOps.TimelineIndexer/StellaOps.TimelineIndexer.Worker/StellaOps.TimelineIndexer.Worker.csproj|StellaOps.TimelineIndexer.Worker|8080
# ── Slot 24: Timeline ───────────────────────────────────────────────────────────
timeline-web|devops/docker/Dockerfile.hardened.template|src/Timeline/StellaOps.Timeline.WebService/StellaOps.Timeline.WebService.csproj|StellaOps.Timeline.WebService|8080
# ── Slot 25: Findings Ledger ────────────────────────────────────────────────────
findings-ledger-web|devops/docker/Dockerfile.hardened.template|src/Findings/StellaOps.Findings.Ledger.WebService/StellaOps.Findings.Ledger.WebService.csproj|StellaOps.Findings.Ledger.WebService|8080
# ── Slot 26: Doctor ─────────────────────────────────────────────────────────────
doctor-web|devops/docker/Dockerfile.hardened.template|src/Doctor/StellaOps.Doctor.WebService/StellaOps.Doctor.WebService.csproj|StellaOps.Doctor.WebService|8080
doctor-scheduler|devops/docker/Dockerfile.hardened.template|src/Doctor/StellaOps.Doctor.Scheduler/StellaOps.Doctor.Scheduler.csproj|StellaOps.Doctor.Scheduler|8080
# ── Slot 27: OpsMemory ──────────────────────────────────────────────────────────
opsmemory-web|devops/docker/Dockerfile.hardened.template|src/OpsMemory/StellaOps.OpsMemory.WebService/StellaOps.OpsMemory.WebService.csproj|StellaOps.OpsMemory.WebService|8080
# ── Slot 28: Notifier ───────────────────────────────────────────────────────────
notifier-web|devops/docker/Dockerfile.hardened.template|src/Notifier/StellaOps.Notifier/StellaOps.Notifier.WebService/StellaOps.Notifier.WebService.csproj|StellaOps.Notifier.WebService|8080
notifier-worker|devops/docker/Dockerfile.hardened.template|src/Notifier/StellaOps.Notifier/StellaOps.Notifier.Worker/StellaOps.Notifier.Worker.csproj|StellaOps.Notifier.Worker|8080
# ── Slot 29: Notify ─────────────────────────────────────────────────────────────
notify-web|devops/docker/Dockerfile.hardened.template|src/Notify/StellaOps.Notify.WebService/StellaOps.Notify.WebService.csproj|StellaOps.Notify.WebService|8080
# ── Slot 30: Signer ─────────────────────────────────────────────────────────────
signer|devops/docker/Dockerfile.hardened.template|src/Signer/StellaOps.Signer/StellaOps.Signer.WebService/StellaOps.Signer.WebService.csproj|StellaOps.Signer.WebService|8441
# ── Slot 31: SmRemote ───────────────────────────────────────────────────────────
smremote|devops/docker/Dockerfile.hardened.template|src/SmRemote/StellaOps.SmRemote.Service/StellaOps.SmRemote.Service.csproj|StellaOps.SmRemote.Service|8080
# ── Slot 32: AirGap Controller ──────────────────────────────────────────────────
airgap-controller|devops/docker/Dockerfile.hardened.template|src/AirGap/StellaOps.AirGap.Controller/StellaOps.AirGap.Controller.csproj|StellaOps.AirGap.Controller|8080
# ── Slot 33: AirGap Time ────────────────────────────────────────────────────────
airgap-time|devops/docker/Dockerfile.hardened.template|src/AirGap/StellaOps.AirGap.Time/StellaOps.AirGap.Time.csproj|StellaOps.AirGap.Time|8080
# ── Slot 34: PacksRegistry ──────────────────────────────────────────────────────
packsregistry-web|devops/docker/Dockerfile.hardened.template|src/PacksRegistry/StellaOps.PacksRegistry/StellaOps.PacksRegistry.WebService/StellaOps.PacksRegistry.WebService.csproj|StellaOps.PacksRegistry.WebService|8080
packsregistry-worker|devops/docker/Dockerfile.hardened.template|src/PacksRegistry/StellaOps.PacksRegistry/StellaOps.PacksRegistry.Worker/StellaOps.PacksRegistry.Worker.csproj|StellaOps.PacksRegistry.Worker|8080
# ── Slot 35: Registry Token ─────────────────────────────────────────────────────
registry-token|devops/docker/Dockerfile.hardened.template|src/Registry/StellaOps.Registry.TokenService/StellaOps.Registry.TokenService.csproj|StellaOps.Registry.TokenService|8080
# ── Slot 36: BinaryIndex ────────────────────────────────────────────────────────
binaryindex-web|devops/docker/Dockerfile.hardened.template|src/BinaryIndex/StellaOps.BinaryIndex.WebService/StellaOps.BinaryIndex.WebService.csproj|StellaOps.BinaryIndex.WebService|8080
# ── Slot 37: IssuerDirectory ────────────────────────────────────────────────────
issuer-directory-web|devops/docker/Dockerfile.hardened.template|src/IssuerDirectory/StellaOps.IssuerDirectory/StellaOps.IssuerDirectory.WebService/StellaOps.IssuerDirectory.WebService.csproj|StellaOps.IssuerDirectory.WebService|8080
# ── Slot 38: Symbols ────────────────────────────────────────────────────────────
symbols|devops/docker/Dockerfile.hardened.template|src/Symbols/StellaOps.Symbols.Server/StellaOps.Symbols.Server.csproj|StellaOps.Symbols.Server|8080
# ── Slot 39: SbomService ────────────────────────────────────────────────────────
sbomservice|devops/docker/Dockerfile.hardened.template|src/SbomService/StellaOps.SbomService/StellaOps.SbomService.csproj|StellaOps.SbomService|8080
# ── Slot 40: ExportCenter ───────────────────────────────────────────────────────
export|devops/docker/Dockerfile.hardened.template|src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.WebService/StellaOps.ExportCenter.WebService.csproj|StellaOps.ExportCenter.WebService|8080
export-worker|devops/docker/Dockerfile.hardened.template|src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Worker/StellaOps.ExportCenter.Worker.csproj|StellaOps.ExportCenter.Worker|8080
# ── Slot 41: Replay ─────────────────────────────────────────────────────────────
replay-web|devops/docker/Dockerfile.hardened.template|src/Replay/StellaOps.Replay.WebService/StellaOps.Replay.WebService.csproj|StellaOps.Replay.WebService|8080
# ── Slot 42: Integrations ───────────────────────────────────────────────────────
integrations-web|devops/docker/Dockerfile.hardened.template|src/Integrations/StellaOps.Integrations.WebService/StellaOps.Integrations.WebService.csproj|StellaOps.Integrations.WebService|8080
# ── Slot 43: Zastava ────────────────────────────────────────────────────────────
zastava-webhook|devops/docker/Dockerfile.hardened.template|src/Zastava/StellaOps.Zastava.Webhook/StellaOps.Zastava.Webhook.csproj|StellaOps.Zastava.Webhook|8080
# ── Slot 44: Signals ────────────────────────────────────────────────────────────
signals|devops/docker/Dockerfile.hardened.template|src/Signals/StellaOps.Signals/StellaOps.Signals.csproj|StellaOps.Signals|8080
# ── Slot 45: AdvisoryAI ─────────────────────────────────────────────────────────
advisory-ai-web|devops/docker/Dockerfile.hardened.template|src/AdvisoryAI/StellaOps.AdvisoryAI.WebService/StellaOps.AdvisoryAI.WebService.csproj|StellaOps.AdvisoryAI.WebService|8080
advisory-ai-worker|devops/docker/Dockerfile.hardened.template|src/AdvisoryAI/StellaOps.AdvisoryAI.Worker/StellaOps.AdvisoryAI.Worker.csproj|StellaOps.AdvisoryAI.Worker|8080
# ── Slot 46: Unknowns ───────────────────────────────────────────────────────────
unknowns-web|devops/docker/Dockerfile.hardened.template|src/Unknowns/StellaOps.Unknowns.WebService/StellaOps.Unknowns.WebService.csproj|StellaOps.Unknowns.WebService|8080
# ── Console (Angular frontend) ──────────────────────────────────────────────────
console|devops/docker/Dockerfile.console|src/Web/StellaOps.Web|StellaOps.Web|8080