1import * as GCP from "@/GCP";
2import * as Test from "@/Test/Alchemy";
3import * as cloudidentity from "@distilled.cloud/gcp/cloudidentity_v1";
4import { expect } from "alchemy-test";
5import * as Effect from "effect/Effect";
6import * as Schedule from "effect/Schedule";
7import { customer, domain, logLevel, runGroupLifecycle } from "./common.ts";
8
9const { test } = Test.make({ providers: GCP.providers() });
10
11const waitUntilGone = (name: string) =>
12 cloudidentity.getInboundSsoAssignments({ name }).pipe(
13 Effect.as("found" as const),
14 Effect.catchTag("NotFound", () => Effect.succeed("gone" as const)),
15 Effect.repeat({
16 schedule: Schedule.spaced("1 second"),
17 until: (status) => status === "gone",
18 times: 10,
19 }),
20 );
21
22test.provider(
23 "getInboundSsoAssignments on a missing assignment fails with a typed tag",
24 (stack) =>
25 Effect.gen(function* () {
26 yield* stack.destroy();
27
28 const error = yield* Effect.flip(
29 cloudidentity.getInboundSsoAssignments({
30 name: "inboundSsoAssignments/alchemy-missing",
31 }),
32 );
33 expect(error._tag).toEqual("ServiceDisabled");
34
35 yield* stack.destroy();
36 }).pipe(logLevel),
37 {
38 tags: ["provider:gcp", "provider:gcp:cloudidentity", "live"],
39 timeout: 90_000,
40 },
41);
42
43test.provider.skipIf(!!process.env.GCP_TEST_CLOUDIDENTITY)(
44 "createInboundSsoAssignments without Cloud Identity access fails with a typed entitlement error",
45 (stack) =>
46 Effect.gen(function* () {
47 yield* stack.destroy();
48
49 const error = yield* Effect.flip(
50 cloudidentity.createInboundSsoAssignments({
51 body: {
52 customer,
53 targetGroup: "groups/alchemy-missing-group",
54 ssoMode: "SSO_OFF",
55 rank: 1,
56 },
57 }),
58 );
59 expect(error._tag).toEqual("ServiceDisabled");
60
61 yield* stack.destroy();
62 }).pipe(logLevel),
63 {
64 tags: ["provider:gcp", "provider:gcp:cloudidentity", "live"],
65 timeout: 90_000,
66 },
67);
68
69test.provider.skipIf(!runGroupLifecycle)(
70 "create, update, and delete an SSO assignment on a group",
71 (stack) =>
72 Effect.gen(function* () {
73 yield* stack.destroy();
74
75 const created = yield* stack.deploy(
76 Effect.gen(function* () {
77 const group = yield* GCP.CloudIdentity.Group("Eng", {
78 parent: customer,
79 domain,
80 displayName: "Engineering",
81 });
82 const assignment = yield* GCP.CloudIdentity.InboundSsoAssignment(
83 "EngSso",
84 {
85 customer,
86 targetGroup: group.name,
87 ssoMode: "SSO_OFF",
88 rank: 1,
89 },
90 );
91 return { group, assignment };
92 }),
93 );
94
95 expect(
96 created.assignment.name.startsWith("inboundSsoAssignments/"),
97 ).toEqual(true);
98 expect(created.assignment.ssoMode).toEqual("SSO_OFF");
99
100 const fetched = yield* cloudidentity.getInboundSsoAssignments({
101 name: created.assignment.name,
102 });
103 expect(fetched.name).toEqual(created.assignment.name);
104
105 const updated = yield* stack.deploy(
106 Effect.gen(function* () {
107 const group = yield* GCP.CloudIdentity.Group("Eng", {
108 parent: customer,
109 groupKeyId: created.group.groupKeyId,
110 displayName: "Engineering",
111 });
112 const assignment = yield* GCP.CloudIdentity.InboundSsoAssignment(
113 "EngSso",
114 {
115 customer,
116 targetGroup: group.name,
117 ssoMode: "SSO_OFF",
118 rank: 2,
119 },
120 );
121 return { group, assignment };
122 }),
123 );
124
125 expect(updated.assignment.name).toEqual(created.assignment.name);
126 expect(updated.assignment.rank).toEqual(2);
127
128 yield* stack.destroy();
129
130 const gone = yield* waitUntilGone(created.assignment.name);
131 expect(gone).toEqual("gone");
132 }).pipe(logLevel),
133 {
134 tags: ["provider:gcp", "provider:gcp:cloudidentity", "live"],
135 timeout: 90_000,
136 },
137);