mirror of
https://github.com/step-security/harden-runner.git
synced 2026-06-08 12:17:07 +00:00
Release v2.4.1 (#309)
This commit is contained in:
parent
215c5ca5ec
commit
55d479fb1c
15 changed files with 496 additions and 86 deletions
|
|
@ -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
115
dist/index.js
vendored
|
|
@ -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
2
dist/index.js.map
vendored
File diff suppressed because one or more lines are too long
120
dist/post/index.js
vendored
120
dist/post/index.js
vendored
|
|
@ -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", {
|
||||
|
|
|
|||
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
119
dist/pre/index.js
vendored
119
dist/pre/index.js
vendored
|
|
@ -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") {
|
||||
|
|
|
|||
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
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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", {
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
});
|
||||
});
|
||||
|
|
|
|||
151
src/common.ts
151
src/common.ts
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ export interface Configuration {
|
|||
disable_telemetry: boolean;
|
||||
disable_sudo: boolean;
|
||||
disable_file_monitoring: boolean;
|
||||
private: string;
|
||||
}
|
||||
|
||||
export interface PolicyResponse {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue