Skip to content

Commit 6b808f9

Browse files
committed
refactor: replace specVersions list with introducedIn/removedIn range tagging
Replaces per-scenario `specVersions: SpecVersion[]` arrays with `introducedIn` and optional `removedIn` range fields on all three scenario interfaces. Extension scenarios get an orthogonal `extension?: boolean` flag instead of the former `'extension'` tag in the versions list. matchesSpecVersion() is rewritten as a range comparison (introducedIn <= target && (!removedIn || target < removedIn)), with draft sorting after all dated versions. getScenarioSpecVersions() reconstructs the effective version list from the range for backward-compat with tier-check. Closes #256.
1 parent 17f1f93 commit 6b808f9

29 files changed

Lines changed: 215 additions & 140 deletions

src/scenarios/authorization-server/authorization-server-metadata.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@
44
import {
55
ClientScenarioForAuthorizationServer,
66
ConformanceCheck,
7-
SpecVersion
7+
DatedSpecVersion
88
} from '../../types';
99
import { request } from 'undici';
1010

1111
type Status = 'SUCCESS' | 'FAILURE';
1212

1313
export class AuthorizationServerMetadataEndpointScenario implements ClientScenarioForAuthorizationServer {
1414
name = 'authorization-server-metadata-endpoint';
15-
specVersions: SpecVersion[] = ['2025-03-26', '2025-06-18', '2025-11-25'];
15+
introducedIn: DatedSpecVersion = '2025-03-26';
1616
description = `Test authorization server metadata endpoint.
1717
1818
**Authorization Server Implementation Requirements:**

src/scenarios/client/auth/basic-cimd.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { Scenario, ConformanceCheck } from '../../../types';
2-
import { ScenarioUrls, SpecVersion } from '../../../types';
2+
import { ScenarioUrls, DatedSpecVersion } from '../../../types';
33
import { createAuthServer } from './helpers/createAuthServer';
44
import { createServer } from './helpers/createServer';
55
import { ServerLifecycle } from './helpers/serverLifecycle';
@@ -22,7 +22,7 @@ export const CIMD_CLIENT_METADATA_URL =
2222
*/
2323
export class AuthBasicCIMDScenario implements Scenario {
2424
name = 'auth/basic-cimd';
25-
specVersions: SpecVersion[] = ['2025-11-25'];
25+
introducedIn: DatedSpecVersion = '2025-11-25';
2626
description =
2727
'Tests OAuth flow with Client ID Metadata Documents (SEP-991/URL-based client IDs). Server advertises client_id_metadata_document_supported=true and client should use URL as client_id instead of DCR.';
2828
private authServer = new ServerLifecycle();

src/scenarios/client/auth/client-credentials.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ import type {
44
Scenario,
55
ConformanceCheck,
66
ScenarioUrls,
7-
ScenarioSpecTag
7+
SpecVersion
88
} from '../../../types';
9+
import { LATEST_SPEC_VERSION } from '../../../types';
910
import { createAuthServer } from './helpers/createAuthServer';
1011
import { createServer } from './helpers/createServer';
1112
import { ServerLifecycle } from './helpers/serverLifecycle';
@@ -37,7 +38,8 @@ async function generateTestKeypair(): Promise<{
3738
*/
3839
export class ClientCredentialsJwtScenario implements Scenario {
3940
name = 'auth/client-credentials-jwt';
40-
specVersions: ScenarioSpecTag[] = ['extension'];
41+
extension = true;
42+
introducedIn: SpecVersion = LATEST_SPEC_VERSION;
4143
description =
4244
'Tests OAuth client_credentials flow with private_key_jwt authentication (SEP-1046)';
4345

@@ -256,7 +258,8 @@ export class ClientCredentialsJwtScenario implements Scenario {
256258
*/
257259
export class ClientCredentialsBasicScenario implements Scenario {
258260
name = 'auth/client-credentials-basic';
259-
specVersions: ScenarioSpecTag[] = ['extension'];
261+
extension = true;
262+
introducedIn: SpecVersion = LATEST_SPEC_VERSION;
260263
description =
261264
'Tests OAuth client_credentials flow with client_secret_basic authentication';
262265

src/scenarios/client/auth/cross-app-access.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@ import type {
55
Scenario,
66
ConformanceCheck,
77
ScenarioUrls,
8-
ScenarioSpecTag
8+
SpecVersion
99
} from '../../../types';
10+
import { LATEST_SPEC_VERSION } from '../../../types';
1011
import { createAuthServer } from './helpers/createAuthServer';
1112
import { createServer } from './helpers/createServer';
1213
import { MockTokenVerifier } from './helpers/mockTokenVerifier';
@@ -60,7 +61,8 @@ async function createIdpIdToken(
6061
*/
6162
export class CrossAppAccessCompleteFlowScenario implements Scenario {
6263
name = 'auth/cross-app-access-complete-flow';
63-
specVersions: ScenarioSpecTag[] = ['extension'];
64+
extension = true;
65+
introducedIn: SpecVersion = LATEST_SPEC_VERSION;
6466
description =
6567
'Tests complete SEP-990 flow: token exchange + JWT bearer grant (Enterprise Managed OAuth)';
6668

src/scenarios/client/auth/discovery-metadata.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*/
88

99
import type { Scenario, ConformanceCheck } from '../../../types';
10-
import { ScenarioUrls } from '../../../types';
10+
import { ScenarioUrls, DatedSpecVersion } from '../../../types';
1111
import { createAuthServer } from './helpers/createAuthServer';
1212
import { createServer } from './helpers/createServer';
1313
import { ServerLifecycle } from './helpers/serverLifecycle';
@@ -87,7 +87,7 @@ function createMetadataScenario(config: MetadataScenarioConfig): Scenario {
8787

8888
return {
8989
name: `auth/${config.name}`,
90-
specVersions: ['2025-11-25'],
90+
introducedIn: '2025-11-25' as DatedSpecVersion,
9191
description: `Tests Basic OAuth metadata discovery flow.
9292
9393
**PRM:** ${config.prmLocation}${config.inWwwAuth ? '' : ' (not in WWW-Authenticate)'}

src/scenarios/client/auth/march-spec-backcompat.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { Scenario, ConformanceCheck } from '../../../types';
2-
import { ScenarioUrls, SpecVersion } from '../../../types';
2+
import { ScenarioUrls, DatedSpecVersion } from '../../../types';
33
import { createAuthServer } from './helpers/createAuthServer';
44
import { createServer } from './helpers/createServer';
55
import { ServerLifecycle } from './helpers/serverLifecycle';
@@ -8,7 +8,8 @@ import { SpecReferences } from './spec-references';
88

99
export class Auth20250326OAuthMetadataBackcompatScenario implements Scenario {
1010
name = 'auth/2025-03-26-oauth-metadata-backcompat';
11-
specVersions: SpecVersion[] = ['2025-03-26'];
11+
introducedIn: DatedSpecVersion = '2025-03-26';
12+
removedIn: DatedSpecVersion = '2025-06-18';
1213
description =
1314
'Tests 2025-03-26 spec OAuth flow: no PRM (Protected Resource Metadata), OAuth metadata at root location';
1415
private server = new ServerLifecycle();
@@ -69,7 +70,8 @@ export class Auth20250326OAuthMetadataBackcompatScenario implements Scenario {
6970

7071
export class Auth20250326OEndpointFallbackScenario implements Scenario {
7172
name = 'auth/2025-03-26-oauth-endpoint-fallback';
72-
specVersions: SpecVersion[] = ['2025-03-26'];
73+
introducedIn: DatedSpecVersion = '2025-03-26';
74+
removedIn: DatedSpecVersion = '2025-06-18';
7375
description =
7476
'Tests OAuth flow with no metadata endpoints, relying on fallback to standard OAuth endpoints at server root (2025-03-26 spec behavior)';
7577
private server = new ServerLifecycle();

src/scenarios/client/auth/offline-access.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import { MockTokenVerifier } from './helpers/mockTokenVerifier';
2727
*/
2828
export class OfflineAccessScopeScenario implements Scenario {
2929
name = 'auth/offline-access-scope';
30-
specVersions: SpecVersion[] = [DRAFT_PROTOCOL_VERSION];
30+
introducedIn: SpecVersion = DRAFT_PROTOCOL_VERSION;
3131
description =
3232
'Tests that a client that wants a refresh token handles offline_access scope and refresh_token grant type when AS supports them (SEP-2207)';
3333

@@ -231,7 +231,7 @@ export class OfflineAccessScopeScenario implements Scenario {
231231
*/
232232
export class OfflineAccessNotSupportedScenario implements Scenario {
233233
name = 'auth/offline-access-not-supported';
234-
specVersions: SpecVersion[] = [DRAFT_PROTOCOL_VERSION];
234+
introducedIn: SpecVersion = DRAFT_PROTOCOL_VERSION;
235235
description =
236236
'Tests that client does not request offline_access when AS does not list it in scopes_supported (SEP-2207)';
237237

src/scenarios/client/auth/pre-registration.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type {
22
Scenario,
33
ConformanceCheck,
44
ScenarioUrls,
5-
SpecVersion
5+
DatedSpecVersion
66
} from '../../../types';
77
import { createAuthServer } from './helpers/createAuthServer';
88
import { createServer } from './helpers/createServer';
@@ -24,7 +24,7 @@ const PRE_REGISTERED_CLIENT_SECRET = 'pre-registered-secret';
2424
*/
2525
export class PreRegistrationScenario implements Scenario {
2626
name = 'auth/pre-registration';
27-
specVersions: SpecVersion[] = ['2025-11-25'];
27+
introducedIn: DatedSpecVersion = '2025-11-25';
2828
description =
2929
'Tests OAuth flow with pre-registered client credentials. Server does not support DCR.';
3030

src/scenarios/client/auth/resource-mismatch.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import { MockTokenVerifier } from './helpers/mockTokenVerifier.js';
3131
*/
3232
export class ResourceMismatchScenario implements Scenario {
3333
name = 'auth/resource-mismatch';
34-
specVersions: SpecVersion[] = [DRAFT_PROTOCOL_VERSION];
34+
introducedIn: SpecVersion = DRAFT_PROTOCOL_VERSION;
3535
description =
3636
'Tests that client rejects when PRM resource does not match server URL';
3737
allowClientError = true;

src/scenarios/client/auth/scope-handling.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { Scenario, ConformanceCheck } from '../../../types';
2-
import { ScenarioUrls, SpecVersion } from '../../../types';
2+
import { ScenarioUrls, DatedSpecVersion } from '../../../types';
33
import { createAuthServer } from './helpers/createAuthServer';
44
import { createServer } from './helpers/createServer';
55
import { ServerLifecycle } from './helpers/serverLifecycle';
@@ -15,7 +15,7 @@ import type { Request, Response, NextFunction } from 'express';
1515
*/
1616
export class ScopeFromWwwAuthenticateScenario implements Scenario {
1717
name = 'auth/scope-from-www-authenticate';
18-
specVersions: SpecVersion[] = ['2025-11-25'];
18+
introducedIn: DatedSpecVersion = '2025-11-25';
1919
description =
2020
'Tests that client uses scope parameter from WWW-Authenticate header when provided';
2121
private authServer = new ServerLifecycle();
@@ -101,7 +101,7 @@ export class ScopeFromWwwAuthenticateScenario implements Scenario {
101101
*/
102102
export class ScopeFromScopesSupportedScenario implements Scenario {
103103
name = 'auth/scope-from-scopes-supported';
104-
specVersions: SpecVersion[] = ['2025-11-25'];
104+
introducedIn: DatedSpecVersion = '2025-11-25';
105105
description =
106106
'Tests that client uses all scopes from scopes_supported when scope not in WWW-Authenticate header';
107107
private authServer = new ServerLifecycle();
@@ -197,7 +197,7 @@ export class ScopeFromScopesSupportedScenario implements Scenario {
197197
*/
198198
export class ScopeOmittedWhenUndefinedScenario implements Scenario {
199199
name = 'auth/scope-omitted-when-undefined';
200-
specVersions: SpecVersion[] = ['2025-11-25'];
200+
introducedIn: DatedSpecVersion = '2025-11-25';
201201
description =
202202
'Tests that client omits scope parameter when scopes_supported is undefined';
203203
private authServer = new ServerLifecycle();
@@ -284,7 +284,7 @@ export class ScopeOmittedWhenUndefinedScenario implements Scenario {
284284
*/
285285
export class ScopeStepUpAuthScenario implements Scenario {
286286
name = 'auth/scope-step-up';
287-
specVersions: SpecVersion[] = ['2025-11-25'];
287+
introducedIn: DatedSpecVersion = '2025-11-25';
288288
description =
289289
'Tests that client handles step-up authentication with different scope requirements per operation';
290290
private authServer = new ServerLifecycle();
@@ -481,7 +481,7 @@ export class ScopeStepUpAuthScenario implements Scenario {
481481
*/
482482
export class ScopeRetryLimitScenario implements Scenario {
483483
name = 'auth/scope-retry-limit';
484-
specVersions: SpecVersion[] = ['2025-11-25'];
484+
introducedIn: DatedSpecVersion = '2025-11-25';
485485
description =
486486
'Tests that client implements retry limits to prevent infinite authorization loops on repeated 403 responses';
487487
allowClientError = true;

0 commit comments

Comments
 (0)