Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
207cad9
fix(release-service): harden compatibility and recovery
ascorbic Aug 27, 2026
4da8fa1
feat(release-service): complete delegated publishing
ascorbic Aug 27, 2026
14099b6
ci: verify delegated release applications
ascorbic Aug 27, 2026
52bd5ed
docs: describe the consolidated review stack
ascorbic Aug 27, 2026
a206da4
docs: align retired stacks with review layers
ascorbic Aug 27, 2026
86f345f
docs: format the review stack table
ascorbic Aug 27, 2026
5ecef29
ci: build workspace before delegated release tests
ascorbic Aug 27, 2026
9e659f6
ci: update query-count snapshots
emdashbot[bot] Aug 27, 2026
1faf643
fix(registry): make verifier bundle safe to rebundle
ascorbic Aug 27, 2026
c817cdc
docs(release-service): align implemented contracts
ascorbic Aug 28, 2026
826b0ce
fix(ci): install Playwright system dependencies
ascorbic Aug 28, 2026
8f1ea1c
fix(release-service): minimize approver readiness data
ascorbic Aug 28, 2026
2182678
docs(registry-client): describe approver readiness
ascorbic Aug 28, 2026
228cb05
docs(release-service): document canonical operator routes
ascorbic Aug 28, 2026
7266c5e
docs(release-service): describe exact delegated scope
ascorbic Aug 28, 2026
201dde7
fix(release-service): validate dry-run source records
ascorbic Aug 28, 2026
8bfd7ae
docs(release-service): require blob-only publication
ascorbic Aug 28, 2026
4acf05f
build(release-action): refresh checked-in bundle
ascorbic Aug 28, 2026
e174335
docs(release-service): correct stack and G0 status
ascorbic Aug 28, 2026
54d3b36
chore(release-service): format integration layer
ascorbic Aug 28, 2026
b11b7b4
ci: fold delegated release checks into shared jobs
ascorbic Aug 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions .changeset/delegated-release-client.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@
"@emdash-cms/plugin-cli": minor
---

Adds typed clients for the experimental delegated release service. `ReleaseServiceClient` submits, polls, and cancels GitHub OpenID Connect release intents, and manages publisher workload policies and retained delegation through a publisher session. `ReleaseServiceOperatorClient` exposes the Cloudflare Access status, sharded publisher and approver inventory, pause, suspension, revocation, cancellation, reconciliation, resumable encryption-key rotation, Workflow-backed encrypted R2 archive, and fail-safe publisher restore and abort operations.
Adds typed clients for the experimental delegated release service. `ReleaseServiceClient` submits, polls, and cancels GitHub OpenID Connect release intents; manages publisher workload policies and retained delegation; and lets publishers check whether profile-listed approvers have an active passkey and inspect publisher-scoped audit events through a publisher session. `ReleaseServiceOperatorClient` exposes the Cloudflare Access status and sanitized audit, sharded publisher and approver inventory, pause, suspension, revocation, cancellation, reconciliation, resumable encryption-key rotation, Workflow-backed fleet verification, audited key retirement, encrypted R2 archive, and fail-safe publisher restore and abort operations.

Both clients validate response envelopes and return stable `ReleaseServiceError` codes with retry metadata. Mutation helpers require idempotency keys, and workload polling requests a fresh token from the configured provider for each call.

The plugin CLI adds `emdash-plugin release submit`, `release status`, and `release cancel` for GitHub Actions jobs. The commands request audience-bound OIDC tokens from the runner, support JSON output, and use the GitHub run identity as the default idempotency key.
The plugin CLI adds `emdash-plugin release dry-run`, `release submit`, `release status`, and `release cancel` for GitHub Actions jobs. Dry-run verifies workload admission without creating an intent, consuming rate budget, or reserving a version. The commands request audience-bound OIDC tokens from the runner, support JSON output, and use the GitHub run identity as the default idempotency key where a mutation occurs.

Delegated submissions use a URL-source release record: each package or listing-image artifact supplies a checksum-bound HTTPS URL and no blob. The service stages and uploads those bytes through the publisher's delegation, then creates a blob-only release record. Submit and dry-run reject mixed or blob-backed source inputs before requesting GitHub OIDC.

Interactive `release delegate`, `revoke`, `workload`, `enrol`, `approve`, and `reject` commands print validated browser handoffs. Publisher application sessions, OAuth credentials, and passkey assertions remain at the release-service origin instead of entering the terminal process.
4 changes: 4 additions & 0 deletions .changeset/swift-verifiers-match.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,7 @@ Adds optional artifact digest candidates to `GitHubProvenanceVerifier`, allowing
Existing callers can continue passing only `artifactDigest`. Successful results return the candidate that matched the signed subject.

Fixes `@emdash-cms/registry-verification` when it is rebundled into an Astro Cloudflare application, preventing requests from failing during Worker startup.

Adds `@emdash-cms/registry-verification/records` for Worker callers that supply an explicit `ProvenanceVerifier`. The runtime-neutral entry does not load the Node-oriented default Sigstore verifier, while the package root keeps the existing default-verifier behavior.

