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 originTls from "@distilled.cloud/cloudflare/origin-tls-client-auth";
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 originTls.getSetting({ zoneId }).pipe(
41 Effect.retry({
42 while: (e) => e._tag === "Forbidden",
43 schedule: forbiddenRetrySchedule,
44 times: 8,
45 }),
46 );
47
48// Normalize the singleton to a known baseline so each run starts from the
49// same cloud state regardless of what a previous (possibly interrupted) run
50// left behind.
51const setBaseline = (zoneId: string, enabled: boolean) =>
52 originTls.putSetting({ zoneId, enabled }).pipe(
53 Effect.retry({
54 while: (e) => e._tag === "Forbidden",
55 schedule: forbiddenRetrySchedule,
56 times: 8,
57 }),
58 );
59
60// Both cases toggle the same zone-level AOP singleton; run them serially so they don't corrupt each other's captured `initialEnabled` under the global concurrent test config.
61describe.sequential(
62 "Setting",
63 {
64 tags: [
65 "provider:cloudflare",
66 "provider:cloudflare:origintlsclientauth",
67 "provider:cloudflare:zone",
68 "live",
69 ],
70 },
71 () => {
72 test.provider(
73 "enables AOP and restores the original value on destroy",
74 (stack) =>
75 Effect.gen(function* () {
76 const zoneId = yield* resolveZoneId;
77
78 yield* stack.destroy();
79 // Known baseline: zone-level AOP defaults to disabled.
80 yield* setBaseline(zoneId, false);
81
82 const setting = yield* stack.deploy(
83 Cloudflare.OriginTlsClientAuth.Setting("Aop", {
84 zoneId,
85 enabled: true,
86 }),
87 );
88
89 expect(setting.zoneId).toEqual(zoneId);
90 expect(setting.enabled).toEqual(true);
91 // The pre-management value is captured for restore-on-destroy.
92 expect(setting.initialEnabled).toEqual(false);
93
94 const observed = yield* getSetting(zoneId);
95 expect(observed.enabled).toEqual(true);
96
97 yield* stack.destroy();
98
99 // Destroy restores the captured baseline, not a hardcoded default.
100 const restored = yield* getSetting(zoneId);
101 expect(restored.enabled).toEqual(false);
102 }).pipe(logLevel),
103 );
104
105 test.provider("updates the enabled flag in place", (stack) =>
106 Effect.gen(function* () {
107 const zoneId = yield* resolveZoneId;
108
109 yield* stack.destroy();
110 yield* setBaseline(zoneId, false);
111
112 const enabled = yield* stack.deploy(
113 Cloudflare.OriginTlsClientAuth.Setting("AopUpdate", {
114 zoneId,
115 enabled: true,
116 }),
117 );
118 expect(enabled.enabled).toEqual(true);
119 expect(enabled.initialEnabled).toEqual(false);
120
121 // In-place update — the singleton is never replaced.
122 const disabled = yield* stack.deploy(
123 Cloudflare.OriginTlsClientAuth.Setting("AopUpdate", {
124 zoneId,
125 enabled: false,
126 }),
127 );
128 expect(disabled.enabled).toEqual(false);
129 // The original baseline survives the update.
130 expect(disabled.initialEnabled).toEqual(false);
131
132 const observed = yield* getSetting(zoneId);
133 expect(observed.enabled).toEqual(false);
134
135 yield* stack.destroy();
136
137 const restored = yield* getSetting(zoneId);
138 expect(restored.enabled).toEqual(false);
139 }).pipe(logLevel),
140 );
141
142 // Canonical `list()` test (zone-scoped singleton): there is no account-wide
143 // API for this per-zone setting, so `list()` enumerates every zone via
144 // `listAllZones` and reads the singleton in each. Assert the result is
145 // non-empty and contains the standing test zone.
146 test.provider("list enumerates the setting across all zones", (stack) =>
147 Effect.gen(function* () {
148 const zoneId = yield* resolveZoneId;
149
150 const provider = yield* Provider.findProvider(
151 Cloudflare.OriginTlsClientAuth.Setting,
152 );
153 // Ride out fresh-token 403 blips on the account-wide enumeration, like
154 // every other out-of-band call in this suite.
155 const all = yield* provider.list().pipe(
156 Effect.retry({
157 while: (e) => e._tag === "Forbidden",
158 schedule: forbiddenRetrySchedule,
159 times: 8,
160 }),
161 );
162
163 expect(all.length).toBeGreaterThan(0);
164 expect(all.some((s) => s.zoneId === zoneId)).toBe(true);
165
166 // `stack` is unused here (the singleton always exists on every zone),
167 // but keep the destroy bookend so the harness state stays clean.
168 yield* stack.destroy();
169 }).pipe(logLevel),
170 );
171 },
172);