Skip to content

Commit e8782d6

Browse files
authored
Adding GitHub api url (#14)
* Adding GitHub base API URL support * Updating the ability to inject GitHub API url and expanding tests * Fixing JSON struture for test data
1 parent a4618a9 commit e8782d6

11 files changed

Lines changed: 1593 additions & 137 deletions

.github_application

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,14 @@
77
"repo": "your-repo-name"
88
},
99
"org": "octodemo"
10+
},
11+
"test-ghes": {
12+
"applicationId": 123456,
13+
"privateKey": "-----BEGIN RSA PRIVATE KEY-----\nk3y_g03s_her3\n-----END RSA PRIVATE KEY-----\n",
14+
"repo": {
15+
"owner": "your-org-name",
16+
"repo": "your-repo-name"
17+
},
18+
"org": "octodemo"
1019
}
1120
}

.vscode/launch.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"configurations": [
3+
{
4+
"args": [
5+
"--timeout",
6+
"999999",
7+
"--colors",
8+
"${workspaceFolder}/lib/**.test.js"
9+
],
10+
"internalConsoleOptions": "openOnSessionStart",
11+
"name": "Mocha Tests",
12+
"program": "${workspaceFolder}/node_modules/mocha/bin/_mocha",
13+
"request": "launch",
14+
"skipFiles": [
15+
"<node_internals>/**"
16+
],
17+
"type": "node"
18+
}
19+
]
20+
}

README.md

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,18 @@ Why would you want to do this? Well the `GITHUB_TOKEN` whilst having an expiry,
77
events that prevent downstream GitHub Actions workflow from triggering. This prevents recursive loops from workflows, but
88
there are a number of valid types of workflows that may require or desire triggering downstream GitHub Actions Workflows.
99

10-
The existing way to work around this today is to use a Personal Access Token, but these tokens are tied to a user and
11-
generally are over priviledged for the tasks at hand, increasing the risk if they get exposed and are not time limited
10+
The existing way to work around this today is to use a Personal Access Token, but these tokens are tied to a user and
11+
generally are over priviledged for the tasks at hand, increasing the risk if they get exposed and are not time limited
1212
like the `GITHUB_TOKEN`.
1313

14-
This is where a GitHub Application access token can really help out. The benefits of GitHub Applications is that you can
15-
restrict/scope the access of the token considerably more than what can be achieved using a Personal Access Token. The
14+
This is where a GitHub Application access token can really help out. The benefits of GitHub Applications is that you can
15+
restrict/scope the access of the token considerably more than what can be achieved using a Personal Access Token. The
1616
access token from the GitHub Application is also time limited, expiring after an hour from being issued, providing some
17-
more protection against any leaking of credentials from a Workflow.
17+
more protection against any leaking of credentials from a Workflow.
1818

1919

2020
## Usage
21-
To use this action you first need a GitHub Application created so that you can request temporary credentials on behalf
21+
To use this action you first need a GitHub Application created so that you can request temporary credentials on behalf
2222
of the application inside your workflows.
2323

2424
__Requirements:__
@@ -28,7 +28,7 @@ __Requirements:__
2828

2929

3030
### Creating a GitHub Application
31-
You will need to have a GitHub Application that is scoped with the necessary permissions for the token that you want to
31+
You will need to have a GitHub Application that is scoped with the necessary permissions for the token that you want to
3232
retrieve at runtime.
3333

3434
To create a GitHub Application you can follow the steps available at https://docs.github.com/en/developers/apps/creating-a-github-app
@@ -43,39 +43,40 @@ The important configuration details for the application are:
4343
* `Where can this GitHub App be installed?` should be scoped to your desired audience (the current account, or any account)
4444

4545
Once the application has been created you will be taken to the `General` settings page for the new application.
46-
The GitHub Application will be issued an `App ID` which you can see in the `About` section, take note of this for later
46+
The GitHub Application will be issued an `App ID` which you can see in the `About` section, take note of this for later
4747
use in the Actions workflow.
4848

49-
On the `General` settings page for the application, at the bottom there is a `Private keys` section that you can use to
49+
On the `General` settings page for the application, at the bottom there is a `Private keys` section that you can use to
5050
generate a private key that can be utilized to authenticate as the application.
5151
Generate a new private key and store the information for later use.
5252

5353
_Note: the private keys can and should be rotated periodically to limit the risks of them being exposed in use._
5454

5555

5656
### Install the GitHub Application
57-
Once you have the GitHub Application defined, you will need to install the application on the target organization or repository/
58-
repositories that you want it to have access to. These will be any repositories that you want to gather information
57+
Once you have the GitHub Application defined, you will need to install the application on the target organization or repository/
58+
repositories that you want it to have access to. These will be any repositories that you want to gather information
5959
from or want the application to modify as per the scopes that were defined when the application was installed.
6060

61-
_Note: The GitHub Application will need to be installed on the organization and or repository that you are executing
61+
_Note: The GitHub Application will need to be installed on the organization and or repository that you are executing
6262
the GitHub Actions workflow from, as the implementation requires this to be able to generate the access tokens_.
6363

6464

6565
### Using the GitHub Action in a Workflow
6666

67-
To use the action in a worklow, it is recommended that you store the GitHub Application Private key in GitHub Secrets.
67+
To use the action in a worklow, it is recommended that you store the GitHub Application Private key in GitHub Secrets.
6868
This can be done at a repository or organization level (provided that the actions workflow has access to the secret).
6969

70-
When storing the Private key, you can store the raw PEM encoded certificate contents that the GitHub Application
71-
generates for you or Base64 encode it in the secret.
70+
When storing the Private key, you can store the raw PEM encoded certificate contents that the GitHub Application
71+
generates for you or Base64 encode it in the secret.
7272

7373
#### Parameters
7474

7575
* `application_id`: The GitHub Application ID that you wil be getting the access token for
7676
* `application_private_key`: A private key generated for the GitHub Application so that you can authenticate (PEM format or base64 encoded)
7777
* `permissions`: The optional limited permissions to request, specifying this allows you to request a subset of the permissions for the underlying GitHub Application. Defaults to all permissions available to the GitHub Application when not specified. Must be provided in a comma separated list of token permissions e.g. `issues:read, secrets:write, packages:read`
7878
* `organization`: An optional organization name if the GitHub Application is installed at the Organization level (instead of the repository).
79+
* `github_api_base_url`: An optional URl to the GitHub API, this will be read and loaded from the runner environment by default, but you might be bridging access to a secondary GHES instance or from GHES to GHEC, you can utilize this to make sure the Octokit library is talking to the right GitHub instance.
7980

8081
#### Examples
8182
Get a token with all the permissions of the GitHub Application:
@@ -92,7 +93,7 @@ jobs:
9293
with:
9394
application_id: ${{ secrets.APPLICATION_ID }}
9495
application_private_key: ${{ secrets.APPLICATION_PRIVATE_KEY }}
95-
96+
9697
- name: Use Application Token to create a release
9798
uses: actions/create-release@v1
9899
env:
@@ -116,7 +117,7 @@ jobs:
116117
application_id: ${{ secrets.APPLICATION_ID }}
117118
application_private_key: ${{ secrets.APPLICATION_PRIVATE_KEY }}
118119
permissions: "actions:write"
119-
120+
120121
- name: Use Application Token to create a release
121122
uses: actions/create-release@v1
122123
env:
@@ -140,7 +141,7 @@ jobs:
140141
application_id: ${{ secrets.APPLICATION_ID }}
141142
application_private_key: ${{ secrets.APPLICATION_PRIVATE_KEY }}
142143
organization: octodemo
143-
144+
144145
- name: Use Application Token to create a release
145146
uses: actions/create-release@v1
146147
env:

action.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ inputs:
2121
description: The GitHub Organization to get the application installation for, if not specified will use the current repository instead
2222
required: false
2323

24+
github_api_base_url:
25+
description: The GitHub API base URL to use, no needed it working within the same GitHub instance as the workflow as it will get picked up from the environment
26+
required: false
27+
2428
outputs:
2529
token:
2630
description: A valid token representing the Application that can be used to access what the Application has been scoped to access.

