@ionite/ecv 0.0.23-beta.20260809.2 → 0.0.23-beta.20260812.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 CHANGED
@@ -231,13 +231,6 @@ interface SSOValidationConfig extends ValidationConfig {
231
231
  */
232
232
  expectedAuthorizationUrlPattern?: RegExp;
233
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
234
  * Test user credentials for end-to-end SSO testing
242
235
  * If not provided, only structural tests will run
243
236
  */
@@ -584,91 +577,77 @@ declare function validateCapabilities(config: CapabilityValidationConfig): Promi
584
577
  * Creates a Vitest-compatible test suite for capability catalog validation.
585
578
  */
586
579
  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
- */
580
+ import { CapabilitiezManifest as CapabilitiezManifest2, CapabilityKey as CapabilityKey2, Ionite as Ionite2 } from "@ionite/server";
581
+ /** SDK versions whose runtime manifest is compatible with this ECV catalog. */
582
+ declare const SUPPORTED_SDK_RANGE = ">=0.0.23-beta.20260809.2 <0.1.0";
583
+ /**
584
+ * Known-bad SDK releases rejected by the local validation handshake.
585
+ *
586
+ * This is fast-fail developer feedback only. The ECI remains authoritative for
587
+ * business workflows based on the version facts uploaded with validation runs.
588
+ */
589
+ declare const QUARANTINED_SDK_VERSIONS: readonly string[];
590
+ interface EcvAnnotationContext {
591
+ annotate?: (message: string, type?: string) => void;
592
+ }
593
+ declare function satisfiesSdkRange(version: string, range?: string): boolean;
594
+ interface ECVCatalogConfig extends ValidationConfig {
595
+ /** ionite basePath used by the application under test. @default "/api/ionite" */
596
+ basePath?: string | (() => string);
597
+ /** Override when capabilitiez is not mounted at `${basePath}/capabilitiez`. */
597
598
  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
599
  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
600
  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
- */
601
+ /** ECV mock server URL. Ignored when `ecv` is provided. */
622
602
  ecvUrl?: string;
623
603
  }
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
- */
604
+ declare function fetchCapabilitiezManifest(config: ECVCatalogConfig): Promise<CapabilitiezManifest2>;
605
+ type EcvCatalogUnit = CapabilityKey2 | "tenant.management" | `sdk.${string}` | `meta.${string}`;
630
606
  interface EcvCatalogEntry {
631
- /** Stable machine id (suite + name slug). */
607
+ /** Stable machine ID parsed from the `ECV(...)` title marker. */
632
608
  id: string;
633
- /** Display group: 'SSO' | 'CIAM' | 'IAM' | 'Workload' | 'Authz/OAA' | 'Authz closure' | 'Discovery' | 'Config retry policy'. */
609
+ /** Compliance or SDK unit that owns this assertion. */
610
+ unit: EcvCatalogUnit;
611
+ /** Human-readable reporter group. */
634
612
  suite: string;
635
- /** Human-readable test name. */
613
+ /** Human-readable assertion name. */
636
614
  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>;
615
+ /** Complete portable reporter title. */
616
+ title: string;
617
+ /** Execute the assertion. Manifest is required only for runtime/meta assertions. */
618
+ run: (manifest: CapabilitiezManifest2 | undefined, context?: EcvAnnotationContext) => Promise<void>;
643
619
  }
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>;
620
+ /** Build the metadata tests that describe and validate an ECV run. */
621
+ declare function buildEcvMetaCatalog(claims: () => readonly CapabilityKey2[]): EcvCatalogEntry[];
622
+ /** Build the in-process SDK regression catalog registered by `ecv.sdk()`. */
623
+ declare function buildEcvSdkCatalog(): EcvCatalogEntry[];
624
+ interface EcvTenantCatalogOptions {
625
+ /** Root tenant-management application URL; defaults to the suite setup baseUrl. */
626
+ baseUrl?: ValidationConfig["baseUrl"];
627
+ tenantPath?: string;
628
+ profile?: TenantValidationProfile;
629
+ webhookPath?: string;
630
+ }
631
+ /** Build root tenant-management assertions registered by `ecv.tenants()`. */
632
+ declare function buildEcvTenantCatalog(config: ECVCatalogConfig, options?: EcvTenantCatalogOptions): EcvCatalogEntry[];
633
+ /** Options specific to one explicitly registered capability unit. */
634
+ interface EcvUnitCatalogOptions {
635
+ expectedCallbackErrorPattern?: RegExp;
636
+ }
637
+ /** Build the static entries for one capability selected by the suite builder. */
638
+ declare function buildEcvUnitCatalog(config: ECVCatalogConfig, unit: CapabilityKey2, options?: EcvUnitCatalogOptions): EcvCatalogEntry[];
666
639
  /**
667
640
  * Runs all CIAM validation tests
668
641
  */
669
642
  declare function validateCIAM(config: CIAMValidationConfig): Promise<ValidationSuiteResult>;
670
643
  declare function createCIAMTests(config: CIAMValidationConfig): {
671
644
  tests: Array<TestDef>;
645
+ ext: {
646
+ createCustomerTests: () => Array<TestDef>;
647
+ createMagicLinkTests: () => Array<TestDef>;
648
+ createOidcLoginTests: () => Array<TestDef>;
649
+ createLogoutTests: () => Array<TestDef>;
650
+ };
672
651
  };
673
652
  /**
674
653
  * Lifecycle hardening coverage (AUDIT_HISTORY.md §5.1/§5.2/§5.4): module-readiness re-arm on de-configuration,
@@ -790,6 +769,41 @@ declare function validateProtocolSurface(): Promise<{
790
769
  passed: boolean;
791
770
  error?: string;
792
771
  }[]>;
772
+ import { CreateTenantRequest } from "@ionite/server";
773
+ interface ProvisionTenantOptions {
774
+ /** Running ECV mock used for workload credentials and the tenant config locator. */
775
+ ecv: EcvServerHandle;
776
+ /** Base URL of the root tenant-management application. */
777
+ baseUrl: string;
778
+ /** Tenant-management endpoint. @default "/api/tenants" */
779
+ tenantPath?: string;
780
+ /** Full manager contract or deployer-style creation-only contract. @default "tenantManager" */
781
+ profile?: TenantValidationProfile;
782
+ /** Tenant data. configLocator and webhookUrl default to ECV mock values. */
783
+ tenant: Omit<CreateTenantRequest, "configLocator"> & {
784
+ configLocator?: CreateTenantRequest["configLocator"];
785
+ };
786
+ /** Tenant ionite mount for creation-only deployers. @default "/api/ionite" */
787
+ basePath?: string;
788
+ /** Readiness polling overrides. */
789
+ readiness?: WaitForReadyOptions;
790
+ }
791
+ interface ProvisionedTenant {
792
+ id: string;
793
+ /** URL used as ValidationConfig.baseUrl for the tenant suite. */
794
+ baseUrl: string;
795
+ /** Tenant ionite mount used to locate capabilitiez and protocol routes. */
796
+ basePath: string;
797
+ /** Tenant URL reported by the tenant-management service. */
798
+ tenantUrl: string;
799
+ }
800
+ /**
801
+ * Provision the fixture tenant that another ECV suite will run against.
802
+ *
803
+ * This helper performs the application's real tenant-management flow. It does not
804
+ * register tenant-management assertions; use `ecv.tenants()` for that contract.
805
+ */
806
+ declare function provisionTenant(options: ProvisionTenantOptions): Promise<ProvisionedTenant>;
793
807
  declare function createRedisStoreTests(): {
794
808
  tests: TestDef[];
795
809
  };
