feat: add proxy support via child process spawning
When proxy environment variables (https_proxy, HTTPS_PROXY, http_proxy, HTTP_PROXY) are detected and NODE_USE_ENV_PROXY is not already set to "1", the action spawns a child process with NODE_USE_ENV_PROXY=1 to enable Node.js native proxy support. - Add lib/run-with-proxy.js shared utility for both main.js and post.js - Update main.js and post.js to use runWithProxy() wrapper - Add tests for proxy spawning, child error handling, and already-enabled path - 100% code coverage maintained Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
+9
-1
@@ -22,7 +22,15 @@ for (const file of testFiles) {
|
||||
GITHUB_OUTPUT: undefined,
|
||||
GITHUB_STATE: undefined,
|
||||
};
|
||||
const { stderr, stdout } = await execa("node", [`tests/${file}`], { env });
|
||||
const { stderr, stdout } = await execa(
|
||||
"node",
|
||||
[
|
||||
"--experimental-test-module-mocks",
|
||||
"--disable-warning=ExperimentalWarning",
|
||||
`tests/${file}`,
|
||||
],
|
||||
{ env },
|
||||
);
|
||||
t.snapshot(stderr, "stderr");
|
||||
t.snapshot(stdout, "stdout");
|
||||
});
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
// Verify that `runWithProxy()` calls the callback directly (no child process)
|
||||
// when `NODE_USE_ENV_PROXY` is already set to `"1"`, even with proxy env vars set.
|
||||
import assert from "node:assert";
|
||||
import { runWithProxy } from "../lib/run-with-proxy.js";
|
||||
|
||||
process.env.https_proxy = "http://proxy.example.com";
|
||||
process.env.NODE_USE_ENV_PROXY = "1";
|
||||
|
||||
let callbackCalled = false;
|
||||
|
||||
await runWithProxy(async () => {
|
||||
callbackCalled = true;
|
||||
});
|
||||
|
||||
assert(callbackCalled, "callback was called directly without spawning");
|
||||
|
||||
delete process.env.NODE_USE_ENV_PROXY;
|
||||
delete process.env.https_proxy;
|
||||
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
// Verify that `main.js` rejects when the child process exits with a non-zero code.
|
||||
import assert from "node:assert";
|
||||
import { mock } from "node:test";
|
||||
|
||||
mock.module("node:child_process", {
|
||||
namedExports: {
|
||||
spawn() {
|
||||
return {
|
||||
on(event, callback) {
|
||||
if (event === "exit") callback(1);
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
process.env.GITHUB_REPOSITORY = "actions/create-github-app-token";
|
||||
process.env.GITHUB_REPOSITORY_OWNER = "actions";
|
||||
process.env.https_proxy = "http://proxy.example.com";
|
||||
delete process.env.NODE_USE_ENV_PROXY;
|
||||
|
||||
const { default: runPromise } = await import("../main.js");
|
||||
|
||||
await assert.rejects(runPromise, {
|
||||
message: "Child process exited with code 1",
|
||||
});
|
||||
assert.equal(process.exitCode, 1, "process exit code is 1");
|
||||
|
||||
// Reset for other tests
|
||||
process.exitCode = 0;
|
||||
@@ -0,0 +1,36 @@
|
||||
// Verify that `main.js` spawns a child process when a proxy env var is set
|
||||
// and `NODE_USE_ENV_PROXY` is not set.
|
||||
import assert from "node:assert";
|
||||
import { mock } from "node:test";
|
||||
|
||||
let spawnArgs;
|
||||
|
||||
mock.module("node:child_process", {
|
||||
namedExports: {
|
||||
spawn(command, args, options) {
|
||||
spawnArgs = { command, args, options };
|
||||
return {
|
||||
on(event, callback) {
|
||||
if (event === "exit") callback(0);
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
process.env.GITHUB_REPOSITORY = "actions/create-github-app-token";
|
||||
process.env.GITHUB_REPOSITORY_OWNER = "actions";
|
||||
process.env.https_proxy = "http://proxy.example.com";
|
||||
delete process.env.NODE_USE_ENV_PROXY;
|
||||
|
||||
const { default: runPromise } = await import("../main.js");
|
||||
await runPromise;
|
||||
|
||||
assert(spawnArgs, "spawn was called");
|
||||
assert.equal(
|
||||
spawnArgs.options.env.NODE_USE_ENV_PROXY,
|
||||
"1",
|
||||
"NODE_USE_ENV_PROXY is set to '1' in child env",
|
||||
);
|
||||
assert.equal(spawnArgs.options.stdio, "inherit", "stdio is inherited");
|
||||
assert.equal(process.exitCode, 0, "process exit code is 0");
|
||||
@@ -0,0 +1,21 @@
|
||||
// Verify that `runWithProxy()` calls the callback directly (no child process)
|
||||
// when `NODE_USE_ENV_PROXY` is already set to `"1"`, even with proxy env vars set.
|
||||
// This ensures post.js would also follow the callback path.
|
||||
import assert from "node:assert";
|
||||
import { runWithProxy } from "../lib/run-with-proxy.js";
|
||||
|
||||
process.env.HTTP_PROXY = "http://proxy.example.com";
|
||||
process.env.NODE_USE_ENV_PROXY = "1";
|
||||
|
||||
let callbackCalled = false;
|
||||
|
||||
await runWithProxy(async () => {
|
||||
callbackCalled = true;
|
||||
});
|
||||
|
||||
assert(callbackCalled, "callback was called directly without spawning");
|
||||
|
||||
delete process.env.NODE_USE_ENV_PROXY;
|
||||
delete process.env.HTTP_PROXY;
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
// Verify that `post.js` spawns a child process when a proxy env var is set
|
||||
// and `NODE_USE_ENV_PROXY` is not set.
|
||||
import assert from "node:assert";
|
||||
import { mock } from "node:test";
|
||||
|
||||
let spawnArgs;
|
||||
|
||||
mock.module("node:child_process", {
|
||||
namedExports: {
|
||||
spawn(command, args, options) {
|
||||
spawnArgs = { command, args, options };
|
||||
return {
|
||||
on(event, callback) {
|
||||
if (event === "exit") callback(0);
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
process.env.https_proxy = "http://proxy.example.com";
|
||||
delete process.env.NODE_USE_ENV_PROXY;
|
||||
|
||||
const { default: runPromise } = await import("../post.js");
|
||||
await runPromise;
|
||||
|
||||
assert(spawnArgs, "spawn was called");
|
||||
assert.equal(
|
||||
spawnArgs.options.env.NODE_USE_ENV_PROXY,
|
||||
"1",
|
||||
"NODE_USE_ENV_PROXY is set to '1' in child env",
|
||||
);
|
||||
assert.equal(spawnArgs.options.stdio, "inherit", "stdio is inherited");
|
||||
assert.equal(process.exitCode, 0, "process exit code is 0");
|
||||
@@ -82,6 +82,36 @@ Generated by [AVA](https://avajs.dev).
|
||||
POST /app/installations/123456/access_tokens␊
|
||||
{"repositories":["create-github-app-token"]}`
|
||||
|
||||
## main-proxy-already-enabled.test.js
|
||||
|
||||
> stderr
|
||||
|
||||
''
|
||||
|
||||
> stdout
|
||||
|
||||
''
|
||||
|
||||
## main-proxy-child-error.test.js
|
||||
|
||||
> stderr
|
||||
|
||||
''
|
||||
|
||||
> stdout
|
||||
|
||||
''
|
||||
|
||||
## main-proxy-spawns-child.test.js
|
||||
|
||||
> stderr
|
||||
|
||||
''
|
||||
|
||||
> stdout
|
||||
|
||||
''
|
||||
|
||||
## main-repo-skew.test.js
|
||||
|
||||
> stderr
|
||||
@@ -333,6 +363,26 @@ Generated by [AVA](https://avajs.dev).
|
||||
POST /app/installations/123456/access_tokens␊
|
||||
{"repositories":["create-github-app-token"],"permissions":{"issues":"write","pull_requests":"read"}}`
|
||||
|
||||
## post-proxy-already-enabled.test.js
|
||||
|
||||
> stderr
|
||||
|
||||
''
|
||||
|
||||
> stdout
|
||||
|
||||
''
|
||||
|
||||
## post-proxy-spawns-child.test.js
|
||||
|
||||
> stderr
|
||||
|
||||
''
|
||||
|
||||
> stdout
|
||||
|
||||
''
|
||||
|
||||
## post-revoke-token-fail-response.test.js
|
||||
|
||||
> stderr
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user