validateCommandSecurity function

SecurityCheckResult validateCommandSecurity(
  1. String command
)

Validate a command for security issues.

Implementation

SecurityCheckResult validateCommandSecurity(String command) {
  final violations = <String>[];
  final warnings = <String>[];

  final trimmed = command.trim();
  if (trimmed.isEmpty) {
    return const SecurityCheckResult(
      passed: false,
      violations: ['Empty command'],
    );
  }

  // Check for dangerous zsh builtins
  final baseCmd = trimmed.split(RegExp(r'\s+')).first;
  if (_dangerousZshBuiltins.contains(baseCmd)) {
    violations.add('Dangerous zsh builtin: $baseCmd');
  }

  // Check zf_ prefixed commands
  if (baseCmd.startsWith('zf_')) {
    violations.add('Dangerous zsh function: $baseCmd');
  }

  // Check for command substitution patterns
  if (_commandSubstitutionPattern.hasMatch(command)) {
    // Allow $() in single-quoted strings
    final inSingleQuote = _isInSingleQuotes(
      command,
      _commandSubstitutionPattern,
    );
    if (!inSingleQuote) {
      violations.add(
        'Command substitution detected — use explicit commands instead',
      );
    }
  }

  // Check for backticks
  if (_hasUnescapedBackticks(command)) {
    violations.add('Backtick command substitution — use \$() instead');
  }

  // Check for control characters
  if (RegExp(r'[\x00-\x08\x0e-\x1f]').hasMatch(command)) {
    violations.add('Control characters detected in command');
  }

  // Check destructive patterns (warnings, not blocking)
  if (_destructiveGitPatterns.hasMatch(command)) {
    warnings.add('Destructive git operation detected');
  }
  if (_destructivePatterns.hasMatch(command)) {
    warnings.add('Potentially destructive operation detected');
  }

  // Check for sleep > 2s (suggest background instead)
  final sleepMatch = RegExp(r'\bsleep\s+(\d+)').firstMatch(command);
  if (sleepMatch != null) {
    final seconds = int.tryParse(sleepMatch.group(1)!) ?? 0;
    if (seconds > 2) {
      warnings.add('Sleep > 2s — consider running in background');
    }
  }

  return SecurityCheckResult(
    passed: violations.isEmpty,
    violations: violations,
    warnings: warnings,
  );
}