Skip to content
Draft
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 25 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ GitHub Action for creating a GitHub App installation access token.
In order to use this action, you need to:

1. [Register new GitHub App](https://docs.github.com/apps/creating-github-apps/setting-up-a-github-app/creating-a-github-app).
2. [Store the App's ID or Client ID in your repository environment variables](https://docs.github.com/actions/learn-github-actions/variables#defining-configuration-variables-for-multiple-workflows) (example: `APP_ID`).
2. [Store the App's Client ID in your repository environment variables](https://docs.github.com/actions/learn-github-actions/variables#defining-configuration-variables-for-multiple-workflows) (example: `APP_CLIENT_ID`).
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`).

Pass the App's Client ID using the `client-id` input. The legacy `app-id` input remains available for compatibility, but is deprecated.

> [!IMPORTANT]
> An installation access token expires after 1 hour. Please [see this comment](https://github.com/actions/create-github-app-token/issues/121#issuecomment-2043214796) for alternative approaches if you have long-running processes.

Expand All @@ -31,7 +33,7 @@ jobs:
- uses: actions/create-github-app-token@v3
id: app-token
with:
app-id: ${{ vars.APP_ID }}
client-id: ${{ vars.APP_CLIENT_ID }}
private-key: ${{ secrets.PRIVATE_KEY }}
- uses: ./actions/staging-tests
with:
Expand All @@ -51,7 +53,7 @@ jobs:
id: app-token
with:
# required
app-id: ${{ vars.APP_ID }}
client-id: ${{ vars.APP_CLIENT_ID }}
private-key: ${{ secrets.PRIVATE_KEY }}
- uses: actions/checkout@v6
with:
Expand All @@ -77,7 +79,7 @@ jobs:
id: app-token
with:
# required
app-id: ${{ vars.APP_ID }}
client-id: ${{ vars.APP_CLIENT_ID }}
private-key: ${{ secrets.PRIVATE_KEY }}
- name: Get GitHub App User ID
id: get-user-id
Expand All @@ -102,7 +104,7 @@ jobs:
id: app-token
with:
# required
app-id: ${{ vars.APP_ID }}
client-id: ${{ vars.APP_CLIENT_ID }}
private-key: ${{ secrets.PRIVATE_KEY }}
- name: Get GitHub App User ID
id: get-user-id
Expand Down Expand Up @@ -138,7 +140,7 @@ jobs:
- uses: actions/create-github-app-token@v3
id: app-token
with:
app-id: ${{ vars.APP_ID }}
client-id: ${{ vars.APP_CLIENT_ID }}
private-key: ${{ secrets.PRIVATE_KEY }}
owner: ${{ github.repository_owner }}
- uses: peter-evans/create-or-update-comment@v4
Expand All @@ -160,7 +162,7 @@ jobs:
- uses: actions/create-github-app-token@v3
id: app-token
with:
app-id: ${{ vars.APP_ID }}
client-id: ${{ vars.APP_CLIENT_ID }}
private-key: ${{ secrets.PRIVATE_KEY }}
owner: ${{ github.repository_owner }}
repositories: |
Expand All @@ -185,7 +187,7 @@ jobs:
- uses: actions/create-github-app-token@v3
id: app-token
with:
app-id: ${{ vars.APP_ID }}
client-id: ${{ vars.APP_CLIENT_ID }}
private-key: ${{ secrets.PRIVATE_KEY }}
owner: another-owner
- uses: peter-evans/create-or-update-comment@v4
Expand All @@ -210,7 +212,7 @@ jobs:
- uses: actions/create-github-app-token@v3
id: app-token
with:
app-id: ${{ vars.APP_ID }}
client-id: ${{ vars.APP_CLIENT_ID }}
private-key: ${{ secrets.PRIVATE_KEY }}
owner: ${{ github.repository_owner }}
permission-issues: write
Expand Down Expand Up @@ -252,7 +254,7 @@ jobs:
- uses: actions/create-github-app-token@v3
id: app-token
with:
app-id: ${{ vars.APP_ID }}
client-id: ${{ vars.APP_CLIENT_ID }}
private-key: ${{ secrets.PRIVATE_KEY }}
owner: ${{ matrix.owners-and-repos.owner }}
repositories: ${{ join(matrix.owners-and-repos.repos) }}
Expand Down Expand Up @@ -281,7 +283,7 @@ jobs:
id: create_token
uses: actions/create-github-app-token@v3
with:
app-id: ${{ vars.GHES_APP_ID }}
client-id: ${{ vars.GHES_APP_CLIENT_ID }}
private-key: ${{ secrets.GHES_APP_PRIVATE_KEY }}
owner: ${{ vars.GHES_INSTALLATION_ORG }}
github-api-url: ${{ vars.GITHUB_API_URL }}
Expand Down Expand Up @@ -310,15 +312,24 @@ If you set `HTTP_PROXY` or `HTTPS_PROXY`, also set `NODE_USE_ENV_PROXY: "1"` on
NO_PROXY: github.example.com
NODE_USE_ENV_PROXY: "1"
with:
app-id: ${{ vars.APP_ID }}
client-id: ${{ vars.APP_CLIENT_ID }}
private-key: ${{ secrets.PRIVATE_KEY }}
```

## Inputs

### `client-id`

**Optional:** GitHub App Client ID. This is the recommended input.

### `app-id`

**Required:** GitHub App ID.
**Optional:** GitHub App ID.

> [!WARNING]
> `app-id` is deprecated. Use `client-id` instead.

You must set either `client-id` or `app-id`. If both are set, `client-id` takes precedence.

### `private-key`

Expand All @@ -338,7 +349,7 @@ steps:
id: app-token
uses: actions/create-github-app-token@v3
with:
app-id: ${{ vars.APP_ID }}
client-id: ${{ vars.APP_CLIENT_ID }}
private-key: ${{ steps.decode.outputs.private-key }}
```

Expand Down
6 changes: 5 additions & 1 deletion action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@ branding:
icon: "lock"
color: "gray-dark"
inputs:
client-id:
description: "GitHub App Client ID"
required: false
app-id:
description: "GitHub App ID"
required: true
required: false
deprecationMessage: "Use 'client-id' instead."
private-key:
description: "GitHub App private key"
required: true
Expand Down
5 changes: 4 additions & 1 deletion dist/main.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -23307,7 +23307,10 @@ if (!process.env.GITHUB_REPOSITORY_OWNER) {
}
async function run() {
ensureNativeProxySupport();
const appId = getInput("app-id");
const appId = getInput("client-id") || getInput("app-id");
if (!appId) {
throw new Error("Either 'client-id' or 'app-id' input must be set");
}
const privateKey = getInput("private-key");
const owner = getInput("owner");
const repositories = getInput("repositories").split(/[\n,]+/).map((s) => s.trim()).filter((x) => x !== "");
Expand Down
5 changes: 4 additions & 1 deletion main.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ if (!process.env.GITHUB_REPOSITORY_OWNER) {
async function run() {
ensureNativeProxySupport();

const appId = core.getInput("app-id");
const appId = core.getInput("client-id") || core.getInput("app-id");
if (!appId) {
throw new Error("Either 'client-id' or 'app-id' input must be set");
}
const privateKey = core.getInput("private-key");
const owner = core.getInput("owner");
const repositories = core
Expand Down
2 changes: 1 addition & 1 deletion tests/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,4 @@ node --test --test-update-snapshots tests/index.js
We have tests both for the `main.js` and `post.js` scripts.

- If you do not expect an error, take [main-token-permissions-set.test.js](tests/main-token-permissions-set.test.js) as a starting point.
- If your test has an expected error, take [main-missing-app-id.test.js](tests/main-missing-app-id.test.js) as a starting point.
- If your test has an expected error, take [main-missing-client-and-app-id.test.js](tests/main-missing-client-and-app-id.test.js) as a starting point.
34 changes: 34 additions & 0 deletions tests/index.js.snapshot
Original file line number Diff line number Diff line change
@@ -1,3 +1,24 @@
exports[`action-deprecated-inputs.test.js > stdout 1`] = `
app-id — Use 'client-id' instead.
`;

exports[`main-client-id.test.js > stdout 1`] = `
Inputs 'owner' and 'repositories' are not set. Creating token for this repository (actions/create-github-app-token).
::add-mask::ghs_16C7e42F292c6912E7710c838347Ae178B4a

::set-output name=token::ghs_16C7e42F292c6912E7710c838347Ae178B4a

::set-output name=installation-id::123456

::set-output name=app-slug::github-actions
::save-state name=token::ghs_16C7e42F292c6912E7710c838347Ae178B4a
::save-state name=expiresAt::2016-07-11T22:14:10Z
--- REQUESTS ---
GET /repos/actions/create-github-app-token/installation
POST /app/installations/123456/access_tokens
{"repositories":["create-github-app-token"]}
`;

exports[`main-custom-github-api-url.test.js > stdout 1`] = `
Inputs 'owner' and 'repositories' are set. Creating token for the following repositories:

Expand All @@ -17,6 +38,19 @@ POST /api/v3/app/installations/123456/access_tokens
{"repositories":["create-github-app-token"]}
`;

exports[`main-missing-client-and-app-id.test.js > stderr 1`] = `
Error: Either 'client-id' or 'app-id' input must be set
at run (file:///home/runner/work/create-github-app-token/create-github-app-token/main.js:23:11)
at file:///home/runner/work/create-github-app-token/create-github-app-token/main.js:51:16
 at ModuleJob.run (node:internal/modules/esm/module_job:430:25)
 at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader:661:26)
at async file:///home/runner/work/create-github-app-token/create-github-app-token/tests/main-missing-client-and-app-id.test.js:12:30
`;

exports[`main-missing-client-and-app-id.test.js > stdout 1`] = `
::error::Either 'client-id' or 'app-id' input must be set
`;

exports[`main-missing-owner.test.js > stderr 1`] = `
GITHUB_REPOSITORY_OWNER missing, must be set to '<owner>'
`;
Expand Down
11 changes: 11 additions & 0 deletions tests/main-client-id.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { DEFAULT_ENV, test } from "./main.js";

// Verify `main` accepts a GitHub App client ID via the `client-id` input
await test(
() => {},
{
...DEFAULT_ENV,
"INPUT_CLIENT-ID": "Iv1.0123456789abcdef",
"INPUT_APP-ID": "",
}
);
14 changes: 14 additions & 0 deletions tests/main-missing-client-and-app-id.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { DEFAULT_ENV } from "./main.js";

for (const [key, value] of Object.entries({
...DEFAULT_ENV,
"INPUT_CLIENT-ID": "",
"INPUT_APP-ID": "",
})) {
process.env[key] = value;
}

// Verify `main` exits with an error when neither `client-id` nor `app-id` is set.
const { default: promise } = await import("../main.js");
await promise;
process.exitCode = 0;
Loading