Skip to content

feat: add package trusted publishing via GitHub OIDC#1461

Merged
onutc merged 12 commits into
mainfrom
onur/clawhub-oidc-plugin-publish
Apr 2, 2026
Merged

feat: add package trusted publishing via GitHub OIDC#1461
onutc merged 12 commits into
mainfrom
onur/clawhub-oidc-plugin-publish

Conversation

@onutc

@onutc onutc commented Apr 1, 2026

Copy link
Copy Markdown

Summary

  • add package-level trusted publisher config and short-lived publish tokens for GitHub Actions OIDC
  • keep first publish manual, keep official separate from publish auth, and record publish actor plus audit data
  • add CLI and HTTP API support for trusted publisher setup, token minting, and CI publish auth

Testing

  • bun run test -- convex/lib/githubActionsOidc.test.ts convex/httpApiV1.handlers.test.ts
  • bun run test:src -- src/cli/commands/packages.test.ts
  • bunx tsc -p packages/schema/tsconfig.json --noEmit
  • bunx tsc -p packages/clawdhub/tsconfig.json --noEmit
  • bun run lint
  • bun run build

Notes

@vercel

vercel Bot commented Apr 1, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
clawhub Ready Ready Preview, Comment Apr 2, 2026 0:32am

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e9bcda667e

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread packages/clawdhub/src/cli/commands/packages.ts
@greptile-apps

greptile-apps Bot commented Apr 1, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR introduces full end-to-end trusted publishing via GitHub Actions OIDC: a new packageTrustedPublishers table and packagePublishTokens table, a self-contained JWT verification library (githubActionsOidc.ts) that fetches and caches GitHub's JWKS, a /api/v1/publish/token/mint endpoint that exchanges a short-lived OIDC JWT for a 15-minute scoped publish token, updated publish auth that transparently accepts either a normal API token or a publish token, and CLI subcommands (trusted-publisher get/set/delete) wired into the clawdhub package.

The implementation is well-structured: OIDC verification is thorough (issuer, audience, time window, signature, repository/owner ID pinning, workflow filename extraction, reusable-workflow rejection), schema changes are additive, access control gating (requireTrustedPublisherEditor) is correct, and the audit trail is comprehensive. Test coverage is good — unit tests for JWT verification edge cases and integration tests for all new HTTP handlers.

Key points to address before shipping:

  • workflow_dispatch-only restriction (convex/lib/githubActionsOidc.ts:155) — tag-push and release-event triggered workflows, which are the most common CD patterns, are silently rejected. Either document this limitation prominently or evaluate allowing additional event types (still gated by the named GitHub environment).
  • Publish token not revoked after successful use (convex/packages.ts:1894) — the packagePublishTokens record's revokedAt is never set after a publish succeeds, leaving the token live for its full 15-minute TTL. Revoking on success enforces the single-use contract that short-lived tokens imply.

Confidence Score: 4/5

  • Safe to merge after addressing the two P2 findings; core OIDC verification logic is sound and the feature is well-tested.
  • Both open findings are P2: one is a design-level documentation/scope gap (workflow_dispatch restriction), and the other is a security best-practice gap (token not revoked after use) with limited practical blast radius given version-binding. Neither causes a current production breakage. Score is 4 rather than 5 because the token lifecycle issue is a security posture concern that is straightforward to fix before merging.
  • convex/lib/githubActionsOidc.ts (event name restriction) and convex/packages.ts / convex/packagePublishTokens.ts (token revocation after publish)
Prompt To Fix All With AI
This is a comment left during a code review.
Path: convex/lib/githubActionsOidc.ts
Line: 155-157

Comment:
**`workflow_dispatch`-only restriction blocks common CD patterns**

The check `eventName !== "workflow_dispatch"` means trusted publishing is unavailable for the most common release trigger patterns: tag pushes (`on: push: tags: ['v*']`), GitHub release creation (`on: release: types: [created]`), and scheduled releases (`on: schedule`). In practice, most CD pipelines publish on these events, not on manual dispatch.

If this is intentional (friction to require a human trigger), it should be documented in the API error message and in user-facing docs so CI authors aren't surprised. If it is meant to be relaxed later, a comment here would help. Consider whether `push` to a protected branch/tag pattern — still verified against a named GitHub environment — is a safe enough signal to allow through.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: convex/packages.ts
Line: 1894-1910

Comment:
**Publish token is never revoked after a successful publish**

After `publishPackageImpl` returns successfully, the `packagePublishTokens` record is not revoked (`revokedAt` remains unset). The token stays valid for the full 15-minute window. An actor who obtained the token (from CI logs, environment variable dumps, etc.) can attempt further publish calls using the same token within that window.

Although the version-binding check (`auth.publishToken.version !== version`) and the version-uniqueness constraint in the DB limit the blast radius (a second publish for the same version will be rejected), the single-use guarantee expected of short-lived publish tokens is not enforced. Revoking the token immediately after a successful return from `publishPackageImpl` (or within `insertReleaseInternal` after the DB insert) would close this gap. If retrying failed publishes within the window is a desired UX, the token could alternatively be revoked only after a version-uniqueness error is returned — but a hard revoke-on-success is simpler and safer.

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "feat: add package trusted publishing via..." | Re-trigger Greptile

Comment thread convex/lib/githubActionsOidc.ts
Comment thread convex/packages.ts

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3cb9991947

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread packages/clawdhub/src/cli/commands/packages.ts Outdated
Comment thread convex/lib/githubActionsOidc.ts

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9580161641

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread packages/clawdhub/src/cli/commands/packages.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 053bc1eea1

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread .github/workflows/package-publish.yml Outdated
@onutc

onutc commented Apr 1, 2026

Copy link
Copy Markdown
Author

Follow-up on the bot summary comments:

  • trusted publishing remains workflow_dispatch-only for now, and the docs/error text now say tag or release automation should keep using the token path;
  • successful trusted publishes now revoke the short-lived publish token;
  • the CLI fallback cases and reusable-workflow checkout bug were also fixed in follow-up commits.

@onutc

onutc commented Apr 1, 2026

Copy link
Copy Markdown
Author

Final maintainer note:

What changed

  • trusted publish fallback now covers unavailable minting, 400/403/404 mint rejections, and OIDC token-request failures;
  • trusted publish tokens are revoked after successful publish;
  • JWKS refreshes on unknown kid before rejecting;
  • the reusable publish workflow now runs the checked-out ClawHub CLI source and keeps the caller checkout pinned to github.sha.

Local validation

  • bun run test convex/lib/githubActionsOidc.test.ts convex/httpApiV1.handlers.test.ts convex/packages.public.test.ts
  • bun run --cwd packages/clawdhub test:src -- src/cli/commands/packages.test.ts
  • bun run test src/__tests__/package-detail-route.test.tsx
  • bun run test convex/lib/apiTokenAuth.test.ts
  • bun run test
  • bun run lint
  • bunx tsc -p packages/clawdhub/tsconfig.json --noEmit
  • bunx tsc --noEmit
  • ruby -e 'require "yaml"; YAML.load_file(".github/workflows/package-publish.yml")'

Notes

  • I could not run Convex codegen locally in this checkout because there is no usable local Convex deployment/config for it.
  • GitHub build is green on the latest head; the remaining Vercel Agent Review status is external/non-code.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0cb0db9786

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread .github/workflows/package-publish.yml
Comment thread .github/workflows/package-publish.yml
@onutc

onutc commented Apr 1, 2026

Copy link
Copy Markdown
Author

Follow-up is done.

Latest fixes:

  • pinned the reusable workflow's clawhub-source checkout to github.workflow_sha
  • kept refs/tags/... as the default publish source ref for tag-triggered callers when inputs.ref is omitted

Validation:

  • bun run test convex/lib/githubActionsOidc.test.ts convex/httpApiV1.handlers.test.ts convex/packages.public.test.ts
  • bun run --cwd packages/clawdhub test:src -- src/cli/commands/packages.test.ts
  • bun run test src/__tests__/package-detail-route.test.tsx
  • bun run test convex/lib/apiTokenAuth.test.ts
  • bun run test
  • bun run lint
  • bunx tsc -p packages/clawdhub/tsconfig.json --noEmit
  • bunx tsc --noEmit
  • ruby -e 'require "yaml"; YAML.load_file(".github/workflows/package-publish.yml")'
  • codex review --base main followed by replying to and resolving the resulting PR threads

Current PR state:

  • all PR checks are green
  • unresolved review threads: 0

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f3d2baa6d0

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread convex/packages.ts Outdated
Comment on lines +215 to +219
const response = await fetchImpl(`https://api.github.com/repos/${normalizedRepository}`, {
headers: {
Accept: "application/vnd.github+json",
"User-Agent": "clawhub/package-trusted-publisher",
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Support private repos when resolving trusted publisher identity

Trusted publisher setup currently calls GitHub’s repo API without authentication, so private repositories return 404 and cannot be configured even though they can run GitHub Actions OIDC. This blocks trusted publishing for private-source/private-package workflows in production; the identity lookup should use authenticated GitHub access or avoid requiring a public repo lookup at setup time.

Useful? React with 👍 / 👎.

Comment thread convex/packages.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: effd5cd72c

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread .github/workflows/package-publish.yml Outdated
Comment thread .github/workflows/package-publish.yml Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dd067f6b2e

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread .github/workflows/package-publish.yml Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants