-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support GitHub Enterprise #8574
Conversation
Codecov Report
@@ Coverage Diff @@
## main #8574 +/- ##
==========================================
- Coverage 12.31% 11.17% -1.14%
==========================================
Files 20 18 -2
Lines 1161 993 -168
==========================================
- Hits 143 111 -32
+ Misses 1014 880 -134
+ Partials 4 2 -2
Flags with carried forward coverage won't be shown. Click here to find out more.
Continue to review full report at Codecov.
|
Taking this back to draft: Should work fine as is, but needs a GitHub Enterprise integration with the preview environment to test it, and once I have that, I might as well add in a few more fixes. |
6d87847
to
d1bfd7a
Compare
…RLs for new auth providers 🤦
…ientSecret values (as GitHub likes to put spaces in there 🤦)
d1bfd7a
to
3fc47b4
Compare
…epos on GitHub Enterprise
d660e96
to
b78071f
Compare
107ffe2
to
953980c
Compare
Holding because of the minor TODOs above: /hold |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Forgot to actually submit the minor TODO comments)
cedb1e6
to
da96bcc
Compare
@jankeromnes Thank you for tackling this, and providing a working solution this fast! 💯 🙏 We discussed this earlier, just want to point it out again:
If I'm missing something here - be it technical, or other - please let me know! Also, really don't want to hinder the good progress here, just want to make sure by point is clear. 🙂 |
Thanks @geropl for the quick review! 🙏
I don't think it "breaks the pattern", because the GitHub App is a singleton in Gitpod (i.e. you can only have one GitHub App per Gitpod installation), while we already allow an arbitrary number of Integrations (of type Also, webhooks and the GitHub App are not mutually exclusive. As a next step to this PR, I'd love to explore what it could look like if you have a single Gitpod Self-Hosted installation, and connect its GitHub App singleton to a single GitHub Enterprise server (as opposed to connecting it to github.com as we do on SaaS). Ironing out any bugs in that process could create a nice alternative integration point specifically for Self-Hosted / GHE.
As mentioned above, I'm happy to follow up, e.g. by testing a Gitpod Self-Hosted using a GitHub App connected to a GitHub Enterprise server. As mentioned above, I don't think webhooks and the GitHub App are mutually exclusive. |
I believe these scopes are all included in the Another relevant question is, provided we have the correct scopes, which users are allowed to perform these actions? Here it seems that only repository |
For some reason Werft decided to hide the preview URL of this Pull Request, but the preview itself is still live FYI: |
app.use(bodyParser.json()) | ||
app.use(bodyParser.urlencoded({ extended: true })) | ||
// Read bodies as JSON (but keep the raw body just in case) | ||
app.use(bodyParser.json({ verify: (req, res, buffer) => { (req as any).rawBody = buffer; }})); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
which also means we carry the row body for all requests. if there is no other reference, the buffer isn't collected anymore.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right, with this change we'll carry the raw body of JSON requests we receive. I'm assuming that, apart from some webhooks, we don't receive too many / very large JSON payloads, but I might be wrong here.
components/server/src/bitbucket-server/bitbucket-server-repository-provider.ts
Outdated
Show resolved
Hide resolved
// Verify the webhook signature | ||
const signature = req.header('X-Hub-Signature-256'); | ||
const body = (req as any).rawBody; | ||
const tokenEntries = (await this.userDB.findTokensForIdentity(gitpodIdentity)).filter(tokenEntry => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how many tokenEntry
s are expected to be there? it would be great to pick the current one if there are multiple.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As many tokenEntry
s as repositories you've installed prebuilds on.
I didn't filter on the cloneUrl
scope that we also add to tokens, because we don't update the cloneUrl
s in tokens when repositories get renamed/moved.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh! that sounds really expensive. if we get many of them, such operations will drive the event loop lag even higher.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How many GitHub Enterprise repositories do we expect a single user to enable prebuilds on? And can this number realistically ever get sufficiently high to make this loop's runtime cost significant?
But you're right, maybe we should add more tracing here.
EDIT: Looks like the current tracing is already sufficient.
await this.githubApi.run(user, gh => gh.repos.deleteWebhook({ owner, repo, hook_id: webhook.id })); | ||
} | ||
} | ||
// TODO(janx): Also delete old tokens with scopes `GitHubService.PREBUILD_TOKEN_SCOPE` and `cloneUrl`? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please, yes! unless it's already done in createGitpodToken
op.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isn't reusing a token another option here?
just in case, I'm thinking of the db-sync
dilemma.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unless it's already done in
createGitpodToken
op.
Ah, good thought! How nice that this is actually the case: 😄
gitpod/components/server/src/user/token-service.ts
Lines 64 to 67 in 3bd683e
await this.userDB.deleteTokens(identity, | |
// delete any tokens with the same scopes | |
tokenEntry => tokenEntry.token.scopes.every(s => scopes.indexOf(s) !== -1) | |
); |
isn't reusing a token another option here?
just in case, I'm thinking of thedb-sync
dilemma.
Could you please explain the db-sync
dilemma regarding whether to reuse a token vs creating a new one? 🤔
FYI, I followed the same pattern as GitLab and Bitbucket webhooks, i.e. generate a new token for every repo (with the scopes "prebuilds"
and cloneUrl
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you please explain the db-sync dilemma regarding whether to reuse a token vs creating a new one? 🤔
If you override tokens in the DB for a particular repo, they won't be available in the other cluster until the following db-sync cycle. But that might be a general problem with self-managed webhooks.
bbf9a64
to
3d7e92f
Compare
@jankeromnes Thanks for the explanation.
💡 It's news to me that we allow/already support these. I saw you slack post earlier this week, but thought the entries where due to bugs.
It's bit complicated because of the two use cases:
My main concern was that I understood that we want to achieve 1.), but this PR uses the techniques we employ for 2.). This is what I meant with "breaking the pattern". Instead of focusing on the problem at hand (having a customer configure they own GitHub App for their own installation) we seem to be fixing the GHE integration in general. Which is also an interesting goal, but feels a bit out of scope here.
Not at runtime, yes, but I'd really like us to see it this way, because it additional maintenance burden, and now we have to schedule the task of cleaning it up (e.g., deciding for one way or the other).
Awesome, really looking forward to this. 💪 |
3d7e92f
to
b0b6761
Compare
Many thanks @andrew-farries, @geropl and @AlexTugarev for your super helpful reviews! 🙏 I think I've addressed all nits, so this now seems ready to be merged. 🚢 /unhold |
const sig = 'sha256=' + createHmac('sha256', user.id + '|' + tokenEntry.token.value) | ||
.update(body) | ||
.digest('hex'); | ||
return sig === signature; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is probably pedantry at this stage, but comparing the HMAC signatures using a simple string comparison is considered insecure because of the potential for timing attacks.
See the github webhook docs. Seems the best way to do it is with crypto.timingSafeEqual
as suggested here.
Description
.gitpod.yml
files successfullyGrant Access
button/flow for private repositories on GitHub EnterpriseclientId
andclientSecret
values when creating a new IntegrationRelated Issue(s)
Fixes #8501 #8429
How to test
Grant Access
, then also workRelease Notes
Documentation