| 1 | import * as Cloudflare from "@/Cloudflare"; |
| 2 | import { CloudflareEnvironment } from "@/Cloudflare/CloudflareEnvironment"; |
| 3 | import * as Test from "@/Test/Alchemy"; |
| 4 | import * as zeroTrust from "@distilled.cloud/cloudflare/zero-trust"; |
| 5 | import { expect } from "alchemy-test"; |
| 6 | import * as Effect from "effect/Effect"; |
| 7 | import { MinimumLogLevel } from "effect/References"; |
| 8 | |
| 9 | const { test } = Test.make({ providers: Cloudflare.providers() }); |
| 10 | |
| 11 | const logLevel = Effect.provideService( |
| 12 | MinimumLogLevel, |
| 13 | process.env.DEBUG ? "Debug" : "Info", |
| 14 | ); |
| 15 | |
| 16 | // DLP is a paid Zero Trust add-on. On the standard testing account |
| 17 | // `POST /accounts/{id}/dlp/profiles/custom` fails with HTTP 403 code |
| 18 | // 3314 "Forbidden" — surfaced as the typed `Forbidden` error. The |
| 19 | // lifecycle tests are gated behind an entitled account supplied via env; |
| 20 | // the probe test always runs and pins the typed tag. |
| 21 | const entitled = !!process.env.CLOUDFLARE_TEST_DLP; |
| 22 | |
| 23 | test.provider.skipIf(entitled)( |
| 24 | "unentitled accounts surface the typed Forbidden error", |
| 25 | (stack) => |
| 26 | Effect.gen(function* () { |
| 27 | const { accountId } = yield* yield* CloudflareEnvironment; |
| 28 | |
| 29 | yield* stack.destroy(); |
| 30 | |
| 31 | const profileError = yield* zeroTrust |
| 32 | .createDlpProfileCustom({ |
| 33 | accountId, |
| 34 | name: "alchemy-dlp-entitlement-probe", |
| 35 | entries: [ |
| 36 | { |
| 37 | enabled: true, |
| 38 | name: "probe-entry", |
| 39 | pattern: { regex: "x{9}" }, |
| 40 | }, |
| 41 | ], |
| 42 | }) |
| 43 | .pipe(Effect.flip); |
| 44 | expect(profileError._tag).toEqual("Forbidden"); |
| 45 | |
| 46 | const entryError = yield* zeroTrust |
| 47 | .createDlpEntryCustom({ |
| 48 | accountId, |
| 49 | enabled: true, |
| 50 | name: "alchemy-dlp-entry-probe", |
| 51 | pattern: { regex: "y{9}" }, |
| 52 | }) |
| 53 | .pipe(Effect.flip); |
| 54 | expect(entryError._tag).toEqual("Forbidden"); |
| 55 | |
| 56 | yield* stack.destroy(); |
| 57 | }).pipe(logLevel), |
| 58 | { |
| 59 | tags: ["provider:cloudflare", "provider:cloudflare:dlp", "live"], |
| 60 | timeout: 90_000, |
| 61 | }, |
| 62 | ); |
| 63 | |
| 64 | test.provider.skipIf(!entitled)( |
| 65 | "create, update, and destroy a DLP profile with a standalone entry", |
| 66 | (stack) => |
| 67 | Effect.gen(function* () { |
| 68 | const { accountId } = yield* yield* CloudflareEnvironment; |
| 69 | |
| 70 | yield* stack.destroy(); |
| 71 | |
| 72 | const created = yield* stack.deploy( |
| 73 | Effect.gen(function* () { |
| 74 | const profile = yield* Cloudflare.Dlp.Profile("EmployeeIds", { |
| 75 | name: "alchemy-test-dlp-profile", |
| 76 | description: "v1", |
| 77 | allowedMatchCount: 0, |
| 78 | entries: [ |
| 79 | { |
| 80 | name: "employee-id", |
| 81 | enabled: true, |
| 82 | pattern: { regex: "EMP-[0-9]{6}" }, |
| 83 | }, |
| 84 | ], |
| 85 | }); |
| 86 | const entry = yield* Cloudflare.Dlp.Entry("CardNumber", { |
| 87 | name: "alchemy-test-dlp-entry", |
| 88 | pattern: { regex: "[0-9]{13,16}", validation: "luhn" }, |
| 89 | profileId: profile.profileId, |
| 90 | }); |
| 91 | return { profile, entry }; |
| 92 | }), |
| 93 | ); |
| 94 | |
| 95 | expect(created.profile.profileId).toBeDefined(); |
| 96 | expect(created.profile.entryIds["employee-id"]).toBeDefined(); |
| 97 | expect(created.entry.entryId).toBeDefined(); |
| 98 | expect(created.entry.profileId).toEqual(created.profile.profileId); |
| 99 | |
| 100 | // Description update converges in place — same profile id. |
| 101 | const updated = yield* stack.deploy( |
| 102 | Effect.gen(function* () { |
| 103 | const profile = yield* Cloudflare.Dlp.Profile("EmployeeIds", { |
| 104 | name: "alchemy-test-dlp-profile", |
| 105 | description: "v2", |
| 106 | allowedMatchCount: 3, |
| 107 | entries: [ |
| 108 | { |
| 109 | name: "employee-id", |
| 110 | enabled: true, |
| 111 | pattern: { regex: "EMP-[0-9]{8}" }, |
| 112 | }, |
| 113 | ], |
| 114 | }); |
| 115 | const entry = yield* Cloudflare.Dlp.Entry("CardNumber", { |
| 116 | name: "alchemy-test-dlp-entry", |
| 117 | pattern: { regex: "[0-9]{13,16}", validation: "luhn" }, |
| 118 | profileId: profile.profileId, |
| 119 | }); |
| 120 | return { profile, entry }; |
| 121 | }), |
| 122 | ); |
| 123 | expect(updated.profile.profileId).toEqual(created.profile.profileId); |
| 124 | expect(updated.profile.description).toEqual("v2"); |
| 125 | expect(updated.profile.allowedMatchCount).toEqual(3); |
| 126 | expect(updated.entry.entryId).toEqual(created.entry.entryId); |
| 127 | |
| 128 | yield* stack.destroy(); |
| 129 | |
| 130 | const gone = yield* zeroTrust |
| 131 | .getDlpProfileCustom({ |
| 132 | accountId, |
| 133 | profileId: created.profile.profileId, |
| 134 | }) |
| 135 | .pipe(Effect.flip); |
| 136 | expect(gone._tag).toEqual("DlpProfileNotFound"); |
| 137 | }).pipe(logLevel), |
| 138 | { |
| 139 | tags: ["provider:cloudflare", "provider:cloudflare:dlp", "live"], |
| 140 | timeout: 90_000, |
| 141 | }, |
| 142 | ); |