@volter/twin-cloudflare 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/README.md +223 -0
- package/dist/r2/src/endpoint.d.ts +14 -0
- package/dist/r2/src/endpoint.js +30 -0
- package/dist/r2/src/fetch.d.ts +7 -0
- package/dist/r2/src/fetch.js +230 -0
- package/dist/r2/src/generated/surface.gen.json +1 -0
- package/dist/r2/src/manifest.d.ts +22 -0
- package/dist/r2/src/manifest.js +69 -0
- package/dist/r2/src/semantics/buckets.d.ts +18 -0
- package/dist/r2/src/semantics/buckets.js +145 -0
- package/dist/r2/src/semantics/objects.d.ts +8 -0
- package/dist/r2/src/semantics/objects.js +252 -0
- package/dist/r2/src/wire.d.ts +54 -0
- package/dist/r2/src/wire.js +120 -0
- package/dist/src/cli.d.ts +2 -0
- package/dist/src/cli.js +26 -0
- package/dist/src/cloudflare-budget.d.ts +22 -0
- package/dist/src/cloudflare-budget.js +40 -0
- package/dist/src/cloudflare-capabilities.d.ts +6 -0
- package/dist/src/cloudflare-capabilities.js +1161 -0
- package/dist/src/cloudflare-common.d.ts +59 -0
- package/dist/src/cloudflare-common.js +142 -0
- package/dist/src/cloudflare-conformance.d.ts +6 -0
- package/dist/src/cloudflare-conformance.js +251 -0
- package/dist/src/cloudflare-connector.d.ts +53 -0
- package/dist/src/cloudflare-connector.js +418 -0
- package/dist/src/cloudflare-openapi-operations.d.ts +10 -0
- package/dist/src/cloudflare-openapi-operations.js +3336 -0
- package/dist/src/cloudflare-provisioning.d.ts +5 -0
- package/dist/src/cloudflare-provisioning.js +2097 -0
- package/dist/src/cloudflare-r2.d.ts +121 -0
- package/dist/src/cloudflare-r2.js +138 -0
- package/dist/src/cloudflare-server.d.ts +17 -0
- package/dist/src/cloudflare-server.js +101 -0
- package/dist/src/cloudflare-twin.d.ts +14 -0
- package/dist/src/cloudflare-twin.js +762 -0
- package/dist/src/cloudflare-worker-assets.d.ts +25 -0
- package/dist/src/cloudflare-worker-assets.js +192 -0
- package/dist/src/index.d.ts +9 -0
- package/dist/src/index.js +69 -0
- package/dist/src/screens/dashboard.d.ts +3 -0
- package/dist/src/screens/dashboard.js +265 -0
- package/package.json +56 -0
- package/src/cli.ts +25 -0
- package/src/cloudflare-budget.ts +61 -0
- package/src/cloudflare-capabilities.ts +1107 -0
- package/src/cloudflare-common.ts +183 -0
- package/src/cloudflare-conformance.ts +204 -0
- package/src/cloudflare-connector.ts +443 -0
- package/src/cloudflare-openapi-operations.ts +3344 -0
- package/src/cloudflare-provisioning.ts +1969 -0
- package/src/cloudflare-r2.ts +173 -0
- package/src/cloudflare-server.ts +109 -0
- package/src/cloudflare-twin.ts +714 -0
- package/src/cloudflare-worker-assets.ts +207 -0
- package/src/index.ts +112 -0
- package/src/screens/dashboard.tsx +297 -0
|
@@ -0,0 +1,1107 @@
|
|
|
1
|
+
// Honest top-down Cloudflare denominator: exactly one capability per HTTP operation
|
|
2
|
+
// in Cloudflare's first-party OpenAPI 4.0.0 document, plus an explicitly separate
|
|
3
|
+
// connector surface. The operation census is
|
|
4
|
+
// generated from cloudflare/api-schemas commit 2ac8369e9b63dccacee1a2284e95bb819f05b307.
|
|
5
|
+
import { mkdtempSync, rmSync } from 'node:fs';
|
|
6
|
+
import { tmpdir } from 'node:os';
|
|
7
|
+
import { join } from 'node:path';
|
|
8
|
+
import { checkCapabilities, type CapabilityReport, type CapabilitySpec, verifyBoundary } from '@volter/world-tooling';
|
|
9
|
+
import { applyTwinWrite, deployableEntries, projectResources } from '@volter/world-core';
|
|
10
|
+
import { handleCloudflareTwinRequest, type CloudflareResponse } from './cloudflare-twin.ts';
|
|
11
|
+
import {
|
|
12
|
+
pullCloudflareState,
|
|
13
|
+
performCloudflareAction,
|
|
14
|
+
syncCloudflareFromReal,
|
|
15
|
+
type CloudflareExecute,
|
|
16
|
+
} from './cloudflare-connector.ts';
|
|
17
|
+
import { CloudflareBudget, CloudflareBudgetError, CLOUDFLARE_BUDGET_CEILING, cloudflareCallWeight } from './cloudflare-budget.ts';
|
|
18
|
+
import { CLOUDFLARE_OPENAPI_OPERATIONS } from './cloudflare-openapi-operations.ts';
|
|
19
|
+
|
|
20
|
+
// Independent official SDK namespace census. It is not used as a denominator: the
|
|
21
|
+
// finer and complete OpenAPI method+path inventory below is the one manifest granularity.
|
|
22
|
+
export const CLOUDFLARE_OFFICIAL_AREAS = [
|
|
23
|
+
'abuse-reports', 'accounts', 'acm', 'addressing', 'ai', 'ai-audit', 'ai-gateway', 'ai-security', 'aisearch',
|
|
24
|
+
'alerting', 'analytics-query', 'api-gateway', 'argo', 'audit-logs', 'billing', 'bot-management', 'botnet-feed',
|
|
25
|
+
'brand-protection', 'browser-rendering', 'cache', 'calls', 'certificate-authorities', 'client-certificates',
|
|
26
|
+
'cloud-connector', 'cloudforce-one', 'connectivity', 'content-scanning', 'csam-scanner', 'custom-certificates',
|
|
27
|
+
'custom-csrs', 'custom-hostnames', 'custom-nameservers', 'custom-pages', 'd1', 'dcv-delegation', 'ddos-protection',
|
|
28
|
+
'diagnostics', 'dls', 'dns', 'dns-firewall', 'durable-objects', 'email-auth', 'email-routing', 'email-security',
|
|
29
|
+
'email-sending', 'filters', 'firewall', 'flagship', 'fraud', 'google-tag-gateway', 'healthchecks', 'hostnames',
|
|
30
|
+
'hyperdrive', 'iam', 'images', 'intel', 'ips', 'keyless-certificates', 'kv', 'leaked-credential-checks',
|
|
31
|
+
'load-balancers', 'logpush', 'logs', 'magic-cloud-networking', 'magic-network-monitoring', 'magic-transit',
|
|
32
|
+
'managed-transforms', 'memberships', 'moq', 'mtls-certificates', 'network-interconnects', 'organizations',
|
|
33
|
+
'origin-ca-certificates', 'origin-post-quantum-encryption', 'origin-tls-client-auth', 'origin-tls-compliance-modes',
|
|
34
|
+
'page-rules', 'page-shield', 'pages', 'pipelines', 'precursor', 'queues', 'r2', 'r2-data-catalog', 'radar',
|
|
35
|
+
'rate-limits', 'realtime-kit', 'registrar', 'registrar-sandbox', 'request-tracers', 'resource-sharing',
|
|
36
|
+
'resource-tagging', 'rules', 'rulesets', 'rum', 'schema-validation', 'secrets-store', 'security-center',
|
|
37
|
+
'security-txt', 'snippets', 'spectrum', 'speed', 'ssl', 'stream', 'tenant-custom-nameservers', 'tenants',
|
|
38
|
+
'token-validation', 'turnstile', 'url-normalization', 'url-scanner', 'user', 'vectorize', 'vulnerability-scanner',
|
|
39
|
+
'waiting-rooms', 'web3', 'workers', 'workers-for-platforms', 'workflows', 'zaraz', 'zero-trust', 'zones',
|
|
40
|
+
] as const;
|
|
41
|
+
|
|
42
|
+
export const CLOUDFLARE_OPENAPI_AREAS = [...new Set(CLOUDFLARE_OPENAPI_OPERATIONS.map((operation) => operation.area))].sort();
|
|
43
|
+
export const CLOUDFLARE_AREAS = [...new Set([...CLOUDFLARE_OPENAPI_AREAS, 'connector'])].sort();
|
|
44
|
+
|
|
45
|
+
const AT = '2026-08-21T00:00:00.000Z';
|
|
46
|
+
const ACCOUNT = 'a'.repeat(32);
|
|
47
|
+
const ZONE = 'b'.repeat(32);
|
|
48
|
+
const VENDOR_TUNNEL = '11111111-2222-4333-a444-555555555555';
|
|
49
|
+
type Step = { m: string; p: string; b?: unknown; raw?: string; ct?: string; auth?: boolean; bearer?: string | undefined };
|
|
50
|
+
type Body = Record<string, any>;
|
|
51
|
+
type Verify = NonNullable<CapabilitySpec['verify']>;
|
|
52
|
+
type Call = (step: Step) => Promise<CloudflareResponse>;
|
|
53
|
+
|
|
54
|
+
async function withRoot(fn: (call: Call, root: string) => Promise<boolean>): Promise<boolean> {
|
|
55
|
+
const root = mkdtempSync(join(tmpdir(), 'cloudflare-cap-'));
|
|
56
|
+
const call = (step: Step) => handleCloudflareTwinRequest({
|
|
57
|
+
root,
|
|
58
|
+
method: step.m,
|
|
59
|
+
path: step.p,
|
|
60
|
+
occurredAt: AT,
|
|
61
|
+
headers: {
|
|
62
|
+
...(step.auth === false ? {} : { authorization: `Bearer ${step.bearer ?? 'local-certification-token'}` }),
|
|
63
|
+
...(step.ct ? { 'content-type': step.ct } : {}),
|
|
64
|
+
},
|
|
65
|
+
...(step.raw !== undefined ? { body: step.raw } : step.b === undefined ? {} : { body: JSON.stringify(step.b) }),
|
|
66
|
+
});
|
|
67
|
+
try { return await verifyBoundary('cloudflare.withRoot', () => fn(call, root)); }
|
|
68
|
+
finally { rmSync(root, { recursive: true, force: true }); }
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async function seed(call: Call): Promise<void> {
|
|
72
|
+
await call({ m: 'POST', p: '/twin/bootstrap', b: {
|
|
73
|
+
accounts: [{ id: ACCOUNT, name: 'Acme' }],
|
|
74
|
+
zones: [{ id: ZONE, account_id: ACCOUNT, name: 'example.test' }],
|
|
75
|
+
} });
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** The head's loop, in miniature (protocol 2): perform each entry the twin appended through the connector,
|
|
79
|
+
* remembering the vendor's id for the ones it minted so a later entry names the vendor's id, not ours. */
|
|
80
|
+
async function performAll(
|
|
81
|
+
root: string,
|
|
82
|
+
execute: (request: { method: string; path: string; headers?: Record<string, string>; body?: string | Uint8Array }) => Promise<{ status: number; headers: Record<string, string>; body: string }>,
|
|
83
|
+
adopted: Map<string, string> = new Map(),
|
|
84
|
+
done: Set<string> = new Set(),
|
|
85
|
+
): Promise<{ performed: number; failed: string | null; adopted: Map<string, string>; done: Set<string> }> {
|
|
86
|
+
const ctx = { resolve: (type: string, id: string) => adopted.get(`${type}:${id}`) ?? id, service: 'cloudflare', root };
|
|
87
|
+
let performed = 0;
|
|
88
|
+
for (const entry of deployableEntries('cloudflare', root)) {
|
|
89
|
+
if (done.has(entry.id)) continue; // the head confirms what it performed; this harness remembers instead
|
|
90
|
+
try {
|
|
91
|
+
const outcome = await performCloudflareAction(execute, entry, ctx as never);
|
|
92
|
+
adopted.set(`${entry.subject.type}:${entry.subject.id}`, outcome.externalId);
|
|
93
|
+
done.add(entry.id);
|
|
94
|
+
performed += 1;
|
|
95
|
+
} catch (error) {
|
|
96
|
+
return { performed, failed: error instanceof Error ? error.message : String(error), adopted, done };
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return { performed, failed: null, adopted, done };
|
|
100
|
+
}
|
|
101
|
+
/** A vendor answering the API v4 envelope, as the kernel's executor hands it over: JSON in, JSON out. */
|
|
102
|
+
function vendor(reply: (method: string, path: string, body: Record<string, unknown> | undefined) => { status: number; body: unknown }) {
|
|
103
|
+
const seen: Array<{ method: string; path: string; body?: Record<string, unknown> }> = [];
|
|
104
|
+
const execute = async (request: { method: string; path: string; body?: string | Uint8Array }) => {
|
|
105
|
+
const body = request.body ? (JSON.parse(typeof request.body === 'string' ? request.body : new TextDecoder().decode(request.body)) as Record<string, unknown>) : undefined;
|
|
106
|
+
const path = request.path.replace(/^\/client\/v4/, '');
|
|
107
|
+
seen.push({ method: request.method, path, ...(body ? { body } : {}) });
|
|
108
|
+
const answer = reply(request.method, path, body);
|
|
109
|
+
return { status: answer.status, headers: {}, body: JSON.stringify(answer.body) };
|
|
110
|
+
};
|
|
111
|
+
return { execute, seen };
|
|
112
|
+
}
|
|
113
|
+
async function tunnel(call: Call, name = 'local-cert'): Promise<string> {
|
|
114
|
+
const response = await call({ m: 'POST', p: `/accounts/${ACCOUNT}/cfd_tunnel`, b: { name, config_src: 'cloudflare' } });
|
|
115
|
+
return String((response.body as Body).result?.id ?? '');
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** Build the exact multipart body an unmodified SDK/wrangler-shaped deploy emits: a JSON
|
|
119
|
+
* `metadata` part plus named module file parts. */
|
|
120
|
+
function moduleUpload(metadata: Body, files: Record<string, string> = { 'worker.js': 'export default { fetch() { return new Response("ok"); } };' }): Step {
|
|
121
|
+
const boundary = 'twin-cap-boundary';
|
|
122
|
+
const parts = [
|
|
123
|
+
`--${boundary}\r\nContent-Disposition: form-data; name="metadata"\r\nContent-Type: application/json\r\n\r\n${JSON.stringify(metadata)}\r\n`,
|
|
124
|
+
...Object.entries(files).map(([name, content]) =>
|
|
125
|
+
`--${boundary}\r\nContent-Disposition: form-data; name="files[]"; filename="${name}"\r\nContent-Type: application/javascript+module\r\n\r\n${content}\r\n`),
|
|
126
|
+
];
|
|
127
|
+
return { m: 'PUT', p: '', raw: `${parts.join('')}--${boundary}--\r\n`, ct: `multipart/form-data; boundary=${boundary}` };
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
async function deployWorker(call: Call, name = 'cert-worker', metadata: Body = { main_module: 'worker.js' }): Promise<CloudflareResponse> {
|
|
131
|
+
const upload = moduleUpload(metadata);
|
|
132
|
+
return call({ ...upload, p: `/accounts/${ACCOUNT}/workers/scripts/${name}` });
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
async function seedQueue(call: Call, name = 'cert-queue'): Promise<string> {
|
|
136
|
+
const response = await call({ m: 'POST', p: `/accounts/${ACCOUNT}/queues`, b: { queue_name: name } });
|
|
137
|
+
return String((response.body as Body).result?.queue_id ?? '');
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const HD_ORIGIN = { scheme: 'postgres', database: 'app', user: 'launch', password: 'secret-launch-pass', host: 'db.internal.test', port: 5432 };
|
|
141
|
+
async function seedHyperdrive(call: Call, name = 'cert-hd'): Promise<string> {
|
|
142
|
+
const response = await call({ m: 'POST', p: `/accounts/${ACCOUNT}/hyperdrive/configs`, b: { name, origin: HD_ORIGIN } });
|
|
143
|
+
return String((response.body as Body).result?.id ?? '');
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const operationVerifiers = new Map<string, Verify>([
|
|
147
|
+
['GET /accounts', () => withRoot(async (call) => {
|
|
148
|
+
await seed(call);
|
|
149
|
+
const denied = await call({ m: 'GET', p: '/accounts', auth: false });
|
|
150
|
+
const response = await call({ m: 'GET', p: '/accounts?name=Acme&per_page=1' });
|
|
151
|
+
return denied.status === 403 && (denied.body as Body).errors?.[0]?.code === 10000
|
|
152
|
+
&& response.status === 200 && (response.body as Body).result?.[0]?.id === ACCOUNT
|
|
153
|
+
&& (response.body as Body).result_info?.total_count === 1;
|
|
154
|
+
})],
|
|
155
|
+
['GET /accounts/{account_id}', () => withRoot(async (call) => {
|
|
156
|
+
await seed(call); const response = await call({ m: 'GET', p: `/accounts/${ACCOUNT}` });
|
|
157
|
+
return response.status === 200 && (response.body as Body).result?.name === 'Acme';
|
|
158
|
+
})],
|
|
159
|
+
['GET /zones', () => withRoot(async (call) => {
|
|
160
|
+
await seed(call); const response = await call({ m: 'GET', p: `/zones?name=example.test&account.id=${ACCOUNT}` });
|
|
161
|
+
return response.status === 200 && (response.body as Body).result?.[0]?.account?.id === ACCOUNT;
|
|
162
|
+
})],
|
|
163
|
+
['GET /zones/{zone_id}', () => withRoot(async (call) => {
|
|
164
|
+
await seed(call); const response = await call({ m: 'GET', p: `/zones/${ZONE}` });
|
|
165
|
+
return response.status === 200 && (response.body as Body).result?.name === 'example.test';
|
|
166
|
+
})],
|
|
167
|
+
['POST /accounts/{account_id}/cfd_tunnel', () => withRoot(async (call) => {
|
|
168
|
+
await seed(call);
|
|
169
|
+
const invalid = await call({ m: 'POST', p: `/accounts/${ACCOUNT}/cfd_tunnel`, b: { name: 'bad', tunnel_secret: 'not-base64' } });
|
|
170
|
+
const id = await tunnel(call);
|
|
171
|
+
return invalid.status === 400 && /^[0-9a-f-]{36}$/.test(id);
|
|
172
|
+
})],
|
|
173
|
+
['GET /accounts/{account_id}/cfd_tunnel', () => withRoot(async (call) => {
|
|
174
|
+
await seed(call); const first = await tunnel(call, 'first'); await tunnel(call, 'second');
|
|
175
|
+
await call({ m: 'DELETE', p: `/accounts/${ACCOUNT}/cfd_tunnel/${first}` });
|
|
176
|
+
const all = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/cfd_tunnel` });
|
|
177
|
+
const active = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/cfd_tunnel?is_deleted=false` });
|
|
178
|
+
const deleted = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/cfd_tunnel?is_deleted=true` });
|
|
179
|
+
return (all.body as Body).result?.length === 2 && (active.body as Body).result?.length === 1
|
|
180
|
+
&& (deleted.body as Body).result?.[0]?.deleted_at !== null;
|
|
181
|
+
})],
|
|
182
|
+
['GET /accounts/{account_id}/cfd_tunnel/{tunnel_id}', () => withRoot(async (call) => {
|
|
183
|
+
await seed(call); const id = await tunnel(call); const response = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/cfd_tunnel/${id}` });
|
|
184
|
+
return response.status === 200 && (response.body as Body).result?.id === id;
|
|
185
|
+
})],
|
|
186
|
+
['PATCH /accounts/{account_id}/cfd_tunnel/{tunnel_id}', () => withRoot(async (call) => {
|
|
187
|
+
await seed(call); const first = await tunnel(call, 'first'); await tunnel(call, 'second');
|
|
188
|
+
const conflict = await call({ m: 'PATCH', p: `/accounts/${ACCOUNT}/cfd_tunnel/${first}`, b: { name: 'second' } });
|
|
189
|
+
const invalid = await call({ m: 'PATCH', p: `/accounts/${ACCOUNT}/cfd_tunnel/${first}`, b: { tunnel_secret: 'not-base64' } });
|
|
190
|
+
const validSecret = Buffer.alloc(32, 7).toString('base64');
|
|
191
|
+
const edited = await call({ m: 'PATCH', p: `/accounts/${ACCOUNT}/cfd_tunnel/${first}`, b: { name: 'renamed', tunnel_secret: validSecret } });
|
|
192
|
+
return conflict.status === 409 && invalid.status === 400 && (edited.body as Body).result?.name === 'renamed';
|
|
193
|
+
})],
|
|
194
|
+
['DELETE /accounts/{account_id}/cfd_tunnel/{tunnel_id}', () => withRoot(async (call) => {
|
|
195
|
+
await seed(call); const id = await tunnel(call); const response = await call({ m: 'DELETE', p: `/accounts/${ACCOUNT}/cfd_tunnel/${id}` });
|
|
196
|
+
return response.status === 200 && (response.body as Body).result?.id === id
|
|
197
|
+
&& typeof (response.body as Body).result?.deleted_at === 'string'
|
|
198
|
+
&& (await call({ m: 'GET', p: `/accounts/${ACCOUNT}/cfd_tunnel/${id}` })).status === 404;
|
|
199
|
+
})],
|
|
200
|
+
['PUT /accounts/{account_id}/cfd_tunnel/{tunnel_id}/configurations', () => withRoot(async (call) => {
|
|
201
|
+
await seed(call); const id = await tunnel(call);
|
|
202
|
+
const response = await call({ m: 'PUT', p: `/accounts/${ACCOUNT}/cfd_tunnel/${id}/configurations`, b: { config: { ingress: [{ hostname: '*', service: 'http_status:404' }] } } });
|
|
203
|
+
return response.status === 200 && (response.body as Body).result?.tunnel_id === id && (response.body as Body).result?.version === 1;
|
|
204
|
+
})],
|
|
205
|
+
['GET /accounts/{account_id}/cfd_tunnel/{tunnel_id}/configurations', () => withRoot(async (call) => {
|
|
206
|
+
await seed(call); const id = await tunnel(call);
|
|
207
|
+
await call({ m: 'PUT', p: `/accounts/${ACCOUNT}/cfd_tunnel/${id}/configurations`, b: { config: { ingress: [{ hostname: '*', service: 'http_status:404' }] } } });
|
|
208
|
+
const response = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/cfd_tunnel/${id}/configurations` });
|
|
209
|
+
return response.status === 200 && (response.body as Body).result?.config?.ingress?.[0]?.service === 'http_status:404';
|
|
210
|
+
})],
|
|
211
|
+
['GET /accounts/{account_id}/cfd_tunnel/{tunnel_id}/token', () => withRoot(async (call) => {
|
|
212
|
+
await seed(call); const id = await tunnel(call);
|
|
213
|
+
const first = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/cfd_tunnel/${id}/token` });
|
|
214
|
+
const second = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/cfd_tunnel/${id}/token` });
|
|
215
|
+
return typeof (first.body as Body).result === 'string' && (first.body as Body).result === (second.body as Body).result;
|
|
216
|
+
})],
|
|
217
|
+
['POST /zones/{zone_id}/dns_records', () => withRoot(async (call) => {
|
|
218
|
+
await seed(call);
|
|
219
|
+
const caa = await call({ m: 'POST', p: `/zones/${ZONE}/dns_records`, b: {
|
|
220
|
+
type: 'CAA', name: 'example.test', ttl: 60, data: { flags: 0, tag: 'issue', value: 'letsencrypt.org' },
|
|
221
|
+
} });
|
|
222
|
+
return caa.status === 200 && (caa.body as Body).result?.type === 'CAA'
|
|
223
|
+
&& (caa.body as Body).result?.data?.value === 'letsencrypt.org'
|
|
224
|
+
&& !Object.hasOwn((caa.body as Body).result, 'content');
|
|
225
|
+
})],
|
|
226
|
+
['GET /zones/{zone_id}/dns_records', () => withRoot(async (call) => {
|
|
227
|
+
await seed(call); await call({ m: 'POST', p: `/zones/${ZONE}/dns_records`, b: { type: 'CNAME', name: 'app.example.test', content: 'target.example.test', ttl: 1 } });
|
|
228
|
+
const response = await call({ m: 'GET', p: `/zones/${ZONE}/dns_records?type=CNAME&name=app.example.test` });
|
|
229
|
+
return response.status === 200 && (response.body as Body).result?.length === 1;
|
|
230
|
+
})],
|
|
231
|
+
['GET /zones/{zone_id}/dns_records/{dns_record_id}', () => withRoot(async (call) => {
|
|
232
|
+
await seed(call); const created = await call({ m: 'POST', p: `/zones/${ZONE}/dns_records`, b: { type: 'A', name: 'a.example.test', content: '192.0.2.1', ttl: 60 } });
|
|
233
|
+
return (await call({ m: 'GET', p: `/zones/${ZONE}/dns_records/${(created.body as Body).result.id}` })).status === 200;
|
|
234
|
+
})],
|
|
235
|
+
['PUT /zones/{zone_id}/dns_records/{dns_record_id}', () => withRoot(async (call) => {
|
|
236
|
+
await seed(call); const created = await call({ m: 'POST', p: `/zones/${ZONE}/dns_records`, b: { type: 'A', name: 'a.example.test', content: '192.0.2.1', ttl: 60, comment: 'old', tags: ['owner:test'], settings: { ipv4_only: true } } });
|
|
237
|
+
const id = (created.body as Body).result.id;
|
|
238
|
+
const partial = await call({ m: 'PUT', p: `/zones/${ZONE}/dns_records/${id}`, b: { content: '192.0.2.2' } });
|
|
239
|
+
const replaced = await call({ m: 'PUT', p: `/zones/${ZONE}/dns_records/${id}`, b: { type: 'CAA', name: 'example.test', ttl: 120, data: { flags: 0, tag: 'issue', value: 'pki.goog' } } });
|
|
240
|
+
const value = (replaced.body as Body).result;
|
|
241
|
+
return partial.status === 400 && replaced.status === 200 && value.type === 'CAA' && value.data?.value === 'pki.goog'
|
|
242
|
+
&& !Object.hasOwn(value, 'content') && value.comment === null && value.tags?.length === 0
|
|
243
|
+
&& Object.keys(value.settings ?? {}).length === 0;
|
|
244
|
+
})],
|
|
245
|
+
['PATCH /zones/{zone_id}/dns_records/{dns_record_id}', () => withRoot(async (call) => {
|
|
246
|
+
await seed(call); const created = await call({ m: 'POST', p: `/zones/${ZONE}/dns_records`, b: { type: 'TXT', name: 'txt.example.test', content: 'one', ttl: 60, comment: 'keep', tags: ['owner:test'] } });
|
|
247
|
+
const response = await call({ m: 'PATCH', p: `/zones/${ZONE}/dns_records/${(created.body as Body).result.id}`, b: { content: 'two' } });
|
|
248
|
+
const value = (response.body as Body).result;
|
|
249
|
+
return response.status === 200 && value.content === 'two' && value.name === 'txt.example.test' && value.comment === 'keep' && value.tags?.[0] === 'owner:test';
|
|
250
|
+
})],
|
|
251
|
+
['DELETE /zones/{zone_id}/dns_records/{dns_record_id}', () => withRoot(async (call) => {
|
|
252
|
+
await seed(call); const created = await call({ m: 'POST', p: `/zones/${ZONE}/dns_records`, b: { type: 'TXT', name: 'txt.example.test', content: 'one', ttl: 60 } });
|
|
253
|
+
const id = (created.body as Body).result.id;
|
|
254
|
+
return (await call({ m: 'DELETE', p: `/zones/${ZONE}/dns_records/${id}` })).status === 200
|
|
255
|
+
&& (await call({ m: 'GET', p: `/zones/${ZONE}/dns_records/${id}` })).status === 404;
|
|
256
|
+
})],
|
|
257
|
+
]);
|
|
258
|
+
|
|
259
|
+
// Workers / R2 / Hyperdrive / Queues provisioning verifiers. Every verify starts from a
|
|
260
|
+
// fresh root, seeds through the twin's own write path, asserts response VALUES, and drives
|
|
261
|
+
// the negative 4xx path its operation implies. Merged into operationVerifiers below.
|
|
262
|
+
const provisioningVerifiers = new Map<string, Verify>([
|
|
263
|
+
['GET /accounts/{account_id}/workers/scripts', () => withRoot(async (call) => {
|
|
264
|
+
await seed(call);
|
|
265
|
+
const uploaded = await deployWorker(call, 'list-me', { main_module: 'worker.js', compatibility_date: '2026-08-01', tags: ['launch'] });
|
|
266
|
+
// A service binding to a Worker that does not exist must be rejected, and the rejected
|
|
267
|
+
// upload must not appear in the list (round-two N4).
|
|
268
|
+
const svcGhost = await deployWorker(call, 'svc-ghost', { main_module: 'worker.js', bindings: [{ type: 'service', name: 'SVC', service: 'never-uploaded' }] });
|
|
269
|
+
const listed = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/workers/scripts` });
|
|
270
|
+
const item = (listed.body as Body).result?.[0];
|
|
271
|
+
return uploaded.status === 200 && svcGhost.status === 400 && listed.status === 200
|
|
272
|
+
&& item?.id === 'list-me' && item?.etag === (uploaded.body as Body).result?.etag
|
|
273
|
+
&& item?.compatibility_date === '2026-08-01' && item?.tags?.[0] === 'launch'
|
|
274
|
+
&& (listed.body as Body).result_info?.total_count === 1;
|
|
275
|
+
})],
|
|
276
|
+
['GET /accounts/{account_id}/workers/scripts/{script_name}', () => withRoot(async (call) => {
|
|
277
|
+
await seed(call);
|
|
278
|
+
await deployWorker(call, 'download-me', { main_module: 'worker.js' });
|
|
279
|
+
const download = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/workers/scripts/download-me` });
|
|
280
|
+
const missing = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/workers/scripts/never-uploaded` });
|
|
281
|
+
// A single-module module-syntax Worker still downloads as multipart/form-data (not raw JS).
|
|
282
|
+
return download.status === 200 && download.raw === true
|
|
283
|
+
&& (download.headers?.['content-type'] ?? '').includes('multipart/form-data')
|
|
284
|
+
&& String(download.body).includes('return new Response("ok")')
|
|
285
|
+
&& missing.status === 404 && (missing.body as Body).errors?.[0]?.code === 10007;
|
|
286
|
+
})],
|
|
287
|
+
['DELETE /accounts/{account_id}/workers/scripts/{script_name}', () => withRoot(async (call) => {
|
|
288
|
+
await seed(call);
|
|
289
|
+
// Dirty-state cell: upload with a DO class AND distinctive metadata, prove no-force delete
|
|
290
|
+
// is BLOCKED by the namespace (the pinned OpenAPI force contract), force-delete, then
|
|
291
|
+
// recreate the same name with BARE metadata and assert none of the deleted script's fields
|
|
292
|
+
// resurrect through the kernel tombstone merge (finding-3).
|
|
293
|
+
await deployWorker(call, 'delete-me', {
|
|
294
|
+
main_module: 'worker.js', usage_model: 'unbound', logpush: true, tags: ['old-tag'],
|
|
295
|
+
compatibility_date: '2026-01-01', migrations: { new_tag: 'v9', new_classes: ['Session'] },
|
|
296
|
+
});
|
|
297
|
+
const blocked = await call({ m: 'DELETE', p: `/accounts/${ACCOUNT}/workers/scripts/delete-me` });
|
|
298
|
+
const forced = await call({ m: 'DELETE', p: `/accounts/${ACCOUNT}/workers/scripts/delete-me?force=true` });
|
|
299
|
+
const gone = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/workers/scripts/delete-me` });
|
|
300
|
+
const namespaces = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/workers/durable_objects/namespaces` });
|
|
301
|
+
const recreated = await deployWorker(call, 'delete-me', { main_module: 'worker.js' });
|
|
302
|
+
const fresh = (recreated.body as Body).result;
|
|
303
|
+
return blocked.status === 400 && forced.status === 200 && (forced.body as Body).result === null
|
|
304
|
+
&& gone.status === 404
|
|
305
|
+
&& (namespaces.body as Body).result?.length === 0
|
|
306
|
+
&& recreated.status === 200 && fresh?.id === 'delete-me'
|
|
307
|
+
&& fresh?.usage_model === 'standard' && fresh?.logpush === false
|
|
308
|
+
&& !Object.hasOwn(fresh ?? {}, 'compatibility_date') && (fresh?.tags?.length ?? 0) === 0
|
|
309
|
+
&& !Object.hasOwn(fresh ?? {}, 'migration_tag')
|
|
310
|
+
&& (await call({ m: 'GET', p: `/accounts/${ACCOUNT}/workers/scripts/delete-me` })).status === 200;
|
|
311
|
+
})],
|
|
312
|
+
['GET /accounts/{account_id}/workers/scripts/{script_name}/schedules', () => withRoot(async (call) => {
|
|
313
|
+
await seed(call); await deployWorker(call);
|
|
314
|
+
await call({ m: 'PUT', p: `/accounts/${ACCOUNT}/workers/scripts/cert-worker/schedules`, b: [{ cron: '*/30 * * * *' }] });
|
|
315
|
+
const response = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/workers/scripts/cert-worker/schedules` });
|
|
316
|
+
const missing = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/workers/scripts/never-uploaded/schedules` });
|
|
317
|
+
return response.status === 200 && (response.body as Body).result?.schedules?.[0]?.cron === '*/30 * * * *'
|
|
318
|
+
&& typeof (response.body as Body).result?.schedules?.[0]?.created_on === 'string'
|
|
319
|
+
&& missing.status === 404;
|
|
320
|
+
})],
|
|
321
|
+
['PUT /accounts/{account_id}/workers/scripts/{script_name}/schedules', () => withRoot(async (call) => {
|
|
322
|
+
await seed(call); await deployWorker(call);
|
|
323
|
+
const invalid = await call({ m: 'PUT', p: `/accounts/${ACCOUNT}/workers/scripts/cert-worker/schedules`, b: [{ cron: 'not a cron' }] });
|
|
324
|
+
// Garbage that happens to have 5 whitespace tokens must still be rejected field-by-field.
|
|
325
|
+
const garbageFields = await call({ m: 'PUT', p: `/accounts/${ACCOUNT}/workers/scripts/cert-worker/schedules`, b: [{ cron: 'zz zz zz zz zz' }] });
|
|
326
|
+
const outOfRange = await call({ m: 'PUT', p: `/accounts/${ACCOUNT}/workers/scripts/cert-worker/schedules`, b: [{ cron: '99 * * * *' }] });
|
|
327
|
+
const replaced = await call({ m: 'PUT', p: `/accounts/${ACCOUNT}/workers/scripts/cert-worker/schedules`, b: [{ cron: '0 3 * * MON' }, { cron: '*/5 9-17 * jan-mar 1,3,5' }] });
|
|
328
|
+
const emptied = await call({ m: 'PUT', p: `/accounts/${ACCOUNT}/workers/scripts/cert-worker/schedules`, b: [] });
|
|
329
|
+
return invalid.status === 400 && garbageFields.status === 400 && outOfRange.status === 400 && replaced.status === 200
|
|
330
|
+
&& (replaced.body as Body).result?.schedules?.map((item: Body) => item.cron).join(',') === '0 3 * * MON,*/5 9-17 * jan-mar 1,3,5'
|
|
331
|
+
&& emptied.status === 200 && (emptied.body as Body).result?.schedules?.length === 0;
|
|
332
|
+
})],
|
|
333
|
+
['GET /accounts/{account_id}/workers/scripts/{script_name}/subdomain', () => withRoot(async (call) => {
|
|
334
|
+
await seed(call); await deployWorker(call);
|
|
335
|
+
const before = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/workers/scripts/cert-worker/subdomain` });
|
|
336
|
+
await call({ m: 'POST', p: `/accounts/${ACCOUNT}/workers/scripts/cert-worker/subdomain`, b: { enabled: true, previews_enabled: true } });
|
|
337
|
+
const after = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/workers/scripts/cert-worker/subdomain` });
|
|
338
|
+
return (before.body as Body).result?.enabled === false && after.status === 200
|
|
339
|
+
&& (after.body as Body).result?.enabled === true && (after.body as Body).result?.previews_enabled === true;
|
|
340
|
+
})],
|
|
341
|
+
['POST /accounts/{account_id}/workers/scripts/{script_name}/subdomain', () => withRoot(async (call) => {
|
|
342
|
+
await seed(call); await deployWorker(call);
|
|
343
|
+
const invalid = await call({ m: 'POST', p: `/accounts/${ACCOUNT}/workers/scripts/cert-worker/subdomain`, b: {} });
|
|
344
|
+
const enabled = await call({ m: 'POST', p: `/accounts/${ACCOUNT}/workers/scripts/cert-worker/subdomain`, b: { enabled: true } });
|
|
345
|
+
return invalid.status === 400 && enabled.status === 200 && (enabled.body as Body).result?.enabled === true;
|
|
346
|
+
})],
|
|
347
|
+
['DELETE /accounts/{account_id}/workers/scripts/{script_name}/subdomain', () => withRoot(async (call) => {
|
|
348
|
+
await seed(call); await deployWorker(call);
|
|
349
|
+
await call({ m: 'POST', p: `/accounts/${ACCOUNT}/workers/scripts/cert-worker/subdomain`, b: { enabled: true, previews_enabled: true } });
|
|
350
|
+
const disabled = await call({ m: 'DELETE', p: `/accounts/${ACCOUNT}/workers/scripts/cert-worker/subdomain` });
|
|
351
|
+
const after = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/workers/scripts/cert-worker/subdomain` });
|
|
352
|
+
return disabled.status === 200 && (disabled.body as Body).result?.enabled === false
|
|
353
|
+
&& (after.body as Body).result?.previews_enabled === false;
|
|
354
|
+
})],
|
|
355
|
+
['GET /accounts/{account_id}/workers/subdomain', () => withRoot(async (call) => {
|
|
356
|
+
await seed(call);
|
|
357
|
+
const missing = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/workers/subdomain` });
|
|
358
|
+
await call({ m: 'PUT', p: `/accounts/${ACCOUNT}/workers/subdomain`, b: { subdomain: 'launch-team' } });
|
|
359
|
+
const after = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/workers/subdomain` });
|
|
360
|
+
return missing.status === 404 && after.status === 200 && (after.body as Body).result?.subdomain === 'launch-team';
|
|
361
|
+
})],
|
|
362
|
+
['PUT /accounts/{account_id}/workers/subdomain', () => withRoot(async (call) => {
|
|
363
|
+
await seed(call);
|
|
364
|
+
const invalid = await call({ m: 'PUT', p: `/accounts/${ACCOUNT}/workers/subdomain`, b: {} });
|
|
365
|
+
const badLabel = await call({ m: 'PUT', p: `/accounts/${ACCOUNT}/workers/subdomain`, b: { subdomain: 'not a label!' } });
|
|
366
|
+
const created = await call({ m: 'PUT', p: `/accounts/${ACCOUNT}/workers/subdomain`, b: { subdomain: 'Launch-Team' } });
|
|
367
|
+
return invalid.status === 400 && badLabel.status === 400
|
|
368
|
+
&& created.status === 200 && (created.body as Body).result?.subdomain === 'launch-team';
|
|
369
|
+
})],
|
|
370
|
+
['DELETE /accounts/{account_id}/workers/subdomain', () => withRoot(async (call) => {
|
|
371
|
+
await seed(call);
|
|
372
|
+
await call({ m: 'PUT', p: `/accounts/${ACCOUNT}/workers/subdomain`, b: { subdomain: 'launch-team' } });
|
|
373
|
+
const deleted = await call({ m: 'DELETE', p: `/accounts/${ACCOUNT}/workers/subdomain` });
|
|
374
|
+
const after = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/workers/subdomain` });
|
|
375
|
+
// 204 with no body per the pinned OpenAPI; a later PUT can re-create over the tombstone.
|
|
376
|
+
const recreated = await call({ m: 'PUT', p: `/accounts/${ACCOUNT}/workers/subdomain`, b: { subdomain: 'launch-team' } });
|
|
377
|
+
return deleted.status === 204 && after.status === 404
|
|
378
|
+
&& recreated.status === 200 && (recreated.body as Body).result?.subdomain === 'launch-team';
|
|
379
|
+
})],
|
|
380
|
+
['GET /accounts/{account_id}/workers/domains', () => withRoot(async (call) => {
|
|
381
|
+
await seed(call); await deployWorker(call);
|
|
382
|
+
await call({ m: 'PUT', p: `/accounts/${ACCOUNT}/workers/domains`, b: { hostname: 'api.example.test', service: 'cert-worker' } });
|
|
383
|
+
const all = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/workers/domains` });
|
|
384
|
+
const filtered = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/workers/domains?hostname=api.example.test` });
|
|
385
|
+
const none = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/workers/domains?hostname=other.example.test` });
|
|
386
|
+
// The documented `environment` filter is honored: production matches, anything else empties.
|
|
387
|
+
const prod = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/workers/domains?environment=production` });
|
|
388
|
+
const staging = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/workers/domains?environment=staging` });
|
|
389
|
+
return all.status === 200 && (all.body as Body).result?.[0]?.service === 'cert-worker'
|
|
390
|
+
&& (filtered.body as Body).result?.length === 1 && (none.body as Body).result?.length === 0
|
|
391
|
+
&& (prod.body as Body).result?.length === 1 && (staging.body as Body).result?.length === 0;
|
|
392
|
+
})],
|
|
393
|
+
['PUT /accounts/{account_id}/workers/domains', () => withRoot(async (call) => {
|
|
394
|
+
await seed(call); await deployWorker(call);
|
|
395
|
+
const outside = await call({ m: 'PUT', p: `/accounts/${ACCOUNT}/workers/domains`, b: { hostname: 'api.unrelated.test', service: 'cert-worker' } });
|
|
396
|
+
const noWorker = await call({ m: 'PUT', p: `/accounts/${ACCOUNT}/workers/domains`, b: { hostname: 'api.example.test', service: 'never-uploaded' } });
|
|
397
|
+
const badZoneName = await call({ m: 'PUT', p: `/accounts/${ACCOUNT}/workers/domains`, b: { hostname: 'api.example.test', service: 'cert-worker', zone_name: 'wrong.test' } });
|
|
398
|
+
const attached = await call({ m: 'PUT', p: `/accounts/${ACCOUNT}/workers/domains`, b: { hostname: 'API.example.test', service: 'cert-worker' } });
|
|
399
|
+
const value = (attached.body as Body).result;
|
|
400
|
+
return outside.status === 400 && noWorker.status === 400 && badZoneName.status === 400 && attached.status === 200
|
|
401
|
+
&& value?.hostname === 'api.example.test' && value?.zone_id === ZONE && value?.zone_name === 'example.test'
|
|
402
|
+
&& typeof value?.cert_id === 'string' && value.cert_id.length > 0;
|
|
403
|
+
})],
|
|
404
|
+
['GET /accounts/{account_id}/workers/domains/{domain_id}', () => withRoot(async (call) => {
|
|
405
|
+
await seed(call); await deployWorker(call);
|
|
406
|
+
const attached = await call({ m: 'PUT', p: `/accounts/${ACCOUNT}/workers/domains`, b: { hostname: 'api.example.test', service: 'cert-worker' } });
|
|
407
|
+
const id = (attached.body as Body).result?.id;
|
|
408
|
+
const fetched = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/workers/domains/${id}` });
|
|
409
|
+
const missing = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/workers/domains/${'f'.repeat(32)}` });
|
|
410
|
+
return fetched.status === 200 && (fetched.body as Body).result?.id === id && missing.status === 404;
|
|
411
|
+
})],
|
|
412
|
+
['DELETE /accounts/{account_id}/workers/domains/{domain_id}', () => withRoot(async (call) => {
|
|
413
|
+
await seed(call); await deployWorker(call);
|
|
414
|
+
const attached = await call({ m: 'PUT', p: `/accounts/${ACCOUNT}/workers/domains`, b: { hostname: 'api.example.test', service: 'cert-worker' } });
|
|
415
|
+
const id = (attached.body as Body).result?.id;
|
|
416
|
+
const detached = await call({ m: 'DELETE', p: `/accounts/${ACCOUNT}/workers/domains/${id}` });
|
|
417
|
+
// Pinned workers_api-response-common envelope: no `result` member.
|
|
418
|
+
return detached.status === 200 && (detached.body as Body).success === true
|
|
419
|
+
&& !Object.hasOwn(detached.body as Body, 'result')
|
|
420
|
+
&& (await call({ m: 'GET', p: `/accounts/${ACCOUNT}/workers/domains/${id}` })).status === 404;
|
|
421
|
+
})],
|
|
422
|
+
['GET /accounts/{account_id}/workers/durable_objects/namespaces', () => withRoot(async (call) => {
|
|
423
|
+
await seed(call);
|
|
424
|
+
await deployWorker(call, 'do-worker', { main_module: 'worker.js', migrations: { new_tag: 'v1', new_sqlite_classes: ['Session'], new_classes: ['Legacy'] } });
|
|
425
|
+
// A REJECTED upload (a DO binding referencing a class the migration does not create) must
|
|
426
|
+
// leave NO orphan namespace and no script — migrations are planned, not applied, until all
|
|
427
|
+
// validation passes (round-two N5).
|
|
428
|
+
const rejected = await deployWorker(call, 'ghost-worker', {
|
|
429
|
+
main_module: 'worker.js',
|
|
430
|
+
bindings: [{ type: 'durable_object_namespace', name: 'DO', class_name: 'Missing' }],
|
|
431
|
+
migrations: { new_tag: 'v1', new_sqlite_classes: ['Present'] },
|
|
432
|
+
});
|
|
433
|
+
const listed = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/workers/durable_objects/namespaces` });
|
|
434
|
+
const classes = ((listed.body as Body).result ?? []).map((item: Body) => `${item.class}:${item.use_sqlite}:${item.script}`).sort();
|
|
435
|
+
return rejected.status === 400
|
|
436
|
+
&& (await call({ m: 'GET', p: `/accounts/${ACCOUNT}/workers/scripts/ghost-worker` })).status === 404
|
|
437
|
+
&& listed.status === 200 && classes.join(',') === 'Legacy:false:do-worker,Session:true:do-worker'
|
|
438
|
+
&& (listed.body as Body).result_info?.total_count === 2;
|
|
439
|
+
})],
|
|
440
|
+
['GET /zones/{zone_id}/workers/routes', () => withRoot(async (call) => {
|
|
441
|
+
await seed(call); await deployWorker(call);
|
|
442
|
+
await call({ m: 'POST', p: `/zones/${ZONE}/workers/routes`, b: { pattern: 'example.test/api/*', script: 'cert-worker' } });
|
|
443
|
+
const listed = await call({ m: 'GET', p: `/zones/${ZONE}/workers/routes` });
|
|
444
|
+
const badZone = await call({ m: 'GET', p: `/zones/${'9'.repeat(32)}/workers/routes` });
|
|
445
|
+
return listed.status === 200 && (listed.body as Body).result?.[0]?.pattern === 'example.test/api/*'
|
|
446
|
+
&& (listed.body as Body).result?.[0]?.script === 'cert-worker' && badZone.status === 404;
|
|
447
|
+
})],
|
|
448
|
+
['POST /zones/{zone_id}/workers/routes', () => withRoot(async (call) => {
|
|
449
|
+
await seed(call); await deployWorker(call);
|
|
450
|
+
const invalid = await call({ m: 'POST', p: `/zones/${ZONE}/workers/routes`, b: {} });
|
|
451
|
+
// A route naming a script that is not a Worker on the zone's account must 400 (finding-5).
|
|
452
|
+
const ghostScript = await call({ m: 'POST', p: `/zones/${ZONE}/workers/routes`, b: { pattern: 'example.test/ghost/*', script: 'never-uploaded' } });
|
|
453
|
+
const created = await call({ m: 'POST', p: `/zones/${ZONE}/workers/routes`, b: { pattern: 'example.test/api/*', script: 'cert-worker' } });
|
|
454
|
+
const duplicate = await call({ m: 'POST', p: `/zones/${ZONE}/workers/routes`, b: { pattern: 'example.test/api/*' } });
|
|
455
|
+
return invalid.status === 400 && ghostScript.status === 400 && (ghostScript.body as Body).errors?.[0]?.code === 10007
|
|
456
|
+
&& created.status === 200
|
|
457
|
+
&& /^[0-9a-f]{32}$/.test(String((created.body as Body).result?.id)) && duplicate.status === 409;
|
|
458
|
+
})],
|
|
459
|
+
['GET /zones/{zone_id}/workers/routes/{route_id}', () => withRoot(async (call) => {
|
|
460
|
+
await seed(call);
|
|
461
|
+
const created = await call({ m: 'POST', p: `/zones/${ZONE}/workers/routes`, b: { pattern: 'example.test/*' } });
|
|
462
|
+
const id = (created.body as Body).result?.id;
|
|
463
|
+
const fetched = await call({ m: 'GET', p: `/zones/${ZONE}/workers/routes/${id}` });
|
|
464
|
+
const missing = await call({ m: 'GET', p: `/zones/${ZONE}/workers/routes/${'f'.repeat(32)}` });
|
|
465
|
+
return fetched.status === 200 && (fetched.body as Body).result?.pattern === 'example.test/*'
|
|
466
|
+
&& !Object.hasOwn((fetched.body as Body).result ?? {}, 'script') && missing.status === 404;
|
|
467
|
+
})],
|
|
468
|
+
['PUT /zones/{zone_id}/workers/routes/{route_id}', () => withRoot(async (call) => {
|
|
469
|
+
await seed(call); await deployWorker(call);
|
|
470
|
+
const created = await call({ m: 'POST', p: `/zones/${ZONE}/workers/routes`, b: { pattern: 'example.test/api/*', script: 'cert-worker' } });
|
|
471
|
+
const id = (created.body as Body).result?.id;
|
|
472
|
+
const invalid = await call({ m: 'PUT', p: `/zones/${ZONE}/workers/routes/${id}`, b: {} });
|
|
473
|
+
const ghostScript = await call({ m: 'PUT', p: `/zones/${ZONE}/workers/routes/${id}`, b: { pattern: 'example.test/v2/*', script: 'never-uploaded' } });
|
|
474
|
+
const updated = await call({ m: 'PUT', p: `/zones/${ZONE}/workers/routes/${id}`, b: { pattern: 'example.test/v2/*', script: 'cert-worker' } });
|
|
475
|
+
return invalid.status === 400 && ghostScript.status === 400 && (ghostScript.body as Body).errors?.[0]?.code === 10007
|
|
476
|
+
&& updated.status === 200 && (updated.body as Body).result?.pattern === 'example.test/v2/*';
|
|
477
|
+
})],
|
|
478
|
+
['DELETE /zones/{zone_id}/workers/routes/{route_id}', () => withRoot(async (call) => {
|
|
479
|
+
await seed(call);
|
|
480
|
+
const created = await call({ m: 'POST', p: `/zones/${ZONE}/workers/routes`, b: { pattern: 'example.test/*' } });
|
|
481
|
+
const id = (created.body as Body).result?.id;
|
|
482
|
+
const deleted = await call({ m: 'DELETE', p: `/zones/${ZONE}/workers/routes/${id}` });
|
|
483
|
+
return deleted.status === 200 && (deleted.body as Body).result?.id === id
|
|
484
|
+
&& (await call({ m: 'GET', p: `/zones/${ZONE}/workers/routes/${id}` })).status === 404;
|
|
485
|
+
})],
|
|
486
|
+
['GET /accounts/{account_id}/r2/buckets', () => withRoot(async (call) => {
|
|
487
|
+
await seed(call);
|
|
488
|
+
await call({ m: 'POST', p: `/accounts/${ACCOUNT}/r2/buckets`, b: { name: 'launch-artifacts' } });
|
|
489
|
+
await call({ m: 'POST', p: `/accounts/${ACCOUNT}/r2/buckets`, b: { name: 'launch-logs' } });
|
|
490
|
+
const listed = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/r2/buckets` });
|
|
491
|
+
const filtered = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/r2/buckets?name_contains=logs` });
|
|
492
|
+
const after = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/r2/buckets?start_after=launch-artifacts` });
|
|
493
|
+
return listed.status === 200
|
|
494
|
+
&& (listed.body as Body).result?.buckets?.map((item: Body) => item.name).join(',') === 'launch-artifacts,launch-logs'
|
|
495
|
+
&& (filtered.body as Body).result?.buckets?.length === 1
|
|
496
|
+
&& (after.body as Body).result?.buckets?.[0]?.name === 'launch-logs';
|
|
497
|
+
})],
|
|
498
|
+
['POST /accounts/{account_id}/r2/buckets', () => withRoot(async (call) => {
|
|
499
|
+
await seed(call);
|
|
500
|
+
const invalid = await call({ m: 'POST', p: `/accounts/${ACCOUNT}/r2/buckets`, b: { name: 'UPPER_CASE' } });
|
|
501
|
+
const created = await call({ m: 'POST', p: `/accounts/${ACCOUNT}/r2/buckets`, b: { name: 'launch-artifacts', locationHint: 'wnam', storageClass: 'Standard' } });
|
|
502
|
+
const duplicate = await call({ m: 'POST', p: `/accounts/${ACCOUNT}/r2/buckets`, b: { name: 'launch-artifacts' } });
|
|
503
|
+
const value = (created.body as Body).result;
|
|
504
|
+
return invalid.status === 400 && created.status === 200
|
|
505
|
+
&& value?.name === 'launch-artifacts' && value?.location === 'wnam' && value?.storage_class === 'Standard'
|
|
506
|
+
&& typeof value?.creation_date === 'string'
|
|
507
|
+
&& duplicate.status === 409 && (duplicate.body as Body).errors?.[0]?.code === 10004;
|
|
508
|
+
})],
|
|
509
|
+
['GET /accounts/{account_id}/r2/buckets/{bucket_name}', () => withRoot(async (call) => {
|
|
510
|
+
await seed(call);
|
|
511
|
+
await call({ m: 'POST', p: `/accounts/${ACCOUNT}/r2/buckets`, b: { name: 'launch-artifacts' } });
|
|
512
|
+
const fetched = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/r2/buckets/launch-artifacts` });
|
|
513
|
+
const missing = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/r2/buckets/never-created` });
|
|
514
|
+
return fetched.status === 200 && (fetched.body as Body).result?.name === 'launch-artifacts'
|
|
515
|
+
&& missing.status === 404 && (missing.body as Body).errors?.[0]?.code === 10006;
|
|
516
|
+
})],
|
|
517
|
+
['DELETE /accounts/{account_id}/r2/buckets/{bucket_name}', () => withRoot(async (call) => {
|
|
518
|
+
await seed(call);
|
|
519
|
+
// Dirty-state cell: create → delete → recreate the same bucket name must yield a live bucket.
|
|
520
|
+
await call({ m: 'POST', p: `/accounts/${ACCOUNT}/r2/buckets`, b: { name: 'launch-artifacts' } });
|
|
521
|
+
const deleted = await call({ m: 'DELETE', p: `/accounts/${ACCOUNT}/r2/buckets/launch-artifacts` });
|
|
522
|
+
const gone = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/r2/buckets/launch-artifacts` });
|
|
523
|
+
const recreated = await call({ m: 'POST', p: `/accounts/${ACCOUNT}/r2/buckets`, b: { name: 'launch-artifacts' } });
|
|
524
|
+
const alive = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/r2/buckets/launch-artifacts` });
|
|
525
|
+
// Pinned r2_v4_response REQUIRES a `result` member (unlike the queue delete envelope).
|
|
526
|
+
return deleted.status === 200 && Object.hasOwn(deleted.body as Body, 'result')
|
|
527
|
+
&& gone.status === 404 && recreated.status === 200
|
|
528
|
+
&& alive.status === 200 && (alive.body as Body).result?.name === 'launch-artifacts';
|
|
529
|
+
})],
|
|
530
|
+
['GET /accounts/{account_id}/hyperdrive/configs', () => withRoot(async (call) => {
|
|
531
|
+
await seed(call);
|
|
532
|
+
const id = await seedHyperdrive(call);
|
|
533
|
+
const listed = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/hyperdrive/configs` });
|
|
534
|
+
const value = (listed.body as Body).result?.[0];
|
|
535
|
+
return listed.status === 200 && value?.id === id && value?.origin?.host === 'db.internal.test'
|
|
536
|
+
&& !Object.hasOwn(value?.origin ?? {}, 'password')
|
|
537
|
+
&& (listed.body as Body).result_info?.total_count === 1;
|
|
538
|
+
})],
|
|
539
|
+
['POST /accounts/{account_id}/hyperdrive/configs', () => withRoot(async (call) => {
|
|
540
|
+
await seed(call);
|
|
541
|
+
const invalid = await call({ m: 'POST', p: `/accounts/${ACCOUNT}/hyperdrive/configs`, b: { name: 'bad', origin: { scheme: 'postgres', database: 'app', user: 'u', password: 'p', host: 'db.test' } } });
|
|
542
|
+
const created = await call({ m: 'POST', p: `/accounts/${ACCOUNT}/hyperdrive/configs`, b: { name: 'cert-hd', origin: HD_ORIGIN, caching: { disabled: false }, origin_connection_limit: 25 } });
|
|
543
|
+
const value = (created.body as Body).result;
|
|
544
|
+
// The origin connection is recorded as configuration — the password is writeOnly in the
|
|
545
|
+
// vendor schema and must never be echoed; the origin is never dialed.
|
|
546
|
+
return invalid.status === 400 && created.status === 200
|
|
547
|
+
&& /^[0-9a-f]{32}$/.test(String(value?.id)) && value?.origin?.port === 5432
|
|
548
|
+
&& !Object.hasOwn(value?.origin ?? {}, 'password')
|
|
549
|
+
&& value?.caching?.disabled === false && value?.origin_connection_limit === 25;
|
|
550
|
+
})],
|
|
551
|
+
['GET /accounts/{account_id}/hyperdrive/configs/{hyperdrive_id}', () => withRoot(async (call) => {
|
|
552
|
+
await seed(call);
|
|
553
|
+
const id = await seedHyperdrive(call);
|
|
554
|
+
const fetched = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/hyperdrive/configs/${id}` });
|
|
555
|
+
const missing = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/hyperdrive/configs/${'f'.repeat(32)}` });
|
|
556
|
+
return fetched.status === 200 && (fetched.body as Body).result?.name === 'cert-hd' && missing.status === 404;
|
|
557
|
+
})],
|
|
558
|
+
['PUT /accounts/{account_id}/hyperdrive/configs/{hyperdrive_id}', () => withRoot(async (call) => {
|
|
559
|
+
await seed(call);
|
|
560
|
+
const id = await seedHyperdrive(call);
|
|
561
|
+
const invalid = await call({ m: 'PUT', p: `/accounts/${ACCOUNT}/hyperdrive/configs/${id}`, b: { name: 'renamed' } });
|
|
562
|
+
const replaced = await call({ m: 'PUT', p: `/accounts/${ACCOUNT}/hyperdrive/configs/${id}`, b: { name: 'renamed', origin: { ...HD_ORIGIN, host: 'db2.internal.test' } } });
|
|
563
|
+
const value = (replaced.body as Body).result;
|
|
564
|
+
return invalid.status === 400 && replaced.status === 200
|
|
565
|
+
&& value?.name === 'renamed' && value?.origin?.host === 'db2.internal.test'
|
|
566
|
+
&& !Object.hasOwn(value ?? {}, 'caching');
|
|
567
|
+
})],
|
|
568
|
+
['PATCH /accounts/{account_id}/hyperdrive/configs/{hyperdrive_id}', () => withRoot(async (call) => {
|
|
569
|
+
await seed(call);
|
|
570
|
+
const id = await seedHyperdrive(call);
|
|
571
|
+
const patched = await call({ m: 'PATCH', p: `/accounts/${ACCOUNT}/hyperdrive/configs/${id}`, b: { caching: { disabled: true } } });
|
|
572
|
+
const value = (patched.body as Body).result;
|
|
573
|
+
// The vendor's edit-origin is a TYPED PARTIAL: a {host,port}-only PATCH must be accepted and
|
|
574
|
+
// MERGED over the existing origin (scheme/database/user preserved), not rejected (finding-4).
|
|
575
|
+
const partialOrigin = await call({ m: 'PATCH', p: `/accounts/${ACCOUNT}/hyperdrive/configs/${id}`, b: { origin: { host: 'db2.internal.test', port: 5433 } } });
|
|
576
|
+
const merged = (partialOrigin.body as Body).result?.origin;
|
|
577
|
+
// An unmodeled caching key must still be rejected, not recorded-and-echoed.
|
|
578
|
+
const badCaching = await call({ m: 'PATCH', p: `/accounts/${ACCOUNT}/hyperdrive/configs/${id}`, b: { caching: { bogus: 1 } } });
|
|
579
|
+
const badOrigin = await call({ m: 'PATCH', p: `/accounts/${ACCOUNT}/hyperdrive/configs/${id}`, b: { origin: { scheme: 'oracle' } } });
|
|
580
|
+
// A partial PATCH must not merge into an INCOHERENT origin the create path could never make:
|
|
581
|
+
// adding a `port` to an Access origin is rejected (round-two N1).
|
|
582
|
+
const access = await call({ m: 'POST', p: `/accounts/${ACCOUNT}/hyperdrive/configs`, b: {
|
|
583
|
+
name: 'access-hd',
|
|
584
|
+
origin: { scheme: 'postgres', database: 'app', user: 'u', password: 'p', access_client_id: 'cid', access_client_secret: 'csec', host: 'access.test' },
|
|
585
|
+
} });
|
|
586
|
+
const accessID = (access.body as Body).result?.id;
|
|
587
|
+
const incoherent = await call({ m: 'PATCH', p: `/accounts/${ACCOUNT}/hyperdrive/configs/${accessID}`, b: { origin: { port: 5432 } } });
|
|
588
|
+
return patched.status === 200 && value?.name === 'cert-hd' && value?.caching?.disabled === true
|
|
589
|
+
&& value?.origin?.host === 'db.internal.test'
|
|
590
|
+
&& partialOrigin.status === 200 && merged?.host === 'db2.internal.test' && merged?.port === 5433
|
|
591
|
+
&& merged?.scheme === 'postgres' && merged?.database === 'app'
|
|
592
|
+
&& badCaching.status === 400 && badOrigin.status === 400
|
|
593
|
+
&& access.status === 200 && incoherent.status === 400;
|
|
594
|
+
})],
|
|
595
|
+
['DELETE /accounts/{account_id}/hyperdrive/configs/{hyperdrive_id}', () => withRoot(async (call) => {
|
|
596
|
+
await seed(call);
|
|
597
|
+
const id = await seedHyperdrive(call);
|
|
598
|
+
const deleted = await call({ m: 'DELETE', p: `/accounts/${ACCOUNT}/hyperdrive/configs/${id}` });
|
|
599
|
+
return deleted.status === 200 && (deleted.body as Body).result === null
|
|
600
|
+
&& (await call({ m: 'GET', p: `/accounts/${ACCOUNT}/hyperdrive/configs/${id}` })).status === 404;
|
|
601
|
+
})],
|
|
602
|
+
['GET /accounts/{account_id}/queues', () => withRoot(async (call) => {
|
|
603
|
+
await seed(call);
|
|
604
|
+
const id = await seedQueue(call);
|
|
605
|
+
await deployWorker(call, 'producer-worker', { main_module: 'worker.js', bindings: [{ type: 'queue', name: 'Q', queue_name: 'cert-queue' }] });
|
|
606
|
+
const listed = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/queues` });
|
|
607
|
+
const value = (listed.body as Body).result?.[0];
|
|
608
|
+
// Producer bindings recorded on a Worker upload surface as the queue's producers.
|
|
609
|
+
return listed.status === 200 && value?.queue_id === id && value?.queue_name === 'cert-queue'
|
|
610
|
+
&& value?.producers?.[0]?.script === 'producer-worker' && value?.producers_total_count === 1;
|
|
611
|
+
})],
|
|
612
|
+
['POST /accounts/{account_id}/queues', () => withRoot(async (call) => {
|
|
613
|
+
await seed(call);
|
|
614
|
+
const invalid = await call({ m: 'POST', p: `/accounts/${ACCOUNT}/queues`, b: {} });
|
|
615
|
+
const created = await call({ m: 'POST', p: `/accounts/${ACCOUNT}/queues`, b: { queue_name: 'cert-queue' } });
|
|
616
|
+
const duplicate = await call({ m: 'POST', p: `/accounts/${ACCOUNT}/queues`, b: { queue_name: 'cert-queue' } });
|
|
617
|
+
const value = (created.body as Body).result;
|
|
618
|
+
return invalid.status === 400 && created.status === 200
|
|
619
|
+
&& /^[0-9a-f]{32}$/.test(String(value?.queue_id)) && value?.queue_name === 'cert-queue'
|
|
620
|
+
&& value?.consumers_total_count === 0 && duplicate.status === 400;
|
|
621
|
+
})],
|
|
622
|
+
['GET /accounts/{account_id}/queues/{queue_id}', () => withRoot(async (call) => {
|
|
623
|
+
await seed(call);
|
|
624
|
+
const id = await seedQueue(call);
|
|
625
|
+
const fetched = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/queues/${id}` });
|
|
626
|
+
const missing = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/queues/${'f'.repeat(32)}` });
|
|
627
|
+
return fetched.status === 200 && (fetched.body as Body).result?.queue_name === 'cert-queue' && missing.status === 404;
|
|
628
|
+
})],
|
|
629
|
+
['DELETE /accounts/{account_id}/queues/{queue_id}', () => withRoot(async (call) => {
|
|
630
|
+
await seed(call); await deployWorker(call);
|
|
631
|
+
const id = await seedQueue(call);
|
|
632
|
+
const consumer = await call({ m: 'POST', p: `/accounts/${ACCOUNT}/queues/${id}/consumers`, b: { type: 'worker', script_name: 'cert-worker' } });
|
|
633
|
+
const deleted = await call({ m: 'DELETE', p: `/accounts/${ACCOUNT}/queues/${id}` });
|
|
634
|
+
const gone = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/queues/${id}` });
|
|
635
|
+
const consumerGone = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/queues/${id}/consumers/${(consumer.body as Body).result?.consumer_id}` });
|
|
636
|
+
// Pinned QueueDeleteResponse envelope carries no `result` member (finding-8).
|
|
637
|
+
return deleted.status === 200 && (deleted.body as Body).success === true
|
|
638
|
+
&& !Object.hasOwn(deleted.body as Body, 'result')
|
|
639
|
+
&& gone.status === 404 && consumerGone.status === 404;
|
|
640
|
+
})],
|
|
641
|
+
['GET /accounts/{account_id}/queues/{queue_id}/consumers', () => withRoot(async (call) => {
|
|
642
|
+
await seed(call); await deployWorker(call);
|
|
643
|
+
const id = await seedQueue(call);
|
|
644
|
+
await call({ m: 'POST', p: `/accounts/${ACCOUNT}/queues/${id}/consumers`, b: { type: 'worker', script_name: 'cert-worker' } });
|
|
645
|
+
const listed = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/queues/${id}/consumers` });
|
|
646
|
+
const value = (listed.body as Body).result?.[0];
|
|
647
|
+
return listed.status === 200 && value?.type === 'worker' && value?.script_name === 'cert-worker'
|
|
648
|
+
&& value?.queue_name === 'cert-queue';
|
|
649
|
+
})],
|
|
650
|
+
['POST /accounts/{account_id}/queues/{queue_id}/consumers', () => withRoot(async (call) => {
|
|
651
|
+
await seed(call); await deployWorker(call);
|
|
652
|
+
const id = await seedQueue(call);
|
|
653
|
+
const badType = await call({ m: 'POST', p: `/accounts/${ACCOUNT}/queues/${id}/consumers`, b: { type: 'lambda' } });
|
|
654
|
+
const noScript = await call({ m: 'POST', p: `/accounts/${ACCOUNT}/queues/${id}/consumers`, b: { type: 'worker', script_name: 'never-uploaded' } });
|
|
655
|
+
const worker = await call({ m: 'POST', p: `/accounts/${ACCOUNT}/queues/${id}/consumers`, b: { type: 'worker', script_name: 'cert-worker', settings: { batch_size: 10, max_retries: 3 } } });
|
|
656
|
+
// A queue has at most one consumer — a second POST must be rejected until the first is gone.
|
|
657
|
+
const second = await call({ m: 'POST', p: `/accounts/${ACCOUNT}/queues/${id}/consumers`, b: { type: 'http_pull' } });
|
|
658
|
+
await call({ m: 'DELETE', p: `/accounts/${ACCOUNT}/queues/${id}/consumers/${(worker.body as Body).result?.consumer_id}` });
|
|
659
|
+
// The vendor documents max_concurrency:null ("opt into the platform maximum") — must be accepted.
|
|
660
|
+
const pull = await call({ m: 'POST', p: `/accounts/${ACCOUNT}/queues/${id}/consumers`, b: { type: 'http_pull', settings: { visibility_timeout_ms: 6000 } } });
|
|
661
|
+
return badType.status === 400 && noScript.status === 400
|
|
662
|
+
&& worker.status === 200 && (worker.body as Body).result?.settings?.batch_size === 10
|
|
663
|
+
&& second.status === 400
|
|
664
|
+
&& pull.status === 200 && (pull.body as Body).result?.type === 'http_pull'
|
|
665
|
+
&& !Object.hasOwn((pull.body as Body).result ?? {}, 'script_name');
|
|
666
|
+
})],
|
|
667
|
+
['GET /accounts/{account_id}/queues/{queue_id}/consumers/{consumer_id}', () => withRoot(async (call) => {
|
|
668
|
+
await seed(call); await deployWorker(call);
|
|
669
|
+
const id = await seedQueue(call);
|
|
670
|
+
const created = await call({ m: 'POST', p: `/accounts/${ACCOUNT}/queues/${id}/consumers`, b: { type: 'worker', script_name: 'cert-worker' } });
|
|
671
|
+
const consumerID = (created.body as Body).result?.consumer_id;
|
|
672
|
+
const fetched = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/queues/${id}/consumers/${consumerID}` });
|
|
673
|
+
const missing = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/queues/${id}/consumers/${'f'.repeat(32)}` });
|
|
674
|
+
return fetched.status === 200 && (fetched.body as Body).result?.consumer_id === consumerID && missing.status === 404;
|
|
675
|
+
})],
|
|
676
|
+
['PUT /accounts/{account_id}/queues/{queue_id}/consumers/{consumer_id}', () => withRoot(async (call) => {
|
|
677
|
+
await seed(call); await deployWorker(call);
|
|
678
|
+
const id = await seedQueue(call);
|
|
679
|
+
await seedQueue(call, 'dlq'); // a dead_letter_queue must reference a real queue on the account
|
|
680
|
+
const created = await call({ m: 'POST', p: `/accounts/${ACCOUNT}/queues/${id}/consumers`, b: { type: 'worker', script_name: 'cert-worker' } });
|
|
681
|
+
const consumerID = (created.body as Body).result?.consumer_id;
|
|
682
|
+
const badSetting = await call({ m: 'PUT', p: `/accounts/${ACCOUNT}/queues/${id}/consumers/${consumerID}`, b: { type: 'http_pull', settings: { max_concurrency: 2 } } });
|
|
683
|
+
const ghostDlq = await call({ m: 'PUT', p: `/accounts/${ACCOUNT}/queues/${id}/consumers/${consumerID}`, b: { type: 'worker', script_name: 'cert-worker', dead_letter_queue: 'nope-queue' } });
|
|
684
|
+
const badNull = await call({ m: 'PUT', p: `/accounts/${ACCOUNT}/queues/${id}/consumers/${consumerID}`, b: { type: 'worker', script_name: 'cert-worker', settings: { batch_size: null } } });
|
|
685
|
+
// The vendor's recommended max_concurrency:null ("platform maximum") must be accepted;
|
|
686
|
+
// batch_size:null must NOT (only max_concurrency is nullable).
|
|
687
|
+
const updated = await call({ m: 'PUT', p: `/accounts/${ACCOUNT}/queues/${id}/consumers/${consumerID}`, b: { type: 'worker', script_name: 'cert-worker', dead_letter_queue: 'dlq', settings: { batch_size: 25, max_concurrency: null } } });
|
|
688
|
+
const value = (updated.body as Body).result;
|
|
689
|
+
// max_concurrency is a worker-consumer setting; the http_pull union does not carry it.
|
|
690
|
+
return badSetting.status === 400 && ghostDlq.status === 400 && badNull.status === 400 && updated.status === 200
|
|
691
|
+
&& value?.dead_letter_queue === 'dlq' && value?.settings?.batch_size === 25
|
|
692
|
+
&& value?.settings?.max_concurrency === null;
|
|
693
|
+
})],
|
|
694
|
+
['DELETE /accounts/{account_id}/queues/{queue_id}/consumers/{consumer_id}', () => withRoot(async (call) => {
|
|
695
|
+
await seed(call); await deployWorker(call);
|
|
696
|
+
const id = await seedQueue(call);
|
|
697
|
+
const created = await call({ m: 'POST', p: `/accounts/${ACCOUNT}/queues/${id}/consumers`, b: { type: 'worker', script_name: 'cert-worker' } });
|
|
698
|
+
const consumerID = (created.body as Body).result?.consumer_id;
|
|
699
|
+
const deleted = await call({ m: 'DELETE', p: `/accounts/${ACCOUNT}/queues/${id}/consumers/${consumerID}` });
|
|
700
|
+
// Pinned ConsumerDeleteResponse envelope carries no `result` member (finding-8).
|
|
701
|
+
return deleted.status === 200 && (deleted.body as Body).success === true
|
|
702
|
+
&& !Object.hasOwn(deleted.body as Body, 'result')
|
|
703
|
+
&& (await call({ m: 'GET', p: `/accounts/${ACCOUNT}/queues/${id}/consumers/${consumerID}` })).status === 404
|
|
704
|
+
&& (await call({ m: 'GET', p: `/accounts/${ACCOUNT}/queues/${id}` })).status === 200;
|
|
705
|
+
})],
|
|
706
|
+
]);
|
|
707
|
+
// Account members: the built-in roles, a member added with role ids and removed, and a bootstrapped member's user
|
|
708
|
+
// two-factor state (Cloudflare's record of the person, which no account API sets).
|
|
709
|
+
const memberSeed = async (call: Call) => {
|
|
710
|
+
await seed(call);
|
|
711
|
+
await call({ m: 'POST', p: '/twin/bootstrap', b: { members: [{ account_id: ACCOUNT, email: 'ana@example.test', roles: ['Super Administrator - All Privileges'], two_factor: true }] } });
|
|
712
|
+
return (((await call({ m: 'GET', p: `/accounts/${ACCOUNT}/roles` })).body as Body).result as { id: string; name: string }[]);
|
|
713
|
+
};
|
|
714
|
+
const memberVerifiers = new Map<string, Verify>([
|
|
715
|
+
['GET /accounts/{account_id}/roles', () => withRoot(async (call) => { const roles = await memberSeed(call); return roles.some((r) => r.name === 'Administrator') && roles.every((r) => /^[a-f0-9]{32}$/.test(r.id)); })],
|
|
716
|
+
['GET /accounts/{account_id}/members', () => withRoot(async (call) => {
|
|
717
|
+
await memberSeed(call);
|
|
718
|
+
const list = ((await call({ m: 'GET', p: `/accounts/${ACCOUNT}/members` })).body as Body).result as any[];
|
|
719
|
+
return list.length === 1 && list[0].user.email === 'ana@example.test' && list[0].user.two_factor_authentication_enabled === true && list[0].status === 'accepted' && list[0].roles[0].name === 'Super Administrator - All Privileges';
|
|
720
|
+
})],
|
|
721
|
+
['POST /accounts/{account_id}/members', () => withRoot(async (call) => {
|
|
722
|
+
const roles = await memberSeed(call);
|
|
723
|
+
const admin = roles.find((r) => r.name === 'Administrator')!.id;
|
|
724
|
+
const added = (await call({ m: 'POST', p: `/accounts/${ACCOUNT}/members`, b: { email: 'ben@example.test', roles: [admin] } })).body as Body;
|
|
725
|
+
const bad = await call({ m: 'POST', p: `/accounts/${ACCOUNT}/members`, b: { email: 'carol@example.test', roles: ['nope'] } });
|
|
726
|
+
const dup = await call({ m: 'POST', p: `/accounts/${ACCOUNT}/members`, b: { email: 'ben@example.test', roles: [admin] } });
|
|
727
|
+
return added.success === true && added.result.status === 'pending' && added.result.user.two_factor_authentication_enabled === false && bad.status === 400 && dup.status === 400;
|
|
728
|
+
})],
|
|
729
|
+
['GET /accounts/{account_id}/members/{member_id}', () => withRoot(async (call) => {
|
|
730
|
+
await memberSeed(call);
|
|
731
|
+
const id = (((await call({ m: 'GET', p: `/accounts/${ACCOUNT}/members` })).body as Body).result as any[])[0].id;
|
|
732
|
+
return ((await call({ m: 'GET', p: `/accounts/${ACCOUNT}/members/${id}` })).body as Body).result.email === 'ana@example.test'
|
|
733
|
+
&& (await call({ m: 'GET', p: `/accounts/${ACCOUNT}/members/${'f'.repeat(32)}` })).status === 404;
|
|
734
|
+
})],
|
|
735
|
+
['DELETE /accounts/{account_id}/members/{member_id}', () => withRoot(async (call) => {
|
|
736
|
+
await memberSeed(call);
|
|
737
|
+
const id = (((await call({ m: 'GET', p: `/accounts/${ACCOUNT}/members` })).body as Body).result as any[])[0].id;
|
|
738
|
+
await call({ m: 'DELETE', p: `/accounts/${ACCOUNT}/members/${id}` });
|
|
739
|
+
return (((await call({ m: 'GET', p: `/accounts/${ACCOUNT}/members` })).body as Body).result as any[]).length === 0;
|
|
740
|
+
})],
|
|
741
|
+
]);
|
|
742
|
+
// The account audit log: a user's API token created, a zone setting changed with it and a member removed are logged
|
|
743
|
+
// newest first; the token and the setting are attributed to that user (the setting with its old and new value), the
|
|
744
|
+
// removal (a token no one owns) to no one.
|
|
745
|
+
operationVerifiers.set('GET /accounts/{account_id}/audit_logs', () => withRoot(async (call) => {
|
|
746
|
+
await memberSeed(call);
|
|
747
|
+
const token = ((await call({ m: 'POST', p: '/twin/users/ana@example.test/tokens' })).body as Body).result.token as string;
|
|
748
|
+
await call({ m: 'PATCH', p: `/zones/${ZONE}/settings/always_use_https`, b: { value: 'on' }, bearer: token });
|
|
749
|
+
const id = (((await call({ m: 'GET', p: `/accounts/${ACCOUNT}/members` })).body as Body).result as any[])[0].id;
|
|
750
|
+
await call({ m: 'DELETE', p: `/accounts/${ACCOUNT}/members/${id}` });
|
|
751
|
+
const log = ((await call({ m: 'GET', p: `/accounts/${ACCOUNT}/audit_logs` })).body as Body).result as any[];
|
|
752
|
+
return log.length === 3 && log[2].action.type === 'create' && log[2].resource.type === 'token' && log[2].actor.email === 'ana@example.test'
|
|
753
|
+
&& log[1].actor.email === 'ana@example.test' && log[1].resource.type === 'zone_setting' && log[1].oldValue === 'off' && log[1].newValue === 'on'
|
|
754
|
+
&& log[0].action.type === 'delete' && log[0].actor.email === ''
|
|
755
|
+
&& (((await call({ m: 'GET', p: `/accounts/${ACCOUNT}/audit_logs?before=2000-01-01T00:00:00Z` })).body as Body).result as any[]).length === 0;
|
|
756
|
+
}));
|
|
757
|
+
for (const [key, verify] of memberVerifiers) operationVerifiers.set(key, verify);
|
|
758
|
+
for (const [key, verify] of provisioningVerifiers) operationVerifiers.set(key, verify);
|
|
759
|
+
|
|
760
|
+
// The Workers deploy plane an unmodified `wrangler deploy` drives beyond the script upload:
|
|
761
|
+
// static-assets upload sessions and bucketed uploads, versions, deployments, script settings,
|
|
762
|
+
// and secrets listing. Same discipline: fresh root, response VALUES, and the negative path.
|
|
763
|
+
const ASSET_A = 'a1'.repeat(16);
|
|
764
|
+
const ASSET_B = 'b2'.repeat(16);
|
|
765
|
+
const ASSET_MANIFEST = { '/index.html': { hash: ASSET_A, size: 5 }, '/app.js': { hash: ASSET_B, size: 3 } };
|
|
766
|
+
function tokenPayload(jwt: unknown): Body {
|
|
767
|
+
try { return JSON.parse(Buffer.from(String(jwt).split('.')[1] ?? '', 'base64url').toString('utf8')) as Body; } catch { return {}; }
|
|
768
|
+
}
|
|
769
|
+
/** One bulk asset upload exactly as wrangler sends it: parts named by hash, base64 content. */
|
|
770
|
+
function assetUpload(jwt: string, files: Record<string, { type: string; content: string }>): Step {
|
|
771
|
+
const boundary = 'twin-asset-boundary';
|
|
772
|
+
const parts = Object.entries(files).map(([hash, file]) =>
|
|
773
|
+
`--${boundary}\r\nContent-Disposition: form-data; name="${hash}"; filename="${hash}"\r\nContent-Type: ${file.type}\r\n\r\n${Buffer.from(file.content).toString('base64')}\r\n`);
|
|
774
|
+
return { m: 'POST', p: `/accounts/${ACCOUNT}/workers/assets/upload?base64=true`, raw: `${parts.join('')}--${boundary}--\r\n`, ct: `multipart/form-data; boundary=${boundary}`, bearer: jwt };
|
|
775
|
+
}
|
|
776
|
+
/** Session → upload every bucket → the completion token (the whole wrangler asset sync). */
|
|
777
|
+
async function syncAssets(call: Call, name = 'cert-worker'): Promise<string> {
|
|
778
|
+
const session = await call({ m: 'POST', p: `/accounts/${ACCOUNT}/workers/scripts/${name}/assets-upload-session`, b: { manifest: ASSET_MANIFEST } });
|
|
779
|
+
const jwt = String((session.body as Body).result?.jwt ?? '');
|
|
780
|
+
if (((session.body as Body).result?.buckets ?? []).length === 0) return jwt;
|
|
781
|
+
const done = await call(assetUpload(jwt, { [ASSET_A]: { type: 'text/html', content: 'hello' }, [ASSET_B]: { type: 'text/javascript', content: '1+1' } }));
|
|
782
|
+
return String((done.body as Body).result?.jwt ?? '');
|
|
783
|
+
}
|
|
784
|
+
async function deployVersion(call: Call, name = 'cert-worker', metadata: Body = { main_module: 'worker.js' }, body = 'export default {};'): Promise<CloudflareResponse> {
|
|
785
|
+
const upload = moduleUpload(metadata, { 'worker.js': body });
|
|
786
|
+
return call({ ...upload, m: 'POST', p: `/accounts/${ACCOUNT}/workers/scripts/${name}/versions` });
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
const deployPlaneVerifiers = new Map<string, Verify>([
|
|
790
|
+
['POST /accounts/{account_id}/workers/scripts/{script_name}/assets-upload-session', () => withRoot(async (call) => {
|
|
791
|
+
await seed(call);
|
|
792
|
+
const invalid = await call({ m: 'POST', p: `/accounts/${ACCOUNT}/workers/scripts/cert-worker/assets-upload-session`, b: { manifest: { 'no-slash': { hash: ASSET_A, size: 1 } } } });
|
|
793
|
+
const first = await call({ m: 'POST', p: `/accounts/${ACCOUNT}/workers/scripts/cert-worker/assets-upload-session`, b: { manifest: ASSET_MANIFEST } });
|
|
794
|
+
const buckets = ((first.body as Body).result?.buckets ?? []).flat().sort().join(',');
|
|
795
|
+
await syncAssets(call);
|
|
796
|
+
// Once the account holds both hashes, a new session names no buckets and its jwt already completes.
|
|
797
|
+
const again = await call({ m: 'POST', p: `/accounts/${ACCOUNT}/workers/scripts/cert-worker/assets-upload-session`, b: { manifest: ASSET_MANIFEST } });
|
|
798
|
+
return invalid.status === 400 && first.status === 200
|
|
799
|
+
&& buckets === [ASSET_A, ASSET_B].sort().join(',') && tokenPayload((first.body as Body).result?.jwt).purpose === 'upload'
|
|
800
|
+
&& again.status === 200 && (again.body as Body).result?.buckets?.length === 0
|
|
801
|
+
&& tokenPayload((again.body as Body).result?.jwt).purpose === 'completion';
|
|
802
|
+
})],
|
|
803
|
+
['POST /accounts/{account_id}/workers/assets/upload', () => withRoot(async (call) => {
|
|
804
|
+
await seed(call);
|
|
805
|
+
const session = await call({ m: 'POST', p: `/accounts/${ACCOUNT}/workers/scripts/cert-worker/assets-upload-session`, b: { manifest: ASSET_MANIFEST } });
|
|
806
|
+
const jwt = String((session.body as Body).result?.jwt);
|
|
807
|
+
// The API token is not the session token; a size that disagrees with the manifest is refused.
|
|
808
|
+
const apiToken = await call({ ...assetUpload(jwt, { [ASSET_A]: { type: 'text/html', content: 'hello' } }), bearer: undefined });
|
|
809
|
+
const wrongSize = await call(assetUpload(jwt, { [ASSET_A]: { type: 'text/html', content: 'hello world' } }));
|
|
810
|
+
const partial = await call(assetUpload(jwt, { [ASSET_A]: { type: 'text/html', content: 'hello' } }));
|
|
811
|
+
const complete = await call(assetUpload(jwt, { [ASSET_B]: { type: 'text/javascript', content: '1+1' } }));
|
|
812
|
+
const completion = String((complete.body as Body).result?.jwt ?? '');
|
|
813
|
+
// The completion token is redeemed by the script upload; an assets binding with no assets is refused.
|
|
814
|
+
const noAssets = await deployWorker(call, 'cert-worker', { main_module: 'worker.js', bindings: [{ type: 'assets', name: 'ASSETS' }] });
|
|
815
|
+
const withAssets = await deployWorker(call, 'cert-worker', { main_module: 'worker.js', bindings: [{ type: 'assets', name: 'ASSETS' }], assets: { jwt: completion, config: { run_worker_first: true } } });
|
|
816
|
+
return apiToken.status === 401 && wrongSize.status === 400
|
|
817
|
+
&& partial.status === 200 && !Object.hasOwn((partial.body as Body).result ?? {}, 'jwt')
|
|
818
|
+
&& complete.status === 200 && tokenPayload(completion).purpose === 'completion'
|
|
819
|
+
&& noAssets.status === 400 && withAssets.status === 200 && (withAssets.body as Body).result?.has_assets === true;
|
|
820
|
+
})],
|
|
821
|
+
['GET /accounts/{account_id}/workers/scripts/{script_name}/versions', () => withRoot(async (call) => {
|
|
822
|
+
await seed(call);
|
|
823
|
+
await deployWorker(call);
|
|
824
|
+
const second = await deployWorker(call, 'cert-worker', { main_module: 'worker.js', compatibility_date: '2026-09-01' });
|
|
825
|
+
const listed = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/workers/scripts/cert-worker/versions` });
|
|
826
|
+
const missing = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/workers/scripts/never-uploaded/versions` });
|
|
827
|
+
const items = (listed.body as Body).result?.items ?? [];
|
|
828
|
+
return listed.status === 200 && items.length === 2 && items[0]?.number === 2 && items[1]?.number === 1
|
|
829
|
+
&& items[0]?.id === (second.body as Body).result?.deployment_id
|
|
830
|
+
&& items[0]?.resources?.script_runtime?.compatibility_date === '2026-09-01'
|
|
831
|
+
&& missing.status === 404 && (missing.body as Body).errors?.[0]?.code === 10007;
|
|
832
|
+
})],
|
|
833
|
+
['GET /accounts/{account_id}/workers/scripts/{script_name}/versions/{version_id}', () => withRoot(async (call) => {
|
|
834
|
+
await seed(call);
|
|
835
|
+
const uploaded = await deployWorker(call, 'cert-worker', { main_module: 'worker.js', bindings: [{ type: 'secret_text', name: 'API_KEY', text: 'shh' }] });
|
|
836
|
+
const id = (uploaded.body as Body).result?.deployment_id;
|
|
837
|
+
const fetched = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/workers/scripts/cert-worker/versions/${id}` });
|
|
838
|
+
const missing = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/workers/scripts/cert-worker/versions/${'0'.repeat(8)}-0000-4000-a000-${'0'.repeat(12)}` });
|
|
839
|
+
const value = (fetched.body as Body).result;
|
|
840
|
+
return fetched.status === 200 && value?.id === id && value?.number === 1
|
|
841
|
+
&& value?.resources?.script?.etag === (uploaded.body as Body).result?.etag
|
|
842
|
+
&& value?.resources?.bindings?.[0]?.name === 'API_KEY' && !Object.hasOwn(value?.resources?.bindings?.[0] ?? {}, 'text')
|
|
843
|
+
&& missing.status === 404;
|
|
844
|
+
})],
|
|
845
|
+
['GET /accounts/{account_id}/workers/scripts/{script_name}/deployments', () => withRoot(async (call) => {
|
|
846
|
+
await seed(call);
|
|
847
|
+
const missing = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/workers/scripts/cert-worker/deployments` });
|
|
848
|
+
const uploaded = await deployWorker(call);
|
|
849
|
+
const listed = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/workers/scripts/cert-worker/deployments` });
|
|
850
|
+
const latest = (listed.body as Body).result?.deployments?.[0];
|
|
851
|
+
return missing.status === 404 && (missing.body as Body).errors?.[0]?.code === 10007
|
|
852
|
+
&& listed.status === 200 && latest?.strategy === 'percentage'
|
|
853
|
+
&& latest?.versions?.[0]?.version_id === (uploaded.body as Body).result?.deployment_id && latest?.versions?.[0]?.percentage === 100;
|
|
854
|
+
})],
|
|
855
|
+
['POST /accounts/{account_id}/workers/scripts/{script_name}/deployments', () => withRoot(async (call) => {
|
|
856
|
+
await seed(call);
|
|
857
|
+
const first = await deployWorker(call);
|
|
858
|
+
// A version upload does not change the live Worker until a deployment routes traffic to it.
|
|
859
|
+
const version = await deployVersion(call, 'cert-worker', { main_module: 'worker.js' }, 'export default { v: 2 };');
|
|
860
|
+
const versionID = (version.body as Body).result?.id;
|
|
861
|
+
const before = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/workers/scripts/cert-worker/settings` });
|
|
862
|
+
const badSum = await call({ m: 'POST', p: `/accounts/${ACCOUNT}/workers/scripts/cert-worker/deployments`, b: { strategy: 'percentage', versions: [{ version_id: versionID, percentage: 60 }, { version_id: (first.body as Body).result?.deployment_id, percentage: 50 }] } });
|
|
863
|
+
const unknown = await call({ m: 'POST', p: `/accounts/${ACCOUNT}/workers/scripts/cert-worker/deployments`, b: { strategy: 'percentage', versions: [{ version_id: 'not-a-version', percentage: 100 }] } });
|
|
864
|
+
const deployed = await call({ m: 'POST', p: `/accounts/${ACCOUNT}/workers/scripts/cert-worker/deployments`, b: { strategy: 'percentage', versions: [{ version_id: versionID, percentage: 100 }], annotations: { 'workers/message': 'ship v2' } } });
|
|
865
|
+
const listed = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/workers/scripts/cert-worker/deployments` });
|
|
866
|
+
const download = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/workers/scripts/cert-worker` });
|
|
867
|
+
return version.status === 200 && before.status === 200 && badSum.status === 400 && unknown.status === 400
|
|
868
|
+
&& deployed.status === 200 && (deployed.body as Body).result?.annotations?.['workers/message'] === 'ship v2'
|
|
869
|
+
&& (listed.body as Body).result?.deployments?.[0]?.id === (deployed.body as Body).result?.id
|
|
870
|
+
&& String(download.body).includes('v: 2');
|
|
871
|
+
})],
|
|
872
|
+
['GET /accounts/{account_id}/workers/scripts/{script_name}/script-settings', () => withRoot(async (call) => {
|
|
873
|
+
await seed(call);
|
|
874
|
+
await deployWorker(call, 'cert-worker', { main_module: 'worker.js', logpush: true, tags: ['launch'] });
|
|
875
|
+
const fetched = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/workers/scripts/cert-worker/script-settings` });
|
|
876
|
+
const missing = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/workers/scripts/never-uploaded/script-settings` });
|
|
877
|
+
const value = (fetched.body as Body).result;
|
|
878
|
+
return fetched.status === 200 && value?.logpush === true && value?.tags?.[0] === 'launch' && missing.status === 404;
|
|
879
|
+
})],
|
|
880
|
+
['PATCH /accounts/{account_id}/workers/scripts/{script_name}/script-settings', () => withRoot(async (call) => {
|
|
881
|
+
await seed(call);
|
|
882
|
+
await deployWorker(call);
|
|
883
|
+
const invalid = await call({ m: 'PATCH', p: `/accounts/${ACCOUNT}/workers/scripts/cert-worker/script-settings`, b: { logpush: 'yes' } });
|
|
884
|
+
const patched = await call({ m: 'PATCH', p: `/accounts/${ACCOUNT}/workers/scripts/cert-worker/script-settings`, b: { observability: { enabled: true, head_sampling_rate: 0.5 }, tags: ['env:prod'] } });
|
|
885
|
+
const after = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/workers/scripts/cert-worker/script-settings` });
|
|
886
|
+
const value = (after.body as Body).result;
|
|
887
|
+
return invalid.status === 400 && patched.status === 200
|
|
888
|
+
&& value?.observability?.enabled === true && value?.observability?.head_sampling_rate === 0.5
|
|
889
|
+
&& value?.tags?.[0] === 'env:prod' && value?.logpush === false;
|
|
890
|
+
})],
|
|
891
|
+
['GET /accounts/{account_id}/workers/scripts/{script_name}/settings', () => withRoot(async (call) => {
|
|
892
|
+
await seed(call);
|
|
893
|
+
await deployWorker(call, 'cert-worker', { main_module: 'worker.js', compatibility_date: '2026-09-01', bindings: [
|
|
894
|
+
{ type: 'plain_text', name: 'MODE', text: 'prod' }, { type: 'secret_text', name: 'API_KEY', text: 'shh' },
|
|
895
|
+
] });
|
|
896
|
+
const fetched = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/workers/scripts/cert-worker/settings` });
|
|
897
|
+
const missing = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/workers/scripts/never-uploaded/settings` });
|
|
898
|
+
const bindings = (fetched.body as Body).result?.bindings ?? [];
|
|
899
|
+
const secret = bindings.find((item: Body) => item.name === 'API_KEY');
|
|
900
|
+
return fetched.status === 200 && (fetched.body as Body).result?.compatibility_date === '2026-09-01'
|
|
901
|
+
&& bindings.find((item: Body) => item.name === 'MODE')?.text === 'prod'
|
|
902
|
+
&& secret?.type === 'secret_text' && !Object.hasOwn(secret ?? {}, 'text')
|
|
903
|
+
&& missing.status === 404 && (missing.body as Body).errors?.[0]?.code === 10007;
|
|
904
|
+
})],
|
|
905
|
+
['GET /accounts/{account_id}/workers/scripts/{script_name}/secrets', () => withRoot(async (call) => {
|
|
906
|
+
await seed(call);
|
|
907
|
+
await deployWorker(call, 'cert-worker', { main_module: 'worker.js', bindings: [
|
|
908
|
+
{ type: 'plain_text', name: 'MODE', text: 'prod' }, { type: 'secret_text', name: 'API_KEY', text: 'shh' },
|
|
909
|
+
] });
|
|
910
|
+
const listed = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/workers/scripts/cert-worker/secrets` });
|
|
911
|
+
const missing = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/workers/scripts/never-uploaded/secrets` });
|
|
912
|
+
const result = (listed.body as Body).result ?? [];
|
|
913
|
+
return listed.status === 200 && result.length === 1 && result[0]?.name === 'API_KEY' && result[0]?.type === 'secret_text'
|
|
914
|
+
&& !Object.hasOwn(result[0] ?? {}, 'text')
|
|
915
|
+
&& missing.status === 404 && (missing.body as Body).errors?.[0]?.code === 10007;
|
|
916
|
+
})],
|
|
917
|
+
['GET /accounts/{account_id}/workers/scripts/{script_name}/secrets/{secret_name}', () => withRoot(async (call) => {
|
|
918
|
+
await seed(call);
|
|
919
|
+
await deployWorker(call, 'cert-worker', { main_module: 'worker.js', bindings: [{ type: 'secret_text', name: 'API_KEY', text: 'shh' }] });
|
|
920
|
+
const fetched = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/workers/scripts/cert-worker/secrets/API_KEY` });
|
|
921
|
+
const missing = await call({ m: 'GET', p: `/accounts/${ACCOUNT}/workers/scripts/cert-worker/secrets/NOPE` });
|
|
922
|
+
return fetched.status === 200 && (fetched.body as Body).result?.name === 'API_KEY'
|
|
923
|
+
&& !Object.hasOwn((fetched.body as Body).result ?? {}, 'text') && missing.status === 404;
|
|
924
|
+
})],
|
|
925
|
+
]);
|
|
926
|
+
for (const [key, verify] of deployPlaneVerifiers) operationVerifiers.set(key, verify);
|
|
927
|
+
|
|
928
|
+
// These official operations contain broad unions/nested schemas. The twin deliberately
|
|
929
|
+
// supports the certification-needed slices (ingress; CNAME/A/CAA records; the multipart
|
|
930
|
+
// module upload with the deploy-critical binding kinds and Durable Object migrations), but
|
|
931
|
+
// each whole vendor operation stays todo until every official variant is schema-faithful.
|
|
932
|
+
const INCOMPLETE_OPERATION_UNIONS = new Set([
|
|
933
|
+
'PUT /accounts/{account_id}/cfd_tunnel/{tunnel_id}/configurations',
|
|
934
|
+
'POST /zones/{zone_id}/dns_records',
|
|
935
|
+
'PUT /zones/{zone_id}/dns_records/{dns_record_id}',
|
|
936
|
+
'PATCH /zones/{zone_id}/dns_records/{dns_record_id}',
|
|
937
|
+
// Served and exercised by every worker-seeding verify above, but the full multipart metadata
|
|
938
|
+
// union (38 binding kinds, assets, placement, limits, observability) is far broader than the
|
|
939
|
+
// implemented deploy slice — the whole vendor operation honestly stays todo.
|
|
940
|
+
'PUT /accounts/{account_id}/workers/scripts/{script_name}',
|
|
941
|
+
// The versions upload carries the same multipart metadata union as the script PUT above.
|
|
942
|
+
'POST /accounts/{account_id}/workers/scripts/{script_name}/versions',
|
|
943
|
+
]);
|
|
944
|
+
|
|
945
|
+
const operationCapabilities: CapabilitySpec[] = CLOUDFLARE_OPENAPI_OPERATIONS.map((operation) => {
|
|
946
|
+
const operationKey = `${operation.method} ${operation.path}`;
|
|
947
|
+
const verify = INCOMPLETE_OPERATION_UNIONS.has(operationKey) ? undefined : operationVerifiers.get(operationKey);
|
|
948
|
+
return {
|
|
949
|
+
id: operation.id,
|
|
950
|
+
area: operation.area,
|
|
951
|
+
title: `${operation.method} ${operation.path} — ${operation.summary}`,
|
|
952
|
+
dimension: 'api',
|
|
953
|
+
tier: operation.tier,
|
|
954
|
+
expected: verify ? 'done' : 'todo',
|
|
955
|
+
...(verify ? { verify } : {}),
|
|
956
|
+
};
|
|
957
|
+
});
|
|
958
|
+
|
|
959
|
+
const doneConnector = (id: string, title: string, tier: CapabilitySpec['tier'], verify: Verify): CapabilitySpec => ({
|
|
960
|
+
id, area: 'connector', title, dimension: 'connector', tier, expected: 'done', verify,
|
|
961
|
+
});
|
|
962
|
+
|
|
963
|
+
const connectorCapabilities: CapabilitySpec[] = [
|
|
964
|
+
doneConnector('cloudflare.connector.pull_complete_pagination', 'Pull walks every result_info page across the account graph', 'core', async () => {
|
|
965
|
+
const calls: string[] = [];
|
|
966
|
+
const execute: CloudflareExecute = async (_method, path) => {
|
|
967
|
+
calls.push(path);
|
|
968
|
+
const page = Number(new URL(path, 'https://x.invalid').searchParams.get('page') ?? 1);
|
|
969
|
+
if (path.startsWith('/accounts?')) return { status: 200, body: { success: true, result: [{ id: page === 1 ? ACCOUNT : 'c'.repeat(32), name: `A${page}` }], result_info: { page, total_pages: 2 } } };
|
|
970
|
+
if (path.startsWith('/zones?')) return { status: 200, body: { success: true, result: [{ id: ZONE, name: 'example.test', account: { id: ACCOUNT } }], result_info: { page, total_pages: 1 } } };
|
|
971
|
+
return { status: 200, body: { success: true, result: [], result_info: { page, total_pages: 1 } } };
|
|
972
|
+
};
|
|
973
|
+
const result = await pullCloudflareState(execute);
|
|
974
|
+
return result.length === 3 && calls.includes('/accounts?per_page=50&page=2');
|
|
975
|
+
}),
|
|
976
|
+
doneConnector('cloudflare.connector.pull_idempotent', 'Repeated identical pull is idempotent in the projection', 'core', () => withRoot(async (_call, root) => {
|
|
977
|
+
const execute: CloudflareExecute = async (_method, path) => ({ status: 200, body: { success: true, result: path.startsWith('/accounts?') ? [{ id: ACCOUNT, name: 'Acme' }] : [] } });
|
|
978
|
+
const first = await syncCloudflareFromReal(execute, { root, occurredAt: AT });
|
|
979
|
+
const second = await syncCloudflareFromReal(execute, { root, occurredAt: AT });
|
|
980
|
+
return first.deltasAppended === 1 && second.deltasAppended === 0;
|
|
981
|
+
})),
|
|
982
|
+
doneConnector('cloudflare.connector.pull_refuses_invalid_envelope', 'Pull requires a valid success:true envelope and refuses transport failures', 'core', async () => {
|
|
983
|
+
for (const response of [{ status: 200, body: {} }, { status: 403, body: { success: false, errors: [{ message: 'denied' }] } }]) {
|
|
984
|
+
try { await pullCloudflareState(async () => response); return false; } catch (error) { if (!String(error).includes('refused')) return false; }
|
|
985
|
+
}
|
|
986
|
+
return true;
|
|
987
|
+
}),
|
|
988
|
+
doneConnector('cloudflare.connector.pull_deletion_convergence', 'A complete later pull tombstones vendor-observed resources that disappeared', 'core', () => withRoot(async (_call, root) => {
|
|
989
|
+
let present = true;
|
|
990
|
+
const execute: CloudflareExecute = async (_method, path) => ({ status: 200, body: {
|
|
991
|
+
success: true,
|
|
992
|
+
result: path.startsWith('/accounts?') && present ? [{ id: ACCOUNT, name: 'Acme' }] : [],
|
|
993
|
+
result_info: { page: 1, total_pages: 1 },
|
|
994
|
+
} });
|
|
995
|
+
await syncCloudflareFromReal(execute, { root, occurredAt: AT }); present = false;
|
|
996
|
+
await syncCloudflareFromReal(execute, { root, occurredAt: '2026-08-21T00:00:01.000Z' });
|
|
997
|
+
return projectResources('cloudflare', root).find((resource) => resource.id === ACCOUNT)?.deleted === true;
|
|
998
|
+
})),
|
|
999
|
+
doneConnector('cloudflare.connector.pull_incomplete_inventory_safe', 'A metadata-free partial inventory cannot tombstone unseen vendor resources', 'core', () => withRoot(async (_call, root) => {
|
|
1000
|
+
let includeSecond = true;
|
|
1001
|
+
const secondID = 'c'.repeat(32);
|
|
1002
|
+
const execute: CloudflareExecute = async (_method, path) => ({ status: 200, body: {
|
|
1003
|
+
success: true,
|
|
1004
|
+
result: path.startsWith('/accounts?') ? [{ id: ACCOUNT, name: 'A' }, ...(includeSecond ? [{ id: secondID, name: 'B' }] : [])] : [],
|
|
1005
|
+
} });
|
|
1006
|
+
await syncCloudflareFromReal(execute, { root, occurredAt: AT }); includeSecond = false;
|
|
1007
|
+
await syncCloudflareFromReal(execute, { root, occurredAt: '2026-08-21T00:00:01.000Z' });
|
|
1008
|
+
// the row is still there and still live: an inventory that never said it was complete cannot erase it
|
|
1009
|
+
const unseen = projectResources('cloudflare', root).find((resource) => resource.id === secondID);
|
|
1010
|
+
return unseen !== undefined && unseen.deleted !== true;
|
|
1011
|
+
})),
|
|
1012
|
+
doneConnector('cloudflare.connector.pull_tunnel_deletion_timestamp', 'Complete pull tunnel tombstones expose the observation timestamp', 'common', () => withRoot(async (_call, root) => {
|
|
1013
|
+
let present = true;
|
|
1014
|
+
const execute: CloudflareExecute = async (_method, path) => {
|
|
1015
|
+
if (path.endsWith('/configurations')) return { status: 404, body: { success: false, result: null, errors: [] } };
|
|
1016
|
+
const result = path.startsWith('/accounts?') ? [{ id: ACCOUNT, name: 'A' }]
|
|
1017
|
+
: path.startsWith('/zones?') ? []
|
|
1018
|
+
: path.includes('/cfd_tunnel?') && present ? [{ id: VENDOR_TUNNEL, account_tag: ACCOUNT, name: 't', config_src: 'cloudflare' }] : [];
|
|
1019
|
+
return { status: 200, body: { success: true, result, result_info: { page: 1, total_pages: 1 } } };
|
|
1020
|
+
};
|
|
1021
|
+
await syncCloudflareFromReal(execute, { root, occurredAt: AT }); present = false;
|
|
1022
|
+
const deletedAt = '2026-08-21T00:00:01.000Z';
|
|
1023
|
+
await syncCloudflareFromReal(execute, { root, occurredAt: deletedAt });
|
|
1024
|
+
const value = projectResources('cloudflare', root).find((resource) => resource.id === VENDOR_TUNNEL);
|
|
1025
|
+
return value?.deleted === true && value.deleted_at === deletedAt;
|
|
1026
|
+
})),
|
|
1027
|
+
doneConnector('cloudflare.connector.mapper_schema_validation', 'Pull rejects malformed vendor fixtures before folding impossible identities', 'common', async () => {
|
|
1028
|
+
try { await pullCloudflareState(async () => ({ status: 200, body: { success: true, result: [{}] } })); return false; }
|
|
1029
|
+
catch (error) { return String(error).includes('id must be a nonempty string'); }
|
|
1030
|
+
}),
|
|
1031
|
+
doneConnector('cloudflare.connector.configuration_identity', 'Pulled and locally-updated configuration converge on one account+tunnel identity', 'core', () => withRoot(async (call, root) => {
|
|
1032
|
+
await seed(call);
|
|
1033
|
+
await applyTwinWrite('cloudflare', { operation: 'tunnel.observe', subjectType: 'cloudflare_tunnel', subjectId: VENDOR_TUNNEL, fields: { account_id: ACCOUNT, name: 't', config_src: 'cloudflare', status: 'inactive', _deleted: false }, occurredAt: AT, actor: { kind: 'system' } }, root);
|
|
1034
|
+
await call({ m: 'PUT', p: `/accounts/${ACCOUNT}/cfd_tunnel/${VENDOR_TUNNEL}/configurations`, b: { config: { ingress: [{ hostname: '*', service: 'http_status:503' }] } } });
|
|
1035
|
+
const execute: CloudflareExecute = async (_method, path) => ({ status: 200, body: { success: true, result: path.startsWith('/accounts?') ? [{ id: ACCOUNT, name: 'Acme' }] : path.startsWith('/zones?') ? [] : path.includes('/cfd_tunnel?') ? [{ id: VENDOR_TUNNEL, account_tag: ACCOUNT, name: 't', config_src: 'cloudflare' }] : { account_id: ACCOUNT, tunnel_id: VENDOR_TUNNEL, config: { ingress: [{ hostname: '*', service: 'http_status:404' }] } } } });
|
|
1036
|
+
await syncCloudflareFromReal(execute, { root, occurredAt: '2026-08-21T00:00:01.000Z' });
|
|
1037
|
+
return projectResources('cloudflare', root).filter((value) => value.type === 'tunnel_configuration').length === 1;
|
|
1038
|
+
})),
|
|
1039
|
+
doneConnector('cloudflare.connector.pull_call_conservation', 'Pull fetches configuration only for remotely-managed tunnels', 'common', async () => {
|
|
1040
|
+
const paths: string[] = [];
|
|
1041
|
+
const execute: CloudflareExecute = async (_method, path) => { paths.push(path); return { status: 200, body: { success: true, result: path.startsWith('/accounts?') ? [{ id: ACCOUNT, name: 'Acme' }] : path.includes('/cfd_tunnel?') ? [{ id: VENDOR_TUNNEL, name: 'local', config_src: 'local', account_tag: ACCOUNT }] : [] } }; };
|
|
1042
|
+
await pullCloudflareState(execute);
|
|
1043
|
+
return paths.length === 3 && !paths.some((path) => path.endsWith('/configurations'));
|
|
1044
|
+
}),
|
|
1045
|
+
doneConnector('cloudflare.connector.push', 'performCloudflareAction carries each entry across through the kernel\'s executor: the tunnel create answers Cloudflare\'s own id, and the configuration that follows is addressed to THAT id, not the local one (protocol 2)', 'core', () => withRoot(async (call, root) => {
|
|
1046
|
+
await seed(call); const localTunnel = await tunnel(call, 'push-me');
|
|
1047
|
+
await call({ m: 'PUT', p: `/accounts/${ACCOUNT}/cfd_tunnel/${localTunnel}/configurations`, b: { config: { ingress: [{ hostname: '*', service: 'http_status:404' }] } } });
|
|
1048
|
+
let failConfiguration = true;
|
|
1049
|
+
const { execute, seen } = vendor((method, _path, body) => {
|
|
1050
|
+
if (method === 'POST') return { status: 200, body: { success: true, result: { id: VENDOR_TUNNEL, account_tag: ACCOUNT, name: 'push-me', config_src: 'cloudflare' } } };
|
|
1051
|
+
if (failConfiguration) return { status: 500, body: { success: false, errors: [{ message: 'retry' }], result: null } };
|
|
1052
|
+
return { status: 200, body: { success: true, result: { account_id: ACCOUNT, tunnel_id: VENDOR_TUNNEL, config: body?.config } } };
|
|
1053
|
+
});
|
|
1054
|
+
// the vendor refuses the configuration once: the create is already across, and the dependent entry stops the batch
|
|
1055
|
+
const first = await performAll(root, execute);
|
|
1056
|
+
if (first.failed === null || !first.failed.includes('retry')) return false;
|
|
1057
|
+
if (first.adopted.get(`cloudflare_tunnel:${localTunnel}`) !== VENDOR_TUNNEL) return false;
|
|
1058
|
+
failConfiguration = false;
|
|
1059
|
+
const again = await performAll(root, execute, first.adopted, first.done);
|
|
1060
|
+
const configurations = seen.filter((request) => request.path.includes('/configurations'));
|
|
1061
|
+
return again.failed === null && configurations.length > 0
|
|
1062
|
+
&& configurations.every((request) => request.path.includes(VENDOR_TUNNEL) && !request.path.includes(localTunnel));
|
|
1063
|
+
})),
|
|
1064
|
+
doneConnector('cloudflare.connector.push_confirmation_shape', 'A perform refuses an HTTP 200 body without success:true and the result identity Cloudflare owes — the entry stays undeployed rather than being marked across on a shapeless answer', 'core', () => withRoot(async (call, root) => {
|
|
1065
|
+
await seed(call); await tunnel(call, 'do-not-confirm');
|
|
1066
|
+
const before = deployableEntries('cloudflare', root).filter((entry) => entry.operation === 'tunnel.create').length;
|
|
1067
|
+
const shapeless = vendor(() => ({ status: 200, body: {} }));
|
|
1068
|
+
const refused = await performAll(root, shapeless.execute);
|
|
1069
|
+
if (refused.failed === null || before === 0) return false;
|
|
1070
|
+
// the same seam confirms a well-shaped answer, so the refusal was the SHAPE and not the seam
|
|
1071
|
+
const proper = vendor(() => ({ status: 200, body: { success: true, result: { id: VENDOR_TUNNEL } } }));
|
|
1072
|
+
const accepted = await performAll(root, proper.execute);
|
|
1073
|
+
return accepted.failed === null && accepted.adopted.size > 0;
|
|
1074
|
+
})),
|
|
1075
|
+
doneConnector('cloudflare.connector.push_dns_replace', 'A local DNS PUT stays a vendor PUT, addressed to the adopted record id, and omits the fields the replacement cleared', 'common', () => withRoot(async (call, root) => {
|
|
1076
|
+
await seed(call);
|
|
1077
|
+
const created = await call({ m: 'POST', p: `/zones/${ZONE}/dns_records`, b: {
|
|
1078
|
+
type: 'A', name: 'replace.example.test', ttl: 60, content: '192.0.2.1', private_routing: true,
|
|
1079
|
+
} });
|
|
1080
|
+
const localID = String((created.body as Body).result?.id);
|
|
1081
|
+
const vendorID = 'e'.repeat(32);
|
|
1082
|
+
const first = vendor(() => ({ status: 200, body: { success: true, result: { id: vendorID } } }));
|
|
1083
|
+
const after = await performAll(root, first.execute);
|
|
1084
|
+
if (after.failed !== null || after.adopted.get(`dns_record:${localID}`) !== vendorID) return false;
|
|
1085
|
+
await call({ m: 'PUT', p: `/zones/${ZONE}/dns_records/${localID}`, b: {
|
|
1086
|
+
type: 'CAA', name: 'replace.example.test', ttl: 120, data: { flags: 0, tag: 'issue', value: 'pki.goog' },
|
|
1087
|
+
} });
|
|
1088
|
+
const second = vendor(() => ({ status: 200, body: { success: true, result: { id: vendorID } } }));
|
|
1089
|
+
const replay = await performAll(root, second.execute, after.adopted, after.done);
|
|
1090
|
+
const observed = second.seen.at(-1);
|
|
1091
|
+
return replay.failed === null && observed?.method === 'PUT' && observed.path.endsWith(`/dns_records/${vendorID}`)
|
|
1092
|
+
&& observed.body?.type === 'CAA' && !Object.hasOwn(observed.body ?? {}, 'content')
|
|
1093
|
+
&& !Object.hasOwn(observed.body ?? {}, 'private_routing');
|
|
1094
|
+
})),
|
|
1095
|
+
doneConnector('cloudflare.connector.budget_weights', 'Budget weights reads at 2 and mutations at 3', 'core', () => cloudflareCallWeight('GET', '/zones') === 2 && cloudflareCallWeight('POST', '/zones/x/dns_records') === 3),
|
|
1096
|
+
doneConnector('cloudflare.connector.budget_ceiling', 'Budget rejects calls above the conservative 60-unit minute', 'core', () => {
|
|
1097
|
+
const root = mkdtempSync(join(tmpdir(), 'cloudflare-budget-cap-'));
|
|
1098
|
+
try { const budget = new CloudflareBudget({ root, token: 'cap' }); budget.recordCall(CLOUDFLARE_BUDGET_CEILING); try { budget.checkBudget(1); return false; } catch (error) { return error instanceof CloudflareBudgetError; } }
|
|
1099
|
+
finally { rmSync(root, { recursive: true, force: true }); }
|
|
1100
|
+
}),
|
|
1101
|
+
];
|
|
1102
|
+
|
|
1103
|
+
export const CLOUDFLARE_CAPABILITIES: CapabilitySpec[] = [...operationCapabilities, ...connectorCapabilities];
|
|
1104
|
+
|
|
1105
|
+
export async function cloudflareCapabilities(): Promise<CapabilityReport> {
|
|
1106
|
+
return checkCapabilities('cloudflare', CLOUDFLARE_CAPABILITIES);
|
|
1107
|
+
}
|