Release v2.4.1 (#309)

This commit is contained in:
Varun Sharma 2023-06-19 17:30:27 -07:00 committed by GitHub
commit 55d479fb1c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 496 additions and 86 deletions

View file

@ -113,7 +113,7 @@ GitHub-hosted runner uses passwordless sudo for running jobs.
### 🔔 Get security alerts
Install the [Harden Runner App](https://github.com/marketplace/harden-runner-app) to get security alerts.
Install the [StepSecurity Actions Security GitHub App](https://github.com/apps/stepsecurity-actions-security) to get security alerts.
- Email and Slack notifications are supported
- Notifications are sent when outbound traffic is blocked or source code is overwritten
@ -123,11 +123,11 @@ Install the [Harden Runner App](https://github.com/marketplace/harden-runner-app
Private repositories are supported if they have a commercial license. Check out the [documentation](https://docs.stepsecurity.io/harden-runner/installation/business-enterprise-license) for more details.
Install the [Harden Runner App](https://github.com/marketplace/harden-runner-app) to use Harden-Runner GitHub Action for `Private` repositories.
Install the [StepSecurity Actions Security GitHub App](https://github.com/apps/stepsecurity-actions-security) to use Harden-Runner GitHub Action for `Private` repositories.
- If you use Harden-Runner GitHub Action in a private repository, the generated insights URL is NOT public.
- You need to authenticate first to access insights URL for private repository. Only those who have access to the repository can view it.
- [Harden Runner App](https://github.com/marketplace/harden-runner-app) only needs `actions: read` permissions on your repositories.
- [StepSecurity Actions Security GitHub App](https://github.com/apps/stepsecurity-actions-security) only needs `actions: read` permissions on your repositories.
Read this [case study on how Kapiche uses Harden Runner](https://www.stepsecurity.io/case-studies/kapiche/) to improve software supply chain security in their open source and private repositories.

115
dist/index.js vendored
View file

@ -2834,6 +2834,8 @@ __nccwpck_require__.r(__webpack_exports__);
// EXTERNAL MODULE: ./node_modules/@actions/core/lib/core.js
var lib_core = __nccwpck_require__(186);
// EXTERNAL MODULE: external "fs"
var external_fs_ = __nccwpck_require__(747);
;// CONCATENATED MODULE: ./src/common.ts
var __awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
@ -2845,25 +2847,122 @@ var __awaiter = (undefined && undefined.__awaiter) || function (thisArg, _argume
});
};
function printInfo(web_url) {
console.log("\x1b[32m%s\x1b[0m", "View security insights and recommended policy at:");
console.log(`${web_url}/github/${process.env["GITHUB_REPOSITORY"]}/actions/runs/${process.env["GITHUB_RUN_ID"]}`);
}
const processLogLine = (line, tableEntries) => {
if (line.includes("pid") &&
line.includes("process") &&
line.includes("domain") &&
line.includes("ip address")) {
const matches = line.match(/ip address:port ([\d.:]+), domain: ([\w.-]+), pid: (\d+), process: (\w+)/);
if (matches) {
const [ipAddress, domain, pid, process] = matches.slice(1);
// Check if all values are non-empty
if (pid && process && domain && ipAddress) {
const status = ipAddress.startsWith("54.185.253.63")
? "❌ Blocked"
: "✅ Allowed";
tableEntries.push({ pid, process, domain, ipAddress, status });
}
}
}
};
function addSummary() {
return __awaiter(this, void 0, void 0, function* () {
if (process.env.STATE_monitorStatusCode === "200") {
const web_url = "https://app.stepsecurity.io";
const insights_url = `${web_url}/github/${process.env["GITHUB_REPOSITORY"]}/actions/runs/${process.env["GITHUB_RUN_ID"]}`;
if (process.env.STATE_monitorStatusCode !== "200") {
return;
}
const web_url = "https://app.stepsecurity.io";
const insights_url = `${web_url}/github/${process.env["GITHUB_REPOSITORY"]}/actions/runs/${process.env["GITHUB_RUN_ID"]}`;
const log = "/home/agent/agent.log";
if (!fs.existsSync(log)) {
return;
}
let needsSubscription = false;
try {
let data = fs.readFileSync("/home/agent/annotation.log", "utf8");
if (data.includes("StepSecurity Harden Runner is disabled")) {
needsSubscription = true;
}
}
catch (err) {
//console.error(err);
}
if (needsSubscription) {
yield core.summary
.addSeparator()
.addRaw(`<p><picture>
<source media="(prefers-color-scheme: light)" srcset="https://github.com/step-security/harden-runner/raw/main/images/banner.png" width="200">
<img alt="Dark Banner" src="https://github.com/step-security/harden-runner/raw/main/images/banner-dark.png" width="200">
</picture></p>`, true)
.addLink("View security insights and recommended policy", insights_url)
.addRaw(`<h2>❌ GitHub Actions Runtime Security is disabled</h2>`);
yield core.summary
.addRaw(`
<p>You are seeing this markdown since this workflow uses the <a href="https://github.com/step-security/harden-runner">Harden-Runner GitHub Action</a> by StepSecurity in a private repository, but your organization has not signed up for a free trial or a paid subscription.</p>
<p>To start a free trial, install the <a href="https://github.com/apps/stepsecurity-actions-security">StepSecurity Actions Security GitHub App</a> or reach out to us via our <a href="https://www.stepsecurity.io/contact">contact form.</a></p>
`)
.addSeparator()
.write();
return;
}
const content = fs.readFileSync(log, "utf-8");
const lines = content.split("\n");
let tableEntries = [];
for (const line of lines) {
processLogLine(line, tableEntries);
}
if (tableEntries.length === 0) {
return;
}
let insightsRow = `<tr>
<td colspan="3" align="center"><a href="${insights_url}">🛡 Check out the full report and recommended policy at StepSecurity</a></td>
</tr>`;
yield core.summary.addSeparator().addRaw(`<h2><a href="${insights_url}">StepSecurity Report</a></h2>
<h3>GitHub Actions Runtime Security</h3>`);
tableEntries.sort((a, b) => {
if (a.status === "❌ Blocked" && b.status !== "❌ Blocked") {
return -1;
}
else if (a.status !== "❌ Blocked" && b.status === "❌ Blocked") {
return 1;
}
else {
return 0;
}
});
tableEntries = tableEntries.slice(0, 3);
yield core.summary.addRaw(`
<h3>🌐 Network Events</h3>
<table>
<thead>
<tr>
<th>Process</th>
<th>Endpoint</th>
<th>Status</th>
</tr>
</thead>
<tbody>
${tableEntries
.map((entry) => `<tr>
<td>${entry.process}</td>
<td>${entry.domain.replace(/\.$/, "")}</td>
<td>${entry.status}</td>
</tr>`)
.join("")}
<tr>
<td>...</td>
<td>...</td>
<td>...</td>
</tr>
${insightsRow}
</tbody>
</table>
`);
yield core.summary
.addSeparator()
.addRaw(`<blockquote>You are seeing this markdown since this workflow uses the <a href="https://github.com/step-security/harden-runner">Harden-Runner GitHub Action</a>.
Harden-Runner is a security agent for GitHub-hosted runners to block egress traffic & detect code overwrite to prevent breaches.</blockquote>`)
.addSeparator()
.write();
});
}
const STATUS_HARDEN_RUNNER_UNAVAILABLE = "409";

2
dist/index.js.map vendored

File diff suppressed because one or more lines are too long

120
dist/post/index.js vendored
View file

@ -61147,24 +61147,119 @@ var __awaiter = (undefined && undefined.__awaiter) || function (thisArg, _argume
});
};
function printInfo(web_url) {
console.log("\x1b[32m%s\x1b[0m", "View security insights and recommended policy at:");
console.log(`${web_url}/github/${process.env["GITHUB_REPOSITORY"]}/actions/runs/${process.env["GITHUB_RUN_ID"]}`);
}
const processLogLine = (line, tableEntries) => {
if (line.includes("pid") &&
line.includes("process") &&
line.includes("domain") &&
line.includes("ip address")) {
const matches = line.match(/ip address:port ([\d.:]+), domain: ([\w.-]+), pid: (\d+), process: (\w+)/);
if (matches) {
const [ipAddress, domain, pid, process] = matches.slice(1);
// Check if all values are non-empty
if (pid && process && domain && ipAddress) {
const status = ipAddress.startsWith("54.185.253.63")
? "❌ Blocked"
: "✅ Allowed";
tableEntries.push({ pid, process, domain, ipAddress, status });
}
}
}
};
function addSummary() {
return __awaiter(this, void 0, void 0, function* () {
if (process.env.STATE_monitorStatusCode === "200") {
const web_url = "https://app.stepsecurity.io";
const insights_url = `${web_url}/github/${process.env["GITHUB_REPOSITORY"]}/actions/runs/${process.env["GITHUB_RUN_ID"]}`;
if (process.env.STATE_monitorStatusCode !== "200") {
return;
}
const web_url = "https://app.stepsecurity.io";
const insights_url = `${web_url}/github/${process.env["GITHUB_REPOSITORY"]}/actions/runs/${process.env["GITHUB_RUN_ID"]}`;
const log = "/home/agent/agent.log";
if (!external_fs_.existsSync(log)) {
return;
}
let needsSubscription = false;
try {
let data = external_fs_.readFileSync("/home/agent/annotation.log", "utf8");
if (data.includes("StepSecurity Harden Runner is disabled")) {
needsSubscription = true;
}
}
catch (err) {
//console.error(err);
}
if (needsSubscription) {
yield core.summary.addSeparator()
.addRaw(`<p><picture>
<source media="(prefers-color-scheme: light)" srcset="https://github.com/step-security/harden-runner/raw/main/images/banner.png" width="200">
<img alt="Dark Banner" src="https://github.com/step-security/harden-runner/raw/main/images/banner-dark.png" width="200">
</picture></p>`, true)
.addLink("View security insights and recommended policy", insights_url)
.addRaw(`<h2>❌ GitHub Actions Runtime Security is disabled</h2>`);
yield core.summary.addRaw(`
<p>You are seeing this markdown since this workflow uses the <a href="https://github.com/step-security/harden-runner">Harden-Runner GitHub Action</a> by StepSecurity in a private repository, but your organization has not signed up for a free trial or a paid subscription.</p>
<p>To start a free trial, install the <a href="https://github.com/apps/stepsecurity-actions-security">StepSecurity Actions Security GitHub App</a> or reach out to us via our <a href="https://www.stepsecurity.io/contact">contact form.</a></p>
`)
.addSeparator()
.write();
return;
}
const content = external_fs_.readFileSync(log, "utf-8");
const lines = content.split("\n");
let tableEntries = [];
for (const line of lines) {
processLogLine(line, tableEntries);
}
if (tableEntries.length === 0) {
return;
}
let insightsRow = `<tr>
<td colspan="3" align="center"><a href="${insights_url}">🛡 Check out the full report and recommended policy at StepSecurity</a></td>
</tr>`;
yield core.summary.addSeparator().addRaw(`<h2><a href="${insights_url}">StepSecurity Report</a></h2>
<h3>GitHub Actions Runtime Security</h3>`);
tableEntries.sort((a, b) => {
if (a.status === "❌ Blocked" && b.status !== "❌ Blocked") {
return -1;
}
else if (a.status !== "❌ Blocked" && b.status === "❌ Blocked") {
return 1;
}
else {
return 0;
}
});
tableEntries = tableEntries.slice(0, 3);
yield core.summary.addRaw(`
<h3>🌐 Network Events</h3>
<table>
<thead>
<tr>
<th>Process</th>
<th>Endpoint</th>
<th>Status</th>
</tr>
</thead>
<tbody>
${tableEntries
.map((entry) => `<tr>
<td>${entry.process}</td>
<td>${entry.domain.replace(/\.$/, "")}</td>
<td>${entry.status}</td>
</tr>`)
.join("")}
<tr>
<td>...</td>
<td>...</td>
<td>...</td>
</tr>
${insightsRow}
</tbody>
</table>
`);
yield core.summary.addSeparator()
.addRaw(`<blockquote>You are seeing this markdown since this workflow uses the <a href="https://github.com/step-security/harden-runner">Harden-Runner GitHub Action</a>.
Harden-Runner is a security agent for GitHub-hosted runners to block egress traffic & detect code overwrite to prevent breaches.</blockquote>`)
.addSeparator()
.write();
});
}
const STATUS_HARDEN_RUNNER_UNAVAILABLE = "409";
@ -61244,7 +61339,6 @@ var cleanup_awaiter = (undefined && undefined.__awaiter) || function (thisArg, _
(() => cleanup_awaiter(void 0, void 0, void 0, function* () {
if (process.platform !== "linux") {
console.log(UBUNTU_MESSAGE);
@ -61287,14 +61381,6 @@ var cleanup_awaiter = (undefined && undefined.__awaiter) || function (thisArg, _
var content = external_fs_.readFileSync(status, "utf-8");
console.log(content);
}
// write annotations
var annotationsFile = "/home/agent/annotation.log";
if (external_fs_.existsSync(annotationsFile)) {
var content = external_fs_.readFileSync(annotationsFile, "utf-8");
content.split(/\r?\n/).forEach((line) => {
core.error(line);
});
}
var disable_sudo = process.env.STATE_disableSudo;
if (disable_sudo !== "true") {
var journalLog = external_child_process_.execSync("sudo journalctl -u agent.service", {

File diff suppressed because one or more lines are too long

119
dist/pre/index.js vendored
View file

@ -68997,25 +68997,122 @@ var __awaiter = (undefined && undefined.__awaiter) || function (thisArg, _argume
});
};
function printInfo(web_url) {
console.log("\x1b[32m%s\x1b[0m", "View security insights and recommended policy at:");
console.log(`${web_url}/github/${process.env["GITHUB_REPOSITORY"]}/actions/runs/${process.env["GITHUB_RUN_ID"]}`);
}
const processLogLine = (line, tableEntries) => {
if (line.includes("pid") &&
line.includes("process") &&
line.includes("domain") &&
line.includes("ip address")) {
const matches = line.match(/ip address:port ([\d.:]+), domain: ([\w.-]+), pid: (\d+), process: (\w+)/);
if (matches) {
const [ipAddress, domain, pid, process] = matches.slice(1);
// Check if all values are non-empty
if (pid && process && domain && ipAddress) {
const status = ipAddress.startsWith("54.185.253.63")
? "❌ Blocked"
: "✅ Allowed";
tableEntries.push({ pid, process, domain, ipAddress, status });
}
}
}
};
function addSummary() {
return __awaiter(this, void 0, void 0, function* () {
if (process.env.STATE_monitorStatusCode === "200") {
const web_url = "https://app.stepsecurity.io";
const insights_url = `${web_url}/github/${process.env["GITHUB_REPOSITORY"]}/actions/runs/${process.env["GITHUB_RUN_ID"]}`;
if (process.env.STATE_monitorStatusCode !== "200") {
return;
}
const web_url = "https://app.stepsecurity.io";
const insights_url = `${web_url}/github/${process.env["GITHUB_REPOSITORY"]}/actions/runs/${process.env["GITHUB_RUN_ID"]}`;
const log = "/home/agent/agent.log";
if (!fs.existsSync(log)) {
return;
}
let needsSubscription = false;
try {
let data = fs.readFileSync("/home/agent/annotation.log", "utf8");
if (data.includes("StepSecurity Harden Runner is disabled")) {
needsSubscription = true;
}
}
catch (err) {
//console.error(err);
}
if (needsSubscription) {
yield core.summary
.addSeparator()
.addRaw(`<p><picture>
<source media="(prefers-color-scheme: light)" srcset="https://github.com/step-security/harden-runner/raw/main/images/banner.png" width="200">
<img alt="Dark Banner" src="https://github.com/step-security/harden-runner/raw/main/images/banner-dark.png" width="200">
</picture></p>`, true)
.addLink("View security insights and recommended policy", insights_url)
.addRaw(`<h2>❌ GitHub Actions Runtime Security is disabled</h2>`);
yield core.summary
.addRaw(`
<p>You are seeing this markdown since this workflow uses the <a href="https://github.com/step-security/harden-runner">Harden-Runner GitHub Action</a> by StepSecurity in a private repository, but your organization has not signed up for a free trial or a paid subscription.</p>
<p>To start a free trial, install the <a href="https://github.com/apps/stepsecurity-actions-security">StepSecurity Actions Security GitHub App</a> or reach out to us via our <a href="https://www.stepsecurity.io/contact">contact form.</a></p>
`)
.addSeparator()
.write();
return;
}
const content = fs.readFileSync(log, "utf-8");
const lines = content.split("\n");
let tableEntries = [];
for (const line of lines) {
processLogLine(line, tableEntries);
}
if (tableEntries.length === 0) {
return;
}
let insightsRow = `<tr>
<td colspan="3" align="center"><a href="${insights_url}">🛡 Check out the full report and recommended policy at StepSecurity</a></td>
</tr>`;
yield core.summary.addSeparator().addRaw(`<h2><a href="${insights_url}">StepSecurity Report</a></h2>
<h3>GitHub Actions Runtime Security</h3>`);
tableEntries.sort((a, b) => {
if (a.status === "❌ Blocked" && b.status !== "❌ Blocked") {
return -1;
}
else if (a.status !== "❌ Blocked" && b.status === "❌ Blocked") {
return 1;
}
else {
return 0;
}
});
tableEntries = tableEntries.slice(0, 3);
yield core.summary.addRaw(`
<h3>🌐 Network Events</h3>
<table>
<thead>
<tr>
<th>Process</th>
<th>Endpoint</th>
<th>Status</th>
</tr>
</thead>
<tbody>
${tableEntries
.map((entry) => `<tr>
<td>${entry.process}</td>
<td>${entry.domain.replace(/\.$/, "")}</td>
<td>${entry.status}</td>
</tr>`)
.join("")}
<tr>
<td>...</td>
<td>...</td>
<td>...</td>
</tr>
${insightsRow}
</tbody>
</table>
`);
yield core.summary
.addSeparator()
.addRaw(`<blockquote>You are seeing this markdown since this workflow uses the <a href="https://github.com/step-security/harden-runner">Harden-Runner GitHub Action</a>.
Harden-Runner is a security agent for GitHub-hosted runners to block egress traffic & detect code overwrite to prevent breaches.</blockquote>`)
.addSeparator()
.write();
});
}
const STATUS_HARDEN_RUNNER_UNAVAILABLE = "409";
@ -69036,7 +69133,7 @@ function verifyChecksum(downloadPath) {
const checksum = external_crypto_.createHash("sha256")
.update(fileBuffer)
.digest("hex"); // checksum of downloaded file
const expectedChecksum = "a1e79e4d7323a63a845c446b9a964a772b0ab7dff9fc94f8a1d10e901f2acde1"; // checksum for v0.13.2
const expectedChecksum = "79cc2df62f6eba9ab4ceadbbdfca4d20ef5b14e1439a98eaa559142b8dd61aac"; // checksum for v0.13.4
if (checksum !== expectedChecksum) {
lib_core.setFailed(`Checksum verification failed, expected ${expectedChecksum} instead got ${checksum}`);
}
@ -69194,6 +69291,7 @@ var setup_awaiter = (undefined && undefined.__awaiter) || function (thisArg, _ar
(() => setup_awaiter(void 0, void 0, void 0, function* () {
var _a, _b;
try {
if (process.platform !== "linux") {
console.log(UBUNTU_MESSAGE);
@ -69218,6 +69316,7 @@ var setup_awaiter = (undefined && undefined.__awaiter) || function (thisArg, _ar
disable_telemetry: lib_core.getBooleanInput("disable-telemetry"),
disable_sudo: lib_core.getBooleanInput("disable-sudo"),
disable_file_monitoring: lib_core.getBooleanInput("disable-file-monitoring"),
private: ((_b = (_a = github.context === null || github.context === void 0 ? void 0 : github.context.payload) === null || _a === void 0 ? void 0 : _a.repository) === null || _b === void 0 ? void 0 : _b.private) || false,
};
let policyName = lib_core.getInput("policy");
if (policyName !== "") {
@ -69288,7 +69387,7 @@ var setup_awaiter = (undefined && undefined.__awaiter) || function (thisArg, _ar
// Note: to avoid github rate limiting
let token = lib_core.getInput("token");
let auth = `token ${token}`;
const downloadPath = yield tool_cache.downloadTool("https://github.com/step-security/agent/releases/download/v0.13.2/agent_0.13.2_linux_amd64.tar.gz", undefined, auth);
const downloadPath = yield tool_cache.downloadTool("https://github.com/step-security/agent/releases/download/v0.13.4/agent_0.13.4_linux_amd64.tar.gz", undefined, auth);
verifyChecksum(downloadPath); // NOTE: verifying agent's checksum, before extracting
const extractPath = yield tool_cache.extractTar(downloadPath);
if (!confg.disable_telemetry || confg.egress_policy === "audit") {

File diff suppressed because one or more lines are too long

View file

@ -1,7 +1,7 @@
{
"name": "step-security-harden-runner",
"version": "2.4.0",
"description": "Security agent for GitHub-hosted runner to monitor the build process",
"version": "2.4.1",
"description": "Security agent for GitHub-hosted runner: block egress traffic & detect code overwrite to prevent breaches",
"main": "index.js",
"scripts": {
"build": "npm run main && npm run pre && npm run post",

View file

@ -10,7 +10,7 @@ export function verifyChecksum(downloadPath: string) {
.digest("hex"); // checksum of downloaded file
const expectedChecksum: string =
"a1e79e4d7323a63a845c446b9a964a772b0ab7dff9fc94f8a1d10e901f2acde1"; // checksum for v0.13.2
"79cc2df62f6eba9ab4ceadbbdfca4d20ef5b14e1439a98eaa559142b8dd61aac"; // checksum for v0.13.4
if (checksum !== expectedChecksum) {
core.setFailed(

View file

@ -61,15 +61,6 @@ import path from "path";
console.log(content);
}
// write annotations
var annotationsFile = "/home/agent/annotation.log";
if (fs.existsSync(annotationsFile)) {
var content = fs.readFileSync(annotationsFile, "utf-8");
content.split(/\r?\n/).forEach((line) => {
core.error(line);
});
}
var disable_sudo = process.env.STATE_disableSudo;
if (disable_sudo !== "true") {
var journalLog = cp.execSync("sudo journalctl -u agent.service", {

View file

@ -1,28 +1,28 @@
import { addSummary } from "./common";
import * as cp from "child_process";
import { processLogLine } from "./common"; // import the function
test("adding stepsecurity summary in github_summary", async () => {
let expected = `<hr>
<p><picture>
<source media=\"(prefers-color-scheme: light)\" srcset=\"https://github.com/step-security/harden-runner/raw/main/images/banner.png\" width=\"200\">
<img alt=\"Dark Banner\" src=\"https://github.com/step-security/harden-runner/raw/main/images/banner-dark.png\" width=\"200\">
</picture></p>
<a href=\"https://app.stepsecurity.io/github/step-security/test/actions/runs/12345\">View security insights and recommended policy</a>
<hr>
`;
describe("processLogLine function", () => {
it("correctly processes the log line and adds an entry to the array", () => {
const tableEntries: {
pid: string;
process: string;
domain: string;
ipAddress: string;
status: string;
}[] = [];
const logLine =
"Thu, 15 Jun 2023 05:35:29 GMT:endpoint called ip address:port 104.16.24.35:443, domain: registry.npmjs.org., pid: 2135, process: node.";
const github_summary = "/tmp/github_summary";
cp.execSync(`touch ${github_summary}`);
processLogLine(logLine, tableEntries);
process.env["STATE_monitorStatusCode"] = "200";
process.env["GITHUB_STEP_SUMMARY"] = github_summary;
process.env["GITHUB_REPOSITORY"] = "step-security/test";
process.env["GITHUB_RUN_ID"] = "12345";
// Check if a single entry is added to the array
expect(tableEntries.length).toBe(1);
await addSummary();
let output = cp.execSync(`cat ${github_summary}`).toString();
cp.execSync(`rm ${github_summary}`);
expect(output).toMatch(expected);
// Check if the entry's properties are set correctly
const entry = tableEntries[0];
expect(entry.pid).toBe("2135");
expect(entry.process).toBe("node");
expect(entry.domain).toBe("registry.npmjs.org.");
expect(entry.ipAddress).toBe("104.16.24.35:443");
expect(entry.status).toBe("✅ Allowed"); // Since the IP address is not '54.185.253.63', status should be '✔️ Allowed'
});
});

View file

@ -1,4 +1,6 @@
import * as core from "@actions/core";
import * as fs from "fs";
export function printInfo(web_url) {
console.log(
"\x1b[32m%s\x1b[0m",
@ -9,24 +11,153 @@ export function printInfo(web_url) {
`${web_url}/github/${process.env["GITHUB_REPOSITORY"]}/actions/runs/${process.env["GITHUB_RUN_ID"]}`
);
}
export async function addSummary() {
if (process.env.STATE_monitorStatusCode === "200") {
const web_url = "https://app.stepsecurity.io";
const insights_url = `${web_url}/github/${process.env["GITHUB_REPOSITORY"]}/actions/runs/${process.env["GITHUB_RUN_ID"]}`;
export const processLogLine = (
line: string,
tableEntries: {
pid: string;
process: string;
domain: string;
ipAddress: string;
status: string;
}[]
): void => {
if (
line.includes("pid") &&
line.includes("process") &&
line.includes("domain") &&
line.includes("ip address")
) {
const matches = line.match(
/ip address:port ([\d.:]+), domain: ([\w.-]+), pid: (\d+), process: (\w+)/
);
if (matches) {
const [ipAddress, domain, pid, process] = matches.slice(1);
// Check if all values are non-empty
if (pid && process && domain && ipAddress) {
const status = ipAddress.startsWith("54.185.253.63")
? "❌ Blocked"
: "✅ Allowed";
tableEntries.push({ pid, process, domain, ipAddress, status });
}
}
}
};
export async function addSummary() {
if (process.env.STATE_monitorStatusCode !== "200") {
return;
}
const web_url = "https://app.stepsecurity.io";
const insights_url = `${web_url}/github/${process.env["GITHUB_REPOSITORY"]}/actions/runs/${process.env["GITHUB_RUN_ID"]}`;
const log = "/home/agent/agent.log";
if (!fs.existsSync(log)) {
return;
}
let needsSubscription = false;
try {
let data = fs.readFileSync("/home/agent/annotation.log", "utf8");
if (data.includes("StepSecurity Harden Runner is disabled")) {
needsSubscription = true;
}
} catch (err) {
//console.error(err);
}
if (needsSubscription) {
await core.summary
.addSeparator()
.addRaw(`<h2>❌ GitHub Actions Runtime Security is disabled</h2>`);
await core.summary
.addRaw(
`<p><picture>
<source media="(prefers-color-scheme: light)" srcset="https://github.com/step-security/harden-runner/raw/main/images/banner.png" width="200">
<img alt="Dark Banner" src="https://github.com/step-security/harden-runner/raw/main/images/banner-dark.png" width="200">
</picture></p>`,
true
`
<p>You are seeing this markdown since this workflow uses the <a href="https://github.com/step-security/harden-runner">Harden-Runner GitHub Action</a> by StepSecurity in a private repository, but your organization has not signed up for a free trial or a paid subscription.</p>
<p>To start a free trial, install the <a href="https://github.com/apps/stepsecurity-actions-security">StepSecurity Actions Security GitHub App</a> or reach out to us via our <a href="https://www.stepsecurity.io/contact">contact form.</a></p>
`
)
.addLink("View security insights and recommended policy", insights_url)
.addSeparator()
.write();
return;
}
const content = fs.readFileSync(log, "utf-8");
const lines = content.split("\n");
let tableEntries = [];
for (const line of lines) {
processLogLine(line, tableEntries);
}
if (tableEntries.length === 0) {
return;
}
let insightsRow = `<tr>
<td colspan="3" align="center"><a href="${insights_url}">🛡 Check out the full report and recommended policy at StepSecurity</a></td>
</tr>`;
await core.summary.addSeparator().addRaw(
`<h2><a href="${insights_url}">StepSecurity Report</a></h2>
<h3>GitHub Actions Runtime Security</h3>`
);
tableEntries.sort((a, b) => {
if (a.status === "❌ Blocked" && b.status !== "❌ Blocked") {
return -1;
} else if (a.status !== "❌ Blocked" && b.status === "❌ Blocked") {
return 1;
} else {
return 0;
}
});
tableEntries = tableEntries.slice(0, 3);
await core.summary.addRaw(`
<h3>🌐 Network Events</h3>
<table>
<thead>
<tr>
<th>Process</th>
<th>Endpoint</th>
<th>Status</th>
</tr>
</thead>
<tbody>
${tableEntries
.map(
(entry) => `<tr>
<td>${entry.process}</td>
<td>${entry.domain.replace(/\.$/, "")}</td>
<td>${entry.status}</td>
</tr>`
)
.join("")}
<tr>
<td>...</td>
<td>...</td>
<td>...</td>
</tr>
${insightsRow}
</tbody>
</table>
`);
await core.summary
.addSeparator()
.addRaw(
`<blockquote>You are seeing this markdown since this workflow uses the <a href="https://github.com/step-security/harden-runner">Harden-Runner GitHub Action</a>.
Harden-Runner is a security agent for GitHub-hosted runners to block egress traffic & detect code overwrite to prevent breaches.</blockquote>`
)
.addSeparator()
.write();
}
export const STATUS_HARDEN_RUNNER_UNAVAILABLE = "409";

View file

@ -9,6 +9,7 @@ export interface Configuration {
disable_telemetry: boolean;
disable_sudo: boolean;
disable_file_monitoring: boolean;
private: string;
}
export interface PolicyResponse {

View file

@ -36,6 +36,7 @@ test("merge configs", async () => {
disable_telemetry: false,
disable_sudo: false,
disable_file_monitoring: false,
private: "true",
};
let policyResponse: PolicyResponse = {
owner: "h0x0er",
@ -58,6 +59,7 @@ test("merge configs", async () => {
disable_telemetry: false,
disable_sudo: false,
disable_file_monitoring: false,
private: "true",
};
localConfig = mergeConfigs(localConfig, policyResponse);

View file

@ -50,6 +50,7 @@ import * as utils from '@actions/cache/lib/internal/cacheUtils'
disable_telemetry: core.getBooleanInput("disable-telemetry"),
disable_sudo: core.getBooleanInput("disable-sudo"),
disable_file_monitoring: core.getBooleanInput("disable-file-monitoring"),
private: context?.payload?.repository?.private || false,
};
let policyName = core.getInput("policy");
@ -145,7 +146,7 @@ import * as utils from '@actions/cache/lib/internal/cacheUtils'
let auth = `token ${token}`;
const downloadPath: string = await tc.downloadTool(
"https://github.com/step-security/agent/releases/download/v0.13.2/agent_0.13.2_linux_amd64.tar.gz",
"https://github.com/step-security/agent/releases/download/v0.13.4/agent_0.13.4_linux_amd64.tar.gz",
undefined,
auth
);