mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-25 17:45:53 +01:00
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - Agents need source control access for repository work > - A shared token cannot preserve the responsible person's identity or an agent's dedicated identity > - GitHub App tokens also need durable refresh, repository access checks, and webhook delivery > - Paperclip already has managed connections, encrypted grants, run secret leases, and merge-confirmation behavior > - This pull request extends those systems with GitHub identities instead of adding a parallel credential system > - The benefit is durable GitHub access with explicit identity, repository, runtime, and webhook boundaries ## Linked Issues or Issue Description No public GitHub issue describes this connection change. This description follows the feature request template. **Subsystem affected** Connected Apps, connection grants, secret resolution, native Git runtime setup, webhook processing, and the Apps UI. **Problem or motivation** Users need to connect GitHub once and let agents use the correct GitHub identity. A run should use a dedicated agent account when one exists. Otherwise, it should use the responsible person's account. The connection must survive token expiry, repository access changes, and temporary instance downtime. **Proposed solution** Add user-owned and agent-owned GitHub grants to the existing connection model. Resolve one identity for MCP, Git, `gh`, health checks, and webhook bindings. Store provider tokens in the existing encrypted secret system. Refresh expiring token pairs under the existing lease and compare-and-swap path. Register signed Cloud webhook bindings and process normalized pull request and installation events through a durable local inbox. **Alternatives considered** An organization-wide GitHub token would lose person and agent attribution. Environment variables alone would bypass the managed connection and grant model. A new GitHub-only credential store would duplicate the existing secret and access systems. GitHub App installation tokens and private-key custody remain outside this first version. **Roadmap alignment** This change implements the Connected Apps direction. It also extends the shipped MCP Tool Gateway, per-agent secret access, and action-attribution systems. It does not add a repository catalog. The open repository catalog work in [#11234](https://github.com/paperclipai/paperclip/pull/11234) is related and complementary. ## What Changed - Added agent-owned connection grants and a per-agent credential policy with company and subject constraints. - Added a managed GitHub App method while keeping the personal access token method as an advanced fallback. - Added durable access-token and refresh-token handling with proactive rotation and one automatic recovery after a provider `401`. - Added GitHub identity and installation summaries without storing repository-name lists. - Added signed Cloud webhook binding, event lease, acknowledgement, local idempotency, pull request merge processing, and installation access handling. - Added one identity resolver for MCP, native Git, `gh`, checkout, health checks, and webhook bindings. - Added a class-3 run projection for `GH_TOKEN`, `GITHUB_TOKEN`, a `github.com`-only credential helper, SSH-to-HTTPS rewrite, and GitHub noreply commit attribution. - Added personal and dedicated-agent setup choices plus identity, repository, continuity, and webhook status in the Apps UI. - Added schema migrations, tests, and connection documentation. ## Verification - The current head is fully green in GitHub CI, including build, typecheck, all serialized/general server shards, all browser shards, policy, canary dry run, review, and security checks. - Live staging proof completed with a non-expiring GitHub App user token, selected-repository installation, repository add/remove refresh, managed MCP, native `gh`, HTTPS clone/push/delete, GitHub noreply commit attribution, signed merged-PR webhook acceptance, durable Cloud-to-instance delivery, and installation-access event processing. Temporary branches and temporary repository access were removed afterward. - `pnpm check:token-gates` passed. - `pnpm -r typecheck` passed before and after the rebase onto `origin/master`. - `pnpm build` passed. - The focused connector suite passed 285 tests after the rebase. - The full stable suite passed 5,790 tests and failed 22 tests across 8 general server files. The failures reproduced as shared-runner environment issues. They included `/tmp` versus `/private/tmp`, closed database connections, and invalid high ephemeral ports. The focused connection tests pass in isolation. ## Risks - Migrations add agent grant subjects and a durable connection-event inbox. Migration numbering and safety checks pass. - A raw GitHub user token enters the agent process for Git and `gh`. Per-tool Ask-first controls cannot limit those shell operations. The UI warns users about this boundary. - GitHub App user tokens can be non-expiring. Paperclip performs a continuity check every 30 days, but provider revocation still requires a reconnect. - The webhook path accepts only signed and bounded payloads. It stores a minimal normalized record and no raw provider payload. - GitHub repository permissions remain authoritative. Removed access can make a cached repository count temporarily stale, but runtime access fails immediately. > For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and discuss it in `#dev` before opening the PR. Feature PRs that overlap with planned core work may need to be redirected — check the roadmap first. See `CONTRIBUTING.md`. ## Model Used OpenAI Codex, `gpt-5.6-sol`, extended reasoning, tool use, code execution, browser control, and multi-file repository editing. The context window size was not provided. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [ ] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing>
108 lines
5.2 KiB
Markdown
108 lines
5.2 KiB
Markdown
# GitHub managed connection
|
|
|
|
GitHub is a Paperclip Cloud-managed GitHub App connection with an advanced PAT
|
|
compatibility method. Cloud owns the fixed public OAuth callback and signed
|
|
webhook inbox; provider tokens are sealed to the enrolled instance and stored
|
|
only in its existing encrypted secret system.
|
|
|
|
## Identity resolution
|
|
|
|
Every MCP call, `gh` invocation, native Git operation, checkout, health check,
|
|
and webhook binding uses the same order:
|
|
|
|
1. An active dedicated GitHub grant for the current agent.
|
|
2. The active personal GitHub grant owned by the run's `responsibleUserId`.
|
|
3. For automated work without a responsible user, a personal grant only when
|
|
an existing standing delegation names the agent.
|
|
4. Legacy `GH_TOKEN`/`GITHUB_TOKEN` only when no managed GitHub connection is
|
|
configured for the company.
|
|
|
|
An unavailable or ambiguous managed identity fails visibly. It never falls
|
|
through to another person, an organization credential, or a legacy token.
|
|
Agent grants are company-scoped, have exactly one `subjectAgentId`, cannot be
|
|
organization defaults, and are installed only for that agent.
|
|
|
|
The connection installation is the credential owner's consent boundary. A
|
|
personal setup may target every agent or a selected set, and runtime resolution
|
|
considers only an enabled, active connection installed for the current agent.
|
|
Within that boundary, Paperclip treats the run's server-resolved
|
|
`responsibleUserId` as its credential principal, including for automated work;
|
|
agents cannot choose or spoof this field. The owner must still be an active
|
|
non-viewer company member at each use. A standing delegation is needed only
|
|
when a run genuinely has no responsible user.
|
|
|
|
## Credential lifecycle
|
|
|
|
The production, staging, and development GitHub Apps deliberately disable
|
|
user-to-server token expiration. The resulting long-lived access token is
|
|
checked with GitHub's `/user` endpoint every 30 days, together with installation
|
|
and repository summary refresh. Routine continuity requires no browser visit.
|
|
|
|
If GitHub returns an expiring access token and rotating refresh token instead,
|
|
Paperclip stores both encrypted and:
|
|
|
|
- refreshes at least one hour before access expiry;
|
|
- forces a rotation at least every 30 days while the instance is active;
|
|
- serializes refresh through the existing database refresh lease and compare-
|
|
and-swap update;
|
|
- atomically advances both secret values before clearing the lease;
|
|
- retries one forced refresh after a provider `401`.
|
|
|
|
Only an unrecoverable provider invalidation marks a grant
|
|
`needs_reauthorization`. Installation removal or suspension is reported as an
|
|
installation-health failure, not as token expiry.
|
|
|
|
## Repository access
|
|
|
|
OAuth completion verifies `/user`, `/user/installations`, and each
|
|
installation's accessible repository count. Setup remains incomplete until at
|
|
least one installation and repository are available. Paperclip stores user and
|
|
installation summaries, not a repository-name cache. GitHub stays authoritative:
|
|
removed repository access fails immediately even if a displayed count is stale.
|
|
|
|
The Apps UI links to GitHub's installation management page and offers
|
|
**Refresh access**. Selected repositories are recommended. Choosing all
|
|
repositories requires an explicit warning in setup.
|
|
|
|
## Webhooks
|
|
|
|
Paperclip Cloud verifies `X-Hub-Signature-256` against the exact bounded request
|
|
body before parsing, deduplicates by `X-GitHub-Delivery`, and persists a minimal
|
|
normalized event before returning `202`. Raw webhook payloads are discarded.
|
|
When registering an active binding, Paperclip sends the current user token only
|
|
inside the signed, payload-bound broker request so Cloud can verify access to
|
|
that exact installation; Cloud neither logs nor persists that proof token.
|
|
Deliveries fan out independently to every enrolled instance bound to the GitHub
|
|
installation and are sealed to each instance's public key.
|
|
|
|
The instance polls with backoff, stores a company-scoped idempotency receipt,
|
|
and acknowledges only successful applications. A merged pull request updates
|
|
its matching external-object snapshot and immediately runs the existing merge-
|
|
confirmation resolver. It wakes the assignee only when that interaction's
|
|
continuation policy requests it; unrelated Paperclip issues are not closed.
|
|
The periodic GitHub merge sweep remains the reconciliation fallback.
|
|
|
|
Installation lifecycle events refresh or invalidate installation summaries and
|
|
remove obsolete Cloud bindings. Activity records contain event identifiers and
|
|
outcomes but no webhook content. GitHub webhook content is never first-party
|
|
telemetry.
|
|
|
|
## Run projection
|
|
|
|
The resolved token is leased at run start as an audited class-3 secret and is
|
|
projected only into the child process:
|
|
|
|
- `GH_TOKEN`, `GITHUB_TOKEN`, and an internal credential-helper environment key;
|
|
- `GIT_TERMINAL_PROMPT=0`;
|
|
- process-scoped `GIT_CONFIG_COUNT/KEY_n/VALUE_n` entries that clear ambient
|
|
helpers, install a `github.com`-only helper, and rewrite GitHub SSH remotes to
|
|
HTTPS;
|
|
- author and committer identity using
|
|
`<numeric-id>+<login>@users.noreply.github.com`.
|
|
|
|
Tokens never appear in arguments, URLs, files, logs, events, or model context,
|
|
and the projection never replaces `HOME`.
|
|
|
|
Cloud deployment and exact GitHub App registration settings live in
|
|
`paperclip-cloud/docs/github-connector-deploy-bootstrap.md`.
|