Skip to content

Commit

Permalink
feat(action): add new options and handle large files
Browse files Browse the repository at this point in the history
  • Loading branch information
swarit-pandey committed Sep 5, 2024
1 parent 79290b7 commit 845a9ac
Show file tree
Hide file tree
Showing 3 changed files with 153 additions and 33 deletions.
22 changes: 18 additions & 4 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,6 @@ inputs:
description: 'Scan for only system events'
required: false
default: 'false'
output:
description: 'Output path for the files to be placed'
required: false
default: './knoxctl-results'
kubearmor_version:
description: 'KubeArmor version to install (default: latest)'
required: false
Expand All @@ -28,6 +24,24 @@ inputs:
description: 'Policy action (Audit or Block)'
required: false
default: 'Audit'
dryrun:
description: 'Generate hardening security policies, but do not apply them'
required: false
default: 'false'
strict:
description: 'Apply all the hardening policies (this might generate a lot of alerts)'
required: false
default: 'false'
policies:
description: 'Path to user defined policies'
required: false
ignore-alerts:
description: 'Ignore alerts (file, network or process)'
required: false
min-severity:
description: 'Set the minimum severity level (1-10)'
required: false


runs:
using: 'node20'
Expand Down
48 changes: 37 additions & 11 deletions src/main/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ async function runKnoxctlScan(): Promise<void> {
{ name: "all", flag: "--all", type: "boolean" },
{ name: "system", flag: "--system", type: "boolean" },
{ name: "output", flag: "--output", type: "string" },
{ name: "ignore-alerts", flag: "--ignore-alerts", type: "string" },
{ name: "min-severity", flag: "--min-severity", type: "string" },
];

