1import * as Cloudflare from "@/Cloudflare";
2import { CloudflareEnvironment } from "@/Cloudflare/CloudflareEnvironment";
3import * as Test from "@/Test/Alchemy";
4import * as zeroTrust from "@distilled.cloud/cloudflare/zero-trust";
5import { expect } from "alchemy-test";
6import * as Effect from "effect/Effect";
7import { MinimumLogLevel } from "effect/References";
8
9const { test } = Test.make({ providers: Cloudflare.providers() });
10
11const 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.
21const entitled = !!process.env.CLOUDFLARE_TEST_DLP;
22
23test.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
64test.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);