Skip to content

Registry: env constraints (env:emdash, env:astro) end-to-end with admin compatibility warning#1238

Merged
ascorbic merged 6 commits into
mainfrom
feat/registry-env-requires
May 31, 2026
Merged

Registry: env constraints (env:emdash, env:astro) end-to-end with admin compatibility warning#1238
ascorbic merged 6 commits into
mainfrom
feat/registry-env-requires

Conversation

@ascorbic
Copy link
Copy Markdown
Collaborator

@ascorbic ascorbic commented May 31, 2026

What does this PR do?

Adds release-level environment constraints (requires) to the experimental plugin registry. Plugin authors declare env:emdash / env:astro (and forward-compat package DIDs) with semver-range values in emdash-plugin.jsonc; the CLI validates and publishes them into the release record. The admin compares them against the running EmDash + Astro versions, shows a compatibility warning, and disables Install when unsatisfied. The server enforces the same check on both install and update, refusing an incompatible release with ENV_INCOMPATIBLE (409) so the UI gate can't be bypassed. The host's Astro version — previously not captured anywhere — is now read in the integration's astro:config:setup hook.

Range evaluation uses the semver package, in one shared module used by the publish-time schema, the server gate, and the admin warning. The gate is fail-open (skips constraints it can't evaluate and logs them; malformed ranges are rejected upstream at publish), and satisfiesRange uses includePrerelease so a prerelease/beta host isn't excluded from release-only ranges.

Part of the registry lexicon-to-UI umbrella (#1026).

Closes #1031.

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. No messages.po changes included.
  • I have added a changeset
  • New features link to an approved Discussion: Marketplace Discussion #296

AI-generated code disclosure

  • This PR includes AI-generated code — model/tool: Claude Opus 4.8

Try this PR

Open a fresh playground →

A full working EmDash site, deployed from this branch. Each visit gets its own session-scoped sandbox: no login needed and no shared state. Try the admin, edit content, hit the public site.

Tracks feat/registry-env-requires. Updated automatically when the playground redeploys.

ascorbic added 3 commits May 31, 2026 11:57
Plugins published to the experimental registry can declare release-level
environment constraints. A manifest's `requires` block (e.g.
`{ "env:emdash": ">=1.0.0", "env:astro": ">=4.16" }`) is validated at
publish time and written into the release record.

- registry-client: new dependency-free `./env` module shared by the CLI,
  server, and admin — `parseRequires` (guards the lexicon-`unknown`
  value), `isValidVersionRange`, `satisfiesRange`, and
  `checkEnvCompatibility` over a focused semver-range grammar
  (comparators, caret, tilde, partial versions, wildcard, AND sets).
- plugin-cli: `RequiresSchema` on the manifest, threaded release-level
  into `publishRelease` (never via the profile input); JSON Schema
  regenerated.
- core: capture the host Astro version in `astro:config:setup` and
  surface it (with EmDash VERSION) on the admin manifest. New
  `assertEnvCompatible` gate refuses incompatible install AND update
  with `ENV_INCOMPATIBLE` (409), placed after yank-check, before the
  artifact fetch.
- admin: RegistryPluginDetail reads host versions, renders a localized
  compatibility warning and disables Install when unsatisfied.

Closes #1031.
Share the version->env:* host map between server and admin via a single
hostEnvFromVersions helper, dropping the admin's redundant /manifest fetch
and the duplicated dev-skip rule (admin now derives host env from the
manifest query the shell already runs).

Log skipped env constraints server-side (findSkippedEnvConstraints) so a
host version the gate can't evaluate is observable rather than a silent
bypass. Cover the gate end-to-end through handleRegistryUpdate with a
mocked DiscoveryClient, asserting ENV_INCOMPATIBLE aborts before any
artifact fetch. Document the accepted, more-permissive prerelease range
semantics relative to node-semver.
Replace the hand-rolled range evaluator in registry-client's env module
with the semver package. Adds || union support and node-semver prerelease
gating; satisfiesRange passes includePrerelease so a prerelease host build
is evaluated by precedence rather than excluded from release-only ranges
(a prerelease host is not a definite mismatch). isValidVersionRange (shared
by the publish-time RequiresSchema) and the fail-open gate semantics are
unchanged.
Copilot AI review requested due to automatic review settings May 31, 2026 12:08
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 31, 2026

🦋 Changeset detected

Latest commit: 2d4364c

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

This PR includes changesets to release 16 packages
Name Type
@emdash-cms/registry-client Minor
@emdash-cms/plugin-cli Minor
@emdash-cms/admin Minor
emdash Minor
@emdash-cms/perf-demo-site Patch
@emdash-cms/cache-demo-site Patch
@emdash-cms/cloudflare Minor
@emdash-cms/sandbox-workerd Patch
@emdash-cms/fixture-perf-site Patch
@emdash-cms/auth Minor
@emdash-cms/blocks Minor
@emdash-cms/gutenberg-to-portable-text Minor
@emdash-cms/x402 Minor
create-emdash Minor
@emdash-cms/auth-atproto Patch
@emdash-cms/plugin-embeds 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

@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented May 31, 2026

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
docs 2d4364c May 31 2026, 02:25 PM

@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented May 31, 2026

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
emdash-demo-cache 2d4364c May 31 2026, 02:26 PM

@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented May 31, 2026

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
emdash-playground 2d4364c May 31 2026, 02:26 PM

@github-actions
Copy link
Copy Markdown
Contributor

Scope check

This PR changes 1,090 lines across 30 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
Copy link
Copy Markdown

pkg-pr-new Bot commented May 31, 2026

Open in StackBlitz

@emdash-cms/admin

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

@emdash-cms/auth

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

@emdash-cms/blocks

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

@emdash-cms/cloudflare

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

emdash

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

create-emdash

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

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

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

@emdash-cms/x402

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

@emdash-cms/plugin-ai-moderation

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

@emdash-cms/plugin-atproto

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

@emdash-cms/plugin-audit-log

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

@emdash-cms/plugin-color

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

@emdash-cms/plugin-embeds

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

@emdash-cms/plugin-forms

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

@emdash-cms/plugin-webhook-notifier

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

commit: 2d4364c

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds end-to-end environment constraint enforcement for the experimental plugin registry. Plugins declare release-level requires (e.g. env:emdash, env:astro) with semver ranges in emdash-plugin.jsonc; the CLI validates and publishes them, the admin disables Install with a compatibility warning when the host doesn't satisfy them, and the server refuses install/update with ENV_INCOMPATIBLE (409) as a belt-and-braces gate. Range evaluation is centralized in a shared @emdash-cms/registry-client/env module (uses semver, fail-open on unparseable input, includePrerelease: true). The host's Astro version is newly captured in astro:config:setup.

Changes:

  • New shared env-compat module in registry-client (parse/validate/satisfies + host-env builder + skipped-constraint reporter), wired into the CLI manifest schema and publish pipeline.
  • Server assertEnvCompatible + buildHostEnv helpers used by install and update handlers; new ENV_INCOMPATIBLE error mapped to 409; integration captures host Astro version into manifest/config.
  • Admin RegistryPluginDetail reads manifest, evaluates requires, shows warning notice, and disables Install on mismatch.

Reviewed changes

Copilot reviewed 29 out of 30 changed files in this pull request and generated no comments.

Show a summary per file
File Description
pnpm-workspace.yaml / pnpm-lock.yaml / packages/registry-client/package.json Add semver + @types/semver to catalog and registry-client deps
packages/registry-client/src/env/index.ts New shared env-compat helpers (parse, satisfies, host-env, skipped)
packages/registry-client/src/index.ts, tsdown.config.ts Export the new ./env subpath
packages/registry-client/tests/env.test.ts Unit tests for env helpers
packages/plugin-cli/src/manifest/schema.ts RequiresSchema validating env:*/DID keys + semver-range values
packages/plugin-cli/src/manifest/translate.ts, commands/publish.ts, publish/api.ts Thread requires from manifest → publish → release record
packages/plugin-cli/schemas/emdash-plugin.schema.json Published JSON Schema gets the new requires field
packages/plugin-cli/tests/manifest-schema.test.ts, manifest-translate.test.ts, publish.test.ts Tests for new requires plumbing
packages/core/src/api/errors.ts New ENV_INCOMPATIBLE error code mapped to 409
packages/core/src/api/handlers/registry.ts, handlers/index.ts buildHostEnv, assertEnvCompatible, gating in install + update
packages/core/src/astro/integration/index.ts, integration/runtime.ts Resolve and store host Astro version at astro:config:setup
packages/core/src/astro/types.ts, emdash-runtime.ts Surface astroVersion in manifest
packages/core/src/astro/routes/api/admin/plugins/registry/{install,[id]/update}.ts Pass hostEnv into handlers
packages/core/tests/unit/api/registry-env-{compat,gate-handler}.test.ts Decision-helper + handler-wiring tests
packages/admin/src/lib/api/client.ts, registry.ts astroVersion on AdminManifest, hostEnvFromManifest helper
packages/admin/src/components/RegistryPluginDetail.tsx Compute env mismatches, show warning notice, disable Install
.changeset/registry-env-requires.md Minor bumps for affected packages
Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Copy Markdown
Contributor

@emdashbot emdashbot Bot left a comment

Choose a reason for hiding this comment

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

I reviewed the full diff for this registry environment-constraints feature. The PR introduces requires (release-level env:emdash / env:astro semver constraints) end-to-end: CLI manifest validation, release record publishing, server-side install/update gating, and admin UI compatibility warnings.

What I checked:

  • Approach: Sound. The change is additive, backwards-compatible (skips the gate when hostEnv is absent), and the fail-open semantics for unknown/unparseable versions are well-documented. Using the semver package via a shared @emdash-cms/registry-client/env module keeps behavior consistent across CLI, server, and admin.
  • Security: The gate is defense-in-depth (the admin UI disables Install, and the server rejects with ENV_INCOMPATIBLE). No SQL changes, no new auth bypasses. parseRequires hardens against garbage shapes and never throws.
  • Conventions (AGENTS.md): All new admin strings go through Lingui. No physical-directional Tailwind classes (ml-/mr-/text-left/etc.) were introduced. API errors use the standard ApiResult envelope and mapErrorStatus maps ENV_INCOMPATIBLE to 409. A changeset is present.
  • Tests: Unit tests cover assertEnvCompatible, buildHostEnv, checkEnvCompatibility, parseRequires, satisfiesRange, and the manifest schema. An integration test verifies the update handler aborts before artifact fetch when constraints are unsatisfied.
  • Wiring: The astroVersion is correctly captured at build time in astro:config:setup, serialized through the virtual module, exposed in the runtime manifest, and consumed by both the install/update routes and the admin detail view.

Headline conclusion: The implementation is clean, well-tested, and consistent with EmDash’s patterns. I found no logic bugs, regressions, security issues, or convention violations.

@github-actions github-actions Bot added review/approved Approved; no new commits since overlap and removed review/needs-review No maintainer or bot review yet labels May 31, 2026
@github-actions
Copy link
Copy Markdown
Contributor

Overlapping PRs

This PR modifies files that are also changed by other open PRs:

This may cause merge conflicts or duplicated work. A maintainer will coordinate.

buildHostEnv was a pure pass-through to hostEnvFromVersions (the shared
registry-client/env helper). The install/update routes now call
hostEnvFromVersions directly, and its duplicate dev-skip/astro-omit test
block is removed (covered by registry-client's env tests).
@github-actions github-actions Bot added review/needs-rereview Author pushed changes since the last review and removed review/approved Approved; no new commits since labels May 31, 2026
Resolves overlap with the merged #1239 (artifacts): the manifest keeps
both release-level `requires` (flat) and the `release.artifacts` block;
the publish path writes both; handler barrel exports both registry
helpers; manifest-schema tests keep both describe blocks. JSON schema
regenerated.
@ascorbic ascorbic added the bot:review Trigger an emdashbot code review on this PR label May 31, 2026
Aligns env constraints with release.artifacts (merged in #1239) under a
single release block, matching the RFC. repo stays top-level (documented
legacy for backwards compatibility). Publish reads manifest.release.requires;
the normalised manifest keeps a flat requires field.
Copy link
Copy Markdown
Contributor

@emdashbot emdashbot Bot left a comment

Choose a reason for hiding this comment

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

Re-reviewed this registry environment-constraints feature after prior approval. The PR adds requires (release-level env:emdash / env:astro semver constraints) end-to-end: CLI manifest validation via RequiresSchema, release record publishing, server-side install/update gating via assertEnvCompatible, and admin UI compatibility warnings with disabled Install.

Approach: Still sound. The change is additive, backwards-compatible (the gate skips when hostEnv is absent or a version is unparseable), and the fail-open semantics are well-documented. Using the semver package via a shared @emdash-cms/registry-client/env module keeps behavior consistent across CLI, server, and admin.

What I checked:

  • Wiring: astroVersion is correctly captured at build time in astro:config:setup via resolveAstroVersion(), serialized through the virtual module, exposed in the runtime manifest (_buildManifest), and consumed by both install/update routes and the admin detail view.
  • Security: The gate is defense-in-depth (admin UI disables Install, server rejects with ENV_INCOMPATIBLE mapped to 409). No SQL changes, no new auth bypasses. parseRequires hardens against garbage shapes and never throws.
  • Conventions (AGENTS.md): All new admin strings go through Lingui (t macro / Trans). No physical-directional Tailwind classes (ml-/mr-/text-left/etc.) were introduced. API errors use the standard ApiResult envelope. A changeset is present.
  • Tests: Unit tests cover assertEnvCompatible, hostEnvFromVersions, checkEnvCompatibility, parseRequires, satisfiesRange, and the manifest schema. An integration test verifies the update handler aborts before artifact fetch when constraints are unsatisfied.
  • Edge cases: Empty/dev/non-semver host versions are handled (skipped/fail-open). Prerelease hosts are included via includePrerelease. DID-keyed constraints are accepted for forward-compat but skipped in env evaluation.

Headline conclusion: The implementation is clean, well-tested, and consistent with EmDash's patterns. No issues were found in this re-review.

@github-actions github-actions Bot added review/approved Approved; no new commits since and removed review/needs-rereview Author pushed changes since the last review labels May 31, 2026
@ascorbic ascorbic enabled auto-merge (squash) May 31, 2026 14:28
@ascorbic ascorbic merged commit 60c0b2e into main May 31, 2026
38 checks passed
@ascorbic ascorbic deleted the feat/registry-env-requires branch May 31, 2026 14:33
@emdashbot emdashbot Bot mentioned this pull request May 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/admin area/core bot:review Trigger an emdashbot code review on this PR cla: signed overlap review/approved Approved; no new commits since size/XL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Registry: env constraints (env:emdash, env:astro) end-to-end with admin compatibility warning

2 participants