Skip to content

Commit f456852

Browse files
gr2mparkerbxyz
andauthoredJun 9, 2023
feat: initial version (#1)
Co-authored-by: Parker Brown <17183625+parkerbxyz@users.noreply.github.com> Co-authored-by: Gregor Martynus <gr2m@users.noreply.github.com>
1 parent abcb015 commit f456852

14 files changed

+24977
-3
lines changed
 

‎.github/workflows/release.yml

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
name: release
2+
"on":
3+
push:
4+
branches:
5+
- main
6+
7+
permissions:
8+
contents: write
9+
issues: write
10+
pull-requests: write
11+
12+
jobs:
13+
release:
14+
name: release
15+
runs-on: ubuntu-latest
16+
steps:
17+
- uses: actions/checkout@v3
18+
- uses: actions/setup-node@v3
19+
with:
20+
cache: npm
21+
node-version: lts/*
22+
- run: npm ci
23+
- run: npm run build
24+
- uses: ./ # Uses the action in the root directory
25+
id: app-token
26+
with:
27+
app_id: ${{ vars.RELEASER_APP_ID }}
28+
private_key: ${{ secrets.RELEASER_APP_PRIVATE_KEY }}
29+
30+
- id: commit
31+
uses: stefanzweifel/git-auto-commit-action@v4
32+
with:
33+
commit_message: "build: update dist files"
34+
- run: npm i semantic-release-plugin-github-breaking-version-tag
35+
- run: npx semantic-release
36+
env:
37+
GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}

‎.github/workflows/test.yml

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
on: [push]
2+
3+
jobs:
4+
demo:
5+
runs-on: ubuntu-latest
6+
steps:
7+
- uses: actions/checkout@v3
8+
- uses: actions/setup-node@v3
9+
with:
10+
node-version: '16.16'
11+
cache: 'npm'
12+
- run: npm ci
13+
- run: npm run build
14+
- uses: ./ # Uses the action in the root directory
15+
id: demo
16+
with:
17+
app_id: ${{ secrets.APP_ID }}
18+
private_key: ${{ secrets.PRIVATE_KEY }}
19+
- uses: octokit/request-action@v2.x
20+
id: get-repository
21+
env:
22+
GITHUB_TOKEN: ${{ steps.demo.outputs.token }}
23+
with:
24+
route: GET /installation/repositories
25+
- run: echo '${{ steps.get-repository.outputs.data }}'

‎.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
node_modules/
2+
.env

‎LICENSE

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
The MIT License (MIT)
22

3-
Copyright (c) 2023 GitHub, Inc. and contributors
3+
Copyright (c) 2023 Gregor Martynus
4+
Copyright (c) 2023 Parker Brown
45

56
Permission is hereby granted, free of charge, to any person obtaining a copy
67
of this software and associated documentation files (the "Software"), to deal

‎README.md

+102-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,109 @@
1-
# 🚧 Work in progress - see [#1](https://github.com/gr2m/app-token-action/pull/1)
2-
31
# `app-token-action`
42

53
> GitHub Action for creating a GitHub App Installation Access Token
64
5+
## Usage
6+
7+
In order to use this action, you need to:
8+
9+
1. [Register new GitHub App](https://docs.github.com/apps/creating-github-apps/setting-up-a-github-app/creating-a-github-app)
10+
2. [Store the App's ID in your repository environment variables](https://docs.github.com/actions/learn-github-actions/variables#defining-configuration-variables-for-multiple-workflows) (example: `APP_ID`)
11+
3. [Store the App's private key in your repository secrets](https://docs.github.com/actions/security-guides/encrypted-secrets?tool=webui#creating-encrypted-secrets-for-a-repository) (example: `PRIVATE_KEY`)
12+
13+
### Minimal usage
14+
15+
```yaml
16+
on: [issues]
17+
18+
jobs:
19+
hello-world:
20+
runs-on: ubuntu-latest
21+
steps:
22+
- uses: gr2m/app-token-action@v1
23+
id: app-token
24+
with:
25+
app_id: ${{ vars.APP_ID }}
26+
private_key: ${{ secrets.PRIVATE_KEY }}
27+
- uses: peter-evans/create-or-update-comment@v3
28+
with:
29+
token: ${{ steps.app-token.outputs.token }}
30+
issue-number: ${{ github.event.issue.number }}
31+
body: "Hello, World!"
32+
```
33+
34+
### Limit the app's permissions and access to repositories
35+
36+
```yaml
37+
on: [issues]
38+
39+
jobs:
40+
with-scoped-token:
41+
runs-on: ubuntu-latest
42+
steps:
43+
- uses: gr2m/app-token-action@v1
44+
id: app-token
45+
with:
46+
# required
47+
app_id: ${{ vars.APP_ID }}
48+
private_key: ${{ secrets.PRIVATE_KEY }}
49+
# do something with the token
50+
```
51+
52+
### Use app token with `actions/checkout`
53+
54+
```yaml
55+
on: [pull_request]
56+
57+
jobs:
58+
auto-format:
59+
runs-on: ubuntu-latest
60+
steps:
61+
- uses: gr2m/app-token-action@v1
62+
id: app-token
63+
with:
64+
# required
65+
app_id: ${{ vars.APP_ID }}
66+
private_key: ${{ secrets.PRIVATE_KEY }}
67+
- uses: actions/checkout@v3
68+
with:
69+
token: ${{ steps.app-token.outputs.token }}
70+
ref: ${{ github.head_ref }}
71+
# Make sure the value of GITHUB_TOKEN will not be persisted in repo's config
72+
persist-credentials: false
73+
- uses: creyD/prettier_action@v4.3
74+
with:
75+
github_token: ${{ steps.app-token.outputs.token }}
76+
```
77+
78+
## Inputs
79+
80+
### `app_id`
81+
82+
**Required:** GitHub app ID.
83+
84+
### `private_key`
85+
86+
**Required:** GitHub app private key.
87+
88+
## Outputs
89+
90+
### `token`
91+
92+
GitHub installation access token.
93+
94+
## How it works
95+
96+
The action creates an installation access token using [the `POST /app/installations/{installation_id}/access_tokens` endpoint](https://docs.github.com/rest/apps/apps?apiVersion=2022-11-28#create-an-installation-access-token-for-an-app). By default,
97+
98+
1. The token is scoped to the current repository
99+
2. The token inherits all the installation's permissions
100+
3. The token is set as output `token` which can be used in subsequent steps
101+
4. The token is revoked in the `post` step of the action, which means it cannot be passed to another job.
102+
5. The token is masked, it cannot be logged accidentally. That is not a feature by the action, but by the GitHub Actions runner itself, due to the specific format of GitHub tokens.
103+
104+
> **Note**
105+
> Installation permissions can differ from the app's permissions they belong to. Installation permissions are set when an app is installed on an account. When the app adds more permissions after the installation, an account administrator will have to approve the new permissions before they are set on the installation.
106+
7107
## License
8108

9109
[MIT](LICENSE)

‎action.yml

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
name: 'github-app-token'
2+
description: ''
3+
author: 'Gregor Martynus and Parker Brown'
4+
inputs:
5+
app_id:
6+
description: 'GitHub app ID'
7+
required: true
8+
private_key:
9+
description: 'GitHub app private key'
10+
required: true
11+
outputs:
12+
token:
13+
description: 'GitHub installation access token'
14+
runs:
15+
using: 'node16'
16+
main: 'dist/main.cjs'
17+
post: 'dist/post.cjs'

‎dist/main.cjs

+17,888
Large diffs are not rendered by default.

‎dist/post.cjs

+5,950
Large diffs are not rendered by default.

‎lib/main.js

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// @ts-check
2+
3+
import core from "@actions/core";
4+
import { createAppAuth } from "@octokit/auth-app";
5+
import { request } from "@octokit/request";
6+
7+
/**
8+
* @param {string} appId
9+
* @param {string} privateKey
10+
* @param {string} repository
11+
* @param {core} core
12+
* @param {createAppAuth} createAppAuth
13+
* @param {request} request
14+
*/
15+
export async function main(
16+
appId,
17+
privateKey,
18+
repository,
19+
core,
20+
createAppAuth,
21+
request
22+
) {
23+
// Get owner and repo name from GITHUB_REPOSITORY
24+
const [owner, repo] = repository.split("/");
25+
26+
const auth = createAppAuth({
27+
appId,
28+
privateKey,
29+
});
30+
31+
const appAuthentication = await auth({
32+
type: "app",
33+
});
34+
35+
// Get the installation ID
36+
// https://docs.github.com/en/rest/apps/apps?apiVersion=2022-11-28#get-a-repository-installation-for-the-authenticated-app
37+
const { data: installation } = await request(
38+
"GET /repos/{owner}/{repo}/installation",
39+
{
40+
owner,
41+
repo,
42+
headers: {
43+
authorization: `bearer ${appAuthentication.token}`,
44+
},
45+
}
46+
);
47+
48+
// Create a new installation token
49+
const authentication = await auth({
50+
type: "installation",
51+
installationId: installation.id,
52+
repositoryNames: [repo],
53+
});
54+
55+
core.setOutput("token", authentication.token);
56+
57+
// Make token accessible to post function (so we can invalidate it)
58+
core.saveState("token", authentication.token);
59+
}

‎lib/post.js

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// @ts-check
2+
3+
import core from "@actions/core";
4+
import { request } from "@octokit/request";
5+
6+
/**
7+
* @param {core} core
8+
* @param {request} request
9+
*/
10+
export async function post(core, request) {
11+
const token = core.getState("token");
12+
13+
await request("DELETE /installation/token", {
14+
headers: {
15+
authorization: `token ${token}`,
16+
},
17+
});
18+
19+
core.info("Token revoked");
20+
}

‎main.js

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// @ts-check
2+
3+
import core from "@actions/core";
4+
import { createAppAuth } from "@octokit/auth-app";
5+
import { request } from "@octokit/request";
6+
7+
import { main } from "./lib/main.js";
8+
9+
if (!process.env.GITHUB_REPOSITORY) {
10+
throw new Error("GITHUB_REPOSITORY missing, must be set to '<owner>/<repo>'");
11+
}
12+
13+
const appId = core.getInput("app_id");
14+
const privateKey = core.getInput("private_key");
15+
16+
const repository = process.env.GITHUB_REPOSITORY;
17+
18+
main(appId, privateKey, repository, core, createAppAuth, request).catch(
19+
(error) => {
20+
console.error(error);
21+
core.setFailed(error.message);
22+
}
23+
);

‎package-lock.json

+812
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎package.json

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"name": "app-token-action",
3+
"private": true,
4+
"type": "module",
5+
"version": "1.0.0",
6+
"description": "GitHub Action for creating a GitHub App Installation Access Token",
7+
"scripts": {
8+
"build": "esbuild main.js post.js --bundle --outdir=dist --out-extension:.js=.cjs --platform=node --target=node16.16",
9+
"test": "echo \"Error: no test specified\" && exit 1"
10+
},
11+
"license": "MIT",
12+
"dependencies": {
13+
"@actions/core": "^1.10.0",
14+
"@octokit/auth-app": "^4.0.13",
15+
"@octokit/request": "^6.2.5"
16+
},
17+
"devDependencies": {
18+
"dotenv": "^16.0.3",
19+
"esbuild": "^0.17.19"
20+
},
21+
"release": {
22+
"branches": [
23+
"+([0-9]).x",
24+
"main"
25+
]
26+
}
27+
}

‎post.js

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// @ts-check
2+
3+
import core from "@actions/core";
4+
import { request } from "@octokit/request";
5+
6+
import { post } from "./lib/post.js";
7+
8+
post(core, request).catch(
9+
(error) => {
10+
console.error(error);
11+
core.setFailed(error.message);
12+
}
13+
);

0 commit comments

Comments
 (0)
Please sign in to comment.