diff --git a/docs/rfcs/0046-release-bundles.md b/docs/rfcs/0046-release-bundles.md index 71266634..5e7ae4f8 100644 --- a/docs/rfcs/0046-release-bundles.md +++ b/docs/rfcs/0046-release-bundles.md @@ -103,6 +103,14 @@ Root `release-manifest.schema.json` (`$id` `https://cloudhal.dev/schemas/v1/rele It holds `version`, `channel`, `securityRelease`, `commit`, `createdAt`, `contracts`, `levels` (`schedules`, `gates`, …), `migrations` (`first`, `last`, `count`, `names`, `compatibleWithPrevious`), `durableObjects` (`bindings`, `lifecycleChange`), `runtime` (compatibility date and flags), `toolchain`, `theme`, `skills`, `workers.site` and `workers.admin` (`mainModule`, `modules[]` with `path`/`type`/`bytes`/`sha256`, `assets` with `count`/`bytes`/`files[]` with a precomputed `assetHash`, inline `headers`), `bindingTemplates`, `requiredScopes`/`optionalScopes`, `requiredCapabilities`/`optionalCapabilities`, `starter`, `features` (a declared map of booleans: the named flags are required and unknown flags are allowed, so an older deployer ignores a new flag), `planVersion` and `signing`. +Scopes (amended 2026-11-14, #225): + +- `requiredScopes` and `optionalScopes` name Cloudflare OAuth scope ids. A deployer asks for every required scope and may ask for optional ones. +- Installing a release creates the site and admin Workers. Since Cloudflare's granular Worker roles (changelog 2026-09-15), only Workers Admin (`workers-scripts.admin`) can create a Worker. Workers Editor (`workers-scripts.edit`) can only change existing ones. Bundles from the next release on therefore require `workers-scripts.admin`. +- Manifests up to and including `v0.9.0` name `workers-scripts.edit`. Releases are immutable, so these manifests keep it. +- A consumer that compares a grant with `requiredScopes` treats `workers-scripts.admin` as covering `workers-scripts.edit`. A consumer that builds a grant from an older manifest asks for `workers-scripts.admin` in its place, because a grant with only `workers-scripts.edit` cannot install a release: the asset upload for a new Worker answers 403. +- This is the only implied scope. Every other id is compared exactly. + Provenance fields: - `commit` is the release commit, which is also the commit the tag names. diff --git a/packages/cli/test/release-bundle.test.ts b/packages/cli/test/release-bundle.test.ts index 6392518a..0d4f4413 100644 --- a/packages/cli/test/release-bundle.test.ts +++ b/packages/cli/test/release-bundle.test.ts @@ -254,4 +254,10 @@ describe("standard manifest facts follow the CLI", () => { expect([...standard.ADMIN_SECRETS]).toEqual([...SECRET_KEYS]); expect([...standard.SITE_SECRETS].sort()).toEqual([...SITE_SECRET_KEYS].sort()); }); + + it("asks for Workers Admin: an installer creates Workers, which Workers Editor cannot (#225)", () => { + const scopes = standard.STANDARD_MANIFEST_FIELDS.requiredScopes as readonly string[]; + expect(scopes).toContain("workers-scripts.admin"); + expect(scopes).not.toContain("workers-scripts.edit"); + }); }); diff --git a/packages/core-contracts/fixtures/invalid/release-manifest/asset-too-large.json b/packages/core-contracts/fixtures/invalid/release-manifest/asset-too-large.json index f3a1fda1..8293f439 100644 --- a/packages/core-contracts/fixtures/invalid/release-manifest/asset-too-large.json +++ b/packages/core-contracts/fixtures/invalid/release-manifest/asset-too-large.json @@ -163,7 +163,7 @@ }, "requiredScopes": [ "account-settings.read", - "workers-scripts.edit", + "workers-scripts.admin", "d1.write", "workers-r2.write" ], diff --git a/packages/core-contracts/fixtures/invalid/release-manifest/cli-site-id-too-short.json b/packages/core-contracts/fixtures/invalid/release-manifest/cli-site-id-too-short.json index 616afda9..696763de 100644 --- a/packages/core-contracts/fixtures/invalid/release-manifest/cli-site-id-too-short.json +++ b/packages/core-contracts/fixtures/invalid/release-manifest/cli-site-id-too-short.json @@ -163,7 +163,7 @@ }, "requiredScopes": [ "account-settings.read", - "workers-scripts.edit", + "workers-scripts.admin", "d1.write", "workers-r2.write" ], diff --git a/packages/core-contracts/fixtures/invalid/release-manifest/missing-feature-flag.json b/packages/core-contracts/fixtures/invalid/release-manifest/missing-feature-flag.json index 8fb427e6..f16a19f8 100644 --- a/packages/core-contracts/fixtures/invalid/release-manifest/missing-feature-flag.json +++ b/packages/core-contracts/fixtures/invalid/release-manifest/missing-feature-flag.json @@ -163,7 +163,7 @@ }, "requiredScopes": [ "account-settings.read", - "workers-scripts.edit", + "workers-scripts.admin", "d1.write", "workers-r2.write" ], diff --git a/packages/core-contracts/fixtures/invalid/release-manifest/schema-version-2.json b/packages/core-contracts/fixtures/invalid/release-manifest/schema-version-2.json index d0b22d2c..62548480 100644 --- a/packages/core-contracts/fixtures/invalid/release-manifest/schema-version-2.json +++ b/packages/core-contracts/fixtures/invalid/release-manifest/schema-version-2.json @@ -163,7 +163,7 @@ }, "requiredScopes": [ "account-settings.read", - "workers-scripts.edit", + "workers-scripts.admin", "d1.write", "workers-r2.write" ], diff --git a/packages/core-contracts/fixtures/invalid/release-manifest/signature-name-unknown.json b/packages/core-contracts/fixtures/invalid/release-manifest/signature-name-unknown.json index a50ae7dd..0494f97e 100644 --- a/packages/core-contracts/fixtures/invalid/release-manifest/signature-name-unknown.json +++ b/packages/core-contracts/fixtures/invalid/release-manifest/signature-name-unknown.json @@ -163,7 +163,7 @@ }, "requiredScopes": [ "account-settings.read", - "workers-scripts.edit", + "workers-scripts.admin", "d1.write", "workers-r2.write" ], diff --git a/packages/core-contracts/fixtures/invalid/release-manifest/unknown-capability.json b/packages/core-contracts/fixtures/invalid/release-manifest/unknown-capability.json index 1b9f184e..74ab0caa 100644 --- a/packages/core-contracts/fixtures/invalid/release-manifest/unknown-capability.json +++ b/packages/core-contracts/fixtures/invalid/release-manifest/unknown-capability.json @@ -163,7 +163,7 @@ }, "requiredScopes": [ "account-settings.read", - "workers-scripts.edit", + "workers-scripts.admin", "d1.write", "workers-r2.write" ], diff --git a/packages/core-contracts/fixtures/invalid/release-manifest/unknown-property.json b/packages/core-contracts/fixtures/invalid/release-manifest/unknown-property.json index 72c4ea41..79542b97 100644 --- a/packages/core-contracts/fixtures/invalid/release-manifest/unknown-property.json +++ b/packages/core-contracts/fixtures/invalid/release-manifest/unknown-property.json @@ -163,7 +163,7 @@ }, "requiredScopes": [ "account-settings.read", - "workers-scripts.edit", + "workers-scripts.admin", "d1.write", "workers-r2.write" ], diff --git a/packages/core-contracts/fixtures/valid/release-manifest/cloudhal-0.6.3.json b/packages/core-contracts/fixtures/valid/release-manifest/cloudhal-0.6.3.json index ab338a99..903b19f1 100644 --- a/packages/core-contracts/fixtures/valid/release-manifest/cloudhal-0.6.3.json +++ b/packages/core-contracts/fixtures/valid/release-manifest/cloudhal-0.6.3.json @@ -161,7 +161,7 @@ }, "requiredScopes": [ "account-settings.read", - "workers-scripts.edit", + "workers-scripts.admin", "d1.write", "workers-r2.write" ], diff --git a/packages/core-contracts/fixtures/valid/release-manifest/starter-bundle.json b/packages/core-contracts/fixtures/valid/release-manifest/starter-bundle.json index 0e1613a6..69135f3d 100644 --- a/packages/core-contracts/fixtures/valid/release-manifest/starter-bundle.json +++ b/packages/core-contracts/fixtures/valid/release-manifest/starter-bundle.json @@ -161,7 +161,7 @@ }, "requiredScopes": [ "account-settings.read", - "workers-scripts.edit", + "workers-scripts.admin", "d1.write", "workers-r2.write" ], diff --git a/packages/core-contracts/fixtures/valid/release-manifest/statement-signed.json b/packages/core-contracts/fixtures/valid/release-manifest/statement-signed.json index 74f8ef67..2515922d 100644 --- a/packages/core-contracts/fixtures/valid/release-manifest/statement-signed.json +++ b/packages/core-contracts/fixtures/valid/release-manifest/statement-signed.json @@ -161,7 +161,7 @@ }, "requiredScopes": [ "account-settings.read", - "workers-scripts.edit", + "workers-scripts.admin", "d1.write", "workers-r2.write" ], diff --git a/scripts/release-bundle/standard.ts b/scripts/release-bundle/standard.ts index ba1a41b8..a3bb1c71 100644 --- a/scripts/release-bundle/standard.ts +++ b/scripts/release-bundle/standard.ts @@ -91,7 +91,15 @@ export const STANDARD_MANIFEST_FIELDS: Readonly> = { cron: ADMIN_CRON, }, }, - requiredScopes: ["account-settings.read", "workers-scripts.edit", "d1.write", "workers-r2.write"], + // Workers Admin, not Workers Editor (`workers-scripts.edit`): installing creates the site and + // admin Workers, and an Editor cannot create Workers (#225). Consumers treat `.admin` as covering + // the `.edit` that manifests up to v0.9.0 name (RFC-0046 §3). + requiredScopes: [ + "account-settings.read", + "workers-scripts.admin", + "d1.write", + "workers-r2.write", + ], optionalScopes: ["account-analytics.read", "workers-routes.write", "dns.write"], requiredCapabilities: ["account", "workers", "d1", "r2"], optionalCapabilities: ["analytics", "domains"],