Skip to content

Let projects use GitHub App installations; report a missing Members permission - #648

Merged
TonsOfFun merged 3 commits into
mainfrom
fix/projects-github-app-installations
Oct 27, 2026
Merged

TonsOfFun merged 3 commits into
mainfrom
fix/projects-github-app-installations

Conversation

@TonsOfFun

Copy link
Copy Markdown
Contributor

Fixes #645

Behavior change

Projects accept a linked GitHub App installation (section 1).
Api::ProjectsController now resolves repositories through the owner's GitHub sources: usable GithubInstallations (only while an App is configured), in the order they were linked, then the OAuth GithubConnection. That is the same order SandboxSession#repository_available checks a repository out in, so a project is read through the source its sandbox will clone from.

  • The github_connection checklist item holds when any source exists. With the App configured, its fix text now says "Install the GitHub App in Settings → Integrations".
  • New GET /api/projects/repositories for the New Project picker. It lists the union of the installations' and the connection's repositories, each with selected and source (app / oauth), selections first and installations ahead of the connection. An installation lists repositories outside its selection only to a caller with :manage_github; anyone else sees its selection. The connection keeps today's listing. NewProject.jsx calls this endpoint now instead of /api/github_connection/repositories.
  • Preflight, secret discovery, create and the default_ref change go to the first source that selected the repository. Failing that, the repository is looked up by name through each source the caller may manage. The 403 is still decided before GitHub is asked. Through an installation the files are read with a token minted for contents: read on that one repository id, used for the request only and never stored. Creating a project from an unselected repository selects it on the source it was found through.
  • A removed or suspended installation answers 422 installation_unavailable with reinstall_required: true, and the installation is marked the way a checkout marks it.
  • GithubConnection and GithubInstallation now share reachable_repositories, find_repository, contents_client and checkout_source, so the controller treats them the same way.

Missing Members permission (section 2). GithubClient#organization_membership still returns nil on 404. On 403 it now raises GithubClient::MembershipForbidden, and the installation callback reports ?github_app=members_permission instead of not_admin. Settings shows a message explaining how to add and accept Members (read), with a note about SAML SSO. The manifest flow already requested members: read; the docs now explain why it is needed.

Callback order (section 3, docs). docs/framework/dashboard.md now says the dashboard callback must be the App's first callback URL, and documents the callback?installation_id=<id>&setup_action=update link for an App that is already installed.

Deferred

  • "Link an existing installation" in Settings (the GET /user/installations picker from section 3). It needs a new user-authorization flow that has no installation id, plus a way to choose among several installations without keeping the user token, so I left it for a follow-up. The documented callback link covers the gap for now.
  • The host runbook step for Members (read) belongs in the host repo, not this one.

Tests

  • New actionagent/test/projects_github_app_test.rb (11 tests) covers:
    • an installation alone counts as connected, and a removed or unconfigured one does not
    • the picker's selection and full listing, and the union with the connection
    • minted token scope (contents: read, repository_ids: [id])
    • create, then boot through the installation
    • an unselected repository is selected on the installation
    • the :manage_github gate, with no mint when it is denied
    • a repository selected both ways goes through the installation
    • a removed installation answers installation_unavailable
  • github_app_client_test.rb: a 403 raises MembershipForbidden.
  • github_installations_test.rb: a 403 redirects with members_permission, not not_admin.
  • Full engine suite: 1845 runs, 13824 assertions, 0 failures, 0 errors, 7 skips.
  • Frontend: npm test passes 711/711, and npm run build regenerated app/assets/builds/action_agent.js.
  • RuboCop: no offenses on the changed Ruby files.

🤖 Generated with Claude Code

https://claude.ai/code/session_01PCEJHsJpjXpDa9Kuq9i4Yg

TonsOfFun and others added 3 commits October 27, 2026 15:45
A dashboard that runs only the GitHub App could link an installation but
not create a project: the projects API only looked at the OAuth
connection. The owner's GitHub sources are now its usable installations,
in the order linked, then the OAuth connection, which is the order a
sandbox checks a repository out in. The New Project checklist counts any
of them as connected, GET /api/projects/repositories lists their
repositories for the picker, and preflight, secret discovery and creation
reach the repository through the first source that selected it, else by
name through each source the caller may manage. Through an installation
the files are read with a token minted for that one repository's
contents. A removed or suspended installation answers
installation_unavailable.

Linking an organization's installation now reports members_permission
when GitHub refuses the membership check with 403 (the App lacks
Members: read), instead of not_admin. The dashboard guide documents the
permission, that the dashboard callback must be the App's first callback
URL, and how to link an installation that is already installed.

Fixes #645

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PCEJHsJpjXpDa9Kuq9i4Yg
The dashboard bundle is rebuilt from the merged sources.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PCEJHsJpjXpDa9Kuq9i4Yg
@TonsOfFun
TonsOfFun merged commit efd7368 into main Oct 27, 2026
12 checks passed
@TonsOfFun TonsOfFun mentioned this pull request Oct 28, 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.

Projects ignore GitHub App installations; App setup gaps (Members permission, return to dashboard)

1 participant