Skip to content

Commit

Permalink
Merge pull request #11
Browse files Browse the repository at this point in the history
  • Loading branch information
therealdwright committed Aug 7, 2023
2 parents 1c6114d + 81fbbc1 commit bce1f1b
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 128 deletions.
4 changes: 4 additions & 0 deletions action.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
name: Trufflehog PR Commenter
description: Take trufflehog JSON output and comment violations on a PR
inputs:
commit:
description: The commit from which to check
required: true
default: ${{ github.event.repository.default_branch }}
secrets-file:
description: Path to save Trufflehog JSON output
required: true
Expand Down
223 changes: 105 additions & 118 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
const axios = require("axios");
const core = require("@actions/core");
const exec = require("@actions/exec");
const fs = require('fs');
const fs = require("fs");
const tar = require("tar");
const { Octokit } = require("@octokit/rest");

const token = process.env["GITHUB_TOKEN"];
const octokit = new Octokit({ auth: `token ${token}` });

const commit = core.getInput("commit");
const filePath = core.getInput("secrets-file");

async function downloadFile(url, outputPath) {
Expand All @@ -20,142 +21,128 @@ async function downloadFile(url, outputPath) {
});
}

async function checkForSecrets() {
let secretsDetected = false;

const data = await fs.promises.readFile(filePath, "utf8");
if (!data || data.trim().length === 0) {
console.log("No data or empty file found, skipping processing...");
return secretsDetected;
}

const jsonData = JSON.parse(data);

if (
jsonData &&
jsonData.SourceMetadata &&
jsonData.SourceMetadata.Data &&
jsonData.SourceMetadata.Data.Git &&
jsonData.SourceMetadata.Data.Git.file
) {
secretsDetected = true;

const repoData = getRepoData(jsonData.SourceMetadata.Data.Git.repository);
if (!repoData) {
console.log("No repo data found, skipping processing...");
return secretsDetected;
}

const commentBody = `🚨 Secret Detected 🚨\nSecret detected at line ${jsonData.SourceMetadata.Data.Git.line} in file ${jsonData.SourceMetadata.Data.Git.file}. Please review.`;

const prs = await octokit.pulls.list({
owner: repoData.owner,
repo: repoData.repo,
});

for (const pr of prs.data) {
if (pr.state === "open") {
const commitId = await octokit.repos.getCommit({
owner: repoData.owner,
repo: repoData.repo,
ref: pr.head.sha,
});

await octokit.pulls.createReviewComment({
owner: repoData.owner,
repo: repoData.repo,
pull_number: pr.number,
body: commentBody,
commit_id: commitId.data.sha,
path: jsonData.SourceMetadata.Data.Git.file,
line: jsonData.SourceMetadata.Data.Git.line,
side: "RIGHT", // assuming the secret was added, not removed
});
}
}
}
return secretsDetected;
}

function getRepoData(repoUrl) {
const regex =
/(?:git@github\.com:|https:\/\/github.com\/)(.+)\/(.+)(?:\.git)?/i;
const match = regex.exec(repoUrl);

if (!match) {
console.log(`No match found for repoUrl: ${repoUrl}`);
return null;
}

return {
owner: match[1],
repo: match[2],
};
}

async function run() {
try {
const tarballPath = "./trufflehog.tar.gz";
await downloadFile(
"https://github.com/trufflesecurity/trufflehog/releases/download/v3.40.0/trufflehog_3.40.0_linux_amd64.tar.gz",
tarballPath
);

// Extract TruffleHog tarball
await tar.x({ file: tarballPath });

// Get the path for the output file from the action's inputs
const secretsFilePath = core.getInput("secrets-file");

let output = '';
let errorOutput = '';

const options = {};
options.listeners = {
let output = "";
const options = {
listeners: {
stdout: (data) => {
output += data.toString();
fs.appendFileSync(secretsFilePath, data.toString());
},
stderr: (data) => {
errorOutput += data.toString();
}
console.error(data.toString());
},
},
};

await exec.exec(`./trufflehog`, [
"git",
"file://./",
"--since-commit",
`${process.env.GITHUB_SHA}`,
"--branch",
"HEAD",
"--fail",
"--no-update",
"--json",
"--no-verification"
], options);

if (errorOutput) {
// Handle the error output if necessary
console.error(errorOutput);
try {
await exec.exec(
`./trufflehog`,
[
"git",
"file://./",
"--since-commit",
`${commit}`,
"--branch",
"HEAD",
"--fail",
"--no-update",
"--json",
"--no-verification",
],
options
);
fs.writeFileSync(secretsFilePath, output);
} catch (error) {
console.error(`Error executing trufflehog: ${error}`);
}

fs.writeFileSync(secretsFilePath, output);

fs.readFile(filePath, "utf8", async (err, data) => {
if (err) {
if (!data) {
console.log("No data found, skipping processing...");
} else {
console.log(`Error reading file from disk: ${err}`);
}
return;
}

if (data.trim().length === 0) {
console.log("Empty file found, skipping processing...");
return;
}

try {
const jsonData = JSON.parse(data);

const repoData = getRepoData(
jsonData.SourceMetadata.Data.Git.repository
);
if (!repoData) {
console.log("No repo data found, skipping processing...");
return;
}

const commentBody = `🚨 Secret Detected 🚨\nSecret detected at line ${jsonData.SourceMetadata.Data.Git.line} in file ${jsonData.SourceMetadata.Data.Git.file}. Please review.`;

try {
const prs = await octokit.pulls.list({
owner: repoData.owner,
repo: repoData.repo,
});

for (const pr of prs.data) {
if (pr.state === "open") {
const commitId = await octokit.repos.getCommit({
owner: repoData.owner,
repo: repoData.repo,
ref: pr.head.sha,
});

await octokit.pulls.createReviewComment({
owner: repoData.owner,
repo: repoData.repo,
pull_number: pr.number,
body: commentBody,
commit_id: commitId.data.sha,
path: jsonData.SourceMetadata.Data.Git.file,
line: jsonData.SourceMetadata.Data.Git.line,
side: "RIGHT", // assuming the secret was added, not removed
});
}
}
} catch (e) {
if (
e.status === 422 &&
e.message.includes("PullRequestReviewComment") &&
e.message.includes("pull_request_review_thread.path") &&
e.message.includes("pull_request_review_thread.diff_hunk")
) {
// Ignore the specific error relating to pull_request_review_thread.diff_hunk
} else if (e.status) {
console.log(`GitHub returned an error: ${e.status}`);
console.log(e.message);
} else {
console.log("Error occurred", e);
}
}
} catch (e) {
console.log("Error parsing JSON:", e);
}
});

function getRepoData(repoUrl) {
// This regex will handle both SSH and HTTPS URLs
const regex =
/(?:git@github\.com:|https:\/\/github.com\/)(.+)\/(.+)(?:\.git)?/i;
const match = regex.exec(repoUrl);

if (!match) {
console.log(`No match found for repoUrl: ${repoUrl}`);
return null;
}
const secretsFound = await checkForSecrets();

return {
owner: match[1],
repo: match[2],
};
if (secretsFound) {
core.setFailed("Secrets detected in the repository.");
}
} catch (error) {
core.setFailed(`Action failed with error: ${error}`);
Expand Down
23 changes: 13 additions & 10 deletions node_modules/jsonparse/package.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit bce1f1b

Please sign in to comment.