Add codeql-action/start-proxy

This commit is contained in:
Arthur Baars 2024-07-02 17:12:56 +02:00
parent 5669f66a72
commit 7b43b7c7ca
7 changed files with 386 additions and 0 deletions

45
lib/start-proxy-action-post.js generated Normal file
View file

@ -0,0 +1,45 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
/**
* This file is the entry point for the `post:` hook of `start-proxy-action.yml`.
* It will run after the all steps in this job, in reverse order in relation to
* other `post:` hooks.
*/
const core = __importStar(require("@actions/core"));
const util_1 = require("./util");
async function runWrapper() {
try {
const pid = core.getState("proxy-process-pid");
if (pid) {
process.kill(Number(pid));
}
}
catch (error) {
core.setFailed(`start-proxy post-action step failed: ${(0, util_1.wrapError)(error).message}`);
}
}
void runWrapper();
//# sourceMappingURL=start-proxy-action-post.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"start-proxy-action-post.js","sourceRoot":"","sources":["../src/start-proxy-action-post.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAAA;;;;GAIG;AACH,oDAAsC;AAEtC,iCAAmC;AAEnC,KAAK,UAAU,UAAU;IACvB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC;QAC/C,IAAI,GAAG,EAAE,CAAC;YACR,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC,SAAS,CACZ,wCAAwC,IAAA,gBAAS,EAAC,KAAK,CAAC,CAAC,OAAO,EAAE,CACnE,CAAC;IACJ,CAAC;AACH,CAAC;AAED,KAAK,UAAU,EAAE,CAAC"}

140
lib/start-proxy-action.js generated Normal file
View file

@ -0,0 +1,140 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
const child_process_1 = require("child_process");
const path = __importStar(require("path"));
const core = __importStar(require("@actions/core"));
const node_forge_1 = require("node-forge");
const actionsUtil = __importStar(require("./actions-util"));
const util = __importStar(require("./util"));
const PROXY_USER = "proxy_user";
const KEY_SIZE = 2048;
const KEY_EXPIRY_YEARS = 2;
const CERT_SUBJECT = [
{
name: "commonName",
value: "Dependabot Internal CA",
},
{
name: "organizationName",
value: "GitHub ic.",
},
{
shortName: "OU",
value: "Dependabot",
},
{
name: "countryName",
value: "US",
},
{
shortName: "ST",
value: "California",
},
{
name: "localityName",
value: "San Francisco",
},
];
function generateCertificateAuthority() {
const keys = node_forge_1.pki.rsa.generateKeyPair(KEY_SIZE);
const cert = node_forge_1.pki.createCertificate();
cert.publicKey = keys.publicKey;
cert.serialNumber = "01";
cert.validity.notBefore = new Date();
cert.validity.notAfter = new Date();
cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + KEY_EXPIRY_YEARS);
cert.setSubject(CERT_SUBJECT);
cert.setIssuer(CERT_SUBJECT);
cert.setExtensions([{ name: "basicConstraints", cA: true }]);
cert.sign(keys.privateKey);
const pem = node_forge_1.pki.certificateToPem(cert);
const key = node_forge_1.pki.privateKeyToPem(keys.privateKey);
return { cert: pem, key };
}
async function runWrapper() {
const tempDir = actionsUtil.getTemporaryDirectory();
const logFilePath = path.resolve(tempDir, "proxy.log");
const input = actionsUtil.getOptionalInput("registry_secrets") || "[]";
const credentials = JSON.parse(input);
const ca = generateCertificateAuthority();
const proxy_password = actionsUtil.getOptionalInput("proxy_password");
let proxy_auth = undefined;
if (proxy_password) {
core.setSecret(proxy_password);
proxy_auth = {
username: PROXY_USER,
password: proxy_password,
};
}
const proxyConfig = {
all_credentials: credentials,
ca,
proxy_auth,
};
const host = "127.0.0.1";
const proxyBin = path.resolve(__dirname, "..", "bin", "update-job-proxy");
let port = 49152;
try {
let subprocess = undefined;
let tries = 5;
let subprocessError = undefined;
while (tries-- > 0 && !subprocess && !subprocessError) {
subprocess = (0, child_process_1.spawn)(proxyBin, ["-addr", `${host}:${port}`, "-config", "-", "-logfile", logFilePath], {
detached: true,
stdio: ["pipe", "ignore", "ignore"],
});
subprocess.unref();
if (subprocess.pid) {
core.saveState("proxy-process-pid", `${subprocess.pid}`);
}
subprocess.on("error", (error) => {
subprocessError = error;
});
subprocess.on("exit", (code) => {
if (code !== 0) {
port = Math.floor(Math.random() * (65535 - 49152) + 49152);
subprocess = undefined;
}
});
subprocess.stdin?.write(JSON.stringify(proxyConfig));
subprocess.stdin?.end();
// Wait a little to allow the proxy to start
await util.delay(1000);
}
if (subprocessError) {
throw subprocessError;
}
core.info(`Proxy started on ${host}:${port}`);
core.setOutput("proxy_host", host);
core.setOutput("proxy_port", port.toString());
core.setOutput("proxy_ca_certificate", ca.cert);
}
catch (error) {
core.setFailed(`start-proxy action failed: ${util.wrapError(error).message}`);
}
}
void runWrapper();
//# sourceMappingURL=start-proxy-action.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"start-proxy-action.js","sourceRoot":"","sources":["../src/start-proxy-action.ts"],"names":[],"mappings":"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"}

