1import * as Cloudflare from "@/Cloudflare";
2import { CloudflareEnvironment } from "@/Cloudflare/CloudflareEnvironment";
3import { findZoneByName } from "@/Cloudflare/Zone/lookup";
4import * as Provider from "@/Provider";
5import * as Test from "@/Test/Alchemy";
6import * as pqe from "@distilled.cloud/cloudflare/origin-post-quantum-encryption";
7import { describe, expect } from "alchemy-test";
8import * as Effect from "effect/Effect";
9import { MinimumLogLevel } from "effect/References";
10import * as Schedule from "effect/Schedule";
11const { test } = Test.make({ providers: Cloudflare.providers() });
12
13const logLevel = Effect.provideService(
14 MinimumLogLevel,
15 process.env.DEBUG ? "Debug" : "Info",
16);
17
18const zoneName =
19 process.env.CLOUDFLARE_TEST_DNS_ZONE_NAME ?? "alchemy-test-2.us";
20
21const resolveZoneId = Effect.gen(function* () {
22 const { accountId } = yield* yield* CloudflareEnvironment;
23 const zone = yield* findZoneByName({ accountId, name: zoneName });
24 if (!zone) {
25 return yield* Effect.die(
26 new Error(`zone "${zoneName}" not found in account`),
27 );
28 }
29 return zone.id;
30});
31
32// The scoped API token the test harness mints propagates eventually-
33// consistently across Cloudflare's edge — a fresh token intermittently 403s
34// with "Unable to authenticate request". Ride out the blips on the test's
35// own out-of-band calls by retrying the typed `Forbidden` error (part of
36// each operation's error union via distilled patches).
37const forbiddenRetrySchedule = Schedule.exponential("500 millis");
38
39const getSetting = (zoneId: string) =>
40 pqe.getOriginPostQuantumEncryption({ zoneId }).pipe(
41 Effect.retry({
42 while: (e) => e._tag === "Forbidden",
43 schedule: forbiddenRetrySchedule,
44 times: 8,
45 }),
46 );
47
48// Normalize the setting to a known baseline so each run starts from the
49// same cloud state regardless of what a previous (possibly interrupted)
50// run left behind. Cloudflare's documented default is "supported".
51const setBaseline = (
52 zoneId: string,
53 value: Cloudflare.OriginPostQuantumEncryption.Value,
54) =>
55 pqe.putOriginPostQuantumEncryption({ zoneId, value }).pipe(
56 Effect.retry({
57 while: (e) => e._tag === "Forbidden",
58 schedule: forbiddenRetrySchedule,
59 times: 8,
60 }),
61 );
62
63describe.sequential(
64 "OriginPostQuantumEncryption",
65 {
66 tags: [
67 "provider:cloudflare",
68 "provider:cloudflare:originpostquantumencryption",
69 "provider:cloudflare:zone",
70 "live",
71 ],
72 },
73 () => {
74 test.provider(
75 "pins the setting and restores the original value on destroy",
76 (stack) =>
77 Effect.gen(function* () {
78 const zoneId = yield* resolveZoneId;
79
80 yield* stack.destroy();
81 // Known baseline: Cloudflare's default is "supported".
82 yield* setBaseline(zoneId, "supported");
83
84 const setting = yield* stack.deploy(
85 Effect.gen(function* () {
86 return yield* Cloudflare.OriginPostQuantumEncryption.OriginPostQuantumEncryption(
87 "OriginPqe",
88 {
89 zoneId,
90 value: "preferred",
91 },
92 );
93 }),
94 );
95
96 expect(setting.zoneId).toEqual(zoneId);
97 expect(setting.value).toEqual("preferred");
98 // The pre-management value was captured for restore-on-destroy.
99 expect(setting.initialValue).toEqual("supported");
100 expect(setting.editable).toEqual(true);
101
102 const live = yield* getSetting(zoneId);
103 expect(live.value).toEqual("preferred");
104
105 yield* stack.destroy();
106
107 // Destroy restored the value the setting had before we managed it.
108 const restored = yield* getSetting(zoneId);
109 expect(restored.value).toEqual("supported");
110 }).pipe(logLevel),
111 );
112
113 test.provider(
114 "updates the value in place and keeps the captured initial value",
115 (stack) =>
116 Effect.gen(function* () {
117 const zoneId = yield* resolveZoneId;
118
119 yield* stack.destroy();
120 // Start from a non-default baseline so capture-and-restore is
121 // observable: destroy must restore "off", not the documented default.
122 yield* setBaseline(zoneId, "off");
123
124 const initial = yield* stack.deploy(
125 Effect.gen(function* () {
126 return yield* Cloudflare.OriginPostQuantumEncryption.OriginPostQuantumEncryption(
127 "OriginPqe",
128 {
129 zoneId,
130 value: "preferred",
131 },
132 );
133 }),
134 );
135
136 expect(initial.value).toEqual("preferred");
137 expect(initial.initialValue).toEqual("off");
138
139 const updated = yield* stack.deploy(
140 Effect.gen(function* () {
141 return yield* Cloudflare.OriginPostQuantumEncryption.OriginPostQuantumEncryption(
142 "OriginPqe",
143 {
144 zoneId,
145 value: "supported",
146 },
147 );
148 }),
149 );
150
151 // Same singleton updated in place; the original value survives the
152 // update so destroy still restores the pre-management state.
153 expect(updated.value).toEqual("supported");
154 expect(updated.initialValue).toEqual("off");
155
156 const live = yield* getSetting(zoneId);
157 expect(live.value).toEqual("supported");
158
159 yield* stack.destroy();
160
161 // Restored to the captured pre-management value, not the default.
162 const restored = yield* getSetting(zoneId);
163 expect(restored.value).toEqual("off");
164
165 // Leave the zone on Cloudflare's documented default for other tests.
166 yield* setBaseline(zoneId, "supported");
167 }).pipe(logLevel),
168 );
169
170 test.provider(
171 "no-op redeploy converges without changing the setting",
172 (stack) =>
173 Effect.gen(function* () {
174 const zoneId = yield* resolveZoneId;
175
176 yield* stack.destroy();
177 yield* setBaseline(zoneId, "supported");
178
179 const deploy = stack.deploy(
180 Effect.gen(function* () {
181 return yield* Cloudflare.OriginPostQuantumEncryption.OriginPostQuantumEncryption(
182 "OriginPqe",
183 {
184 zoneId,
185 value: "off",
186 },
187 );
188 }),
189 );
190
191 const first = yield* deploy;
192 expect(first.value).toEqual("off");
193 expect(first.initialValue).toEqual("supported");
194
195 // Redeploy with identical props — reconcile observes "off" already
196 // live and skips the PUT; attributes stay stable.
197 const second = yield* deploy;
198 expect(second.value).toEqual("off");
199 expect(second.initialValue).toEqual("supported");
200
201 const live = yield* getSetting(zoneId);
202 expect(live.value).toEqual("off");
203
204 yield* stack.destroy();
205
206 const restored = yield* getSetting(zoneId);
207 expect(restored.value).toEqual("supported");
208 }).pipe(logLevel),
209 );
210
211 // Canonical `list()` test (zone-scoped singleton): there is no account-wide
212 // API for this per-zone setting, so `list()` enumerates every zone via
213 // `listAllZones` and reads the singleton in each. Assert the result is
214 // non-empty and contains the standing test zone.
215 test.provider("list enumerates the setting across all zones", (stack) =>
216 Effect.gen(function* () {
217 const zoneId = yield* resolveZoneId;
218
219 const provider = yield* Provider.findProvider(
220 Cloudflare.OriginPostQuantumEncryption.OriginPostQuantumEncryption,
221 );
222 // The freshly-minted scoped token propagates eventually-consistently, so
223 // the account-wide enumeration intermittently 403s (`Forbidden`) or 401s
224 // (`Unauthorized`). Both are transient here — ride out the blip like
225 // every other out-of-band call in this suite.
226 const all = yield* provider.list().pipe(
227 Effect.retry({
228 while: (e) => e._tag === "Forbidden" || e._tag === "Unauthorized",
229 schedule: forbiddenRetrySchedule,
230 times: 8,
231 }),
232 );
233
234 expect(all.length).toBeGreaterThan(0);
235 expect(all.some((s) => s.zoneId === zoneId)).toBe(true);
236
237 // `stack` is unused here (the singleton always exists on every zone),
238 // but keep the destroy bookend so the harness state stays clean.
239 yield* stack.destroy();
240 }).pipe(logLevel),
241 );
242 },
243);