Skip to content

fix(plugin-sdk): carry contentAccess from definePlugin config into the manifest - #333

Open
mostafasadeghidev wants to merge 1 commit into
CoreBunch:mainfrom
mostafasadeghidev:fix/plugin-sdk-content-access
Open

fix(plugin-sdk): carry contentAccess from definePlugin config into the manifest#333
mostafasadeghidev wants to merge 1 commit into
CoreBunch:mainfrom
mostafasadeghidev:fix/plugin-sdk-content-access

Conversation

@mostafasadeghidev

Copy link
Copy Markdown

What changed

definePlugin() silently dropped contentAccess: DefinePluginConfig had no such field and the builder never copied it into the manifest it returns — even though PluginManifest supports contentAccess?: ContentAccessEntry[] and the CLI's own content-editor scaffold emits a config that passes it. Any plugin built with the CLI lost its per-table allowlist, so every cms.content.* call failed closed at runtime despite the operator granting the permissions.

  • definePlugin (definePlugin.ts): contentAccess?: ContentAccessEntry[] added to DefinePluginConfig, snapshotted into the manifest (entries + modes arrays copied), key omitted when undefined — same pattern as the other optional fields. Also fixed the stale docblock that showed editor:/server:/frontend: config fields that don't exist and referenced a dead scripts/build-plugin.ts path.
  • Lint coherence (lint.ts): new warning when a declared cms.content.* permission has no contentAccess entry carrying the matching mode — a permission with no consumer; the host fails closed per table+mode. The missing-allowlist case (permissions with zero entries) stays a single hard error via parsePluginManifest, which lint already runs — before this fix that error fired misleadingly even for authors who did declare entries. Also: source-scan finding paths are now reported POSIX-style on Windows.
  • Scaffold (init.ts): removed the dead entrypoints: { server: 'server/index.js' } line from the content-editor template — same class of bug (config field DefinePluginConfig doesn't accept: an IDE type error for authors, silently ignored at runtime) and redundant, since instatic-plugin build auto-wires entrypoints.server from server/index.ts.

Why

Operator grants the cms.content.* permissions on install, plugin still gets 403s on every content call — the manifest never carried the allowlist the author wrote. Fails closed, no error at build time, nothing pointing at the cause.

Impact

CLI-built content plugins work as authored. instatic-plugin lint now catches the "permission declared but unusable" case pre-upload. Scaffolded configs typecheck clean in the author's IDE.

Tests

  • definePlugin copies contentAccess as an independent deep copy (input mutation doesn't leak) and omits the key entirely when unset (the Value.Convert round-trip footgun).
  • Lint: warning fires for an uncovered mode, stays quiet when coherent, and the missing-allowlist case reports exactly one manifest error (no duplicate warnings).
  • End-to-end regression: scaffold the CLI's own content-editor template, assert the manifest carries contentAccess, and assert it lints with zero findings — this exact path failed before the fix.

Verification

bun run build   # tsc -b && vite build — clean
bun test        # plugin-sdk suites 50/50 green
bun run lint    # clean

Full bun test shows 299 pre-existing failures (symlink swap semantics, site-document save, etc.) — verified byte-identical with and without this diff on the same machine (Windows-environmental, e.g. symlink privileges), not related to this change.

…manifest

DefinePluginConfig had no contentAccess field and definePlugin() never
copied it into the manifest it returns, even though PluginManifest
supports it and the CLI's own content-editor scaffold passes it. Any
plugin built with the CLI silently lost its per-table allowlist, so
every cms.content.* call failed closed at runtime despite the operator
granting the permissions.

- Add contentAccess to DefinePluginConfig and snapshot it into the
  manifest (key omitted when undefined, matching the other optional
  fields).
- Lint: warn when a declared cms.content.* permission has no
  contentAccess entry carrying the matching mode (permission with no
  consumer — fails closed per table+mode). The missing-allowlist case
  stays a single hard error from parsePluginManifest.
- Lint: report source-scan finding paths POSIX-style on Windows.
- Scaffold: drop the dead `entrypoints:` line from the content-editor
  template — not a DefinePluginConfig field (an IDE type error for
  authors, silently ignored at runtime) and redundant, since the build
  auto-wires entrypoints.server from server/index.ts.
- Fix the stale definePlugin docblock that showed editor/server/frontend
  config fields which don't exist and a dead scripts/build-plugin.ts path.
- Tests: definePlugin contentAccess deep-copy + omission; lint warning
  fires/stays quiet correctly; end-to-end regression scaffolding the
  content-editor template and asserting it lints clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@mostafasadeghidev
mostafasadeghidev marked this pull request as ready for review August 3, 2026 03:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant