1
0
Fork 0
mirror of synced 2026-06-05 17:18:19 +00:00

Compare commits

...

8 commits

Author SHA1 Message Date
Varun Sharma
4ff48025a8
Merge pull request #632 from h0x0er/macos
Add agent-maocs installer
2026-01-29 17:04:49 -08:00
Jatin
6ddaf38701
reverted formatting 2026-01-29 19:59:25 +05:30
Jatin
6b1c98f1d2
refactor: reduced wait to 10sec and fixed a log 2026-01-29 17:40:26 +05:30
Jatin
0b4d9af9ef
refactor: fixed checksum key 2026-01-29 17:31:34 +05:30
Jatin
4dd31d13de
refactor: simplified cleanup and added checksum verification 2026-01-29 17:27:45 +05:30
Jatin
8a6170d7ba
refactor: use agent 0.0.1 2026-01-29 13:58:34 +05:30
Jatin
a6f64cd1a2
build changes 2026-01-29 13:50:45 +05:30
Jatin
3559266854
added maco agent installer 2026-01-29 13:50:24 +05:30
14 changed files with 129922 additions and 122099 deletions

12401
dist/index.js vendored

File diff suppressed because one or more lines are too long

2
dist/index.js.map vendored

File diff suppressed because one or more lines are too long

12594
dist/post/index.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

