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.
6.1 KiB
Module: Program (composition root) + GlobalUsings
Files (2): Program.cs, GlobalUsings.cs
NOTE (forward-looking): post-rename. Today's source has
Azaion.Flightsnamespace anddotnet Azaion.Flights.dllentrypoint. Renames + DLL/image changes tracked under Jira AZ-EPIC children B5 (namespace), B7 (drop GPS policy), B10 (Dockerfile + docker image rename).
Purpose
Top-level statements that build the ASP.NET Core web host: read environment, register DI services (DB connection, services, auth, CORS, MVC, Swagger), run the migrator once, then app.Run().
GlobalUsings.cs adds three project-wide global using directives so individual files don't need to repeat them:
global using LinqToDB;
global using LinqToDB.Async;
global using LinqToDB.Data;
Public Interface
Program.cs is a top-level program -- it is not a class with a public surface. Its observable contract is the resulting HTTP server:
- Listens on the Kestrel-default URL (typically
http://0.0.0.0:8080in container per DockerfileEXPOSE 8080). - Exposes routes mapped by
MapControllers(seecontroller_vehicles.md,controller_missions.md) plusGET /health. - Serves Swagger UI at the default
/swaggerroute (not gated on environment).
Internal Logic
1. WebApplicationBuilder = WebApplication.CreateBuilder(args)
2. Resolve DATABASE_URL (Configuration -> Env -> fallback)
If it begins with "postgresql://" -> ConvertPostgresUrl() to Npgsql key=value form.
3. Resolve JWT_SECRET (Configuration -> Env -> fallback)
4. Register services (scoped where applicable):
- AppDataConnection <- scoped, built via new DataOptions().UsePostgreSQL(connectionString)
- MissionService, WaypointService, VehicleService <- scoped
- AddJwtAuth(jwtSecret) -> JWT bearer + "FL" policy
- AddCors with default policy = AllowAnyOrigin/Method/Header
- AddControllers, AddEndpointsApiExplorer, AddSwaggerGen
5. Build the WebApplication.
6. Open a temp scope, resolve AppDataConnection, call DatabaseMigrator.Migrate(db).
7. Configure pipeline (order matters):
a. UseMiddleware<ErrorHandlingMiddleware>
b. UseCors
c. UseAuthentication
d. UseAuthorization
e. UseSwagger, UseSwaggerUI
f. MapControllers
g. MapGet("/health", () => Results.Ok({status:"healthy"}))
8. app.Run()
ConvertPostgresUrl(url):
parses postgresql://user[:pass]@host[:port]/db into
"Host={host};Port={port};Database={db};Username={user};Password={pass}"
(defaults port to 5432; absent password becomes empty)
Dependencies
- All internal namespaces:
Azaion.Missions.{Auth, Database, Middleware, Services}. - ASP.NET Core, LinqToDB, Npgsql, Swashbuckle, JWT bearer (NuGet).
Consumers
- The container runtime (
ENTRYPOINT ["dotnet", "Azaion.Missions.dll"]inDockerfileafter B10). dotnet runfor local development.
Configuration
| Env / Config Key | Required? | Default |
|---|---|---|
DATABASE_URL |
No (has dev fallback) | Host=localhost;Database=azaion;Username=postgres;Password=changeme |
JWT_SECRET |
No (has dev fallback) | development-secret-key-min-32-chars!! |
AZAION_REVISION |
Set by Dockerfile from CI_COMMIT_SHA |
unknown (build arg default) |
There is no appsettings.json in this repo (per discovery) -- config comes from env / process variables only. Suite-wide env conventions live in ../../suite/_docs/00_top_level_architecture.md (Edge compose excerpt).
External Integrations
- PostgreSQL (read/write) via Npgsql.
- Identity provider: the suite's
adminservice mints JWTs against the central user PostgreSQL;JWT_SECRETis the shared HMAC secret. Local validation only -- no network round-trip per request.
Security
- Hardcoded fallbacks for both
DATABASE_URLandJWT_SECRETare dev-only. Production deployments MUST override them; failure to do so silently runs with weak/known credentials. - CORS is permissive in all environments (
AllowAnyOrigin/Method/Header). Combined with JWT auth this is not catastrophic (browser will send the bearer token only if the front-end opts in), but exposes the API to opportunistic browser-based scraping. - Swagger is unconditionally enabled -- both the JSON document and the UI are served regardless of environment. Anyone reaching the host can enumerate the API surface.
- No HTTPS redirection middleware (
UseHttpsRedirection) -- TLS is assumed to terminate at an upstream reverse proxy. app.UseMiddleware<ErrorHandlingMiddleware>runs beforeUseAuthentication/UseAuthorization-- auth failures still emit the framework's stock 401/403 (which is fine), but any auth-stage exceptions ALSO run through the global handler (which convertsKeyNotFoundException-> 404, etc.; auth pipeline doesn't typically throw those).
Tests
None present.
Notes / Smells
DATABASE_URLURL parsing:ConvertPostgresUrlis a small ad-hoc parser. Fine for typical cases but does not URL-decode the user/password. A password containing@,:,/,%would break parsing or be interpreted wrong. Carry to verification log.- No
IsDevelopment()checks anywhere inProgram.cs. Dev/prod behaviors (Swagger, fallback secrets) are not gated. AddSwaggerGen()with no JWT bearer security definition -- Swagger UI's "Authorize" button won't appear; users must supply tokens viacurl -H "Authorization: Bearer ...". Not a bug, but a usability issue.DatabaseMigrator.Migrateis fire-and-forget -- if it throws (DB down at startup), the host process crashes. Acceptable for container orchestration that restarts on failure.GlobalUsings.csimportsLinqToDB.Asyncbut most async LINQ extensions used by the project (AnyAsync,FirstOrDefaultAsync,ToListAsync, etc.) actually live in theLinqToDBnamespace already. Harmless redundancy.- Service lifetime:
AppDataConnectionis scoped (per-HTTP-request) -- correct, becauseDataConnectionholds a backing Npgsql connection that should not be shared across requests. The three domain services share this scope, so all DB calls within one request go through the same physical connection (good for correctness, no implicit transactions though).