1import * as GCP from "@/GCP";
2import * as Test from "@/Test/Alchemy";
3import * as Core from "@/Test/Core";
4import * as kms from "@distilled.cloud/gcp/cloudkms_v1";
5import { describe, expect } from "alchemy-test";
6import * as Effect from "effect/Effect";
7import { dockerAvailable, expectProbe } from "../bindingHost.ts";
8import KmsBindingsHost, { Cipher } from "./fixtures/bindings-host.ts";
9
10const testOptions = { providers: GCP.providers() };
11const { test, beforeAll, afterAll } = Test.make(testOptions);
12const sharedStack = Core.scratchStack(testOptions, "KmsBindings");
13
14let baseUrl: string;
15let keyName: string;
16let hostAccount: string;
17
18describe.skipIf(!dockerAvailable)(
19 "KMS Bindings",
20 { tags: ["provider:gcp", "provider:gcp:kms", "provider:gcp:run", "live"] },
21 () => {
22 beforeAll(
23 Effect.gen(function* () {
24 yield* sharedStack.destroy();
25 const out = yield* sharedStack.deploy(
26 Effect.gen(function* () {
27 const host = yield* KmsBindingsHost;
28 const key = yield* Cipher;
29 return {
30 uri: host.uri,
31 serviceAccount: host.serviceAccount,
32 key: key.name,
33 };
34 }),
35 );
36 baseUrl = out.uri!;
37 keyName = out.key;
38 hostAccount = out.serviceAccount!;
39 }),
40 { timeout: 900_000 },
41 );
42
43 afterAll(sharedStack.destroy(), { timeout: 600_000 });
44
45 describe("Encrypt / Decrypt", () => {
46 test.provider(
47 "round-trip as the host's service account, granted on the key only",
48 (_stack) =>
49 Effect.gen(function* () {
50 const out = yield* expectProbe<{
51 plaintext: string;
52 ciphertext: string;
53 decrypted: string;
54 }>(baseUrl, "roundTrip");
55 expect(out.ciphertext).not.toEqual(out.plaintext);
56 expect(out.decrypted).toEqual(out.plaintext);
57
58 const policy =
59 yield* kms.getIamPolicyProjectsLocationsKeyRingsCryptoKeys({
60 resource: keyName,
61 });
62 const roles = (policy.bindings ?? [])
63 .filter((binding) =>
64 (binding.members ?? []).includes(
65 `serviceAccount:${hostAccount}`,
66 ),
67 )
68 .map((binding) => binding.role)
69 .sort();
70 expect(roles).toEqual([
71 "roles/cloudkms.cryptoKeyDecrypter",
72 "roles/cloudkms.cryptoKeyEncrypter",
73 ]);
74 }),
75 {
76 tags: ["provider:gcp", "provider:gcp:kms", "live"],
77 timeout: 600_000,
78 },
79 );
80 });
81 },
82);