Compare commits

...
Author SHA1 Message Date
Varun Sharma 35cd77bcf6 docs: document the Global Block List in the features list
The Global Block List shipped earlier but was never added to the README.
It applies to both the Community and Enterprise tiers, so it is listed
under Community (Free), which the Enterprise list already inherits.
2026-08-03 19:24:47 -07:00
Varun Sharma bb6dbef4bf chore: rebuild dist with clean dependency install
The bundle was previously built against a stale node_modules
(@actions/cache 4.0.3) instead of the lockfile version (4.1.0), so the
committed dist did not match a clean-install build and build-check
failed.
2026-08-03 09:29:25 -07:00
Varun Sharma 98f73c5a0d chore: update eBPF agent to v1.8.14
Bump the TLS and bravo agent downloads to agent-ebpf v1.8.14 and update
the corresponding SHA256 checksums. Non-TLS, macOS, and Windows agents
are unchanged.
2026-08-03 09:24:47 -07:00
Varun Sharma 54193c17a4 Reapply "feat(runners): detect AWS CodeBuild-hosted runners as third-party provider"
This reverts commit a3c333d110.
2026-07-29 08:01:48 -07:00
Varun Sharma d22dd481ce Revert "fix(self-hosted): flush agent events at job end when deploy-on-self-hosted-vm is used"
This reverts commit 0ff09412fb.
2026-07-29 08:01:38 -07:00
Varun Sharma 0ff09412fb fix(self-hosted): flush agent events at job end when deploy-on-self-hosted-vm is used
The post step exited early for all self-hosted runners, so an agent
deployed by the pre-step via deploy-on-self-hosted-vm never received the
job-end signal (post_event.json) and never flushed process and file
events. On ephemeral VMs such as AWS CodeBuild-hosted runners the VM is
destroyed right after the job, losing those events.

Record in GITHUB_STATE when the pre-step installs the agent on the VM
and run the same Linux cleanup as GitHub-hosted in that case. Persistent
self-hosted runners with a pre-installed agent keep the early exit.
2026-07-29 01:52:01 -07:00
Varun Sharma a3c333d110 Revert "feat(runners): detect AWS CodeBuild-hosted runners as third-party provider"
This reverts commit bf94c00d6b.
2026-07-29 01:49:47 -07:00
Varun Sharma bf94c00d6b feat(runners): detect AWS CodeBuild-hosted runners as third-party provider
CodeBuild-hosted runner VMs are ephemeral, so the persistent self-hosted
agent mode does not fit: its machine-scoped config carries no run_id or
one_time_key (process and file events are not attributed to the run) and
the post step exits without flushing events before the VM is destroyed.
Detect CODEBUILD_RUNNER_TYPE=GITHUB and route to the per-run bravo agent,
which reports run-scoped insights and flushes on job end.
2026-07-29 01:39:41 -07:00
Varun Sharma 514522c5e4 fix(self-hosted): resolve runner user when USER env var is unset
On AWS CodeBuild-hosted runners the Actions runner executes as root and
the USER environment variable is not set, so the self-hosted install
path ran 'sudo chown -R undefined /home/agent' and agent installation
failed silently. Resolve the user via os.userInfo() when USER is unset,
and skip the chown instead of failing when no user can be determined.
2026-07-29 01:31:37 -07:00
Varun Sharma bf7454d06d Merge pull request #673 from step-security/fix/aggregate-error-startup-hang
Release v2.20.0
2026-07-06 23:21:11 -10:00
12 changed files with 128 additions and 29 deletions
+1
View File
@@ -118,6 +118,7 @@ Harden-Runner offers a comprehensive suite of features to enhance the security o
- **Automated Baseline Creation:** Harden-Runner builds a baseline for each job based on past outbound network connections.
- **Anomaly Detection:** Once the baseline is created, any future outbound calls not in the baseline trigger a detection.
- **Block Network Egress Traffic with Domain Allowlist:** Optionally use the automatically created baseline to control outbound network traffic by specifying allowed domains, preventing unauthorized data exfiltration.
- **Global Block List:** Block known-malicious domains and IP addresses tied to active supply chain attacks, maintained by StepSecurity's 24x7 SOC. No configuration required, new indicators apply automatically without an action version bump, and it is enforced even in `egress-policy: audit` mode.
- **Detect Modification of Source Code:** Monitor and alert on unauthorized changes to your source code during the CI/CD pipeline.
### Enterprise (Paid)
+23
View File
@@ -31880,9 +31880,12 @@ var lib_core = __nccwpck_require__(7484);
var external_child_process_ = __nccwpck_require__(5317);
// EXTERNAL MODULE: external "fs"
var external_fs_ = __nccwpck_require__(9896);
// EXTERNAL MODULE: external "os"
var external_os_ = __nccwpck_require__(857);
;// CONCATENATED MODULE: ./src/utils.ts
function isPlatformSupported(platform) {
switch (platform) {
case "linux":
@@ -31893,7 +31896,25 @@ function isPlatformSupported(platform) {
return false;
}
}
// Resolves the user the runner process is executing as. Some runner
// environments (e.g. AWS CodeBuild-hosted runners) do not set the USER
// environment variable.
function getRunnerUser() {
if (process.env.USER) {
return process.env.USER;
}
try {
return os.userInfo().username;
}
catch (_a) {
return undefined;
}
}
function chownForFolder(newOwner, target) {
if (!newOwner) {
console.log(`Unable to determine runner user; skipping chown of ${target}`);
return;
}
let cmd = "sudo";
let args = ["chown", "-R", newOwner, target];
cp.execFileSync(cmd, args);
@@ -31921,6 +31942,8 @@ function detectThirdPartyRunnerProvider() {
return "namespace";
if (process.env["BITRISE_IO"])
return "bitrise";
if (process.env["CODEBUILD_RUNNER_TYPE"] === "GITHUB")
return "codebuild";
const runnerName = (_a = process.env["RUNNER_NAME"]) !== null && _a !== void 0 ? _a : "";
if (runnerName.startsWith("warp-"))
return "warp";
+1 -1
View File
File diff suppressed because one or more lines are too long
+23
View File
@@ -31886,9 +31886,12 @@ const STEPSECURITY_WEB_URL = "https://app.stepsecurity.io";
// EXTERNAL MODULE: external "child_process"
var external_child_process_ = __nccwpck_require__(5317);
// EXTERNAL MODULE: external "os"
var external_os_ = __nccwpck_require__(857);
;// CONCATENATED MODULE: ./src/utils.ts
function isPlatformSupported(platform) {
switch (platform) {
case "linux":
@@ -31899,7 +31902,25 @@ function isPlatformSupported(platform) {
return false;
}
}
// Resolves the user the runner process is executing as. Some runner
// environments (e.g. AWS CodeBuild-hosted runners) do not set the USER
// environment variable.
function getRunnerUser() {
if (process.env.USER) {
return process.env.USER;
}
try {
return os.userInfo().username;
}
catch (_a) {
return undefined;
}
}
function chownForFolder(newOwner, target) {
if (!newOwner) {
console.log(`Unable to determine runner user; skipping chown of ${target}`);
return;
}
let cmd = "sudo";
let args = ["chown", "-R", newOwner, target];
cp.execFileSync(cmd, args);
@@ -31927,6 +31948,8 @@ function detectThirdPartyRunnerProvider() {
return "namespace";
if (process.env["BITRISE_IO"])
return "bitrise";
if (process.env["CODEBUILD_RUNNER_TYPE"] === "GITHUB")
return "codebuild";
const runnerName = (_a = process.env["RUNNER_NAME"]) !== null && _a !== void 0 ? _a : "";
if (runnerName.startsWith("warp-"))
return "warp";
+1 -1
View File
File diff suppressed because one or more lines are too long
+33 -12
View File
@@ -85078,9 +85078,12 @@ const validate = dist/* validate */.tf;
const stringify = dist/* stringify */.As;
const parse = dist/* parse */.qg;
// EXTERNAL MODULE: external "os"
var external_os_ = __nccwpck_require__(857);
;// CONCATENATED MODULE: ./src/utils.ts
function isPlatformSupported(platform) {
switch (platform) {
case "linux":
@@ -85091,7 +85094,25 @@ function isPlatformSupported(platform) {
return false;
}
}
// Resolves the user the runner process is executing as. Some runner
// environments (e.g. AWS CodeBuild-hosted runners) do not set the USER
// environment variable.
function getRunnerUser() {
if (process.env.USER) {
return process.env.USER;
}
try {
return external_os_.userInfo().username;
}
catch (_a) {
return undefined;
}
}
function chownForFolder(newOwner, target) {
if (!newOwner) {
console.log(`Unable to determine runner user; skipping chown of ${target}`);
return;
}
let cmd = "sudo";
let args = ["chown", "-R", newOwner, target];
external_child_process_.execFileSync(cmd, args);
@@ -85119,6 +85140,8 @@ function detectThirdPartyRunnerProvider() {
return "namespace";
if (process.env["BITRISE_IO"])
return "bitrise";
if (process.env["CODEBUILD_RUNNER_TYPE"] === "GITHUB")
return "codebuild";
const runnerName = (_a = process.env["RUNNER_NAME"]) !== null && _a !== void 0 ? _a : "";
if (runnerName.startsWith("warp-"))
return "warp";
@@ -85285,8 +85308,6 @@ function isDocker() {
// EXTERNAL MODULE: ./node_modules/@actions/github/lib/github.js
var github = __nccwpck_require__(3228);
// EXTERNAL MODULE: external "os"
var external_os_ = __nccwpck_require__(857);
;// CONCATENATED MODULE: ./src/cache.ts
const cacheKey = "harden-runner-cacheKey";
const cacheFile = "/home/agent/cache.txt";
@@ -85543,15 +85564,15 @@ var external_crypto_ = __nccwpck_require__(6982);
const CHECKSUMS = {
tls: {
amd64: "a54c4305b5665ba54bfdc46eb32aee1758699b994550ca3658d698367cc96a3f", // v1.8.12
arm64: "3f401d508e1427b9ba205681d5abecde3b4a0f0a18542d198b6dc14cadd93ab5", // v1.8.12
amd64: "47c42675bce38c6ab7c4dcba90f009c8567f491bc71ecf492f4ef1876c300700", // v1.8.14
arm64: "9aed5e0a4a97ad019f943087dee6b7bd6ace340b06c6faba5615927b9a50a7d4", // v1.8.14
},
non_tls: {
amd64: "4b14d8a3a5fbcef95af55e0c54d3bee6f44da802878c10289a4ca0b79b6d0237", // v0.16.2
},
bravo: {
amd64: "c986d0a19637325c9a8d4a331a6c4ed047e4cddb798f56b641d0e66f8bf9b1b2", // v1.8.12
arm64: "5c3df17f82e317c8b288dfbbcee449c2a24a80deeeb3416dccabd0a61982c676", // v1.8.12
amd64: "83d8189320edc26085e3fefc3682db231e778b563d2f22bc7bf7c339a9562aab", // v1.8.14
arm64: "1d9813cdf3684339c542f9342805a173c457af1860b98da66b7672918e121434", // v1.8.14
},
darwin: "2990f0390d2760fa6262a3830060b6db1233f16a1410ffe1ed2bf13dfda80c38", // v0.0.6
windows: {
@@ -85624,7 +85645,7 @@ function installAgent(isTLS, configStr) {
encoding: "utf8",
});
if (isTLS) {
downloadPath = yield tool_cache.downloadTool(`https://github.com/step-security/agent-ebpf/releases/download/v1.8.12/harden-runner_1.8.12_linux_${variant}.tar.gz`, undefined, auth);
downloadPath = yield tool_cache.downloadTool(`https://github.com/step-security/agent-ebpf/releases/download/v1.8.14/harden-runner_1.8.14_linux_${variant}.tar.gz`, undefined, auth);
}
else {
if (variant === "arm64") {
@@ -85659,7 +85680,7 @@ function installAgentBravo(configStr) {
const token = lib_core.getInput("token", { required: true });
const auth = `token ${token}`;
const variant = process.arch === "x64" ? "amd64" : "arm64";
const downloadPath = yield tool_cache.downloadTool(`https://github.com/step-security/agent-ebpf/releases/download/v1.8.12/harden-runner-bravo_1.8.12_linux_${variant}.tar.gz`, undefined, auth);
const downloadPath = yield tool_cache.downloadTool(`https://github.com/step-security/agent-ebpf/releases/download/v1.8.14/harden-runner-bravo_1.8.14_linux_${variant}.tar.gz`, undefined, auth);
if (!verifyChecksum(downloadPath, true, variant, "linux", "bravo")) {
return false;
}
@@ -85706,7 +85727,7 @@ function installMacosAgent(configStr) {
// Create working directory
lib_core.info("Creating /opt/step-security directory...");
external_child_process_.execSync("sudo mkdir -p /opt/step-security");
chownForFolder(process.env.USER, "/opt/step-security");
chownForFolder(getRunnerUser(), "/opt/step-security");
lib_core.info("✓ Successfully created /opt/step-security directory");
// Create agent configuration file
lib_core.info("Creating agent.json");
@@ -86208,7 +86229,7 @@ process.on("unhandledRejection", (reason) => {
statusFile = "/home/agent/agent.status";
logFile = "/home/agent/agent.log";
external_child_process_.execSync("sudo mkdir -p /home/agent");
chownForFolder(process.env.USER, "/home/agent");
chownForFolder(getRunnerUser(), "/home/agent");
let isTLS = yield isTLSEnabled(github.context.repo.owner);
agentInstalled = yield installAgent(isTLS, configStr);
break;
@@ -86319,7 +86340,7 @@ function installAgentForSelfHosted(owner, confg) {
};
const selfHostedConfigStr = JSON.stringify(selfHostedConfig);
external_child_process_.execSync("sudo mkdir -p /home/agent");
chownForFolder(process.env.USER, "/home/agent");
chownForFolder(getRunnerUser(), "/home/agent");
const agentInstalled = yield installAgent(isTLS, selfHostedConfigStr);
if (agentInstalled) {
const statusFile = "/home/agent/agent.status";
@@ -86361,7 +86382,7 @@ function installAgentForBravo(owner, bravoConfigStr) {
return;
}
external_child_process_.execSync("sudo mkdir -p /home/agent");
chownForFolder(process.env.USER, "/home/agent");
chownForFolder(getRunnerUser(), "/home/agent");
yield installAgentBravo(bravoConfigStr);
}
catch (error) {
+1 -1
View File
File diff suppressed because one or more lines are too long
+4 -4
View File
@@ -4,15 +4,15 @@ import * as fs from "fs";
export const CHECKSUMS = {
tls: {
amd64: "a54c4305b5665ba54bfdc46eb32aee1758699b994550ca3658d698367cc96a3f", // v1.8.12
arm64: "3f401d508e1427b9ba205681d5abecde3b4a0f0a18542d198b6dc14cadd93ab5", // v1.8.12
amd64: "47c42675bce38c6ab7c4dcba90f009c8567f491bc71ecf492f4ef1876c300700", // v1.8.14
arm64: "9aed5e0a4a97ad019f943087dee6b7bd6ace340b06c6faba5615927b9a50a7d4", // v1.8.14
},
non_tls: {
amd64: "4b14d8a3a5fbcef95af55e0c54d3bee6f44da802878c10289a4ca0b79b6d0237", // v0.16.2
},
bravo: {
amd64: "c986d0a19637325c9a8d4a331a6c4ed047e4cddb798f56b641d0e66f8bf9b1b2", // v1.8.12
arm64: "5c3df17f82e317c8b288dfbbcee449c2a24a80deeeb3416dccabd0a61982c676", // v1.8.12
amd64: "83d8189320edc26085e3fefc3682db231e778b563d2f22bc7bf7c339a9562aab", // v1.8.14
arm64: "1d9813cdf3684339c542f9342805a173c457af1860b98da66b7672918e121434", // v1.8.14
},
darwin: "2990f0390d2760fa6262a3830060b6db1233f16a1410ffe1ed2bf13dfda80c38", // v0.0.6
windows: {
+4 -4
View File
@@ -6,7 +6,7 @@ import * as fs from "fs";
import { verifyChecksum } from "./checksum";
import { EOL } from "os";
import { ARM64_RUNNER_MESSAGE, ARM64_WINDOWS_RUNNER_MESSAGE } from "./common";
import { chownForFolder } from "./utils";
import { chownForFolder, getRunnerUser } from "./utils";
export async function installAgent(
isTLS: boolean,
@@ -26,7 +26,7 @@ export async function installAgent(
if (isTLS) {
downloadPath = await tc.downloadTool(
`https://github.com/step-security/agent-ebpf/releases/download/v1.8.12/harden-runner_1.8.12_linux_${variant}.tar.gz`,
`https://github.com/step-security/agent-ebpf/releases/download/v1.8.14/harden-runner_1.8.14_linux_${variant}.tar.gz`,
undefined,
auth
);
@@ -76,7 +76,7 @@ export async function installAgentBravo(configStr: string): Promise<boolean> {
const variant = process.arch === "x64" ? "amd64" : "arm64";
const downloadPath = await tc.downloadTool(
`https://github.com/step-security/agent-ebpf/releases/download/v1.8.12/harden-runner-bravo_1.8.12_linux_${variant}.tar.gz`,
`https://github.com/step-security/agent-ebpf/releases/download/v1.8.14/harden-runner-bravo_1.8.14_linux_${variant}.tar.gz`,
undefined,
auth
);
@@ -131,7 +131,7 @@ export async function installMacosAgent(configStr: string): Promise<boolean> {
// 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");
chownForFolder(getRunnerUser(), "/opt/step-security");
core.info("✓ Successfully created /opt/step-security directory");
// Create agent configuration file
+4 -4
View File
@@ -37,7 +37,7 @@ import {
installWindowsAgent,
} from "./install-agent";
import { chownForFolder, detectThirdPartyRunnerProvider, isAgentInstalled, isPlatformSupported, shouldDeployAgentOnSelfHosted } from "./utils";
import { chownForFolder, getRunnerUser, detectThirdPartyRunnerProvider, isAgentInstalled, isPlatformSupported, shouldDeployAgentOnSelfHosted } from "./utils";
import { buildBravoConfig } from "./bravo-config";
interface MonitorResponse {
@@ -455,7 +455,7 @@ process.on("unhandledRejection", (reason) => {
logFile = "/home/agent/agent.log";
cp.execSync("sudo mkdir -p /home/agent");
chownForFolder(process.env.USER, "/home/agent");
chownForFolder(getRunnerUser(), "/home/agent");
let isTLS = await isTLSEnabled(context.repo.owner);
agentInstalled = await installAgent(isTLS, configStr);
@@ -575,7 +575,7 @@ export async function installAgentForSelfHosted(owner: string, confg: Configurat
const selfHostedConfigStr = JSON.stringify(selfHostedConfig);
cp.execSync("sudo mkdir -p /home/agent");
chownForFolder(process.env.USER, "/home/agent");
chownForFolder(getRunnerUser(), "/home/agent");
const agentInstalled = await installAgent(isTLS, selfHostedConfigStr);
@@ -619,7 +619,7 @@ export async function installAgentForBravo(owner: string, bravoConfigStr: string
}
cp.execSync("sudo mkdir -p /home/agent");
chownForFolder(process.env.USER, "/home/agent");
chownForFolder(getRunnerUser(), "/home/agent");
await installAgentBravo(bravoConfigStr);
} catch (error) {
+11
View File
@@ -99,6 +99,7 @@ describe("detectThirdPartyRunnerProvider", () => {
delete process.env.DEPOT_RUNNER;
delete process.env.NAMESPACE_GITHUB_RUNTIME;
delete process.env.BITRISE_IO;
delete process.env.CODEBUILD_RUNNER_TYPE;
delete process.env.RUNNER_NAME;
});
@@ -126,6 +127,16 @@ describe("detectThirdPartyRunnerProvider", () => {
expect(detectThirdPartyRunnerProvider()).toBe("bitrise");
});
test("returns codebuild when CODEBUILD_RUNNER_TYPE=GITHUB", () => {
process.env.CODEBUILD_RUNNER_TYPE = "GITHUB";
expect(detectThirdPartyRunnerProvider()).toBe("codebuild");
});
test("returns null when CODEBUILD_RUNNER_TYPE has a non-GITHUB value", () => {
process.env.CODEBUILD_RUNNER_TYPE = "OTHER";
expect(detectThirdPartyRunnerProvider()).toBeNull();
});
test("returns warp for RUNNER_NAME prefix warp-", () => {
process.env.RUNNER_NAME = "warp-4x-x64-abc";
expect(detectThirdPartyRunnerProvider()).toBe("warp");
+22 -2
View File
@@ -1,5 +1,6 @@
import * as cp from "child_process";
import * as fs from "fs";
import * as os from "os";
export function isPlatformSupported(platform: NodeJS.Platform) {
switch (platform) {
@@ -13,7 +14,25 @@ export function isPlatformSupported(platform: NodeJS.Platform) {
}
}
export function chownForFolder(newOwner: string, target: string) {
// Resolves the user the runner process is executing as. Some runner
// environments (e.g. AWS CodeBuild-hosted runners) do not set the USER
// environment variable.
export function getRunnerUser(): string | undefined {
if (process.env.USER) {
return process.env.USER;
}
try {
return os.userInfo().username;
} catch {
return undefined;
}
}
export function chownForFolder(newOwner: string | undefined, target: string) {
if (!newOwner) {
console.log(`Unable to determine runner user; skipping chown of ${target}`);
return;
}
let cmd = "sudo";
let args = ["chown", "-R", newOwner, target];
cp.execFileSync(cmd, args);
@@ -40,12 +59,13 @@ export function shouldDeployAgentOnSelfHosted(
return deployOnSelfHostedVm && !isContainer && !agentAlreadyInstalled;
}
export type ThirdPartyRunnerProvider = "depot" | "namespace" | "warp" | "blacksmith" | "bitrise";
export type ThirdPartyRunnerProvider = "depot" | "namespace" | "warp" | "blacksmith" | "bitrise" | "codebuild";
export function detectThirdPartyRunnerProvider(): ThirdPartyRunnerProvider | null {
if (process.env["DEPOT_RUNNER"] === "1") return "depot";
if (process.env["NAMESPACE_GITHUB_RUNTIME"]) return "namespace";
if (process.env["BITRISE_IO"]) return "bitrise";
if (process.env["CODEBUILD_RUNNER_TYPE"] === "GITHUB") return "codebuild";
const runnerName = process.env["RUNNER_NAME"] ?? "";
if (runnerName.startsWith("warp-")) return "warp";
if (runnerName.startsWith("blacksmith-")) return "blacksmith";