Files
missions/_docs/00_problem/restrictions.md
T
Oleksandr Bezdieniezhnykh 78dea8ebab
ci/woodpecker/push/build-arm Pipeline was successful
chore: update configuration and Docker setup for JWT and test results
Enhanced the .gitignore to exclude test results and updated the Dockerfile to include a new entrypoint script for improved container initialization. Refactored JWT configuration to support additional parameters for automatic refresh intervals, ensuring better control over token management. Updated the ConfigurationResolver to enforce required environment variables without hardcoded fallbacks, enhancing security and flexibility.
2026-05-15 03:23:23 +03:00

10 KiB

Restrictions — Azaion.Missions

Status: derived-from-code (autodev /document Step 6, 2026-05-14). Each restriction below is grounded in code, configuration, or Dockerfile evidence — none are aspirational. References point to the artefact that establishes the constraint.


Hardware restrictions

# Restriction Evidence
H1 Service runs on operator-owned edge devices (Jetson Orin / OrangePI / operator-PC), one container per device Dockerfile multi-arch; ../../suite/_docs/00_top_level_architecture.md § Edge Tier
H2 Multi-arch container — ARM64 dominant (Jetson / OrangePI), AMD64 supported (operator-PC) Dockerfile --platform=$BUILDPLATFORM, dotnet publish --os linux --arch $arch; .woodpecker/build-arm.yml tag suffix -arm
H3 Vertical scale only — exactly one instance per device, no horizontal scale-out _docs/02_document/architecture.md § 3 Deployment Model; suite arch doc § Edge Tier
H4 No managed cloud — every deployment is on customer-owned hardware suite arch doc § Edge Tier
H5 Watchtower handles container restarts; flight-gate prevents container restart mid-mission suite arch doc § Edge Tier; _docs/02_document/architecture.md § 6 Availability
H6 Resource limits not enforced inside the container; device-level cgroups / docker compose limits set at suite level Dockerfile (no --memory / cpu); suite _infra/_compose/

Software restrictions

# Restriction Evidence
S1 Language: C#; runtime: .NET 10 (net10.0) Azaion.Flights.csproj (post-B5: Azaion.Missions.csproj)
S2 Web framework: ASP.NET Core (Microsoft.NET.Sdk.Web) csproj
S3 Data access library: linq2db 6.2.0 csproj <PackageReference Include="linq2db" Version="6.2.0" />
S4 Database driver: Npgsql 10.0.2 csproj
S5 Auth library: Microsoft.AspNetCore.Authentication.JwtBearer 10.0.5 csproj
S6 Swagger / OpenAPI: Swashbuckle 10.1.5, mounted unconditionally (NOT gated on IsDevelopment()) — ADR-005 carry-forward csproj + Program.cs
S7 Database engine: PostgreSQL (no other DB engines supported) Program.cs UsePostgreSQL; suite arch doc § Database Topology
S8 One csproj, one root namespace (Azaion.Missions.* post-B5) — components are logical groupings, not compilation units csproj; _docs/02_document/architecture.md ADR-008
S9 No src/ directory — project sits at the repo root repo layout; _docs/02_document/00_discovery.md § Repository Layout
S10 Layer-organized layout (Controllers/, Services/, DTOs/, Enums/, Auth/, Middleware/, Database/ at repo root) repo layout; _docs/02_document/module-layout.md
S11 No automated tests today (no tests/ directory; no test sibling project) repo layout; _docs/02_document/00_discovery.md § Test Layout
S12 No migration tool — schema bootstrap via raw CREATE TABLE IF NOT EXISTS + one-shot B9 DROP TABLE IF EXISTS block Database/DatabaseMigrator.cs; ADR-004
S13 No in-process message queue, no event bus, no RPC — components communicate via direct C# calls registered in DI _docs/02_document/architecture.md § 5; Program.cs
S14 Tables OWNED by this service (post-B7+B9): vehicles, missions, waypoints, map_objects (4 owned). 3 borrowed read-only stubs (media, annotations, detection) Database/DatabaseMigrator.cs; Database/AppDataConnection.cs; _docs/02_document/data_model.md
S15 gps-denied is decoupled by design — no runtime call in either direction; gps-denied references mission_id / waypoint_id as plain GUIDs in its own tables ADR-007

Environment / configuration restrictions

