1import * as Cloudflare from "@/Cloudflare";
2import * as Provider from "@/Provider";
3import * as Test from "@/Test/Alchemy";
4import { expect } from "alchemy-test";
5import * as Effect from "effect/Effect";
6import { MinimumLogLevel } from "effect/References";
7import * as Redacted from "effect/Redacted";
8
9const { test } = Test.make({ providers: Cloudflare.providers() });
10
11const logLevel = Effect.provideService(
12 MinimumLogLevel,
13 process.env.DEBUG ? "Debug" : "Info",
14);
15
16// Canonical `list()` test (parent fan-out): secrets are sub-resources of a
17// Secrets Store and there is no account-wide secret enumeration API, so
18// `list()` enumerates every store and lists the secrets inside each. Deploy a
19// store + secret, then assert the deployed secret appears in the result.
20test.provider(
21 "list enumerates the deployed secret across stores",
22 (stack) =>
23 Effect.gen(function* () {
24 yield* stack.destroy();
25
26 const deployed = yield* stack.deploy(
27 Effect.gen(function* () {
28 const store = yield* Cloudflare.SecretsStore.Store("ListSecretStore");
29 return yield* Cloudflare.SecretsStore.Secret("ListSecret", {
30 store,
31 value: Redacted.make("sk-list-test-value"),
32 });
33 }),
34 );
35
36 const provider = yield* Provider.findProvider(
37 Cloudflare.SecretsStore.Secret,
38 );
39 const all = yield* provider.list();
40
41 expect(all.some((s) => s.secretId === deployed.secretId)).toBe(true);
42 const found = all.find((s) => s.secretId === deployed.secretId)!;
43 expect(found.secretName).toEqual(deployed.secretName);
44 expect(found.storeId).toEqual(deployed.storeId);
45
46 yield* stack.destroy();
47 }).pipe(logLevel),
48 { tags: ["provider:cloudflare", "provider:cloudflare:secretsstore", "live"] },
49);
50
51// #995: an interrupted first deploy can persist `creating` props whose parent
52// Outputs were stripped to holes, so `olds.store` survives as `{}`. `read`
53// must treat an unresolved parent reference like a missing one (return
54// `undefined` → plan falls through to the create path) instead of handing
55// `storeId: undefined` to the API and crashing every later plan with a
56// SchemaError defect.
57test.provider(
58 "read treats an unresolved parent store reference as missing",
59 () =>
60 Effect.gen(function* () {
61 const provider = yield* Provider.findProvider(
62 Cloudflare.SecretsStore.Secret,
63 );
64 const attr = yield* provider.read!({
65 id: "OrphanSecret",
66 fqn: "OrphanSecret",
67 instanceId: "orphan-instance",
68 olds: {
69 store: {} as never,
70 value: Redacted.make("sk-orphan"),
71 },
72 output: undefined,
73 });
74 expect(attr).toBeUndefined();
75 }).pipe(logLevel),
76 { tags: ["provider:cloudflare", "provider:cloudflare:secretsstore", "live"] },
77);