ktg-plugin-marketplace/plugins/llm-security/scanners/lib/fs-utils.mjs
Kjell Tore Guttormsen 708c898754 feat(llm-security): sandboxed remote cloning v5.1.0
Harden git clone attack surface for remote scans with defense-in-depth:

Layer 1 (all platforms): 8 git config flags disable hooks, symlinks,
filter/smudge drivers, fsmonitor, local file protocol. 4 env vars
isolate from system/user git config and block interactive prompts.

Layer 2 (OS sandbox): macOS sandbox-exec and Linux bubblewrap (bwrap)
restrict file writes to only the specific temp directory. bwrap
probe-tests availability before use. Graceful fallback on Windows
and Ubuntu 24.04+ (git config hardening only).

Additional: post-clone 100MB size check, UUID-unique evidence filenames,
evidence file cleanup, cleanup guarantee in scan/plugin-audit commands.

32 new tests (1147 total).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 17:08:32 +02:00

66 lines
2.2 KiB
JavaScript

#!/usr/bin/env node
// fs-utils.mjs — Cross-platform file operations for /security clean
// Usage:
// node fs-utils.mjs backup <target> → prints backup path to stdout
// node fs-utils.mjs restore <backup> <target> → restores backup over target
// node fs-utils.mjs cleanup <backup> → removes backup directory
// node fs-utils.mjs tmppath <filename> → prints cross-platform temp file path
import { cpSync, rmSync, renameSync, existsSync } from 'node:fs';
import { join, basename } from 'node:path';
import { tmpdir } from 'node:os';
import { randomUUID } from 'node:crypto';
const [,, command, ...args] = process.argv;
switch (command) {
case 'backup': {
const target = args[0];
if (!target || !existsSync(target)) {
console.error(`backup: target does not exist: ${target}`);
process.exit(1);
}
const ts = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
const backupPath = `${target}.security-backup-${ts}`;
cpSync(target, backupPath, { recursive: true });
process.stdout.write(backupPath + '\n');
break;
}
case 'restore': {
const [backup, target] = args;
if (!backup || !existsSync(backup)) {
console.error(`restore: backup does not exist: ${backup}`);
process.exit(1);
}
if (target && existsSync(target)) {
rmSync(target, { recursive: true, force: true });
}
renameSync(backup, target);
process.stdout.write(`Restored ${backup}${target}\n`);
break;
}
case 'cleanup': {
const path = args[0];
if (path && existsSync(path)) {
rmSync(path, { recursive: true, force: true });
process.stdout.write(`Removed ${path}\n`);
}
break;
}
case 'tmppath': {
const base = args[0] || 'llm-security-temp.json';
const dotIdx = base.lastIndexOf('.');
const name = dotIdx > 0 ? base.slice(0, dotIdx) : base;
const ext = dotIdx > 0 ? base.slice(dotIdx) : '.json';
const unique = `${name}-${randomUUID().slice(0, 8)}${ext}`;
process.stdout.write(join(tmpdir(), unique) + '\n');
break;
}
default:
console.error('Usage: node fs-utils.mjs <backup|restore|cleanup|tmppath> [args...]');
process.exit(1);
}