mirror of
https://github.com/azaion/missions.git
synced 2026-06-22 18:41:07 +00:00
[AZ-581] [AZ-582] [AZ-583] [AZ-584] Sec+Res NFT tests
Batch 3 of test implementation cycle 1 (existing-code Step 6). - AZ-581 AuthClaimsTests: NFT-SEC-01..06+04b (foreign-keypair, byte-flip, 30s skew, iss/aud/perms, multi-value permissions array). - AZ-582 CrossCutting/ErrorRedaction/JwksRotation/StartupConfig/CorsConfig: NFT-SEC-07..13 (alg pin, kid rotation grace window, env fail-fast, CORS Production gate). - AZ-583 CascadeF3/CascadeF4/MigratorRestart: NFT-RES-01..04. CascadeF4 pins current walk-order divergence with carry_forward AC-4.6. - AZ-584 ConfigDbStartup/JwksRotationNoRestart/DefaultVehicleRace: NFT-RES-05..08. NFT-RES-08 pins current behaviour (unique-index closes the race) with carry_forward AC-1.4. Mock contract: SignBody accepts permissions OR permissions_array (mutually exclusive). TokenSigner validates kid_override against published keys so NFT-SEC-11 can assert "mock refuses old kid post-grace". Helpers added: ForeignKeypair (test-only ECDSA P-256), MissionsContainerHelper (docker-run wrapper for startup-time scenarios), DockerLogs. 7 of 22 new tests are Skippable, gated on COMPOSE_RESTART_ENABLED + docker CLI in the e2e-consumer image (explicit skip reason; no silent pass). Build green: test csproj + jwks-mock csproj. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -31,6 +31,25 @@ public sealed class TokenSigner
|
||||
var kid = request.KidOverride ?? active.Kid;
|
||||
var alg = request.AlgOverride ?? "ES256";
|
||||
|
||||
if (request.Permissions is not null && request.PermissionsArray is not null)
|
||||
throw new ArgumentException(
|
||||
"permissions and permissions_array are mutually exclusive — set at most one.",
|
||||
nameof(request));
|
||||
|
||||
// NFT-SEC-11 AC-5.4: the mock refuses kid_override values that don't
|
||||
// correspond to a currently-published kid (active or in-grace retired).
|
||||
// Without this guard, a tester could mint a token with any kid string
|
||||
// and the SUT would simply 401 on JWKS lookup — defeating the
|
||||
// "post-grace mock refuses old kid" assertion.
|
||||
if (request.KidOverride is not null)
|
||||
{
|
||||
var known = _keys.PublishedKeys().Select(k => k.Kid).ToHashSet(StringComparer.Ordinal);
|
||||
if (!known.Contains(request.KidOverride))
|
||||
throw new ArgumentException(
|
||||
$"kid_override '{request.KidOverride}' is not a currently-published kid.",
|
||||
nameof(request));
|
||||
}
|
||||
|
||||
var nowUnix = _clock.GetUtcNow().ToUnixTimeSeconds();
|
||||
var expUnix = nowUnix + (request.ExpOffsetSeconds ?? 3600);
|
||||
|
||||
@@ -50,6 +69,13 @@ public sealed class TokenSigner
|
||||
};
|
||||
if (request.Permissions is not null)
|
||||
payload["permissions"] = request.Permissions;
|
||||
if (request.PermissionsArray is not null)
|
||||
{
|
||||
var arr = new JsonArray();
|
||||
foreach (var p in request.PermissionsArray)
|
||||
arr.Add(p);
|
||||
payload["permissions"] = arr;
|
||||
}
|
||||
if (request.Subject is not null)
|
||||
payload["sub"] = request.Subject;
|
||||
|
||||
@@ -95,6 +121,7 @@ public sealed record SignRequest(
|
||||
string? Audience,
|
||||
int? ExpOffsetSeconds,
|
||||
string? Permissions,
|
||||
string[]? PermissionsArray,
|
||||
string? Subject,
|
||||
string? AlgOverride,
|
||||
string? KidOverride);
|
||||
|
||||
Reference in New Issue
Block a user