mirror of
https://github.com/azaion/missions.git
synced 2026-06-21 18:01:08 +00:00
chore: update configuration and Docker setup for JWT and test results
ci/woodpecker/push/build-arm Pipeline was successful
ci/woodpecker/push/build-arm Pipeline was successful
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.
This commit is contained in:
@@ -2,96 +2,133 @@
|
||||
|
||||
**Spec source**: `../../../suite/_docs/10_auth.md` (suite-wide JWT model), `../../../suite/_docs/00_roles_permissions.md` (the `FL` permission code).
|
||||
|
||||
**Implementation status**: ✅ implemented. Single policy `FL` is declared and consumed by every controller.
|
||||
**Implementation status**: ✅ implemented. Single policy `FL` is declared and consumed by every controller in the post-rename target scope.
|
||||
|
||||
> **NOTE (forward-looking)**: post-rename + post-GPS-Denied-removal. Today's `JwtExtensions.cs` also declares a `"GPS"` policy reserved for the (now-removed-from-this-repo) GPS-Denied endpoints. After Jira AZ-EPIC child B7 lands, only `"FL"` remains.
|
||||
|
||||
**Files**: `Auth/JwtExtensions.cs`
|
||||
**Files**: `Auth/JwtExtensions.cs`, `Infrastructure/ConfigurationResolver.cs` (consumed for fail-fast value resolution)
|
||||
|
||||
## 1. High-Level Overview
|
||||
|
||||
**Purpose**: Validate JWT bearer tokens issued by the remote `admin` service and expose the named authorization policy (`FL`) used by controllers in the feature components. This service does not issue tokens -- it consumes them.
|
||||
**Purpose**: Validate JWT bearer tokens issued by the remote `admin` service and expose the named authorization policy (`FL`) used by controllers in the feature components. This service does not issue tokens — it consumes them.
|
||||
|
||||
**Architectural pattern**: ASP.NET Core extension method (`AddJwtAuth`) configuring `IServiceCollection` at DI time.
|
||||
**Architectural pattern**: ASP.NET Core extension method (`AddJwtAuth`) configuring `IServiceCollection` at DI time. JWT signature validation is **asymmetric (ECDSA-SHA256)** against public keys retrieved from `admin`'s JWKS endpoint and cached locally; `admin` is **not** contacted on the request path after the first JWKS fetch.
|
||||
|
||||
**Upstream dependencies**: None internally.
|
||||
**Upstream dependencies**: `Infrastructure/ConfigurationResolver.cs` (shared with `07_host`) for fail-fast value resolution.
|
||||
|
||||
**Downstream consumers**: `07_host` (calls `AddJwtAuth(jwtSecret)` once); `01_vehicle_catalog`, `02_mission_planning` (controllers carry `[Authorize(Policy = "FL")]`).
|
||||
**Downstream consumers**: `07_host` (calls `AddJwtAuth(builder.Configuration)` once); `01_vehicle_catalog`, `02_mission_planning` (controllers carry `[Authorize(Policy = "FL")]`).
|
||||
|
||||
## 2. Internal Interface
|
||||
|
||||
```csharp
|
||||
public static IServiceCollection AddJwtAuth(this IServiceCollection services, string jwtSecret);
|
||||
public static IServiceCollection AddJwtAuth(this IServiceCollection services, IConfiguration configuration);
|
||||
```
|
||||
|
||||
Side effects: registers `JwtBearerDefaults.AuthenticationScheme` and one named authorization policy in DI:
|
||||
`AddJwtAuth` reads three required values via `ConfigurationResolver.ResolveRequiredOrThrow`:
|
||||
|
||||
| Policy | Requirement |
|
||||
|--------|-------------|
|
||||
| `"FL"` | JWT contains a `permissions` claim with value `"FL"` |
|
||||
| Env var | Config key | Purpose |
|
||||
|---------|------------|---------|
|
||||
| `JWT_ISSUER` | `Jwt:Issuer` | Expected `iss` claim value |
|
||||
| `JWT_AUDIENCE` | `Jwt:Audience` | Expected `aud` claim value |
|
||||
| `JWT_JWKS_URL` | `Jwt:JwksUrl` | HTTPS URL of admin's JWKS document (e.g. `https://admin.azaion/.well-known/jwks.json`) |
|
||||
|
||||
## 3. Suite-wide JWT pattern
|
||||
Each value is resolved env-var-first, then config-key, then throws `InvalidOperationException` at startup. There is **no dev fallback**. The legacy `JWT_SECRET` env var is no longer consulted.
|
||||
|
||||
This is the canonical "every backend service" identity model in the Azaion suite. Per `../../../suite/_docs/00_top_level_architecture.md` and `../../../suite/_docs/10_auth.md`:
|
||||
Side effects: registers `JwtBearerDefaults.AuthenticationScheme` and **two** named authorization policies in DI (one is removed after B7 lands):
|
||||
|
||||
| Policy | Requirement | Notes |
|
||||
|--------|-------------|-------|
|
||||
| `"FL"` | JWT contains a `permissions` claim with value `"FL"` | Permanent |
|
||||
| `"GPS"` | JWT contains a `permissions` claim with value `"GPS"` | Removed in Jira B7 (legacy GPS-Denied routes are moving out of this repo) |
|
||||
|
||||
## 3. JWT model (this service) vs. suite-wide pattern
|
||||
|
||||
**This service's implementation** is described in code below. The suite-wide pattern lives in `../../../suite/_docs/00_top_level_architecture.md` and `../../../suite/_docs/10_auth.md` — those documents currently describe the legacy HS256 / shared-secret model and have **not yet been updated** to reflect the ECDSA-on-JWKS evolution captured here. The drift between this service and the suite docs is flagged in `_docs/02_document/05_drift_findings_2026-05-14.md` and will be picked up at the suite level on the next suite `/autodev` invocation. The remaining .NET consumers (`annotations`, `satellite-provider`) may or may not have made the same transition; their docs are the source of truth for their own implementation.
|
||||
|
||||
What is verified against `Auth/JwtExtensions.cs` today:
|
||||
|
||||
```
|
||||
┌─────────────────────┐ ┌──────────────────────┐
|
||||
│ Operator UI │ POST /login │ admin (.NET, remote) │
|
||||
│ (React, edge) │ ──────────────► │ central user DB │
|
||||
│ │ ◄────────────── │ mints HS256 JWT │
|
||||
│ │ Bearer JWT │ (claim: permissions)│
|
||||
└──────────┬──────────┘ └──────────────────────┘
|
||||
│ Bearer JWT (the SAME token reused for every service)
|
||||
│
|
||||
├──────────────────► annotations (.NET, edge) -- ANN claim
|
||||
├──────────────────► missions (.NET, edge) -- FL claim ◄── this service
|
||||
├──────────────────► satellite-provider (.NET, remote) -- ADM claim
|
||||
└──────────────────► (any future .NET service)
|
||||
│ │ ◄────────────── │ ECDSA-signs JWT, │
|
||||
│ │ Bearer JWT │ exposes JWKS │
|
||||
└──────────┬──────────┘ └──────┬───────────────┘
|
||||
│ Bearer JWT │
|
||||
│ │ /.well-known/jwks.json
|
||||
│ │ (HTTPS, fetched once at startup,
|
||||
│ │ cached by ConfigurationManager,
|
||||
│ │ refreshed on default schedule)
|
||||
└────────────► missions ◄───────────┘
|
||||
(this service)
|
||||
validates: ECDSA-SHA256 signature,
|
||||
iss = JWT_ISSUER,
|
||||
aud = JWT_AUDIENCE,
|
||||
exp (with 30s clock skew),
|
||||
alg pinned to EcdsaSha256
|
||||
```
|
||||
|
||||
Every service (admin, annotations, missions, satellite-provider, ...) shares one HMAC secret (`JWT_SECRET`) and validates tokens locally with no network round-trip. The user logs in once at the UI; the resulting bearer token is reusable across every service. **This service neither issues tokens nor talks to the central user DB** -- it only validates.
|
||||
`admin` holds the **private** ECDSA key and signs tokens. This service fetches the **public** JWKS document from `admin` once at startup (on the first protected request after process start) and caches it. Request-path validation is purely cryptographic against the cached keys; `admin` is not contacted per request. The user logs in once at the UI; the resulting bearer token is reusable across every backend service for its lifetime.
|
||||
|
||||
The `permissions` claim drives per-service `[Authorize(Policy = "...")]` checks. The role -> permission matrix lives in `../../../suite/_docs/00_roles_permissions.md`. All routes here require `FL`.
|
||||
The `permissions` claim drives per-service `[Authorize(Policy = "...")]` checks. The role → permission matrix lives in `../../../suite/_docs/00_roles_permissions.md`. All routes in `01_vehicle_catalog` and `02_mission_planning` require `FL`.
|
||||
|
||||
## 4. External API
|
||||
|
||||
None directly. Auth contract is observable only via `401 Unauthorized` / `403 Forbidden` on protected routes.
|
||||
None directly. Auth contract is observable only via `401 Unauthorized` / `403 Forbidden` on protected routes, plus the HTTPS JWKS fetch to `admin` at startup (out-of-band).
|
||||
|
||||
## 5. Data Access Patterns
|
||||
|
||||
None.
|
||||
None against the local PostgreSQL. One outbound HTTPS GET to the configured `JWT_JWKS_URL` at process start, cached by `ConfigurationManager<JsonWebKeySet>` and refreshed on its default schedule (matches admin's `Cache-Control: public, max-age=3600` on the JWKS endpoint).
|
||||
|
||||
## 6. Implementation Details
|
||||
|
||||
**Algorithm**: HMAC-SHA256 signature validation via `SymmetricSecurityKey(UTF-8(jwtSecret))`. Matches the suite-wide shared-secret model.
|
||||
**Mechanism**: ECDSA-SHA256 signature validation against public keys retrieved from `admin`'s JWKS endpoint. The keys are wrapped in a `ConfigurationManager<JsonWebKeySet>` configured with:
|
||||
|
||||
**Token validation flags**:
|
||||
- `ValidateIssuerSigningKey = true`
|
||||
- `ValidateLifetime = true` (with `ClockSkew = 1 minute` -- tighter than .NET's 5-minute default)
|
||||
- `ValidateIssuer = false`, `ValidateAudience = false` -- `iss` / `aud` NOT enforced (consistent with shared-secret intra-suite model). Per the CMMC L2 scorecard (`../../../suite/_docs/05_security/cmmc_l2_scorecard.md` row 3), this is a known finding tracked at the suite level under AZ-487/AZ-494; the remediation will copy the `satellite-provider` pattern across `annotations` and `missions`.
|
||||
- `jwksUrl` — resolved at startup from `JWT_JWKS_URL` / `Jwt:JwksUrl` (fail-fast if missing).
|
||||
- A custom `JwksRetriever : IConfigurationRetriever<JsonWebKeySet>` (private nested class in `JwtExtensions.cs`) that wraps an `IDocumentRetriever` and parses the response as a `JsonWebKeySet`. The stock `OpenIdConnectConfigurationRetriever` targets the full OIDC discovery document, which `admin` does not publish — only the JWKS endpoint is exposed — so the minimal retriever is used.
|
||||
- `HttpDocumentRetriever { RequireHttps = true }` — non-HTTPS JWKS URLs are rejected at configuration time.
|
||||
|
||||
**Token validation parameters** (`TokenValidationParameters`):
|
||||
|
||||
| Parameter | Value |
|
||||
|-----------|-------|
|
||||
| `ValidateIssuer` | `true` |
|
||||
| `ValidIssuer` | `<resolved JWT_ISSUER>` |
|
||||
| `ValidateAudience` | `true` |
|
||||
| `ValidAudience` | `<resolved JWT_AUDIENCE>` |
|
||||
| `ValidateLifetime` | `true` |
|
||||
| `ValidateIssuerSigningKey` | `true` |
|
||||
| `ValidAlgorithms` | `[SecurityAlgorithms.EcdsaSha256]` |
|
||||
| `RequireSignedTokens` | `true` |
|
||||
| `RequireExpirationTime` | `true` |
|
||||
| `ClockSkew` | `TimeSpan.FromSeconds(30)` |
|
||||
| `IssuerSigningKeyResolver` | Delegate that fetches the cached `JsonWebKeySet` and returns the matching `kid`'s keys (or all keys if `kid` is empty) |
|
||||
|
||||
**Key Dependencies**:
|
||||
|
||||
| Library | Version | Purpose |
|
||||
|---------|---------|---------|
|
||||
| `Microsoft.AspNetCore.Authentication.JwtBearer` | 10.0.5 | JWT bearer middleware + handler |
|
||||
| `Microsoft.IdentityModel.Tokens` | (transitive) | `SymmetricSecurityKey`, `TokenValidationParameters` |
|
||||
| `Microsoft.IdentityModel.Protocols` | (transitive) | `ConfigurationManager<T>`, `HttpDocumentRetriever`, `IConfigurationRetriever<T>`, `IDocumentRetriever` |
|
||||
| `Microsoft.IdentityModel.Tokens` | (transitive) | `JsonWebKeySet`, `TokenValidationParameters`, `SecurityAlgorithms` |
|
||||
|
||||
## 7. Extensions and Helpers
|
||||
|
||||
None.
|
||||
- `JwksRetriever` — private nested class in `JwtExtensions.cs`. Minimal `IConfigurationRetriever<JsonWebKeySet>` implementation; ~5 lines. Exists because Microsoft does not ship a JWKS-only retriever.
|
||||
|
||||
## 8. Caveats & Edge Cases
|
||||
|
||||
1. **Shared-secret trust model** -- any service that knows `JWT_SECRET` can mint tokens this API will accept. Not safe for multi-tenant or third-party token issuance. Consistent with the rest of the suite; tightening this is suite-wide work, not a per-service decision.
|
||||
2. **No claim type for "user id" is consumed** -- only the `permissions` claim is checked. Services don't know who is calling them; per-user audit trails / business rules cannot be enforced at the service layer today. When a future feature needs an "applied by" attribution this gap will need to close.
|
||||
3. **No offline-grace-window logic in this service** -- `../../../suite/_docs/10_auth.md` describes an offline JWT cache; that lives in the UI / `admin` consumption pattern, not here.
|
||||
4. **Hardcoded fallback secret** in `Program.cs` (`"development-secret-key-min-32-chars!!"`) is dev-only. Production deployments MUST set `JWT_SECRET`.
|
||||
5. **`FL` permission code carries the legacy "Flight" name even after the service rename to `missions`.** The plan documents this explicitly: changing the permission code is a fleet-wide auth change (would break every issued token until new ones are minted) and is **NOT** in this Epic's scope. Tracked as a TODO in `../../../suite/_docs/00_roles_permissions.md`.
|
||||
1. **`admin` reachability at startup** — the first protected request blocks on the JWKS fetch. If `admin` is unreachable when that fetch happens, the request fails with a 500 (the `IssuerSigningKeyResolver` delegate throws while resolving signing keys). On the local LAN this is single-digit ms typical. Once cached, subsequent requests do not call `admin`.
|
||||
2. **No claim type for "user id" is consumed** — only the `permissions` claim is checked. Services don't know who is calling them; per-user audit trails / business rules cannot be enforced at the service layer today. When a future feature needs an "applied by" attribution this gap will need to close.
|
||||
3. **No offline-grace-window logic in this service** — `../../../suite/_docs/10_auth.md` describes an offline JWT cache; that lives in the UI / `admin` consumption pattern, not here.
|
||||
4. **Fail-fast on missing configuration**: `JWT_ISSUER`, `JWT_AUDIENCE`, `JWT_JWKS_URL` are all required at startup. A production deploy without any of them throws `InvalidOperationException` from `ConfigurationResolver.ResolveRequiredOrThrow` before the host is built. There is **no hardcoded fallback** (ADR-005's "dev-fallback secret" branch is obsolete for JWT).
|
||||
5. **JWKS rotation does NOT require a coordinated redeploy** — when `admin` rotates keys, the next refresh tick on every consumer's `ConfigurationManager` picks up the new public key. Old tokens signed by the previous key remain valid until expiry as long as the old `kid` is still published. This is the major operational improvement over the legacy HS256 shared-secret model.
|
||||
6. **Algorithm pin (`ValidAlgorithms = [EcdsaSha256]`)** prevents the classic "HS256 confusion" attack — without the pin, an attacker who learned the JWKS public key could forge `alg: HS256` tokens using the public key as the HMAC secret. The pin forces ECDSA regardless of the token header's `alg` claim.
|
||||
7. **`FL` permission code carries the legacy "Flight" name even after the service rename to `missions`.** The plan documents this explicitly: changing the permission code is a fleet-wide auth change (would break every issued token until new ones are minted) and is **NOT** in this Epic's scope. Tracked as a TODO in `../../../suite/_docs/00_roles_permissions.md`.
|
||||
|
||||
## 9. Dependency Graph
|
||||
|
||||
**Must be implemented after**: nothing.
|
||||
**Must be implemented after**: `Infrastructure/ConfigurationResolver.cs` (the fail-fast resolver — shared with `07_host`).
|
||||
|
||||
**Can be implemented in parallel with**: `04_persistence`, `06_http_conventions`.
|
||||
|
||||
@@ -99,4 +136,4 @@ None.
|
||||
|
||||
## 10. Logging Strategy
|
||||
|
||||
ASP.NET Core's JwtBearer handler logs token validation outcomes at default levels (Information / Debug). Not customized.
|
||||
ASP.NET Core's JwtBearer handler logs token validation outcomes at default levels (Information / Debug). Not customized. The custom `JwksRetriever` does not emit logs of its own; the `ConfigurationManager<JsonWebKeySet>` may log refresh failures at Warning per its built-in instrumentation.
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# 07 — Host (Composition Root)
|
||||
|
||||
**Spec source**: `../../../suite/_docs/00_top_level_architecture.md` § Edge compose excerpt -- confirms the env vars (`DATABASE_URL`, `JWT_SECRET`), port (`5002:8080`), and DB target (`postgres-local`).
|
||||
**Spec source**: `../../../suite/_docs/00_top_level_architecture.md` § Edge compose excerpt — confirms the port (`5002:8080`) and DB target (`postgres-local`). **The env-var contract in suite docs still references the legacy `JWT_SECRET`** and predates this service's transition to JWKS-based JWT validation; the four-variable env contract documented below is the verified current state in code, and the suite docs are flagged for sync in `_docs/02_document/05_drift_findings_2026-05-14.md`.
|
||||
|
||||
**Implementation status**: ✅ implemented.
|
||||
|
||||
> **NOTE (forward-looking)**: post-rename. Today's source has `Azaion.Flights` namespace + `dotnet Azaion.Flights.dll` entrypoint + container image `azaion/flights:*-arm`. Renames + DLL/image/compose changes tracked under Jira AZ-EPIC children B5 (namespace), B10 (Dockerfile + Woodpecker + suite compose).
|
||||
|
||||
**Files**: `Program.cs`, `GlobalUsings.cs`
|
||||
**Files**: `Program.cs`, `GlobalUsings.cs`, `Infrastructure/ConfigurationResolver.cs`, `Infrastructure/CorsConfigurationValidator.cs`
|
||||
|
||||
## 1. High-Level Overview
|
||||
|
||||
@@ -50,9 +50,26 @@ None. The host has no exported types -- its surface is the running HTTP server.
|
||||
|
||||
**Error Handling**: Delegated to `06_http_conventions`' middleware, placed FIRST in the pipeline so it wraps everything else.
|
||||
|
||||
**Configuration**: Reads `DATABASE_URL` and `JWT_SECRET` from `IConfiguration` -> `Environment.GetEnvironmentVariable` -> hardcoded dev fallback. Both fallbacks are dev-only and MUST be overridden in production.
|
||||
**Configuration**: All required values flow through `Infrastructure/ConfigurationResolver.cs` → `ResolveRequiredOrThrow`. Resolution order per value: `Environment.GetEnvironmentVariable(envVar)` → `IConfiguration[configKey]` → throws `InvalidOperationException` at startup with a message naming both the env var and the config key. There are **no hardcoded dev fallbacks**; a misconfigured production deploy cannot silently boot.
|
||||
|
||||
**`ConvertPostgresUrl` helper**: ad-hoc parser converting `postgresql://user[:pass]@host[:port]/db` to Npgsql key=value form. Does not URL-decode user/password -- caveat for credentials with `@`, `:`, `/`, `%`.
|
||||
| Env var | Config key | Required? | Purpose |
|
||||
|---------|------------|-----------|---------|
|
||||
| `DATABASE_URL` | `Database:Url` | **Yes** | Either Npgsql key=value form OR a `postgresql://` URI (converted via `ConvertPostgresUrl`) |
|
||||
| `JWT_ISSUER` | `Jwt:Issuer` | **Yes** | Expected `iss` claim value (see `05_identity`) |
|
||||
| `JWT_AUDIENCE` | `Jwt:Audience` | **Yes** | Expected `aud` claim value (see `05_identity`) |
|
||||
| `JWT_JWKS_URL` | `Jwt:JwksUrl` | **Yes** | HTTPS URL of admin's JWKS endpoint (see `05_identity`) |
|
||||
| `CorsConfig:AllowedOrigins` | (same) | No (defaults to `[]`) | String array of allowed origins for the CORS policy |
|
||||
| `CorsConfig:AllowAnyOrigin` | (same) | No (defaults to `false`) | When `true`, applies `AllowAnyOrigin/Method/Header` regardless of origins |
|
||||
|
||||
The legacy `JWT_SECRET` env var is **no longer consulted**; `05_identity` documents the JWKS-based replacement.
|
||||
|
||||
**CORS gating** (`Infrastructure/CorsConfigurationValidator.cs`):
|
||||
|
||||
- `EnsureSafeForEnvironment(origins, allowAnyOrigin, environmentName)` THROWS `InvalidOperationException` in `Production` (case-insensitive match on the `ASPNETCORE_ENVIRONMENT` value) when origins are empty AND `allowAnyOrigin` is `false`. The host refuses to start with an implicit permissive policy in Production.
|
||||
- `ShouldUsePermissivePolicy(origins, allowAnyOrigin)` returns `true` when `allowAnyOrigin == true` OR origins is empty — used by the CORS policy builder. In non-Production environments with empty origins this falls back to permissive.
|
||||
- `ShouldWarnAboutPermissiveDefault(origins, allowAnyOrigin)` is `true` when origins are empty AND `allowAnyOrigin` is `false` (implicit permissive). When true, the host logs `PermissiveDefaultWarning` at startup with the current environment name.
|
||||
|
||||
**`ConvertPostgresUrl` helper**: ad-hoc parser converting `postgresql://user[:pass]@host[:port]/db` to Npgsql key=value form. Does not URL-decode user/password — caveat for credentials with `@`, `:`, `/`, `%`.
|
||||
|
||||
## 6. Extensions and Helpers
|
||||
|
||||
@@ -60,10 +77,11 @@ None. The host has no exported types -- its surface is the running HTTP server.
|
||||
|
||||
## 7. Caveats & Edge Cases
|
||||
|
||||
- **No environment guards**: Swagger and the dev fallbacks for secrets are NOT gated on `IsDevelopment()`. If `JWT_SECRET` is unset in production, the service silently runs with the well-known development secret.
|
||||
- **CORS open by default**: `AllowAnyOrigin/Method/Header` applied unconditionally. Spec doesn't mandate a CORS policy -- likely safe behind suite's reverse proxy on edge, but worth confirming.
|
||||
- **Swagger is unconditional**: Swagger UI + JSON spec are mounted regardless of environment (no `IsDevelopment()` guard). This is the **only remaining** aspect of ADR-005 that still applies — the legacy "dev-fallback secret" aspect of ADR-005 is now obsolete (`ConfigurationResolver.ResolveRequiredOrThrow` throws on any missing value at startup).
|
||||
- **CORS hard-fail is `Production`-only**. In `Staging` or any custom environment name that is not literal `Production` (case-insensitive), an empty allow-list with `AllowAnyOrigin=false` falls back to permissive (with a startup warning) instead of throwing. Operators deploying to a "Staging" tier that should be locked down need to set `CorsConfig:AllowedOrigins` explicitly — the validator will not enforce it for them.
|
||||
- **JWKS startup dependency**: the first protected request after process start triggers a synchronous HTTPS fetch to `JWT_JWKS_URL`. If `admin` is unreachable at that moment, the request fails 500 from `05_identity`'s `IssuerSigningKeyResolver`. Once cached, request-path validation does not call `admin`.
|
||||
- **Migrator failure crashes the process** at startup. Container orchestrator (Watchtower-restarted Docker) is expected to bring it back; `flight-gate` (per `../../../suite/_docs/00_top_level_architecture.md`) ensures this doesn't happen mid-mission.
|
||||
- **No HTTPS redirection** middleware; assumes a TLS-terminating reverse proxy upstream (Caddy fronting Gitea is documented but in-deployment TLS termination is environment-specific).
|
||||
- **No HTTPS redirection** middleware; assumes a TLS-terminating reverse proxy upstream (Caddy fronting Gitea is documented but in-deployment TLS termination is environment-specific). Note: `JWT_JWKS_URL` is independently constrained to HTTPS by `HttpDocumentRetriever { RequireHttps = true }` inside `05_identity`.
|
||||
- **Port 8080** matches the Dockerfile `EXPOSE 8080` and edge compose `5002:8080` mapping per `../../../suite/_docs/00_top_level_architecture.md` excerpt.
|
||||
- **No GPS-Denied service registration** here. Earlier drafts of this doc reserved a slot for a GPS-Denied feature component; per Jira AZ-EPIC child B7, GPS-Denied lives in a separate (out-of-this-repo) service, so this host registers only `VehicleService`, `MissionService`, `WaypointService`.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user