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 { describe, expect } from "alchemy-test";
7import * as Effect from "effect/Effect";
8import { MinimumLogLevel } from "effect/References";
9const { test } = Test.make({ providers: Cloudflare.providers() });
10
11const logLevel = Effect.provideService(
12 MinimumLogLevel,
13 process.env.DEBUG ? "Debug" : "Info",
14);
15
16// Gate on the dedicated env var so this test only runs in environments
17// the operator has explicitly opted in to mutating the WARP default
18// profile of.
19const ENABLED = process.env.CLOUDFLARE_TEST_DEVICES === "1";
20const skip = !ENABLED;
21
22// Both cases mutate the same account-level WARP default device profile
23// singleton; run them serially so they don't corrupt each other's captured
24// baseline under the global concurrent test config.
25describe.sequential(
26 "DefaultProfile",
27 { tags: ["provider:cloudflare", "provider:cloudflare:devices", "live"] },
28 () => {
29 test.provider.skipIf(skip)(
30 "reads the existing default device profile without mutating it",
31 (stack) =>
32 Effect.gen(function* () {
33 const { accountId } = yield* yield* CloudflareEnvironment;
34
35 const before = yield* zeroTrust.getDevicePolicyDefault({ accountId });
36
37 const profile = yield* stack.deploy(
38 Effect.gen(function* () {
39 return yield* Cloudflare.Devices.DeviceDefaultProfile(
40 "Default",
41 {},
42 );
43 }),
44 );
45
46 expect(profile.accountId).toEqual(accountId);
47 expect(["include", "exclude"]).toContain(profile.mode);
48
49 // Nothing supplied => no PATCH, no PUTs => observed state matches before.
50 const after = yield* zeroTrust.getDevicePolicyDefault({ accountId });
51 expect(after.captivePortal ?? null).toEqual(
52 before.captivePortal ?? null,
53 );
54 expect(after.allowedToLeave ?? null).toEqual(
55 before.allowedToLeave ?? null,
56 );
57
58 // Singleton: delete is a no-op, so destroy must NOT remove the profile.
59 yield* stack.destroy();
60 const stillThere = yield* zeroTrust.getDevicePolicyDefault({
61 accountId,
62 });
63 expect(stillThere).toBeDefined();
64 }).pipe(logLevel),
65 );
66
67 test.provider.skipIf(skip)(
68 "toggles captivePortal and restores the original value",
69 (stack) =>
70 Effect.gen(function* () {
71 const { accountId } = yield* yield* CloudflareEnvironment;
72
73 const original = yield* zeroTrust.getDevicePolicyDefault({
74 accountId,
75 });
76 const originalCaptive = original.captivePortal ?? 180;
77
78 // Step 1 — set to 180 seconds.
79 const a = yield* stack.deploy(
80 Effect.gen(function* () {
81 return yield* Cloudflare.Devices.DeviceDefaultProfile("Default", {
82 captivePortal: 180,
83 });
84 }),
85 );
86 expect(a.captivePortal).toEqual(180);
87 const live1 = yield* zeroTrust.getDevicePolicyDefault({ accountId });
88 expect(live1.captivePortal).toEqual(180);
89
90 // Step 2 — flip to 360.
91 const b = yield* stack.deploy(
92 Effect.gen(function* () {
93 return yield* Cloudflare.Devices.DeviceDefaultProfile("Default", {
94 captivePortal: 360,
95 });
96 }),
97 );
98 expect(b.captivePortal).toEqual(360);
99 const live2 = yield* zeroTrust.getDevicePolicyDefault({ accountId });
100 expect(live2.captivePortal).toEqual(360);
101
102 // Restore via a final deploy so the account is not left mutated.
103 yield* stack.deploy(
104 Effect.gen(function* () {
105 return yield* Cloudflare.Devices.DeviceDefaultProfile("Default", {
106 captivePortal: originalCaptive,
107 });
108 }),
109 );
110
111 yield* stack.destroy();
112 }).pipe(logLevel),
113 );
114
115 // Canonical `list()` test (account-scoped singleton): there is exactly one
116 // default device profile per account and no enumeration API, so `list()`
117 // reads the single profile and returns it as a one-element array — exactly
118 // mirroring `read`. Read-only, so it is NOT gated behind the mutation env
119 // var; it only requires the account to have Zero Trust / WARP entitlement.
120 test.provider(
121 "list returns the singleton default device profile",
122 (stack) =>
123 Effect.gen(function* () {
124 const { accountId } = yield* yield* CloudflareEnvironment;
125
126 yield* stack.destroy();
127
128 const provider = yield* Provider.findProvider(
129 Cloudflare.Devices.DeviceDefaultProfile,
130 );
131 const all = yield* provider.list();
132
133 // Account singleton: exactly one element, well-typed Attributes.
134 expect(all.length).toEqual(1);
135 expect(all[0].accountId).toEqual(accountId);
136 expect(["include", "exclude"]).toContain(all[0].mode);
137
138 yield* stack.destroy();
139 }).pipe(logLevel),
140 );
141 },
142);