feat(llm-security-copilot): port llm-security v5.1.0 to GitHub Copilot CLI

Full port of llm-security plugin for internal use on Windows with GitHub
Copilot CLI. Protocol translation layer (copilot-hook-runner.mjs)
normalizes Copilot camelCase I/O to Claude Code snake_case format — all
original hook scripts run unmodified.

- 8 hooks with protocol translation (stdin/stdout/exit code)
- 18 SKILL.md skills (Agent Skills Open Standard)
- 6 .agent.md agent definitions
- 20 scanners + 14 scanner lib modules (unchanged)
- 14 knowledge files (unchanged)
- 39 test files including copilot-port-verify.mjs (17 tests)
- Windows-ready: node:path, os.tmpdir(), process.execPath, no bash

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-04-09 21:56:10 +02:00
commit f418a8fe08
169 changed files with 37631 additions and 0 deletions

View file

@ -0,0 +1,19 @@
// cache-dir.mjs — Cross-platform cache directory resolution.
// Windows: %LOCALAPPDATA%/llm-security or %APPDATA%/llm-security
// macOS/Linux: ~/.cache/llm-security (XDG_CACHE_HOME fallback)
import { homedir } from 'node:os';
import { join } from 'node:path';
export function getCacheDir() {
if (process.platform === 'win32') {
const localAppData = process.env.LOCALAPPDATA;
if (localAppData) return join(localAppData, 'llm-security');
const appData = process.env.APPDATA;
if (appData) return join(appData, 'llm-security');
return join(homedir(), '.cache', 'llm-security');
}
const xdg = process.env.XDG_CACHE_HOME;
if (xdg) return join(xdg, 'llm-security');
return join(homedir(), '.cache', 'llm-security');
}

View file

@ -0,0 +1,73 @@
#!/usr/bin/env node
// copilot-adapter.mjs — Normalizes GitHub Copilot hook I/O to internal format.
//
// Copilot CLI hooks receive JSON on stdin with camelCase field names
// (toolName, toolArgs, toolResult) and signal blocking via exit code 2
// or stdout JSON with permissionDecision: "deny".
//
// This adapter provides a consistent interface so hook logic stays
// platform-agnostic. If Copilot changes field names, only this file
// needs updating.
import { readFileSync } from 'node:fs';
/**
* Parse hook input from stdin. Returns normalized object or null on failure.
* Supports both Copilot (camelCase) and Claude Code (snake_case) field names.
*/
export function parseInput() {
try {
const raw = readFileSync(0, 'utf-8');
const input = JSON.parse(raw);
return {
toolName: input.toolName ?? input.tool_name ?? '',
toolInput: input.toolArgs ?? input.tool_input ?? {},
toolOutput: input.toolResult ?? input.tool_output ?? '',
message: input.message ?? {},
sessionId: input.sessionId ?? input.session_id ?? '',
raw: input,
};
} catch {
return null;
}
}
/**
* Block the tool call with a reason message.
*/
export function block(reason) {
process.stderr.write(reason + '\n');
process.stdout.write(JSON.stringify({
permissionDecision: 'deny',
reason,
}));
process.exit(2);
}
/**
* Allow the tool call, optionally with an advisory message.
*/
export function allow(message) {
if (message) {
process.stdout.write(JSON.stringify({
permissionDecision: 'allow',
message,
}));
}
process.exit(0);
}
/**
* Emit a warning to stderr without blocking. Exit 0.
*/
export function warn(message) {
process.stderr.write(message + '\n');
process.exit(0);
}
/**
* Fail-open: exit 0 silently. Used when input can't be parsed.
*/
export function failOpen() {
process.exit(0);
}

View file

@ -0,0 +1,25 @@
// windows-paths.mjs — Additional path patterns for Windows environments.
// Loaded by copilot-hook-runner.mjs when running on Windows.
//
// The original pre-write-pathguard.mjs has Unix-specific SYSTEM_PATTERNS
// that won't match on Windows. This module exports additional patterns
// for Windows system directories.
export const WINDOWS_SYSTEM_PATTERNS = [
/^[A-Z]:\\Windows\\/i,
/^[A-Z]:\\Program Files/i,
/^[A-Z]:\\Program Files \(x86\)/i,
/^[A-Z]:\\ProgramData\\/i,
/^[A-Z]:\\System Volume Information/i,
];
export const WINDOWS_CREDENTIAL_PATHS = [
/[\\/]\.docker[\\/]config\.json$/i,
/[\\/]\.kube[\\/]config$/i,
/[\\/]\.azure[\\/]/i,
/[\\/]\.aws[\\/]/i,
/[\\/]\.ssh[\\/]/i,
/[\\/]\.gnupg[\\/]/i,
/[\\/]AppData[\\/]Local[\\/]Google[\\/]Chrome[\\/]User Data/i,
/[\\/]AppData[\\/]Local[\\/]Microsoft[\\/]Edge[\\/]User Data/i,
];