Skip to content

WIP: #570 GitHub PR/commit automation slice#707

Open
jaeyunha wants to merge 3 commits into
stagingfrom
issue-558-parity-implement-github-pr-commit
Open

WIP: #570 GitHub PR/commit automation slice#707
jaeyunha wants to merge 3 commits into
stagingfrom
issue-558-parity-implement-github-pr-commit

Conversation

@jaeyunha

@jaeyunha jaeyunha commented Jun 16, 2026

Copy link
Copy Markdown
Member

Refs #570 under parent #558. Does not close #558.

This PR is currently blocked before merge until the GitHub App install/repository mapping/signed webhook substrate from #569 is landed or this branch is explicitly narrowed to replace #569's substrate contract.

Scoped changes currently present:

  • Adds GitHub installation/repository mapping tables plus PR/commit link and workflow automation tables.
  • Adds GitHub setup/status/workflow/disconnect API routes and signed webhook ingestion for pull_request and push events.
  • Parses TEAM-123 identifiers from branches, PR titles/bodies, and commit messages; links PRs/commits idempotently; records issue history; applies configured merged-PR workflow automation.
  • Adds integration settings UI for configuring a GitHub App installation/repo and issue detail rendering for GitHub PR/commit activity plus branch-name copy support.
  • Updates OpenAPI and generated SDK types.

Validation evidence:

  • Controller focused Go passed: cd apps/api && go test ./internal/integrations ./internal/http.
  • Controller OpenAPI/migration/API-boundary guards passed: node scripts/check-migrations.mjs, node scripts/check-go-openapi-generated.mjs, node scripts/check-openapi-coverage.mjs, node scripts/check-web-api-empty.mjs.
  • Worker-reported focused checks: pnpm exec vitest run tests/integrations-view.test.tsx, SDK test/build, pnpm lint, make openapi-coverage, make migrations, make openapi-strict.

Current blockers:

Required before merge:

@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: 65edf4b4c5

ℹ️ 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".

