combined windows and macos changes
This commit is contained in:
parent
e3f713f2d8
commit
ef9c6372b3
16 changed files with 130385 additions and 122113 deletions
12327
dist/index.js
vendored
12327
dist/index.js
vendored
File diff suppressed because one or more lines are too long
2
dist/index.js.map
vendored
2
dist/index.js.map
vendored
File diff suppressed because one or more lines are too long
12487
dist/post/index.js
vendored
12487
dist/post/index.js
vendored
File diff suppressed because one or more lines are too long
2
dist/post/index.js.map
vendored
2
dist/post/index.js.map
vendored
File diff suppressed because one or more lines are too long
2
dist/post/sourcemap-register.js
vendored
2
dist/post/sourcemap-register.js
vendored
File diff suppressed because one or more lines are too long
32481
dist/pre/index.js
vendored
32481
dist/pre/index.js
vendored
File diff suppressed because one or more lines are too long
2
dist/pre/index.js.map
vendored
2
dist/pre/index.js.map
vendored
File diff suppressed because one or more lines are too long
2
dist/pre/sourcemap-register.js
vendored
2
dist/pre/sourcemap-register.js
vendored
File diff suppressed because one or more lines are too long
2
dist/sourcemap-register.js
vendored
2
dist/sourcemap-register.js
vendored
File diff suppressed because one or more lines are too long
|
|
@ -10,12 +10,17 @@ const CHECKSUMS = {
|
||||||
non_tls: {
|
non_tls: {
|
||||||
amd64: "336093af8ebe969567b66fd035af3bd4f7e1c723ce680d6b4b5b2a1f79bc329e", // v0.14.2
|
amd64: "336093af8ebe969567b66fd035af3bd4f7e1c723ce680d6b4b5b2a1f79bc329e", // v0.14.2
|
||||||
},
|
},
|
||||||
|
darwin: "caaacc24bbf6a39ba7560e5e4701353c537883cb3ab9553359bd5caf5097246f", // v0.0.1
|
||||||
|
windows: {
|
||||||
|
amd64: "9e4fde66331be3261ae6ff954e531e94335b5774ac7e105f0126b391ee1c6d66", // v1.0.0-int
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export function verifyChecksum(
|
export function verifyChecksum(
|
||||||
downloadPath: string,
|
downloadPath: string,
|
||||||
isTLS: boolean,
|
isTLS: boolean,
|
||||||
variant: string
|
variant: string,
|
||||||
|
platform: string
|
||||||
) {
|
) {
|
||||||
const fileBuffer: Buffer = fs.readFileSync(downloadPath);
|
const fileBuffer: Buffer = fs.readFileSync(downloadPath);
|
||||||
const checksum: string = crypto
|
const checksum: string = crypto
|
||||||
|
|
@ -25,17 +30,28 @@ export function verifyChecksum(
|
||||||
|
|
||||||
let expectedChecksum: string = "";
|
let expectedChecksum: string = "";
|
||||||
|
|
||||||
if (isTLS) {
|
switch (platform) {
|
||||||
expectedChecksum = CHECKSUMS["tls"][variant];
|
case "linux":
|
||||||
} else {
|
expectedChecksum = isTLS
|
||||||
expectedChecksum = CHECKSUMS["non_tls"][variant];
|
? CHECKSUMS["tls"][variant]
|
||||||
|
: CHECKSUMS["non_tls"][variant];
|
||||||
|
break;
|
||||||
|
case "darwin":
|
||||||
|
expectedChecksum = CHECKSUMS["darwin"];
|
||||||
|
break;
|
||||||
|
case "win32":
|
||||||
|
expectedChecksum = CHECKSUMS["windows"][variant];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error(`Unsupported platform: ${platform}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (checksum !== expectedChecksum) {
|
if (checksum !== expectedChecksum) {
|
||||||
core.setFailed(
|
core.setFailed(
|
||||||
`Checksum verification failed, expected ${expectedChecksum} instead got ${checksum}`
|
`❌ Checksum verification failed, expected ${expectedChecksum} instead got ${checksum}`
|
||||||
);
|
);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
core.debug("Checksum verification passed.");
|
core.info(`✅ Checksum verification passed. checksum=${checksum}`);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
188
src/cleanup.ts
188
src/cleanup.ts
|
|
@ -1,10 +1,13 @@
|
||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
import * as cp from "child_process";
|
|
||||||
import * as common from "./common";
|
import * as common from "./common";
|
||||||
|
import * as cp from "child_process";
|
||||||
|
import * as path from "path";
|
||||||
import isDocker from "is-docker";
|
import isDocker from "is-docker";
|
||||||
import { isARCRunner } from "./arc-runner";
|
import { isARCRunner } from "./arc-runner";
|
||||||
import { isGithubHosted } from "./tls-inspect";
|
import { isGithubHosted } from "./tls-inspect";
|
||||||
import { context } from "@actions/github";
|
import { context } from "@actions/github";
|
||||||
|
import { isPlatformSupported } from "./utils";
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
console.log("[harden-runner] post-step");
|
console.log("[harden-runner] post-step");
|
||||||
|
|
||||||
|
|
@ -14,8 +17,8 @@ import { context } from "@actions/github";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process.platform !== "linux") {
|
if (!isPlatformSupported(process.platform)) {
|
||||||
console.log(common.UBUNTU_MESSAGE);
|
console.log(common.UNSUPPORTED_RUNNER_MESSAGE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (isGithubHosted() && isDocker()) {
|
if (isGithubHosted() && isDocker()) {
|
||||||
|
|
@ -36,10 +39,6 @@ import { context } from "@actions/github";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process.env.STATE_isTLS === "false" && process.arch === "arm64") {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
String(process.env.STATE_monitorStatusCode) ===
|
String(process.env.STATE_monitorStatusCode) ===
|
||||||
common.STATUS_HARDEN_RUNNER_UNAVAILABLE
|
common.STATUS_HARDEN_RUNNER_UNAVAILABLE
|
||||||
|
|
@ -48,6 +47,30 @@ import { context } from "@actions/github";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch (process.platform) {
|
||||||
|
case "linux":
|
||||||
|
await handleLinuxCleanup();
|
||||||
|
break;
|
||||||
|
case "win32":
|
||||||
|
await handleWindowsCleanup();
|
||||||
|
break;
|
||||||
|
case "darwin":
|
||||||
|
await handleMacosCleanup();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await common.addSummary();
|
||||||
|
} catch (exception) {
|
||||||
|
console.log(exception);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
|
async function handleLinuxCleanup() {
|
||||||
|
if (process.env.STATE_isTLS === "false" && process.arch === "arm64") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (isGithubHosted() && fs.existsSync("/home/agent/post_event.json")) {
|
if (isGithubHosted() && fs.existsSync("/home/agent/post_event.json")) {
|
||||||
console.log("Post step already executed, skipping");
|
console.log("Post step already executed, skipping");
|
||||||
return;
|
return;
|
||||||
|
|
@ -69,8 +92,8 @@ import { context } from "@actions/github";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
await sleep(1000);
|
await sleep(1000);
|
||||||
} // The file *does* exist
|
} else {
|
||||||
else {
|
// The file *does* exist
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -114,13 +137,152 @@ import { context } from "@actions/github";
|
||||||
console.log("Warning: Could not fetch service logs:", error.message);
|
console.log("Warning: Could not fetch service logs:", error.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleMacosCleanup() {
|
||||||
|
fs.writeFileSync(
|
||||||
|
"/opt/step-security/post_event.json",
|
||||||
|
JSON.stringify({ event: "post" })
|
||||||
|
);
|
||||||
|
|
||||||
|
let macDone = "/opt/step-security/done.json";
|
||||||
|
let counter = 0;
|
||||||
|
while (true) {
|
||||||
|
if (!fs.existsSync(macDone)) {
|
||||||
|
counter++;
|
||||||
|
if (counter > 10) {
|
||||||
|
console.log("timed out");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
await sleep(1000);
|
||||||
|
} else {
|
||||||
|
// The file *does* exist
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let macAgenLog = "/opt/step-security/agent.log";
|
||||||
|
if (fs.existsSync(macAgenLog)) {
|
||||||
|
console.log("macAgenLog:");
|
||||||
|
var content = fs.readFileSync(macAgenLog, "utf-8");
|
||||||
|
console.log(content);
|
||||||
|
} else {
|
||||||
|
console.log("😭 macos agent.log file not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Capture system log stream for harden-runner subsystem
|
||||||
|
try {
|
||||||
|
console.log("\nSystem log stream for io.stepsecurity.harden-runner:");
|
||||||
|
const logStreamOutput = cp.execSync(
|
||||||
|
"log show --predicate 'subsystem == \"io.stepsecurity.harden-runner\"' --info --last 10m",
|
||||||
|
{
|
||||||
|
encoding: "utf8",
|
||||||
|
maxBuffer: 1024 * 1024 * 10, // 10MB buffer
|
||||||
|
timeout: 10000, // 10 second timeout
|
||||||
|
}
|
||||||
|
);
|
||||||
|
console.log(logStreamOutput);
|
||||||
|
} catch (error) {
|
||||||
|
console.log("Warning: Could not fetch system log stream:", error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleWindowsCleanup() {
|
||||||
|
// windows cleanup
|
||||||
|
const agentDir = process.env.STATE_agentDir || "C:\\agent";
|
||||||
|
const postEventFile = path.join(agentDir, "post_event.json");
|
||||||
|
|
||||||
|
if (isGithubHosted() && fs.existsSync(postEventFile)) {
|
||||||
|
console.log("Windows post step already executed, skipping");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const p = cp.spawn(
|
||||||
|
"powershell.exe",
|
||||||
|
[
|
||||||
|
"-NoProfile",
|
||||||
|
"-NonInteractive",
|
||||||
|
"-Command",
|
||||||
|
"query user; exit $LASTEXITCODE",
|
||||||
|
],
|
||||||
|
{ stdio: ["ignore", "pipe", "pipe"], shell: false, windowsHide: true }
|
||||||
|
);
|
||||||
|
p.unref();
|
||||||
|
|
||||||
|
fs.writeFileSync(postEventFile, JSON.stringify({ event: "post" }));
|
||||||
|
|
||||||
|
const doneFile = path.join(agentDir, "done.json");
|
||||||
|
let counter = 0;
|
||||||
|
while (true) {
|
||||||
|
if (!fs.existsSync(doneFile)) {
|
||||||
|
counter++;
|
||||||
|
if (counter > 10) {
|
||||||
|
console.log("timed out");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
await sleep(1000);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("stopping windows agent process...");
|
||||||
|
const pidFile = path.join(agentDir, "agent.pid");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await common.addSummary();
|
if (!fs.existsSync(pidFile)) {
|
||||||
} catch (exception) {
|
console.log("PID file not found. Agent may not be running.");
|
||||||
console.log(exception);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pid = parseInt(fs.readFileSync(pidFile, "utf8").trim());
|
||||||
|
console.log(`agent PID from file: ${pid}`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
process.kill(pid, 0); // signal 0 just checks if process exists
|
||||||
|
} catch {
|
||||||
|
console.log("agent process not running.");
|
||||||
|
fs.unlinkSync(pidFile);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`stopping agent process (PID: ${pid})...`);
|
||||||
|
process.kill(pid, "SIGINT");
|
||||||
|
|
||||||
|
let gracefulShutdown = false;
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
await sleep(1000);
|
||||||
|
|
||||||
|
try {
|
||||||
|
process.kill(pid, 0); // check if still exists
|
||||||
|
} catch {
|
||||||
|
gracefulShutdown = true;
|
||||||
|
console.log("agent process stopped gracefully");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!gracefulShutdown) {
|
||||||
|
console.log("graceful shutdown timeout (10s), forcing termination...");
|
||||||
|
process.kill(pid, "SIGKILL");
|
||||||
|
console.log("agent process terminated forcefully");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fs.existsSync(pidFile)) {
|
||||||
|
fs.unlinkSync(pidFile);
|
||||||
|
console.log("PID file cleaned up");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log("warning: error stopping agent process:", error.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
const log = path.join(agentDir, "agent.log");
|
||||||
|
if (fs.existsSync(log)) {
|
||||||
|
console.log("agent log:");
|
||||||
|
const content = fs.readFileSync(log, "utf-8");
|
||||||
|
console.log(content);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})();
|
|
||||||
|
|
||||||
function sleep(ms) {
|
function sleep(ms) {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
|
|
|
||||||
|
|
@ -128,8 +128,8 @@ export const STATUS_HARDEN_RUNNER_UNAVAILABLE = "409";
|
||||||
export const CONTAINER_MESSAGE =
|
export const CONTAINER_MESSAGE =
|
||||||
"This job is running in a container. Such jobs can be monitored by installing Harden Runner in a custom VM image for GitHub-hosted runners.";
|
"This job is running in a container. Such jobs can be monitored by installing Harden Runner in a custom VM image for GitHub-hosted runners.";
|
||||||
|
|
||||||
export const UBUNTU_MESSAGE =
|
export const UNSUPPORTED_RUNNER_MESSAGE =
|
||||||
"This job is not running in a GitHub Actions Hosted Runner Ubuntu VM. Harden Runner is only supported on Ubuntu VM. This job will not be monitored.";
|
"This job is not running in a GitHub Actions Hosted Runner. Harden Runner is only supported on GitHub-hosted runners (Ubuntu, Windows, and macOS). This job will not be monitored.";
|
||||||
|
|
||||||
export const SELF_HOSTED_RUNNER_MESSAGE =
|
export const SELF_HOSTED_RUNNER_MESSAGE =
|
||||||
"This job is running on a self-hosted runner.";
|
"This job is running on a self-hosted runner.";
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@ import isDocker from "is-docker";
|
||||||
import { STEPSECURITY_WEB_URL } from "./configs";
|
import { STEPSECURITY_WEB_URL } from "./configs";
|
||||||
import { isGithubHosted } from "./tls-inspect";
|
import { isGithubHosted } from "./tls-inspect";
|
||||||
import { context } from "@actions/github";
|
import { context } from "@actions/github";
|
||||||
|
import { isPlatformSupported } from "./utils";
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
console.log("[harden-runner] main-step");
|
console.log("[harden-runner] main-step");
|
||||||
|
|
||||||
|
|
@ -13,8 +15,8 @@ import { context } from "@actions/github";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process.platform !== "linux") {
|
if (!isPlatformSupported(process.platform)) {
|
||||||
console.log(common.UBUNTU_MESSAGE);
|
console.log(common.UNSUPPORTED_RUNNER_MESSAGE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (isGithubHosted() && isDocker()) {
|
if (isGithubHosted() && isDocker()) {
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import * as fs from "fs";
|
||||||
import { verifyChecksum } from "./checksum";
|
import { verifyChecksum } from "./checksum";
|
||||||
import { EOL } from "os";
|
import { EOL } from "os";
|
||||||
import { ARM64_RUNNER_MESSAGE } from "./common";
|
import { ARM64_RUNNER_MESSAGE } from "./common";
|
||||||
|
import { chownForFolder } from "./utils";
|
||||||
|
|
||||||
export async function installAgent(
|
export async function installAgent(
|
||||||
isTLS: boolean,
|
isTLS: boolean,
|
||||||
|
|
@ -41,7 +42,7 @@ export async function installAgent(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
verifyChecksum(downloadPath, isTLS, variant);
|
verifyChecksum(downloadPath, isTLS, variant, "linux");
|
||||||
|
|
||||||
const extractPath = await tc.extractTar(downloadPath);
|
const extractPath = await tc.extractTar(downloadPath);
|
||||||
|
|
||||||
|
|
@ -65,3 +66,149 @@ export async function installAgent(
|
||||||
cp.execSync("sudo service agent start", { timeout: 15000 });
|
cp.execSync("sudo service agent start", { timeout: 15000 });
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function installMacosAgent(confgStr: string): Promise<boolean> {
|
||||||
|
const token = core.getInput("token", { required: true });
|
||||||
|
const auth = `token ${token}`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Create working directory
|
||||||
|
core.info("Creating /opt/step-security directory...");
|
||||||
|
cp.execSync("sudo mkdir -p /opt/step-security");
|
||||||
|
chownForFolder(process.env.USER, "/opt/step-security");
|
||||||
|
core.info("✓ Successfully created /opt/step-security directory");
|
||||||
|
|
||||||
|
// Create agent configuration file
|
||||||
|
core.info("Creating agent.json");
|
||||||
|
fs.writeFileSync("/opt/step-security/agent.json", confgStr);
|
||||||
|
core.info(
|
||||||
|
"✓ Successfully created agent.json at /opt/step-security/agent.json"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Download installer package
|
||||||
|
const downloadUrl =
|
||||||
|
"https://github.com/step-security/agent-releases/releases/download/v1.0.0-int/macos-installer-0.0.1.tar.gz";
|
||||||
|
core.info(`Downloading macOS installer.. : ${downloadUrl}`);
|
||||||
|
const downloadPath = await tc.downloadTool(downloadUrl, undefined, auth);
|
||||||
|
core.info(`✓ Successfully downloaded installer to: ${downloadPath}`);
|
||||||
|
|
||||||
|
// Verify SHA256 checksum
|
||||||
|
core.info("Verifying SHA256 checksum of downloaded tar file...");
|
||||||
|
verifyChecksum(downloadPath, false, "", "darwin");
|
||||||
|
|
||||||
|
// Extract installer package
|
||||||
|
core.info("Extracting installer...");
|
||||||
|
const extractPath = await tc.extractTar(downloadPath);
|
||||||
|
core.info(`✓ Successfully extracted installer to: ${extractPath}`);
|
||||||
|
|
||||||
|
// Copy Installer binary to /opt/step-security
|
||||||
|
const installerSourcePath = path.join(extractPath, "Installer");
|
||||||
|
core.info(
|
||||||
|
`Copying Installer from ${installerSourcePath} to /opt/step-security...`
|
||||||
|
);
|
||||||
|
cp.execSync(`cp "${installerSourcePath}" /opt/step-security/`);
|
||||||
|
core.info("✓ Successfully copied Installer to /opt/step-security");
|
||||||
|
|
||||||
|
const installerBinaryPath = "/opt/step-security/Installer";
|
||||||
|
|
||||||
|
// Verify installer binary exists
|
||||||
|
if (!fs.existsSync(installerBinaryPath)) {
|
||||||
|
throw new Error(
|
||||||
|
"Installer binary not found at /opt/step-security/Installer"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
core.info("✓ Installer binary verified");
|
||||||
|
|
||||||
|
// Make installer executable
|
||||||
|
core.info("Making installer executable...");
|
||||||
|
cp.execSync(`chmod +x "${installerBinaryPath}"`);
|
||||||
|
core.info("✓ Installer is now executable");
|
||||||
|
|
||||||
|
// Run installer
|
||||||
|
core.info("Running installer...");
|
||||||
|
cp.execSync(
|
||||||
|
`sudo "${installerBinaryPath}" -workdir /opt/step-security >> /opt/step-security/agent.log 2>&1`,
|
||||||
|
{
|
||||||
|
shell: "/bin/bash",
|
||||||
|
timeout: 10000, // 10 second timeout
|
||||||
|
}
|
||||||
|
);
|
||||||
|
core.info("✓ Installer completed successfully");
|
||||||
|
|
||||||
|
core.info("✅ macOS agent installation completed successfully");
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
core.error(`❌ Failed to install macOS agent: ${error}`);
|
||||||
|
if (error instanceof Error && error.stack) {
|
||||||
|
core.debug(error.stack);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function installWindowsAgent(configStr: string): Promise<boolean> {
|
||||||
|
const token = core.getInput("token", { required: true });
|
||||||
|
const auth = `token ${token}`;
|
||||||
|
|
||||||
|
const variant = process.arch === "x64" ? "amd64" : "arm64";
|
||||||
|
if (variant === "arm64") {
|
||||||
|
console.log(ARM64_RUNNER_MESSAGE);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const agentDir = "C:\\agent";
|
||||||
|
core.info(`Creating agent directory: ${agentDir}`);
|
||||||
|
if (!fs.existsSync(agentDir)) {
|
||||||
|
fs.mkdirSync(agentDir, { recursive: true });
|
||||||
|
}
|
||||||
|
fs.appendFileSync(process.env.GITHUB_STATE, `agentDir=${agentDir}${EOL}`, {
|
||||||
|
encoding: "utf8",
|
||||||
|
});
|
||||||
|
const agentExePath = path.join(agentDir, "agent.exe");
|
||||||
|
|
||||||
|
const downloadPath = await tc.downloadTool(
|
||||||
|
`https://github.com/step-security/agent-releases/releases/download/v1.0.0-int/harden-runner-agent-windows_int_windows_amd64.tar.gz`,
|
||||||
|
undefined,
|
||||||
|
auth
|
||||||
|
);
|
||||||
|
verifyChecksum(downloadPath, false, variant, process.platform);
|
||||||
|
|
||||||
|
const extractPath = await tc.extractTar(downloadPath);
|
||||||
|
|
||||||
|
const extractedAgentPath = path.join(extractPath, "agent.exe");
|
||||||
|
fs.copyFileSync(extractedAgentPath, agentExePath);
|
||||||
|
core.info(`Copied agent from ${extractedAgentPath} to ${agentExePath}`);
|
||||||
|
|
||||||
|
const configPath = path.join(agentDir, "config.json");
|
||||||
|
fs.writeFileSync(configPath, configStr);
|
||||||
|
core.info(`Created config file: ${configPath}`);
|
||||||
|
|
||||||
|
core.info("Starting Windows Agent...");
|
||||||
|
|
||||||
|
try {
|
||||||
|
const logPath = path.join(agentDir, "agent.log");
|
||||||
|
const logStream = fs.openSync(logPath, "a");
|
||||||
|
core.info(`Agent logs will be written to: ${logPath}`);
|
||||||
|
|
||||||
|
const agentProcess = cp.spawn(agentExePath, [], {
|
||||||
|
cwd: agentDir,
|
||||||
|
detached: true,
|
||||||
|
stdio: ["ignore", logStream, logStream],
|
||||||
|
windowsHide: false,
|
||||||
|
shell: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
const pidFile = path.join(agentDir, "agent.pid");
|
||||||
|
fs.writeFileSync(pidFile, agentProcess.pid.toString());
|
||||||
|
core.info(`Agent process started with PID: ${agentProcess.pid}`);
|
||||||
|
core.info(`PID saved to: ${pidFile}`);
|
||||||
|
|
||||||
|
agentProcess.unref();
|
||||||
|
|
||||||
|
core.info("Windows Agent process started successfully");
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
core.setFailed(`Failed to start Windows agent process: ${error.message}`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
57
src/setup.ts
57
src/setup.ts
|
|
@ -27,7 +27,13 @@ import * as utils from "@actions/cache/lib/internal/cacheUtils";
|
||||||
import { isARCRunner, sendAllowedEndpoints } from "./arc-runner";
|
import { isARCRunner, sendAllowedEndpoints } from "./arc-runner";
|
||||||
import { STEPSECURITY_API_URL, STEPSECURITY_WEB_URL } from "./configs";
|
import { STEPSECURITY_API_URL, STEPSECURITY_WEB_URL } from "./configs";
|
||||||
import { isGithubHosted, isTLSEnabled } from "./tls-inspect";
|
import { isGithubHosted, isTLSEnabled } from "./tls-inspect";
|
||||||
import { installAgent } from "./install-agent";
|
import {
|
||||||
|
installAgent,
|
||||||
|
installMacosAgent,
|
||||||
|
installWindowsAgent,
|
||||||
|
} from "./install-agent";
|
||||||
|
|
||||||
|
import { chownForFolder, isAgentInstalled, isPlatformSupported } from "./utils";
|
||||||
|
|
||||||
interface MonitorResponse {
|
interface MonitorResponse {
|
||||||
runner_ip_address?: string;
|
runner_ip_address?: string;
|
||||||
|
|
@ -45,8 +51,8 @@ interface MonitorResponse {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process.platform !== "linux") {
|
if (!isPlatformSupported(process.platform)) {
|
||||||
console.log(common.UBUNTU_MESSAGE);
|
console.log(common.UNSUPPORTED_RUNNER_MESSAGE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (isGithubHosted() && isDocker()) {
|
if (isGithubHosted() && isDocker()) {
|
||||||
|
|
@ -263,7 +269,7 @@ interface MonitorResponse {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isGithubHosted() && fs.existsSync("/home/agent/agent.status")) {
|
if (isGithubHosted() && isAgentInstalled(process.platform)) {
|
||||||
console.log("Agent already installed, skipping installation");
|
console.log("Agent already installed, skipping installation");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -322,17 +328,46 @@ interface MonitorResponse {
|
||||||
}
|
}
|
||||||
|
|
||||||
const confgStr = JSON.stringify(confg);
|
const confgStr = JSON.stringify(confg);
|
||||||
|
|
||||||
|
// platform specific
|
||||||
|
let statusFile = "";
|
||||||
|
let logFile = "";
|
||||||
|
let agentInstalled = false;
|
||||||
|
|
||||||
|
switch (process.platform) {
|
||||||
|
case "linux":
|
||||||
|
statusFile = "/home/agent/agent.status";
|
||||||
|
logFile = "/home/agent/agent.log";
|
||||||
|
|
||||||
cp.execSync("sudo mkdir -p /home/agent");
|
cp.execSync("sudo mkdir -p /home/agent");
|
||||||
chownForFolder(process.env.USER, "/home/agent");
|
chownForFolder(process.env.USER, "/home/agent");
|
||||||
|
|
||||||
let isTLS = await isTLSEnabled(context.repo.owner);
|
let isTLS = await isTLSEnabled(context.repo.owner);
|
||||||
|
agentInstalled = await installAgent(isTLS, confgStr);
|
||||||
|
|
||||||
const agentInstalled = await installAgent(isTLS, confgStr);
|
break;
|
||||||
|
case "win32":
|
||||||
|
core.info("Installing Windows Agent...");
|
||||||
|
agentInstalled = await installWindowsAgent(confgStr);
|
||||||
|
|
||||||
|
const agentDir = process.env.STATE_agentDir || "C:\\agent";
|
||||||
|
statusFile = path.join(agentDir, "agent.status");
|
||||||
|
logFile = path.join(agentDir, "agent.log");
|
||||||
|
|
||||||
|
break;
|
||||||
|
case "darwin":
|
||||||
|
const installed = await installMacosAgent(confgStr);
|
||||||
|
if (!installed) {
|
||||||
|
core.warning("😭 macos agent installation failed");
|
||||||
|
}
|
||||||
|
return; // early return
|
||||||
|
default:
|
||||||
|
throw new Error(
|
||||||
|
`Setup failed because of unsupported platform: ${process.platform}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (agentInstalled) {
|
if (agentInstalled) {
|
||||||
// Check that the file exists locally
|
|
||||||
var statusFile = "/home/agent/agent.status";
|
|
||||||
var logFile = "/home/agent/agent.log";
|
|
||||||
var counter = 0;
|
var counter = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
if (!fs.existsSync(statusFile)) {
|
if (!fs.existsSync(statusFile)) {
|
||||||
|
|
@ -367,9 +402,3 @@ export function sleep(ms: number) {
|
||||||
setTimeout(resolve, ms);
|
setTimeout(resolve, ms);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function chownForFolder(newOwner: string, target: string) {
|
|
||||||
let cmd = "sudo";
|
|
||||||
let args = ["chown", "-R", newOwner, target];
|
|
||||||
cp.execFileSync(cmd, args);
|
|
||||||
}
|
|
||||||
|
|
|
||||||
33
src/utils.ts
Normal file
33
src/utils.ts
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
import * as cp from "child_process";
|
||||||
|
import * as fs from "fs";
|
||||||
|
|
||||||
|
export function isPlatformSupported(platform: string) {
|
||||||
|
switch (platform) {
|
||||||
|
case "linux":
|
||||||
|
case "win32":
|
||||||
|
case "darwin":
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function chownForFolder(newOwner: string, target: string) {
|
||||||
|
let cmd = "sudo";
|
||||||
|
let args = ["chown", "-R", newOwner, target];
|
||||||
|
cp.execFileSync(cmd, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isAgentInstalled(platform: string) {
|
||||||
|
switch (platform) {
|
||||||
|
case "linux":
|
||||||
|
return fs.existsSync("/home/agent/agent.status");
|
||||||
|
case "win32":
|
||||||
|
return fs.existsSync("C:\\agent\\agent.status");
|
||||||
|
case "darwin":
|
||||||
|
return fs.existsSync("/opt/step-security/agent.status");
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue