Skip to content

Commit 39940a1

Browse files
committed
ghapp_token improvements and documentation
we don't need to create a app token and pass a installation_id if we just want to generate a jwt token. add a long description of how it works and how it can be used. Signed-off-by: Chmouel Boudjnah <[email protected]>
1 parent 6b8bd58 commit 39940a1

File tree

1 file changed

+58
-19
lines changed

1 file changed

+58
-19
lines changed

hack/dev/ghapp_token.py

Lines changed: 58 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,35 +6,53 @@
66
import os
77
import pathlib
88
import subprocess
9+
import sys
910
import time
1011

1112
import requests
1213
from jwcrypto import jwk, jwt
1314

1415
SECRET_NAME = "pipelines-as-code-secret"
1516
NAMESPACE = "pipelines-as-code"
16-
EXPIRE_MINUTES_AS_SECONDS = (
17-
int(os.environ.get("GITHUBAPP_TOKEN_EXPIRATION_MINUTES", 10)) * 60
18-
)
17+
JWT_EXPIRE_MINUTES_AS_SECONDS = 10 * 60
18+
1919
# TODO support github enteprise
2020
GITHUB_API_URL = "https://api.github.com"
2121

22+
HELP_TEXT = """
23+
ghapp_token.py let you generate a token for a github app out of an application
24+
id and a private key
25+
26+
The way it works is that first we generate a jwt token out of the private key
27+
then use it to get a installation token. (see documentation here:
28+
https://is.gd/DsPw4z)
29+
30+
It will automatically detect the secret from the cluster in the
31+
pipelines-as-code namespace (unless you specify the -n flag for another
32+
namespace) and get the value from there.
33+
34+
If you are generating a token on GHE you probably want to pass the flag -a for
35+
another api endpoint.
36+
37+
Alternatively you can use a pass (https://passwordstore.org) profile to get
38+
the keys with the -P flag.
39+
40+
You can use a cache file to avoid generating a new token each time and reuse
41+
"""
42+
2243

2344
# pylint: disable=too-few-public-methods
2445
class GitHub:
2546
token = None
2647

27-
def __init__(
28-
self, private_key, app_id, expiration_time, github_api_url, installation_id=None
29-
):
48+
def __init__(self, private_key, app_id, expiration_time, github_api_url):
3049
if not isinstance(private_key, bytes):
3150
private_key = private_key.encode()
3251
self._private_key = private_key
3352
self.app_id = app_id
3453
self.expiration_time = expiration_time
3554
self.github_api_url = github_api_url
3655
self.jwt_token = self._get_jwt_token()
37-
self.token = self._get_token(installation_id)
3856

3957
@classmethod
4058
def _load_private_key(cls, pem_key_bytes):
@@ -56,7 +74,7 @@ def _get_jwt_token(self):
5674
token.make_signed_token(key)
5775
return token.serialize()
5876

59-
def _get_token(self, installation_id):
77+
def get_token(self, installation_id):
6078
req = self._request(
6179
"POST",
6280
f"/app/installations/{installation_id}/access_tokens",
@@ -127,7 +145,7 @@ def main(args):
127145
if datetime.datetime.fromtimestamp(
128146
mtime
129147
) < datetime.datetime.now() - datetime.timedelta(
130-
seconds=args.token_expiration_time
148+
seconds=args.jwt_token_expiration_time
131149
):
132150
os.remove(args.cache_file)
133151
else:
@@ -140,14 +158,23 @@ def main(args):
140158
github_app = GitHub(
141159
private_key,
142160
application_id,
143-
expiration_time=args.token_expiration_time,
161+
expiration_time=args.jwt_token_expiration_time,
144162
github_api_url=args.api_url,
145-
installation_id=args.installation_id,
146163
)
164+
147165
if args.jwt_token:
148166
print(github_app.jwt_token)
149-
else:
150-
print(github_app.token)
167+
sys.exit(0)
168+
169+
if not args.installation_id:
170+
print(
171+
"You need to provide an installation id or have the -j flag to only generate jwt token"
172+
)
173+
sys.exit(1)
174+
175+
github_app.token = github_app.get_token(args.installation_id)
176+
print(github_app.token)
177+
151178
if args.cache_file:
152179
print(
153180
pathlib.Path(args.cache_file).write_text(
@@ -157,15 +184,20 @@ def main(args):
157184

158185

159186
def parse_args():
160-
parser = argparse.ArgumentParser(description="Generate a user token")
187+
parser = argparse.ArgumentParser(
188+
description="Generate a installation token from github application pac secret"
189+
)
161190
parser.add_argument(
162-
"--token-expiration-time",
191+
"--jwt-token-expiration-time",
163192
type=int,
164193
help="Token expiration time (seconds)",
165-
default=EXPIRE_MINUTES_AS_SECONDS,
194+
default=JWT_EXPIRE_MINUTES_AS_SECONDS,
166195
)
167196
parser.add_argument(
168-
"--installation-id", "-i", type=int, help="Installation_ID", required=True
197+
"--installation-id",
198+
"-i",
199+
type=int,
200+
help="Installation_ID",
169201
)
170202

171203
parser.add_argument(
@@ -191,11 +223,18 @@ def parse_args():
191223
"--cache-file",
192224
help=(
193225
f"Cache file will only regenerate after the expiration time, "
194-
f"default: {EXPIRE_MINUTES_AS_SECONDS / 60} minutes"
226+
f"default: {JWT_EXPIRE_MINUTES_AS_SECONDS / 60} minutes"
195227
),
196228
default=os.environ.get("GITHUBAPP_RESULT_PATH"),
197229
)
198-
return parser.parse_args()
230+
args = parser.parse_args()
231+
if not args.installation_id or not args.jwt_token:
232+
parser.print_help()
233+
print("Description:", end="")
234+
print("\n".join([f" {x}" for x in HELP_TEXT.splitlines()]))
235+
sys.exit(1)
236+
237+
return args
199238

200239

201240
if __name__ == "__main__":

0 commit comments

Comments
 (0)