accountLogin: gitHubAccountLogin,
repositories: [
{
id: gitHubRepositoryFullName.trim(),

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 Use the GitHub repository ID for mappings

When a user connects GitHub through this form, the saved repository_id is the owner/repo full name, but webhook ingestion checks the mapping against payload.Repository.ID from GitHub, which is the numeric repository id (gitHubRepositoryIsMapped(..., gitHubAnyID(payload.Repository.ID))). As a result, PR/push webhooks for repositories configured by the UI are treated as unmapped and return processedIssueCount: 0, so the new automation never links issues unless the repo was configured out-of-band with the numeric id.

Useful? React with 👍 / 👎.

StateID string
}

var gitHubIdentifierPattern = regexp.MustCompile(`(?i)\b[A-Z][A-Z0-9]{1,9}-[0-9]+\b`)

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 Allow one-character team keys in GitHub identifiers

Team keys can be a single character (validateKey only rejects empty keys, keys over 10 chars, or invalid characters), but this pattern requires at least two characters before the dash. In workspaces with identifiers like A-1, a PR title, branch, or commit message containing that issue id produces no matches, so GitHub webhooks won't link commits/PRs or run merged-PR workflow automation for those teams.

Useful? React with 👍 / 👎.

@jaeyunha

Copy link
Copy Markdown
Member Author

Controller disposition for current head 65edf4b: blocked before merge.

Current blockers:

Evidence checked:

  • PR targets staging, is mergeable, and uses current split-monorepo paths.
  • git diff --check origin/staging...HEAD passed.
  • node scripts/check-migrations.mjs, check-go-openapi-generated.mjs, check-openapi-coverage.mjs, and check-web-api-empty.mjs passed.

Required before merge: either land/repair #569 first and rebase this slice to consume its substrate, or explicitly retarget/narrow this PR as the #569 substrate replacement with the #569 contract and acceptance checks. Then rerun full Go/web/OpenAPI/SDK/Playwright gates in a dependency-complete environment.

@jaeyunha jaeyunha changed the title feat: add GitHub PR and commit automation slice WIP: #570 GitHub PR/commit automation slice Jun 16, 2026
@jaeyunha

Copy link
Copy Markdown
Member Author

Controller update: PR #707 has been re-scoped in title/body to child #570 and marked WIP/blocked. It still must not merge as-is.

Current path:

Merge gate remains: rerun full Go/web/OpenAPI/SDK/Playwright validation in a dependency-complete environment after the re-scope/rebase.

@jaeyunha

Copy link
Copy Markdown
Member Author

Controller update after #696/#569 merged to staging.

#569 substrate is now available on origin/staging at merge commit d1f8fe8, so the old dependency blocker is cleared. #707 is still blocked before merge for the rebase/narrowing step:

Required path now: rebase #707 onto current origin/staging, keep only the #570 PR/commit linking + workflow automation delta that consumes the #569 substrate, resolve migration/OpenAPI/SDK conflicts, then rerun full Go/web/OpenAPI/SDK/Playwright gates.

jaeyunha and others added 2 commits June 17, 2026 13:53
Union-merged all conflicts from origin/staging:
- apps/api/internal/http/router.go: union both webhook routes (global + legacy per-integrationID)
- apps/api/internal/integrations/github.go: union both architectures (legacy manual setup + new GitHub App connect/register flow + PR/commit processing logic); renamed legacy webhook handler to GitHubWebhookLegacy
- apps/api/internal/integrations/handler.go: union all GitHub routes; take staging's setupRequirement checks
- apps/api/internal/integrations/handler_test.go: take staging's figma/intercom/github env checks; remove duplicate TestGitHubSignatureVerification and duplicate githubTestSignature helper
- packages/proto/openapi.yaml: union all GitHub endpoints and schemas from both sides
- packages/sdk/src/generated.ts: regenerated from resolved openapi.yaml
- apps/web/src/app/(app)/settings/integrations/page.tsx: take staging (newer GitHub App flow supersedes WIP manual setup UI)
- apps/web/tests/integrations-view.test.tsx: take staging

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…r actor identity

- Add canManage role gate to GitHubStatus handler (was ungated, any workspace member could call it)
- Remove WebhookSecret from gitHubStatusResponse struct and GitHubStatus response literal (secret only surfaces at setup time via GitHubSetup)
- Remove gitHubActorIDByEmail call from handleGitHubCommitEvents (commit author email is untrusted git metadata; raw author name/email still stored as informational metadata)
- Delete now-unused gitHubActorIDByEmail function

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@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: 4e328d6c13

ℹ️ 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 on lines +940 to +943
actorName := firstNonEmpty(commit.Author.Name, commit.Author.Username, commit.Committer.Name, commit.Committer.Username, payload.Sender.Login)
actorEmail := firstNonEmpty(commit.Author.Email, commit.Committer.Email)
actorLogin := firstNonEmpty(commit.Author.Username, commit.Committer.Username, payload.Sender.Login)
out = append(out, gitHubCommitEvent{RepositoryID: repositoryID, RepositoryFullName: payload.Repository.FullName, RepositoryURL: payload.Repository.HTMLURL, SHA: sha, Message: commit.Message, URL: firstNonEmpty(commit.HTMLURL, commit.URL), Identifiers: identifiers, ActorName: actorName, ActorEmail: actorEmail, ActorLogin: actorLogin, DeliveryID: deliveryID})

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 Avoid trusting commit author emails as actors

For push webhooks, commit.Author.Name and commit.Author.Email are git metadata controlled by whoever authored the commit, not a verified GitHub identity. Since these values are later inserted into issue_history as actor_name/actor_email, a commit mentioning an issue can spoof the issue timeline by using an arbitrary author like CEO <ceo@company.com>. Use the GitHub sender/login as the actor and keep commit author details only as source metadata.

Useful? React with 👍 / 👎.

Comment on lines +4965 to +4967
GitHubStatusResponse:
type: object
required: [connected, integrationId, installationId, displayName, webhookUrl, webhookSecret, repositories, workflows]

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 Remove webhookSecret from the status contract

The new GET /integrations/github schema marks webhookSecret as a required response field, but the GitHubStatus handler serializes gitHubStatusResponse, which has no WebhookSecret member and never returns it. Generated SDK consumers will therefore treat a field as guaranteed even though the API omits it on both connected and disconnected responses; either return the secret intentionally or remove it from the status response schema.

Useful? React with 👍 / 👎.

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