32539
dist/pre/index.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -10,12 +10,14 @@ const CHECKSUMS = {
non_tls: { non_tls: {
amd64: "336093af8ebe969567b66fd035af3bd4f7e1c723ce680d6b4b5b2a1f79bc329e", // v0.14.2 amd64: "336093af8ebe969567b66fd035af3bd4f7e1c723ce680d6b4b5b2a1f79bc329e", // v0.14.2
}, },
darwin: "caaacc24bbf6a39ba7560e5e4701353c537883cb3ab9553359bd5caf5097246f", // v0.0.1
}; };
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 +27,25 @@ 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;
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}`);
} }

View file

@ -14,9 +14,14 @@ import { context } from "@actions/github";
return; return;
} }
if (process.platform !== "linux") { let platform = process.platform;
console.log(common.UBUNTU_MESSAGE); switch (platform) {
return; case "linux":
case "darwin":
break;
default:
console.log(common.UBUNTU_MESSAGE);
return;
} }
if (isGithubHosted() && isDocker()) { if (isGithubHosted() && isDocker()) {
console.log(common.CONTAINER_MESSAGE); console.log(common.CONTAINER_MESSAGE);
@ -28,6 +33,72 @@ import { context } from "@actions/github";
return; return;
} }
switch (platform) {
case "darwin":
await handleDarwinCleanup();
break;
case "linux":
await handleLinuxCleanup();
break;
}
try {
await common.addSummary();
} catch (exception) {
console.log(exception);
}
})();
async function handleDarwinCleanup() {
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, // 30 second timeout
}
);
console.log(logStreamOutput);
} catch (error) {
console.log("Warning: Could not fetch system log stream:", error.message);
}
}
async function handleLinuxCleanup() {
if (process.env.STATE_selfHosted === "true") { if (process.env.STATE_selfHosted === "true") {
return; return;
} }
@ -65,12 +136,11 @@ import { context } from "@actions/github";
counter++; counter++;
if (counter > 10) { if (counter > 10) {
console.log("timed out"); console.log("timed out");
break; break;
} }
await sleep(1000); await sleep(1000);
} // The file *does* exist } else {
else { // The file *does* exist
break; break;
} }
} }
@ -114,13 +184,7 @@ 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);
} }
} }
}
try {
await common.addSummary();
} catch (exception) {
console.log(exception);
}
})();
function sleep(ms) { function sleep(ms) {
return new Promise((resolve) => { return new Promise((resolve) => {

View file

@ -1,5 +1,6 @@
import * as core from "@actions/core"; import * as core from "@actions/core";
import * as fs from "fs"; import * as fs from "fs";
import * as cp from "child_process";
import { STEPSECURITY_API_URL, STEPSECURITY_WEB_URL } from "./configs"; import { STEPSECURITY_API_URL, STEPSECURITY_WEB_URL } from "./configs";
export function printInfo(web_url) { export function printInfo(web_url) {
@ -64,7 +65,6 @@ export async function addSummary() {
return; return;
} }
let needsSubscription = false; let needsSubscription = false;
try { try {
let data = fs.readFileSync("/home/agent/annotation.log", "utf8"); let data = fs.readFileSync("/home/agent/annotation.log", "utf8");
@ -97,23 +97,21 @@ export async function addSummary() {
// Extract owner and repo from GITHUB_REPOSITORY (format: owner/repo) // Extract owner and repo from GITHUB_REPOSITORY (format: owner/repo)
const [owner, repo] = process.env["GITHUB_REPOSITORY"]?.split("/") || []; const [owner, repo] = process.env["GITHUB_REPOSITORY"]?.split("/") || [];
const run_id = process.env["GITHUB_RUN_ID"]; const run_id = process.env["GITHUB_RUN_ID"];
if (!owner || !repo || !run_id || !correlation_id) { if (!owner || !repo || !run_id || !correlation_id) {
return; return;
} }
// Fetch job summary from API // Fetch job summary from API
const apiUrl = `${STEPSECURITY_API_URL}/github/${owner}/${repo}/actions/runs/${run_id}/correlation/${correlation_id}/job-markdown-summary`; const apiUrl = `${STEPSECURITY_API_URL}/github/${owner}/${repo}/actions/runs/${run_id}/correlation/${correlation_id}/job-markdown-summary`;
try { try {
const response = await fetch(apiUrl); const response = await fetch(apiUrl);
if (!response.ok) { if (!response.ok) {
console.error(`Failed to fetch job summary: ${response.status} ${response.statusText}`); console.error(`Failed to fetch job summary: ${response.status} ${response.statusText}`);
return; return;
} }
const markdownSummary = await response.text(); const markdownSummary = await response.text();
// Render the markdown summary using core.summary.addRaw // Render the markdown summary using core.summary.addRaw
await core.summary.addRaw(markdownSummary).write(); await core.summary.addRaw(markdownSummary).write();
return; return;
@ -123,6 +121,12 @@ export async function addSummary() {
} }
} }
export function chownForFolder(newOwner: string, target: string) {
let cmd = "sudo";
let args = ["chown", "-R", newOwner, target];
cp.execFileSync(cmd, args);
}
export const STATUS_HARDEN_RUNNER_UNAVAILABLE = "409"; export const STATUS_HARDEN_RUNNER_UNAVAILABLE = "409";
export const CONTAINER_MESSAGE = export const CONTAINER_MESSAGE =

View file

@ -5,7 +5,7 @@ import * as path from "path";
import * as fs from "fs"; 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, chownForFolder } from "./common";
export async function installAgent( export async function installAgent(
isTLS: boolean, isTLS: boolean,
@ -41,7 +41,7 @@ export async function installAgent(
); );
} }
verifyChecksum(downloadPath, isTLS, variant); verifyChecksum(downloadPath, isTLS, variant, process.platform);
const extractPath = await tc.extractTar(downloadPath); const extractPath = await tc.extractTar(downloadPath);
@ -65,3 +65,82 @@ 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);
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;
}
}

View file

@ -27,7 +27,7 @@ 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 } from "./install-agent";
interface MonitorResponse { interface MonitorResponse {
runner_ip_address?: string; runner_ip_address?: string;
@ -45,10 +45,16 @@ interface MonitorResponse {
return; return;
} }
if (process.platform !== "linux") { let platform = process.platform;
console.log(common.UBUNTU_MESSAGE); switch (platform) {
return; case "linux":
case "darwin":
break;
default:
console.log(common.UBUNTU_MESSAGE);
return;
} }
if (isGithubHosted() && isDocker()) { if (isGithubHosted() && isDocker()) {
console.log(common.CONTAINER_MESSAGE); console.log(common.CONTAINER_MESSAGE);
return; return;
@ -94,13 +100,15 @@ interface MonitorResponse {
// Only fail the job if ID token is not available // Only fail the job if ID token is not available
if (err.message && err.message.includes('Unable to get ACTIONS_ID_TOKEN_REQUEST')) { if (err.message && err.message.includes('Unable to get ACTIONS_ID_TOKEN_REQUEST')) {
core.setFailed('Policy store requires id-token write permission as it uses OIDC to fetch the policy from StepSecurity API. Please add "id-token: write" to your job permissions.'); core.setFailed('Policy store requires id-token write permission as it uses OIDC to fetch the policy from StepSecurity API. Please add "id-token: write" to your job permissions.');
} else { } else {
// Handle different HTTP status codes // Handle different HTTP status codes
if (err.statusCode >= 400 && err.statusCode < 500) { if (err.statusCode >= 400 && err.statusCode < 500) {
core.error('Policy not found'); core.error('Policy not found');
} else { } else {
core.error(`Unexpected error occurred: ${err}. Falling back to egress policy audit`); core.error(
confg.egress_policy = 'audit'; `Unexpected error occurred: ${err}. Falling back to egress policy audit`
);
confg.egress_policy = "audit";
} }
} }
} }
@ -322,39 +330,51 @@ interface MonitorResponse {
} }
const confgStr = JSON.stringify(confg); const confgStr = JSON.stringify(confg);
cp.execSync("sudo mkdir -p /home/agent");
chownForFolder(process.env.USER, "/home/agent");
let isTLS = await isTLSEnabled(context.repo.owner); switch (platform) {
case "linux":
cp.execSync("sudo mkdir -p /home/agent");
common.chownForFolder(process.env.USER, "/home/agent");
const agentInstalled = await installAgent(isTLS, confgStr); let isTLS = await isTLSEnabled(context.repo.owner);
if (agentInstalled) { const agentInstalled = await installAgent(isTLS, confgStr);
// Check that the file exists locally
var statusFile = "/home/agent/agent.status"; if (agentInstalled) {
var logFile = "/home/agent/agent.log"; // Check that the file exists locally
var counter = 0; var statusFile = "/home/agent/agent.status";
while (true) { var logFile = "/home/agent/agent.log";
if (!fs.existsSync(statusFile)) { var counter = 0;
counter++; while (true) {
if (counter > 30) { if (!fs.existsSync(statusFile)) {
console.log("timed out"); counter++;
if (fs.existsSync(logFile)) { if (counter > 30) {
var content = fs.readFileSync(logFile, "utf-8"); console.log("timed out");
if (fs.existsSync(logFile)) {
var content = fs.readFileSync(logFile, "utf-8");
console.log(content);
}
break;
}
await sleep(300);
} // The file *does* exist
else {
// Read the file
var content = fs.readFileSync(statusFile, "utf-8");
console.log(content); console.log(content);
break;
} }
break;
} }
await sleep(300);
} // The file *does* exist
else {
// Read the file
var content = fs.readFileSync(statusFile, "utf-8");
console.log(content);
break;
} }
}
case "darwin":
const installed = await installMacosAgent(confgStr);
if (!installed) {
core.warning("😭 macos agent installation failed");
return;
}
} }
} catch (error) { } catch (error) {
core.setFailed(error.message); core.setFailed(error.message);
} }
@ -367,9 +387,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);
}