feat(integrations): github enterprise support #8348
Conversation
|
In keeping with our Python filename conventions, should we not rename the |
Yes. And don't use capital letters in filenames. |
6d18402 to
1f8fc12
Compare
21f4ff2 to
7c6a34b
Compare
| allow_redirects=False, | ||
| timeout=30, | ||
| verify_ssl=True, | ||
| verify_ssl=False, |
There was a problem hiding this comment.
these are in here temporarily because the github enterprise test instance doesn't have a valid cert
There was a problem hiding this comment.
Let's not forget to turn this off, or at least make it a configuration of the integration or something.
There was a problem hiding this comment.
👀
This should absolutely be configurable in the integration. It's likely that more than 0 GH enterprise installs use an non-standard cert. Whether it's an internally trusted cert, self signed, something that we can't validate.
There was a problem hiding this comment.
Yeah, it will have to be a toggle on in the configuration form.
| if self.oauth_access_token_url is not '': | ||
| return self.oauth_access_token_url | ||
|
|
||
| # # check the model for instalation information |
There was a problem hiding this comment.
these commented out blocks will be used later when the installation flow has completed successfully
| return [ | ||
| OAuth2LoginView( | ||
| authorize_url=self.oauth_authorize_url, | ||
| lambda: OAuth2LoginView( |
There was a problem hiding this comment.
this was needed to be postponed because we can't evaluate the urls until earlier parts of the flow have completed
| installation_data = state['installation_data'] | ||
| # user = get_user_info(installation_data['url'], identity['access_token']) | ||
| # this doesn't work yet (404s): | ||
| installation = self.get_installation_info( |
There was a problem hiding this comment.
this is the main issue right now.
There was a problem hiding this comment.
I think you were maybe using the wrong id?
| self.provider_model = provider_model | ||
|
|
||
| self.config = config | ||
| self.provider.set_pipeline(self) |
There was a problem hiding this comment.
this is definitely why the tests are failing. @MeredithAnya tomorrow maybe you can try removing this change and seeing what breaks for GHE?
and/or @evanpurkhiser do you by chance have any context into why this change would be necessary?
There was a problem hiding this comment.
This is for sure needed so that the provider is able to lookup the OAuth configuration from the parent pipleine (available on the executing pipeline). I'll take a look at tests.
There was a problem hiding this comment.
Should be fixed. The tests overrode the variable this assigned to.
| allow_redirects=False, | ||
| timeout=30, | ||
| verify_ssl=True, | ||
| verify_ssl=False, |
There was a problem hiding this comment.
Let's not forget to turn this off, or at least make it a configuration of the integration or something.
| self.config = config | ||
| self.logger = logging.getLogger('sentry.identity.%s'.format(self.key)) | ||
|
|
||
| def get_pipeline(self): |
There was a problem hiding this comment.
Can you pull this into a separate PR. This is pretty unrelated and just about removing a totally unused abstract method.
| from sentry.identity.oauth2 import OAuth2Provider | ||
|
|
||
|
|
||
| def get_user_info(url, access_token): |
There was a problem hiding this comment.
maybe we can have this reused in the github integration? Definitely some duplication here. Or maybe this can get sucked into the github client.
There was a problem hiding this comment.
@macqueen thoughts here? I could also put it in github/utils with the jwt stuff if that makes sense
| return resp | ||
|
|
||
|
|
||
| class GitHubEnterpriseIdentityProvider(OAuth2Provider): |
There was a problem hiding this comment.
Can this just extend GithubIdentityProvider and override the key and name?
There was a problem hiding this comment.
the GitHubIdentityProvider also has other methods and whatnot that the GHE doesn't need so wouldn't you just end up needing to overriding those too?
There was a problem hiding this comment.
Ah okay, that makes sense. This is fine.
| def build_identity(self, data): | ||
| data = data['data'] | ||
|
|
||
| user = get_user_info(data['access_token']) |
There was a problem hiding this comment.
This call is wrong, doesn't provide the url.
| GitHubEnterpriseInstallationRedirect(), | ||
| identity_pipeline_view] | ||
|
|
||
| def get_installation_info(self, installation_data, access_token, installation_id): |
There was a problem hiding this comment.
It would be nice for this to be abstracted between the two github integrations.
| logger = logging.getLogger('sentry.integrations.github-enterprise') | ||
|
|
||
|
|
||
| class GitHubEnterpriseAppsEndpoint(Endpoint): |
There was a problem hiding this comment.
Are these webhooks going to be so different that we have to use an entirely different endpoint?
| 'redirect_url': absolute_uri('/extensions/github-enterprise/setup/'), | ||
| } | ||
|
|
||
| identity_pipeline_view = NestedPipelineView( |
There was a problem hiding this comment.
Okay so I realized, because we now allow for late binding of pipeline steps, we can actually do a better job providing the oauth parameters to the identity pipeline through it's config object, versus it expecting to find it in a parent pipeline. How about this
If we have a helper method to construct the identity pipeline view
def _make_identity_pipeline_view(self):
"""
Make the nested identity provider view. It is important that this view is
not constructed until we reach this step and the
``oauth_config_information`` is available in the pipeline state. This
method should be late bound into the pipeline vies.
"""
identity_pipeline_config = dict(
oauth_scopes=(),
redirect_url=absolute_uri('/extensions/github-enterprise/setup/'),
*self.pipeline.fetch_state('oauth_config_information'),
)
return NestedPipelineView(
bind_key='identity',
provider_key='github-enterprise',
pipeline_cls=IdentityProviderPipeline,
config=identity_pipeline_config,
)Then in the get_pipeline_views
return [
InstallationConfigView(),
GitHubEnterpriseInstallationRedirect(),
# The identity provider pipeline should be constructed at execution
# time, this allows for the oauth configuration parameters to be made
# available from the installation config view.
lambda: self._make_identity_pipeline_view(),
]|
|
||
| def set_pipeline(self, pipeline): | ||
| """ | ||
| todo(maxbittker) |
There was a problem hiding this comment.
This should probably say something along the lines of
Used by the pipeline to give the provider access to the executing pipeline.
| self.provider_model = provider_model | ||
|
|
||
| self.config = config | ||
| self.provider.set_pipeline(self) |
There was a problem hiding this comment.
Should be fixed. The tests overrode the variable this assigned to.
evanpurkhiser
left a comment
There was a problem hiding this comment.
A couple minor nits, but looks awesome. Great work @MaxBittker and @MeredithAnya!
| if model and model.config.get(parameter_name) is not None: | ||
| return model.config.get(parameter_name) | ||
|
|
||
| raise KeyError |
There was a problem hiding this comment.
Could you give this a message like
KeyError(u'Unable to resolve OAuth parameter "{}"'.format(parameter_name))| return [ | ||
| OAuth2LoginView( | ||
| authorize_url=self.oauth_authorize_url, | ||
| lambda: OAuth2LoginView( |
There was a problem hiding this comment.
You can switch these back to being initialized at class construction time.
| defaults={'config': identity_config}, | ||
| ) | ||
|
|
||
| if created: |
https://paper.dropbox.com/doc/Github-Enterprise-Development-Guide-KUZuzK9mVLv2NmHZKcJ7P