View file

@ -0,0 +1,23 @@
/**
* This file is the entry point for the `post:` hook of `start-proxy-action.yml`.
* It will run after the all steps in this job, in reverse order in relation to
* other `post:` hooks.
*/
import * as core from "@actions/core";
import { wrapError } from "./util";
async function runWrapper() {
try {
const pid = core.getState("proxy-process-pid");
if (pid) {
process.kill(Number(pid));
}
} catch (error) {
core.setFailed(
`start-proxy post-action step failed: ${wrapError(error).message}`,
);
}
}
void runWrapper();

154
src/start-proxy-action.ts Normal file
View file

@ -0,0 +1,154 @@
import { ChildProcess, spawn } from "child_process";
import * as path from "path";
import * as core from "@actions/core";
import { pki } from "node-forge";
import * as actionsUtil from "./actions-util";
import * as util from "./util";
const PROXY_USER = "proxy_user";
const KEY_SIZE = 2048;
const KEY_EXPIRY_YEARS = 2;
export type CertificateAuthority = {
cert: string;
key: string;
};
export type Credential = {
type: string;
host: string;
username?: string;
password?: string;
token?: string;
};
export type BasicAuthCredentials = {
username: string;
password: string;
};
export type ProxyConfig = {
all_credentials: Credential[];
ca: CertificateAuthority;
proxy_auth?: BasicAuthCredentials;
};
const CERT_SUBJECT = [
{
name: "commonName",
value: "Dependabot Internal CA",
},
{
name: "organizationName",
value: "GitHub ic.",
},
{
shortName: "OU",
value: "Dependabot",
},
{
name: "countryName",
value: "US",
},
{
shortName: "ST",
value: "California",
},
{
name: "localityName",
value: "San Francisco",
},
];
function generateCertificateAuthority(): CertificateAuthority {
const keys = pki.rsa.generateKeyPair(KEY_SIZE);
const cert = pki.createCertificate();
cert.publicKey = keys.publicKey;
cert.serialNumber = "01";
cert.validity.notBefore = new Date();
cert.validity.notAfter = new Date();
cert.validity.notAfter.setFullYear(
cert.validity.notBefore.getFullYear() + KEY_EXPIRY_YEARS,
);
cert.setSubject(CERT_SUBJECT);
cert.setIssuer(CERT_SUBJECT);
cert.setExtensions([{ name: "basicConstraints", cA: true }]);
cert.sign(keys.privateKey);
const pem = pki.certificateToPem(cert);
const key = pki.privateKeyToPem(keys.privateKey);
return { cert: pem, key };
}
async function runWrapper() {
const tempDir = actionsUtil.getTemporaryDirectory();
const logFilePath = path.resolve(tempDir, "proxy.log");
const input = actionsUtil.getOptionalInput("registry_secrets") || "[]";
const credentials = JSON.parse(input) as Credential[];
const ca = generateCertificateAuthority();
const proxy_password = actionsUtil.getOptionalInput("proxy_password");
let proxy_auth: BasicAuthCredentials | undefined = undefined;
if (proxy_password) {
core.setSecret(proxy_password);
proxy_auth = {
username: PROXY_USER,
password: proxy_password,
};
}
const proxyConfig: ProxyConfig = {
all_credentials: credentials,
ca,
proxy_auth,
};
const host = "127.0.0.1";
const proxyBin = path.resolve(__dirname, "..", "bin", "update-job-proxy");
let port = 49152;
try {
let subprocess: ChildProcess | undefined = undefined;
let tries = 5;
let subprocessError: Error | undefined = undefined;
while (tries-- > 0 && !subprocess && !subprocessError) {
subprocess = spawn(
proxyBin,
["-addr", `${host}:${port}`, "-config", "-", "-logfile", logFilePath],
{
detached: true,
stdio: ["pipe", "ignore", "ignore"],
},
);
subprocess.unref();
if (subprocess.pid) {
core.saveState("proxy-process-pid", `${subprocess.pid}`);
}
subprocess.on("error", (error) => {
subprocessError = error;
});
subprocess.on("exit", (code) => {
if (code !== 0) {
port = Math.floor(Math.random() * (65535 - 49152) + 49152);
subprocess = undefined;
}
});
subprocess.stdin?.write(JSON.stringify(proxyConfig));
subprocess.stdin?.end();
// Wait a little to allow the proxy to start
await util.delay(1000);
}
if (subprocessError) {
throw subprocessError;
}
core.info(`Proxy started on ${host}:${port}`);
core.setOutput("proxy_host", host);
core.setOutput("proxy_port", port.toString());
core.setOutput("proxy_ca_certificate", ca.cert);
} catch (error) {
core.setFailed(
`start-proxy action failed: ${util.wrapError(error).message}`,
);
}
}
void runWrapper();

22
start-proxy/action.yml Normal file
View file

@ -0,0 +1,22 @@
name: "CodeQL: Start proxy"
description: "Start HTTP proxy server"
author: "GitHub"
inputs:
registry_secrets:
description: The URLs and credentials of package registries
required: false
default: "[]"
proxy_password:
required: false
description: The password of the proxy
outputs:
proxy_host:
description: The IP address of the proxy
proxy_port:
description: The port of the proxy
proxy_ca_certificate:
description: The proxy's internal CA certificate in PEM format
runs:
using: node20
main: "../lib/start-proxy-action.js"
post: "../lib/start-proxy-action-post.js"