Skip to content

fix(workerd): accept current plugin capability names - #2576

Draft
logelog wants to merge 2 commits into
emdash-cms:mainfrom
logelog:fix/workerd-capability-aliases
Draft

fix(workerd): accept current plugin capability names#2576
logelog wants to merge 2 commits into
emdash-cms:mainfrom
logelog:fix/workerd-capability-aliases

Conversation

@logelog

@logelog logelog commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

Fixes the Workerd sandbox rejecting manifests that declare current capability names for content, media, users, and network access.

The bridge and generated wrapper now normalize manifest capabilities before checking them. Current names authorize the matching APIs, supported legacy aliases remain accepted, and permission errors report the current names. This also exposes ctx.users when a manifest declares users:read.

Regression tests cover current and legacy names across the bridge, generated wrapper, and a real Workerd process. CI now runs the deterministic Workerd capability tests for this package.

Type of change

  • Bug fix
  • Feature (requires maintainer-approved Discussion)
  • Refactor (no behavior change)
  • Translation
  • Documentation
  • Performance improvement
  • Tests
  • Chore (dependencies, CI, tooling)

Checklist

  • I have read CONTRIBUTING.md
  • pnpm typecheck passes
  • pnpm lint passes
  • pnpm test passes (or targeted tests for my change)
  • pnpm format has been run
  • I have added/updated tests for my changes (if applicable)
  • User-visible strings in the admin UI are wrapped for translation (if applicable). Do not include messages.po changes except in translation PRs — a workflow extracts catalogs on merge to main. Not applicable: this PR does not change the admin UI.
  • I have added and reviewed the user-facing changeset (if this PR changes a published package)
  • New features link to an approved Discussion: not applicable; this is a bug fix.

AI-generated code disclosure

  • This PR includes AI generated code: Claude Opus 5, GPT 5.6 (via private dev orchestra)

Screenshots / test output

  • macOS arm64 on the current branch, with Node.js 22.23.2 and pnpm 11.9.0: targeted lane 47/47 and full Workerd suite 123/123, with zero skipped tests. Workerd build and typecheck, root typecheck, lint, pnpm format:check, and git diff --check passed.
  • Windows 11 x64 on the same behavior patch before the test-only cleanup: targeted lane 51/51 and full Workerd suite 127/127, with zero skipped tests. The integration file passed 18/18 using a real Workerd process; removing the binary as a negative control produced 18 skipped tests, confirming the full run did not silently skip runtime coverage.
  • Windows build, Workerd and root typechecks, lint, Prettier, and git diff --check passed. pnpm format:check reported the same 10 symlink-checkout files on the pristine base and candidate because the Windows checkout had core.symlinks=false; this was not a candidate regression.

@changeset-bot

changeset-bot Bot commented Aug 20, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 636050f

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@emdash-cms/sandbox-workerd Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions

Copy link
Copy Markdown
Contributor

Scope check

This PR changes 640 lines across 12 files. Large PRs are harder to review and more likely to be closed without review.

If this scope is intentional, no action needed. A maintainer will review it. If not, please consider splitting this into smaller PRs.

See CONTRIBUTING.md for contribution guidelines.

@pkg-pr-new

pkg-pr-new Bot commented Aug 20, 2026

Copy link
Copy Markdown

Open in StackBlitz

@emdash-cms/admin

npm i https://pkg.pr.new/@emdash-cms/admin@2576

@emdash-cms/auth

npm i https://pkg.pr.new/@emdash-cms/auth@2576

@emdash-cms/auth-atproto

npm i https://pkg.pr.new/@emdash-cms/auth-atproto@2576

@emdash-cms/blocks

npm i https://pkg.pr.new/@emdash-cms/blocks@2576

@emdash-cms/cloudflare

npm i https://pkg.pr.new/@emdash-cms/cloudflare@2576

@emdash-cms/contentful-to-portable-text

npm i https://pkg.pr.new/@emdash-cms/contentful-to-portable-text@2576

emdash

npm i https://pkg.pr.new/emdash@2576

create-emdash

npm i https://pkg.pr.new/create-emdash@2576

@emdash-cms/gutenberg-to-portable-text

npm i https://pkg.pr.new/@emdash-cms/gutenberg-to-portable-text@2576

@emdash-cms/plugin-cli

npm i https://pkg.pr.new/@emdash-cms/plugin-cli@2576

@emdash-cms/plugin-types

npm i https://pkg.pr.new/@emdash-cms/plugin-types@2576

@emdash-cms/registry-client

npm i https://pkg.pr.new/@emdash-cms/registry-client@2576

@emdash-cms/registry-lexicons

npm i https://pkg.pr.new/@emdash-cms/registry-lexicons@2576

@emdash-cms/registry-verification

npm i https://pkg.pr.new/@emdash-cms/registry-verification@2576

@emdash-cms/sandbox-workerd