Fixes `@emdash-cms/registry-verification` when it is rebundled into an Astro Cloudflare application, preventing requests from failing during Worker startup.
11 changes: 10 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@ jobs:
- run: pnpm run --filter emdash-demo --filter @emdash-cms/demo-cloudflare typecheck
- run: pnpm typecheck:templates
- run: node scripts/typecheck-public-source.mjs
- run: pnpm run --filter @emdash-cms/release-service --filter @emdash-cms/release-verifier --filter @emdash-cms/release-action typecheck
- run: pnpm run --filter @emdash-cms/release-service --filter @emdash-cms/release-verifier --filter @emdash-cms/release-action build
- run: git diff --exit-code -- apps/release-action/dist/index.js
- run: pnpm --dir apps/release-service exec wrangler types --check
- run: pnpm --dir apps/release-verifier exec wrangler types --check
- run: pnpm --dir apps/release-service exec wrangler deploy --dry-run
- run: pnpm --dir apps/release-verifier exec wrangler deploy --dry-run

lint:
name: Lint
Expand Down Expand Up @@ -129,6 +136,7 @@ jobs:
# Render tests use the Astro Vite plugin (vitest.repro.config.ts);
# they can't run under the plain-node config in test:unit.
- run: pnpm --filter emdash exec vitest run --config vitest.repro.config.ts
- run: pnpm run --filter @emdash-cms/release-service --filter @emdash-cms/release-verifier --filter @emdash-cms/release-action test

test-smoke:
name: Smoke Tests
Expand Down Expand Up @@ -191,14 +199,15 @@ jobs:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm run --filter @emdash-cms/admin... build
- run: pnpm run --filter @emdash-cms/admin... --filter @emdash-cms/release-service... build
- uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
id: playwright-cache
with:
path: ~/.cache/ms-playwright
key: playwright-${{ hashFiles('pnpm-lock.yaml') }}
- run: pnpm exec playwright install --with-deps chromium
if: steps.playwright-cache.outputs.cache-hit != 'true'
- run: pnpm --filter @emdash-cms/release-service test:browser
- run: pnpm run --filter @emdash-cms/admin test

test-e2e-rollup:
Expand Down
22 changes: 11 additions & 11 deletions apps/release-action/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# EmDash delegated release Action

This experimental Action submits a package release record to an EmDash delegated release service. It requests a GitHub OpenID Connect (OIDC) token for each service call, so the workflow does not store a release-service secret.
This experimental Action submits a URL-source package release record to an EmDash delegated release service. It requests a GitHub OpenID Connect (OIDC) token for each service call, so the workflow does not store a release-service secret.

## Workflow setup

Expand Down Expand Up @@ -36,19 +36,19 @@ jobs:

Replace the example service URL, publisher DID, build command, and exact commit with values for your publisher. Pin the Action to an exact commit while the delegated release protocol remains experimental.

The release record must conform to `com.emdashcms.experimental.package.release`. The service validates its package, version, artifact, declared access, and provenance before publication.
The source release record must conform to `com.emdashcms.experimental.package.release`. Every package or listing-image artifact must have a checksum-bound HTTPS `url` and must not contain `blob`. The service validates and uploads those bytes to the publisher's PDS, then creates a release record whose artifact descriptors contain blobs and no source URLs. Provenance remains checksum-bound to its HTTPS source.

## Inputs

| Input | Required | Default | Purpose |
| ----------------------- | -------- | -------------- | ---------------------------------------------------------------------------------------------- |
| `service-url` | Yes | — | HTTPS origin of the delegated release service. |
| `publisher-did` | Yes | — | DID that owns the package profile and release records. |
| `release-file` | Yes | — | JSON file containing the package release record. The path must stay inside `GITHUB_WORKSPACE`. |
| `idempotency-key` | No | Current run ID | Stable key used to replay the same submission. |
| `poll-interval-seconds` | No | `5` | Delay between intent status requests. |
| `timeout-minutes` | No | `30` | Maximum polling time. |
| `wait-for-approval` | No | `false` | Continue polling when the intent reaches `awaiting_approval`. |
| Input | Required | Default | Purpose |
| ----------------------- | -------- | -------------- | --------------------------------------------------------------------------------------------------------- |
| `service-url` | Yes | — | HTTPS origin of the delegated release service. |
| `publisher-did` | Yes | — | DID that owns the package profile and release records. |
| `release-file` | Yes | — | JSON file containing the URL-source package release record. The path must stay inside `GITHUB_WORKSPACE`. |
| `idempotency-key` | No | Current run ID | Stable key used to replay the same submission. |
| `poll-interval-seconds` | No | `5` | Delay between intent status requests. |
| `timeout-minutes` | No | `30` | Maximum polling time. |
| `wait-for-approval` | No | `false` | Continue polling when the intent reaches `awaiting_approval`. |

The default idempotency key is stable across attempts of one GitHub run. Set `idempotency-key` when separate runs or jobs must replay the same submission identity.

Expand Down
2 changes: 1 addition & 1 deletion apps/release-action/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ inputs:
description: Publisher DID that owns the package.
required: true
release-file:
description: Path to the package release record JSON file.
description: Path to a URL-source package release JSON file. The service publishes PDS blobs.
required: true
idempotency-key:
description: Stable key for replaying this submission. Defaults to the GitHub run.
Expand Down
Loading
Loading