isReadOnlyCommand function

({bool isSafe, String? reason}) isReadOnlyCommand(
  1. String command
)

Check if a command is safe in read-only mode.

Implementation

({bool isSafe, String? reason}) isReadOnlyCommand(String command) {
  final segments = command.split(RegExp(r'\s*[|;&]\s*'));

  for (final seg in segments) {
    final parts = seg.trim().split(RegExp(r'\s+'));
    if (parts.isEmpty) continue;

    final base = parts.first;

    // Strip env var prefixes (FOO=bar command)
    var cmd = base;
    if (cmd.contains('=')) {
      final remaining = parts.sublist(1);
      if (remaining.isEmpty) continue;
      cmd = remaining.first;
    }

    if (!_readOnlySafeCommands.contains(cmd) &&
        !_safeGitSubcommands.contains(cmd)) {
      // Check git subcommand
      if (cmd == 'git' && parts.length > 1) {
        final subCmd = parts[1];
        if (!_safeGitSubcommands.contains(subCmd)) {
          return (
            isSafe: false,
            reason: 'git $subCmd is not allowed in read-only mode',
          );
        }
      } else {
        return (isSafe: false, reason: '$cmd is not allowed in read-only mode');
      }
    }

    // Check sed -i (in-place edit)
    if (cmd == 'sed' && (parts.contains('-i') || parts.contains('-i.bak'))) {
      return (
        isSafe: false,
        reason: 'sed -i (in-place edit) is not allowed in read-only mode',
      );
    }

    // Check output redirection
    if (seg.contains('>') || seg.contains('>>')) {
      return (
        isSafe: false,
        reason: 'Output redirection is not allowed in read-only mode',
      );
    }
  }

  return (isSafe: true, reason: null);
}