@ionite/ecv 0.0.23-beta.20260729.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +1035 -0
- package/dist/index.js +1 -0
- package/dist/runner.js +22 -0
- package/dist/shared/ecv-rcmx1a2s.js +15 -0
- package/package.json +44 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,1035 @@
|
|
|
1
|
+
import { ChildProcess } from "node:child_process";
|
|
2
|
+
/**
|
|
3
|
+
* Options controlling how readiness is polled.
|
|
4
|
+
*/
|
|
5
|
+
interface WaitForReadyOptions {
|
|
6
|
+
/**
|
|
7
|
+
* Readiness path appended to the base URL. When omitted it is derived from {@link basePath}.
|
|
8
|
+
* @default "`${basePath}/readyz`" (i.e. `/api/ionite/readyz`)
|
|
9
|
+
*/
|
|
10
|
+
readyPath?: string;
|
|
11
|
+
/**
|
|
12
|
+
* Base path the ionite app mounts the SDK handler under, used to derive {@link readyPath} when it is
|
|
13
|
+
* not given (ionite apps expose `${basePath}/readyz`). Ignored when `readyPath` is set explicitly.
|
|
14
|
+
* @default "/api/ionite"
|
|
15
|
+
*/
|
|
16
|
+
basePath?: string;
|
|
17
|
+
/**
|
|
18
|
+
* Optional liveness path checked before readiness (e.g. "/api/livez").
|
|
19
|
+
* When set, an attempt only succeeds if liveness is OK and readiness is OK.
|
|
20
|
+
*/
|
|
21
|
+
livenessPath?: string;
|
|
22
|
+
/**
|
|
23
|
+
* Maximum number of polling attempts.
|
|
24
|
+
* @default 30
|
|
25
|
+
*/
|
|
26
|
+
maxRetries?: number;
|
|
27
|
+
/**
|
|
28
|
+
* Delay between attempts in milliseconds.
|
|
29
|
+
* @default 1000
|
|
30
|
+
*/
|
|
31
|
+
retryDelayMs?: number;
|
|
32
|
+
/**
|
|
33
|
+
* Per-request abort timeout in milliseconds.
|
|
34
|
+
* @default 3000
|
|
35
|
+
*/
|
|
36
|
+
requestTimeoutMs?: number;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Poll an application until its readiness endpoint responds OK.
|
|
40
|
+
*/
|
|
41
|
+
declare function waitForReady(baseUrl: string, options?: WaitForReadyOptions): Promise<void>;
|
|
42
|
+
/**
|
|
43
|
+
* Options for {@link startAppUnderTest}.
|
|
44
|
+
*/
|
|
45
|
+
interface StartAppOptions extends WaitForReadyOptions {
|
|
46
|
+
/** Executable to run (e.g. "bun"). */
|
|
47
|
+
command: string;
|
|
48
|
+
/** Arguments passed to the command (e.g. ["run", "api"]). */
|
|
49
|
+
args?: string[];
|
|
50
|
+
/** Working directory for the spawned process. */
|
|
51
|
+
cwd?: string;
|
|
52
|
+
/**
|
|
53
|
+
* Environment variables merged on top of `process.env`.
|
|
54
|
+
* Pass `ecv.env` here so the app connects to the ECV mock server.
|
|
55
|
+
*/
|
|
56
|
+
env?: Record<string, string | undefined>;
|
|
57
|
+
/** Public base URL the app will be reachable at (used for readiness polling and returned to callers). */
|
|
58
|
+
baseUrl: string;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Handle for a spawned application under test.
|
|
62
|
+
*/
|
|
63
|
+
interface AppUnderTest {
|
|
64
|
+
/** Base URL the app is reachable at. */
|
|
65
|
+
baseUrl: string;
|
|
66
|
+
/** The spawned child process. */
|
|
67
|
+
process: ChildProcess;
|
|
68
|
+
/** Stop the app (SIGTERM, then SIGKILL fallback if it is still running). */
|
|
69
|
+
stop(): Promise<void>;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Spawn an application under test, wait for it to become ready, and return a handle with a `stop()`.
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```ts
|
|
76
|
+
* const ecv = await startEcvServer();
|
|
77
|
+
* const app = await startAppUnderTest({
|
|
78
|
+
* command: 'bun',
|
|
79
|
+
* args: ['run', 'api'],
|
|
80
|
+
* env: { ...ecv.env, APP_BASE_URL: 'http://localhost:3544' },
|
|
81
|
+
* baseUrl: 'http://localhost:3544',
|
|
82
|
+
* // readyPath defaults to `${basePath}/readyz` (i.e. /api/ionite/readyz); override basePath if needed.
|
|
83
|
+
* });
|
|
84
|
+
* // ...run tests against app.baseUrl...
|
|
85
|
+
* await app.stop();
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
88
|
+
declare function startAppUnderTest(options: StartAppOptions): Promise<AppUnderTest>;
|
|
89
|
+
import { EnterpriseExtension, Ionite } from "@ionite/server";
|
|
90
|
+
declare function setVaultRedisUrl(url: string | undefined): void;
|
|
91
|
+
declare function getVaultRedisUrl(): string | undefined;
|
|
92
|
+
interface EcvServerHandle {
|
|
93
|
+
baseUrl: string;
|
|
94
|
+
port: number;
|
|
95
|
+
host: string;
|
|
96
|
+
env: {
|
|
97
|
+
ION_CONFIG_TYPE: "vault";
|
|
98
|
+
ION_VAULT_URL: string;
|
|
99
|
+
ION_VAULT_TOKEN: string;
|
|
100
|
+
ION_VAULT_PATH: string;
|
|
101
|
+
REDIS_URL?: string;
|
|
102
|
+
};
|
|
103
|
+
/**
|
|
104
|
+
* Narrow tenant config-locator pointer for seeding tenant rows / tenant-create requests. The root
|
|
105
|
+
* vault connection comes from `env` (ION_VAULT_*); a tenant only stores its config `path`.
|
|
106
|
+
*/
|
|
107
|
+
configLocator: {
|
|
108
|
+
path: string;
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Server configuration options
|
|
113
|
+
*/
|
|
114
|
+
interface ServerOptions {
|
|
115
|
+
/**
|
|
116
|
+
* Port to listen on
|
|
117
|
+
* @default 3515
|
|
118
|
+
*/
|
|
119
|
+
port?: number;
|
|
120
|
+
/**
|
|
121
|
+
* Host to bind to
|
|
122
|
+
* @default 'localhost'
|
|
123
|
+
*/
|
|
124
|
+
host?: string;
|
|
125
|
+
/**
|
|
126
|
+
* Enable verbose logging
|
|
127
|
+
* @default false
|
|
128
|
+
*/
|
|
129
|
+
verbose?: boolean;
|
|
130
|
+
/**
|
|
131
|
+
* Redis URL for vault secrets at `{ION_VAULT_PATH}/redis` (consumed by ionRedis).
|
|
132
|
+
* Falls back to `REDIS_URL` when omitted.
|
|
133
|
+
*/
|
|
134
|
+
redisUrl?: string;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Start the ECV mock server
|
|
138
|
+
*
|
|
139
|
+
* @param options - Server configuration options
|
|
140
|
+
* @returns Promise that resolves with the server connection config when the server is listening
|
|
141
|
+
*/
|
|
142
|
+
declare function startEcvServer(options?: ServerOptions): Promise<EcvServerHandle>;
|
|
143
|
+
/**
|
|
144
|
+
* Stop the ECV mock server
|
|
145
|
+
*
|
|
146
|
+
* @returns Promise that resolves when the server has stopped
|
|
147
|
+
*/
|
|
148
|
+
declare function stopEcvServer(): Promise<void>;
|
|
149
|
+
/**
|
|
150
|
+
* ionite Validator Types
|
|
151
|
+
*
|
|
152
|
+
* These types define the configuration and result structures for
|
|
153
|
+
* ionite validation tests.
|
|
154
|
+
*/
|
|
155
|
+
/**
|
|
156
|
+
* Test definition for Vitest-compatible test suites
|
|
157
|
+
*/
|
|
158
|
+
interface TestDef {
|
|
159
|
+
name: string;
|
|
160
|
+
fn: () => Promise<void>;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Base configuration for all validation suites
|
|
164
|
+
*/
|
|
165
|
+
interface ValidationConfig {
|
|
166
|
+
/**
|
|
167
|
+
* Base URL of the application under test.
|
|
168
|
+
* May be a getter so Vitest suites can resolve the URL after `beforeAll`.
|
|
169
|
+
* @example "http://localhost:3000"
|
|
170
|
+
*/
|
|
171
|
+
baseUrl: string | (() => string);
|
|
172
|
+
/**
|
|
173
|
+
* Optional timeout for requests in milliseconds
|
|
174
|
+
* @default 5000
|
|
175
|
+
*/
|
|
176
|
+
timeout?: number;
|
|
177
|
+
/**
|
|
178
|
+
* Whether to skip TLS certificate verification (for local testing)
|
|
179
|
+
* @default false
|
|
180
|
+
*/
|
|
181
|
+
skipTlsVerify?: boolean;
|
|
182
|
+
/**
|
|
183
|
+
* Optional custom headers to include in all requests.
|
|
184
|
+
* May be a function (or async function) so that headers are resolved when the request runs
|
|
185
|
+
* (e.g. for workload auth token that is obtained in beforeAll).
|
|
186
|
+
*/
|
|
187
|
+
headers?: Record<string, string> | (() => Record<string, string> | Promise<Record<string, string>>);
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* SSO Validation Configuration
|
|
191
|
+
*/
|
|
192
|
+
interface SSOValidationConfig extends ValidationConfig {
|
|
193
|
+
/**
|
|
194
|
+
* Path to the login endpoint
|
|
195
|
+
* @default "/api/auth/login"
|
|
196
|
+
*/
|
|
197
|
+
loginPath?: string;
|
|
198
|
+
/**
|
|
199
|
+
* Path to the callback endpoint (where the IdP redirects after auth)
|
|
200
|
+
* @default "/api/auth/callback"
|
|
201
|
+
*/
|
|
202
|
+
callbackPath?: string;
|
|
203
|
+
/**
|
|
204
|
+
* Path to the user info endpoint
|
|
205
|
+
* @default "/api/auth/user"
|
|
206
|
+
*/
|
|
207
|
+
userPath?: string;
|
|
208
|
+
/**
|
|
209
|
+
* Path to the logout endpoint
|
|
210
|
+
* @default "/api/auth/logout"
|
|
211
|
+
*/
|
|
212
|
+
logoutPath?: string;
|
|
213
|
+
/**
|
|
214
|
+
* Path to the back-channel logout endpoint
|
|
215
|
+
* @default "/api/auth/logout/backchannel"
|
|
216
|
+
*/
|
|
217
|
+
backChannelLogoutPath?: string;
|
|
218
|
+
/**
|
|
219
|
+
* Path to the token endpoint
|
|
220
|
+
* @default "/api/auth/token"
|
|
221
|
+
*/
|
|
222
|
+
tokenPath?: string;
|
|
223
|
+
/**
|
|
224
|
+
* Path to the refresh endpoint
|
|
225
|
+
* @default "/api/auth/refresh"
|
|
226
|
+
*/
|
|
227
|
+
refreshPath?: string;
|
|
228
|
+
/**
|
|
229
|
+
* Expected redirect location pattern for login
|
|
230
|
+
* Should match the IdP authorization URL
|
|
231
|
+
*/
|
|
232
|
+
expectedAuthorizationUrlPattern?: RegExp;
|
|
233
|
+
/**
|
|
234
|
+
* Optional opt-in best-practice assertion: when set, a FAILED callback's `Location` header must
|
|
235
|
+
* match this pattern. Apps following the recommended pattern redirect login failures to an
|
|
236
|
+
* unauthenticated-reachable page carrying a generic error code (e.g. `/[?&]auth_error=login_failed/`).
|
|
237
|
+
* When unset, the failure path is only asserted to be a same-origin 302 (the SDK contract).
|
|
238
|
+
*/
|
|
239
|
+
expectedCallbackErrorPattern?: RegExp;
|
|
240
|
+
/**
|
|
241
|
+
* Test user credentials for end-to-end SSO testing
|
|
242
|
+
* If not provided, only structural tests will run
|
|
243
|
+
*/
|
|
244
|
+
testCredentials?: {
|
|
245
|
+
username: string;
|
|
246
|
+
password: string;
|
|
247
|
+
};
|
|
248
|
+
/**
|
|
249
|
+
* Expected fields returned by the authenticated user endpoint after a successful SSO flow.
|
|
250
|
+
* Useful for validating userStore.lookup-enriched profile data while preserving JWT-owned auth fields.
|
|
251
|
+
*/
|
|
252
|
+
expectedUser?: {
|
|
253
|
+
id?: string;
|
|
254
|
+
userName?: string;
|
|
255
|
+
name?: string;
|
|
256
|
+
email?: string;
|
|
257
|
+
avatar?: string;
|
|
258
|
+
requireSso?: boolean;
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* CIAM Validation Configuration
|
|
263
|
+
*
|
|
264
|
+
* Validates the customer (CIAM) domain route contracts that are distinct from
|
|
265
|
+
* the workforce (SSO) domain: the customer info endpoint and magic-link issuance.
|
|
266
|
+
*/
|
|
267
|
+
interface CIAMValidationConfig extends ValidationConfig {
|
|
268
|
+
/**
|
|
269
|
+
* Path to the customer info endpoint (CIAM equivalent of the SSO `userPath`).
|
|
270
|
+
* @default "/api/ionite/auth/customer"
|
|
271
|
+
*/
|
|
272
|
+
customerPath?: string;
|
|
273
|
+
/**
|
|
274
|
+
* Path to the magic-link generation endpoint (workload-authenticated POST).
|
|
275
|
+
* @default "/api/ionite/magic-link"
|
|
276
|
+
*/
|
|
277
|
+
magicLinkPath?: string;
|
|
278
|
+
/**
|
|
279
|
+
* Path to the magic-link login endpoint (GET with token).
|
|
280
|
+
* @default "/api/ionite/magic-link/login"
|
|
281
|
+
*/
|
|
282
|
+
magicLinkLoginPath?: string;
|
|
283
|
+
/**
|
|
284
|
+
* Path to the CIAM logout endpoint (distinct from the SSO logout path).
|
|
285
|
+
* @default "/api/ionite/auth/customer/logout"
|
|
286
|
+
*/
|
|
287
|
+
logoutPath?: string;
|
|
288
|
+
/**
|
|
289
|
+
* Former CIAM provider-initiated back-channel logout path. The endpoint has been
|
|
290
|
+
* removed (AUDIT_HISTORY.md §1.6); the validation suite probes this path to confirm it now
|
|
291
|
+
* returns 404. Customer logout is first-party / local session invalidation only.
|
|
292
|
+
* @default "/api/ionite/auth/customer/logout/backchannel"
|
|
293
|
+
*/
|
|
294
|
+
backChannelLogoutPath?: string;
|
|
295
|
+
/**
|
|
296
|
+
* Path to the sanitized third-party provider discovery endpoint (GET).
|
|
297
|
+
* @default "/api/ionite/auth/customer/providers"
|
|
298
|
+
*/
|
|
299
|
+
customerProvidersPath?: string;
|
|
300
|
+
/**
|
|
301
|
+
* Path to the third-party customer login endpoint (GET; `?provider=` selects).
|
|
302
|
+
* @default "/api/ionite/auth/customer/login"
|
|
303
|
+
*/
|
|
304
|
+
customerLoginPath?: string;
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* IAM Validation Configuration
|
|
308
|
+
*/
|
|
309
|
+
interface IAMValidationConfig extends ValidationConfig {
|
|
310
|
+
/**
|
|
311
|
+
* Path prefix for SCIM endpoints (used for both outgoing proxy and incoming handler)
|
|
312
|
+
* @default "/api/iam"
|
|
313
|
+
*/
|
|
314
|
+
scimPath?: string;
|
|
315
|
+
/**
|
|
316
|
+
* Path for Groups Inbound handler (app's own SCIM server for receiving group provisioning)
|
|
317
|
+
* If not provided, defaults to `${scimPath}/Groups`
|
|
318
|
+
* @example "/api/iam/Groups"
|
|
319
|
+
*/
|
|
320
|
+
groupsInboundPath?: string;
|
|
321
|
+
/**
|
|
322
|
+
* Ionite instance for workload authentication.
|
|
323
|
+
* Optional escape hatch: when provided, IAM tests use ionite workload token acquisition
|
|
324
|
+
* (requires workload to be configured). Can be a function that returns the instance
|
|
325
|
+
* (useful when instance is initialized in beforeAll).
|
|
326
|
+
*
|
|
327
|
+
* When omitted, IAM tests mint a workload token from the ECV mock server at `ecvUrl`.
|
|
328
|
+
*/
|
|
329
|
+
ion?: Ionite | (() => Ionite | null);
|
|
330
|
+
/**
|
|
331
|
+
* URL of the ECV mock server used to mint a workload token for SCIM calls when `ion` is not provided.
|
|
332
|
+
* @default "http://localhost:3515"
|
|
333
|
+
*/
|
|
334
|
+
ecvUrl?: string;
|
|
335
|
+
/**
|
|
336
|
+
* Test user data for CRUD operations
|
|
337
|
+
*/
|
|
338
|
+
testUser?: {
|
|
339
|
+
userName: string;
|
|
340
|
+
displayName: string;
|
|
341
|
+
emails: Array<{
|
|
342
|
+
value: string;
|
|
343
|
+
primary?: boolean;
|
|
344
|
+
}>;
|
|
345
|
+
name?: {
|
|
346
|
+
givenName?: string;
|
|
347
|
+
familyName?: string;
|
|
348
|
+
};
|
|
349
|
+
"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"?: EnterpriseExtension;
|
|
350
|
+
};
|
|
351
|
+
/**
|
|
352
|
+
* Test group data for CRUD operations
|
|
353
|
+
*/
|
|
354
|
+
testGroup?: {
|
|
355
|
+
displayName: string;
|
|
356
|
+
externalId?: string;
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Workload Validation Configuration
|
|
361
|
+
*/
|
|
362
|
+
interface WorkloadValidationConfig extends ValidationConfig {
|
|
363
|
+
/**
|
|
364
|
+
* Path to the token validation endpoint
|
|
365
|
+
* @default "/api/workload/validate"
|
|
366
|
+
*/
|
|
367
|
+
validatePath?: string;
|
|
368
|
+
/**
|
|
369
|
+
* Path to the JWKS endpoint
|
|
370
|
+
* @default "/api/workload/jwks"
|
|
371
|
+
*/
|
|
372
|
+
jwksPath?: string;
|
|
373
|
+
/**
|
|
374
|
+
* A valid workload token for the positive-path validation tests. When not provided, one is
|
|
375
|
+
* minted from the ECV mock IdP at `{ecvUrl}/workload/token`; if that fails the tests FAIL
|
|
376
|
+
* (no silent skip).
|
|
377
|
+
*/
|
|
378
|
+
validToken?: string;
|
|
379
|
+
/**
|
|
380
|
+
* URL of the ECV mock server for testing workload authentication
|
|
381
|
+
* Used for the whoami test to validate tokens independently
|
|
382
|
+
* @default "http://localhost:3515"
|
|
383
|
+
*/
|
|
384
|
+
ecvUrl?: string;
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Tenant validation scope.
|
|
388
|
+
*
|
|
389
|
+
* - `tenantManager`: full tenant management API (GET/DELETE/upsert by id)
|
|
390
|
+
* - `creation`: POST upsert only (async TMS / deployer-style servers)
|
|
391
|
+
*/
|
|
392
|
+
type TenantValidationProfile = "tenantManager" | "creation";
|
|
393
|
+
/**
|
|
394
|
+
* Tenant Validation Configuration
|
|
395
|
+
*/
|
|
396
|
+
interface TenantValidationConfig extends ValidationConfig {
|
|
397
|
+
/**
|
|
398
|
+
* Which tenant-management surface to validate.
|
|
399
|
+
* @default 'tenantManager'
|
|
400
|
+
*/
|
|
401
|
+
profile?: TenantValidationProfile;
|
|
402
|
+
/**
|
|
403
|
+
* Path to the tenant creation endpoint
|
|
404
|
+
* @default "/api/tenant"
|
|
405
|
+
*/
|
|
406
|
+
tenantPath?: string;
|
|
407
|
+
/**
|
|
408
|
+
* URL path where ESVS webhook server listens for tenant creation updates
|
|
409
|
+
* If not provided, webhook tests will be skipped
|
|
410
|
+
*/
|
|
411
|
+
webhookPath?: string;
|
|
412
|
+
/**
|
|
413
|
+
* Test tenant data for tenant creation
|
|
414
|
+
*/
|
|
415
|
+
testTenantData?: {
|
|
416
|
+
id: string;
|
|
417
|
+
companyId: string;
|
|
418
|
+
companyName: string;
|
|
419
|
+
environmentType: "POC" | "DEV" | "QA" | "PROD";
|
|
420
|
+
email?: string;
|
|
421
|
+
webhookUrl?: string;
|
|
422
|
+
callbackUrl?: string;
|
|
423
|
+
/** Required: create requests must carry a `configLocator` (see `CreateTenantRequest`). */
|
|
424
|
+
configLocator: {
|
|
425
|
+
/** Optional name of a secrets source declared on the root Ionite; omit to use the default `ion.secret`. */
|
|
426
|
+
source?: string;
|
|
427
|
+
/** Tenant-specific secret path within that source. */
|
|
428
|
+
path: string;
|
|
429
|
+
/** Optional poll interval (ms) for the tenant config subscription. */
|
|
430
|
+
ttl?: number;
|
|
431
|
+
};
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
/**
|
|
435
|
+
* Capability Catalog Validation Configuration.
|
|
436
|
+
*
|
|
437
|
+
* Validates the runtime readiness endpoint (`${basePath}/readyz`) and catalogs the application's
|
|
438
|
+
* capabilities for publishing to the ECI. Runs at CI/CD time; the readiness endpoint it reads is the
|
|
439
|
+
* runtime source of truth for per-module readiness and shares one capability definition
|
|
440
|
+
* (`ION_CAPABILITY_CATALOG`) with this suite so the SDK, ECV, and docs cannot drift.
|
|
441
|
+
*/
|
|
442
|
+
interface CapabilityValidationConfig extends ValidationConfig {
|
|
443
|
+
/**
|
|
444
|
+
* Path to the readiness endpoint (`${basePath}/readyz`).
|
|
445
|
+
* @default "/api/ionite/readyz"
|
|
446
|
+
*/
|
|
447
|
+
readyzPath?: string;
|
|
448
|
+
/**
|
|
449
|
+
* Path to the ECV/dev-only capability discovery endpoint (`${basePath}/capabilitiez`).
|
|
450
|
+
* @default "/api/ionite/capabilitiez"
|
|
451
|
+
*/
|
|
452
|
+
capabilitiezPath?: string;
|
|
453
|
+
/**
|
|
454
|
+
* ECV mock server base URL used to mint workload tokens for authenticated capabilitiez requests.
|
|
455
|
+
* @default "http://localhost:3515"
|
|
456
|
+
*/
|
|
457
|
+
ecvUrl?: string;
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
460
|
+
* Authz / OAA Validation Configuration.
|
|
461
|
+
*
|
|
462
|
+
* Validates the Veza OAA projection (`ion.authz.oaa`). The in-process closure tests run with no
|
|
463
|
+
* dependencies; the OAA projection tests build an Ionite instance whose OAA client points
|
|
464
|
+
* at the ECV mock server's Veza receiver, so the real SDK OAA payloads can be decoded and asserted.
|
|
465
|
+
*/
|
|
466
|
+
interface AuthzValidationConfig {
|
|
467
|
+
/**
|
|
468
|
+
* ECV mock server handle (or getter) from `startEcvServer`. Provides the OAA receiver base URL the
|
|
469
|
+
* projection tests target. When omitted, only the dependency-free closure tests run.
|
|
470
|
+
*/
|
|
471
|
+
ecv?: EcvServerHandle | (() => EcvServerHandle);
|
|
472
|
+
/**
|
|
473
|
+
* Timeout (ms) applied to OAA readiness waits.
|
|
474
|
+
* @default 5000
|
|
475
|
+
*/
|
|
476
|
+
timeout?: number;
|
|
477
|
+
}
|
|
478
|
+
/**
|
|
479
|
+
* Result of an individual validation test
|
|
480
|
+
*/
|
|
481
|
+
interface ValidationResult {
|
|
482
|
+
/**
|
|
483
|
+
* Name of the test
|
|
484
|
+
*/
|
|
485
|
+
name: string;
|
|
486
|
+
/**
|
|
487
|
+
* Whether the test passed
|
|
488
|
+
*/
|
|
489
|
+
passed: boolean;
|
|
490
|
+
/**
|
|
491
|
+
* Error message if the test failed
|
|
492
|
+
*/
|
|
493
|
+
error?: string;
|
|
494
|
+
/**
|
|
495
|
+
* Duration of the test in milliseconds
|
|
496
|
+
*/
|
|
497
|
+
duration: number;
|
|
498
|
+
/**
|
|
499
|
+
* Additional details or diagnostics
|
|
500
|
+
*/
|
|
501
|
+
details?: Record<string, unknown>;
|
|
502
|
+
}
|
|
503
|
+
/**
|
|
504
|
+
* Result of a validation suite
|
|
505
|
+
*/
|
|
506
|
+
interface ValidationSuiteResult {
|
|
507
|
+
/**
|
|
508
|
+
* Name of the suite (e.g., "SSO", "IAM", "Workload")
|
|
509
|
+
*/
|
|
510
|
+
suite: string;
|
|
511
|
+
/**
|
|
512
|
+
* Whether all tests in the suite passed
|
|
513
|
+
*/
|
|
514
|
+
passed: boolean;
|
|
515
|
+
/**
|
|
516
|
+
* Individual test results
|
|
517
|
+
*/
|
|
518
|
+
tests: ValidationResult[];
|
|
519
|
+
/**
|
|
520
|
+
* Total duration of the suite in milliseconds
|
|
521
|
+
*/
|
|
522
|
+
duration: number;
|
|
523
|
+
/**
|
|
524
|
+
* Summary statistics
|
|
525
|
+
*/
|
|
526
|
+
summary: {
|
|
527
|
+
total: number;
|
|
528
|
+
passed: number;
|
|
529
|
+
failed: number;
|
|
530
|
+
skipped: number;
|
|
531
|
+
};
|
|
532
|
+
}
|
|
533
|
+
/**
|
|
534
|
+
* Full validation report
|
|
535
|
+
*/
|
|
536
|
+
interface ValidationReport {
|
|
537
|
+
/**
|
|
538
|
+
* Timestamp of the validation run
|
|
539
|
+
*/
|
|
540
|
+
timestamp: Date;
|
|
541
|
+
/**
|
|
542
|
+
* Base URL tested
|
|
543
|
+
*/
|
|
544
|
+
baseUrl: string;
|
|
545
|
+
/**
|
|
546
|
+
* Whether all suites passed
|
|
547
|
+
*/
|
|
548
|
+
passed: boolean;
|
|
549
|
+
/**
|
|
550
|
+
* Individual suite results
|
|
551
|
+
*/
|
|
552
|
+
suites: ValidationSuiteResult[];
|
|
553
|
+
/**
|
|
554
|
+
* Total duration of all tests
|
|
555
|
+
*/
|
|
556
|
+
duration: number;
|
|
557
|
+
}
|
|
558
|
+
declare function createAuthzClosureTests(): {
|
|
559
|
+
tests: TestDef[];
|
|
560
|
+
};
|
|
561
|
+
/**
|
|
562
|
+
* OAA projection tests. They require a running ECV mock server (its Veza receiver records the decoded
|
|
563
|
+
* payloads) and validate that the real `ion.authz.oaa` client emits well-formed, correctly-encoded
|
|
564
|
+
* incremental and full-snapshot payloads for pushes, grants, revokes, and sync.
|
|
565
|
+
*/
|
|
566
|
+
declare function createOaaProjectionTests(config: AuthzValidationConfig): TestDef[];
|
|
567
|
+
/**
|
|
568
|
+
* Workload OAuth-scope tests (require the ECV mock server for JWKS + token minting). They validate
|
|
569
|
+
* the two authorization sources for a workload: explicit `hasScope*` (token claims) and the
|
|
570
|
+
* config-gated `scopesAsEntitlements` auto-honor inside `has*`.
|
|
571
|
+
*/
|
|
572
|
+
declare function createWorkloadScopeTests(config: AuthzValidationConfig): TestDef[];
|
|
573
|
+
/**
|
|
574
|
+
* Programmatic Authz/OAA validation runner. Always runs the in-process closure tests; when an ECV
|
|
575
|
+
* mock server handle is provided, also runs the OAA projection tests against its Veza receiver.
|
|
576
|
+
*/
|
|
577
|
+
declare function validateAuthz(config?: AuthzValidationConfig): Promise<ValidationSuiteResult>;
|
|
578
|
+
/**
|
|
579
|
+
* Runs all Capability Catalog validation tests and returns a suite result whose details carry the
|
|
580
|
+
* capability catalog for publishing to the ECI.
|
|
581
|
+
*/
|
|
582
|
+
declare function validateCapabilities(config: CapabilityValidationConfig): Promise<ValidationSuiteResult>;
|
|
583
|
+
/**
|
|
584
|
+
* Creates a Vitest-compatible test suite for capability catalog validation.
|
|
585
|
+
*/
|
|
586
|
+
declare function createCapabilityTests(config: CapabilityValidationConfig): Array<TestDef>;
|
|
587
|
+
import { CapabilitiezManifest, CapabilityKey, Ionite as Ionite2 } from "@ionite/server";
|
|
588
|
+
interface DiscoveredECVConfig extends ValidationConfig {
|
|
589
|
+
/**
|
|
590
|
+
* ionite basePath used by the application under test.
|
|
591
|
+
* @default "/api/ionite"
|
|
592
|
+
*/
|
|
593
|
+
basePath?: string;
|
|
594
|
+
/**
|
|
595
|
+
* Override the capabilitiez path when the endpoint is not mounted at `${basePath}/capabilitiez`.
|
|
596
|
+
*/
|
|
597
|
+
capabilitiezPath?: string;
|
|
598
|
+
/**
|
|
599
|
+
* Opt-in best-practice assertion threaded into the SSO suite: when set, a FAILED callback's
|
|
600
|
+
* `Location` must match this pattern (e.g. `/[?&]auth_error=login_failed/`). See
|
|
601
|
+
* {@link SSOValidationConfig.expectedCallbackErrorPattern}.
|
|
602
|
+
*/
|
|
603
|
+
expectedCallbackErrorPattern?: RegExp;
|
|
604
|
+
/**
|
|
605
|
+
* ECV mock server handle (from `startEcvServer`), or a getter returning it. Preferred over `ecvUrl`:
|
|
606
|
+
* the discovery and IAM token-minting URL is derived from `ecv.baseUrl`, so it can never drift from
|
|
607
|
+
* where the server started. A getter is supported because the handle is often created in `beforeAll`,
|
|
608
|
+
* after test collection.
|
|
609
|
+
*/
|
|
610
|
+
ecv?: EcvServerHandle | (() => EcvServerHandle);
|
|
611
|
+
/**
|
|
612
|
+
* Ionite instance used by IAM tests to obtain workload-authenticated SCIM tokens.
|
|
613
|
+
* Optional escape hatch for real-IdP / custom-scope runs; when omitted, tokens are minted from the
|
|
614
|
+
* ECV mock server.
|
|
615
|
+
*/
|
|
616
|
+
ion?: Ionite2 | (() => Ionite2 | null);
|
|
617
|
+
/**
|
|
618
|
+
* ECV mock server base URL used to mint workload tokens for authenticated discovery.
|
|
619
|
+
* Ignored when `ecv` is provided.
|
|
620
|
+
* @default "http://localhost:3515"
|
|
621
|
+
*/
|
|
622
|
+
ecvUrl?: string;
|
|
623
|
+
}
|
|
624
|
+
declare function fetchCapabilitiezManifest(config: DiscoveredECVConfig): Promise<CapabilitiezManifest>;
|
|
625
|
+
/**
|
|
626
|
+
* A single discoverable ECV check. Entries are enumerated up front (so every possible check is
|
|
627
|
+
* visible in the test reporter) and gated at run time against the capabilitiez manifest. `alwaysRun`
|
|
628
|
+
* entries (in-process closure, config retry, manifest reachability) ignore capability gating.
|
|
629
|
+
*/
|
|
630
|
+
interface EcvCatalogEntry {
|
|
631
|
+
/** Stable machine id (suite + name slug). */
|
|
632
|
+
id: string;
|
|
633
|
+
/** Display group: 'SSO' | 'CIAM' | 'IAM' | 'Workload' | 'Authz/OAA' | 'Authz closure' | 'Discovery' | 'Config retry policy'. */
|
|
634
|
+
suite: string;
|
|
635
|
+
/** Human-readable test name. */
|
|
636
|
+
name: string;
|
|
637
|
+
/** Capability gate; when omitted (or `alwaysRun`), the check is not gated. An array passes if ANY key is testable. */
|
|
638
|
+
capability?: CapabilityKey | CapabilityKey[];
|
|
639
|
+
/** Always run regardless of capabilitiez (in-process or infrastructure checks). */
|
|
640
|
+
alwaysRun?: boolean;
|
|
641
|
+
/** Execute the underlying assertion using the resolved manifest (present for capability-gated entries). */
|
|
642
|
+
run: (manifest?: CapabilitiezManifest) => Promise<void>;
|
|
643
|
+
}
|
|
644
|
+
/**
|
|
645
|
+
* Compute a skip reason for an entry's capability gate, or `undefined` when it should run. Prefers the
|
|
646
|
+
* manifest's own `reason` string so skips explain why a capability is not wired/testable.
|
|
647
|
+
*/
|
|
648
|
+
declare function capabilitySkipReason(manifest: CapabilitiezManifest, capability?: CapabilityKey | CapabilityKey[]): string | undefined;
|
|
649
|
+
/**
|
|
650
|
+
* Build the full catalog of discoverable ECV checks. Names are enumerated synchronously so the
|
|
651
|
+
* complete list is visible at collection time; capability-gated entries resolve their shared factory
|
|
652
|
+
* instance lazily from the manifest at run time (preserving cross-test state such as created user ids).
|
|
653
|
+
*/
|
|
654
|
+
declare function buildEcvCatalog(config: DiscoveredECVConfig, options?: {
|
|
655
|
+
configRetry?: boolean;
|
|
656
|
+
}): EcvCatalogEntry[];
|
|
657
|
+
/**
|
|
658
|
+
* Build discovered ECV tests as a flat `TestDef[]` for manual wiring.
|
|
659
|
+
*
|
|
660
|
+
* @deprecated Plain `TestDef`s cannot signal a real skip to the test reporter, so a capability that
|
|
661
|
+
* is not testable is reported as a pass — only mitigated here by a visible `console.warn` SKIP line.
|
|
662
|
+
* Prefer {@link defineDiscoveredECVSuite}, which reports each skipped capability via `ctx.skip(reason)`
|
|
663
|
+
* so the reporter distinguishes skipped from passed (AUDIT_HISTORY.md §4.10).
|
|
664
|
+
*/
|
|
665
|
+
declare function createDiscoveredECVTests(config: DiscoveredECVConfig): Array<TestDef>;
|
|
666
|
+
/**
|
|
667
|
+
* Runs all CIAM validation tests
|
|
668
|
+
*/
|
|
669
|
+
declare function validateCIAM(config: CIAMValidationConfig): Promise<ValidationSuiteResult>;
|
|
670
|
+
declare function createCIAMTests(config: CIAMValidationConfig): {
|
|
671
|
+
tests: Array<TestDef>;
|
|
672
|
+
};
|
|
673
|
+
/**
|
|
674
|
+
* Lifecycle hardening coverage (AUDIT_HISTORY.md §5.1/§5.2/§5.4): module-readiness re-arm on de-configuration,
|
|
675
|
+
* async/deadlock-guarded `beforeChange`, and robust `afterChange` error handling.
|
|
676
|
+
*/
|
|
677
|
+
declare function createConfigLifecycleTests(): TestDef[];
|
|
678
|
+
/**
|
|
679
|
+
* Config-merge & secrets-boundary coverage (AUDIT_HISTORY.md §2.1/§2.2/§2.3/§4.3/§4.5): the ConfigSource owns
|
|
680
|
+
* credentials, unimplemented backends fail fast at apply, invalid/empty config payloads and locators
|
|
681
|
+
* are rejected, a configured `beforeChange` always re-applies, and declared-but-unconfigured secrets
|
|
682
|
+
* sources keep the module not-ready.
|
|
683
|
+
*/
|
|
684
|
+
declare function createConfigBoundaryTests(): TestDef[];
|
|
685
|
+
declare function createConfigRetryTests(): TestDef[];
|
|
686
|
+
/**
|
|
687
|
+
* Canonical `ion:*` scope strings the ECV harness embeds in workload tokens so deny-by-default SDK
|
|
688
|
+
* endpoints (AUDIT_HISTORY.md §1.32) authorize via `scopesAsEntitlements`. They mirror the SDK-owned Permission
|
|
689
|
+
* ids so they can never drift from the gate.
|
|
690
|
+
*/
|
|
691
|
+
/** All three SCIM scopes (read + user/group writes) — the IAM suite reads and writes with one token. */
|
|
692
|
+
declare const ION_IAM_SCOPES: string;
|
|
693
|
+
/** Scope required to read the capability manifest at the capabilitiez endpoint. */
|
|
694
|
+
declare const ION_CAPABILITIEZ_SCOPE: string;
|
|
695
|
+
/** Scope required to manage tenant records via the tenant-management endpoints. */
|
|
696
|
+
declare const ION_TENANT_SCOPE: string;
|
|
697
|
+
/**
|
|
698
|
+
* Get a workload token from the ECV mock server for use when calling the SDK's protected endpoints
|
|
699
|
+
* (tenant management, SCIM, capabilitiez). Used by tests so the call is authenticated with a workload
|
|
700
|
+
* identity.
|
|
701
|
+
*
|
|
702
|
+
* The SDK gates its protected endpoints deny-by-default (AUDIT_HISTORY.md §1.32). When the app under test enables
|
|
703
|
+
* `RemoteConfig.authz.scopesAsEntitlements` (the ECV mock vault does), the requested `scope` is honored
|
|
704
|
+
* as the matching entitlement — so pass the `ion:*` permission id(s) the endpoint requires (e.g.
|
|
705
|
+
* `ion:tenant:manage`, `ion:capabilitiez:read`, or the IAM scopes). Omit `scope` to mint an
|
|
706
|
+
* authenticated-but-unauthorized token (useful for asserting 403 denial).
|
|
707
|
+
*
|
|
708
|
+
* @param esvBaseUrl - Base URL of the ECV mock server (e.g. http://localhost:3515)
|
|
709
|
+
* @param scope - Space-delimited OAuth scope(s) to embed in the token (the SDK `ion:*` permission ids)
|
|
710
|
+
* @param clientId - Client ID for client_credentials grant (default: local-workload-client)
|
|
711
|
+
* @param clientSecret - Client secret (default: local-workload-secret)
|
|
712
|
+
* @returns The access token to use as Authorization: Bearer <token>
|
|
713
|
+
*/
|
|
714
|
+
declare function getTenantAuthToken(esvBaseUrl?: string, scope?: string, clientId?: string, clientSecret?: string): Promise<string>;
|
|
715
|
+
declare function createHarnessSelfTests(): TestDef[];
|
|
716
|
+
/**
|
|
717
|
+
* Runs all IAM validation tests (core user tests + optional groups tests)
|
|
718
|
+
*/
|
|
719
|
+
declare function validateIAM(config: IAMValidationConfig): Promise<ValidationSuiteResult>;
|
|
720
|
+
/**
|
|
721
|
+
* Creates Vitest-compatible test suite for IAM validation.
|
|
722
|
+
*
|
|
723
|
+
* Returns `{ tests, ext }` where:
|
|
724
|
+
* - `tests`: Core user management tests (always run)
|
|
725
|
+
* - `ext`: Extension methods for optional functionality:
|
|
726
|
+
* - `createGroupsOutboundTests()` - Tests app calling external IAM provider
|
|
727
|
+
* - `createGroupsInboundTests()` - Tests external IAM provider calling app
|
|
728
|
+
*
|
|
729
|
+
* @example
|
|
730
|
+
* ```ts
|
|
731
|
+
* describe('IAM', () => {
|
|
732
|
+
* const { tests, ext } = createIAMTests({ ... });
|
|
733
|
+
*
|
|
734
|
+
* // Core user tests
|
|
735
|
+
* tests.forEach(({ name, fn }) => it(name, fn));
|
|
736
|
+
*
|
|
737
|
+
* // Optional: Groups Outbound tests (app -> external IAM)
|
|
738
|
+
* describe('Groups Outbound', () => {
|
|
739
|
+
* ext.createGroupsOutboundTests().forEach(({ name, fn }) => it(name, fn));
|
|
740
|
+
* });
|
|
741
|
+
*
|
|
742
|
+
* // Optional: Groups Inbound tests (external IAM -> app)
|
|
743
|
+
* describe('Groups Inbound', () => {
|
|
744
|
+
* ext.createGroupsInboundTests().forEach(({ name, fn }) => it(name, fn));
|
|
745
|
+
* });
|
|
746
|
+
* });
|
|
747
|
+
* ```
|
|
748
|
+
*/
|
|
749
|
+
declare function createIAMTests(config: IAMValidationConfig): {
|
|
750
|
+
tests: Array<TestDef>;
|
|
751
|
+
ext: {
|
|
752
|
+
createGroupsOutboundTests: () => Array<TestDef>;
|
|
753
|
+
createGroupsInboundTests: () => Array<TestDef>;
|
|
754
|
+
};
|
|
755
|
+
};
|
|
756
|
+
declare function createIamDeltaPatchTests(): {
|
|
757
|
+
tests: TestDef[];
|
|
758
|
+
};
|
|
759
|
+
/**
|
|
760
|
+
* Programmatic IAM delta validation runner (always in-process; no external server required).
|
|
761
|
+
*/
|
|
762
|
+
declare function validateIamDelta(): Promise<ValidationSuiteResult>;
|
|
763
|
+
declare function createLfvCallbackTests(): {
|
|
764
|
+
tests: TestDef[];
|
|
765
|
+
};
|
|
766
|
+
declare function validateLfvDelivery(): Promise<ValidationSuiteResult>;
|
|
767
|
+
declare function createOtelTests(): {
|
|
768
|
+
tests: TestDef[];
|
|
769
|
+
};
|
|
770
|
+
declare function validateOtel(): Promise<ValidationSuiteResult>;
|
|
771
|
+
declare function createPerformanceTuningTests(): {
|
|
772
|
+
tests: TestDef[];
|
|
773
|
+
};
|
|
774
|
+
declare function validatePerformanceTuning(): Promise<ValidationSuiteResult>;
|
|
775
|
+
/**
|
|
776
|
+
* Validate the hardened protocol/error surface of the routed ionite handler. In-process; no running app.
|
|
777
|
+
*/
|
|
778
|
+
declare function createProtocolSurfaceTests(): {
|
|
779
|
+
tests: TestDef[];
|
|
780
|
+
};
|
|
781
|
+
/**
|
|
782
|
+
* Run the protocol-surface validation suite and return a structured result list.
|
|
783
|
+
*/
|
|
784
|
+
declare function validateProtocolSurface(): Promise<{
|
|
785
|
+
name: string;
|
|
786
|
+
passed: boolean;
|
|
787
|
+
error?: string;
|
|
788
|
+
}[]>;
|
|
789
|
+
declare function createRedisStoreTests(): {
|
|
790
|
+
tests: TestDef[];
|
|
791
|
+
};
|
|
792
|
+
declare function validateRedisStores(): Promise<ValidationSuiteResult>;
|
|
793
|
+
declare function createSecretsHardeningTests(): {
|
|
794
|
+
tests: TestDef[];
|
|
795
|
+
};
|
|
796
|
+
declare function validateSecretsHardening(): Promise<ValidationSuiteResult>;
|
|
797
|
+
/**
|
|
798
|
+
* Runs all SSO validation tests
|
|
799
|
+
*/
|
|
800
|
+
declare function validateSSO(config: SSOValidationConfig): Promise<ValidationSuiteResult>;
|
|
801
|
+
/**
|
|
802
|
+
* Creates Vitest-compatible test suite for SSO validation
|
|
803
|
+
*/
|
|
804
|
+
declare function createSSOTests(config: SSOValidationConfig): {
|
|
805
|
+
tests: Array<TestDef>;
|
|
806
|
+
ext: {
|
|
807
|
+
createJITTests: () => Array<TestDef>;
|
|
808
|
+
createLogoutTests: () => Array<TestDef>;
|
|
809
|
+
createBackChannelLogoutTests: () => Array<TestDef>;
|
|
810
|
+
};
|
|
811
|
+
};
|
|
812
|
+
declare function createSsoIdTokenVerificationTests(): {
|
|
813
|
+
tests: TestDef[];
|
|
814
|
+
};
|
|
815
|
+
declare function validateSsoIdTokenVerification(): Promise<ValidationSuiteResult>;
|
|
816
|
+
/**
|
|
817
|
+
* Runs all Tenant validation tests
|
|
818
|
+
*/
|
|
819
|
+
declare function validateTenant(config: TenantValidationConfig): Promise<ValidationSuiteResult>;
|
|
820
|
+
/**
|
|
821
|
+
* Creates Vitest-compatible test suite for Tenant validation
|
|
822
|
+
*/
|
|
823
|
+
declare function createTenantTests(config: TenantValidationConfig): Array<TestDef>;
|
|
824
|
+
declare function createTenantLifecycleTests(): {
|
|
825
|
+
tests: TestDef[];
|
|
826
|
+
};
|
|
827
|
+
declare function validateTenantLifecycle(): Promise<ValidationSuiteResult>;
|
|
828
|
+
type StandardSchemaV1 = {
|
|
829
|
+
readonly "~standard": {
|
|
830
|
+
readonly validate: (value: unknown) => {
|
|
831
|
+
value: unknown;
|
|
832
|
+
} | {
|
|
833
|
+
issues: ReadonlyArray<{
|
|
834
|
+
message: string;
|
|
835
|
+
path?: ReadonlyArray<unknown>;
|
|
836
|
+
}>;
|
|
837
|
+
} | Promise<{
|
|
838
|
+
value: unknown;
|
|
839
|
+
} | {
|
|
840
|
+
issues: ReadonlyArray<{
|
|
841
|
+
message: string;
|
|
842
|
+
path?: ReadonlyArray<unknown>;
|
|
843
|
+
}>;
|
|
844
|
+
}>;
|
|
845
|
+
};
|
|
846
|
+
};
|
|
847
|
+
/**
|
|
848
|
+
* Creates a fetch function with default configuration
|
|
849
|
+
*/
|
|
850
|
+
declare function resolveBaseUrl(config: Pick<ValidationConfig, "baseUrl">): string;
|
|
851
|
+
declare function createFetcher(config: ValidationConfig): (path: string, options?: RequestInit) => Promise<Response>;
|
|
852
|
+
/**
|
|
853
|
+
* Wraps a test function to capture timing and errors
|
|
854
|
+
*/
|
|
855
|
+
declare function runTest(name: string, testFn: () => Promise<undefined | {
|
|
856
|
+
details?: Record<string, unknown>;
|
|
857
|
+
}>): Promise<ValidationResult>;
|
|
858
|
+
/**
|
|
859
|
+
* Creates a skipped test result
|
|
860
|
+
*/
|
|
861
|
+
declare function skipTest(name: string, reason: string): ValidationResult;
|
|
862
|
+
/**
|
|
863
|
+
* Assertion helper for tests
|
|
864
|
+
*/
|
|
865
|
+
declare function assert(condition: boolean, message: string): asserts condition;
|
|
866
|
+
/**
|
|
867
|
+
* Assertion helper for equality
|
|
868
|
+
*/
|
|
869
|
+
declare function assertEqual<T>(actual: T, expected: T, message?: string): void;
|
|
870
|
+
/**
|
|
871
|
+
* Assertion helper for validating data against a StandardSchemaV1 validator
|
|
872
|
+
*
|
|
873
|
+
* This is the preferred way to validate data when you have a validator available.
|
|
874
|
+
* The validator can be from valibot, zod, or any other library that implements StandardSchemaV1.
|
|
875
|
+
*
|
|
876
|
+
* @param data - The data to validate
|
|
877
|
+
* @param validator - A StandardSchemaV1 validator (e.g., from valibotValidators or zodValidators)
|
|
878
|
+
* @param message - Optional custom error message
|
|
879
|
+
*
|
|
880
|
+
* @example
|
|
881
|
+
* ```typescript
|
|
882
|
+
* import { valibotValidators } from '@ionite/valibot';
|
|
883
|
+
* const tenantValidator = valibotValidators.tenantResponse();
|
|
884
|
+
* assertValid(data, tenantValidator);
|
|
885
|
+
* ```
|
|
886
|
+
*
|
|
887
|
+
* @throws Error if validation fails
|
|
888
|
+
*/
|
|
889
|
+
declare function assertValid(data: unknown, validator: StandardSchemaV1, message?: string): void;
|
|
890
|
+
declare function createValidatorParityTests(): {
|
|
891
|
+
tests: TestDef[];
|
|
892
|
+
};
|
|
893
|
+
declare function validateValidatorParity(): Promise<ValidationSuiteResult>;
|
|
894
|
+
declare function createVaultWebSocketTransportTests(): {
|
|
895
|
+
tests: TestDef[];
|
|
896
|
+
};
|
|
897
|
+
declare function validateVaultWebSocketTransport(): Promise<ValidationSuiteResult>;
|
|
898
|
+
/**
|
|
899
|
+
* Runs all Workload validation tests
|
|
900
|
+
*/
|
|
901
|
+
declare function validateWorkload(config: WorkloadValidationConfig): Promise<ValidationSuiteResult>;
|
|
902
|
+
/**
|
|
903
|
+
* Creates Vitest-compatible test suite for Workload validation
|
|
904
|
+
*/
|
|
905
|
+
declare function createWorkloadTests(config: WorkloadValidationConfig): Array<TestDef>;
|
|
906
|
+
import { Ionite as Ionite3 } from "@ionite/server";
|
|
907
|
+
/**
|
|
908
|
+
* Helper to create a complete Vitest test suite
|
|
909
|
+
*
|
|
910
|
+
* @example
|
|
911
|
+
* ```typescript
|
|
912
|
+
* import { describe, it } from 'vitest';
|
|
913
|
+
* import { defineECVTests } from '@ionite/ecv';
|
|
914
|
+
*
|
|
915
|
+
* defineECVTests(describe, it, {
|
|
916
|
+
* baseUrl: 'http://localhost:3000',
|
|
917
|
+
* sso: true,
|
|
918
|
+
* workload: true,
|
|
919
|
+
* });
|
|
920
|
+
* ```
|
|
921
|
+
*/
|
|
922
|
+
declare function defineECVTests(describe: (name: string, fn: () => void) => void, it: (name: string, fn: () => Promise<void>) => void, config: {
|
|
923
|
+
baseUrl: string;
|
|
924
|
+
sso?: boolean | SSOValidationConfig;
|
|
925
|
+
ciam?: boolean | CIAMValidationConfig;
|
|
926
|
+
lfv?: boolean;
|
|
927
|
+
/**
|
|
928
|
+
* OpenTelemetry module validation. OPT-IN (`otel: true`): the suite starts a process-global
|
|
929
|
+
* `NodeSDK`, which registers global OTel providers/diagnostics for the whole test process, so it
|
|
930
|
+
* is off by default to avoid interfering with a consumer's own tracing/other suites. In-repo
|
|
931
|
+
* coverage still runs it via the discovered `capabilitiez` catalog (always-run).
|
|
932
|
+
*/
|
|
933
|
+
otel?: boolean;
|
|
934
|
+
protocolSurface?: boolean;
|
|
935
|
+
harness?: boolean;
|
|
936
|
+
secretsHardening?: boolean;
|
|
937
|
+
redisStores?: boolean;
|
|
938
|
+
tenantLifecycle?: boolean;
|
|
939
|
+
vaultWebsocket?: boolean;
|
|
940
|
+
idTokenVerification?: boolean;
|
|
941
|
+
performanceTuning?: boolean;
|
|
942
|
+
validatorParity?: boolean;
|
|
943
|
+
iam?: IAMValidationConfig;
|
|
944
|
+
workload?: boolean | WorkloadValidationConfig;
|
|
945
|
+
tenant?: boolean | TenantValidationConfig;
|
|
946
|
+
capabilities?: boolean | CapabilityValidationConfig;
|
|
947
|
+
authz?: boolean | AuthzValidationConfig;
|
|
948
|
+
}): void;
|
|
949
|
+
/**
|
|
950
|
+
* Vitest-style lifecycle hooks passed into {@link defineDiscoveredECVSuite}.
|
|
951
|
+
*
|
|
952
|
+
* The helper takes hooks rather than importing `vitest` so the package stays framework-agnostic.
|
|
953
|
+
*/
|
|
954
|
+
/**
|
|
955
|
+
* Minimal Vitest test-context shape used by discovered ECV tests. Vitest's real `TestContext`
|
|
956
|
+
* structurally satisfies this (its `skip(note?)` dynamically marks the running test as skipped).
|
|
957
|
+
*/
|
|
958
|
+
interface EcvTestContext {
|
|
959
|
+
skip: (note?: string) => void;
|
|
960
|
+
}
|
|
961
|
+
interface DiscoveredECVSuiteHooks {
|
|
962
|
+
describe: (name: string, fn: () => void) => void;
|
|
963
|
+
it: (name: string, fn: (ctx: EcvTestContext) => Promise<void> | void) => void;
|
|
964
|
+
beforeAll: (fn: () => Promise<void> | void) => void;
|
|
965
|
+
afterAll: (fn: () => Promise<void> | void) => void;
|
|
966
|
+
}
|
|
967
|
+
/**
|
|
968
|
+
* Configuration for {@link defineDiscoveredECVSuite}.
|
|
969
|
+
*/
|
|
970
|
+
interface DiscoveredECVSuiteConfig {
|
|
971
|
+
/**
|
|
972
|
+
* ECV mock server handle (or getter) from `startEcvServer`. The app's connection env is taken from
|
|
973
|
+
* `ecv.env`, and IAM/workload/capabilitiez token minting is derived from `ecv.baseUrl`.
|
|
974
|
+
*/
|
|
975
|
+
ecv: EcvServerHandle | (() => EcvServerHandle);
|
|
976
|
+
/**
|
|
977
|
+
* The application under test to spawn. `ecv.env` is merged in automatically (your `app.env` wins on
|
|
978
|
+
* conflicts), so you only specify app-specific variables here.
|
|
979
|
+
*/
|
|
980
|
+
app: StartAppOptions;
|
|
981
|
+
/**
|
|
982
|
+
* ionite basePath used by the application under test.
|
|
983
|
+
* @default "/api/ionite"
|
|
984
|
+
*/
|
|
985
|
+
basePath?: string;
|
|
986
|
+
/** Timeout (ms) applied to discovered validation requests. */
|
|
987
|
+
timeout?: number;
|
|
988
|
+
/**
|
|
989
|
+
* Opt-in best-practice assertion: when set, a FAILED SSO callback's `Location` must match this
|
|
990
|
+
* pattern (e.g. `/[?&]auth_error=login_failed/`), proving the app surfaces login errors to the user.
|
|
991
|
+
*/
|
|
992
|
+
expectedCallbackErrorPattern?: RegExp;
|
|
993
|
+
/**
|
|
994
|
+
* Register the config-retry policy tests alongside discovered tests.
|
|
995
|
+
* @default false
|
|
996
|
+
*/
|
|
997
|
+
configRetry?: boolean;
|
|
998
|
+
/**
|
|
999
|
+
* Optional Ionite instance escape hatch for IAM token minting (real-IdP / custom scopes).
|
|
1000
|
+
* When omitted, IAM tokens are minted from the ECV mock server.
|
|
1001
|
+
*/
|
|
1002
|
+
ion?: Ionite3 | (() => Ionite3 | null);
|
|
1003
|
+
}
|
|
1004
|
+
/**
|
|
1005
|
+
* Register a complete discovered-ECV suite: spawn the app under test, run config-retry (optional) and
|
|
1006
|
+
* capabilitiez-discovered module tests, and tear the app down afterwards.
|
|
1007
|
+
*
|
|
1008
|
+
* The ECV mock server (and any Redis) lifecycle stays with the caller, since not every project uses Redis.
|
|
1009
|
+
*
|
|
1010
|
+
* @example
|
|
1011
|
+
* ```ts
|
|
1012
|
+
* import { afterAll, beforeAll, describe, it } from 'vitest';
|
|
1013
|
+
* import { defineDiscoveredECVSuite, startEcvServer, stopEcvServer } from '@ionite/ecv';
|
|
1014
|
+
*
|
|
1015
|
+
* let ecv: Awaited<ReturnType<typeof startEcvServer>>;
|
|
1016
|
+
* beforeAll(async () => { ecv = await startEcvServer(); });
|
|
1017
|
+
* afterAll(async () => { await stopEcvServer(); });
|
|
1018
|
+
*
|
|
1019
|
+
* defineDiscoveredECVSuite(
|
|
1020
|
+
* { describe, it, beforeAll, afterAll },
|
|
1021
|
+
* {
|
|
1022
|
+
* ecv: () => ecv,
|
|
1023
|
+
* app: { command: 'bun', args: ['run', 'api'], baseUrl: 'http://localhost:3544' },
|
|
1024
|
+
* basePath: '/api/ionite',
|
|
1025
|
+
* configRetry: true,
|
|
1026
|
+
* },
|
|
1027
|
+
* );
|
|
1028
|
+
* ```
|
|
1029
|
+
*/
|
|
1030
|
+
declare function defineDiscoveredECVSuite(hooks: DiscoveredECVSuiteHooks, config: DiscoveredECVSuiteConfig): void;
|
|
1031
|
+
/**
|
|
1032
|
+
* Print a validation report to console
|
|
1033
|
+
*/
|
|
1034
|
+
declare function printReport(report: ValidationReport): void;
|
|
1035
|
+
export { waitForReady, validateWorkload, validateVaultWebSocketTransport, validateValidatorParity, validateTenantLifecycle, validateTenant, validateSsoIdTokenVerification, validateSecretsHardening, validateSSO, validateRedisStores, validateProtocolSurface, validatePerformanceTuning, validateOtel, validateLfvDelivery, validateIamDelta, validateIAM, validateCapabilities, validateCIAM, validateAuthz, stopEcvServer, startEcvServer, startAppUnderTest, skipTest, setVaultRedisUrl, runTest, resolveBaseUrl, printReport, getVaultRedisUrl, getTenantAuthToken, fetchCapabilitiezManifest, defineECVTests, defineDiscoveredECVSuite, createWorkloadTests, createWorkloadScopeTests, createVaultWebSocketTransportTests, createValidatorParityTests, createTenantTests, createTenantLifecycleTests, createSsoIdTokenVerificationTests, createSecretsHardeningTests, createSSOTests, createRedisStoreTests, createProtocolSurfaceTests, createPerformanceTuningTests, createOtelTests, createOaaProjectionTests, createLfvCallbackTests, createIamDeltaPatchTests, createIAMTests, createHarnessSelfTests, createFetcher, createDiscoveredECVTests, createConfigRetryTests, createConfigLifecycleTests, createConfigBoundaryTests, createCapabilityTests, createCIAMTests, createAuthzClosureTests, capabilitySkipReason, buildEcvCatalog, assertValid, assertEqual, assert, WorkloadValidationConfig, WaitForReadyOptions, ValidationSuiteResult, ValidationResult, ValidationReport, ValidationConfig, TestDef, TenantValidationProfile, TenantValidationConfig, StartAppOptions, SSOValidationConfig, ION_TENANT_SCOPE, ION_IAM_SCOPES, ION_CAPABILITIEZ_SCOPE, IAMValidationConfig, EcvTestContext, EcvServerHandle, EcvCatalogEntry, DiscoveredECVSuiteHooks, DiscoveredECVSuiteConfig, DiscoveredECVConfig, CapabilityValidationConfig, CIAMValidationConfig, AuthzValidationConfig, AppUnderTest };
|