feat(marketplace): expose github.clientId from discovery + harden publish auth#271
feat(marketplace): expose github.clientId from discovery + harden publish auth#271masonjames wants to merge 3 commits intoemdash-cms:mainfrom
Conversation
🦋 Changeset detectedLatest commit: 072c147 The changes in this PR will be included in the next version bump. 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 |
|
I have read the CLA Document and I hereby sign the CLA 1 out of 2 committers have signed the CLA. |
There was a problem hiding this comment.
Pull request overview
This PR updates EmDash’s marketplace auth/discovery and publish flow so the CLI can discover the GitHub OAuth app at runtime, while also tightening failure behavior when marketplace auth is misconfigured. It also introduces a new email:status plugin hook type/schema entry and adds targeted unit/e2e coverage.
Changes:
- Expose
github.clientIdfromGET /api/v1/auth/discoveryand harden marketplace GitHub auth routes to return clear 503s when OAuth config is missing. - Fix the CLI GitHub Device Flow requests to use
application/x-www-form-urlencoded, and add unit tests for encoding + redirect middleware DB fallback. - Add
email:statusto core hook typing, hook pipeline capability gating, and manifest validation; update docs + deploy workflow accordingly.
Reviewed changes
Copilot reviewed 20 out of 20 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| packages/marketplace/wrangler.jsonc | Documents required Worker secrets for production deploys. |
| packages/marketplace/tests/publish-e2e.test.ts | Adds e2e assertions for discovery payload and 503 behavior when OAuth config is missing. |
| packages/marketplace/src/routes/public.ts | Returns discovery payload including github.clientId. |
| packages/marketplace/src/routes/author.ts | Adds shared GitHub OAuth config validation + clearer 503 errors for misconfigurations. |
| packages/marketplace/README.md | Documents production deploy secret requirements and a post-deploy discovery check. |
| packages/core/tests/unit/redirects/middleware.test.ts | Adds unit coverage for redirect middleware DB fallback behavior. |
| packages/core/tests/unit/plugins/manifest-schema.test.ts | Ensures manifests accept the new email:status hook. |
| packages/core/tests/unit/plugins/define-plugin.test.ts | Ensures definePlugin resolves/retains email:status hooks. |
| packages/core/tests/unit/cli/publish.test.ts | Adds unit test for form-urlencoded encoding used by GitHub device flow. |
| packages/core/src/plugins/types.ts | Introduces EmailStatusEvent + EmailStatusHandler and registers the hook in types. |
| packages/core/src/plugins/manifest-schema.ts | Adds email:status to manifest hook allowlist. |
| packages/core/src/plugins/hooks.ts | Registers email:status in the pipeline and gates it behind email:provide. |
| packages/core/src/cli/commands/publish.ts | Uses discovery github.clientId, fails fast if missing, and switches GitHub device flow to form-urlencoded. |
| packages/core/src/astro/middleware/redirect.ts | Falls back to getDb() when locals.emdash isn’t available for anonymous requests. |
| docs/src/content/docs/reference/configuration.mdx | Updates plugin configuration guidance and “paired trusted/marketplace” guidance. |
| docs/src/content/docs/plugins/sandbox.mdx | Adds guidance on paired trusted + marketplace packages. |
| docs/src/content/docs/plugins/publishing.mdx | Documents paired package strategy for trusted vs sandbox-safe distributions. |
| docs/src/content/docs/plugins/installing.mdx | Adds tip about paired trusted + marketplace packages. |
| .github/workflows/deploy-marketplace.yml | Validates required secrets, pushes Worker secrets, deploys Worker, and smoke-checks discovery before seeding plugins. |
| .changeset/smooth-bugs-wave.md | Adds a patch changeset describing the hook + marketplace auth hardening. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| publicRoutes.get("/auth/discovery", (c) => { | ||
| const clientId = typeof c.env.GITHUB_CLIENT_ID === "string" ? c.env.GITHUB_CLIENT_ID : ""; | ||
| return c.json({ | ||
| github: { | ||
| clientId: c.env.GITHUB_CLIENT_ID, | ||
| clientId, | ||
| deviceAuthorizationEndpoint: "https://github.com/login/device/code", |
There was a problem hiding this comment.
/auth/discovery returns clientId without trimming. If the Worker secret contains trailing whitespace/newlines (common when copy/pasting), discovery will expose a non-empty but invalid clientId, and the CLI will proceed until GitHub rejects the request. Consider .trim() here (matching getGitHubOAuthConfig() in author routes) so whitespace-only values become an empty string.
…lish auth - Add `email:status` to the core plugin hook type/manifest schema so trusted SMTP plugins can subscribe to delivery status events. - Expose `github.clientId` from `/api/v1/auth/discovery` so `emdash plugin login` / device flow can discover the marketplace GitHub OAuth app at runtime. - Harden the CLI publish path and marketplace author/publish routes so configuration failures (missing OAuth client, missing seed token) surface clearly instead of silently returning an empty discovery payload. - Update deploy-marketplace.yml to validate required secrets up front, push Worker secrets via wrangler before deploy, and smoke-check discovery after deploy. - Refresh plugin docs (installing, publishing, sandbox, configuration) for the marketplace-publish auth flow. - Add unit tests for the CLI publish command and redirect middleware.
daa6df5 to
d5ccbd5
Compare
What does this PR do?
Hardens the marketplace GitHub auth discovery/publish flow so partial or missing OAuth configuration fails clearly instead of advertising a broken device-login path.
It also adds the
email:statushook to core typing/manifest validation, updates the deploy smoke check to requiregithub.enabled === true, and adds tests covering the discovery and manifest changes.Type of change
Checklist
pnpm typecheckpassespnpm --silent lint:json | jq '.diagnostics | length'returns 0pnpm testpasses (or targeted tests for my change)pnpm formathas been runAI-generated code disclosure
Screenshots / test output
pnpm --silent lint:quickpnpm --filter @emdash-cms/marketplace exec vitest run tests/publish-e2e.test.ts tests/manifest-schema.test.tspnpm --filter emdash exec vitest run tests/unit/cli/publish.test.ts tests/unit/plugins/define-plugin.test.ts tests/unit/plugins/manifest-schema.test.ts tests/unit/plugins/hooks.test.tspnpm typecheckpnpm --silent lint:json | jq '.diagnostics | length'