mirror of
https://github.com/samiyev/puaros.git
synced 2025-12-28 07:16:53 +05:00
Git tools: - GitStatusTool: repository status (branch, staged, modified, untracked) - GitDiffTool: uncommitted changes with diff output - GitCommitTool: create commits with confirmation Run tools: - CommandSecurity: blacklist/whitelist shell command validation - RunCommandTool: execute shell commands with security checks - RunTestsTool: auto-detect and run vitest/jest/mocha/npm test All 18 planned tools now implemented. Tests: 1086 (+233), Coverage: 98.08%
258 lines
5.6 KiB
TypeScript
258 lines
5.6 KiB
TypeScript
/**
|
|
* Command security classification.
|
|
*/
|
|
export type CommandClassification = "allowed" | "blocked" | "requires_confirmation"
|
|
|
|
/**
|
|
* Result of command security check.
|
|
*/
|
|
export interface SecurityCheckResult {
|
|
/** Classification of the command */
|
|
classification: CommandClassification
|
|
/** Reason for the classification */
|
|
reason: string
|
|
}
|
|
|
|
/**
|
|
* Dangerous commands that are always blocked.
|
|
* These commands can cause data loss or security issues.
|
|
*/
|
|
export const DEFAULT_BLACKLIST: string[] = [
|
|
// Destructive file operations
|
|
"rm -rf",
|
|
"rm -r",
|
|
"rm -fr",
|
|
"rmdir",
|
|
// Dangerous git operations
|
|
"git push --force",
|
|
"git push -f",
|
|
"git reset --hard",
|
|
"git clean -fd",
|
|
"git clean -f",
|
|
// Publishing/deployment
|
|
"npm publish",
|
|
"yarn publish",
|
|
"pnpm publish",
|
|
// System commands
|
|
"sudo",
|
|
"su ",
|
|
"chmod",
|
|
"chown",
|
|
// Network/download commands that could be dangerous
|
|
"| sh",
|
|
"| bash",
|
|
// Environment manipulation
|
|
"export ",
|
|
"unset ",
|
|
// Process control
|
|
"kill -9",
|
|
"killall",
|
|
"pkill",
|
|
// Disk operations (require exact command start)
|
|
"mkfs",
|
|
"fdisk",
|
|
// Other dangerous
|
|
":(){ :|:& };:",
|
|
"eval ",
|
|
]
|
|
|
|
/**
|
|
* Safe commands that don't require confirmation.
|
|
* Matched by first word (command name).
|
|
*/
|
|
export const DEFAULT_WHITELIST: string[] = [
|
|
// Package managers
|
|
"npm",
|
|
"pnpm",
|
|
"yarn",
|
|
"npx",
|
|
"bun",
|
|
// Node.js
|
|
"node",
|
|
"tsx",
|
|
"ts-node",
|
|
// Git (read operations)
|
|
"git",
|
|
// Build tools
|
|
"tsc",
|
|
"tsup",
|
|
"esbuild",
|
|
"vite",
|
|
"webpack",
|
|
"rollup",
|
|
// Testing
|
|
"vitest",
|
|
"jest",
|
|
"mocha",
|
|
"playwright",
|
|
"cypress",
|
|
// Linting/formatting
|
|
"eslint",
|
|
"prettier",
|
|
"biome",
|
|
// Utilities
|
|
"echo",
|
|
"cat",
|
|
"ls",
|
|
"pwd",
|
|
"which",
|
|
"head",
|
|
"tail",
|
|
"grep",
|
|
"find",
|
|
"wc",
|
|
"sort",
|
|
"diff",
|
|
]
|
|
|
|
/**
|
|
* Git subcommands that are safe and don't need confirmation.
|
|
*/
|
|
const SAFE_GIT_SUBCOMMANDS: string[] = [
|
|
"status",
|
|
"log",
|
|
"diff",
|
|
"show",
|
|
"branch",
|
|
"remote",
|
|
"fetch",
|
|
"pull",
|
|
"stash",
|
|
"tag",
|
|
"blame",
|
|
"ls-files",
|
|
"ls-tree",
|
|
"rev-parse",
|
|
"describe",
|
|
]
|
|
|
|
/**
|
|
* Command security checker.
|
|
* Determines if a command is safe to execute, blocked, or requires confirmation.
|
|
*/
|
|
export class CommandSecurity {
|
|
private readonly blacklist: string[]
|
|
private readonly whitelist: string[]
|
|
|
|
constructor(blacklist: string[] = DEFAULT_BLACKLIST, whitelist: string[] = DEFAULT_WHITELIST) {
|
|
this.blacklist = blacklist.map((cmd) => cmd.toLowerCase())
|
|
this.whitelist = whitelist.map((cmd) => cmd.toLowerCase())
|
|
}
|
|
|
|
/**
|
|
* Check if a command is safe to execute.
|
|
*/
|
|
check(command: string): SecurityCheckResult {
|
|
const normalized = command.trim().toLowerCase()
|
|
|
|
const blacklistMatch = this.isBlacklisted(normalized)
|
|
if (blacklistMatch) {
|
|
return {
|
|
classification: "blocked",
|
|
reason: `Command contains blocked pattern: '${blacklistMatch}'`,
|
|
}
|
|
}
|
|
|
|
if (this.isWhitelisted(normalized)) {
|
|
return {
|
|
classification: "allowed",
|
|
reason: "Command is in the whitelist",
|
|
}
|
|
}
|
|
|
|
return {
|
|
classification: "requires_confirmation",
|
|
reason: "Command is not in the whitelist and requires user confirmation",
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if command matches any blacklist pattern.
|
|
* Returns the matched pattern or null.
|
|
*/
|
|
private isBlacklisted(command: string): string | null {
|
|
for (const pattern of this.blacklist) {
|
|
if (command.includes(pattern)) {
|
|
return pattern
|
|
}
|
|
}
|
|
return null
|
|
}
|
|
|
|
/**
|
|
* Check if command's first word is in the whitelist.
|
|
*/
|
|
private isWhitelisted(command: string): boolean {
|
|
const firstWord = this.getFirstWord(command)
|
|
|
|
if (!this.whitelist.includes(firstWord)) {
|
|
return false
|
|
}
|
|
|
|
if (firstWord === "git") {
|
|
return this.isGitCommandSafe(command)
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
/**
|
|
* Check if git command is safe (read-only operations).
|
|
*/
|
|
private isGitCommandSafe(command: string): boolean {
|
|
const parts = command.split(/\s+/)
|
|
if (parts.length < 2) {
|
|
return false
|
|
}
|
|
|
|
const subcommand = parts[1]
|
|
return SAFE_GIT_SUBCOMMANDS.includes(subcommand)
|
|
}
|
|
|
|
/**
|
|
* Get first word from command.
|
|
*/
|
|
private getFirstWord(command: string): string {
|
|
const match = /^(\S+)/.exec(command)
|
|
return match ? match[1] : ""
|
|
}
|
|
|
|
/**
|
|
* Add patterns to the blacklist.
|
|
*/
|
|
addToBlacklist(patterns: string[]): void {
|
|
for (const pattern of patterns) {
|
|
const normalized = pattern.toLowerCase()
|
|
if (!this.blacklist.includes(normalized)) {
|
|
this.blacklist.push(normalized)
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Add commands to the whitelist.
|
|
*/
|
|
addToWhitelist(commands: string[]): void {
|
|
for (const cmd of commands) {
|
|
const normalized = cmd.toLowerCase()
|
|
if (!this.whitelist.includes(normalized)) {
|
|
this.whitelist.push(normalized)
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get current blacklist.
|
|
*/
|
|
getBlacklist(): string[] {
|
|
return [...this.blacklist]
|
|
}
|
|
|
|
/**
|
|
* Get current whitelist.
|
|
*/
|
|
getWhitelist(): string[] {
|
|
return [...this.whitelist]
|
|
}
|
|
}
|