Mergebot as a Github application
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 159
- Forks
- 156
- Avg merge
- 1d 13h
- Merged PRs (30d)
- 16
Description
Motivation
PATs are a problem, along multiple axis:
- they are a 1:1 representation of a user account's accesses (with some
restrictions but e.g.repois necessary to do anything with private
repositories and it's basically full unfettered access), across all
organizations and repositories, this makes them extremely dangerous - they can not be audited or managed by organizations beyond a completely
binary "allow all" / "deny all" - as a consequence of (2), it is not possible for Odoo to deny PATs
(and require e.g. FGTs) as long as infrastructure tools like the mergebot
need PATs
FGTs are not a solution (for the mergebot)
FGTs exist as a finer-grained and more auditable alternative to PATs, however
they do not work for the mergebot: an FGT is strongly bound to one owner.
This means cross-owner operations can only be performed between public
repositories: given two organizations A and B, and the repositories A.r and
B.r (a fork of A.r), creating a PR from B.r to A.r requires content (ref)
read access to B.r and PR write access to A.r. If both repositories are
private, this is infeasible, because an FGT can only get access to the private
repositories of the owner they are bound to.
Apps do work
By default ("installation access") github apps behave like FGTs, except in
the access token can be even more restricted than the application, and the
access token only has a 1h lifetime.
However apps also have user access tokens, so if they are installed
in a user's account and multiple organizations (/ repositories?) using that
mode they can interact across organizations. This is a more PAT-like usage
but still requires opt-in (installing the app) and respects the application's
restrictions. UATs also have an 8h lifetime after which they need to be
refreshed so the UAT is a bit less of a security risk than an FGT let alone
PAT. The refresh token is a lot more valuable, however because it's consumed
on refresh if the refresh token is leaked you should know within 8h (however if
someone has continuous access to the instance they could just read the UAT every
time it's refreshed...).
Changing the permission requirements of an app will also require that the
owner applies the upgrade to their installation(s).
As such apps can do the job for better security, but at the cost of a
complexity increase:
-
needs to store multiple "key to the kingdom" secrets (private key, client secret
uat/refresh token pair) -
needs to track installations in order to generate IATs
-
needs to track an (UAT, refresh token) pair per "actor"
this is mitigation by only needing one such, in order to create PRs...
TODO
check if scoped tokens can be derived from IATs
they can't, only UATs- check if a user with read access to A and write to B can install the
application and grant it the ability to push branches to B and create
PRs in A- yes, being a
readcollaborator on A is sufficient to create a PR
there, don't even need to be associated with the org
- yes, being a
- check if a user with read access to A and write to B can install the
- check if an app owned by one org can be installed by an other org, or a
user (purpose: have odoo own the mergebot app, with odoo-dev/robodoo/...
installing it from there, rather than have robodoo own the app)- yes
- use
X-Accepted-GitHub-Permissionsto figure the exact ACL- POST /orgs/{org}/repos administration=write
- GET /repos/{owner}/{repo} metadata=read
- POST /repos/{owner}/{repo}/forks None
- GET /repos/{owner}/{repo}/branches/dsfasfsfsaf contents=read
- POST /repos/{owner}/{repo}/git/trees contents=write
- POST /repos/{owner}/{repo}/git/refs contents=write; contents=write,workflows=write
- GET /repos/{owner}/{repo}/issues/{number} issues=read (even if it's a PR)
- POST /repos/{owner}/{repo}/pulls pull_requests=write
This one is a bit weird because the app needs pull_requests=write but the
user only needs read on the repository. - GET /repos/{owner}/{repo}/pulls/{number}/commits pull_requests=read
- POST /repos/{owner}/{repo}/issues/{number}/comments issues=write; pull_requests=write
- PUT /repos/{owner}/{repo}/issues/{number}/labels issues=write; pull_requests=write
- PATCH /repos/{owner}/{repo}/pulls/{number} pull_requests=write
- POST /repos/{owner}/{repo}/issues/comments/{id}/reactions issues=write; pull_requests=write
- GET /repos/{owner}/{repo}/commits/{ref}/status ?commit_statuses=read
- add apps support to DC (ugh...)
- split API config into a separate object, with abstract token retrieval
- add scope information to token retrieval
- ?
- user access flow requires a bunch of endpoints of its own
- use
/user/installationsto check that cross-org interactions can work - allow supporting app webhooks somehow (probably have the webhooks
controller feed into the API config object) - provide an app manifest so third parties can deploy their own
mergebot-as-app - apps can be configured to bypass rulesets protection
Critical interactions
- "App" endpoints (app-level operations) require JWT signed with (one
of) the app's private keys. - Refreshing UATs require the client secret and refresh token. There is no
way (that I found) to check the validity of a UAT aside from trying to use it,
so might be nice to associate a pessimistic lifetime to UATs on retrieval,
also maybe only store UAT and IAT in memory? Unlogged table?- IATs come with an
expires_at - if the app is configured with non-expiring tokens, the response of the
auth flow will contain just theaccess_token
- IATs come with an
- "Installation" endpoints require IATs.
- General API access can use either IAT or UAT depending on their action role
(and requirements, mostly, for us), the main effect is the actor the action is
associated with: with an IAT, it's the application's[Bot]user whereas with
a UAT it's the user whose account granted the authorization - git network operations (push/pull) require using https and the
x-access-tokenuser
Limitations
- issues:write / pull_requests:write is necessary to leave comments on issues
and PRs (respectively) for private repositories, - scoped tokens have to be bound to a specific owner (
target/target_id)
so they create the same restriction as FGT/IAT when it comes to the one
thing I need them for: trying to create a cross-org PR fails with "not all
refs are readable" (same as FGT). - github apps can't fork private repositories cross-orgs, which means workarounds
are required for testing interactions between private forks
Additional features
-
IAT means apps interact as apps, rather than impersonating a user
-
automatic webhooks setup
-
IP whitelisting
-
webhooks for installation, repository addition (/ creation)
-
checks API
-
multiple private keys and client secrets can be active at the same time, making those easy to rotate
UAT/refresh tokens, not so much [nb: to test but IIRC if a new UAT is created, even through a full auth flow, the previous one is invalidated]
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the TODO and the critical interactions sections, then trace the existing API config and webhook controller entry points mentioned there. Map app, installation, and user-access-token flows, including scope and token storage requirements. Done means Mergebot can use GitHub Apps for its required operations, webhooks and configuration are supported, and the listed permission constraints are handled.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- github, python
- Domain
- authentication, authorization, backend-api-design, security
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Needs clarification
- Newbie friendliness
- 35/100