@@ -798,37 +812,6 @@ declare function createSecretsHardeningTests(): {
798
812
  tests: TestDef[];
799
813
  };
800
814
  declare function validateSecretsHardening(): Promise<ValidationSuiteResult>;
801
- /**
802
- * Runs all SSO validation tests
803
- */
804
- declare function validateSSO(config: SSOValidationConfig): Promise<ValidationSuiteResult>;
805
- /**
806
- * Creates Vitest-compatible test suite for SSO validation
807
- */
808
- declare function createSSOTests(config: SSOValidationConfig): {
809
- tests: Array<TestDef>;
810
- ext: {
811
- createJITTests: () => Array<TestDef>;
812
- createLogoutTests: () => Array<TestDef>;
813
- createBackChannelLogoutTests: () => Array<TestDef>;
814
- };
815
- };
816
- declare function createSsoIdTokenVerificationTests(): {
817
- tests: TestDef[];
818
- };
819
- declare function validateSsoIdTokenVerification(): Promise<ValidationSuiteResult>;
820
- /**
821
- * Runs all Tenant validation tests
822
- */
823
- declare function validateTenant(config: TenantValidationConfig): Promise<ValidationSuiteResult>;
824
- /**
825
- * Creates Vitest-compatible test suite for Tenant validation
826
- */
827
- declare function createTenantTests(config: TenantValidationConfig): Array<TestDef>;
828
- declare function createTenantLifecycleTests(): {
829
- tests: TestDef[];
830
- };
831
- declare function validateTenantLifecycle(): Promise<ValidationSuiteResult>;
832
815
  type StandardSchemaV1 = {
833
816
  readonly "~standard": {
834
817
  readonly validate: (value: unknown) => {
@@ -891,6 +874,77 @@ declare function assertEqual<T>(actual: T, expected: T, message?: string): void;
891
874
  * @throws Error if validation fails
892
875
  */
893
876
  declare function assertValid(data: unknown, validator: StandardSchemaV1, message?: string): void;
877
+ /**
878
+ * Drive a login from initiation through the callback (optionally tampering the auth code or carrying
879
+ * a `?redirect` param) and return the callback Response plus the minted state. Mock OIDC must be
880
+ * reachable (same wiring the JIT flow relies on).
881
+ */
882
+ declare function runLoginToCallback(config: SSOValidationConfig, fetch: ReturnType<typeof createFetcher>, opts?: {
883
+ redirectParam?: string;
884
+ bogusCode?: boolean;
885
+ }): Promise<{
886
+ callback: Response;
887
+ state: string | null;
888
+ }>;
889
+ /**
890
+ * Helper: Complete a full SSO login flow through the mock server
891
+ *
892
+ * Returns the cookies set after successful authentication
893
+ */
894
+ declare function completeLoginFlow(config: SSOValidationConfig, fetch: ReturnType<typeof createFetcher>): Promise<{
895
+ cookies: Map<string, string>;
896
+ success: boolean;
897
+ error?: string;
898
+ }>;
899
+ /**
900
+ * Runs all SSO validation tests
901
+ */
902
+ declare function validateSSO(config: SSOValidationConfig): Promise<ValidationSuiteResult>;
903
+ /**
904
+ * Creates Vitest-compatible test suite for SSO validation
905
+ */
906
+ declare function createSSOTests(config: SSOValidationConfig): {
907
+ tests: Array<TestDef>;
908
+ ext: {
909
+ createJITTests: () => Array<TestDef>;
910
+ createLogoutTests: () => Array<TestDef>;
911
+ createBackChannelLogoutTests: () => Array<TestDef>;
912
+ createCallbackErrorSurfacedTests: (expectedPattern: RegExp) => Array<TestDef>;
913
+ };
914
+ };
915
+ declare function createSsoIdTokenVerificationTests(): {
916
+ tests: TestDef[];
917
+ };
918
+ declare function validateSsoIdTokenVerification(): Promise<ValidationSuiteResult>;
919
+ /**
920
+ * Runs all Tenant validation tests
921
+ */
922
+ declare function validateTenant(config: TenantValidationConfig): Promise<ValidationSuiteResult>;
923
+ /**
924
+ * Creates Vitest-compatible test suite for Tenant validation
925
+ */
926
+ declare function createTenantTests(config: TenantValidationConfig): Array<TestDef>;
927
+ interface TenantManagementTestConfig extends ValidationConfig {
928
+ /** ECV mock used to mint tenant-management tokens and serve tenant config. */
929
+ ecv: EcvServerHandle | (() => EcvServerHandle);
930
+ /** Tenant-management endpoint. @default "/api/tenants" */
931
+ tenantPath?: string;
932
+ /** Full tenant manager or creation-only deployer contract. @default "tenantManager" */
933
+ profile?: TenantValidationProfile;
934
+ /** Optional app-owned webhook path retained for the lower-level contract tests. */
935
+ webhookPath?: string;
936
+ }
937
+ /**
938
+ * Build the root tenant-management contract used by `ecv.tenants()`.
939
+ *
940
+ * These tests create their own ephemeral tenants and never mutate the fixture tenant
941
+ * returned by the suite's setup function.
942
+ */
943
+ declare function createTenantManagementTests(config: TenantManagementTestConfig): Array<TestDef>;
944
+ declare function createTenantLifecycleTests(): {
945
+ tests: TestDef[];
946
+ };
947
+ declare function validateTenantLifecycle(): Promise<ValidationSuiteResult>;
894
948
  declare function createValidatorParityTests(): {
895
949
  tests: TestDef[];
896
950
  };
@@ -904,6 +958,12 @@ declare function createVaultWebSocketTransportTests(): {
904
958
  };
905
959
  declare function validateVaultWebSocketTransport(): Promise<ValidationSuiteResult>;
906
960
  /**
961
+ * Generated package version embedded in validation result metadata.
962
+ *
963
+ * Keep this synchronized with packages/ecv/package.json via publish.ts.
964
+ */
965
+ declare const ECV_VERSION = "0.0.23-beta.20260812.1";
966
+ /**
907
967
  * Runs all Workload validation tests
908
968
  */
909
969
  declare function validateWorkload(config: WorkloadValidationConfig): Promise<ValidationSuiteResult>;
@@ -912,135 +972,86 @@ declare function validateWorkload(config: WorkloadValidationConfig): Promise<Val
912
972
  */
913
973
  declare function createWorkloadTests(config: WorkloadValidationConfig): Array<TestDef>;
914
974
  import { Ionite as Ionite3 } from "@ionite/server";
915
- /**
916
- * Helper to create a complete Vitest test suite
917
- *
918
- * @example
919
- * ```typescript
920
- * import { describe, it } from 'vitest';
921
- * import { defineECVTests } from '@ionite/ecv';
922
- *
923
- * defineECVTests(describe, it, {
924
- * baseUrl: 'http://localhost:3000',
925
- * sso: true,
926
- * workload: true,
927
- * });
928
- * ```
929
- */
930
- declare function defineECVTests(describe: (name: string, fn: () => void) => void, it: (name: string, fn: () => Promise<void>) => void, config: {
931
- baseUrl: string;
932
- sso?: boolean | SSOValidationConfig;
933
- ciam?: boolean | CIAMValidationConfig;
934
- lfv?: boolean;
935
- /**
936
- * OpenTelemetry module validation. OPT-IN (`otel: true`): the suite starts a process-global
937
- * `NodeSDK`, which registers global OTel providers/diagnostics for the whole test process, so it
938
- * is off by default to avoid interfering with a consumer's own tracing/other suites. In-repo
939
- * coverage still runs it via the discovered `capabilitiez` catalog (always-run).
940
- */
941
- otel?: boolean;
942
- /** KMS token-pool lifecycle validation. Enabled by default; set `false` to omit it. */
943
- kms?: boolean;
944
- protocolSurface?: boolean;
945
- harness?: boolean;
946
- secretsHardening?: boolean;
947
- redisStores?: boolean;
948
- tenantLifecycle?: boolean;
949
- vaultWebsocket?: boolean;
950
- vaultCoordination?: boolean;
951
- idTokenVerification?: boolean;
952
- performanceTuning?: boolean;
953
- validatorParity?: boolean;
954
- iam?: IAMValidationConfig;
955
- workload?: boolean | WorkloadValidationConfig;
956
- tenant?: boolean | TenantValidationConfig;
957
- capabilities?: boolean | CapabilityValidationConfig;
958
- authz?: boolean | AuthzValidationConfig;
959
- }): void;
960
- /**
961
- * Vitest-style lifecycle hooks passed into {@link defineDiscoveredECVSuite}.
962
- *
963
- * The helper takes hooks rather than importing `vitest` so the package stays framework-agnostic.
964
- */
965
- /**
966
- * Minimal Vitest test-context shape used by discovered ECV tests. Vitest's real `TestContext`
967
- * structurally satisfies this (its `skip(note?)` dynamically marks the running test as skipped).
968
- */
975
+ /** Minimal test context used to emit portable JUnit testcase properties when supported. */
969
976
  interface EcvTestContext {
970
- skip: (note?: string) => void;
977
+ annotate?: (message: string, type?: string) => void;
971
978
  }
972
- interface DiscoveredECVSuiteHooks {
979
+ /** Test-framework hooks needed by {@link ecvSuite}. */
980
+ interface EcvSuiteHooks {
973
981
  describe: (name: string, fn: () => void) => void;
974
- it: (name: string, fn: (ctx: EcvTestContext) => Promise<void> | void) => void;
982
+ it: (name: string, fn: (context: EcvTestContext) => Promise<void> | void) => void;
975
983
  beforeAll: (fn: () => Promise<void> | void) => void;
976
- afterAll: (fn: () => Promise<void> | void) => void;
977
984
  }
978
- /**
979
- * Configuration for {@link defineDiscoveredECVSuite}.
980
- */
981
- interface DiscoveredECVSuiteConfig {
982
- /**
983
- * ECV mock server handle (or getter) from `startEcvServer`. The app's connection env is taken from
984
- * `ecv.env`, and IAM/workload/capabilitiez token minting is derived from `ecv.baseUrl`.
985
- */
986
- ecv: EcvServerHandle | (() => EcvServerHandle);
985
+ interface EcvSuiteSetup {
986
+ /** Running ECV mock/control server used for workload token minting. */
987
+ ecv: EcvServerHandle;
988
+ /** URL of the already-running application under test. */
989
+ baseUrl: string;
990
+ /** Runtime ionite mount, useful when setup provisions a tenant dynamically. */
991
+ basePath?: string;
992
+ }
993
+ interface EcvSuiteOptions {
994
+ /** Hooks for the test framework that will own the generated suites. */
995
+ hooks: EcvSuiteHooks;
987
996
  /**
988
- * The application under test to spawn. `ecv.env` is merged in automatically (your `app.env` wins on
989
- * conflicts), so you only specify app-specific variables here.
990
- */
991
- app: StartAppOptions;
992
- /**
993
- * ionite basePath used by the application under test.
994
- * @default "/api/ionite"
997
+ * Caller-owned setup. Start databases, indexes, the ECV mock, and the app in
998
+ * the order your system needs; return only after the app is ready.
995
999
  */
1000
+ setup: () => Promise<EcvSuiteSetup>;
1001
+ /** ionite handler mount. @default "/api/ionite" */
996
1002
  basePath?: string;
997
- /** Timeout (ms) applied to discovered validation requests. */
1003
+ /** Override `${basePath}/capabilitiez`. */
1004
+ capabilitiezPath?: string;
1005
+ /** Request timeout in milliseconds. @default 15000 */
998
1006
  timeout?: number;
999
- /**
1000
- * Opt-in best-practice assertion: when set, a FAILED SSO callback's `Location` must match this
1001
- * pattern (e.g. `/[?&]auth_error=login_failed/`), proving the app surfaces login errors to the user.
1002
- */
1003
- expectedCallbackErrorPattern?: RegExp;
1004
- /**
1005
- * Register the config-retry policy tests alongside discovered tests.
1006
- * @default false
1007
- */
1008
- configRetry?: boolean;
1009
- /**
1010
- * Optional Ionite instance escape hatch for IAM token minting (real-IdP / custom scopes).
1011
- * When omitted, IAM tokens are minted from the ECV mock server.
1012
- */
1007
+ skipTlsVerify?: boolean;
1008
+ headers?: ECVCatalogConfig["headers"];
1009
+ /** Optional IAM token-minting escape hatch for real IdP/custom scope runs. */
1013
1010
  ion?: Ionite3 | (() => Ionite3 | null);
1014
1011
  }
1012
+ interface EcvSsoLoginOptions {
1013
+ /** Register a named assertion that failed callbacks expose this generic error marker. */
1014
+ expectedCallbackErrorPattern?: RegExp;
1015
+ }
1016
+ type EcvTenantsOptions = EcvTenantCatalogOptions;
1017
+ /** Navigable ECV unit registrar returned by {@link ecvSuite}. */
1018
+ interface EcvSuite {
1019
+ sso: {
1020
+ login: (options?: EcvSsoLoginOptions) => void;
1021
+ jit: () => void;
1022
+ logout: () => void;
1023
+ back_channel_logout: () => void;
1024
+ };
1025
+ ciam: {
1026
+ customer: () => void;
1027
+ magic_link: () => void;
1028
+ oidc_login: () => void;
1029
+ logout: () => void;
1030
+ };
1031
+ iam: {
1032
+ users: () => void;
1033
+ groups: () => void;
1034
+ };
1035
+ workload: {
1036
+ incoming: () => void;
1037
+ outgoing: () => void;
1038
+ };
1039
+ authz: {
1040
+ oaa: () => void;
1041
+ };
1042
+ /** Register root tenant-management and cross-tenant isolation assertions. */
1043
+ tenants: (options?: EcvTenantsOptions) => void;
1044
+ /** Register in-process SDK lifecycle and regression assertions. */
1045
+ sdk: () => void;
1046
+ }
1015
1047
  /**
1016
- * Register a complete discovered-ECV suite: spawn the app under test, run config-retry (optional) and
1017
- * capabilitiez-discovered module tests, and tear the app down afterwards.
1048
+ * Create an explicit ECV suite against caller-managed infrastructure.
1018
1049
  *
1019
- * The ECV mock server (and any Redis) lifecycle stays with the caller, since not every project uses Redis.
1020
- *
1021
- * @example
1022
- * ```ts
1023
- * import { afterAll, beforeAll, describe, it } from 'vitest';
1024
- * import { defineDiscoveredECVSuite, startEcvServer, stopEcvServer } from '@ionite/ecv';
1025
- *
1026
- * let ecv: Awaited<ReturnType<typeof startEcvServer>>;
1027
- * beforeAll(async () => { ecv = await startEcvServer(); });
1028
- * afterAll(async () => { await stopEcvServer(); });
1029
- *
1030
- * defineDiscoveredECVSuite(
1031
- * { describe, it, beforeAll, afterAll },
1032
- * {
1033
- * ecv: () => ecv,
1034
- * app: { command: 'bun', args: ['run', 'api'], baseUrl: 'http://localhost:3544' },
1035
- * basePath: '/api/ionite',
1036
- * configRetry: true,
1037
- * },
1038
- * );
1039
- * ```
1040
- */
1041
- declare function defineDiscoveredECVSuite(hooks: DiscoveredECVSuiteHooks, config: DiscoveredECVSuiteConfig): void;
1042
- /**
1043
- * Print a validation report to console
1050
+ * Calling a unit method registers that unit's tests at collection time. Runtime
1051
+ * capabilitiez state resolves endpoint URLs and validates parity; it never
1052
+ * silently changes the selected test set.
1044
1053
  */
1054
+ declare function ecvSuite(config: EcvSuiteOptions): EcvSuite;
1055
+ /** Print the legacy structured report used by the deferred standalone runner. */
1045
1056
  declare function printReport(report: ValidationReport): void;
1046
- export { waitForReady, validateWorkload, validateVaultWebSocketTransport, validateVaultCoordination, validateValidatorParity, validateTenantLifecycle, validateTenant, validateSsoIdTokenVerification, validateSecretsHardening, validateSSO, validateRedisStores, validateProtocolSurface, validatePerformanceTuning, validateOtel, validateLfvDelivery, validateKms, validateIamDelta, validateIAM, validateCapabilities, validateCIAM, validateAuthz, stopEcvServer, startEcvServer, startAppUnderTest, skipTest, setVaultRedisUrl, runTest, resolveBaseUrl, printReport, getVaultRedisUrl, getTenantAuthToken, fetchCapabilitiezManifest, defineECVTests, defineDiscoveredECVSuite, createWorkloadTests, createWorkloadScopeTests, createVaultWebSocketTransportTests, createVaultCoordinationTests, createValidatorParityTests, createTenantTests, createTenantLifecycleTests, createSsoIdTokenVerificationTests, createSecretsHardeningTests, createSSOTests, createRedisStoreTests, createProtocolSurfaceTests, createPerformanceTuningTests, createOtelTests, createOaaProjectionTests, createLfvCallbackTests, createKmsTests, 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 };
1057
+ export { waitForReady, validateWorkload, validateVaultWebSocketTransport, validateVaultCoordination, validateValidatorParity, validateTenantLifecycle, validateTenant, validateSsoIdTokenVerification, validateSecretsHardening, validateSSO, validateRedisStores, validateProtocolSurface, validatePerformanceTuning, validateOtel, validateLfvDelivery, validateKms, validateIamDelta, validateIAM, validateCapabilities, validateCIAM, validateAuthz, stopEcvServer, startEcvServer, startAppUnderTest, skipTest, setVaultRedisUrl, satisfiesSdkRange, runTest, runLoginToCallback, resolveBaseUrl, provisionTenant, printReport, getVaultRedisUrl, getTenantAuthToken, fetchCapabilitiezManifest, ecvSuite, createWorkloadTests, createWorkloadScopeTests, createVaultWebSocketTransportTests, createVaultCoordinationTests, createValidatorParityTests, createTenantTests, createTenantManagementTests, createTenantLifecycleTests, createSsoIdTokenVerificationTests, createSecretsHardeningTests, createSSOTests, createRedisStoreTests, createProtocolSurfaceTests, createPerformanceTuningTests, createOtelTests, createOaaProjectionTests, createLfvCallbackTests, createKmsTests, createIamDeltaPatchTests, createIAMTests, createHarnessSelfTests, createFetcher, createConfigRetryTests, createConfigLifecycleTests, createConfigBoundaryTests, createCapabilityTests, createCIAMTests, createAuthzClosureTests, completeLoginFlow, buildEcvUnitCatalog, buildEcvTenantCatalog, buildEcvSdkCatalog, buildEcvMetaCatalog, assertValid, assertEqual, assert, WorkloadValidationConfig, WaitForReadyOptions, ValidationSuiteResult, ValidationResult, ValidationReport, ValidationConfig, TestDef, TenantValidationProfile, TenantValidationConfig, TenantManagementTestConfig, StartAppOptions, SUPPORTED_SDK_RANGE, SSOValidationConfig, QUARANTINED_SDK_VERSIONS, ProvisionedTenant, ProvisionTenantOptions, ION_TENANT_SCOPE, ION_IAM_SCOPES, ION_CAPABILITIEZ_SCOPE, IAMValidationConfig, EcvUnitCatalogOptions, EcvTestContext, EcvTenantsOptions, EcvTenantCatalogOptions, EcvSuiteSetup, EcvSuiteOptions, EcvSuiteHooks, EcvSuite, EcvSsoLoginOptions, EcvServerHandle, EcvCatalogUnit, EcvCatalogEntry, ECV_VERSION, ECVCatalogConfig, CapabilityValidationConfig, CIAMValidationConfig, AuthzValidationConfig, AppUnderTest };
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{$ as _,A as z,B as A,C as B,D as C,E as D,F as E,G as F,H as G,I as H,J as I,K as J,L as K,M as L,N as M,O as N,P as O,Q as P,R as Q,S as R,T as S,U as T,V as U,W as V,X as W,Y as X,Z as Y,_ as Z,aa as $,b as a,ba as aa,c as b,ca as ba,d as c,da as ca,e as d,ea as da,f as e,fa as ea,g as f,ga as fa,h as g,ha as ga,i as h,ia as ha,j as i,ja as ia,k as j,ka as ja,l as k,la as ka,m as l,ma as la,n as m,na as ma,o as n,oa as na,p as o,pa as oa,q as p,qa as pa,r as q,s as r,t as s,u as t,v as u,w as v,x as w,y as x,z as y}from"./shared/ecv-e6q7dq32.js";export{a as waitForReady,V as validateWorkload,ma as validateVaultWebSocketTransport,U as validateVaultCoordination,ka as validateValidatorParity,ia as validateTenantLifecycle,fa as validateTenant,S as validateSsoIdTokenVerification,ea as validateSecretsHardening,P as validateSSO,ca as validateRedisStores,O as validateProtocolSurface,aa as validatePerformanceTuning,M as validateOtel,K as validateLfvDelivery,I as validateKms,G as validateIamDelta,D as validateIAM,v as validateCapabilities,x as validateCIAM,q as validateAuthz,f as stopEcvServer,e as startEcvServer,b as startAppUnderTest,j as skipTest,c as setVaultRedisUrl,i as runTest,g as resolveBaseUrl,pa as printReport,d as getVaultRedisUrl,u as getTenantAuthToken,X as fetchCapabilitiezManifest,na as defineECVTests,oa as defineDiscoveredECVSuite,W as createWorkloadTests,p as createWorkloadScopeTests,la as createVaultWebSocketTransportTests,T as createVaultCoordinationTests,ja as createValidatorParityTests,ga as createTenantTests,ha as createTenantLifecycleTests,R as createSsoIdTokenVerificationTests,da as createSecretsHardeningTests,Q as createSSOTests,ba as createRedisStoreTests,N as createProtocolSurfaceTests,$ as createPerformanceTuningTests,L as createOtelTests,o as createOaaProjectionTests,J as createLfvCallbackTests,H as createKmsTests,F as createIamDeltaPatchTests,E as createIAMTests,C as createHarnessSelfTests,h as createFetcher,_ as createDiscoveredECVTests,B as createConfigRetryTests,z as createConfigLifecycleTests,A as createConfigBoundaryTests,w as createCapabilityTests,y as createCIAMTests,n as createAuthzClosureTests,Y as capabilitySkipReason,Z as buildEcvCatalog,m as assertValid,l as assertEqual,k as assert,t as ION_TENANT_SCOPE,r as ION_IAM_SCOPES,s as ION_CAPABILITIEZ_SCOPE};
1
+ import{$ as _,A as z,B as A,C as B,D as C,E as D,F as E,G as F,H as G,I as H,J as I,K as J,L as K,M as L,N as M,O as N,P as O,Q as P,R as Q,S as R,T as S,U as T,V as U,W as V,X as W,Y as X,Z as Y,_ as Z,aa as $,b as a,ba as aa,c as b,ca as ba,d as c,da as ca,e as d,ea as da,f as e,fa as ea,g as f,ga as fa,h as g,ha as ga,i as h,ia as ha,j as i,ja as ia,k as j,ka as ja,l as k,la as ka,m as l,ma as la,n as m,na as ma,o as n,oa as na,p as o,pa as oa,q as p,qa as pa,r as q,ra as qa,s as r,sa as ra,t as s,ta as sa,u as t,ua as ta,v as u,va as ua,w as v,wa as va,x as w,xa as wa,y as x,ya as xa,z as y}from"./shared/ecv-0fhy6dss.js";export{a as waitForReady,da as validateWorkload,va as validateVaultWebSocketTransport,ca as validateVaultCoordination,ta as validateValidatorParity,ra as validateTenantLifecycle,_ as validateTenant,Y as validateSsoIdTokenVerification,pa as validateSecretsHardening,V as validateSSO,na as validateRedisStores,S as validateProtocolSurface,la as validatePerformanceTuning,Q as validateOtel,K as validateLfvDelivery,I as validateKms,G as validateIamDelta,D as validateIAM,v as validateCapabilities,x as validateCIAM,q as validateAuthz,f as stopEcvServer,e as startEcvServer,b as startAppUnderTest,j as skipTest,c as setVaultRedisUrl,O as satisfiesSdkRange,i as runTest,T as runLoginToCallback,g as resolveBaseUrl,Z as provisionTenant,xa as printReport,d as getVaultRedisUrl,u as getTenantAuthToken,fa as fetchCapabilitiezManifest,wa as ecvSuite,ea as createWorkloadTests,p as createWorkloadScopeTests,ua as createVaultWebSocketTransportTests,ba as createVaultCoordinationTests,sa as createValidatorParityTests,$ as createTenantTests,aa as createTenantManagementTests,qa as createTenantLifecycleTests,X as createSsoIdTokenVerificationTests,oa as createSecretsHardeningTests,W as createSSOTests,ma as createRedisStoreTests,R as createProtocolSurfaceTests,ka as createPerformanceTuningTests,P as createOtelTests,o as createOaaProjectionTests,J as createLfvCallbackTests,H as createKmsTests,F as createIamDeltaPatchTests,E as createIAMTests,C as createHarnessSelfTests,h as createFetcher,B as createConfigRetryTests,z as createConfigLifecycleTests,A as createConfigBoundaryTests,w as createCapabilityTests,y as createCIAMTests,n as createAuthzClosureTests,U as completeLoginFlow,ja as buildEcvUnitCatalog,ia as buildEcvTenantCatalog,ha as buildEcvSdkCatalog,ga as buildEcvMetaCatalog,m as assertValid,l as assertEqual,k as assert,M as SUPPORTED_SDK_RANGE,N as QUARANTINED_SDK_VERSIONS,t as ION_TENANT_SCOPE,r as ION_IAM_SCOPES,s as ION_CAPABILITIEZ_SCOPE,L as ECV_VERSION};
package/dist/runner.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env bun
2
- import{E as V,H as W,J as y,L as D,Q as x,W as M,a as E,ba as _,ga as A,k as H,la as w,r as N,y as O}from"./shared/ecv-e6q7dq32.js";import{ionite as S,vault as P,vaultConfig as f}from"@ionite/server";import{createValidators as m}from"@ionite/valibot";function L(G,F,X){return{suite:G,passed:!0,tests:[H(F,X)],duration:0,summary:{total:1,passed:0,failed:0,skipped:1}}}async function Z(G,F,X){console.log(`\uD83D\uDCDD Running ${F} validation tests...`);try{let Q=await X();return console.log(` ${Q.passed?"✅":"❌"} ${G}: ${Q.summary.passed}/${Q.summary.total} passed
2
+ import{$ as M,E as V,H as W,J as y,L as D,W as x,a as E,ea as _,k as H,ma as A,r as N,ua as w,y as O}from"./shared/ecv-0fhy6dss.js";import{ionite as S,vault as P,vaultConfig as f}from"@ionite/server";import{createValidators as m}from"@ionite/valibot";function L(G,F,X){return{suite:G,passed:!0,tests:[H(F,X)],duration:0,summary:{total:1,passed:0,failed:0,skipped:1}}}async function Z(G,F,X){console.log(`\uD83D\uDCDD Running ${F} validation tests...`);try{let Q=await X();return console.log(` ${Q.passed?"✅":"❌"} ${G}: ${Q.summary.passed}/${Q.summary.total} passed
3
3
  `),Q}catch(Q){return console.error(` ❌ ${G} tests failed: ${Q instanceof Error?Q.message:String(Q)}
4
4
  `),{suite:G,passed:!1,tests:[{name:`${G} Test Execution`,passed:!1,error:Q instanceof Error?Q.message:String(Q),duration:0}],duration:0,summary:{total:1,passed:0,failed:1,skipped:0}}}}function k(G){let F=P({type:"vault",url:process.env.ION_VAULT_URL,token:process.env.ION_VAULT_TOKEN});return S(f({vault:F,path:G}),{validators:m()})}function p(){let G=process.env.TEST_BASE_URL,F=process.env.ION_VAULT_URL,X=process.env.ION_VAULT_TOKEN,Q=process.env.ION_VAULT_PATH,Y=process.env.RESULTS_CALLBACK_URL;if(!G)throw Error("TEST_BASE_URL environment variable is required");if(!F)throw Error("ION_VAULT_URL environment variable is required");if(!X)throw Error("ION_VAULT_TOKEN environment variable is required");if(!Q)throw Error("ION_VAULT_PATH environment variable is required");if(!Y)throw Error("RESULTS_CALLBACK_URL environment variable is required");return{baseUrl:G,vaultUrl:F,vaultToken:X,vaultPath:Q,callbackUrl:Y}}function R(G){return{baseUrl:G,loginPath:process.env.TEST_SSO_LOGIN_PATH,callbackPath:process.env.TEST_SSO_CALLBACK_PATH,userPath:process.env.TEST_SSO_USER_PATH,logoutPath:process.env.TEST_SSO_LOGOUT_PATH,backChannelLogoutPath:process.env.TEST_SSO_BACKCHANNEL_LOGOUT_PATH}}function U(G,F){return{baseUrl:G,ion:F,scimPath:process.env.TEST_IAM_SCIM_PATH,groupsInboundPath:process.env.TEST_IAM_GROUPS_INBOUND_PATH}}function c(G){return{baseUrl:G,validatePath:process.env.TEST_WORKLOAD_VALIDATE_PATH,jwksPath:process.env.TEST_WORKLOAD_JWKS_PATH}}function b(G){return{baseUrl:G,customerPath:process.env.TEST_CIAM_CUSTOMER_PATH,magicLinkPath:process.env.TEST_CIAM_MAGIC_LINK_PATH,magicLinkLoginPath:process.env.TEST_CIAM_MAGIC_LINK_LOGIN_PATH,logoutPath:process.env.TEST_CIAM_LOGOUT_PATH,backChannelLogoutPath:process.env.TEST_CIAM_BACKCHANNEL_LOGOUT_PATH}}function d(G){let F=process.env.TEST_TENANT_COMPANY_ID?{id:process.env.TEST_TENANT_APP_ID||process.env.TEST_TENANT_COMPANY_ID,companyId:process.env.TEST_TENANT_COMPANY_ID,companyName:process.env.TEST_TENANT_COMPANY_NAME||"Test Company",environmentType:process.env.TEST_TENANT_ENVIRONMENT_TYPE||"POC",email:process.env.TEST_TENANT_EMAIL||"test@example.com",callbackUrl:process.env.TEST_TENANT_CALLBACK_URL,configLocator:{path:process.env.TEST_TENANT_CONFIG_LOCATOR_PATH||"/ecv/test-config",...process.env.TEST_TENANT_CONFIG_LOCATOR_SOURCE?{source:process.env.TEST_TENANT_CONFIG_LOCATOR_SOURCE}:{},...process.env.TEST_TENANT_CONFIG_LOCATOR_TTL?{ttl:Number(process.env.TEST_TENANT_CONFIG_LOCATOR_TTL)}:{}}}:void 0;return{baseUrl:G,tenantPath:process.env.TEST_TENANT_PATH,testTenantData:F}}async function v(G,F){let X=await fetch(G,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({...F,timestamp:F.timestamp.toISOString()})});if(!X.ok){let Q=await X.text().catch(()=>"Unknown error");throw Error(`Failed to post results to callback URL: ${X.status} ${X.statusText} - ${Q}`)}}async function n(){let G=performance.now();try{console.log(`\uD83D\uDE80 Starting Enterprise Control Validation Test Runner...
5
5
  `);let{baseUrl:F,vaultUrl:X,vaultToken:Q,vaultPath:Y,callbackUrl:q}=p();console.log("\uD83D\uDCCB Configuration:"),console.log(` Base URL: ${F}`),console.log(` Vault URL: ${X}`),console.log(` Vault Path: ${Y}`),console.log(` Callback URL: ${q}
@@ -10,13 +10,13 @@ import{E as V,H as W,J as y,L as D,Q as x,W as M,a as E,ba as _,ga as A,k as H,l
10
10
  `)}catch(B){console.error(` ❌ SSO tests failed: ${B instanceof Error?B.message:String(B)}
11
11
  `),J.push({suite:"SSO",passed:!1,tests:[{name:"SSO Test Execution",passed:!1,error:B instanceof Error?B.message:String(B),duration:0}],duration:0,summary:{total:1,passed:0,failed:1,skipped:0}})}console.log("\uD83D\uDCDD Running IAM validation tests...");try{let B=await V(T);J.push(B),console.log(` ${B.passed?"✅":"❌"} IAM: ${B.summary.passed}/${B.summary.total} passed
12
12
  `)}catch(B){console.error(` ❌ IAM tests failed: ${B instanceof Error?B.message:String(B)}
13
- `),J.push({suite:"IAM",passed:!1,tests:[{name:"IAM Test Execution",passed:!1,error:B instanceof Error?B.message:String(B),duration:0}],duration:0,summary:{total:1,passed:0,failed:1,skipped:0}})}console.log("\uD83D\uDCDD Running Workload validation tests...");try{let B=await M(I);J.push(B),console.log(` ${B.passed?"✅":"❌"} Workload: ${B.summary.passed}/${B.summary.total} passed
13
+ `),J.push({suite:"IAM",passed:!1,tests:[{name:"IAM Test Execution",passed:!1,error:B instanceof Error?B.message:String(B),duration:0}],duration:0,summary:{total:1,passed:0,failed:1,skipped:0}})}console.log("\uD83D\uDCDD Running Workload validation tests...");try{let B=await _(I);J.push(B),console.log(` ${B.passed?"✅":"❌"} Workload: ${B.summary.passed}/${B.summary.total} passed
14
14
  `)}catch(B){console.error(` ❌ Workload tests failed: ${B instanceof Error?B.message:String(B)}
15
- `),J.push({suite:"Workload",passed:!1,tests:[{name:"Workload Test Execution",passed:!1,error:B instanceof Error?B.message:String(B),duration:0}],duration:0,summary:{total:1,passed:0,failed:1,skipped:0}})}console.log("\uD83D\uDCDD Running Tenant validation tests...");try{let B=await A(g);J.push(B),console.log(` ${B.passed?"✅":"❌"} Tenant: ${B.summary.passed}/${B.summary.total} passed
15
+ `),J.push({suite:"Workload",passed:!1,tests:[{name:"Workload Test Execution",passed:!1,error:B instanceof Error?B.message:String(B),duration:0}],duration:0,summary:{total:1,passed:0,failed:1,skipped:0}})}console.log("\uD83D\uDCDD Running Tenant validation tests...");try{let B=await M(g);J.push(B),console.log(` ${B.passed?"✅":"❌"} Tenant: ${B.summary.passed}/${B.summary.total} passed
16
16
  `)}catch(B){console.error(` ❌ Tenant tests failed: ${B instanceof Error?B.message:String(B)}
17
17
  `),J.push({suite:"Tenant",passed:!1,tests:[{name:"Tenant Test Execution",passed:!1,error:B instanceof Error?B.message:String(B),duration:0}],duration:0,summary:{total:1,passed:0,failed:1,skipped:0}})}console.log("\uD83D\uDCDD Running CIAM validation tests...");try{let B=await O(C);J.push(B),console.log(` ${B.passed?"✅":"❌"} CIAM: ${B.summary.passed}/${B.summary.total} passed
18
18
  `)}catch(B){console.error(` ❌ CIAM tests failed: ${B instanceof Error?B.message:String(B)}
19
- `),J.push({suite:"CIAM",passed:!1,tests:[{name:"CIAM Test Execution",passed:!1,error:B instanceof Error?B.message:String(B),duration:0}],duration:0,summary:{total:1,passed:0,failed:1,skipped:0}})}J.push(await Z("Authz","Authz",()=>N())),J.push(await Z("IAM Delta","IAM Delta",()=>W())),J.push(await Z("LFV","LFV",()=>D())),J.push(await Z("KMS","KMS token pools",()=>y())),J.push(await Z("Validator parity","Validator parity",()=>w())),J.push(await Z("Performance tuning","Performance tuning",()=>_()));let z="requires the ECV mock-server harness (capabilitiez token broker / Veza receiver); run via defineDiscoveredECVSuite or defineECVTests";J.push(L("Capabilities","Capability catalog",z)),J.push(L("Workload scopes","Workload scope authorization",z));let K=performance.now()-G,j={timestamp:new Date,baseUrl:F,passed:J.every((B)=>B.passed),suites:J,duration:K};console.log("\uD83D\uDCCA Test Summary:"),console.log(` Total Suites: ${J.length}`),console.log(` Passed: ${J.filter((B)=>B.passed).length}`),console.log(` Failed: ${J.filter((B)=>!B.passed).length}`),console.log(` Duration: ${K.toFixed(2)}ms`),console.log(` Overall: ${j.passed?"✅ PASSED":"❌ FAILED"}
19
+ `),J.push({suite:"CIAM",passed:!1,tests:[{name:"CIAM Test Execution",passed:!1,error:B instanceof Error?B.message:String(B),duration:0}],duration:0,summary:{total:1,passed:0,failed:1,skipped:0}})}J.push(await Z("Authz","Authz",()=>N())),J.push(await Z("IAM Delta","IAM Delta",()=>W())),J.push(await Z("LFV","LFV",()=>D())),J.push(await Z("KMS","KMS token pools",()=>y())),J.push(await Z("Validator parity","Validator parity",()=>w())),J.push(await Z("Performance tuning","Performance tuning",()=>A()));let z="requires the ECV mock-server harness (capabilitiez token broker / Veza receiver); run via ecvSuite";J.push(L("Capabilities","Capability catalog",z)),J.push(L("Workload scopes","Workload scope authorization",z));let K=performance.now()-G,j={timestamp:new Date,baseUrl:F,passed:J.every((B)=>B.passed),suites:J,duration:K};console.log("\uD83D\uDCCA Test Summary:"),console.log(` Total Suites: ${J.length}`),console.log(` Passed: ${J.filter((B)=>B.passed).length}`),console.log(` Failed: ${J.filter((B)=>!B.passed).length}`),console.log(` Duration: ${K.toFixed(2)}ms`),console.log(` Overall: ${j.passed?"✅ PASSED":"❌ FAILED"}
20
20
  `),console.log("\uD83D\uDCE4 Posting results to callback URL..."),await v(q,j),console.log(`✅ Results posted successfully
21
21
  `),process.exit(j.passed?0:1)}catch(F){if(console.error(`
22
22
  ❌ Fatal error:`,F instanceof Error?F.message:String(F)),F instanceof Error&&F.stack)console.error(F.stack);process.exit(1)}}if(E.main==E.module)n();