feat: initial open marketplace with llm-security, config-audit, ultraplan-local
This commit is contained in:
commit
f93d6abdae
380 changed files with 65935 additions and 0 deletions
102
plugins/llm-security/scanners/lib/git-clone.mjs
Normal file
102
plugins/llm-security/scanners/lib/git-clone.mjs
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
#!/usr/bin/env node
|
||||
// git-clone.mjs — Clone GitHub repos to temp dirs for security scanning
|
||||
// Usage:
|
||||
// node git-clone.mjs clone <url> [--branch <name>] → shallow clone, prints tmpdir path
|
||||
// node git-clone.mjs cleanup <dir> → removes temp directory
|
||||
// node git-clone.mjs validate <url> → exits 0 if valid GitHub URL, 1 if not
|
||||
|
||||
import { mkdtempSync, rmSync, existsSync } from 'node:fs';
|
||||
import { join } from 'node:path';
|
||||
import { tmpdir } from 'node:os';
|
||||
import { spawnSync } from 'node:child_process';
|
||||
|
||||
const GITHUB_URL_RE = /^https:\/\/github\.com\/[\w.-]+\/[\w.-]+(\.git)?\/?$/;
|
||||
const GITHUB_SSH_RE = /^git@github\.com:[\w.-]+\/[\w.-]+(\.git)?$/;
|
||||
|
||||
function isValidUrl(url) {
|
||||
return GITHUB_URL_RE.test(url) || GITHUB_SSH_RE.test(url);
|
||||
}
|
||||
|
||||
function parseArgs(argv) {
|
||||
const args = { branch: null, positional: [] };
|
||||
for (let i = 0; i < argv.length; i++) {
|
||||
if (argv[i] === '--branch' && i + 1 < argv.length) {
|
||||
args.branch = argv[++i];
|
||||
} else {
|
||||
args.positional.push(argv[i]);
|
||||
}
|
||||
}
|
||||
return args;
|
||||
}
|
||||
|
||||
const [,, command, ...rest] = process.argv;
|
||||
|
||||
switch (command) {
|
||||
case 'clone': {
|
||||
const { branch, positional } = parseArgs(rest);
|
||||
const url = positional[0];
|
||||
|
||||
if (!url) {
|
||||
console.error('clone: URL required');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (!isValidUrl(url)) {
|
||||
console.error(`clone: invalid GitHub URL: ${url}`);
|
||||
console.error('Supported: https://github.com/user/repo or git@github.com:user/repo.git');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const tmpDir = mkdtempSync(join(tmpdir(), 'llm-sec-'));
|
||||
const gitArgs = ['clone', '--depth', '1'];
|
||||
if (branch) gitArgs.push('--branch', branch);
|
||||
gitArgs.push(url, tmpDir);
|
||||
|
||||
const result = spawnSync('git', gitArgs, {
|
||||
stdio: ['ignore', 'pipe', 'pipe'],
|
||||
timeout: 60_000,
|
||||
});
|
||||
|
||||
if (result.status !== 0) {
|
||||
// Clean up on failure
|
||||
try { rmSync(tmpDir, { recursive: true, force: true }); } catch {}
|
||||
const stderr = result.stderr?.toString().trim() || 'unknown error';
|
||||
console.error(`clone: git clone failed: ${stderr}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
process.stdout.write(tmpDir + '\n');
|
||||
break;
|
||||
}
|
||||
|
||||
case 'cleanup': {
|
||||
const dir = rest[0];
|
||||
if (!dir) {
|
||||
console.error('cleanup: directory path required');
|
||||
process.exit(1);
|
||||
}
|
||||
// Safety: only remove paths in system temp directory
|
||||
const tmp = tmpdir();
|
||||
if (!dir.startsWith(tmp)) {
|
||||
console.error(`cleanup: refusing to remove path outside tmpdir: ${dir}`);
|
||||
process.exit(1);
|
||||
}
|
||||
if (existsSync(dir)) {
|
||||
rmSync(dir, { recursive: true, force: true });
|
||||
process.stdout.write(`Removed ${dir}\n`);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'validate': {
|
||||
const url = rest[0];
|
||||
if (!url || !isValidUrl(url)) {
|
||||
process.exit(1);
|
||||
}
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
default:
|
||||
console.error('Usage: node git-clone.mjs <clone|cleanup|validate> [args...]');
|
||||
process.exit(1);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue