Skip to content

Commit 53ce0ba

Browse files
committed
feat: Add a 'revoke' input for configuring token revocation
1 parent d400084 commit 53ce0ba

File tree

11 files changed

+74
-5
lines changed

11 files changed

+74
-5
lines changed

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,10 @@ jobs:
145145
> [!NOTE]
146146
> 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.
147147

148+
### `revoke`
149+
150+
**Optional:** Whether to revoke the token when the current job is complete. Default: `"true"`.
151+
148152
## Outputs
149153

150154
### `token`
@@ -158,7 +162,7 @@ The action creates an installation access token using [the `POST /app/installati
158162
1. The token is scoped to the current repository or `repositories` if set.
159163
2. The token inherits all the installation's permissions.
160164
3. The token is set as output `token` which can be used in subsequent steps.
161-
4. The token is revoked in the `post` step of the action, which means it cannot be passed to another job.
165+
4. Unless `revoke: "false"` is set, the token is revoked in the `post` step of the action, which means it cannot be passed to another job.
162166
5. The token is masked, it cannot be logged accidentally.
163167

164168
> [!NOTE]

action.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ inputs:
1717
repositories:
1818
description: "Repositories to install the GitHub App on (defaults to current repository if owner is unset)"
1919
required: false
20+
revoke:
21+
description: "Whether to revoke the token when the current job is complete"
22+
required: false
23+
default: "true"
2024
outputs:
2125
token:
2226
description: "GitHub installation access token"

lib/main.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
* @param {import("@actions/core")} core
99
* @param {import("@octokit/auth-app").createAppAuth} createAppAuth
1010
* @param {import("@octokit/request").request} request
11+
* @param {boolean} revoke
1112
*/
1213
export async function main(
1314
appId,
@@ -16,7 +17,8 @@ export async function main(
1617
repositories,
1718
core,
1819
createAppAuth,
19-
request
20+
request,
21+
revoke
2022
) {
2123
let parsedOwner = "";
2224
let parsedRepositoryNames = "";
@@ -122,5 +124,7 @@ export async function main(
122124
core.setOutput("token", authentication.token);
123125

124126
// Make token accessible to post function (so we can invalidate it)
125-
core.saveState("token", authentication.token);
127+
if (revoke) {
128+
core.saveState("token", authentication.token);
129+
}
126130
}

lib/post.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,13 @@
55
* @param {import("@octokit/request").request} request
66
*/
77
export async function post(core, request) {
8+
const revoke = core.getInput("revoke") === "true";
9+
10+
if (!revoke) {
11+
core.info("Token revocation was skipped");
12+
return;
13+
}
14+
815
const token = core.getState("token");
916

1017
if (!token) {

main.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ const privateKey = core.getInput("private_key");
1919
const owner = core.getInput("owner");
2020
const repositories = core.getInput("repositories");
2121

22+
const revoke = core.getInput("revoke") === "true";
23+
2224
main(
2325
appId,
2426
privateKey,
@@ -28,7 +30,8 @@ main(
2830
createAppAuth,
2931
request.defaults({
3032
baseUrl: process.env["GITHUB_API_URL"],
31-
})
33+
}),
34+
revoke
3235
).catch((error) => {
3336
console.error(error);
3437
core.setFailed(error.message);

tests/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Add one test file per scenario. You can run them in isolation with:
66
node tests/post-token-set.test.js
77
```
88

9-
All tests are run together in [tests/index.js](index.js), which can be execauted with ava
9+
All tests are run together in [tests/index.js](index.js), which can be executed with ava
1010

1111
```
1212
npx ava tests/index.js

tests/post-token-set.test.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ import { MockAgent, setGlobalDispatcher } from "undici";
44
// https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#sending-values-to-the-pre-and-post-actions
55
process.env.STATE_token = "secret123";
66

7+
// inputs are set as environment variables with the prefix INPUT_
8+
// https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions#example-specifying-inputs
9+
process.env.INPUT_REVOKE = "true";
10+
711
const mockAgent = new MockAgent();
812

913
setGlobalDispatcher(mockAgent);

tests/post-token-skipped.test.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { MockAgent, setGlobalDispatcher } from "undici";
2+
3+
// state variables are set as environment variables with the prefix STATE_
4+
// https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#sending-values-to-the-pre-and-post-actions
5+
process.env.STATE_token = "secret123";
6+
7+
// inputs are set as environment variables with the prefix INPUT_
8+
// https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions#example-specifying-inputs
9+
process.env.INPUT_REVOKE = "false";
10+
11+
const mockAgent = new MockAgent();
12+
13+
setGlobalDispatcher(mockAgent);
14+
15+
// Provide the base url to the request
16+
const mockPool = mockAgent.get("https://api.github.com");
17+
18+
// intercept the request
19+
mockPool
20+
.intercept({
21+
path: "/installation/token",
22+
method: "DELETE",
23+
headers: {
24+
authorization: "token secret123",
25+
},
26+
})
27+
.reply(204);
28+
29+
await import("../post.js");

tests/post-token-unset.test.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,8 @@
22
// https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#sending-values-to-the-pre-and-post-actions
33
delete process.env.STATE_token;
44

5+
// inputs are set as environment variables with the prefix INPUT_
6+
// https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions#example-specifying-inputs
7+
process.env.INPUT_REVOKE = "true";
8+
59
await import("../post.js");

tests/snapshots/index.js.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,16 @@ Generated by [AVA](https://avajs.dev).
1414
1515
'Token revoked'
1616

17+
## post-token-skipped.test.js
18+
19+
> stderr
20+
21+
''
22+
23+
> stdout
24+
25+
'Token revocation was skipped'
26+
1727
## post-token-unset.test.js
1828

1929
> stderr

tests/snapshots/index.js.snap

31 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)