1import * as Cloudflare from "@/Cloudflare";
2import { CloudflareEnvironment } from "@/Cloudflare/CloudflareEnvironment";
3import * as Provider from "@/Provider";
4import * as Test from "@/Test/Alchemy";
5import * as zeroTrust from "@distilled.cloud/cloudflare/zero-trust";
6import { expect } from "alchemy-test";
7import * as Effect from "effect/Effect";
8import { MinimumLogLevel } from "effect/References";
9
10const { test } = Test.make({
11 providers: Cloudflare.providers(),
12 state: Cloudflare.state(),
13});
14
15const logLevel = Effect.provideService(
16 MinimumLogLevel,
17 process.env.DEBUG ? "Debug" : "Info",
18);
19
20test.provider(
21 "create and delete basic allow policy",
22 (stack) =>
23 Effect.gen(function* () {
24 const { accountId } = yield* yield* CloudflareEnvironment;
25
26 yield* stack.destroy();
27
28 const policy = yield* stack.deploy(
29 Effect.gen(function* () {
30 return yield* Cloudflare.Access.Policy("BasicAllowPolicy", {
31 decision: "allow",
32 include: [{ emailDomain: { domain: "example.com" } }],
33 });
34 }),
35 );
36
37 expect(policy.policyId).toBeDefined();
38 expect(policy.decision).toEqual("allow");
39 expect(policy.accountId).toEqual(accountId);
40
41 const actual = yield* zeroTrust.getAccessPolicy({
42 accountId,
43 policyId: policy.policyId,
44 });
45 expect(actual.id).toEqual(policy.policyId);
46 expect(actual.decision).toEqual("allow");
47 expect(actual.include?.length).toEqual(1);
48
49 yield* stack.destroy();
50
51 const afterDestroy = yield* zeroTrust
52 .getAccessPolicy({ accountId, policyId: policy.policyId })
53 .pipe(Effect.catch(() => Effect.succeed(undefined)));
54 expect(afterDestroy).toBeUndefined();
55 }).pipe(logLevel),
56 { tags: ["provider:cloudflare", "provider:cloudflare:access", "live"] },
57);
58
59test.provider(
60 "update mutates includes without replacing",
61 (stack) =>
62 Effect.gen(function* () {
63 const { accountId } = yield* yield* CloudflareEnvironment;
64
65 yield* stack.destroy();
66
67 const initial = yield* stack.deploy(
68 Effect.gen(function* () {
69 return yield* Cloudflare.Access.Policy("UpdatePolicy", {
70 decision: "allow",
71 include: [{ emailDomain: { domain: "example.com" } }],
72 adopt: true,
73 });
74 }),
75 );
76
77 expect(initial.policyId).toBeDefined();
78
79 const updated = yield* stack.deploy(
80 Effect.gen(function* () {
81 return yield* Cloudflare.Access.Policy("UpdatePolicy", {
82 decision: "allow",
83 include: [
84 { emailDomain: { domain: "example.com" } },
85 { emailDomain: { domain: "test.example.com" } },
86 ],
87 adopt: true,
88 });
89 }),
90 );
91
92 expect(updated.policyId).toEqual(initial.policyId);
93
94 const actual = yield* zeroTrust.getAccessPolicy({
95 accountId,
96 policyId: updated.policyId,
97 });
98 expect(actual.include?.length).toEqual(2);
99
100 yield* stack.destroy();
101 }).pipe(logLevel),
102 { tags: ["provider:cloudflare", "provider:cloudflare:access", "live"] },
103);
104
105test.provider(
106 "adopts an out-of-band reusable policy",
107 (stack) =>
108 Effect.gen(function* () {
109 const { accountId } = yield* yield* CloudflareEnvironment;
110 const name = "alchemy-access-policy-adopt-test";
111
112 yield* stack.destroy();
113
114 // Pre-create the policy out of band so adoption has something to find.
115 const preExisting = yield* zeroTrust.createAccessPolicy({
116 accountId,
117 name,
118 decision: "allow",
119 include: [{ emailDomain: { domain: "example.com" } }],
120 });
121 expect(preExisting.id).toBeDefined();
122
123 const adopted = yield* stack.deploy(
124 Effect.gen(function* () {
125 return yield* Cloudflare.Access.Policy("AdoptPolicy", {
126 name,
127 decision: "allow",
128 include: [{ emailDomain: { domain: "example.com" } }],
129 adopt: true,
130 });
131 }),
132 );
133
134 expect(adopted.policyId).toEqual(preExisting.id);
135 expect(adopted.accountId).toEqual(accountId);
136
137 yield* stack.destroy();
138
139 const afterDestroy = yield* zeroTrust
140 .getAccessPolicy({ accountId, policyId: preExisting.id! })
141 .pipe(Effect.catch(() => Effect.succeed(undefined)));
142 expect(afterDestroy).toBeUndefined();
143 }).pipe(logLevel),
144 { tags: ["provider:cloudflare", "provider:cloudflare:access", "live"] },
145);
146
147test.provider(
148 "list enumerates the deployed reusable policy",
149 (stack) =>
150 Effect.gen(function* () {
151 const { accountId } = yield* yield* CloudflareEnvironment;
152
153 yield* stack.destroy();
154
155 const policy = yield* stack.deploy(
156 Effect.gen(function* () {
157 return yield* Cloudflare.Access.Policy("ListPolicy", {
158 decision: "allow",
159 include: [{ emailDomain: { domain: "example.com" } }],
160 });
161 }),
162 );
163
164 const provider = yield* Provider.findProvider(Cloudflare.Access.Policy);
165 const all = yield* provider.list();
166
167 const match = all.find((p) => p.policyId === policy.policyId);
168 expect(match).toBeDefined();
169 expect(match?.accountId).toEqual(accountId);
170 expect(match?.decision).toEqual("allow");
171
172 yield* stack.destroy();
173 }).pipe(logLevel),
174 { tags: ["provider:cloudflare", "provider:cloudflare:access", "live"] },
175);