1import * as GCP from "@/GCP";
2import * as Test from "@/Test/Alchemy";
3import * as assuredworkloads from "@distilled.cloud/gcp/assuredworkloads_v1";
4import * as resourcemanager from "@distilled.cloud/gcp/cloudresourcemanager_v3";
5import { expect } from "alchemy-test";
6import * as Effect from "effect/Effect";
7import { MinimumLogLevel } from "effect/References";
8import * as Schedule from "effect/Schedule";
9import { GcpEnvironment } from "@/GCP/Environment";
10
11const { test } = Test.make({ providers: GCP.providers() });
12
13const logLevel = Effect.provideService(
14 MinimumLogLevel,
15 process.env.DEBUG ? "Debug" : "Info",
16);
17
18const defaultLocation = "us-central1";
19
20// Workloads live under an organization the credentials administer. Set
21// GOOGLE_ORGANIZATION_ID and GOOGLE_BILLING_ACCOUNT to run the lifecycle.
22const organizationId = process.env.GOOGLE_ORGANIZATION_ID?.trim();
23const organization = organizationId
24 ? organizationId.startsWith("organizations/")
25 ? organizationId
26 : `organizations/${organizationId}`
27 : undefined;
28
29const waitUntilGone = (name: string) =>
30 assuredworkloads.getOrganizationsLocationsWorkloads({ name }).pipe(
31 Effect.as("found" as const),
32 Effect.catchTag("NotFound", () => Effect.succeed("gone" as const)),
33 Effect.repeat({
34 schedule: Schedule.spaced("2 seconds"),
35 until: (status) => status === "gone",
36 times: 10,
37 }),
38 );
39
40const billingAccount = process.env.GOOGLE_BILLING_ACCOUNT
41 ? process.env.GOOGLE_BILLING_ACCOUNT.startsWith("billingAccounts/")
42 ? process.env.GOOGLE_BILLING_ACCOUNT
43 : `billingAccounts/${process.env.GOOGLE_BILLING_ACCOUNT}`
44 : undefined;
45
46const runLifecycle =
47 organization !== undefined &&
48 billingAccount !== undefined &&
49 !process.env.FAST;
50
51test.provider.skipIf(organization === undefined)(
52 "getOrganizationsLocationsWorkloads on a missing workload fails with NotFound",
53 (stack) =>
54 Effect.gen(function* () {
55 yield* stack.destroy();
56
57 const error = yield* Effect.flip(
58 assuredworkloads.getOrganizationsLocationsWorkloads({
59 name: `${organization}/locations/${defaultLocation}/workloads/alchemy-missing`,
60 }),
61 );
62 expect(error._tag).toEqual("NotFound");
63
64 yield* stack.destroy();
65 }).pipe(logLevel),
66 {
67 tags: ["provider:gcp", "provider:gcp:assuredworkloads", "live"],
68 timeout: 90_000,
69 },
70);
71
72test.provider.skipIf(organization !== undefined)(
73 "getOrganizationsLocationsWorkloads without organization access fails with Forbidden",
74 (stack) =>
75 Effect.gen(function* () {
76 const { project } = yield* GcpEnvironment.current;
77 yield* stack.destroy();
78
79 const parent = yield* resourcemanager.getProjects({
80 name: `projects/${project}`,
81 });
82 // "Permission 'assuredworkloads.workload.get' denied on resource ...
83 // (or it may not exist)": the testing credentials hold no
84 // organization-level Assured Workloads role.
85 const error = yield* Effect.flip(
86 assuredworkloads.getOrganizationsLocationsWorkloads({
87 name: `${parent.parent}/locations/${defaultLocation}/workloads/alchemy-missing`,
88 }),
89 );
90 expect(error._tag).toEqual("Forbidden");
91
92 yield* stack.destroy();
93 }).pipe(logLevel),
94 {
95 tags: ["provider:gcp", "provider:gcp:assuredworkloads", "live"],
96 timeout: 90_000,
97 },
98);
99
100test.provider.skipIf(!runLifecycle)(
101 "create, update, and delete a workload",
102 (stack) =>
103 Effect.gen(function* () {
104 yield* stack.destroy();
105
106 const created = yield* stack.deploy(
107 Effect.gen(function* () {
108 return yield* GCP.AssuredWorkloads.Workload("Regulated", {
109 organization: organization!,
110 location: defaultLocation,
111 displayName: "alchemy test",
112 complianceRegime: "US_REGIONAL_ACCESS",
113 billingAccount,
114 labels: { env: "test" },
115 });
116 }),
117 );
118
119 expect(created.workloadId).toEqual(expect.any(String));
120 expect(created.organization).toEqual(organization);
121 expect(created.location).toEqual(defaultLocation);
122 expect(created.name).toEqual(
123 `${organization}/locations/${defaultLocation}/workloads/${created.workloadId}`,
124 );
125 expect(created.displayName).toEqual("alchemy test");
126 expect(created.complianceRegime).toEqual("US_REGIONAL_ACCESS");
127 expect(created.labels).toMatchObject({ env: "test" });
128
129 const fetched =
130 yield* assuredworkloads.getOrganizationsLocationsWorkloads({
131 name: created.name,
132 });
133 expect(fetched.name).toEqual(created.name);
134 expect(fetched.labels?.env).toEqual("test");
135 expect(fetched.labels?.["alchemy-id"]).toEqual(expect.any(String));
136
137 const updated = yield* stack.deploy(
138 Effect.gen(function* () {
139 return yield* GCP.AssuredWorkloads.Workload("Regulated", {
140 organization: organization!,
141 location: defaultLocation,
142 displayName: "alchemy prod",
143 complianceRegime: "US_REGIONAL_ACCESS",
144 billingAccount,
145 labels: { env: "prod", role: "aw" },
146 violationNotificationsEnabled: false,
147 });
148 }),
149 );
150
151 expect(updated.name).toEqual(created.name);
152 expect(updated.workloadId).toEqual(created.workloadId);
153 expect(updated.displayName).toEqual("alchemy prod");
154 expect(updated.labels).toMatchObject({ env: "prod", role: "aw" });
155 expect(updated.violationNotificationsEnabled).toEqual(false);
156
157 yield* stack.destroy();
158
159 const gone = yield* waitUntilGone(created.name);
160 expect(gone).toEqual("gone");
161 }).pipe(logLevel),
162 {
163 tags: ["provider:gcp", "provider:gcp:assuredworkloads", "live"],
164 timeout: 120_000,
165 },
166);