fix: require NODE_USE_ENV_PROXY for proxy support (#342)

This PR switches proxy support to Node's native env-proxy handling and
makes the required configuration explicit.

## What changed

- fail fast in both `main` and `post` when proxy configuration is
present without `NODE_USE_ENV_PROXY=1`
- document the supported proxy configuration in `README.md`
- add regression tests for the proxy guard in both entrypoints
- keep the existing successful end-to-end coverage and add a smaller
proxy-specific workflow check that enables native proxy support, points
`https_proxy` at an unreachable proxy, and asserts the action fails
- update the test workflow so the same checks also run on pushes to
`beta`

## Proxy configuration

When using `HTTP_PROXY` or `HTTPS_PROXY`, set `NODE_USE_ENV_PROXY=1` on
the action step. If you need bypass rules, set `NO_PROXY` alongside
them.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Parker Brown
2026-03-12 23:18:56 -07:00
committed by GitHub
parent bf559f8544
commit 54e58b612c
12 changed files with 289 additions and 105 deletions
+27 -1
View File
@@ -4,6 +4,7 @@ on:
push: push:
branches: branches:
- main - main
- beta
pull_request: pull_request:
workflow_dispatch: workflow_dispatch:
@@ -33,7 +34,7 @@ jobs:
name: End-to-End name: End-to-End
runs-on: ubuntu-latest runs-on: ubuntu-latest
# do not run from forks, as forks dont have access to repository secrets # do not run from forks, as forks dont have access to repository secrets
if: github.event.pull_request.head.repo.owner.login == github.event.pull_request.base.repo.owner.login if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.owner.login == github.event.pull_request.base.repo.owner.login
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v5
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
@@ -54,3 +55,28 @@ jobs:
with: with:
route: GET /installation/repositories route: GET /installation/repositories
- run: echo '${{ steps.get-repository.outputs.data }}' - run: echo '${{ steps.get-repository.outputs.data }}'
end-to-end-proxy:
name: End-to-End with unreachable proxy
runs-on: ubuntu-latest
# do not run from forks, as forks dont have access to repository secrets
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.owner.login == github.event.pull_request.base.repo.owner.login
steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v4
with:
node-version-file: package.json
cache: 'npm'
- run: npm ci
- run: npm run build
- uses: ./ # Uses the action in the root directory
continue-on-error: true
id: test
env:
NODE_USE_ENV_PROXY: "1"
https_proxy: http://127.0.0.1:9
with:
app-id: ${{ vars.TEST_APP_ID }}
private-key: ${{ secrets.TEST_APP_PRIVATE_KEY }}
- name: Assert action failed through unreachable proxy
run: test "${{ steps.test.outcome }}" = "failure"
+18
View File
@@ -296,6 +296,24 @@ jobs:
GITHUB_TOKEN: ${{ steps.create_token.outputs.token }} GITHUB_TOKEN: ${{ steps.create_token.outputs.token }}
``` ```
### Proxy support
This action relies on Node.js native proxy support.
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.
```yaml
- uses: actions/create-github-app-token@v3
id: app-token
env:
HTTPS_PROXY: http://proxy.example.com:8080
NO_PROXY: github.example.com
NODE_USE_ENV_PROXY: "1"
with:
app-id: ${{ vars.APP_ID }}
private-key: ${{ secrets.PRIVATE_KEY }}
```
## Inputs ## Inputs
### `app-id` ### `app-id`
+103 -79
View File
@@ -21294,11 +21294,11 @@ function createOAuthAppAuth(options) {
} }
// node_modules/universal-github-app-jwt/lib/utils.js // node_modules/universal-github-app-jwt/lib/utils.js
function isPkcs1(privateKey2) { function isPkcs1(privateKey) {
return privateKey2.includes("-----BEGIN RSA PRIVATE KEY-----"); return privateKey.includes("-----BEGIN RSA PRIVATE KEY-----");
} }
function isOpenSsh(privateKey2) { function isOpenSsh(privateKey) {
return privateKey2.includes("-----BEGIN OPENSSH PRIVATE KEY-----"); return privateKey.includes("-----BEGIN OPENSSH PRIVATE KEY-----");
} }
function string2ArrayBuffer(str) { function string2ArrayBuffer(str) {
const buf = new ArrayBuffer(str.length); const buf = new ArrayBuffer(str.length);
@@ -21335,17 +21335,17 @@ function base64encodeJSON(obj) {
// node_modules/universal-github-app-jwt/lib/crypto-node.js // node_modules/universal-github-app-jwt/lib/crypto-node.js
var import_node_crypto = require("node:crypto"); var import_node_crypto = require("node:crypto");
var import_node_crypto2 = require("node:crypto"); var import_node_crypto2 = require("node:crypto");
function convertPrivateKey(privateKey2) { function convertPrivateKey(privateKey) {
if (!isPkcs1(privateKey2)) return privateKey2; if (!isPkcs1(privateKey)) return privateKey;
return (0, import_node_crypto2.createPrivateKey)(privateKey2).export({ return (0, import_node_crypto2.createPrivateKey)(privateKey).export({
type: "pkcs8", type: "pkcs8",
format: "pem" format: "pem"
}); });
} }
// node_modules/universal-github-app-jwt/lib/get-token.js // node_modules/universal-github-app-jwt/lib/get-token.js
async function getToken({ privateKey: privateKey2, payload }) { async function getToken({ privateKey, payload }) {
const convertedPrivateKey = convertPrivateKey(privateKey2); const convertedPrivateKey = convertPrivateKey(privateKey);
if (isPkcs1(convertedPrivateKey)) { if (isPkcs1(convertedPrivateKey)) {
throw new Error( throw new Error(
"[universal-github-app-jwt] Private Key is in PKCS#1 format, but only PKCS#8 is supported. See https://github.com/gr2m/universal-github-app-jwt#private-key-formats" "[universal-github-app-jwt] Private Key is in PKCS#1 format, but only PKCS#8 is supported. See https://github.com/gr2m/universal-github-app-jwt#private-key-formats"
@@ -21383,10 +21383,10 @@ async function getToken({ privateKey: privateKey2, payload }) {
// node_modules/universal-github-app-jwt/index.js // node_modules/universal-github-app-jwt/index.js
async function githubAppJwt({ async function githubAppJwt({
id, id,
privateKey: privateKey2, privateKey,
now = Math.floor(Date.now() / 1e3) now = Math.floor(Date.now() / 1e3)
}) { }) {
const privateKeyWithNewlines = privateKey2.replace(/\\n/g, "\n"); const privateKeyWithNewlines = privateKey.replace(/\\n/g, "\n");
const nowWithSafetyMargin = now - 30; const nowWithSafetyMargin = now - 30;
const expiration = nowWithSafetyMargin + 60 * 10; const expiration = nowWithSafetyMargin + 60 * 10;
const payload = { const payload = {
@@ -21544,14 +21544,14 @@ var LruObject = class {
// node_modules/@octokit/auth-app/dist-node/index.js // node_modules/@octokit/auth-app/dist-node/index.js
async function getAppAuthentication({ async function getAppAuthentication({
appId: appId2, appId,
privateKey: privateKey2, privateKey,
timeDifference timeDifference
}) { }) {
try { try {
const authOptions = { const authOptions = {
id: appId2, id: appId,
privateKey: privateKey2 privateKey
}; };
if (timeDifference) { if (timeDifference) {
Object.assign(authOptions, { Object.assign(authOptions, {
@@ -21566,7 +21566,7 @@ async function getAppAuthentication({
expiresAt: new Date(appAuthentication.expiration * 1e3).toISOString() expiresAt: new Date(appAuthentication.expiration * 1e3).toISOString()
}; };
} catch (error) { } catch (error) {
if (privateKey2 === "-----BEGIN RSA PRIVATE KEY-----") { if (privateKey === "-----BEGIN RSA PRIVATE KEY-----") {
throw new Error( throw new Error(
"The 'privateKey` option contains only the first line '-----BEGIN RSA PRIVATE KEY-----'. If you are setting it using a `.env` file, make sure it is set on a single line with newlines replaced by '\n'" "The 'privateKey` option contains only the first line '-----BEGIN RSA PRIVATE KEY-----'. If you are setting it using a `.env` file, make sure it is set on a single line with newlines replaced by '\n'"
); );
@@ -21597,19 +21597,19 @@ async function get(cache, options) {
permissionsString, permissionsString,
singleFileName singleFileName
] = result.split("|"); ] = result.split("|");
const permissions2 = options.permissions || permissionsString.split(/,/).reduce((permissions22, string) => { const permissions = options.permissions || permissionsString.split(/,/).reduce((permissions2, string) => {
if (/!$/.test(string)) { if (/!$/.test(string)) {
permissions22[string.slice(0, -1)] = "write"; permissions2[string.slice(0, -1)] = "write";
} else { } else {
permissions22[string] = "read"; permissions2[string] = "read";
} }
return permissions22; return permissions2;
}, {}); }, {});
return { return {
token, token,
createdAt, createdAt,
expiresAt, expiresAt,
permissions: permissions2, permissions,
repositoryIds: options.repositoryIds, repositoryIds: options.repositoryIds,
repositoryNames: options.repositoryNames, repositoryNames: options.repositoryNames,
singleFileName, singleFileName,
@@ -21633,11 +21633,11 @@ async function set(cache, options, data) {
} }
function optionsToCacheKey({ function optionsToCacheKey({
installationId, installationId,
permissions: permissions2 = {}, permissions = {},
repositoryIds = [], repositoryIds = [],
repositoryNames = [] repositoryNames = []
}) { }) {
const permissionsString = Object.keys(permissions2).sort().map((name) => permissions2[name] === "read" ? name : `${name}!`).join(","); const permissionsString = Object.keys(permissions).sort().map((name) => permissions[name] === "read" ? name : `${name}!`).join(",");
const repositoryIdsString = repositoryIds.sort().join(","); const repositoryIdsString = repositoryIds.sort().join(",");
const repositoryNamesString = repositoryNames.join(","); const repositoryNamesString = repositoryNames.join(",");
return [ return [
@@ -21653,7 +21653,7 @@ function toTokenAuthentication({
createdAt, createdAt,
expiresAt, expiresAt,
repositorySelection, repositorySelection,
permissions: permissions2, permissions,
repositoryIds, repositoryIds,
repositoryNames, repositoryNames,
singleFileName singleFileName
@@ -21664,7 +21664,7 @@ function toTokenAuthentication({
tokenType: "installation", tokenType: "installation",
token, token,
installationId, installationId,
permissions: permissions2, permissions,
createdAt, createdAt,
expiresAt, expiresAt,
repositorySelection repositorySelection
@@ -21717,7 +21717,7 @@ async function getInstallationAuthenticationImpl(state, options, request2) {
token: token2, token: token2,
createdAt: createdAt2, createdAt: createdAt2,
expiresAt: expiresAt2, expiresAt: expiresAt2,
permissions: permissions22, permissions: permissions2,
repositoryIds: repositoryIds2, repositoryIds: repositoryIds2,
repositoryNames: repositoryNames2, repositoryNames: repositoryNames2,
singleFileName: singleFileName2, singleFileName: singleFileName2,
@@ -21728,7 +21728,7 @@ async function getInstallationAuthenticationImpl(state, options, request2) {
token: token2, token: token2,
createdAt: createdAt2, createdAt: createdAt2,
expiresAt: expiresAt2, expiresAt: expiresAt2,
permissions: permissions22, permissions: permissions2,
repositorySelection: repositorySelection2, repositorySelection: repositorySelection2,
repositoryIds: repositoryIds2, repositoryIds: repositoryIds2,
repositoryNames: repositoryNames2, repositoryNames: repositoryNames2,
@@ -21761,7 +21761,7 @@ async function getInstallationAuthenticationImpl(state, options, request2) {
data: { data: {
token, token,
expires_at: expiresAt, expires_at: expiresAt,
repositories: repositories2, repositories,
permissions: permissionsOptional, permissions: permissionsOptional,
repository_selection: repositorySelectionOptional, repository_selection: repositorySelectionOptional,
single_file: singleFileName single_file: singleFileName
@@ -21770,17 +21770,17 @@ async function getInstallationAuthenticationImpl(state, options, request2) {
"POST /app/installations/{installation_id}/access_tokens", "POST /app/installations/{installation_id}/access_tokens",
payload payload
); );
const permissions2 = permissionsOptional || {}; const permissions = permissionsOptional || {};
const repositorySelection = repositorySelectionOptional || "all"; const repositorySelection = repositorySelectionOptional || "all";
const repositoryIds = repositories2 ? repositories2.map((r) => r.id) : void 0; const repositoryIds = repositories ? repositories.map((r) => r.id) : void 0;
const repositoryNames = repositories2 ? repositories2.map((repo) => repo.name) : void 0; const repositoryNames = repositories ? repositories.map((repo) => repo.name) : void 0;
const createdAt = (/* @__PURE__ */ new Date()).toISOString(); const createdAt = (/* @__PURE__ */ new Date()).toISOString();
const cacheOptions = { const cacheOptions = {
token, token,
createdAt, createdAt,
expiresAt, expiresAt,
repositorySelection, repositorySelection,
permissions: permissions2, permissions,
repositoryIds, repositoryIds,
repositoryNames repositoryNames
}; };
@@ -21794,7 +21794,7 @@ async function getInstallationAuthenticationImpl(state, options, request2) {
createdAt, createdAt,
expiresAt, expiresAt,
repositorySelection, repositorySelection,
permissions: permissions2, permissions,
repositoryIds, repositoryIds,
repositoryNames repositoryNames
}; };
@@ -21986,16 +21986,16 @@ function createAppAuth(options) {
// lib/get-permissions-from-inputs.js // lib/get-permissions-from-inputs.js
function getPermissionsFromInputs(env) { function getPermissionsFromInputs(env) {
return Object.entries(env).reduce((permissions2, [key, value]) => { return Object.entries(env).reduce((permissions, [key, value]) => {
if (!key.startsWith("INPUT_PERMISSION-")) return permissions2; if (!key.startsWith("INPUT_PERMISSION-")) return permissions;
if (!value) return permissions2; if (!value) return permissions;
const permission = key.slice("INPUT_PERMISSION-".length).toLowerCase().replaceAll(/-/g, "_"); const permission = key.slice("INPUT_PERMISSION-".length).toLowerCase().replaceAll(/-/g, "_");
if (permissions2 === void 0) { if (permissions === void 0) {
return { [permission]: value }; return { [permission]: value };
} }
return { return {
// @ts-expect-error - needs to be typed correctly // @ts-expect-error - needs to be typed correctly
...permissions2, ...permissions,
[permission]: value [permission]: value
}; };
}, void 0); }, void 0);
@@ -22112,43 +22112,43 @@ async function pRetry(input, options) {
} }
// lib/main.js // lib/main.js
async function main(appId2, privateKey2, owner2, repositories2, permissions2, core3, createAppAuth2, request2, skipTokenRevoke2) { async function main(appId, privateKey, owner, repositories, permissions, core3, createAppAuth2, request2, skipTokenRevoke) {
let parsedOwner = ""; let parsedOwner = "";
let parsedRepositoryNames = []; let parsedRepositoryNames = [];
if (!owner2 && repositories2.length === 0) { if (!owner && repositories.length === 0) {
const [owner3, repo] = String(process.env.GITHUB_REPOSITORY).split("/"); const [owner2, repo] = String(process.env.GITHUB_REPOSITORY).split("/");
parsedOwner = owner3; parsedOwner = owner2;
parsedRepositoryNames = [repo]; parsedRepositoryNames = [repo];
core3.info( core3.info(
`Inputs 'owner' and 'repositories' are not set. Creating token for this repository (${owner3}/${repo}).` `Inputs 'owner' and 'repositories' are not set. Creating token for this repository (${owner2}/${repo}).`
); );
} }
if (owner2 && repositories2.length === 0) { if (owner && repositories.length === 0) {
parsedOwner = owner2; parsedOwner = owner;
core3.info( core3.info(
`Input 'repositories' is not set. Creating token for all repositories owned by ${owner2}.` `Input 'repositories' is not set. Creating token for all repositories owned by ${owner}.`
); );
} }
if (!owner2 && repositories2.length > 0) { if (!owner && repositories.length > 0) {
parsedOwner = String(process.env.GITHUB_REPOSITORY_OWNER); parsedOwner = String(process.env.GITHUB_REPOSITORY_OWNER);
parsedRepositoryNames = repositories2; parsedRepositoryNames = repositories;
core3.info( core3.info(
`No 'owner' input provided. Using default owner '${parsedOwner}' to create token for the following repositories:${repositories2.map((repo) => ` `No 'owner' input provided. Using default owner '${parsedOwner}' to create token for the following repositories:${repositories.map((repo) => `
- ${parsedOwner}/${repo}`).join("")}` - ${parsedOwner}/${repo}`).join("")}`
); );
} }
if (owner2 && repositories2.length > 0) { if (owner && repositories.length > 0) {
parsedOwner = owner2; parsedOwner = owner;
parsedRepositoryNames = repositories2; parsedRepositoryNames = repositories;
core3.info( core3.info(
`Inputs 'owner' and 'repositories' are set. Creating token for the following repositories: `Inputs 'owner' and 'repositories' are set. Creating token for the following repositories:
${repositories2.map((repo) => ` ${repositories.map((repo) => `
- ${parsedOwner}/${repo}`).join("")}` - ${parsedOwner}/${repo}`).join("")}`
); );
} }
const auth5 = createAppAuth2({ const auth5 = createAppAuth2({
appId: appId2, appId,
privateKey: privateKey2, privateKey,
request: request2 request: request2
}); });
let authentication, installationId, appSlug; let authentication, installationId, appSlug;
@@ -22159,7 +22159,7 @@ async function main(appId2, privateKey2, owner2, repositories2, permissions2, co
auth5, auth5,
parsedOwner, parsedOwner,
parsedRepositoryNames, parsedRepositoryNames,
permissions2 permissions
), ),
{ {
shouldRetry: (error) => error.status >= 500, shouldRetry: (error) => error.status >= 500,
@@ -22175,7 +22175,7 @@ async function main(appId2, privateKey2, owner2, repositories2, permissions2, co
)); ));
} else { } else {
({ authentication, installationId, appSlug } = await pRetry( ({ authentication, installationId, appSlug } = await pRetry(
() => getTokenFromOwner(request2, auth5, parsedOwner, permissions2), () => getTokenFromOwner(request2, auth5, parsedOwner, permissions),
{ {
onFailedAttempt: (error) => { onFailedAttempt: (error) => {
core3.info( core3.info(
@@ -22190,12 +22190,12 @@ async function main(appId2, privateKey2, owner2, repositories2, permissions2, co
core3.setOutput("token", authentication.token); core3.setOutput("token", authentication.token);
core3.setOutput("installation-id", installationId); core3.setOutput("installation-id", installationId);
core3.setOutput("app-slug", appSlug); core3.setOutput("app-slug", appSlug);
if (!skipTokenRevoke2) { if (!skipTokenRevoke) {
core3.saveState("token", authentication.token); core3.saveState("token", authentication.token);
core3.saveState("expiresAt", authentication.expiresAt); core3.saveState("expiresAt", authentication.expiresAt);
} }
} }
async function getTokenFromOwner(request2, auth5, parsedOwner, permissions2) { async function getTokenFromOwner(request2, auth5, parsedOwner, permissions) {
const response = await request2("GET /users/{username}/installation", { const response = await request2("GET /users/{username}/installation", {
username: parsedOwner, username: parsedOwner,
request: { request: {
@@ -22205,13 +22205,13 @@ async function getTokenFromOwner(request2, auth5, parsedOwner, permissions2) {
const authentication = await auth5({ const authentication = await auth5({
type: "installation", type: "installation",
installationId: response.data.id, installationId: response.data.id,
permissions: permissions2 permissions
}); });
const installationId = response.data.id; const installationId = response.data.id;
const appSlug = response.data["app_slug"]; const appSlug = response.data["app_slug"];
return { authentication, installationId, appSlug }; return { authentication, installationId, appSlug };
} }
async function getTokenFromRepository(request2, auth5, parsedOwner, parsedRepositoryNames, permissions2) { async function getTokenFromRepository(request2, auth5, parsedOwner, parsedRepositoryNames, permissions) {
const response = await request2("GET /repos/{owner}/{repo}/installation", { const response = await request2("GET /repos/{owner}/{repo}/installation", {
owner: parsedOwner, owner: parsedOwner,
repo: parsedRepositoryNames[0], repo: parsedRepositoryNames[0],
@@ -22223,7 +22223,7 @@ async function getTokenFromRepository(request2, auth5, parsedOwner, parsedReposi
type: "installation", type: "installation",
installationId: response.data.id, installationId: response.data.id,
repositoryNames: parsedRepositoryNames, repositoryNames: parsedRepositoryNames,
permissions: permissions2 permissions
}); });
const installationId = response.data.id; const installationId = response.data.id;
const appSlug = response.data["app_slug"]; const appSlug = response.data["app_slug"];
@@ -22233,6 +22233,26 @@ async function getTokenFromRepository(request2, auth5, parsedOwner, parsedReposi
// lib/request.js // lib/request.js
var import_core = __toESM(require_core(), 1); var import_core = __toESM(require_core(), 1);
var baseUrl = import_core.default.getInput("github-api-url").replace(/\/$/, ""); var baseUrl = import_core.default.getInput("github-api-url").replace(/\/$/, "");
var proxyEnvironmentKeys = [
"https_proxy",
"HTTPS_PROXY",
"http_proxy",
"HTTP_PROXY"
];
function proxyEnvironmentConfigured() {
return proxyEnvironmentKeys.some((key) => process.env[key]);
}
function nativeProxySupportEnabled() {
return process.env.NODE_USE_ENV_PROXY === "1";
}
function ensureNativeProxySupport() {
if (!proxyEnvironmentConfigured() || nativeProxySupportEnabled()) {
return;
}
throw new 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."
);
}
var request_default = request.defaults({ var request_default = request.defaults({
headers: { "user-agent": "actions/create-github-app-token" }, headers: { "user-agent": "actions/create-github-app-token" },
baseUrl baseUrl
@@ -22245,23 +22265,27 @@ if (!process.env.GITHUB_REPOSITORY) {
if (!process.env.GITHUB_REPOSITORY_OWNER) { if (!process.env.GITHUB_REPOSITORY_OWNER) {
throw new Error("GITHUB_REPOSITORY_OWNER missing, must be set to '<owner>'"); throw new Error("GITHUB_REPOSITORY_OWNER missing, must be set to '<owner>'");
} }
var appId = import_core2.default.getInput("app-id"); async function run() {
var privateKey = import_core2.default.getInput("private-key"); ensureNativeProxySupport();
var owner = import_core2.default.getInput("owner"); const appId = import_core2.default.getInput("app-id");
var repositories = import_core2.default.getInput("repositories").split(/[\n,]+/).map((s) => s.trim()).filter((x) => x !== ""); const privateKey = import_core2.default.getInput("private-key");
var skipTokenRevoke = import_core2.default.getBooleanInput("skip-token-revoke"); const owner = import_core2.default.getInput("owner");
var permissions = getPermissionsFromInputs(process.env); const repositories = import_core2.default.getInput("repositories").split(/[\n,]+/).map((s) => s.trim()).filter((x) => x !== "");
var main_default = main( const skipTokenRevoke = import_core2.default.getBooleanInput("skip-token-revoke");
appId, const permissions = getPermissionsFromInputs(process.env);
privateKey, return main(
owner, appId,
repositories, privateKey,
permissions, owner,
import_core2.default, repositories,
createAppAuth, permissions,
request_default, import_core2.default,
skipTokenRevoke createAppAuth,
).catch((error) => { request_default,
skipTokenRevoke
);
}
var main_default = run().catch((error) => {
console.error(error); console.error(error);
import_core2.default.setFailed(error.message); import_core2.default.setFailed(error.message);
}); });
+25 -1
View File
@@ -20485,13 +20485,37 @@ var request = withDefaults2(endpoint, defaults_default);
// lib/request.js // lib/request.js
var baseUrl = import_core.default.getInput("github-api-url").replace(/\/$/, ""); var baseUrl = import_core.default.getInput("github-api-url").replace(/\/$/, "");
var proxyEnvironmentKeys = [
"https_proxy",
"HTTPS_PROXY",
"http_proxy",
"HTTP_PROXY"
];
function proxyEnvironmentConfigured() {
return proxyEnvironmentKeys.some((key) => process.env[key]);
}
function nativeProxySupportEnabled() {
return process.env.NODE_USE_ENV_PROXY === "1";
}
function ensureNativeProxySupport() {
if (!proxyEnvironmentConfigured() || nativeProxySupportEnabled()) {
return;
}
throw new 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."
);
}
var request_default = request.defaults({ var request_default = request.defaults({
headers: { "user-agent": "actions/create-github-app-token" }, headers: { "user-agent": "actions/create-github-app-token" },
baseUrl baseUrl
}); });
// post.js // post.js
post(import_core2.default, request_default).catch((error) => { async function run() {
ensureNativeProxySupport();
return post(import_core2.default, request_default);
}
run().catch((error) => {
console.error(error); console.error(error);
import_core2.default.setFailed(error.message); import_core2.default.setFailed(error.message);
}); });
+25
View File
@@ -4,6 +4,31 @@ import { request } from "@octokit/request";
// Get the GitHub API URL from the action input and remove any trailing slash // Get the GitHub API URL from the action input and remove any trailing slash
const baseUrl = core.getInput("github-api-url").replace(/\/$/, ""); const baseUrl = core.getInput("github-api-url").replace(/\/$/, "");
const proxyEnvironmentKeys = [
"https_proxy",
"HTTPS_PROXY",
"http_proxy",
"HTTP_PROXY",
];
function proxyEnvironmentConfigured() {
return proxyEnvironmentKeys.some((key) => process.env[key]);
}
function nativeProxySupportEnabled() {
return process.env.NODE_USE_ENV_PROXY === "1";
}
export function ensureNativeProxySupport() {
if (!proxyEnvironmentConfigured() || nativeProxySupportEnabled()) {
return;
}
throw new 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.",
);
}
// Configure the default settings for GitHub API requests // Configure the default settings for GitHub API requests
export default request.defaults({ export default request.defaults({
headers: { "user-agent": "actions/create-github-app-token" }, headers: { "user-agent": "actions/create-github-app-token" },
+28 -22
View File
@@ -5,7 +5,7 @@ import { createAppAuth } from "@octokit/auth-app";
import { getPermissionsFromInputs } from "./lib/get-permissions-from-inputs.js"; import { getPermissionsFromInputs } from "./lib/get-permissions-from-inputs.js";
import { main } from "./lib/main.js"; import { main } from "./lib/main.js";
import request from "./lib/request.js"; import request, { ensureNativeProxySupport } from "./lib/request.js";
if (!process.env.GITHUB_REPOSITORY) { if (!process.env.GITHUB_REPOSITORY) {
throw new Error("GITHUB_REPOSITORY missing, must be set to '<owner>/<repo>'"); throw new Error("GITHUB_REPOSITORY missing, must be set to '<owner>/<repo>'");
@@ -15,31 +15,37 @@ if (!process.env.GITHUB_REPOSITORY_OWNER) {
throw new Error("GITHUB_REPOSITORY_OWNER missing, must be set to '<owner>'"); throw new Error("GITHUB_REPOSITORY_OWNER missing, must be set to '<owner>'");
} }
const appId = core.getInput("app-id"); async function run() {
const privateKey = core.getInput("private-key"); ensureNativeProxySupport();
const owner = core.getInput("owner");
const repositories = core
.getInput("repositories")
.split(/[\n,]+/)
.map((s) => s.trim())
.filter((x) => x !== "");
const skipTokenRevoke = core.getBooleanInput("skip-token-revoke"); const appId = core.getInput("app-id");
const privateKey = core.getInput("private-key");
const owner = core.getInput("owner");
const repositories = core
.getInput("repositories")
.split(/[\n,]+/)
.map((s) => s.trim())
.filter((x) => x !== "");
const permissions = getPermissionsFromInputs(process.env); const skipTokenRevoke = core.getBooleanInput("skip-token-revoke");
const permissions = getPermissionsFromInputs(process.env);
return main(
appId,
privateKey,
owner,
repositories,
permissions,
core,
createAppAuth,
request,
skipTokenRevoke,
);
}
// Export promise for testing // Export promise for testing
export default main( export default run().catch((error) => {
appId,
privateKey,
owner,
repositories,
permissions,
core,
createAppAuth,
request,
skipTokenRevoke,
).catch((error) => {
/* c8 ignore next 3 */ /* c8 ignore next 3 */
console.error(error); console.error(error);
core.setFailed(error.message); core.setFailed(error.message);
+8 -2
View File
@@ -3,9 +3,15 @@
import core from "@actions/core"; import core from "@actions/core";
import { post } from "./lib/post.js"; import { post } from "./lib/post.js";
import request from "./lib/request.js"; import request, { ensureNativeProxySupport } from "./lib/request.js";
post(core, request).catch((error) => { async function run() {
ensureNativeProxySupport();
return post(core, request);
}
run().catch((error) => {
/* c8 ignore next 3 */ /* c8 ignore next 3 */
console.error(error); console.error(error);
core.setFailed(error.message); core.setFailed(error.message);
+8
View File
@@ -21,6 +21,14 @@ for (const file of testFiles) {
const env = { const env = {
GITHUB_OUTPUT: undefined, GITHUB_OUTPUT: undefined,
GITHUB_STATE: undefined, GITHUB_STATE: undefined,
HTTP_PROXY: undefined,
HTTPS_PROXY: undefined,
http_proxy: undefined,
https_proxy: undefined,
NO_PROXY: undefined,
no_proxy: undefined,
NODE_OPTIONS: undefined,
NODE_USE_ENV_PROXY: undefined,
}; };
const { stderr, stdout } = await execa("node", [`tests/${file}`], { env }); const { stderr, stdout } = await execa("node", [`tests/${file}`], { env });
t.snapshot(stderr, "stderr"); t.snapshot(stderr, "stderr");
@@ -0,0 +1,14 @@
process.env.GITHUB_REPOSITORY = "actions/create-github-app-token";
process.env.GITHUB_REPOSITORY_OWNER = "actions";
process.env.HTTPS_PROXY = "http://127.0.0.1:3128";
const originalConsoleError = console.error;
console.error = (...args) => {
originalConsoleError(
...args.map((arg) => (arg instanceof Error ? arg.message : arg)),
);
};
await import("../main.js");
await new Promise((resolve) => setImmediate(resolve));
process.exitCode = 0;
@@ -0,0 +1,13 @@
process.env["INPUT_GITHUB-API-URL"] = "https://api.github.com";
process.env.HTTPS_PROXY = "http://127.0.0.1:3128";
const originalConsoleError = console.error;
console.error = (...args) => {
originalConsoleError(
...args.map((arg) => (arg instanceof Error ? arg.message : arg)),
);
};
await import("../post.js");
await new Promise((resolve) => setImmediate(resolve));
process.exitCode = 0;
+20
View File
@@ -82,6 +82,16 @@ Generated by [AVA](https://avajs.dev).
POST /app/installations/123456/access_tokens␊ POST /app/installations/123456/access_tokens␊
{"repositories":["create-github-app-token"]}` {"repositories":["create-github-app-token"]}`
## main-proxy-requires-native-support.test.js
> stderr
'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.'
> stdout
'::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.'
## main-repo-skew.test.js ## main-repo-skew.test.js
> stderr > stderr
@@ -333,6 +343,16 @@ Generated by [AVA](https://avajs.dev).
POST /app/installations/123456/access_tokens␊ POST /app/installations/123456/access_tokens␊
{"repositories":["create-github-app-token"],"permissions":{"issues":"write","pull_requests":"read"}}` {"repositories":["create-github-app-token"],"permissions":{"issues":"write","pull_requests":"read"}}`
## post-proxy-requires-native-support.test.js
> stderr
'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.'
> stdout
'::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.'
## post-revoke-token-fail-response.test.js ## post-revoke-token-fail-response.test.js
> stderr > stderr
Binary file not shown.