Skip to content

Commit 96f2c00

Browse files
authored
Merge pull request #1999 from Automattic/feat/1971-authenticated-provisioning-api
Add authenticated Cloudflare provisioning API core
2 parents 6d23e72 + 6f58fe3 commit 96f2c00

7 files changed

Lines changed: 336 additions & 3 deletions

File tree

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Cloudflare provisioning API core
2+
3+
The D1 Worker exposes a versioned control-plane API before hostname-based WordPress routing. `/v1/*` never boots or falls through to WordPress.
4+
5+
## Authentication
6+
7+
`WORDPRESS_API_TOKENS` is a JSON array of bounded verifier records:
8+
9+
```json
10+
[{"id":"client-a","principal":"client-a","digest":"<sha256 bearer token hex>","scopes":["sites:create","sites:read","sites:import","operations:read"],"expiresAt":"2027-01-01T00:00:00.000Z","maxSites":3,"sites":["optional-existing-site"]}]
11+
```
12+
13+
The Worker compares SHA-256 token digests and never accepts plaintext API credentials in configuration. `WORDPRESS_OPERATOR_TOKEN` remains exclusive to legacy `?phase=operator-*` endpoints.
14+
15+
## Resources
16+
17+
- `POST /v1/sites` requires `Authorization: Bearer ...` with `sites:create` and `Idempotency-Key`. Its body is `wp-codebox/provisioning-create-request/v1`; it references an immutable staged artifact at `sites/provisioning/import-artifacts/<sha256>.json`. The Worker verifies the bounded artifact before allocating a site, then copies it immutably to the selected site namespace.
18+
- `GET /v1/sites/{siteId}` requires `sites:read`.
19+
- `POST /v1/sites/{siteId}/imports` requires `sites:import` and uses the existing bounded static-artifact request.
20+
- `GET /v1/sites/{siteId}/operations/{operationId}` requires `operations:read`.
21+
22+
All responses use versioned WP Codebox provisioning schemas. Site IDs are allocated only from `WORDPRESS_SITE_CONTEXTS`; caller hostnames, DNS, and Cloudflare control APIs are not inputs. The allocation transaction reserves the same shipped D1 site identity used by legacy/operator operations, so both interfaces contend on one hostname and an existing site cannot be taken over. D1 stores allocation ownership, immutable artifact identity and import options, and API operation links. The scheduler resumes incomplete allocations for its selected site before it runs an operation; it verifies staged bytes and converges the conditional destination copy, operation, and API link without blocking publication or cron when recovery fails.
23+
24+
This is the API core portion of #1971. Administrator claims are intentionally a follow-up and are not represented by a route, secret, D1 field, resource field, documentation contract, or test in this PR.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@
105105
"generate:cloudflare-canonical-mdi-seed": "npm run generate:cloudflare-mdi-runtime-bundle && php scripts/build-cloudflare-canonical-mdi-seed.php",
106106
"smoke": "tsx scripts/run-smoke.ts",
107107
"test:redaction": "tsx tests/redaction.test.ts",
108-
"test:cloudflare-runtime": "node --test tests/cloudflare-d1-provisioner.test.mjs && tsx tests/cloudflare-site-context.test.ts && tsx tests/cloudflare-coordinator-site-partitioning.test.ts && tsx tests/cloudflare-d1-operation-repository.test.ts && tsx tests/cloudflare-runtime.test.ts && node ./node_modules/typescript/bin/tsc -p packages/runtime-cloudflare --noEmit",
108+
"test:cloudflare-runtime": "node --test tests/cloudflare-d1-provisioner.test.mjs && tsx tests/cloudflare-site-context.test.ts && tsx tests/cloudflare-coordinator-site-partitioning.test.ts && tsx tests/cloudflare-d1-operation-repository.test.ts && tsx tests/cloudflare-provisioning-api.test.ts && tsx tests/cloudflare-runtime.test.ts && node ./node_modules/typescript/bin/tsc -p packages/runtime-cloudflare --noEmit",
109109
"test:cloudflare-wordpress-auth": "tsx tests/cloudflare-wordpress-auth.test.ts",
110110
"test:cloudflare-wordpress-archive-corpus": "tsx tests/cloudflare-wordpress-archive-corpus.test.ts",
111111
"test:agent-task-contracts": "tsx tests/agent-task-contracts.test.ts && tsx tests/agent-task-canonical-evidence.test.ts && npm run test:agent-task-workflow-interface && npm run test:runtime-sources-materialization && tsx tests/agent-task-reusable-workflow.test.ts",

packages/runtime-cloudflare/src/d1-operation-repository.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ export function shouldRecoverPreparedCommit(prepared: StaticArtifactOperation["p
3333
export class D1OperationRepository {
3434
constructor(private readonly database: D1Database, private readonly claimMs = 600_000) {}
3535

36+
/** Makes the shipped operation/site schema available to API allocation code. */
37+
async initialize(): Promise<void> { await ensureSchema(this.database) }
38+
3639
async createOrConverge(site: SiteContext, input: StaticArtifactOperationInput): Promise<{ operation: StaticArtifactOperation; created: boolean }> {
3740
await ensureSchema(this.database)
3841
const now = Date.now()

0 commit comments

Comments
 (0)