dist/index.js

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

index.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@ async function run() {
88
try {
99
const privateKey = getRequiredInputValue('application_private_key')
1010
, applicationId = getRequiredInputValue('application_id')
11+
, githubApiBaseUrl = core.getInput('github_api_base_url') || process.env['GITHUB_API_URL'] || 'https://api.github.com'
1112
;
12-
app = await githubApplication.create(privateKey, applicationId);
13+
app = await githubApplication.create(privateKey, applicationId, githubApiBaseUrl);
1314
} catch(err) {
1415
fail(err, 'Failed to initialize GitHub Application connection using provided id and private key');
1516
}
@@ -46,7 +47,7 @@ async function run() {
4647
fail(null, `GitHub Application is not installed on repository: ${repository}`);
4748
}
4849
}
49-
50+
5051
if (installationId) {
5152
const permissions = {};
5253
// Build up the list of requested permissions
@@ -67,7 +68,7 @@ async function run() {
6768
core.info(JSON.stringify(accessToken));
6869
core.info(`Successfully generated an access token for application.`)
6970
} else {
70-
fail('No installation of the specified GitHub application was abel to be retrieved');
71+
fail('No installation of the specified GitHub application was able to be retrieved.');
7172
}
7273
} catch (err) {
7374
fail(err);
@@ -78,7 +79,7 @@ run();
7879

7980
function fail(err, message) {
8081
core.error(err);
81-
82+
8283
if (message) {
8384
core.setFailed(message);
8485
} else {

lib/github-application.js

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ const jwt = require('jsonwebtoken')
33
, PrivateKey = require('./private-key')
44
;
55

6-
module.exports.create = (privateKey, applicationId, timeout) => {
7-
const app = new GitHubApplication(privateKey, applicationId);
6+
module.exports.create = (privateKey, applicationId, baseApiUrl, timeout) => {
7+
const app = new GitHubApplication(privateKey, applicationId, baseApiUrl);
88

99
return app.connect(timeout)
1010
.then(() => {
@@ -14,12 +14,13 @@ module.exports.create = (privateKey, applicationId, timeout) => {
1414

1515
class GitHubApplication {
1616

17-
constructor(privateKey, applicationId) {
17+
constructor(privateKey, applicationId, baseApiUrl) {
1818
this._config = {
1919
privateKey: new PrivateKey(_validateVariableValue('privateKey', privateKey)),
2020
id: _validateVariableValue('applicationId', applicationId),
2121
};
2222

23+
this._githubApiUrl = baseApiUrl;
2324
this._client = null;
2425
}
2526

@@ -36,14 +37,19 @@ class GitHubApplication {
3637
};
3738

3839
const token = jwt.sign(payload, this.privateKey, {algorithm: 'RS256'});
39-
this._client = new github.getOctokit(token);
40+
41+
const octokitOptions = {};
42+
if (this.githubApiBaseUrl) {
43+
octokitOptions.baseUrl = this.githubApiBaseUrl;
44+
}
45+
this._client = new github.getOctokit(token, octokitOptions);
4046

4147
return this.client.request('GET /app', {
4248
mediaType: {
4349
previews: ['machine-man']
4450
}
4551
}).catch(err => {
46-
throw new Error(`Failed to connect as application; ${err.message}`);
52+
throw new Error(`Failed to connect as application; status code: ${err.status}\n${err.message}`);
4753
}).then(resp => {
4854
if (resp.status === 200) {
4955
// Store the metadata for debug purposes
@@ -56,6 +62,10 @@ class GitHubApplication {
5662
});
5763
}
5864

65+
get githubApiBaseUrl() {
66+
return this._githubApiUrl;
67+
}
68+
5969
get metadata() {
6070
return this._metadata;
6171
}
@@ -95,8 +105,6 @@ class GitHubApplication {
95105
});
96106
}
97107

98-
//TODO can get other types of app installations too at org and enterprise
99-
100108
getRepositoryInstallation(owner, repo) {
101109
return this.client.rest.apps.getRepoInstallation({
102110
owner: owner,

0 commit comments

Comments
 (0)