Support every GitHub App installation
Los mantenedores suelen responder en 1 día
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 5/5
- Tiempo estimado
- Más de una semana
- Aptitud para principiantes
- 35/100
- Tipo de issue
- Nueva funcionalidad
- Claridad
- Bien especificado
- Estado de actividad
- Activo
- Stack tecnológico
- github, github-actions, typescript
- Área
- api, authentication, backend, devtools
Línea de trabajo
Start with the GitHub plugin's egress credential routing, webhook handlers, and trigger creation and edit paths; the issue also names resolve-pull-request-review-thread.ts as a host tool to update. Read PR #2405 for the existing partial implementation and compare it with the owner installation map and provider-neutral trigger check described here. Done means webhooks use their signed installation, requests route to the correct installation by owner, trigger checks reject uninstalled owners, and config, docs, tests, and eval fixtures are updated.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Problem
The GitHub plugin works with only one GitHub App installation. That installation is set by GITHUB_INSTALLATION_ID. Repositories in any other installation of the same App do not work.
Example from prod: an event automation for fairsource/fair.io never ran. The App is installed on the fairsource org with access to all of its repositories. But prod is configured with the getsentry installation, so:
- The webhook handler drops every
fairsourcedelivery with202 Ignored. - Every token Junior creates is for the
getsentryinstallation. Lookups, reactions and agent actions onfairsource/fair.iofail. - Saving the trigger succeeds and shows it as available, so nothing tells the user that it can never run.
How Junior differs from other GitHub Apps
Most GitHub Apps choose the installation from context before they call the API:
- Event handlers (Probot and similar) use
installation.idfrom the webhook payload for all work on that event. - Apps with stored records (Vercel, Sentry's GitHub integration) save the installation ID when a user connects an org or imports a repo.
- Repo-only callers call
GET /repos/{owner}/{repo}/installationonce and keep the result.
Junior also routes raw gh and git traffic from the agent through host egress, one request at a time. The host sees every request, and almost every request names its owner:
- REST
/repos/{owner}/{repo}/...and/orgs/{org}/... - Git smart HTTP
github.com/{owner}/{repo}.git ghGraphQL reads, which sendownerandrepoornamevariables (cli/cliapi/queries_pr.go,api/queries_repo.go)- Host tools, which already put
owner/repoin the egressoperationfor GraphQL mutations
The credential contract does not depend on the conversation. SandboxEgressCredentialContext.conversationId is telemetry only, and installation leases are shared across all sandboxes. So we route by owner for each request, and do not bind an installation to a conversation.
Plan
1. Webhooks: use the installation that sent the delivery
- Remove the installation ID check. The webhook secret belongs to the App, so a valid signature proves the delivery is for one of its installations.
- Use
installation.idfrom the signed payload for all follow-up requests of that delivery: PR commits, opener and author filters, check suites and reactions. - Ignore a delivery that has no installation.
2. Egress: route by owner, not by repository
An App can be installed at most once per account. So the owner identifies the installation.
- Installation map: load
GET /app/installations, signed as the App, into the plugin cache asaccount login → installation id. Refresh it when aninstallationorinstallation_repositorieswebhook arrives. Keep a TTL as a backstop. - Target:
grantForEgressfinds the owner from the URL path, GraphQLownervariable, or host tooloperation. The grantleaseScopeisowner:<login>(lowercase). So there is one remembered lease per installation and grant, the same as today forgetsentry. - Default installation: the installation on the account that owns the App. It is in the same map. Use it for reads that name no owner, and for reads of owners where the App is not installed (public repositories).
- Writes: a write to an owner with no installation fails with
The GitHub App is not installed on <owner>.It never falls back to another installation. - Tokens: write tokens keep the full installed permissions. Read tokens keep the read-only permissions of their own installation. Tokens are not limited to one repository, because the lease is per owner.
- Host tools: read requests that use only a node ID, such as the review-thread lookup in
resolve-pull-request-review-thread.ts, putowner/repoinoperation, as the mutations already do.
3. Config and docs
- Remove
GITHUB_INSTALLATION_IDand theinstallationIdEnvoption as a hard cutover. Only the App ID, private key and webhook secret stay. - Update
SETUP.md, the GitHub plugin docs,.env.examplefiles, tests and eval fixtures. - Document the limit: requests that name no owner use the default installation.
4. Trigger checks
- Saving a GitHub trigger or Watch for an owner with no installation fails with a plain error.
- Core has no async plugin hook for this today. Add the smallest provider-neutral hook to plugin events, for example
checkResource({ resourceType, identifier }), which returns a problem message. Call it from event automation create and edit, and fromwatchEvents. - With the installation map, the GitHub check is a cache read.
5. junior-prod
- After release, remove the
GITHUB_INSTALLATION_IDenv var.
Decisions
- No allowlist by installation or org. The App is private, so only orgs we choose can install it. Junior accepts every installation of the App.
- A token is used only for its own installation. A request for an owner in one installation never uses another installation's token. Only reads for owners with no installation use the default installation.
- Route by owner, not by conversation. A conversation can touch more than one org, and the credential contract does not depend on the conversation.
- Owner, not repository. A per-repository lookup with
GET /repos/{owner}/{repo}/installationgives one API call, lease and token per repository. Each of those tokens covers the whole installation anyway.
Open questions
- Which account owns the prod App, and is the App installed on that account? If not, reads that name no owner have no default installation.
- Trigger checks in evals: evals use fake App credentials and cannot reach
api.github.com. They need a fixed installation map, or the check must allow a save when the map cannot load. - Search reads (
/search/issues?q=repo:owner/name) could take the owner fromrepo:,org:oruser:qualifiers. Is this worth doing now? - Should reads with no owner use the requester's GitHub user token when one exists? A user token reaches every installation the user can access, but the read then acts as the user.
Not in scope
- The event-first trigger work in #2362. Broad "all repos" triggers there will then cover every installation, so review the required
repofilter rules from #2362 item 7 when this lands.
Status
- #2405 has steps 1 and 3 done. It also has a first version of step 2 that routes by repository: it calls
GET /repos/{owner}/{repo}/installationor/orgs/{org}/installationfor each target, andGET /appto find the default installation. That part must change to the owner map above. - Step 4 is not started.
via David Cramer.
--
- Lenguaje dominante
- TypeScript
- Estrellas
- 397
- Forks
- 43
- Merge medio
- 7 h 42 min
- PR fusionados (30 d)
- 566
Preparar el entorno
- Incluye un Dockerfile o un archivo de Docker Compose
- Sin plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de getsentry/junior
-
documentation
Dificultad 2/5 1-3 horas Aptitud para principiantes 84/100
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 64/100
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 65/100
getsentry/junior#335 · 1 reacción ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
Los mantenedores suelen responder en 1 día
Todos los issues de getsentry/junior
Issues similares
-
Cleanup SetupPosiblemente ocupada @AlexanderKaran la tomó hoy. Abiertodocumentation enhancement
Dificultad 2/5 1-3 horas Aptitud para principiantes 64/100
e18e/framework-tracker#769 ·
Los mantenedores suelen responder en 1 día
-
fix(docker): correct stale --db-path comments in fetch/git Dockerfiles and clarify git READMEAbiertobug v2
Dificultad 1/5 Menos de una hora Aptitud para principiantes 88/100
modelcontextprotocol/servers#5483 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 1/5 Menos de una hora Aptitud para principiantes 84/100
XiaomiMiMo/MiMo-Code#2783 ·
Los mantenedores suelen responder en 1 día
-
area: web bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
kinqsradio/orbyn-engineering#227 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 85/100
joeldesante/TurfBuilder#258 ·
Los mantenedores suelen responder en 1 día