feat(plugin-types): add declared access escalation#1937
Conversation
🦋 Changeset detectedLatest commit: 3762224 The changes in this PR will be included in the next version bump. This PR includes changesets to release 19 packages
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 |
Scope checkThis PR changes 728 lines across 4 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. |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
emdash-demo-do | 3762224 | Jul 11 2026, 06:30 AM |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
emdash-playground | 3762224 | Jul 11 2026, 06:30 AM |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
emdash-demo-cache | 3762224 | Jul 11 2026, 06:30 AM |
There was a problem hiding this comment.
This PR adds well-scoped comparison primitives for DeclaredAccess inside the shared @emdash-cms/plugin-types package — the right place, since both plugin-cli (writer) and emdash core (reader) will need to agree on canonical form, diff semantics, and digest inputs.
I read the new declared-access.ts, the index.ts re-exports, the test file, and the changeset. I traced the wildcard-coverage logic against the decision table, the write-implies-read implication closure, the __proto__/constructor/prototype handling, the circular-reference detection, and the domain-separated digest preimage. Everything checks out:
- Canonicalization is deterministic (sorted keys, deduplicated/sorted hosts, normalized
-0) and rejects non-JSON values without mutating input. - Write-implies-read is applied only where intended (
content,media) and is idempotent. - Host escalation is conservative: adding
allowedHostsis a de-escalation, removing it or broadening coverage is an escalation; bare domains are not covered by*.example.com, narrower wildcards are. __proto__,constructor,prototypekeys are preserved as ordinary own properties viaObject.defineProperty, avoiding prototype pollution.- The digest preimage is a stable, valid JSON string with a domain/version envelope.
- Tests cover the decision table, key ordering, frozen/immutable output, malformed inputs, prototype-sensitive keys, and digest stability.
- The changeset is present and follows AGENTS.md conventions (present-tense, user-facing description). The barrel file separates value and type exports.
I did not run the test suite or linters (no shell), but I see no logic bugs or convention violations from reading the code. The feature links to the claimed approved Discussion #1590; I cannot verify the approval status without network access, but the checklist item and link are present.
What does this PR do?
Adds canonical declared-access comparison primitives for delegated release policy checks. The new API closes write-implies-read access, normalizes host sets, produces deterministic structured escalation diffs, and generates a domain-separated digest preimage.
Unknown constraints are compared conservatively, wildcard host containment follows RFC #1870, and malformed or prototype-sensitive non-JSON input is safely represented or rejected.
Related to #1908 and Discussion #1590.
Type of change
Checklist
pnpm typecheckpassespnpm lintpassespnpm testpasses (or targeted tests for my change)pnpm formathas been runAI-generated code disclosure
Screenshots / test output
git diff --checkpassTry 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/delegated-release-service-08-access-escalation. Updated automatically when the playground redeploys.