This commit captures everything produced during autodev existing-code Steps 1 (Document), 2 (Architecture Baseline Scan), and 3 (Test Spec), together with the targeted auth + CORS re-sync triggered on 2026-05-14 when codebase drift was detected at Step 4 entry. None of this work was previously committed. Step 1 (Document) — 50+ _docs/02_document/ files: problem, solution, architecture, system flows, glossary, module-layout, per-component specs (01..06), modules, deployment, diagrams, data model, FINAL report, verification log, discovery. Step 2 (Architecture Baseline) — architecture_compliance_baseline.md. Verdict PASS_WITH_WARNINGS (0 Critical, 0 High, 1 Medium, 2 Low). No High/Critical findings; auto-chained to Step 3 per existing-code flow. Step 3 (Test Spec) — _docs/02_document/tests/* (67 scenarios across blackbox, security, resilience, resource-limit, performance), plus e2e/docker-compose.test.yml, e2e/seed/run.sh, scripts/run-tests.sh, scripts/run-performance-tests.sh. Coverage 88% over the active scope (40 of 45 items covered, 6 RB-deferred, 5 documented-as-uncovered). Targeted auth + CORS re-sync — replaces the deleted in-house token issuer with a JWKS-verifier model. AuthController and TokenService removed; JwtExtensions switched from HS256 symmetric to ES256 over admin's JWKS. ConfigurationResolver and CorsConfigurationValidator added under src/Infrastructure/. ADR-002 and ADR-006 retired; SEC-01, SEC-02, SEC-03 marked Closed. One new testability risk recorded in architecture.md Open Risks Section 6 (JWKS HTTPS gating). Source changes: - src/Auth/JwtExtensions.cs (modified) — ES256, JWKS, alg pinning - src/Program.cs (modified) — DI wiring for ConfigurationResolver and CorsConfigurationValidator - src/Controllers/AuthController.cs (deleted) — no in-service issuance - src/Services/TokenService.cs (deleted) — same - src/Infrastructure/ConfigurationResolver.cs (new) - src/Infrastructure/CorsConfigurationValidator.cs (new) - .env.example (new) — required env var documentation - .gitignore (updated) Cross-repo coordination: _docs/cross-repo/flights_h1_h2_h3_change_spec captures the change-spec for downstream services that consumed the now deleted /auth endpoints. Co-authored-by: Cursor <cursoragent@cursor.com>
4.5 KiB
Environment Strategy
Source of truth: src/Program.cs + src/Database/DatabaseMigrator.cs + .woodpecker/build-arm.yml.
Environments
Branch-driven from CI:
| Branch | Image tag | Intended environment |
|---|---|---|
dev |
dev-arm |
Development (shared) |
stage |
stage-arm |
Pre-production |
main |
main-arm |
Production |
The service binary is identical across environments — all variation is runtime configuration via env vars (no per-environment build flags).
Configuration sources (priority order, per Program.cs)
Environment.GetEnvironmentVariable("KEY").- ASP.NET Core
IConfiguration(builder.Configuration["KEY"]) — coversappsettings.json, command-line args, etc. - No hard-coded fallback for security-sensitive values.
DATABASE_URL,JWT_ISSUER,JWT_AUDIENCE,JWT_JWKS_URL, and (inProduction) a non-emptyCorsConfig:AllowedOriginsare required; missing values cause startup to fail fast viaConfigurationResolver.ResolveRequiredOrThrow/CorsConfigurationValidator.EnsureSafeForEnvironment.
Required environment variables
| Variable | Purpose | Default | Production action |
|---|---|---|---|
DATABASE_URL |
Postgres connection (URL or LinqToDB conn string) | — (required, fail-fast) | MUST set |
JWT_ISSUER |
Expected iss claim; must match admin's JwtConfig:Issuer |
— (required, fail-fast) | MUST set |
JWT_AUDIENCE |
Expected aud claim; must match admin's JwtConfig:Audience |
— (required, fail-fast) | MUST set |
JWT_JWKS_URL |
Admin's JWKS endpoint (HTTPS) | — (required, fail-fast) | https://admin.azaion.com/.well-known/jwks.json |
CorsConfig__AllowedOrigins__0 |
First allowed CORS origin (array via __N indices) |
— | MUST set (or CorsConfig__AllowAnyOrigin=true) in Production |
CorsConfig__AllowAnyOrigin |
Opt-in to permissive CORS (non-production only) | false |
Leave false in Production |
RABBITMQ_HOST |
Stream host | 127.0.0.1 |
Override |
RABBITMQ_STREAM_PORT |
Stream port | 5552 |
Override if non-default |
RABBITMQ_PRODUCER_USER |
Stream user | azaion_producer |
Override |
RABBITMQ_PRODUCER_PASS |
Stream password | producer_pass |
Override |
RABBITMQ_STREAM_NAME |
Stream name | azaion-annotations |
Usually keep (suite contract) |
JWT_SECRET was removed in this cycle — annotations no longer mints HS256 tokens; admin is the sole token issuer (ES256).
URL format conversion
Program.cs accepts DATABASE_URL either as a Linq2DB connection string or as a postgresql://user:pass@host:port/db URL. The ConvertPostgresUrl helper rewrites the URL form into LinqToDB conn-string form. This means operators can use either ENV-style URLs (kubectl/Postgres operator output) or Host=... directly.
DB-driven configuration
Several runtime concerns are stored in database tables, not env:
- Filesystem roots —
directory_settings(defaults/data/...). Updated viaPUT /settings/directories; must triggerPathResolver.Resetfor the change to take effect (Flow F7). - System settings —
system_settings(generate_annotated_image,silent_detection, thumbnail dimensions). - User settings —
user_settings(per UI session prefs).
Operators changing filesystem layout in production need an ADM JWT and the right cluster connectivity, not a redeploy.
Filesystem mounts
The container expects /data/ (or whatever directory_settings points at) to be a writable persistent mount:
/data/images— annotation full images/data/labels— YOLO.txtfiles/data/thumbnails— thumbnails/data/results— annotated images (whengenerate_annotated_image=true)/data/videos— media uploads/data/gps_sat,/data/gps_route— GPS overlays
Without these mounts, every annotation-create / media-upload flow returns 500 from ErrorHandlingMiddleware (FS write fails).
Config drift between environments
Today, environment-specific config is held wherever the deployment platform places env vars (Helm values / Kustomize overlays / Compose files in _infra/). This repo intentionally does not commit per-environment values; the only environment-aware file in-repo is .woodpecker/build-arm.yml.
Open items
- No
appsettings.Production.json— all env-specific config is operator-supplied. Swagger UIis mounted in all environments (ADR-005); production exposure must be controlled at the perimeter.