Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions docs/cloudflare-provisioning-api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Cloudflare provisioning API core

The D1 Worker exposes a versioned control-plane API before hostname-based WordPress routing. `/v1/*` never boots or falls through to WordPress.

## Authentication

`WORDPRESS_API_TOKENS` is a JSON array of bounded verifier records:

```json
[{"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"]}]
```

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.

## Resources

- `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.
- `GET /v1/sites/{siteId}` requires `sites:read`.
- `POST /v1/sites/{siteId}/imports` requires `sites:import` and uses the existing bounded static-artifact request.
- `GET /v1/sites/{siteId}/operations/{operationId}` requires `operations:read`.

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.

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.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@
"generate:cloudflare-canonical-mdi-seed": "npm run generate:cloudflare-mdi-runtime-bundle && php scripts/build-cloudflare-canonical-mdi-seed.php",
"smoke": "tsx scripts/run-smoke.ts",
"test:redaction": "tsx tests/redaction.test.ts",
"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",
"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",
"test:cloudflare-wordpress-auth": "tsx tests/cloudflare-wordpress-auth.test.ts",
"test:cloudflare-wordpress-archive-corpus": "tsx tests/cloudflare-wordpress-archive-corpus.test.ts",
"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",
Expand Down
3 changes: 3 additions & 0 deletions packages/runtime-cloudflare/src/d1-operation-repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ export function shouldRecoverPreparedCommit(prepared: StaticArtifactOperation["p
export class D1OperationRepository {
constructor(private readonly database: D1Database, private readonly claimMs = 600_000) {}

/** Makes the shipped operation/site schema available to API allocation code. */
async initialize(): Promise<void> { await ensureSchema(this.database) }

async createOrConverge(site: SiteContext, input: StaticArtifactOperationInput): Promise<{ operation: StaticArtifactOperation; created: boolean }> {
await ensureSchema(this.database)
const now = Date.now()
Expand Down
Loading
Loading