# Restriction Evidence
E1 Four required env vars at runtime: DATABASE_URL, JWT_ISSUER, JWT_AUDIENCE, JWT_JWKS_URL. Each resolved via Infrastructure/ConfigurationResolver.csResolveRequiredOrThrow (env-first, then IConfiguration config key Database:Url / Jwt:Issuer / Jwt:Audience / Jwt:JwksUrl, else throw at startup). The legacy JWT_SECRET env var is no longer consulted Program.cs, Auth/JwtExtensions.cs, Infrastructure/ConfigurationResolver.cs
E2 DATABASE_URL accepts either a postgresql://user:pass@host:port/db URL OR a raw Npgsql connection string (local helper ConvertPostgresUrl). ConvertPostgresUrl does NOT URL-decode user/password — credentials with @, :, /, % need raw Npgsql form Program.cs ConvertPostgresUrl
E3 No hardcoded development fallbacks. ResolveRequiredOrThrow throws InvalidOperationException at startup if any of DATABASE_URL / JWT_ISSUER / JWT_AUDIENCE / JWT_JWKS_URL is missing or whitespace-only. ADR-005's "dev fallback secret" branch is obsolete; only the Swagger-unconditional branch remains Infrastructure/ConfigurationResolver.cs; Program.cs
E4 JWT signature validation is asymmetric (ECDSA-SHA256) against the JWKS at JWT_JWKS_URL. admin holds the private key; this service caches the public JWKS via Microsoft.IdentityModel.Protocols.ConfigurationManager<JsonWebKeySet> (fetched at startup, refreshed on default schedule, HTTPS-only via HttpDocumentRetriever { RequireHttps = true }). JWKS rotation does NOT require a coordinated redeploy — consumers pick up the new keys at the next refresh tick Auth/JwtExtensions.cs; _docs/02_document/components/05_identity/description.md
E5 Container EXPOSE 8080; edge compose maps host port 5002:8080 Dockerfile; suite _infra/_compose/
E6 Image tag: ${REGISTRY_HOST}/azaion/missions:${BRANCH}-arm post-B10 (was azaion/flights:*-arm pre-B10) .woodpecker/build-arm.yml (post-B10)
E7 Entrypoint: dotnet Azaion.Missions.dll post-B5 (was Azaion.Flights.dll pre-B5) Dockerfile (post-B5)
E8 No environment-specific overrides in appsettings.*.json today, but IConfiguration lookups (e.g. Database:Url, Jwt:Issuer) are wired so adding appsettings.*.json later requires no code changes Program.cs; no appsettings.*.json in repo
E9 CORS is gated by Infrastructure/CorsConfigurationValidator.cs. In Production (case-insensitive on ASPNETCORE_ENVIRONMENT) startup THROWS when CorsConfig:AllowedOrigins is empty AND CorsConfig:AllowAnyOrigin != true. In non-Production environments, an empty allow-list with AllowAnyOrigin=false falls back to permissive (AllowAnyOrigin/Method/Header) and emits the PermissiveDefaultWarning startup log. The "all environments permissive" claim no longer holds Program.cs, Infrastructure/CorsConfigurationValidator.cs
E10 TLS termination is the suite reverse proxy's responsibility — container exposes plain HTTP on :8080. The JWKS fetch itself is independently constrained to HTTPS (RequireHttps = true) Dockerfile; suite arch doc; Auth/JwtExtensions.cs

Operational restrictions

# Restriction Evidence
O1 Migrator runs at every process start; idempotent (IF NOT EXISTS); B9 adds a one-shot DROP TABLE IF EXISTS orthophotos / gps_corrections block for fielded legacy devices Database/DatabaseMigrator.cs
O2 flight-gate (suite-level) is the ONLY orchestration that prevents restart mid-mission; no Kubernetes suite arch doc § Edge Tier
O3 No version table; the migrator runs every startup Database/DatabaseMigrator.cs
O4 Single Woodpecker CI job per repo: docker build + push on [dev, stage, main] branches; no test, no security scan, no migration check .woodpecker/build-arm.yml
O5 No structured logging (Serilog / Seq) — LogError(ex, "Unhandled exception") is the only application-level log Middleware/ErrorHandlingMiddleware.cs; _docs/02_document/architecture.md § 7
O6 No correlation ID, no per-request audit trail, no per-user attribution (JWT user-id claim parsed but not consumed) Auth/JwtExtensions.cs; _docs/02_document/components/05_identity/description.md
O7 Health endpoint: GET /health returns { status: "healthy" } with no DB ping (process-liveness only) Program.cs MapGet("/health")
O8 Cascade-delete is NOT transaction-wrapped today (ADR-006) — partial failure leaves orphan rows in media / annotations / detection / map_objects Services/FlightService.cs (post-B6: MissionService.cs); Services/WaypointService.cs
O9 Each backend service is responsible for its own table migrations; if annotations is absent at deploy time, the cascade-delete walk fails on relation does not exist (abnormal edge deployment) _docs/02_document/components/02_mission_planning/description.md Caveats #6
O10 One-instance-per-device constraint means session state, in-memory caches, and rate limits are NOT cluster-aware (none of these are implemented today either) Program.cs; suite arch doc

Out-of-scope (NOT this service's responsibility)

Concern Where it lives Why it's not here
Token issuance (sign / mint) admin (central .NET service) Local validation only; offline-tolerant edge design
User CRUD, role assignment admin + ../../suite/_docs/00_roles_permissions.md Suite-level concern
Media storage / upload annotations (sibling edge service) annotations owns the table schema
AI annotation rules annotations Schema and behaviour both owned by annotations
Object detection / class definitions Detection pipeline (sibling edge service) Pipeline owns the detection table
map_objects write path autopilot (sibling edge service) This service owns the schema + cascade-delete only
Orthophoto / live-GPS / GPS correction gps-denied (separate service after B7) ADR-007
TLS / HTTPS termination Suite reverse proxy _docs/02_document/architecture.md § 7
Schema rename / column drop / type change Future migration tool (ADR-004 carry-forward) Today's IF NOT EXISTS migrator can't reshape existing schema; B9's DROP TABLE IF EXISTS is the single explicit destructive step
iss / aud JWT validation Now implemented in this service's code (ValidateIssuer=true against JWT_ISSUER, ValidateAudience=true against JWT_AUDIENCE). The CMMC L2 row 3 finding is structurally fixed here; suite-level docs may still describe the legacy model and have a separate sync task pending n/a — no longer a carry-forward in this repo
camelCase wire-shape migration Suite-wide cutover (ADR-002 carry-forward) All-or-nothing; UI + autopilot consume PascalCase today