npm i https://pkg.pr.new/@emdash-cms/sandbox-workerd@2576

@emdash-cms/x402

npm i https://pkg.pr.new/@emdash-cms/x402@2576

@emdash-cms/plugin-ai-moderation

npm i https://pkg.pr.new/@emdash-cms/plugin-ai-moderation@2576

@emdash-cms/plugin-atproto

npm i https://pkg.pr.new/@emdash-cms/plugin-atproto@2576

@emdash-cms/plugin-audit-log

npm i https://pkg.pr.new/@emdash-cms/plugin-audit-log@2576

@emdash-cms/plugin-color

npm i https://pkg.pr.new/@emdash-cms/plugin-color@2576

@emdash-cms/plugin-embeds

npm i https://pkg.pr.new/@emdash-cms/plugin-embeds@2576

@emdash-cms/plugin-field-kit

npm i https://pkg.pr.new/@emdash-cms/plugin-field-kit@2576

@emdash-cms/plugin-forms

npm i https://pkg.pr.new/@emdash-cms/plugin-forms@2576

@emdash-cms/plugin-webhook-notifier

npm i https://pkg.pr.new/@emdash-cms/plugin-webhook-notifier@2576

commit: 636050f

@logelog
logelog marked this pull request as ready for review August 20, 2026 03:37
@github-actions github-actions Bot added the review/needs-review No maintainer or bot review yet label Aug 20, 2026

@emdashbot emdashbot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the right fix, in the right place, and implemented consistently.

The bug is that the workerd bridge and wrapper were checking for legacy capability names (read:content, network:fetch, etc.) and rejecting the current canonical names that emdash already uses elsewhere. The correct boundary fix is to normalize legacy aliases to current names at the bridge/wrapper entry points, which is exactly what the PR does. This mirrors the existing Cloudflare runner behavior (which already calls normalizeCapabilities), so the two sandbox runners now agree.

What I checked:

  • The full diff and every changed source file.
  • The capability rename map in @emdash-cms/plugin-types (CAPABILITY_RENAMES) to confirm network:fetch:any → network:request:unrestricted, read:users → users:read, etc.
  • The flow through WorkerdSandboxRunner.generatePluginToken → backing service → createBridgeHandler, and through generatePluginWrapper, to confirm both paths now normalize consistently.
  • The new regression tests cover current names, legacy aliases, the unrestricted network supersede, wrapper ctx.users exposure, and end-to-end capability behavior through a spawned workerd isolate.
  • CI change is correctly scoped to deterministic tests that do not need the workerd binary or Miniflare.

Headline conclusion: the implementation is sound and the regression coverage is solid. I have two minor test-quality suggestions — one clearly tautological assertion and one brittle generated-source check — but nothing that blocks the fix.

];

it("declares no capability that publish rejects", () => {
expect(MANIFEST_CAPABILITIES.filter(isDeprecatedCapability)).toEqual([]);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[suggestion] This assertion checks a test-local literal against itself via isDeprecatedCapability. It cannot fail on a real regression; it only fails if someone intentionally edits MANIFEST_CAPABILITIES. The neighboring test already verifies that the fixture authorizes every declared operation, so this assertion is redundant and inflates coverage.

Suggested change
expect(MANIFEST_CAPABILITIES.filter(isDeprecatedCapability)).toEqual([]);
it("authorizes every operation the manifest declares", async () => {

Remove the declares no capability that publish rejects test block entirely (and then drop the unused isDeprecatedCapability import).

});

describe("wrapper API surface", () => {
function usersExposed(capabilities: string[]) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[suggestion] usersExposed tests the generated wrapper by looking for the exact emitted string const users = true ?. That pattern is an implementation detail of the generator; a behavior-preserving refactor (e.g., emitting a named boolean) would break this test without breaking users. The new workerd-integration.test.ts already observes typeof ctx.users through a real isolate, so consider relying on that integration coverage or evaluating the generated module instead of asserting on source shape.

@github-actions github-actions Bot added review/needs-rereview Author pushed changes since the last review and removed review/needs-review No maintainer or bot review yet labels Aug 20, 2026
The Workerd bridge and wrapper were added after the capability rename but still checked the pre-rename names. As a result, manifests using current content, media, users and network capabilities could be denied, and users:read did not expose ctx.users.

Normalize capabilities at the bridge handler and wrapper boundaries, keep supported legacy aliases working, and report current names in permission errors. Add deterministic Workerd capability tests to the existing Tests job because pnpm test:unit does not run this package's tests.
@logelog
logelog force-pushed the fix/workerd-capability-aliases branch from ac36b14 to 636050f Compare August 20, 2026 09:42
@logelog
logelog marked this pull request as draft August 20, 2026 14:30
@github-actions github-actions Bot removed the review/needs-rereview Author pushed changes since the last review label Aug 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant