@ionite/ecv 0.0.23-beta.20260809.2 → 0.0.23-beta.20260812.3

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
  */
@@ -432,31 +425,6 @@ interface TenantValidationConfig extends ValidationConfig {
432
425
  };
433
426
  }
434
427
  /**
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
428
  * Authz / OAA Validation Configuration.
461
429
  *
462
430
  * Validates the Veza OAA projection (`ion.authz.oaa`). The in-process closure tests run with no
@@ -575,100 +543,77 @@ declare function createWorkloadScopeTests(config: AuthzValidationConfig): TestDe
575
543
  * mock server handle is provided, also runs the OAA projection tests against its Veza receiver.
576
544
  */
577
545
  declare function validateAuthz(config?: AuthzValidationConfig): Promise<ValidationSuiteResult>;
546
+ import { CapabilitiezManifest as CapabilitiezManifest2, CapabilityKey as CapabilityKey2, Ionite as Ionite2 } from "@ionite/server";
547
+ /** SDK versions whose runtime manifest is compatible with this ECV catalog. */
548
+ declare const SUPPORTED_SDK_RANGE = ">=0.0.23-beta.20260809.2 <0.1.0";
578
549
  /**
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.
550
+ * Known-bad SDK releases rejected by the local validation handshake.
551
+ *
552
+ * This is fast-fail developer feedback only. The ECI remains authoritative for
553
+ * business workflows based on the version facts uploaded with validation runs.
585
554
  */
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
- */
555
+ declare const QUARANTINED_SDK_VERSIONS: readonly string[];
556
+ interface EcvAnnotationContext {
557
+ annotate?: (message: string, type?: string) => void;
558
+ }
559
+ declare function satisfiesSdkRange(version: string, range?: string): boolean;
560
+ interface ECVCatalogConfig extends ValidationConfig {
561
+ /** ionite basePath used by the application under test. @default "/api/ionite" */
562
+ basePath?: string | (() => string);
563
+ /** Override when capabilitiez is not mounted at `${basePath}/capabilitiez`. */
597
564
  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
565
  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
566
  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
- */
567
+ /** ECV mock server URL. Ignored when `ecv` is provided. */
622
568
  ecvUrl?: string;
623
569
  }
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
- */
570
+ declare function fetchCapabilitiezManifest(config: ECVCatalogConfig): Promise<CapabilitiezManifest2>;
571
+ type EcvCatalogUnit = CapabilityKey2 | "tenant.management" | `sdk.${string}` | `meta.${string}`;
630
572
  interface EcvCatalogEntry {
631
- /** Stable machine id (suite + name slug). */
573
+ /** Stable machine ID parsed from the `ECV(...)` title marker. */
632
574
  id: string;
633
- /** Display group: 'SSO' | 'CIAM' | 'IAM' | 'Workload' | 'Authz/OAA' | 'Authz closure' | 'Discovery' | 'Config retry policy'. */
575
+ /** Compliance or SDK unit that owns this assertion. */
576
+ unit: EcvCatalogUnit;
577
+ /** Human-readable reporter group. */
634
578
  suite: string;
635
- /** Human-readable test name. */
579
+ /** Human-readable assertion name. */
636
580
  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>;
581
+ /** Complete portable reporter title. */
582
+ title: string;
583
+ /** Execute the assertion. Manifest is required only for runtime/meta assertions. */
584
+ run: (manifest: CapabilitiezManifest2 | undefined, context?: EcvAnnotationContext) => Promise<void>;
643
585
  }
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>;
586
+ /** Build the metadata tests that describe and validate an ECV run. */
587
+ declare function buildEcvMetaCatalog(claims: () => readonly CapabilityKey2[]): EcvCatalogEntry[];
588
+ /** Build the in-process SDK regression catalog registered by `ecv.sdk()`. */
589
+ declare function buildEcvSdkCatalog(): EcvCatalogEntry[];
590
+ interface EcvTenantCatalogOptions {
591
+ /** Root tenant-management application URL; defaults to the suite setup baseUrl. */
592
+ baseUrl?: ValidationConfig["baseUrl"];
593
+ tenantPath?: string;
594
+ profile?: TenantValidationProfile;
595
+ webhookPath?: string;
596
+ }
597
+ /** Build root tenant-management assertions registered by `ecv.tenants()`. */
598
+ declare function buildEcvTenantCatalog(config: ECVCatalogConfig, options?: EcvTenantCatalogOptions): EcvCatalogEntry[];
599
+ /** Options specific to one explicitly registered capability unit. */
600
+ interface EcvUnitCatalogOptions {
601
+ expectedCallbackErrorPattern?: RegExp;
602
+ }
603
+ /** Build the static entries for one capability selected by the suite builder. */
604
+ declare function buildEcvUnitCatalog(config: ECVCatalogConfig, unit: CapabilityKey2, options?: EcvUnitCatalogOptions): EcvCatalogEntry[];
666
605
  /**
667
606
  * Runs all CIAM validation tests
668
607
  */
669
608
  declare function validateCIAM(config: CIAMValidationConfig): Promise<ValidationSuiteResult>;
670
609
  declare function createCIAMTests(config: CIAMValidationConfig): {
671
610
  tests: Array<TestDef>;
611
+ ext: {
612
+ createCustomerTests: () => Array<TestDef>;
613
+ createMagicLinkTests: () => Array<TestDef>;
614
+ createOidcLoginTests: () => Array<TestDef>;
615
+ createLogoutTests: () => Array<TestDef>;
616
+ };
672
617
  };
673
618
  /**
674
619
  * Lifecycle hardening coverage (AUDIT_HISTORY.md §5.1/§5.2/§5.4): module-readiness re-arm on de-configuration,
@@ -790,6 +735,41 @@ declare function validateProtocolSurface(): Promise<{
790
735
  passed: boolean;
791
736
  error?: string;
792
737
  }[]>;
738
+ import { CreateTenantRequest } from "@ionite/server";
739
+ interface ProvisionTenantOptions {
740
+ /** Running ECV mock used for workload credentials and the tenant config locator. */
741
+ ecv: EcvServerHandle;
742
+ /** Base URL of the root tenant-management application. */
743
+ baseUrl: string;
744
+ /** Tenant-management endpoint. @default "/api/tenants" */
745
+ tenantPath?: string;
746
+ /** Full manager contract or deployer-style creation-only contract. @default "tenantManager" */
747
+ profile?: TenantValidationProfile;
748
+ /** Tenant data. configLocator and webhookUrl default to ECV mock values. */
749
+ tenant: Omit<CreateTenantRequest, "configLocator"> & {
750
+ configLocator?: CreateTenantRequest["configLocator"];
751
+ };
752
+ /** Tenant ionite mount for creation-only deployers. @default "/api/ionite" */
753
+ basePath?: string;
754
+ /** Readiness polling overrides. */
755
+ readiness?: WaitForReadyOptions;
756
+ }
757
+ interface ProvisionedTenant {
758
+ id: string;
759
+ /** URL used as ValidationConfig.baseUrl for the tenant suite. */
760
+ baseUrl: string;
761
+ /** Tenant ionite mount used to locate capabilitiez and protocol routes. */
762
+ basePath: string;
763
+ /** Tenant URL reported by the tenant-management service. */
764
+ tenantUrl: string;
765
+ }
766
+ /**
767
+ * Provision the fixture tenant that another ECV suite will run against.
768
+ *
769
+ * This helper performs the application's real tenant-management flow. It does not
770
+ * register tenant-management assertions; use `ecv.tenants()` for that contract.
771
+ */
772
+ declare function provisionTenant(options: ProvisionTenantOptions): Promise<ProvisionedTenant>;
793
773
  declare function createRedisStoreTests(): {
794
774
  tests: TestDef[];
795
775
  };
@@ -798,37 +778,6 @@ declare function createSecretsHardeningTests(): {
798
778
  tests: TestDef[];
799
779
  };
800
780
  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
