From 788a484aa700b1541600333ab6bbc08653a4edd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Sat, 13 Jul 2024 10:52:49 +0200 Subject: [PATCH] master/reporters/github: render token for each request MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Github token can expire i.e. if an GitHub apps are used the token needs to be renewed every hour from the installation token. By moving the renderSecrets just when the requests happens, we provide an interface for users to provide a new refresh GITHUB_TOKEN Signed-off-by: Jörg Thalheim --- master/buildbot/reporters/github.py | 28 +++++++++++++++---- .../github-reporter-secret-handling.change | 3 ++ 2 files changed, 26 insertions(+), 5 deletions(-) create mode 100644 newsfragments/github-reporter-secret-handling.change diff --git a/master/buildbot/reporters/github.py b/master/buildbot/reporters/github.py index 3873c2676..27242831f 100644 --- a/master/buildbot/reporters/github.py +++ b/master/buildbot/reporters/github.py @@ -70,7 +70,7 @@ def reconfigService( generators=None, **kwargs, ): - token = yield self.renderSecrets(token) + self.token = token self.debug = debug self.verify = verify self.verbose = verbose @@ -89,7 +89,7 @@ def reconfigService( self._http = yield httpclientservice.HTTPClientService.getService( self.master, baseURL, - headers={'Authorization': 'token ' + token, 'User-Agent': 'Buildbot'}, + headers={'User-Agent': 'Buildbot'}, debug=self.debug, verify=self.verify, ) @@ -109,6 +109,15 @@ def _create_default_generators(self): ), ] + @defer.inlineCallbacks + def _get_auth_header(self, props: Properties | None) -> dict[str, str]: + if props: + token = yield props.render(self.token) + else: + token = yield self.renderSecrets(self.token) + return {'Authorization': f"token {token}"} + + @defer.inlineCallbacks def createStatus( self, repo_user, @@ -119,6 +128,7 @@ def createStatus( context=None, issue=None, description=None, + props=None, ): """ :param repo_user: GitHub user or organization @@ -137,6 +147,7 @@ def createStatus( """ payload = {'state': state} + if description is not None: payload['description'] = description @@ -146,9 +157,11 @@ def createStatus( if context is not None: payload['context'] = context - return self._http.post( - '/'.join(['/repos', repo_user, repo_name, 'statuses', sha]), json=payload + headers = yield self._get_auth_header(props) + ret = yield self._http.post( + '/'.join(['/repos', repo_user, repo_name, 'statuses', sha]), json=payload, headers=headers ) + return ret def is_status_2xx(self, code): return code // 100 == 2 @@ -241,6 +254,7 @@ def sendMessage(self, reports): context=context, issue=issue, description=description, + props=props, ) if not response: @@ -305,6 +319,7 @@ def createStatus( context=None, issue=None, description=None, + props=None, ): """ :param repo_user: GitHub user or organization @@ -313,6 +328,8 @@ def createStatus( :param state: one of the following 'pending', 'success', 'error' or 'failure'. :param description: Short description of the status. + :param context: Build context + :param props: Properties object of the build (used for render GITHUB_TOKEN secret) :return: A deferred with the result from GitHub. This code comes from txgithub by @tomprince. @@ -328,5 +345,6 @@ def createStatus( return None url = '/'.join(['/repos', repo_user, repo_name, 'issues', issue, 'comments']) - ret = yield self._http.post(url, json=payload) + headers = yield self._get_auth_header(props) + ret = yield self._http.post(url, json=payload, headers=headers) return ret diff --git a/newsfragments/github-reporter-secret-handling.change b/newsfragments/github-reporter-secret-handling.change new file mode 100644 index 000000000..a1ebd5408 --- /dev/null +++ b/newsfragments/github-reporter-secret-handling.change @@ -0,0 +1,3 @@ +GitHubStatusPush will now render github tokens right before the request. +This allow to update the token in the configuration file without restarting the server, +which is in example useful for Githuhb App installations. -- 2.45.1