diff --git a/deploy/compose/env/airgap.env.example b/deploy/compose/env/airgap.env.example index 03828473c..77ec391c2 100644 --- a/deploy/compose/env/airgap.env.example +++ b/deploy/compose/env/airgap.env.example @@ -1,48 +1,75 @@ # Substitutions for docker-compose.airgap.yaml -MONGO_INITDB_ROOT_USERNAME=stellaops -MONGO_INITDB_ROOT_PASSWORD=airgap-password -MINIO_ROOT_USER=stellaops-offline -MINIO_ROOT_PASSWORD=airgap-minio-secret -MINIO_CONSOLE_PORT=29001 + +# PostgreSQL Database +POSTGRES_USER=stellaops +POSTGRES_PASSWORD=airgap-password +POSTGRES_DB=stellaops_platform +POSTGRES_PORT=25432 + +# Valkey (Redis-compatible cache and messaging) +VALKEY_PORT=26379 + +# RustFS Object Storage RUSTFS_HTTP_PORT=8080 + +# Authority AUTHORITY_ISSUER=https://authority.airgap.local AUTHORITY_PORT=8440 +AUTHORITY_OFFLINE_CACHE_TOLERANCE=00:45:00 + +# Signer SIGNER_POE_INTROSPECT_URL=file:///offline/poe/introspect.json SIGNER_PORT=8441 + +# Attestor ATTESTOR_PORT=8442 -# Secrets for Issuer Directory are provided via issuer-directory.mongo.env (see etc/secrets/issuer-directory.mongo.secret.example). + +# Issuer Directory ISSUER_DIRECTORY_PORT=8447 -ISSUER_DIRECTORY_MONGO_CONNECTION_STRING=mongodb://${MONGO_INITDB_ROOT_USERNAME}:${MONGO_INITDB_ROOT_PASSWORD}@mongo:27017 ISSUER_DIRECTORY_SEED_CSAF=true + +# Concelier CONCELIER_PORT=8445 + +# Scanner SCANNER_WEB_PORT=8444 -UI_PORT=9443 -NATS_CLIENT_PORT=24222 -SCANNER_QUEUE_BROKER=nats://nats:4222 -AUTHORITY_OFFLINE_CACHE_TOLERANCE=00:45:00 +SCANNER_QUEUE_BROKER=valkey://valkey:6379 SCANNER_EVENTS_ENABLED=false -SCANNER_EVENTS_DRIVER=redis -# Leave SCANNER_EVENTS_DSN empty to inherit the Redis queue DSN when SCANNER_QUEUE_BROKER uses redis://. -SCANNER_EVENTS_DSN= +SCANNER_EVENTS_DRIVER=valkey +SCANNER_EVENTS_DSN=valkey:6379 SCANNER_EVENTS_STREAM=stella.events SCANNER_EVENTS_PUBLISH_TIMEOUT_SECONDS=5 SCANNER_EVENTS_MAX_STREAM_LENGTH=10000 + +# Scanner Surface.Env Configuration SCANNER_SURFACE_FS_ENDPOINT=http://rustfs:8080/api/v1 SCANNER_SURFACE_CACHE_ROOT=/var/lib/stellaops/surface -# Zastava inherits Scanner defaults; override if Observer/Webhook diverge -ZASTAVA_SURFACE_FS_ENDPOINT=${SCANNER_SURFACE_FS_ENDPOINT} -ZASTAVA_SURFACE_CACHE_ROOT=${SCANNER_SURFACE_CACHE_ROOT} SCANNER_SURFACE_SECRETS_PROVIDER=file SCANNER_SURFACE_SECRETS_NAMESPACE= SCANNER_SURFACE_SECRETS_ROOT=/etc/stellaops/secrets SCANNER_SURFACE_SECRETS_FALLBACK_PROVIDER= SURFACE_SECRETS_HOST_PATH=./offline/surface-secrets -SCHEDULER_QUEUE_KIND=Nats -SCHEDULER_QUEUE_NATS_URL=nats://nats:4222 -SCHEDULER_STORAGE_DATABASE=stellaops_scheduler + +# Zastava (inherits Scanner defaults; override if Observer/Webhook diverge) +ZASTAVA_SURFACE_FS_ENDPOINT=${SCANNER_SURFACE_FS_ENDPOINT} +ZASTAVA_SURFACE_CACHE_ROOT=${SCANNER_SURFACE_CACHE_ROOT} + +# Scheduler (Valkey default, NATS optional) +SCHEDULER_QUEUE_KIND=Valkey +SCHEDULER_QUEUE_VALKEY_URL=valkey:6379 +# SCHEDULER_QUEUE_NATS_URL=nats://nats:4222 +SCHEDULER_STORAGE_DATABASE=stellaops_platform SCHEDULER_SCANNER_BASEADDRESS=http://scanner-web:8444 + +# NATS (Optional - only if using NATS instead of Valkey for queues) +NATS_CLIENT_PORT=24222 + +# Advisory AI ADVISORY_AI_WEB_PORT=8448 ADVISORY_AI_SBOM_BASEADDRESS=http://scanner-web:8444 ADVISORY_AI_INFERENCE_MODE=Local ADVISORY_AI_REMOTE_BASEADDRESS= ADVISORY_AI_REMOTE_APIKEY= + +# Web UI +UI_PORT=9443 diff --git a/deploy/compose/env/prod.env.example b/deploy/compose/env/prod.env.example index 476d3ad2e..96286b817 100644 --- a/deploy/compose/env/prod.env.example +++ b/deploy/compose/env/prod.env.example @@ -1,49 +1,76 @@ -# Substitutions for docker-compose.prod.yaml -# ⚠️ Replace all placeholder secrets with values sourced from your secret manager. -MONGO_INITDB_ROOT_USERNAME=stellaops-prod -MONGO_INITDB_ROOT_PASSWORD=REPLACE_WITH_STRONG_PASSWORD -MINIO_ROOT_USER=stellaops-prod -MINIO_ROOT_PASSWORD=REPLACE_WITH_STRONG_PASSWORD -# Expose the MinIO console only to trusted operator networks. -MINIO_CONSOLE_PORT=39001 -RUSTFS_HTTP_PORT=8080 -AUTHORITY_ISSUER=https://authority.prod.stella-ops.org -AUTHORITY_PORT=8440 -SIGNER_POE_INTROSPECT_URL=https://licensing.prod.stella-ops.org/introspect +# Substitutions for docker-compose.prod.yaml +# ⚠️ Replace all placeholder secrets with values sourced from your secret manager. + +# PostgreSQL Database +POSTGRES_USER=stellaops-prod +POSTGRES_PASSWORD=REPLACE_WITH_STRONG_PASSWORD +POSTGRES_DB=stellaops_platform +POSTGRES_PORT=5432 + +# Valkey (Redis-compatible cache and messaging) +VALKEY_PORT=6379 + +# RustFS Object Storage +RUSTFS_HTTP_PORT=8080 + +# Authority +AUTHORITY_ISSUER=https://authority.prod.stella-ops.org +AUTHORITY_PORT=8440 + +# Signer +SIGNER_POE_INTROSPECT_URL=https://licensing.prod.stella-ops.org/introspect SIGNER_PORT=8441 + +# Attestor ATTESTOR_PORT=8442 -# Secrets for Issuer Directory are provided via issuer-directory.mongo.env (see etc/secrets/issuer-directory.mongo.secret.example). + +# Issuer Directory ISSUER_DIRECTORY_PORT=8447 -ISSUER_DIRECTORY_MONGO_CONNECTION_STRING=mongodb://${MONGO_INITDB_ROOT_USERNAME}:${MONGO_INITDB_ROOT_PASSWORD}@mongo:27017 ISSUER_DIRECTORY_SEED_CSAF=true + +# Concelier CONCELIER_PORT=8445 -SCANNER_WEB_PORT=8444 -UI_PORT=8443 -NATS_CLIENT_PORT=4222 -SCANNER_QUEUE_BROKER=nats://nats:4222 -# `true` enables signed scanner events for Notify ingestion. -SCANNER_EVENTS_ENABLED=true -SCANNER_EVENTS_DRIVER=redis -# Leave SCANNER_EVENTS_DSN empty to inherit the Redis queue DSN when SCANNER_QUEUE_BROKER uses redis://. -SCANNER_EVENTS_DSN= + +# Scanner +SCANNER_WEB_PORT=8444 +SCANNER_QUEUE_BROKER=valkey://valkey:6379 +# `true` enables signed scanner events for Notify ingestion. +SCANNER_EVENTS_ENABLED=true +SCANNER_EVENTS_DRIVER=valkey +SCANNER_EVENTS_DSN=valkey:6379 SCANNER_EVENTS_STREAM=stella.events SCANNER_EVENTS_PUBLISH_TIMEOUT_SECONDS=5 SCANNER_EVENTS_MAX_STREAM_LENGTH=10000 + +# Scanner Surface.Env Configuration SCANNER_SURFACE_FS_ENDPOINT=https://surfacefs.prod.stella-ops.org/api/v1 SCANNER_SURFACE_CACHE_ROOT=/var/lib/stellaops/surface -# Zastava inherits Scanner defaults; override if Observer/Webhook diverge -ZASTAVA_SURFACE_FS_ENDPOINT=${SCANNER_SURFACE_FS_ENDPOINT} -ZASTAVA_SURFACE_CACHE_ROOT=${SCANNER_SURFACE_CACHE_ROOT} SCANNER_SURFACE_SECRETS_PROVIDER=kubernetes SCANNER_SURFACE_SECRETS_ROOT=stellaops/scanner -SCHEDULER_QUEUE_KIND=Nats -SCHEDULER_QUEUE_NATS_URL=nats://nats:4222 -SCHEDULER_STORAGE_DATABASE=stellaops_scheduler + +# Zastava (inherits Scanner defaults; override if Observer/Webhook diverge) +ZASTAVA_SURFACE_FS_ENDPOINT=${SCANNER_SURFACE_FS_ENDPOINT} +ZASTAVA_SURFACE_CACHE_ROOT=${SCANNER_SURFACE_CACHE_ROOT} + +# Scheduler (Valkey default, NATS optional) +SCHEDULER_QUEUE_KIND=Valkey +SCHEDULER_QUEUE_VALKEY_URL=valkey:6379 +# SCHEDULER_QUEUE_NATS_URL=nats://nats:4222 +SCHEDULER_STORAGE_DATABASE=stellaops_platform SCHEDULER_SCANNER_BASEADDRESS=http://scanner-web:8444 + +# NATS (Optional - only if using NATS instead of Valkey for queues) +NATS_CLIENT_PORT=4222 + +# Advisory AI ADVISORY_AI_WEB_PORT=8448 ADVISORY_AI_SBOM_BASEADDRESS=https://scanner-web:8444 ADVISORY_AI_INFERENCE_MODE=Local ADVISORY_AI_REMOTE_BASEADDRESS= ADVISORY_AI_REMOTE_APIKEY= -# External reverse proxy (Traefik, Envoy, etc.) that terminates TLS. -FRONTDOOR_NETWORK=stellaops_frontdoor + +# Web UI +UI_PORT=8443 + +# External reverse proxy (Traefik, Envoy, etc.) that terminates TLS. +FRONTDOOR_NETWORK=stellaops_frontdoor diff --git a/deploy/compose/env/stage.env.example b/deploy/compose/env/stage.env.example index 670238958..799830c4a 100644 --- a/deploy/compose/env/stage.env.example +++ b/deploy/compose/env/stage.env.example @@ -1,44 +1,71 @@ -# Substitutions for docker-compose.stage.yaml -MONGO_INITDB_ROOT_USERNAME=stellaops -MONGO_INITDB_ROOT_PASSWORD=stage-password -MINIO_ROOT_USER=stellaops-stage -MINIO_ROOT_PASSWORD=stage-minio-secret -MINIO_CONSOLE_PORT=19001 +# Substitutions for docker-compose.stage.yaml + +# PostgreSQL Database +POSTGRES_USER=stellaops +POSTGRES_PASSWORD=stage-password +POSTGRES_DB=stellaops_platform +POSTGRES_PORT=5432 + +# Valkey (Redis-compatible cache and messaging) +VALKEY_PORT=6379 + +# RustFS Object Storage RUSTFS_HTTP_PORT=8080 + +# Authority AUTHORITY_ISSUER=https://authority.stage.stella-ops.internal -AUTHORITY_PORT=8440 -SIGNER_POE_INTROSPECT_URL=https://licensing.stage.stella-ops.internal/introspect +AUTHORITY_PORT=8440 + +# Signer +SIGNER_POE_INTROSPECT_URL=https://licensing.stage.stella-ops.internal/introspect SIGNER_PORT=8441 + +# Attestor ATTESTOR_PORT=8442 -# Secrets for Issuer Directory are provided via issuer-directory.mongo.env (see etc/secrets/issuer-directory.mongo.secret.example). + +# Issuer Directory ISSUER_DIRECTORY_PORT=8447 -ISSUER_DIRECTORY_MONGO_CONNECTION_STRING=mongodb://${MONGO_INITDB_ROOT_USERNAME}:${MONGO_INITDB_ROOT_PASSWORD}@mongo:27017 ISSUER_DIRECTORY_SEED_CSAF=true + +# Concelier CONCELIER_PORT=8445 + +# Scanner SCANNER_WEB_PORT=8444 -UI_PORT=8443 -NATS_CLIENT_PORT=4222 -SCANNER_QUEUE_BROKER=nats://nats:4222 +SCANNER_QUEUE_BROKER=valkey://valkey:6379 SCANNER_EVENTS_ENABLED=false -SCANNER_EVENTS_DRIVER=redis -# Leave SCANNER_EVENTS_DSN empty to inherit the Redis queue DSN when SCANNER_QUEUE_BROKER uses redis://. -SCANNER_EVENTS_DSN= +SCANNER_EVENTS_DRIVER=valkey +SCANNER_EVENTS_DSN=valkey:6379 SCANNER_EVENTS_STREAM=stella.events SCANNER_EVENTS_PUBLISH_TIMEOUT_SECONDS=5 SCANNER_EVENTS_MAX_STREAM_LENGTH=10000 + +# Scanner Surface.Env Configuration SCANNER_SURFACE_FS_ENDPOINT=http://rustfs:8080/api/v1 SCANNER_SURFACE_CACHE_ROOT=/var/lib/stellaops/surface -# Zastava inherits Scanner defaults; override if Observer/Webhook diverge -ZASTAVA_SURFACE_FS_ENDPOINT=${SCANNER_SURFACE_FS_ENDPOINT} -ZASTAVA_SURFACE_CACHE_ROOT=${SCANNER_SURFACE_CACHE_ROOT} SCANNER_SURFACE_SECRETS_PROVIDER=kubernetes SCANNER_SURFACE_SECRETS_ROOT=stellaops/scanner -SCHEDULER_QUEUE_KIND=Nats -SCHEDULER_QUEUE_NATS_URL=nats://nats:4222 -SCHEDULER_STORAGE_DATABASE=stellaops_scheduler + +# Zastava (inherits Scanner defaults; override if Observer/Webhook diverge) +ZASTAVA_SURFACE_FS_ENDPOINT=${SCANNER_SURFACE_FS_ENDPOINT} +ZASTAVA_SURFACE_CACHE_ROOT=${SCANNER_SURFACE_CACHE_ROOT} + +# Scheduler (Valkey default, NATS optional) +SCHEDULER_QUEUE_KIND=Valkey +SCHEDULER_QUEUE_VALKEY_URL=valkey:6379 +# SCHEDULER_QUEUE_NATS_URL=nats://nats:4222 +SCHEDULER_STORAGE_DATABASE=stellaops_platform SCHEDULER_SCANNER_BASEADDRESS=http://scanner-web:8444 + +# NATS (Optional - only if using NATS instead of Valkey for queues) +NATS_CLIENT_PORT=4222 + +# Advisory AI ADVISORY_AI_WEB_PORT=8448 ADVISORY_AI_SBOM_BASEADDRESS=http://scanner-web:8444 ADVISORY_AI_INFERENCE_MODE=Local ADVISORY_AI_REMOTE_BASEADDRESS= ADVISORY_AI_REMOTE_APIKEY= + +# Web UI +UI_PORT=8443 diff --git a/docs/07_HIGH_LEVEL_ARCHITECTURE.md b/docs/07_HIGH_LEVEL_ARCHITECTURE.md index fe6338ded..e6ceb3175 100755 --- a/docs/07_HIGH_LEVEL_ARCHITECTURE.md +++ b/docs/07_HIGH_LEVEL_ARCHITECTURE.md @@ -54,9 +54,10 @@ * **Fulcio** (Sigstore CA) — issues short‑lived signing certs (keyless). * **Rekor v2** (tile‑backed transparency log). -* **RustFS** — offline-first object store with deterministic REST API (S3/MinIO fallback available for legacy installs). +* **RustFS** — offline-first object store with deterministic REST API; S3/MinIO compatibility layer available for legacy deployments. * **PostgreSQL** (≥16) — primary control-plane storage with per-module schema isolation (authority, vuln, vex, scheduler, notify, policy, concelier). See [Database Architecture](#database-architecture-postgresql). -* **Queue** — Redis Streams / NATS / RabbitMQ (pluggable). +* **Valkey** (≥8.0) — Redis-compatible cache for DPoP nonces, event streams, queues, and rate limiting. +* **Queue** — Valkey Streams (default); NATS JetStream available as optional transport (opt-in only). * **OCI Registry** — must support **Referrers API** (discover SBOMs/signatures). ### 1.3 Cloud licensing (Stella Ops) @@ -86,9 +87,9 @@ flowchart LR ATT[Attestor\n(Rekor v2 submit/verify)] UI[Web UI (Angular)] Z[Zastava\n(Runtime Inspector/Enforcer)] - RFS[(RustFS object store)] + RFS[(RustFS)] PG[(PostgreSQL)] - QUE[(Queue/Streams)] + VK[(Valkey)] end CLI[StellaOps.Cli / Buildx Plugin] @@ -97,8 +98,8 @@ flowchart LR REK[ Rekor v2 (tiles) ] CLI -->|scan/build| SW - SW -->|jobs| QUE - QUE --> WK + SW -->|jobs| VK + VK --> WK WK --> RFS SW --> PG CONC --> PG @@ -604,8 +605,8 @@ Binary header + purl table + roaring bitmaps; optional `usedByEntrypoint` flags ## 9) Scale, performance & quotas -* **Workers:** horizontal; **distributed lock per layer digest**; global CAS in MinIO. -* **Queues:** Redis Streams / NATS / RabbitMQ. HPA by queue depth, CPU, memory. +* **Workers:** horizontal; **distributed lock per layer digest**; global CAS in RustFS. +* **Queues:** Valkey Streams (default); NATS JetStream available as opt-in alternative. HPA by queue depth, CPU, memory. * **Registry throttling:** per‑registry concurrency budgets. * **Targets:** @@ -630,20 +631,21 @@ Binary header + purl table + roaring bitmaps; optional `usedByEntrypoint` flags ```yaml services: - authority: { image: stellaops/authority, depends_on: [postgres] } + authority: { image: stellaops/authority, depends_on: [postgres, valkey] } fulcio: { image: sigstore/fulcio } rekor: { image: sigstore/rekor-v2 } - minio: { image: minio/minio, command: server /data --console-address ":9001" } - postgres: { image: postgres:15-alpine, environment: { POSTGRES_DB: stellaops, POSTGRES_USER: stellaops } } + rustfs: { image: stellaops/rustfs, environment: { RUSTFS_DATA: /data } } + valkey: { image: valkey/valkey:8.0, command: valkey-server } + postgres: { image: postgres:16-alpine, environment: { POSTGRES_DB: stellaops, POSTGRES_USER: stellaops } } signer: { image: stellaops/signer, depends_on: [authority, fulcio] } attestor: { image: stellaops/attestor, depends_on: [rekor, signer] } - scanner-web: { image: stellaops/scanner-web, depends_on: [postgres, minio, signer, attestor] } + scanner-web: { image: stellaops/scanner-web, depends_on: [postgres, rustfs, valkey, signer, attestor] } scanner-worker: { image: stellaops/scanner-worker, deploy: { replicas: 4 }, depends_on: [scanner-web] } concelier: { image: stellaops/concelier-web, depends_on: [postgres] } excititor: { image: stellaops/excititor-web, depends_on: [postgres] } - scheduler-web: { image: stellaops/scheduler-web, depends_on: [postgres] } + scheduler-web: { image: stellaops/scheduler-web, depends_on: [postgres, valkey] } scheduler-worker:{ image: stellaops/scheduler-worker, deploy: { replicas: 2 }, depends_on: [scheduler-web] } - notify-web: { image: stellaops/notify-web, depends_on: [postgres] } + notify-web: { image: stellaops/notify-web, depends_on: [postgres, valkey] } notify-worker: { image: stellaops/notify-worker, deploy: { replicas: 2 }, depends_on: [notify-web] } ui: { image: stellaops/ui, depends_on: [scanner-web, concelier, excititor, scheduler-web, notify-web] } ``` @@ -667,7 +669,7 @@ services: * **Notify metrics:** `notify.sent_total{channel}`, `notify.dropped_total{reason}`, `notify.digest_coalesced_total`, `notify.latency_ms`. * **Tracing:** per‑stage spans; correlation IDs across Scanner→Signer→Attestor and Concelier/Excititor→Scheduler→Scanner→Notify. * **Audit logs:** every signing records `license_id`, `image_digest`, `policy_digest`, and Rekor UUID; Scheduler records who scheduled what; Notify records where, when, and why messages were sent or deduped. -* **Compliance:** RustFS retention headers (or MinIO Object Lock when operating in S3 mode) keep immutable artifacts tamper‑resistant; reproducible outputs via policy digest + SBOM digest in predicate. +* **Compliance:** RustFS retention headers keep immutable artifacts tamper‑resistant; S3-compatibility mode can use native Object Lock when enabled for legacy deployments; reproducible outputs via policy digest + SBOM digest in predicate. --- diff --git a/docs/11_DATA_SCHEMAS.md b/docs/11_DATA_SCHEMAS.md index ad1a7300a..7cf98b7ff 100755 --- a/docs/11_DATA_SCHEMAS.md +++ b/docs/11_DATA_SCHEMAS.md @@ -1,7 +1,7 @@ # Data Schemas & Persistence Contracts -*Audience* – backend developers, plug‑in authors, DB admins. -*Scope* – describes **Redis**, **PostgreSQL**, and on‑disk blob shapes that power Stella Ops. +*Audience* – backend developers, plug‑in authors, DB admins. +*Scope* – describes **Valkey**, **PostgreSQL**, and on‑disk blob shapes that power Stella Ops. --- @@ -46,12 +46,12 @@ blobs/ │   └─ sbom.meta.json # wrapper (shape above) ``` -> **Note** – blob storage can point at S3, MinIO, or plain disk; driver plug‑ins adapt. +> **Note** – RustFS is the primary object store; S3/MinIO compatibility layer available for legacy deployments; driver plug‑ins support multiple backends. #### 1.3 Delta SBOM Extension -When `partial: true`, *only* the missing layers have been scanned. -Merging logic inside `scanning` module stitches new data onto the cached full SBOM in Redis. +When `partial: true`, *only* the missing layers have been scanned. +Merging logic inside `scanning` module stitches new data onto the cached full SBOM in Valkey. --- diff --git a/src/Aoc/StellaOps.Aoc.Cli/Commands/VerifyCommand.cs b/src/Aoc/StellaOps.Aoc.Cli/Commands/VerifyCommand.cs index f85f66eee..8ae47f294 100644 --- a/src/Aoc/StellaOps.Aoc.Cli/Commands/VerifyCommand.cs +++ b/src/Aoc/StellaOps.Aoc.Cli/Commands/VerifyCommand.cs @@ -17,13 +17,12 @@ public static class VerifyCommand IsRequired = true }; - var mongoOption = new Option( - aliases: ["--mongo", "-m"], - description: "MongoDB connection string (legacy support)"); - - var postgresOption = new Option( + var postgresOption = new Option( aliases: ["--postgres", "-p"], - description: "PostgreSQL connection string"); + description: "PostgreSQL connection string") + { + IsRequired = true + }; var outputOption = new Option( aliases: ["--output", "-o"], @@ -50,7 +49,6 @@ public static class VerifyCommand var command = new Command("verify", "Verify AOC compliance for documents since a given point") { sinceOption, - mongoOption, postgresOption, outputOption, ndjsonOption, @@ -62,8 +60,7 @@ public static class VerifyCommand command.SetHandler(async (context) => { var since = context.ParseResult.GetValueForOption(sinceOption)!; - var mongo = context.ParseResult.GetValueForOption(mongoOption); - var postgres = context.ParseResult.GetValueForOption(postgresOption); + var postgres = context.ParseResult.GetValueForOption(postgresOption)!; var output = context.ParseResult.GetValueForOption(outputOption); var ndjson = context.ParseResult.GetValueForOption(ndjsonOption); var tenant = context.ParseResult.GetValueForOption(tenantOption); @@ -73,7 +70,6 @@ public static class VerifyCommand var options = new VerifyOptions { Since = since, - MongoConnectionString = mongo, PostgresConnectionString = postgres, OutputPath = output, NdjsonPath = ndjson, @@ -95,17 +91,11 @@ public static class VerifyCommand { Console.WriteLine($"AOC Verify starting..."); Console.WriteLine($" Since: {options.Since}"); + Console.WriteLine($" PostgreSQL: {options.PostgresConnectionString}"); Console.WriteLine($" Tenant: {options.Tenant ?? "(all)"}"); Console.WriteLine($" Dry run: {options.DryRun}"); } - // Validate connection string is provided - if (string.IsNullOrEmpty(options.MongoConnectionString) && string.IsNullOrEmpty(options.PostgresConnectionString)) - { - Console.Error.WriteLine("Error: Either --mongo or --postgres connection string is required"); - return 1; - } - if (options.DryRun) { Console.WriteLine("Dry run mode - configuration validated successfully"); diff --git a/src/Aoc/StellaOps.Aoc.Cli/Models/VerifyOptions.cs b/src/Aoc/StellaOps.Aoc.Cli/Models/VerifyOptions.cs index 15675f950..a4826defc 100644 --- a/src/Aoc/StellaOps.Aoc.Cli/Models/VerifyOptions.cs +++ b/src/Aoc/StellaOps.Aoc.Cli/Models/VerifyOptions.cs @@ -3,8 +3,7 @@ namespace StellaOps.Aoc.Cli.Models; public sealed class VerifyOptions { public required string Since { get; init; } - public string? MongoConnectionString { get; init; } - public string? PostgresConnectionString { get; init; } + public required string PostgresConnectionString { get; init; } public string? OutputPath { get; init; } public string? NdjsonPath { get; init; } public string? Tenant { get; init; } diff --git a/src/Aoc/StellaOps.Aoc.Cli/Services/AocVerificationService.cs b/src/Aoc/StellaOps.Aoc.Cli/Services/AocVerificationService.cs index 6bf34e2c5..a40ab2bad 100644 --- a/src/Aoc/StellaOps.Aoc.Cli/Services/AocVerificationService.cs +++ b/src/Aoc/StellaOps.Aoc.Cli/Services/AocVerificationService.cs @@ -22,17 +22,8 @@ public sealed class AocVerificationService // Parse the since parameter var sinceTimestamp = ParseSinceParameter(options.Since); - // Route to appropriate database verification - if (!string.IsNullOrEmpty(options.PostgresConnectionString)) - { - await VerifyPostgresAsync(options.PostgresConnectionString, sinceTimestamp, options.Tenant, result, cancellationToken); - } - else if (!string.IsNullOrEmpty(options.MongoConnectionString)) - { - // MongoDB support - for legacy verification - // Note: The codebase is transitioning to PostgreSQL - await VerifyMongoAsync(options.MongoConnectionString, sinceTimestamp, options.Tenant, result, cancellationToken); - } + // Verify PostgreSQL database + await VerifyPostgresAsync(options.PostgresConnectionString, sinceTimestamp, options.Tenant, result, cancellationToken); stopwatch.Stop(); result.DurationMs = stopwatch.ElapsedMilliseconds; @@ -237,20 +228,4 @@ public sealed class AocVerificationService Console.WriteLine("Note: excititor.vex_documents table not found (may not be initialized)"); } } - - private Task VerifyMongoAsync( - string connectionString, - DateTimeOffset since, - string? tenant, - VerificationResult result, - CancellationToken cancellationToken) - { - // MongoDB support is deprecated - log warning and return empty result - Console.WriteLine("Warning: MongoDB verification is deprecated. The codebase is transitioning to PostgreSQL."); - Console.WriteLine(" Use --postgres instead of --mongo for production verification."); - - // For backwards compatibility during transition, we don't fail - // but we also don't perform actual MongoDB queries - return Task.CompletedTask; - } }