Skip to content

Commit

Permalink
fix: update to newer github output style, simplify ci test
Browse files Browse the repository at this point in the history
* add .gitignore file, update app path

Signed-off-by: Steve Arnold <[email protected]>
  • Loading branch information
sarnold committed Apr 25, 2024
1 parent 2d92b2a commit 72d2f80
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 73 deletions.
77 changes: 29 additions & 48 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
@@ -1,55 +1,36 @@
name: Tests
on: [push]
name: action-tests

jobs:
build-temp-container:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master

- name: build-temp-container
run: |
echo ${PASSWORD} | docker login -u $USERNAME --password-stdin
docker build -t hamelsmu/app-token:temp -f prebuild.Dockerfile .
docker push hamelsmu/app-token:temp
env:
USERNAME: ${{ secrets.DOCKER_USERNAME }}
PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
on:
workflow_dispatch:
pull_request:
push:
branches: [ main ]

test-container:
needs: [build-temp-container]
jobs:
test_defaults:
runs-on: ubuntu-latest
name: Test local action
steps:

- uses: actions/checkout@master

# - name: Setup tmate session
# uses: mxschmitt/action-tmate@v1
# env:
# INPUT_APP_PEM: ${{ secrets.APP_PEM }}
# INPUT_APP_ID: ${{ secrets.APP_ID }}
# To use this repository's private action,
# you must check out the repository
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0

# tested with https://github.com/apps/fastpages-chatops
- name: test
id: test
uses: docker://hamelsmu/app-token:temp
env:
INPUT_APP_PEM: ${{ secrets.APP_PEM }}
INPUT_APP_ID: ${{ secrets.APP_ID }}
- name: Environment
run: |
bash -c set
- name: pre-build action image
run: |
cd $GITHUB_WORKSPACE
echo ${PASSWORD} | docker login -u $USERNAME --password-stdin
docker build -t hamelsmu/app-token -f prebuild.Dockerfile .
docker push hamelsmu/app-token
env:
USERNAME: ${{ secrets.DOCKER_USERNAME }}
PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
- name: Get token local action
id: get_token
uses: ./ # Uses an action in the root directory
with:
APP_ID: ${{ vars.VCT_GHT_APP_ID }}
APP_PEM: ${{ secrets.VCT_GHT_APP_PEM }}

# tested withhttps://github.com/apps/fastpages-chatops
- name: final-test
uses: machine-learning-apps/actions-app-token@master
with:
APP_PEM: ${{ secrets.APP_PEM }}
APP_ID: ${{ secrets.APP_ID }}
- name: Check App Installation Token
run: |
echo "This token is masked: ${TOKEN}"
env:
TOKEN: ${{ steps.get_token.outputs.app_token }}
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
__pycache__/
jwt-key*
pem.txt
16 changes: 16 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
FROM python:3.9-alpine3.16

RUN apk --no-cache add git bash

ADD entrypoint.sh /
ADD token_getter.py /

RUN pip install \
cryptography==3.4.8 \
github3.py==1.3.0 \
jwcrypto==0.6.0 \
pyjwt==1.7.1

RUN chmod u+x /entrypoint.sh

ENTRYPOINT ["/entrypoint.sh"]
2 changes: 1 addition & 1 deletion action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ branding:
icon: 'unlock'
runs:
using: 'docker'
image: 'docker://hamelsmu/app-token'
image: 'Dockerfile'
2 changes: 1 addition & 1 deletion entrypoint.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/bin/bash

echo $INPUT_APP_PEM | base64 -d > pem.txt
python /app/token_getter.py
python token_getter.py
48 changes: 25 additions & 23 deletions token_getter.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,27 +12,27 @@
class GitHubApp(GitHub):
"""
This is a small wrapper around the github3.py library
Provides some convenience functions for testing purposes.
"""

def __init__(self, pem_path, app_id, nwo):
super().__init__()
self.app_id = app_id

self.path = Path(pem_path)
self.app_id = app_id
if not self.path.is_file():
raise ValueError(f'argument: `pem_path` must be a valid filename. {pem_path} was not found.')
raise ValueError(f'argument: `pem_path` must be a valid filename. {pem_path} was not found.')
self.nwo = nwo

def get_app(self):
with open(self.path, 'rb') as key_file:
client = GitHub()
client.login_as_app(private_key_pem=key_file.read(),
app_id=self.app_id)
return client

def get_installation(self, installation_id):
"login as app installation without requesting previously gathered data."
with open(self.path, 'rb') as key_file:
Expand All @@ -41,30 +41,30 @@ def get_installation(self, installation_id):
app_id=self.app_id,
installation_id=installation_id)
return client

def get_test_installation_id(self):
"Get a sample test_installation id."
client = self.get_app()
return next(client.app_installations()).id

def get_test_installation(self):
"login as app installation with the first installation_id retrieved."
return self.get_installation(self.get_test_installation_id())

def get_test_repo(self):
repo = self.get_all_repos(self.get_test_installation_id())[0]
appInstallation = self.get_test_installation()
owner, name = repo['full_name'].split('/')
return appInstallation.repository(owner, name)

def get_test_issue(self):
test_repo = self.get_test_repo()
return next(test_repo.issues())

def get_jwt(self):
"""
This is needed to retrieve the installation access token (for debugging).
This is needed to retrieve the installation access token (for debugging).
Useful for debugging purposes. Must call .decode() on returned object to get string.
"""
now = self._now_int()
Expand All @@ -76,7 +76,7 @@ def get_jwt(self):
with open(self.path, 'rb') as key_file:
private_key = default_backend().load_pem_private_key(key_file.read(), None)
return jwt.encode(payload, private_key, algorithm='RS256')

def get_installation_id(self):
"https://developer.github.com/v3/apps/#find-repository-installation"

Expand All @@ -86,19 +86,19 @@ def get_installation_id(self):

headers = {'Authorization': f'Bearer {self.get_jwt().decode()}',
'Accept': 'application/vnd.github.machine-man-preview+json'}

response = requests.get(url=url, headers=headers)
if response.status_code != 200:
raise Exception(f'Status code : {response.status_code}, {response.json()}')
return response.json()['id']

def get_installation_access_token(self, installation_id):
"Get the installation access token for debugging."

url = f'https://api.github.com/app/installations/{installation_id}/access_tokens'
headers = {'Authorization': f'Bearer {self.get_jwt().decode()}',
'Accept': 'application/vnd.github.machine-man-preview+json'}

response = requests.post(url=url, headers=headers)
if response.status_code != 201:
raise Exception(f'Status code : {response.status_code}, {response.json()}')
Expand All @@ -107,24 +107,24 @@ def get_installation_access_token(self, installation_id):
def _extract(self, d, keys):
"extract selected keys from a dict."
return dict((k, d[k]) for k in keys if k in d)

def _now_int(self):
return int(time.time())

def get_all_repos(self, installation_id):
"""Get all repos that this installation has access to.
Useful for testing and debugging.
"""
url = 'https://api.github.com/installation/repositories'
headers={'Authorization': f'token {self.get_installation_access_token(installation_id)}',
'Accept': 'application/vnd.github.machine-man-preview+json'}

response = requests.get(url=url, headers=headers)

if response.status_code >= 400:
raise Exception(f'Status code : {response.status_code}, {response.json()}')

fields = ['name', 'full_name', 'id']
return [self._extract(x, fields) for x in response.json()['repositories']]

Expand All @@ -134,7 +134,7 @@ def generate_installation_curl(self, endpoint):
print(f'curl -i -H "Authorization: token {iat}" -H "Accept: application/vnd.github.machine-man-preview+json" https://api.github.com{endpoint}')

if __name__ == '__main__':

pem_path = 'pem.txt'
app_id = os.getenv('INPUT_APP_ID')
nwo = os.getenv('GITHUB_REPOSITORY')
Expand All @@ -148,5 +148,7 @@ def generate_installation_curl(self, endpoint):
token = app.get_installation_access_token(installation_id=id)
assert token, 'Token not returned!'

env_file = os.getenv("GITHUB_ENV")
print(f"::add-mask::{token}")
print(f"::set-output name=app_token::{token}")
with open(env_file, "a") as myfile:
myfile.write(f"app_token={token}\n")

0 comments on commit 72d2f80

Please sign in to comment.