let policyAction = core.getInput("policy_action").toLowerCase();
Expand All @@ -136,17 +138,37 @@ async function runKnoxctlScan(): Promise<void> {
// Capitalize the first letter
policyAction = policyAction.charAt(0).toUpperCase() + policyAction.slice(1);

// Run the policy command first
await exec.exec("knoxctl", [
// Prepare policy command options
const policyCommand = [
"knoxctl",
"scan",
"policy",
"--event",
"ADDED",
"--action",
policyAction,
]);
];

// Add new policy options
const dryrun = core.getBooleanInput("dryrun");
if (dryrun) {
policyCommand.push("--dryrun");
}

const strict = core.getBooleanInput("strict");
if (strict) {
policyCommand.push("--strict");
}

const command: string[] = ["knoxctl", "scan"];
const policies = core.getInput("policies");
if (policies) {
policyCommand.push("--policies", policies);
}

// Run the policy command first
await exec.exec(policyCommand[0], policyCommand.slice(1));

const scanCommand: string[] = ["knoxctl", "scan"];
let outputDir = getOutputDir();

for (const option of knoxctlOptions) {
Expand All @@ -155,15 +177,15 @@ async function runKnoxctlScan(): Promise<void> {
if (option.type === "boolean") {
value = core.getBooleanInput(option.name);
if (value) {
command.push(option.flag);
scanCommand.push(option.flag);
}
} else if (option.type === "string") {
value = core.getInput(option.name);
if (value) {
if (option.name === "output") {
outputDir = value;
}
command.push(option.flag, value);
scanCommand.push(option.flag, value);
}
}
}
Expand All @@ -176,13 +198,17 @@ async function runKnoxctlScan(): Promise<void> {
log(`Output directory already exists: ${outputDir}`);
}

const commandString = command.join(" ");
const commandString = scanCommand.join(" ");
log(`Executing command: ${commandString}`);

const scanProcess: ChildProcess = spawn(command[0], command.slice(1), {
stdio: "inherit",
detached: true,
});
const scanProcess: ChildProcess = spawn(
scanCommand[0],
scanCommand.slice(1),
{
stdio: "inherit",
detached: true,
},
);

log(`knoxctl scan started with PID: ${scanProcess.pid}`);

Expand Down
116 changes: 98 additions & 18 deletions src/post/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,86 @@ const NETWORK_EVENTS_PREFIX = "knoxctl_scan_network_events_md_";
const PROCESS_TREE_PREFIX = "knoxctl_scan_process_tree_";
const ALERTS_PREFIX = "knoxctl_scan_processed_alerts_";

const MAX_SUMMARY_SIZE = 1024 * 1024;
const TRUNCATION_MESSAGE =
"\n\n... (content truncated due to size limits, please download artifacts) ...";

function truncateContent(content: string, maxSize: number): string {
if (Buffer.byteLength(content, "utf8") <= maxSize) {
return content;
}

let truncated = content;
while (Buffer.byteLength(truncated + TRUNCATION_MESSAGE, "utf8") > maxSize) {
truncated = truncated.slice(0, -100);
}

return truncated + TRUNCATION_MESSAGE;
}

async function uploadContentAsArtifact(
content: string,
fileName: string,
): Promise<string> {
const artifactClient = artifact.create();
const artifactName = `full-content-${fileName}`;
const tempDir = path.join(getOutputDir(), "temp-artifacts");
const tempFile = path.join(tempDir, fileName);

if (!fs.existsSync(tempDir)) {
fs.mkdirSync(tempDir, { recursive: true });
}

fs.writeFileSync(tempFile, content, ENCODING);

try {
const uploadResult = await artifactClient.uploadArtifact(
artifactName,
[tempFile],
tempDir,
{ continueOnError: false },
);

log(`Uploaded full content as artifact: ${uploadResult.artifactName}`);
return artifactName;
} catch (error) {
log(
`Failed to upload content as artifact: ${error instanceof Error ? error.message : String(error)}`,
"error",
);
return "";
} finally {
fs.unlinkSync(tempFile);
}
}

async function addToSummaryWithSizeCheck(
content: string,
title: string,
): Promise<void> {
let summaryContent = `## ${title}\n\n${content}`;
const contentSize = Buffer.byteLength(summaryContent, "utf8");

if (contentSize > MAX_SUMMARY_SIZE) {
log(
`Content for ${title} exceeds maximum size. Truncating and uploading full content as artifact.`,
);
const artifactName = await uploadContentAsArtifact(
content,
`${title.toLowerCase().replace(/\s+/g, "-")}.md`,
);

summaryContent = truncateContent(summaryContent, MAX_SUMMARY_SIZE - 200);
summaryContent += `\n\n[View full content](${artifactName})`;
}

if (IS_GITHUB_ACTIONS) {
core.summary.addRaw(summaryContent).addEOL();
} else {
console.log(summaryContent);
}
}

function stopKnoxctlScan(): void {
const pidFile = getPidFilePath();
if (fs.existsSync(pidFile)) {
Expand Down Expand Up @@ -69,34 +149,26 @@ function getLatestFile(directory: string, prefix: string): string | null {
return matchingFiles.length > 0 ? matchingFiles[0].name : null;
}

function addToSummary(content: string): void {
if (IS_GITHUB_ACTIONS) {
core.summary.addRaw(content).addEOL();
} else {
console.log(content);
}
}

function processResultFile(
async function processResultFile(
outputDir: string,
prefix: string,
title: string,
emoji: string,
): void {
): Promise<void> {
const file = getLatestFile(outputDir, prefix);
if (file) {
const filePath = path.join(outputDir, file);
log(`Processing ${title} file: ${filePath}`);
const content = fs.readFileSync(filePath, ENCODING);
addToSummary(`## ${emoji} ${title}\n\n${content}`);
await addToSummaryWithSizeCheck(`${emoji} ${title}\n\n${content}`, title);
} else {
log(
`No ${title.toLowerCase()} file found with prefix ${prefix} in ${outputDir}`,
);
}
}

function processResults(): void {
async function processResults(): Promise<void> {
const outputDir = path.resolve(getOutputDir());
log(`Processing knoxctl results from directory: ${outputDir}`);

Expand All @@ -112,11 +184,19 @@ function processResults(): void {
);
}

addToSummary("# 📊 Runtime Security Report Generated by AccuKnox\n\n");
await addToSummaryWithSizeCheck(
"📊 Runtime Security Report Generated by AccuKnox",
"Report Overview",
);

processResultFile(outputDir, NETWORK_EVENTS_PREFIX, "Network Events", "🌐");
processResultFile(outputDir, PROCESS_TREE_PREFIX, "Process Tree", "🖥️");
processResultFile(outputDir, ALERTS_PREFIX, "Alerts Summary", "🚨");
await processResultFile(outputDir, ALERTS_PREFIX, "Alerts Summary", "🚨");
await processResultFile(outputDir, PROCESS_TREE_PREFIX, "Process Tree", "🖥️");
await processResultFile(
outputDir,
NETWORK_EVENTS_PREFIX,
"Network Events",
"🌐",
);

if (!IS_GITHUB_ACTIONS) {
log(
Expand All @@ -128,8 +208,8 @@ function processResults(): void {
async function run(): Promise<void> {
try {
stopKnoxctlScan();
await new Promise((resolve) => setTimeout(resolve, 6000));
processResults();
await new Promise((resolve) => setTimeout(resolve, 9000));
await processResults();

const outputDir = getOutputDir();
await uploadArtifacts(outputDir);
Expand Down

0 comments on commit 845a9ac

Please sign in to comment.