Option B per user decision: production ships with empty Jwt.Issuer / Jwt.Audience in appsettings.json so the API process refuses to start unless JWT_ISSUER + JWT_AUDIENCE env vars are supplied. Development ships with grep-friendly DEV-ONLY- placeholders so local + docker flows keep working unchanged. AuthenticationServiceCollectionExtensions flips ValidateIssuer + ValidateAudience to true and wires ValidIssuer / ValidAudience via a new ResolveRequiredOrThrow helper that all three required values (secret, iss, aud) now share. JwtTokenFactory.Create + CreateExpired gain optional iss / aud parameters (default null) so existing call sites compile unchanged. JwtTestHelpers adds MintAuthenticated / MintExpired wrappers that resolve iss + aud from env, plus ResolveIssuerOrThrow / ResolveAudienceOrThrow. PerfBootstrap.MintToken + Program.cs JWT bootstrap migrated to the new surface so the perf harness and the integration runner both validate against the same contract. Adds 4 fail-fast unit tests (missing/empty issuer + audience), 2 negative integration scenarios (WrongIssuer_Returns401, WrongAudience_Returns401), and re-tags every existing integration mint site via MintAuthenticated. Compose, .env.example, run-tests.sh, run-performance-tests.sh all load + export JWT_ISSUER + JWT_AUDIENCE alongside JWT_SECRET. Resolves F-AUTH-2 (security_report.md + owasp_review.md). AC-7 (cross-repo suite/_docs/10_auth.md write) deferred — outside this workspace; tracked in deploy_cycle2.md R3 follow-up. Co-authored-by: Cursor <cursoragent@cursor.com>
5.1 KiB
Module: Tests/SatelliteProvider.Tests
Purpose
Unit test project for component-internal logic. Original AZ-2/AZ-3 era had only a placeholder dummy; the suite has since grown across the AZ-285..AZ-380 baseline + cycle 1 (AZ-484) + cycle 2 (AZ-487, AZ-488) tracks. The "dummy test only" note in older revisions of this file is obsolete — the project now hosts the full unit suite executed by scripts/run-tests.sh --unit-only and CI's 01-test.yml.
Public Interface (test classes)
Existing baseline (pre-cycle-2) test classes cover TileService, RegionService, RouteService, geo math, repositories, validators, idempotency, and migration helpers — not enumerated exhaustively here. Cycle-2 additions:
AZ-487 — JWT validation baseline
Authentication/AuthenticationServiceCollectionExtensionsTests—AddSatelliteJwt_RegistersJwtBearerScheme,AddSatelliteJwt_ThrowsOnMissingSecret,AddSatelliteJwt_ThrowsOnShortSecret.Authentication/JwtTokenFactoryTests—Create_ProducesTokenValidatedByMatchingParameters,CreateExpired_TokenFailsValidationWithLifetimeException,Create_WithExtraClaims_PropagatesClaimsThroughValidation,TamperSignature_TokenFailsValidationWithSignatureException.Authentication/AuthenticationServiceCollectionExtensionsTests— coversAddSatelliteJwtregistration +TokenValidationParametersshape (AZ-487, AZ-494). Includes AZ-494's fail-fast assertions:AddSatelliteJwt_ThrowsOnMissingIssuer,AddSatelliteJwt_ThrowsOnEmptyIssuer,AddSatelliteJwt_ThrowsOnMissingAudience,AddSatelliteJwt_ThrowsOnEmptyAudience, plus the updated_ConfiguresTokenValidationParameters_AsPerContractand_PrefersEnvironmentVariableOverConfigurationcases that assertValidateIssuer = true+ValidIssuer+ValidateAudience = true+ValidAudience.TestUtilities/JwtTokenFactory— helper that mints HS256 tokens with the sameTokenValidationParametersused in production. AdjustsnotBeforefor negative-lifetime requests soJwtSecurityTokenaccepts the value and downstream lifetime validation can fire (IDX12401workaround documented inline).
AZ-488 — UAV tile upload
UavTileQualityGateTests— one happy path + ≥ 1 reject path per rule (Rule 1 INVALID_FORMAT × 2, Rule 2 SIZE_OUT_OF_BAND × 2, Rule 3 WRONG_DIMENSIONS × 1, Rule 4 CAPTURED_AT_FUTURE / _TOO_OLD × 2, Rule 5 IMAGE_TOO_UNIFORM × 1) + rule-ordering determinism. Uses aFixedTimeProviderfor Rule-4 isolation andUavTileImageFactoryfor deterministic JPEG fixtures.UavTileUploadHandlerTests— end-to-end with a mockedITileRepository: 1-item happy path, 3-item mixed batch (file written +InsertAsynccalled only for accepted), per-source UPSERT pass-through.UavTileFilePathTests— verifiesBuildUavTileFilePathproducestiles/uav/{z}/{x}/{y}.jpgfor sample (z, x, y) tuples and that integer-typed coordinates make string-injection of path traversal impossible.Authentication/PermissionsRequirementTests—PermissionsAuthorizationHandlercorrectly accepts apermissionsclaim shaped as a single string OR as a JSON array, rejects when the requested permission is absent, and short-circuits when the principal has nopermissionsclaim at all.TestUtilities/UavTileImageFactory— programmatic JPEG factories used by the gate + handler tests:CreateValidJpeg(width, height, seed),CreateUniformJpeg,CreatePng(for Rule 1 negative path).
Internal Logic
- Tests follow Arrange / Act / Assert. Time-dependent paths inject a
FixedTimeProvider(cycle-2 addition) so Rule 4 has deterministic age windows. JwtSecurityTokenHandler.MapInboundClaims = falseis set explicitly in JWT tests so claims read by their original names (sub,permissions, …) rather than the framework-remapped names.
Dependencies
- Project references:
SatelliteProvider.Services.TileDownloader,SatelliteProvider.Services.RegionProcessing,SatelliteProvider.Services.RouteManagement,SatelliteProvider.Common,SatelliteProvider.DataAccess,SatelliteProvider.Api(for the Authentication tests — added in AZ-487),SatelliteProvider.TestSupport(added by AZ-491; provides the canonicalJwtTokenFactoryconsumed by both this project andSatelliteProvider.IntegrationTests). - NuGet: xUnit (2.5.3), Moq (4.20.72), FluentAssertions (8.8.0), coverlet.collector (6.0.0), Microsoft.NET.Test.Sdk (17.8.0), Microsoft.Extensions.* (Caching.Memory, Configuration, DI, Logging, Options, Http),
Microsoft.AspNetCore.Authentication.JwtBearer8.0.25 (consumed transitively via theProjectReferencetoSatelliteProvider.Api; AZ-487 added the dependency at 8.0.21, AZ-496 bumped it to 8.0.25),SixLabors.ImageSharp3.1.11 (added by AZ-488 for the gate tests). appsettings.jsoncopied to output (used by Authentication tests for theJwtsection binding scenario).
Consumers
- CI pipeline (
01-test.yml) andscripts/run-tests.sh --unit-onlyrundotnet testagainst this project.
Tests
This IS the test module. Cycle-2 added ~25 unit tests on top of the existing baseline; the full project executes in seconds (no external services required).