Skip to content

feat(registry): graduate verification and its type/lexicon dependencies to main#2067

Merged
ascorbic merged 1 commit into
mainfrom
feat/graduate-registry-verification
Jul 16, 2026
Merged

feat(registry): graduate verification and its type/lexicon dependencies to main#2067
ascorbic merged 1 commit into
mainfrom
feat/graduate-registry-verification

Conversation

@ascorbic

@ascorbic ascorbic commented Jul 16, 2026

Copy link
Copy Markdown
Collaborator

What does this PR do?

Graduates packages/registry-verification — and the two additive package slices it hard-depends on — from feat/delegated-release-service to main, per the ratified W7.1 inversion rule in the labelling-service plan (".opencode/plans/plugin-registry-labelling-service/implementation-plan.md": if W7 starts first, graduate the package to main in a standalone PR; three-package scope + the pnpm patch ratified 2026-07-16). The labelling branch's W7 (verified artifact acquisition) builds on this once merged.

Everything is lifted byte-identical from origin/feat/delegated-release-servicegit diff against that branch over the lifted paths is empty; zero deviations were forced by main's toolchain. Source commits: registry-verification 9f429c0e, plugin-types 5473b880, registry-lexicons 75498780.

What lands

  • @emdash-cms/registry-verification (new, publishable): runtime-neutral release-artifact verification — multihash checksums, guarded artifact fetch (size/redirect limits), canonical tarball/bundle validation, Sigstore build provenance. Node + workerd.
  • @emdash-cms/plugin-types additions: manifest-schema.ts (manifest validation, reconcileManifestAccess) and declared-access.ts (canonicalization, diff, escalation detection) + index re-exports and tests.
  • @emdash-cms/registry-lexicons additions: the packageProfileExtension lexicon + generated types, and a provenance reference on the release extension.
  • ⚠️ Repo-wide pnpm patch (please review deliberately): patches/@sigstore__core@4.0.1.patch + a patchedDependencies entry in pnpm-workspace.yaml — main's first dependency patch. It fixes a provenance-verification weakness: when a signature omits the hash algorithm, upstream @sigstore/core passes undefined into crypto.verify (accepting unsupported RSA keys); the patch derives the algorithm from the key type (P-256/384/521 → sha256/384/512, ed25519) and rejects unsupported keys. registry-verification's build config documents relying on it and three of its tests enforce the rejection — the package cannot land correct or green without it.

Honest flag for the delegated-branch owners

The verbatim registry-lexicons/src/index.ts lift also carries getDelegatedReleasePermission() / DELEGATED_RELEASE_PERMISSION — inert delegated-publishing scaffolding (pure function + frozen const, unwired), kept to preserve byte-identity so the delegated branch reconciles conflict-free on its next main sync. Deliberately not advertised in the changesets.

Type of change

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)
  • I have added a changeset (if this PR changes a published package)
  • New features link to an approved Discussion

AI-generated code disclosure

  • This PR includes AI-generated code — model/tool: Claude Opus 4.8 (the graduation/promotion; the lifted code was authored and reviewed on the delegated release-service branch, model per that branch's PRs)

Screenshots / test output

plugin-types 68/68 · registry-lexicons 19/19 · registry-verification 93 node + 36 workerd
repo typecheck exit 0 · lint 0 diagnostics

…es to main

Graduates the plugin-registry release-artifact verification package to main
as a standalone, coordinated promotion, per the ratified W7.1 decision and
today's three-package amendment (sequencing inverted: the labelling branch's
W7 needs these on main before the delegated-release-service branch merges).

Lifted byte-identical from origin/feat/delegated-release-service:
- packages/registry-verification @ 9f429c0
- packages/plugin-types           @ 5473b88
  (adds src/manifest-schema.ts, src/declared-access.ts and their re-exports --
  required by registry-verification's bundle/records modules)
- packages/registry-lexicons      @ 7549878
  (adds the packageProfileExtension lexicon and a release-extension provenance
  field -- required by registry-verification's records module)

Also lifts patches/@sigstore__core@4.0.1.patch and its pnpm-workspace.yaml
patchedDependencies entry (a repo-wide patch). The patch makes @sigstore/core's
verify() derive the hash algorithm from the public key type when the algorithm
is omitted and reject unsupported keys, instead of passing undefined through to
crypto.verify. registry-verification depends on it: without it, provenance
verification accepts unsupported RSA keys and its test suite fails.

Claude-Session: https://claude.ai/code/session_014rikrGMh25h1rJczUQyTMM
Copilot AI review requested due to automatic review settings July 16, 2026 06:58
@changeset-bot

changeset-bot Bot commented Jul 16, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 17d30af

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

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

@github-actions

Copy link
Copy Markdown
Contributor

Scope check

This PR changes 5,294 lines across 55 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.

@github-actions github-actions Bot added the review/needs-review No maintainer or bot review yet label Jul 16, 2026
@cloudflare-workers-and-pages

Copy link
Copy Markdown

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 17d30af Jul 16 2026, 06:59 AM

@cloudflare-workers-and-pages

Copy link
Copy Markdown

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-do 17d30af Jul 16 2026, 07:00 AM

@cloudflare-workers-and-pages

Copy link
Copy Markdown

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 17d30af Jul 16 2026, 07:00 AM

@pkg-pr-new

pkg-pr-new Bot commented Jul 16, 2026

Copy link
Copy Markdown

Open in StackBlitz

@emdash-cms/admin

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

@emdash-cms/auth

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

@emdash-cms/auth-atproto

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

@emdash-cms/blocks

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

@emdash-cms/cloudflare

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

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

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

emdash

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

create-emdash

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

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

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

@emdash-cms/plugin-cli

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

@emdash-cms/plugin-types

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

@emdash-cms/registry-client

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

@emdash-cms/registry-lexicons

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

@emdash-cms/registry-verification

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

@emdash-cms/sandbox-workerd

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

@emdash-cms/x402

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

@emdash-cms/plugin-ai-moderation

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

@emdash-cms/plugin-atproto

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

@emdash-cms/plugin-audit-log

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

@emdash-cms/plugin-color

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

@emdash-cms/plugin-embeds

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

@emdash-cms/plugin-field-kit

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

@emdash-cms/plugin-forms

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

@emdash-cms/plugin-webhook-notifier

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

commit: 17d30af

@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 a clean, additive graduation PR: it moves an already-reviewed slice of the plugin-registry work from feat/delegated-release-service to main without touching core runtime code. The contents are well-scoped (plugin-types, registry-lexicons, and the new registry-verification package) and come with comprehensive tests for both Node and workerd.

What I checked:

  • The three changed packages and their new/changed source files.
  • The @sigstore/core pnpm patch: it is correctly declared in pnpm-workspace.yaml, reflected in the lockfile, and directly exercised by the provenance tests.
  • Changesets for all three published packages.
  • AGENTS.md conventions: .js internal imports, import type usage, changeset style, and package export shapes.

Headline: no logic bugs, security regressions, or broken contracts. I did find two non-blocking maintainability issues: a circular import in plugin-types and a test that imports an internal path from @sigstore/verify. Both are suggestions, not blockers.


import { z } from "zod";

import { capabilitiesToDeclaredAccess, declaredAccessToCapabilities } from "./index.js";

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] manifest-schema.ts imports runtime helpers (capabilitiesToDeclaredAccess, declaredAccessToCapabilities) and PluginManifest from ./index.js, while src/index.ts re-exports everything from ./manifest-schema.js (line 477). This creates a circular module dependency. It loads safely today only because the imported values are initialized before the re-export is evaluated, but it is fragile: reordering or adding an eager side-effect could turn it into a TDZ/runtime initialization failure later.

Move the two access-mapping helpers and the DeclaredAccess/PluginManifest types they need into a small shared module (e.g. src/access.ts) and have both index.ts and manifest-schema.ts import from it:

import {
  capabilitiesToDeclaredAccess,
  declaredAccessToCapabilities,
  type PluginManifest,
} from "./access.js";

That breaks the cycle cleanly without changing any public export.

import type { TransparencyLogEntry } from "@sigstore/bundle";
import { crypto as sigstoreCrypto } from "@sigstore/core";
import type { TLogAuthority } from "@sigstore/verify";
import { verifyCheckpoint } from "@sigstore/verify/dist/tlog/checkpoint.js";

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] The test contract imports verifyCheckpoint from @sigstore/verify/dist/tlog/checkpoint.js, which is a non-public internal path. This will break on any patch/minor release of @sigstore/verify that moves or renames that file, even if the API surface is otherwise compatible.

Prefer using a public @sigstore/verify export, or inline a minimal Ed25519 checkpoint verifier for this contract test so the test is pinned to the dependency's stable API rather than its internal layout.

@github-actions github-actions Bot added review/awaiting-author Reviewed; waiting on the author to respond and removed review/needs-review No maintainer or bot review yet labels Jul 16, 2026
@ascorbic

Copy link
Copy Markdown
Collaborator Author

Both suggestions are valid and deliberately not addressed in this PR: every lifted file is byte-identical to feat/delegated-release-service so that branch reconciles conflict-free on its next main sync — fixing here would fork the code from its source. Both issues (the manifest-schema.tsindex.ts circular import in plugin-types, and the provenance contract test importing @sigstore/verify/dist/tlog/checkpoint.js internals) are flagged to the delegated-branch owners as upstream improvements to make on their branch, from which they'll flow back to main.

~ 🤖 Claude Opus 4.8

@ascorbic ascorbic merged commit 07c9f21 into main Jul 16, 2026
56 checks passed
@ascorbic ascorbic deleted the feat/graduate-registry-verification branch July 16, 2026 07:14
@emdashbot emdashbot Bot mentioned this pull request Jul 16, 2026

Copilot AI 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.

Pull request overview

Graduates the new @emdash-cms/registry-verification package (and its additive dependencies in plugin-types and registry-lexicons) onto main, introducing runtime-neutral primitives for verifying plugin release artifacts (checksums, bounded fetching, bundle validation, and Sigstore provenance) alongside required workspace-level dependency patching for @sigstore/core.

Changes:

  • Adds @emdash-cms/registry-verification with Node + workerd test coverage and build packaging checks.
  • Extends @emdash-cms/plugin-types with manifest validation (pluginManifestSchema, reconcileManifestAccess) and declared-access canonicalization/diff helpers.
  • Extends @emdash-cms/registry-lexicons with packageProfileExtension and an optional provenance reference on releaseExtension, plus a repo-wide pnpm patch for @sigstore/core@4.0.1.

Reviewed changes

Copilot reviewed 50 out of 55 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
pnpm-workspace.yaml Registers a workspace-level patch for @sigstore/core@4.0.1.
pnpm-lock.yaml Locks patched dependency hash and adds new package importer entries.
patches/@sigstore__core@4.0.1.patch Patches sigstore verify algorithm selection to fail-closed when omitted.
packages/registry-verification/wrangler.jsonc Adds Wrangler config for workerd test runs.
packages/registry-verification/vitest.workerd.config.ts Adds Vitest config for workerd pool tests.
packages/registry-verification/vitest.config.ts Adds Vitest config for Node environment tests.
packages/registry-verification/tsdown.config.ts Configures neutral + Node builds; bundles Sigstore for published workerd path.
packages/registry-verification/tsconfig.json Adds TS config for the new package (includes tests).
packages/registry-verification/tests/workerd/worker.ts Test worker entrypoint for workerd pool.
packages/registry-verification/tests/workerd/smoke.test.ts Workerd smoke tests for checksums/fetch/bundle validation.
packages/registry-verification/tests/workerd/provenance.test.ts Runs shared provenance contract in workerd.
packages/registry-verification/tests/workerd/packed-output.test.ts Ensures packed dist entrypoints execute correctly in workerd.
packages/registry-verification/tests/records.test.ts Unit tests for record + provenance policy verification.
packages/registry-verification/tests/provenance.test.ts Runs shared provenance contract in Node.
packages/registry-verification/tests/provenance-contract.ts Comprehensive provenance verification contract + regression vectors.
packages/registry-verification/tests/fetch.test.ts Tests for safe, bounded, redirect-aware fetching.
packages/registry-verification/tests/checksum.test.ts Tests for multihash encoding/decoding and digest comparisons.
packages/registry-verification/tests/check-packed-output.test.ts Validates packaging script fails closed without package manager entrypoint.
packages/registry-verification/tests/bundle.test.ts Tests for canonical plugin bundle validation and limits.
packages/registry-verification/src/trust-roots/sigstore-public-good-v1.json Vendored Sigstore “public-good” trusted root subset for verification.
packages/registry-verification/src/repository.ts Canonicalizes repository URLs for signed identity binding.
packages/registry-verification/src/records.ts Validates signed profile/release records and applies provenance policy.
packages/registry-verification/src/provenance.ts Implements GitHub workflow Sigstore provenance verification.
packages/registry-verification/src/index.ts Public exports for checksum/fetch/bundle/provenance/record verification APIs.
packages/registry-verification/src/fetch.ts Implements bounded fetch with redirect, DNS, and size/time limits.
packages/registry-verification/src/fetch-entry.ts Worker-safe fetch entrypoint exports.
packages/registry-verification/src/errors.ts Defines stable verification error codes and result shape.
packages/registry-verification/src/checksum.ts Implements multibase multihash checksum compute/verify helpers.
packages/registry-verification/src/bundle.ts Validates gzip+tar plugin bundle structure and manifest constraints.
packages/registry-verification/src/bundle-limits.ts Centralizes bundle size/count limits for validation.
packages/registry-verification/scripts/check-packed-output.mjs Verifies packed output is worker-safe and contains the patched algorithm mapping.
packages/registry-verification/package.json Adds publishable package metadata, scripts, and dependencies.
packages/registry-verification/fixtures/records/release.json Fixture for release record verification tests.
packages/registry-verification/fixtures/records/profile.json Fixture for profile record verification tests.
packages/registry-verification/fixtures/provenance/sigstore-core-4.0.1-slsa.bundle.json Fixture Sigstore bundle used for provenance contract tests.
packages/registry-verification/fixtures/provenance/README.md Documents fixture provenance and trust-root update process.
packages/registry-lexicons/tests/types.test.ts Expands lexicon smoke tests for new extension types and delegated permission helper.
packages/registry-lexicons/src/index.ts Exports new NSIDs/types and adds getDelegatedReleasePermission().
packages/registry-lexicons/src/generated/types/com/emdashcms/experimental/package/releaseExtension.ts Adds optional provenance embedded object schema/type.
packages/registry-lexicons/src/generated/types/com/emdashcms/experimental/package/profileExtension.ts Adds generated types for the new profile extension lexicon.
packages/registry-lexicons/src/generated/types/com/emdashcms/experimental/package/profile.ts Adds extensions field to profile schema as opaque container.
packages/registry-lexicons/src/generated/index.ts Re-exports generated profileExtension types.
packages/registry-lexicons/README.md Documents delegated release grant scoping helper.
packages/registry-lexicons/lexicons/com/emdashcms/experimental/package/releaseExtension.json Adds provenance ref to the release extension lexicon.
packages/registry-lexicons/lexicons/com/emdashcms/experimental/package/profileExtension.json Adds new profileExtension lexicon definition.
packages/registry-lexicons/lexicons/com/emdashcms/experimental/package/profile.json Documents extensions field semantics in the profile lexicon.
packages/plugin-types/tests/declared-access.test.ts Adds tests for declared-access canonicalization, diffing, and escalation detection.
packages/plugin-types/tests/capabilities.test.ts Extends capability tests to cover manifest schema validation.
packages/plugin-types/src/manifest-schema.ts Adds Zod manifest schema + reconciliation helpers.
packages/plugin-types/src/index.ts Re-exports manifest schema and declared-access helpers/types.
packages/plugin-types/src/declared-access.ts Adds declared-access canonicalization/diff logic and digest preimage builder.
packages/plugin-types/package.json Adds zod dependency for runtime manifest validation.
.changeset/plugin-types-manifest-schema.md Changeset for @emdash-cms/plugin-types minor feature additions.
.changeset/lexicons-profile-extension.md Changeset for @emdash-cms/registry-lexicons minor additions.
.changeset/graduate-registry-verification.md Changeset for first release of @emdash-cms/registry-verification.
Files not reviewed (1)
  • pnpm-lock.yaml: Generated file

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

Comment on lines +13 to +32
export interface CanonicalDeclaredAccess {
readonly content?: Readonly<{
read?: CanonicalAccessConstraints;
write?: CanonicalAccessConstraints;
}>;
readonly email?: Readonly<{
events?: CanonicalAccessConstraints;
send?: CanonicalAccessConstraints;
transport?: CanonicalAccessConstraints;
}>;
readonly media?: Readonly<{
read?: CanonicalAccessConstraints;
write?: CanonicalAccessConstraints;
}>;
readonly network?: Readonly<{
request?: CanonicalAccessConstraints & { readonly allowedHosts?: readonly string[] };
}>;
readonly page?: Readonly<{ fragments?: CanonicalAccessConstraints }>;
readonly users?: Readonly<{ read?: CanonicalAccessConstraints }>;
}
Comment on lines +11 to +15
import { z } from "zod";

import { capabilitiesToDeclaredAccess, declaredAccessToCapabilities } from "./index.js";
import type { PluginManifest } from "./index.js";

Comment on lines +1 to +11
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "./dist",
"rootDir": "./src",
"lib": ["es2024", "dom", "esnext.typedarrays"],
"types": ["@cloudflare/vitest-pool-workers/types"]
},
"include": ["src/**/*", "tests/**/*"],
"exclude": ["node_modules", "dist", "tests"]
}
Comment on lines +44 to +51
const limits = {
headerTimeoutMs: options.headerTimeoutMs ?? DEFAULT_FETCH_LIMITS.headerTimeoutMs,
totalTimeoutMs: options.totalTimeoutMs ?? DEFAULT_FETCH_LIMITS.totalTimeoutMs,
maxBytes: options.maxBytes ?? DEFAULT_FETCH_LIMITS.maxBytes,
maxRedirects: options.maxRedirects ?? DEFAULT_FETCH_LIMITS.maxRedirects,
};
if (!areValidLimits(limits))
return verificationError("INVALID_URL", "Fetch limits must be positive integers.");
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cla: signed review/awaiting-author Reviewed; waiting on the author to respond size/XL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants