Skip to content

P2 Zapier: public app contract#682

Closed
jaeyunha wants to merge 3 commits into
stagingfrom
issue-589-p2-zapier-public-zapier-app-with-t
Closed

P2 Zapier: public app contract#682
jaeyunha wants to merge 3 commits into
stagingfrom
issue-589-p2-zapier-public-zapier-app-with-t

Conversation

@jaeyunha

Copy link
Copy Markdown
Member

Summary

  • add apps/zapier public Zapier Platform app contract for OAuth, polling/rest-hook triggers, actions, and structured error handling
  • allow /api/zapier routes through proxy so bearer/API key auth reaches route handlers
  • document the app source and current link-attachment behavior

Validation

  • make check
  • make test (passed on rerun; first run exposed a transient tests/initiatives-view.test.tsx isolation/order failure that passed alone)
  • TZ=Asia/Seoul npx vitest run tests/zapier-app.test.ts tests/zapier.test.ts tests/zapier-routes.test.ts tests/middleware.test.ts
  • node .scratch/zapier-manifest-smoke.mjs against local dev server on port 3015

Notes

  • make test-e2e is environment-blocked because the Playwright Chromium binary is missing from the shared cache.
  • Native binary attachment upload still needs a public metadata/presigned-upload contract; this slice exposes the implemented Zapier link-attachment action.

Closes #589

jaeyunha and others added 3 commits June 9, 2026 10:08
Add the Zapier manifest, auth test, trigger polling, action wrappers, webhook subscription registration, OAuth bearer validation, and setup docs for #589.

Constraint: Full reliable webhook delivery worker is not present in this branch, so this slice stores signed Zapier webhook subscriptions and documents the delivery handoff.

Tested: make check; npx vitest run tests/zapier.test.ts tests/zapier-routes.test.ts; npx vitest run tests/account-security-route.test.ts tests/workspace-invite-route.test.ts tests/team-cycles-cycleId-route.test.ts tests/project-templates-route.test.ts; npx vitest run tests/auth.test.ts; npx vitest run tests/security-settings-view.test.tsx; npx vitest run tests/agent-logic.test.tsx

Not-tested: make test times out under full-suite concurrency in unrelated suites that pass individually; make test-e2e is blocked by local Postgres password authentication failure for user postgres.

Confidence: medium

Co-authored-by: OmX <omx@oh-my-codex.dev>
@jaeyunha

Copy link
Copy Markdown
Member Author

Controller intake: blocked before QA/merge.

Current blocker:

  • PR is CONFLICTING against staging.
  • The diff mixes a current apps/zapier/docs addition with legacy top-level src/... and tests/... paths. Current staging is split monorepo (apps/web/..., apps/api/..., packages/proto/...); top-level Next/API business routes are stale.
  • The P2 Zapier: public Zapier app with triggers and actions #589 spec-prep contract requires OAuth/public API integration through existing API/auth boundaries plus OpenAPI/SDK sync. Any protected API route changes must land in the current Go API / generated SDK boundary or current apps/web UI paths, not legacy src/app/api routes.
  • No GitHub checks are reported.

Required fix:

  1. Rebuild/rebase from current origin/staging.
  2. Keep the Zapier app under apps/zapier and docs under docs/, but port any UI to apps/web/... and API/auth/webhook work to apps/api + packages/proto/SDK/migrations as needed.
  3. Preserve the P2 Zapier: public Zapier app with triggers and actions #589 contract: OAuth2 public flow, PAT fallback if private/testing, webhook-backed triggers, status-change filtering, SDK-backed actions, structured RFC 7807-style failures, and attachment via presigned upload/metadata contract.
  4. Rerun focused Zapier package/API tests plus make check/make test, or report the exact unrelated baseline blocker.

@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: e978b4fc01

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/lib/zapier.ts
Comment on lines +1110 to +1112
if (url.protocol !== "https:") {
throw new ZapierActionError("targetUrl must use HTTPS.", {
field: "targetUrl",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Reject unsafe Zapier hook URLs

This new subscription path only verifies https: and skips the existing validateWebhookUrl guard used by the normal webhook API, so a direct Zapier API call can persist targets such as https://127.0.0.1/..., private/link-local hosts, or URLs with fragments. When webhook delivery runs server-side, that becomes an SSRF/internal-callback path; please reuse the shared webhook URL validator before inserting the subscription.

Useful? React with 👍 / 👎.

Comment thread src/lib/zapier.ts
Comment on lines +1088 to +1092
if (!zapierSessionHasScope(context.session, "webhooks:write")) {
throw new ZapierActionError("Zapier requires the webhooks:write scope.", {
status: 403,
code: "insufficient_scope",
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Enforce admin role for Zapier webhook changes

Checking only webhooks:write lets any workspace member who can create an API key, or authorize an OAuth app with that scope, create workspace-wide webhook subscriptions; the existing /api/workspaces/current/api webhook create/delete path gates this on canManageWorkspaceApi because these hooks can exfiltrate workspace issue activity. Please carry the member role through OAuth sessions and require owner/admin before subscribe/unsubscribe.

Useful? React with 👍 / 👎.

Comment thread apps/zapier/index.ts
redirect_uri: bundle.inputData?.redirect_uri,
},
}),
autoRefresh: false,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Refresh expiring OAuth tokens for Zapier

The OAuth token endpoint returns one-hour access tokens with a refresh token, but this Zapier app sets autoRefresh: false and defines no refreshAccessToken, so OAuth-connected Zaps will keep sending the expired lin_oauth_at_... token after about an hour and every trigger/action will start receiving 401s. Zapier's OAuth docs describe using refreshAccessToken/autoRefresh for expiring tokens: https://docs.zapier.com/integrations/build-cli/overview.

Useful? React with 👍 / 👎.

Comment thread src/lib/zapier.ts
trigger === "new_issue" ? issue.createdAt : issue.updatedAt;
const rows = await db
.select({
id: issue.id,

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 Make updated-issue poll IDs update-specific

For the updated_issue polling path this returns the stable issue id as Zapier's default primary key, so once a Zap's initial poll has seen an issue, later updates to that same issue are deduped away and never trigger. Zapier's deduplication docs recommend making updated-item ids include the update timestamp, or defining primary output fields: https://docs.zapier.com/integrations/build/deduplication.

Useful? React with 👍 / 👎.

@jaeyunha

Copy link
Copy Markdown
Member Author

Closing in favor of regeneration on the current architecture.

This PR was authored against the pre-monorepo-split layout (src/...) and targets file paths that no longer exist — business logic lives in the old Next.js src/app/api/* routes instead of the Go API. A code review found this is not a line-level conflict but a structural mismatch: every changed file would need relocation to apps/web/, and the business endpoints must be reimplemented in apps/api (Go) and registered in packages/proto/openapi.yaml with a regenerated SDK.

Review also flagged blocking security/correctness issues (varies per PR: SSRF, OAuth CSRF nonce never verified, full-table workspace scans, issue-number races, javascript: URI injection, unenforced review gates).

Re-generate from the spec in #589 on current staging. Issue #589 remains open.

@jaeyunha jaeyunha closed this Jun 16, 2026
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.

1 participant