781
  type StandardSchemaV1 = {
833
782
  readonly "~standard": {
834
783
  readonly validate: (value: unknown) => {
@@ -891,6 +840,77 @@ declare function assertEqual<T>(actual: T, expected: T, message?: string): void;
891
840
  * @throws Error if validation fails
892
841
  */
893
842
  declare function assertValid(data: unknown, validator: StandardSchemaV1, message?: string): void;
843
+ /**
844
+ * Drive a login from initiation through the callback (optionally tampering the auth code or carrying
845
+ * a `?redirect` param) and return the callback Response plus the minted state. Mock OIDC must be
846
+ * reachable (same wiring the JIT flow relies on).
847
+ */
848
+ declare function runLoginToCallback(config: SSOValidationConfig, fetch: ReturnType<typeof createFetcher>, opts?: {
849
+ redirectParam?: string;
850
+ bogusCode?: boolean;
851
+ }): Promise<{
852
+ callback: Response;
853
+ state: string | null;
854
+ }>;
855
+ /**
856
+ * Helper: Complete a full SSO login flow through the mock server
857
+ *
858
+ * Returns the cookies set after successful authentication
859
+ */
860
+ declare function completeLoginFlow(config: SSOValidationConfig, fetch: ReturnType<typeof createFetcher>): Promise<{
861
+ cookies: Map<string, string>;
862
+ success: boolean;
863
+ error?: string;
864
+ }>;
865
+ /**
866
+ * Runs all SSO validation tests
867
+ */
868
+ declare function validateSSO(config: SSOValidationConfig): Promise<ValidationSuiteResult>;
869
+ /**
870
+ * Creates Vitest-compatible test suite for SSO validation
871
+ */
872
+ declare function createSSOTests(config: SSOValidationConfig): {
873
+ tests: Array<TestDef>;
874
+ ext: {
875
+ createJITTests: () => Array<TestDef>;
876
+ createLogoutTests: () => Array<TestDef>;
877
+ createBackChannelLogoutTests: () => Array<TestDef>;
878
+ createCallbackErrorSurfacedTests: (expectedPattern: RegExp) => Array<TestDef>;
879
+ };
880
+ };
881
+ declare function createSsoIdTokenVerificationTests(): {
882
+ tests: TestDef[];
883
+ };
884
+ declare function validateSsoIdTokenVerification(): Promise<ValidationSuiteResult>;
885
+ /**
886
+ * Runs all Tenant validation tests
887
+ */
888
+ declare function validateTenant(config: TenantValidationConfig): Promise<ValidationSuiteResult>;
889
+ /**
890
+ * Creates Vitest-compatible test suite for Tenant validation
891
+ */
892
+ declare function createTenantTests(config: TenantValidationConfig): Array<TestDef>;
893
+ interface TenantManagementTestConfig extends ValidationConfig {
894
+ /** ECV mock used to mint tenant-management tokens and serve tenant config. */
895
+ ecv: EcvServerHandle | (() => EcvServerHandle);
896
+ /** Tenant-management endpoint. @default "/api/tenants" */
897
+ tenantPath?: string;
898
+ /** Full tenant manager or creation-only deployer contract. @default "tenantManager" */
899
+ profile?: TenantValidationProfile;
900
+ /** Optional app-owned webhook path retained for the lower-level contract tests. */
901
+ webhookPath?: string;
902
+ }
903
+ /**
904
+ * Build the root tenant-management contract used by `ecv.tenants()`.
905
+ *
906
+ * These tests create their own ephemeral tenants and never mutate the fixture tenant
907
+ * returned by the suite's setup function.
908
+ */
909
+ declare function createTenantManagementTests(config: TenantManagementTestConfig): Array<TestDef>;
910
+ declare function createTenantLifecycleTests(): {
911
+ tests: TestDef[];
912
+ };
913
+ declare function validateTenantLifecycle(): Promise<ValidationSuiteResult>;
894
914
  declare function createValidatorParityTests(): {
895
915
  tests: TestDef[];
896
916
  };
@@ -904,6 +924,12 @@ declare function createVaultWebSocketTransportTests(): {
904
924
  };
905
925
  declare function validateVaultWebSocketTransport(): Promise<ValidationSuiteResult>;
906
926
  /**
927
+ * Generated package version embedded in validation result metadata.
928
+ *
929
+ * Keep this synchronized with packages/ecv/package.json via publish.ts.
930
+ */
931
+ declare const ECV_VERSION = "0.0.23-beta.20260812.3";
932
+ /**
907
933
  * Runs all Workload validation tests
908
934
  */
909
935
  declare function validateWorkload(config: WorkloadValidationConfig): Promise<ValidationSuiteResult>;
@@ -912,135 +938,86 @@ declare function validateWorkload(config: WorkloadValidationConfig): Promise<Val
912
938
  */
913
939
  declare function createWorkloadTests(config: WorkloadValidationConfig): Array<TestDef>;
914
940
  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
- */
941
+ /** Minimal test context used to emit portable JUnit testcase properties when supported. */
969
942
  interface EcvTestContext {
970
- skip: (note?: string) => void;
943
+ annotate?: (message: string, type?: string) => void;
971
944
  }
972
- interface DiscoveredECVSuiteHooks {
945
+ /** Test-framework hooks needed by {@link ecvSuite}. */
946
+ interface EcvSuiteHooks {
973
947
  describe: (name: string, fn: () => void) => void;
974
- it: (name: string, fn: (ctx: EcvTestContext) => Promise<void> | void) => void;
948
+ it: (name: string, fn: (context: EcvTestContext) => Promise<void> | void) => void;
975
949
  beforeAll: (fn: () => Promise<void> | void) => void;
976
- afterAll: (fn: () => Promise<void> | void) => void;
977
950
  }
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);
987
- /**
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;
951
+ interface EcvSuiteSetup {
952
+ /** Running ECV mock/control server used for workload token minting. */
953
+ ecv: EcvServerHandle;
954
+ /** URL of the already-running application under test. */
955
+ baseUrl: string;
956
+ /** Runtime ionite mount, useful when setup provisions a tenant dynamically. */
957
+ basePath?: string;
958
+ }
959
+ interface EcvSuiteOptions {
960
+ /** Hooks for the test framework that will own the generated suites. */
961
+ hooks: EcvSuiteHooks;
992
962
  /**
993
- * ionite basePath used by the application under test.
994
- * @default "/api/ionite"
963
+ * Caller-owned setup. Start databases, indexes, the ECV mock, and the app in
964
+ * the order your system needs; return only after the app is ready.
995
965
  */
966
+ setup: () => Promise<EcvSuiteSetup>;
967
+ /** ionite handler mount. @default "/api/ionite" */
996
968
  basePath?: string;
997
- /** Timeout (ms) applied to discovered validation requests. */
969
+ /** Override `${basePath}/capabilitiez`. */
970
+ capabilitiezPath?: string;
971
+ /** Request timeout in milliseconds. @default 15000 */
998
972
  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
- */
973
+ skipTlsVerify?: boolean;
974
+ headers?: ECVCatalogConfig["headers"];
975
+ /** Optional IAM token-minting escape hatch for real IdP/custom scope runs. */
1013
976
  ion?: Ionite3 | (() => Ionite3 | null);
1014
977
  }
978
+ interface EcvSsoLoginOptions {
979
+ /** Register a named assertion that failed callbacks expose this generic error marker. */
980
+ expectedCallbackErrorPattern?: RegExp;
981
+ }
982
+ type EcvTenantsOptions = EcvTenantCatalogOptions;
983
+ /** Navigable ECV unit registrar returned by {@link ecvSuite}. */
984
+ interface EcvSuite {
985
+ sso: {
986
+ login: (options?: EcvSsoLoginOptions) => void;
987
+ jit: () => void;
988
+ logout: () => void;
989
+ back_channel_logout: () => void;
990
+ };
991
+ ciam: {
992
+ customer: () => void;
993
+ magic_link: () => void;
994
+ oidc_login: () => void;
995
+ logout: () => void;
996
+ };
997
+ iam: {
998
+ users: () => void;
999
+ groups: () => void;
1000
+ };
1001
+ workload: {
1002
+ incoming: () => void;
1003
+ outgoing: () => void;
1004
+ };
1005
+ authz: {
1006
+ oaa: () => void;
1007
+ };
1008
+ /** Register root tenant-management and cross-tenant isolation assertions. */
1009
+ tenants: (options?: EcvTenantsOptions) => void;
1010
+ /** Register in-process SDK lifecycle and regression assertions. */
1011
+ sdk: () => void;
1012
+ }
1015
1013
  /**
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.
1018
- *
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(); });
1014
+ * Create an explicit ECV suite against caller-managed infrastructure.
1029
1015
  *
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
1016
+ * Calling a unit method registers that unit's tests at collection time. Runtime
1017
+ * capabilitiez state resolves endpoint URLs and validates parity; it never
1018
+ * silently changes the selected test set.
1044
1019
  */
1020
+ declare function ecvSuite(config: EcvSuiteOptions): EcvSuite;
1021
+ /** Print the legacy structured report used by the deferred standalone runner. */
1045
1022
  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 };
1023
+ export { waitForReady, validateWorkload, validateVaultWebSocketTransport, validateVaultCoordination, validateValidatorParity, validateTenantLifecycle, validateTenant, validateSsoIdTokenVerification, validateSecretsHardening, validateSSO, validateRedisStores, validateProtocolSurface, validatePerformanceTuning, validateOtel, validateLfvDelivery, validateKms, validateIamDelta, validateIAM, 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, 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, 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,y as x,z as y}from"./shared/ecv-9qs0n38v.js";export{a as waitForReady,ba as validateWorkload,ta as validateVaultWebSocketTransport,aa as validateVaultCoordination,ra as validateValidatorParity,pa as validateTenantLifecycle,Y as validateTenant,W as validateSsoIdTokenVerification,na as validateSecretsHardening,T as validateSSO,la as validateRedisStores,Q as validateProtocolSurface,ja as validatePerformanceTuning,O as validateOtel,I as validateLfvDelivery,G as validateKms,E as validateIamDelta,B as validateIAM,r as validateCIAM,q as validateAuthz,f as stopEcvServer,e as startEcvServer,b as startAppUnderTest,j as skipTest,c as setVaultRedisUrl,M as satisfiesSdkRange,i as runTest,R as runLoginToCallback,g as resolveBaseUrl,X as provisionTenant,va as printReport,d as getVaultRedisUrl,z as getTenantAuthToken,da as fetchCapabilitiezManifest,ua as ecvSuite,ca as createWorkloadTests,p as createWorkloadScopeTests,sa as createVaultWebSocketTransportTests,$ as createVaultCoordinationTests,qa as createValidatorParityTests,Z as createTenantTests,_ as createTenantManagementTests,oa as createTenantLifecycleTests,V as createSsoIdTokenVerificationTests,ma as createSecretsHardeningTests,U as createSSOTests,ka as createRedisStoreTests,P as createProtocolSurfaceTests,ia as createPerformanceTuningTests,N as createOtelTests,o as createOaaProjectionTests,H as createLfvCallbackTests,F as createKmsTests,D as createIamDeltaPatchTests,C as createIAMTests,A as createHarnessSelfTests,h as createFetcher,v as createConfigRetryTests,t as createConfigLifecycleTests,u as createConfigBoundaryTests,s as createCIAMTests,n as createAuthzClosureTests,S as completeLoginFlow,ha as buildEcvUnitCatalog,ga as buildEcvTenantCatalog,fa as buildEcvSdkCatalog,ea as buildEcvMetaCatalog,m as assertValid,l as assertEqual,k as assert,K as SUPPORTED_SDK_RANGE,L as QUARANTINED_SDK_VERSIONS,y as ION_TENANT_SCOPE,w as ION_IAM_SCOPES,x as ION_CAPABILITIEZ_SCOPE,J 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{C as V,F as W,H as y,J as D,U as x,Z as M,a as E,ca as _,k as H,ka as A,r as N,s as O,sa as w}from"./shared/ecv-9qs0n38v.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();