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 * as Redacted from "effect/Redacted";
9import { MinimumLogLevel } from "effect/References";
10
11const { test } = Test.make({ providers: Cloudflare.providers() });
12
13const logLevel = Effect.provideService(
14 MinimumLogLevel,
15 process.env.DEBUG ? "Debug" : "Info",
16);
17
18// Device posture integrations require a reachable third-party tenant —
19// Cloudflare validates the configured credentials against the live
20// provider API at create time. Without one, `POST
21// /accounts/{id}/devices/posture/integration` fails with HTTP 400 code
22// 2046 "invalid posture integration request: invalid credentials: ..."
23// — surfaced as the typed `InvalidPostureIntegrationConfig` error
24// (observed: a custom_s2s probe against https://example.com/posture with
25// a real Access service token returns exactly this tag because the
26// endpoint answers 405 instead of a posture payload). The lifecycle test
27// is gated behind a real provider supplied via env; the probe test
28// always runs and pins the typed tag.
29const external = !!process.env.CLOUDFLARE_TEST_POSTURE_INTEGRATION;
30
31test.provider.skipIf(external)(
32 "creates without a real provider surface the typed InvalidPostureIntegrationConfig error",
33 (stack) =>
34 Effect.gen(function* () {
35 const { accountId } = yield* yield* CloudflareEnvironment;
36
37 yield* stack.destroy();
38
39 // A real Access service token isolates the probe to the third-party
40 // validation step (dummy Access creds would fail earlier).
41 const { token } = yield* stack.deploy(
42 Effect.gen(function* () {
43 const token = yield* Cloudflare.Access.ServiceToken("ProbeToken", {
44 name: "alchemy-test-posture-probe-token",
45 });
46 return { token };
47 }),
48 );
49 expect(token.clientId).toBeDefined();
50 expect(token.clientSecret).toBeDefined();
51
52 const error = yield* zeroTrust
53 .createDevicePostureIntegration({
54 accountId,
55 name: "alchemy-posture-probe",
56 type: "custom_s2s",
57 interval: "10m",
58 config: {
59 apiUrl: "https://example.com/posture",
60 clientSecret: "dummy-secret",
61 accessClientId: token.clientId,
62 accessClientSecret: Redacted.value(token.clientSecret!),
63 },
64 })
65 .pipe(Effect.flip);
66 expect(error._tag).toEqual("InvalidPostureIntegrationConfig");
67 if (error._tag === "InvalidPostureIntegrationConfig") {
68 expect(error.message).toContain("invalid posture integration request");
69 }
70
71 yield* stack.destroy();
72 }).pipe(logLevel),
73 {
74 tags: [
75 "provider:cloudflare",
76 "provider:cloudflare:access",
77 "provider:cloudflare:devices",
78 "live",
79 ],
80 timeout: 90_000,
81 },
82);
83
84test.provider.skipIf(!external)(
85 "create, update in place, and destroy a posture integration",
86 (stack) =>
87 Effect.gen(function* () {
88 const { accountId } = yield* yield* CloudflareEnvironment;
89
90 yield* stack.destroy();
91
92 // Requires a reachable custom_s2s endpoint configured via env.
93 const apiUrl = process.env.CLOUDFLARE_TEST_POSTURE_API_URL!;
94 const secret = process.env.CLOUDFLARE_TEST_POSTURE_SECRET!;
95
96 const created = yield* stack.deploy(
97 Effect.gen(function* () {
98 const token = yield* Cloudflare.Access.ServiceToken("S2sToken", {
99 name: "alchemy-test-posture-s2s-token",
100 });
101 const integration =
102 yield* Cloudflare.Devices.DevicePostureIntegration("Custom", {
103 name: "alchemy-test-posture-integration",
104 type: "custom_s2s",
105 interval: "10m",
106 config: {
107 apiUrl,
108 clientSecret: Redacted.make(secret),
109 accessClientId: token.clientId,
110 accessClientSecret: token.clientSecret!,
111 },
112 });
113 return { token, integration };
114 }),
115 );
116
117 expect(created.integration.integrationId).toBeDefined();
118 expect(created.integration.accountId).toEqual(accountId);
119 expect(created.integration.interval).toEqual("10m");
120
121 const live = yield* zeroTrust.getDevicePostureIntegration({
122 accountId,
123 integrationId: created.integration.integrationId,
124 });
125 expect(live.id).toEqual(created.integration.integrationId);
126
127 yield* stack.destroy();
128
129 const gone = yield* zeroTrust
130 .getDevicePostureIntegration({
131 accountId,
132 integrationId: created.integration.integrationId,
133 })
134 .pipe(Effect.flip);
135 expect(gone._tag).toEqual("DevicePostureIntegrationNotFound");
136 }).pipe(logLevel),
137 {
138 tags: [
139 "provider:cloudflare",
140 "provider:cloudflare:access",
141 "provider:cloudflare:devices",
142 "live",
143 ],
144 timeout: 90_000,
145 },
146);
147
148// Canonical `list()` test (account collection): `list()` enumerates every
149// posture integration in the ambient account via the distilled paginated
150// list op and returns the exact `read` Attributes shape. This read-only
151// assertion always runs — without an entitled account / external provider
152// the account simply has no integrations, so `list()` returns a well-typed
153// empty array (Zero Trust `Forbidden` is mapped to `[]`).
154test.provider(
155 "list enumerates posture integrations in the account",
156 (stack) =>
157 Effect.gen(function* () {
158 yield* stack.destroy();
159
160 const provider = yield* Provider.findProvider(
161 Cloudflare.Devices.DevicePostureIntegration,
162 );
163 const all = yield* provider.list();
164
165 expect(Array.isArray(all)).toBe(true);
166 for (const item of all) {
167 expect(typeof item.integrationId).toBe("string");
168 expect(typeof item.accountId).toBe("string");
169 expect(typeof item.type).toBe("string");
170 }
171
172 yield* stack.destroy();
173 }).pipe(logLevel),
174 {
175 tags: ["provider:cloudflare", "provider:cloudflare:devices", "live"],
176 timeout: 90_000,
177 },
178);
179
180// When an entitled account + reachable external provider is supplied via
181// env, deploy a real integration and assert `list()` includes it.
182test.provider.skipIf(!external)(
183 "list includes a deployed posture integration",
184 (stack) =>
185 Effect.gen(function* () {
186 yield* stack.destroy();
187
188 const apiUrl = process.env.CLOUDFLARE_TEST_POSTURE_API_URL!;
189 const secret = process.env.CLOUDFLARE_TEST_POSTURE_SECRET!;
190
191 const { integration } = yield* stack.deploy(
192 Effect.gen(function* () {
193 const token = yield* Cloudflare.Access.ServiceToken("ListS2sToken", {
194 name: "alchemy-test-posture-list-token",
195 });
196 const integration =
197 yield* Cloudflare.Devices.DevicePostureIntegration("ListCustom", {
198 name: "alchemy-test-posture-list-integration",
199 type: "custom_s2s",
200 interval: "10m",
201 config: {
202 apiUrl,
203 clientSecret: Redacted.make(secret),
204 accessClientId: token.clientId,
205 accessClientSecret: token.clientSecret!,
206 },
207 });
208 return { integration };
209 }),
210 );
211
212 const provider = yield* Provider.findProvider(
213 Cloudflare.Devices.DevicePostureIntegration,
214 );
215 const all = yield* provider.list();
216
217 expect(
218 all.some((i) => i.integrationId === integration.integrationId),
219 ).toBe(true);
220
221 yield* stack.destroy();
222 }).pipe(logLevel),
223 {
224 tags: [
225 "provider:cloudflare",
226 "provider:cloudflare:access",
227 "provider:cloudflare:devices",
228 "live",
229 ],
230 timeout: 90_000,
231 },
232);