Skip to content

Commit 4451bcb

Browse files
committed
fix!: require NODE_USE_ENV_PROXY for proxy support (#342)
BREAKING CHANGE: Custom proxy handling has been removed. If you use HTTP_PROXY or HTTPS_PROXY, you must now also set NODE_USE_ENV_PROXY=1 on the action step.
1 parent dce0ab0 commit 4451bcb

File tree

10 files changed

+163
-27
lines changed

10 files changed

+163
-27
lines changed

.github/workflows/test.yml

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ on:
44
push:
55
branches:
66
- main
7+
- beta
78
pull_request:
89
merge_group:
910
workflow_dispatch:
@@ -33,7 +34,7 @@ jobs:
3334
name: end-to-end
3435
runs-on: ubuntu-latest
3536
# do not run from forks, as forks don’t have access to repository secrets
36-
if: github.event_name == 'merge_group' || github.event.pull_request.head.repo.owner.login == github.event.pull_request.base.repo.owner.login
37+
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.owner.login == github.event.pull_request.base.repo.owner.login
3738
steps:
3839
- uses: actions/checkout@v6
3940
- uses: actions/setup-node@v6
@@ -53,3 +54,28 @@ jobs:
5354
with:
5455
route: GET /installation/repositories
5556
- run: echo '${{ steps.get-repository.outputs.data }}'
57+
58+
end-to-end-proxy:
59+
name: End-to-End with unreachable proxy
60+
runs-on: ubuntu-latest
61+
# do not run from forks, as forks don’t have access to repository secrets
62+
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.owner.login == github.event.pull_request.base.repo.owner.login
63+
steps:
64+
- uses: actions/checkout@v5
65+
- uses: actions/setup-node@v4
66+
with:
67+
node-version-file: package.json
68+
cache: 'npm'
69+
- run: npm ci
70+
- run: npm run build
71+
- uses: ./ # Uses the action in the root directory
72+
continue-on-error: true
73+
id: test
74+
env:
75+
NODE_USE_ENV_PROXY: "1"
76+
https_proxy: http://127.0.0.1:9
77+
with:
78+
app-id: ${{ vars.TEST_APP_ID }}
79+
private-key: ${{ secrets.TEST_APP_PRIVATE_KEY }}
80+
- name: Assert action failed through unreachable proxy
81+
run: test "${{ steps.test.outcome }}" = "failure"

README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,24 @@ jobs:
296296
GITHUB_TOKEN: ${{ steps.create_token.outputs.token }}
297297
```
298298

299+
### Proxy support
300+
301+
This action relies on Node.js native proxy support.
302+
303+
If you set `HTTP_PROXY` or `HTTPS_PROXY`, also set `NODE_USE_ENV_PROXY: "1"` on the action step so Node.js honors those variables. If you need proxy bypass rules, set `NO_PROXY` alongside them.
304+
305+
```yaml
306+
- uses: actions/create-github-app-token@v3
307+
id: app-token
308+
env:
309+
HTTPS_PROXY: http://proxy.example.com:8080
310+
NO_PROXY: github.example.com
311+
NODE_USE_ENV_PROXY: "1"
312+
with:
313+
app-id: ${{ vars.APP_ID }}
314+
private-key: ${{ secrets.PRIVATE_KEY }}
315+
```
316+
299317
## Inputs
300318

301319
### `app-id`

lib/request.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,31 @@ import { request } from "@octokit/request";
44
// Get the GitHub API URL from the action input and remove any trailing slash
55
const baseUrl = core.getInput("github-api-url").replace(/\/$/, "");
66

7+
const proxyEnvironmentKeys = [
8+
"https_proxy",
9+
"HTTPS_PROXY",
10+
"http_proxy",
11+
"HTTP_PROXY",
12+
];
13+
14+
function proxyEnvironmentConfigured() {
15+
return proxyEnvironmentKeys.some((key) => process.env[key]);
16+
}
17+
18+
function nativeProxySupportEnabled() {
19+
return process.env.NODE_USE_ENV_PROXY === "1";
20+
}
21+
22+
export function ensureNativeProxySupport() {
23+
if (!proxyEnvironmentConfigured() || nativeProxySupportEnabled()) {
24+
return;
25+
}
26+
27+
throw new Error(
28+
"A proxy environment variable is set, but Node.js native proxy support is not enabled. Set NODE_USE_ENV_PROXY=1 for this action step.",
29+
);
30+
}
31+
732
// Configure the default settings for GitHub API requests
833
export default request.defaults({
934
headers: { "user-agent": "actions/create-github-app-token" },

main.js

Lines changed: 30 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { createAppAuth } from "@octokit/auth-app";
55

66
import { getPermissionsFromInputs } from "./lib/get-permissions-from-inputs.js";
77
import { main } from "./lib/main.js";
8-
import request from "./lib/request.js";
8+
import request, { ensureNativeProxySupport } from "./lib/request.js";
99

1010
if (!process.env.GITHUB_REPOSITORY) {
1111
throw new Error("GITHUB_REPOSITORY missing, must be set to '<owner>/<repo>'");
@@ -15,31 +15,37 @@ if (!process.env.GITHUB_REPOSITORY_OWNER) {
1515
throw new Error("GITHUB_REPOSITORY_OWNER missing, must be set to '<owner>'");
1616
}
1717

18-
const appId = core.getInput("app-id");
19-
const privateKey = core.getInput("private-key");
20-
const owner = core.getInput("owner");
21-
const repositories = core
22-
.getInput("repositories")
23-
.split(/[\n,]+/)
24-
.map((s) => s.trim())
25-
.filter((x) => x !== "");
26-
27-
const skipTokenRevoke = core.getBooleanInput("skip-token-revoke");
28-
29-
const permissions = getPermissionsFromInputs(process.env);
18+
async function run() {
19+
ensureNativeProxySupport();
20+
21+
const appId = core.getInput("app-id");
22+
const privateKey = core.getInput("private-key");
23+
const owner = core.getInput("owner");
24+
const repositories = core
25+
.getInput("repositories")
26+
.split(/[\n,]+/)
27+
.map((s) => s.trim())
28+
.filter((x) => x !== "");
29+
30+
const skipTokenRevoke = core.getBooleanInput("skip-token-revoke");
31+
32+
const permissions = getPermissionsFromInputs(process.env);
33+
34+
return main(
35+
appId,
36+
privateKey,
37+
owner,
38+
repositories,
39+
permissions,
40+
core,
41+
createAppAuth,
42+
request,
43+
skipTokenRevoke,
44+
);
45+
}
3046

3147
// Export promise for testing
32-
export default main(
33-
appId,
34-
privateKey,
35-
owner,
36-
repositories,
37-
permissions,
38-
core,
39-
createAppAuth,
40-
request,
41-
skipTokenRevoke,
42-
).catch((error) => {
48+
export default run().catch((error) => {
4349
/* c8 ignore next 3 */
4450
console.error(error);
4551
core.setFailed(error.message);

post.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,15 @@
33
import * as core from "@actions/core";
44

55
import { post } from "./lib/post.js";
6-
import request from "./lib/request.js";
6+
import request, { ensureNativeProxySupport } from "./lib/request.js";
77

8-
post(core, request).catch((error) => {
8+
async function run() {
9+
ensureNativeProxySupport();
10+
11+
return post(core, request);
12+
}
13+
14+
run().catch((error) => {
915
/* c8 ignore next 3 */
1016
console.error(error);
1117
core.setFailed(error.message);

tests/index.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,14 @@ for (const file of testFiles) {
2121
const env = {
2222
GITHUB_OUTPUT: undefined,
2323
GITHUB_STATE: undefined,
24+
HTTP_PROXY: undefined,
25+
HTTPS_PROXY: undefined,
26+
http_proxy: undefined,
27+
https_proxy: undefined,
28+
NO_PROXY: undefined,
29+
no_proxy: undefined,
30+
NODE_OPTIONS: undefined,
31+
NODE_USE_ENV_PROXY: undefined,
2432
};
2533
const { stderr, stdout } = await execa("node", [`tests/${file}`], { env });
2634
t.snapshot(stderr, "stderr");
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
process.env.GITHUB_REPOSITORY = "actions/create-github-app-token";
2+
process.env.GITHUB_REPOSITORY_OWNER = "actions";
3+
process.env.HTTPS_PROXY = "http://127.0.0.1:3128";
4+
5+
const originalConsoleError = console.error;
6+
console.error = (...args) => {
7+
originalConsoleError(
8+
...args.map((arg) => (arg instanceof Error ? arg.message : arg)),
9+
);
10+
};
11+
12+
await import("../main.js");
13+
await new Promise((resolve) => setImmediate(resolve));
14+
process.exitCode = 0;
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
process.env["INPUT_GITHUB-API-URL"] = "https://api.github.com";
2+
process.env.HTTPS_PROXY = "http://127.0.0.1:3128";
3+
4+
const originalConsoleError = console.error;
5+
console.error = (...args) => {
6+
originalConsoleError(
7+
...args.map((arg) => (arg instanceof Error ? arg.message : arg)),
8+
);
9+
};
10+
11+
await import("../post.js");
12+
await new Promise((resolve) => setImmediate(resolve));
13+
process.exitCode = 0;

tests/snapshots/index.js.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,16 @@ Generated by [AVA](https://avajs.dev).
8282
POST /app/installations/123456/access_tokens␊
8383
{"repositories":["create-github-app-token"]}`
8484

85+
## main-proxy-requires-native-support.test.js
86+
87+
> stderr
88+
89+
'A proxy environment variable is set, but Node.js native proxy support is not enabled. Set NODE_USE_ENV_PROXY=1 for this action step.'
90+
91+
> stdout
92+
93+
'::error::A proxy environment variable is set, but Node.js native proxy support is not enabled. Set NODE_USE_ENV_PROXY=1 for this action step.'
94+
8595
## main-repo-skew.test.js
8696

8797
> stderr
@@ -333,6 +343,16 @@ Generated by [AVA](https://avajs.dev).
333343
POST /app/installations/123456/access_tokens␊
334344
{"repositories":["create-github-app-token"],"permissions":{"issues":"write","pull_requests":"read"}}`
335345

346+
## post-proxy-requires-native-support.test.js
347+
348+
> stderr
349+
350+
'A proxy environment variable is set, but Node.js native proxy support is not enabled. Set NODE_USE_ENV_PROXY=1 for this action step.'
351+
352+
> stdout
353+
354+
'::error::A proxy environment variable is set, but Node.js native proxy support is not enabled. Set NODE_USE_ENV_PROXY=1 for this action step.'
355+
336356
## post-revoke-token-fail-response.test.js
337357

338358
> stderr

tests/snapshots/index.js.snap

146 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)