Compare commits

..

7 Commits

Author SHA1 Message Date
semantic-release-bot 9d97a4282b build(release): 1.5.0 [skip ci]
# [1.5.0](https://github.com/actions/create-github-app-token/compare/v1.4.0...v1.5.0) (2023-10-06)

### Features

* use dash notation for inputs (deprecates underscore notation) ([#59](https://github.com/actions/create-github-app-token/issues/59)) ([7b1d2ae](https://github.com/actions/create-github-app-token/commit/7b1d2aef87b41884c03f2e69a0a422d5c69c5d72)), closes [#57](https://github.com/actions/create-github-app-token/issues/57) [/github.com/actions/create-github-app-token/issues/57#issuecomment-1751272252](https://github.com//github.com/actions/create-github-app-token/issues/57/issues/issuecomment-1751272252)
2023-10-06 20:42:48 +00:00
Gregor Martynus d21ec768fd ci(release): do not persist credentials when checking out (#62) 2023-10-06 13:42:08 -07:00
Gregor Martynus 998b8757ce ci(release): use local version (#60)
follow up to
https://github.com/actions/create-github-app-token/pull/59#issuecomment-1751353971

---------

Co-authored-by: Parker Brown <17183625+parkerbxyz@users.noreply.github.com>
2023-10-06 13:29:38 -07:00
Parker Brown b94a200224 docs: update skip-token-revoke input name (#61)
This is a quick follow-up to #59. I was mid-review when it merged and
noticed one instance of `skip_token_revoke` in the README that didn't
get changed to `skip-token-revoke`. The PR merged just before I pushed a
commit to fix it.
2023-10-06 13:19:45 -07:00
Clay Miller 7b1d2aef87 feat: use dash notation for inputs (deprecates underscore notation) (#59)
Fixes #57 

This PR implements the 3-step plan proposed by @gr2m in
https://github.com/actions/create-github-app-token/issues/57#issuecomment-1751272252:

> 1. Support both input types
> 2. Log a deprecation warning for the old notation
> 3. Add a test for deprecations

Although this PR supports both input formats simultaneously, I opted
_not_ to document the old format in the updated README. That’s a
decision I’m happy to revisit, if y’all would prefer to have
documentation for both the old and new formats.
2023-10-06 13:10:49 -07:00
Gregor Martynus bdb2377ad0 test: add coverage (#58) 2023-10-06 12:54:48 -07:00
Clay Miller 9b283559f1 test: integration tests for main.js (#56)
Part of https://github.com/actions/create-github-app-token/issues/43

This PR adds tests for
[`main.js`](https://github.com/actions/create-github-app-token/blob/main/lib/main.js),
similar to [the tests that already exist for
`post.js`](https://github.com/actions/create-github-app-token/tree/main/tests).

Specifically, it tests that:
- `main` exits with an error when `GITHUB_REPOSITORY` is missing.
- `main` exits with an error when `GITHUB_REPOSITORY_OWNER` is missing.
- `main` successfully obtains a token when…
- …the `owner` and `repositories` inputs are set (and the latter is a
single repo).
- …the `owner` and `repositories` inputs are set (and the latter is a
list of repos).
- …the `owner` input is set (to an org), but the `repositories` input
isn’t set.
- …the `owner` input is set (to a user), but the `repositories` input
isn’t set.
  - …the `owner` input is not set, but the `repositories` input is set.
  - …neither the `owner` nor `repositories` input is set.

❧

Architecturally, in order to keep individual tests concise, this PR adds
`tests/main.js`, which:
- sets commonly-used inputs, environment variables, and mocks, then
- calls a callback function that can edit the variables and add
additional mocks, then
- runs `main.js` itself.

The `tests/main-token-get-*.test.js` test files run `tests/main.js` with
various scenario-specific callback functions.
2023-10-06 12:39:35 -07:00
29 changed files with 2170 additions and 43 deletions
+14 -7
View File
@@ -14,16 +14,23 @@ jobs:
name: release
runs-on: ubuntu-latest
steps:
- uses: actions/create-github-app-token@v1
id: app-token
with:
app_id: ${{ vars.RELEASER_APP_ID }}
private_key: ${{ secrets.RELEASER_APP_PRIVATE_KEY }}
# build local version to create token
- uses: actions/checkout@v4
with:
token: ${{ steps.app-token.outputs.token }}
- run: npm install --no-save @semantic-release/git semantic-release-plugin-github-breaking-version-tag
persist-credentials: false
- uses: actions/setup-node@v3
with:
node-version: 20
cache: "npm"
- run: npm ci
- run: npm run build
- uses: ./
id: app-token
with:
app-id: ${{ vars.RELEASER_APP_ID }}
private-key: ${{ secrets.RELEASER_APP_PRIVATE_KEY }}
# install release dependencies and release
- run: npm install --no-save @semantic-release/git semantic-release-plugin-github-breaking-version-tag
- run: npx semantic-release --debug
env:
GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}
+2 -2
View File
@@ -38,8 +38,8 @@ jobs:
- uses: ./ # Uses the action in the root directory
id: test
with:
app_id: ${{ vars.TEST_APP_ID }}
private_key: ${{ secrets.TEST_APP_PRIVATE_KEY }}
app-id: ${{ vars.TEST_APP_ID }}
private-key: ${{ secrets.TEST_APP_PRIVATE_KEY }}
- uses: octokit/request-action@v2.x
id: get-repository
env:
+2 -1
View File
@@ -1,2 +1,3 @@
node_modules/
.env
coverage
node_modules/
+14 -14
View File
@@ -22,8 +22,8 @@ jobs:
- uses: actions/create-github-app-token@v1
id: app-token
with:
app_id: ${{ vars.APP_ID }}
private_key: ${{ secrets.PRIVATE_KEY }}
app-id: ${{ vars.APP_ID }}
private-key: ${{ secrets.PRIVATE_KEY }}
- uses: peter-evans/create-or-update-comment@v3
with:
token: ${{ steps.app-token.outputs.token }}
@@ -44,8 +44,8 @@ jobs:
id: app-token
with:
# required
app_id: ${{ vars.APP_ID }}
private_key: ${{ secrets.PRIVATE_KEY }}
app-id: ${{ vars.APP_ID }}
private-key: ${{ secrets.PRIVATE_KEY }}
- uses: actions/checkout@v3
with:
token: ${{ steps.app-token.outputs.token }}
@@ -69,8 +69,8 @@ jobs:
- uses: actions/create-github-app-token@v1
id: app-token
with:
app_id: ${{ vars.APP_ID }}
private_key: ${{ secrets.PRIVATE_KEY }}
app-id: ${{ vars.APP_ID }}
private-key: ${{ secrets.PRIVATE_KEY }}
owner: ${{ github.repository_owner }}
- uses: peter-evans/create-or-update-comment@v3
with:
@@ -91,8 +91,8 @@ jobs:
- uses: actions/create-github-app-token@v1
id: app-token
with:
app_id: ${{ vars.APP_ID }}
private_key: ${{ secrets.PRIVATE_KEY }}
app-id: ${{ vars.APP_ID }}
private-key: ${{ secrets.PRIVATE_KEY }}
owner: ${{ github.repository_owner }}
repositories: "repo1,repo2"
- uses: peter-evans/create-or-update-comment@v3
@@ -114,8 +114,8 @@ jobs:
- uses: actions/create-github-app-token@v1
id: app-token
with:
app_id: ${{ vars.APP_ID }}
private_key: ${{ secrets.PRIVATE_KEY }}
app-id: ${{ vars.APP_ID }}
private-key: ${{ secrets.PRIVATE_KEY }}
owner: another-owner
- uses: peter-evans/create-or-update-comment@v3
with:
@@ -126,11 +126,11 @@ jobs:
## Inputs
### `app_id`
### `app-id`
**Required:** GitHub App ID.
### `private_key`
### `private-key`
**Required:** GitHub App private key.
@@ -145,7 +145,7 @@ jobs:
> [!NOTE]
> If `owner` is set and `repositories` is empty, access will be scoped to all repositories in the provided repository owner's installation. If `owner` and `repositories` are empty, access will be scoped to only the current repository.
### `skip_token_revoke`
### `skip-token-revoke`
**Optional:** If truthy, the token will not be revoked when the current job is complete.
@@ -162,7 +162,7 @@ The action creates an installation access token using [the `POST /app/installati
1. The token is scoped to the current repository or `repositories` if set.
2. The token inherits all the installation's permissions.
3. The token is set as output `token` which can be used in subsequent steps.
4. Unless the `skip_token_revoke` input is set to a truthy value, the token is revoked in the `post` step of the action, which means it cannot be passed to another job.
4. Unless the `skip-token-revoke` input is set to a truthy value, the token is revoked in the `post` step of the action, which means it cannot be passed to another job.
5. The token is masked, it cannot be logged accidentally.
> [!NOTE]
+14 -2
View File
@@ -5,21 +5,33 @@ branding:
icon: "lock"
color: "gray-dark"
inputs:
app-id:
description: "GitHub App ID"
required: false # TODO: When 'app_id' is removed, make 'app-id' required
app_id:
description: "GitHub App ID"
required: true
required: false
deprecationMessage: "'app_id' is deprecated and will be removed in a future version. Use 'app-id' instead."
private-key:
description: "GitHub App private key"
required: false # TODO: When 'private_key' is removed, make 'private-key' required
private_key:
description: "GitHub App private key"
required: true
required: false
deprecationMessage: "'private_key' is deprecated and will be removed in a future version. Use 'private-key' instead."
owner:
description: "GitHub App owner (defaults to current repository owner)"
required: false
repositories:
description: "Repositories to install the GitHub App on (defaults to current repository if owner is unset)"
required: false
skip-token-revoke:
description: "If truthy, the token will not be revoked when the current job is complete"
required: false
skip_token_revoke:
description: "If truthy, the token will not be revoked when the current job is complete"
required: false
deprecationMessage: "'skip_token_revoke' is deprecated and will be removed in a future version. Use 'skip-token-revoke' instead."
outputs:
token:
description: "GitHub installation access token"
+11 -3
View File
@@ -10103,11 +10103,19 @@ if (!process.env.GITHUB_REPOSITORY) {
if (!process.env.GITHUB_REPOSITORY_OWNER) {
throw new Error("GITHUB_REPOSITORY_OWNER missing, must be set to '<owner>'");
}
var appId = import_core.default.getInput("app_id");
var privateKey = import_core.default.getInput("private_key");
var appId = import_core.default.getInput("app-id") || import_core.default.getInput("app_id");
if (!appId) {
throw new Error("Input required and not supplied: app-id");
}
var privateKey = import_core.default.getInput("private-key") || import_core.default.getInput("private_key");
if (!privateKey) {
throw new Error("Input required and not supplied: private-key");
}
var owner = import_core.default.getInput("owner");
var repositories = import_core.default.getInput("repositories");
var skipTokenRevoke = Boolean(import_core.default.getInput("skip_token_revoke"));
var skipTokenRevoke = Boolean(
import_core.default.getInput("skip-token-revoke") || import_core.default.getInput("skip_token_revoke")
);
main(
appId,
privateKey,
+3 -1
View File
@@ -2973,7 +2973,9 @@ var import_core = __toESM(require_core(), 1);
// lib/post.js
async function post(core2, request2) {
const skipTokenRevoke = Boolean(core2.getInput("skip_token_revoke"));
const skipTokenRevoke = Boolean(
core2.getInput("skip-token-revoke") || core2.getInput("skip_token_revoke")
);
if (skipTokenRevoke) {
core2.info("Token revocation was skipped");
return;
+2 -1
View File
@@ -100,6 +100,7 @@ export async function main(
authorization: `bearer ${appAuthentication.token}`,
},
}).catch((error) => {
/* c8 ignore next */
if (error.status !== 404) throw error;
// https://docs.github.com/rest/apps/apps?apiVersion=2022-11-28#get-a-user-installation-for-the-authenticated-app
@@ -122,7 +123,7 @@ export async function main(
core.setSecret(authentication.token);
core.setOutput("token", authentication.token);
// Make token accessible to post function (so we can invalidate it)
if (!skipTokenRevoke) {
core.saveState("token", authentication.token);
+3 -1
View File
@@ -5,7 +5,9 @@
* @param {import("@octokit/request").request} request
*/
export async function post(core, request) {
const skipTokenRevoke = Boolean(core.getInput("skip_token_revoke"));
const skipTokenRevoke = Boolean(
core.getInput("skip-token-revoke") || core.getInput("skip_token_revoke")
);
if (skipTokenRevoke) {
core.info("Token revocation was skipped");
+14 -3
View File
@@ -14,12 +14,22 @@ if (!process.env.GITHUB_REPOSITORY_OWNER) {
throw new Error("GITHUB_REPOSITORY_OWNER missing, must be set to '<owner>'");
}
const appId = core.getInput("app_id");
const privateKey = core.getInput("private_key");
const appId = core.getInput("app-id") || core.getInput("app_id");
if (!appId) {
// The 'app_id' input was previously required, but it and 'app-id' are both optional now, until the former is removed. Still, we want to ensure that at least one of them is set.
throw new Error("Input required and not supplied: app-id");
}
const privateKey = core.getInput("private-key") || core.getInput("private_key");
if (!privateKey) {
// The 'private_key' input was previously required, but it and 'private-key' are both optional now, until the former is removed. Still, we want to ensure that at least one of them is set.
throw new Error("Input required and not supplied: private-key");
}
const owner = core.getInput("owner");
const repositories = core.getInput("repositories");
const skipTokenRevoke = Boolean(core.getInput("skip_token_revoke"));
const skipTokenRevoke = Boolean(
core.getInput("skip-token-revoke") || core.getInput("skip_token_revoke")
);
main(
appId,
@@ -33,6 +43,7 @@ main(
}),
skipTokenRevoke
).catch((error) => {
/* c8 ignore next 3 */
console.error(error);
core.setFailed(error.message);
});
+1684 -3
View File
File diff suppressed because it is too large Load Diff
+8 -3
View File
@@ -2,11 +2,13 @@
"name": "create-github-app-token",
"private": true,
"type": "module",
"version": "1.4.0",
"version": "1.5.0",
"description": "GitHub Action for creating a GitHub App Installation Access Token",
"scripts": {
"build": "esbuild main.js post.js --bundle --outdir=dist --out-extension:.js=.cjs --platform=node --target=node16.16",
"test": "ava tests/index.js"
"test": "c8 --100 ava tests/index.js",
"coverage": "c8 report --reporter html",
"postcoverage": "open-cli coverage/index.html"
},
"license": "MIT",
"dependencies": {
@@ -16,10 +18,13 @@
},
"devDependencies": {
"ava": "^5.3.1",
"c8": "^8.0.1",
"dotenv": "^16.3.1",
"esbuild": "^0.19.4",
"execa": "^8.0.1",
"undici": "^5.25.2"
"open-cli": "^7.2.0",
"undici": "^5.25.2",
"yaml": "^2.3.2"
},
"release": {
"branches": [
+1
View File
@@ -11,6 +11,7 @@ post(
baseUrl: process.env["GITHUB_API_URL"],
})
).catch((error) => {
/* c8 ignore next 3 */
console.error(error);
core.setFailed(error.message);
});
+16
View File
@@ -0,0 +1,16 @@
import { readFileSync } from "node:fs";
import * as url from "node:url";
import YAML from "yaml";
const action = YAML.parse(
readFileSync(
url.fileURLToPath(new URL("../action.yml", import.meta.url)),
"utf8"
)
);
for (const [key, value] of Object.entries(action.inputs)) {
if ("deprecationMessage" in value) {
console.log(`${key}${value.deprecationMessage}`);
}
}
+6 -1
View File
@@ -7,7 +7,12 @@ const tests = readdirSync("tests").filter((file) => file.endsWith(".test.js"));
for (const file of tests) {
test(file, async (t) => {
const { stderr, stdout } = await execa("node", [`tests/${file}`]);
// Override Actions environment variables that change `core`s behavior
const env = {
GITHUB_OUTPUT: undefined,
GITHUB_STATE: undefined,
};
const { stderr, stdout } = await execa("node", [`tests/${file}`], { env });
t.snapshot(stderr, "stderr");
t.snapshot(stdout, "stdout");
});
+9
View File
@@ -0,0 +1,9 @@
process.env.GITHUB_REPOSITORY_OWNER = "actions";
process.env.GITHUB_REPOSITORY = "actions/create-github-app-token";
// Verify `main` exits with an error when neither the `app-id` nor `app_id` input is set.
try {
await import("../main.js");
} catch (error) {
console.error(error.message);
}
+9
View File
@@ -0,0 +1,9 @@
process.env.GITHUB_REPOSITORY = "actions/create-github-app-token";
delete process.env.GITHUB_REPOSITORY_OWNER;
// Verify `main` exits with an error when `GITHUB_REPOSITORY_OWNER` is missing.
try {
await import("../main.js");
} catch (error) {
console.error(error.message);
}
+10
View File
@@ -0,0 +1,10 @@
process.env.GITHUB_REPOSITORY_OWNER = "actions";
process.env.GITHUB_REPOSITORY = "actions/create-github-app-token";
process.env["INPUT_APP-ID"] = "123456";
// Verify `main` exits with an error when neither the `private-key` nor `private_key` input is set.
try {
await import("../main.js");
} catch (error) {
console.error(error.message);
}
+8
View File
@@ -0,0 +1,8 @@
delete process.env.GITHUB_REPOSITORY;
// Verify `main` exits with an error when `GITHUB_REPOSITORY` is missing.
try {
await import("../main.js");
} catch (error) {
console.error(error.message);
}
@@ -0,0 +1,7 @@
import { test } from "./main.js";
// Verify `main` successfully obtains a token when the `owner` and `repositories` inputs are set (and the latter is a list of repos).
await test(() => {
process.env.INPUT_OWNER = process.env.GITHUB_REPOSITORY_OWNER;
process.env.INPUT_REPOSITORIES = `${process.env.GITHUB_REPOSITORY},actions/toolkit`;
});
@@ -0,0 +1,7 @@
import { test } from "./main.js";
// Verify `main` successfully obtains a token when the `owner` and `repositories` inputs are set (and the latter is a single repo).
await test(() => {
process.env.INPUT_OWNER = process.env.GITHUB_REPOSITORY_OWNER;
process.env.INPUT_REPOSITORIES = process.env.GITHUB_REPOSITORY;
});
@@ -0,0 +1,25 @@
import { test } from "./main.js";
// Verify `main` successfully obtains a token when the `owner` input is set (to an org), but the `repositories` input isnt set.
await test((mockPool) => {
process.env.INPUT_OWNER = process.env.GITHUB_REPOSITORY_OWNER;
delete process.env.INPUT_REPOSITORIES;
// Mock installation id request
const mockInstallationId = "123456";
mockPool
.intercept({
path: `/orgs/${process.env.INPUT_OWNER}/installation`,
method: "GET",
headers: {
accept: "application/vnd.github.v3+json",
"user-agent": "actions/create-github-app-token",
// Intentionally omitting the `authorization` header, since JWT creation is not idempotent.
},
})
.reply(
200,
{ id: mockInstallationId },
{ headers: { "content-type": "application/json" } }
);
});
@@ -0,0 +1,36 @@
import { test } from "./main.js";
// Verify `main` successfully obtains a token when the `owner` input is set (to a user), but the `repositories` input isnt set.
await test((mockPool) => {
process.env.INPUT_OWNER = "smockle";
delete process.env.INPUT_REPOSITORIES;
// Mock installation id request
const mockInstallationId = "123456";
mockPool
.intercept({
path: `/orgs/${process.env.INPUT_OWNER}/installation`,
method: "GET",
headers: {
accept: "application/vnd.github.v3+json",
"user-agent": "actions/create-github-app-token",
// Intentionally omitting the `authorization` header, since JWT creation is not idempotent.
},
})
.reply(404);
mockPool
.intercept({
path: `/users/${process.env.INPUT_OWNER}/installation`,
method: "GET",
headers: {
accept: "application/vnd.github.v3+json",
"user-agent": "actions/create-github-app-token",
// Intentionally omitting the `authorization` header, since JWT creation is not idempotent.
},
})
.reply(
200,
{ id: mockInstallationId },
{ headers: { "content-type": "application/json" } }
);
});
@@ -0,0 +1,7 @@
import { test } from "./main.js";
// Verify `main` successfully obtains a token when the `owner` input is not set, but the `repositories` input is set.
await test(() => {
delete process.env.INPUT_OWNER;
process.env.INPUT_REPOSITORIES = process.env.GITHUB_REPOSITORY;
});
@@ -0,0 +1,25 @@
import { test } from "./main.js";
// Verify `main` successfully obtains a token when neither the `owner` nor `repositories` input is set.
await test((mockPool) => {
delete process.env.INPUT_OWNER;
delete process.env.INPUT_REPOSITORIES;
// Mock installation id request
const mockInstallationId = "123456";
mockPool
.intercept({
path: `/repos/${process.env.GITHUB_REPOSITORY}/installation`,
method: "GET",
headers: {
accept: "application/vnd.github.v3+json",
"user-agent": "actions/create-github-app-token",
// Intentionally omitting the `authorization` header, since JWT creation is not idempotent.
},
})
.reply(
200,
{ id: mockInstallationId },
{ headers: { "content-type": "application/json" } }
);
});
+96
View File
@@ -0,0 +1,96 @@
// Base for all `main` tests.
// @ts-check
import { MockAgent, setGlobalDispatcher } from "undici";
export async function test(cb = (_mockPool) => {}) {
// Set required environment variables and inputs
process.env.GITHUB_REPOSITORY_OWNER = "actions";
process.env.GITHUB_REPOSITORY = "actions/create-github-app-token";
// inputs are set as environment variables with the prefix INPUT_
// https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions#example-specifying-inputs
process.env["INPUT_APP-ID"] = "123456";
process.env["INPUT_PRIVATE-KEY"] = `-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA280nfuUM9w00Ib9E2rvZJ6Qu3Ua3IqR34ZlK53vn/Iobn2EL
Z9puc5Q/nFBU15NKwHyQNb+OG2hTCkjd1Xi9XPzEOH1r42YQmTGq8YCkUSkk6KZA
5dnhLwN9pFquT9fQgrf4r1D5GJj3rqvj8JDr1sBmunArqY5u4gziSrIohcjLIZV0
cIMz/RUIMe/EAsNeiwzEteHAtf/WpMs+OfF94SIUrDlkPr0H0H3DER8l1HZAvE0e
eD3ZJ6njrF6UHQWDVrekSTB0clpVTTU9TMpe+gs2nnFww9G8As+WsW8xHVjVipJy
AwqBhiR+s7wlcbh2i0NQqt8GL9/jIFTmleiwsQIDAQABAoIBAHNyP8pgl/yyzKzk
/0871wUBMTQ7zji91dGCaFtJM0HrcDK4D/uOOPEv7nE1qDpKPLr5Me1pHUS7+NGw
EAPtlNhgUtew2JfppdIwyi5qeOPADoi7ud6AH8xHsxg+IMwC+JuP8WhzyUHoJj9y
PRi/pX94Mvy9qdE25HqKddjx1mLdaHhxqPkr16/em23uYZqm1lORsCPD3vTlthj7
WiEbBSqmpYvjj8iFP4yFk2N+LvuWgSilRzq1Af3qE7PUp4xhjmcOPs78Sag1T7nl
ww/pgqCegISABHik7j++/5T+UlI5cLsyp/XENU9zAd4kCIczwNKpun2bn+djJdft
ravyX4ECgYEA+k2mHfi1zwKF3wT+cJbf30+uXrJczK2yZ33//4RKnhBaq7nSbQAI
nhWz2JESBK0TEo0+L7yYYq3HnT9vcES5R1NxzruH9wXgxssSx3JUj6w1raXYPh3B
+1XpYQsa6/bo2LmBELEx47F8FQbNgD5dmTJ4jBrf6MV4rRh9h6Bs7UkCgYEA4M3K
eAw52c2MNMIxH/LxdOQtEBq5GMu3AQC8I64DSSRrAoiypfEgyTV6S4gWJ5TKgYfD
zclnOVJF+tITe3neO9wHoZp8iCjCnoijcT6p2cJ4IaW68LEHPOokWBk0EpLjF4p2
7sFi9+lUpXYXfCN7aMJ77QpGzB7dNsBf0KUxMCkCgYEAjw/mjGbk82bLwUaHby6s
0mQmk7V6WPpGZ+Sadx7TzzglutVAslA8nK5m1rdEBywtJINaMcqnhm8xEm15cj+1
blEBUVnaQpQ3fyf+mcR9FIknPRL3X7l+b/sQowjH4GqFd6m/XR0KGMwO0a3Lsyry
MGeqgtmxdMe5S6YdyXEmERECgYAgQsgklDSVIh9Vzux31kh6auhgoEUh3tJDbZSS
Vj2YeIZ21aE1mTYISglj34K2aW7qSc56sMWEf18VkKJFHQccdgYOVfo7HAZZ8+fo
r4J2gqb0xTDfq7gLMNrIXc2QQM4gKbnJp60JQM3p9NmH8huavBZGvSvNzTwXyGG3
so0tiQKBgGQXZaxaXhYUcxYHuCkQ3V4Vsj3ezlM92xXlP32SGFm3KgFhYy9kATxw
Cax1ytZzvlrKLQyQFVK1COs2rHt7W4cJ7op7C8zXfsigXCiejnS664oAuX8sQZID
x3WQZRiXlWejSMUAHuMwXrhGlltF3lw83+xAjnqsVp75kGS6OH61
-----END RSA PRIVATE KEY-----`; // This key is invalidated. Its from https://github.com/octokit/auth-app.js/issues/465#issuecomment-1564998327.
// Set up mocking
const mockAgent = new MockAgent();
mockAgent.disableNetConnect();
setGlobalDispatcher(mockAgent);
const mockPool = mockAgent.get("https://api.github.com");
// Calling `auth({ type: "app" })` to obtain a JWT doesnt make network requests, so no need to intercept.
// Mock installation id request
const mockInstallationId = "123456";
const owner = process.env.INPUT_OWNER ?? process.env.GITHUB_REPOSITORY_OWNER;
const repo = encodeURIComponent(
(process.env.INPUT_REPOSITORIES ?? process.env.GITHUB_REPOSITORY).split(
","
)[0]
);
mockPool
.intercept({
path: `/repos/${owner}/${repo}/installation`,
method: "GET",
headers: {
accept: "application/vnd.github.v3+json",
"user-agent": "actions/create-github-app-token",
// Intentionally omitting the `authorization` header, since JWT creation is not idempotent.
},
})
.reply(
200,
{ id: mockInstallationId },
{ headers: { "content-type": "application/json" } }
);
// Mock installation access token request
const mockInstallationAccessToken =
"ghs_16C7e42F292c6912E7710c838347Ae178B4a"; // This token is invalidated. Its from https://docs.github.com/en/rest/apps/apps?apiVersion=2022-11-28#create-an-installation-access-token-for-an-app.
mockPool
.intercept({
path: `/app/installations/${mockInstallationId}/access_tokens`,
method: "POST",
headers: {
accept: "application/vnd.github.v3+json",
"user-agent": "actions/create-github-app-token",
// Note: Intentionally omitting the `authorization` header, since JWT creation is not idempotent.
},
})
.reply(
201,
{ token: mockInstallationAccessToken },
{ headers: { "content-type": "application/json" } }
);
// Run the callback
cb(mockPool);
// Run the main script
await import("../main.js");
}
+1 -1
View File
@@ -6,7 +6,7 @@ process.env.STATE_token = "secret123";
// inputs are set as environment variables with the prefix INPUT_
// https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions#example-specifying-inputs
process.env.INPUT_SKIP_TOKEN_REVOKE = "true";
process.env["INPUT_SKIP-TOKEN-REVOKE"] = "true";
const mockAgent = new MockAgent();
+136
View File
@@ -4,6 +4,142 @@ The actual snapshot is saved in `index.js.snap`.
Generated by [AVA](https://avajs.dev).
## action-deprecated-inputs.test.js
> stderr
''
> stdout
`app_id — 'app_id' is deprecated and will be removed in a future version. Use 'app-id' instead.␊
private_key — 'private_key' is deprecated and will be removed in a future version. Use 'private-key' instead.␊
skip_token_revoke — 'skip_token_revoke' is deprecated and will be removed in a future version. Use 'skip-token-revoke' instead.`
## main-missing-app-id.test.js
> stderr
'Input required and not supplied: app-id'
> stdout
''
## main-missing-owner.test.js
> stderr
'GITHUB_REPOSITORY_OWNER missing, must be set to \'<owner>\''
> stdout
''
## main-missing-private-key.test.js
> stderr
'Input required and not supplied: private-key'
> stdout
''
## main-missing-repository.test.js
> stderr
'GITHUB_REPOSITORY missing, must be set to \'<owner>/<repo>\''
> stdout
''
## main-token-get-owner-set-repo-set-to-many.test.js
> stderr
''
> stdout
`owner and repositories set, creating token for repositories "actions/create-github-app-token,actions/toolkit" owned by "actions"␊
::add-mask::ghs_16C7e42F292c6912E7710c838347Ae178B4a␊
::set-output name=token::ghs_16C7e42F292c6912E7710c838347Ae178B4a␊
::save-state name=token::ghs_16C7e42F292c6912E7710c838347Ae178B4a`
## main-token-get-owner-set-repo-set-to-one.test.js
> stderr
''
> stdout
`owner and repositories set, creating token for repositories "actions/create-github-app-token" owned by "actions"␊
::add-mask::ghs_16C7e42F292c6912E7710c838347Ae178B4a␊
::set-output name=token::ghs_16C7e42F292c6912E7710c838347Ae178B4a␊
::save-state name=token::ghs_16C7e42F292c6912E7710c838347Ae178B4a`
## main-token-get-owner-set-to-org-repo-unset.test.js
> stderr
''
> stdout
`repositories not set, creating token for all repositories for given owner "actions"␊
::add-mask::ghs_16C7e42F292c6912E7710c838347Ae178B4a␊
::set-output name=token::ghs_16C7e42F292c6912E7710c838347Ae178B4a␊
::save-state name=token::ghs_16C7e42F292c6912E7710c838347Ae178B4a`
## main-token-get-owner-set-to-user-repo-unset.test.js
> stderr
''
> stdout
`repositories not set, creating token for all repositories for given owner "smockle"␊
::add-mask::ghs_16C7e42F292c6912E7710c838347Ae178B4a␊
::set-output name=token::ghs_16C7e42F292c6912E7710c838347Ae178B4a␊
::save-state name=token::ghs_16C7e42F292c6912E7710c838347Ae178B4a`
## main-token-get-owner-unset-repo-set.test.js
> stderr
''
> stdout
`owner not set, creating owner for given repositories "actions/create-github-app-token" in current owner ("actions")␊
::add-mask::ghs_16C7e42F292c6912E7710c838347Ae178B4a␊
::set-output name=token::ghs_16C7e42F292c6912E7710c838347Ae178B4a␊
::save-state name=token::ghs_16C7e42F292c6912E7710c838347Ae178B4a`
## main-token-get-owner-unset-repo-unset.test.js
> stderr
''
> stdout
`owner and repositories not set, creating token for the current repository ("create-github-app-token")␊
::add-mask::ghs_16C7e42F292c6912E7710c838347Ae178B4a␊
::set-output name=token::ghs_16C7e42F292c6912E7710c838347Ae178B4a␊
::save-state name=token::ghs_16C7e42F292c6912E7710c838347Ae178B4a`
## post-token-set.test.js
> stderr
Binary file not shown.