1import * as AWS from "@/AWS";
2import { PolicyStore, PolicyStoreAlias } from "@/AWS/VerifiedPermissions";
3import * as Test from "@/Test/Alchemy";
4import * as avp from "@distilled.cloud/aws/verifiedpermissions";
5import { expect } from "alchemy-test";
6import * as Effect from "effect/Effect";
7import * as Result from "effect/Result";
8
9const { test } = Test.make({ providers: AWS.providers() });
10
11const findAlias = (aliasName: string) =>
12 avp
13 .getPolicyStoreAlias({ aliasName })
14 .pipe(
15 Effect.catchTag("ResourceNotFoundException", () =>
16 Effect.succeed(undefined),
17 ),
18 );
19
20// CreatePolicyStoreAlias currently rejects every alias name shape with a
21// typed ValidationException in this account/region (probed 2026-07-15 with
22// hyphenated, plain, underscore, slash, and mixed-case names — all fail with
23// "Invalid input"). The API appears not yet generally available. This
24// ungated probe pins the typed error; the full lifecycle below is gated
25// behind AWS_TEST_POLICY_STORE_ALIAS=1 so an enabled account can run it
26// unchanged.
27test.provider(
28 "createPolicyStoreAlias surfaces a typed ValidationException (API not yet available)",
29 (stack) =>
30 Effect.gen(function* () {
31 yield* stack.destroy();
32 const { store } = yield* stack.deploy(
33 Effect.gen(function* () {
34 const store = yield* PolicyStore("Store", {
35 validationMode: "OFF",
36 });
37 return { store };
38 }),
39 );
40 const result = yield* Effect.result(
41 avp.createPolicyStoreAlias({
42 aliasName: "alchemy-probe-alias",
43 policyStoreId: store.policyStoreId,
44 }),
45 );
46 expect(Result.isFailure(result)).toBe(true);
47 if (Result.isFailure(result)) {
48 expect(result.failure._tag).toBe("ValidationException");
49 }
50 yield* stack.destroy();
51 }),
52 {
53 tags: ["provider:aws", "provider:aws:verifiedpermissions", "live"],
54 timeout: 120_000,
55 },
56);
57
58test.provider.skipIf(!process.env.AWS_TEST_POLICY_STORE_ALIAS)(
59 "policy store alias lifecycle: create with generated name, verify, destroy (hard delete)",
60 (stack) =>
61 Effect.gen(function* () {
62 yield* stack.destroy();
63
64 const makeStack = Effect.gen(function* () {
65 const store = yield* PolicyStore("Store", { validationMode: "OFF" });
66 const alias = yield* PolicyStoreAlias("Alias", {
67 policyStoreId: store.policyStoreId,
68 // HardDelete frees the generated name immediately so repeated test
69 // runs never collide with a PendingDeletion alias
70 deletionMode: "HardDelete",
71 });
72 return { store, alias };
73 });
74
75 // create
76 const { store, alias } = yield* stack.deploy(makeStack);
77 expect(alias.aliasName).toBeDefined();
78 expect(alias.aliasArn).toContain(":policy-store-alias/");
79 expect(alias.policyStoreId).toBe(store.policyStoreId);
80
81 // out-of-band verify
82 const created = yield* findAlias(alias.aliasName);
83 expect(created?.policyStoreId).toBe(store.policyStoreId);
84 expect(created?.state).toBe("Active");
85
86 // idempotent redeploy — same alias, no replacement
87 const redeployed = yield* stack.deploy(makeStack);
88 expect(redeployed.alias.aliasName).toBe(alias.aliasName);
89 expect(redeployed.alias.aliasArn).toBe(alias.aliasArn);
90
91 // destroy
92 yield* stack.destroy();
93 const gone = yield* findAlias(alias.aliasName);
94 expect(gone).toBeUndefined();
95 }),
96 {
97 tags: ["provider:aws", "provider:aws:verifiedpermissions", "live"],
98 timeout: 180_000,
99 },
100);