Files
missions/_docs/00_problem/restrictions.md
T
Oleksandr Bezdieniezhnykh 7025f4d075 refactor: enhance JWT authentication and CORS configuration
Updated JWT authentication to use configuration values instead of hardcoded secrets, improving security and flexibility. Enhanced CORS policy to conditionally allow origins based on configuration settings, with logging for permissive defaults. Updated README to reflect project renaming and clarify service context.
2026-05-14 19:48:25 +03:00

84 lines
8.9 KiB
Markdown

# 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 | Two required env vars at runtime: `DATABASE_URL`, `JWT_SECRET` | `Program.cs` `Environment.GetEnvironmentVariable` |
| E2 | `DATABASE_URL` accepts either a `postgresql://user:pass@host:port/db` URL OR a raw Npgsql connection string (local helper `ConvertPostgresUrl`) | `Program.cs` `ConvertPostgresUrl` |
| E3 | Hardcoded development fallbacks: `JWT_SECRET=development-secret-key-min-32-chars!!`, `DATABASE_URL=Host=localhost;Database=azaion;Username=postgres;Password=changeme` (NOT gated on `IsDevelopment()`) — ADR-005 carry-forward; production deploys MUST override | `Program.cs` |
| E4 | `JWT_SECRET` is shared across `admin` + every backend service on the same edge device — rotation requires a coordinated re-deploy across all of them | `_docs/02_document/components/05_identity/description.md`; suite arch doc |
| 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` — single config flow via env vars | `Program.cs`; no `appsettings.Production.json` in repo |
| E9 | CORS: `AllowAnyOrigin / AllowAnyMethod / AllowAnyHeader` in **all** environments (assumed safe behind suite reverse proxy) | `Program.cs` |
| E10 | TLS termination is the suite reverse proxy's responsibility — container exposes plain HTTP on `:8080` | `Dockerfile`; suite arch doc |
## 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 | Suite-level remediation (CMMC L2 row 3, AZ-487 / AZ-494) | Out of this Epic; consistent with shared-secret model today |
| camelCase wire-shape migration | Suite-wide cutover (ADR-002 carry-forward) | All-or-nothing; UI + autopilot consume PascalCase today |