Class: KairosMcp::Daemon::RestrictedShell::PandocArgvValidator

Inherits:
BaseArgvValidator show all
Defined in:
lib/kairos_mcp/daemon/restricted_shell/argv_validators.rb

Overview

Pandoc: forbidden filters + engine whitelist.

Constant Summary collapse

FORBIDDEN_FLAGS =
%w[
  --filter --lua-filter -F -L
  --include-in-header --include-before-body --include-after-body -H -B -A
  --data-dir --defaults -d --extract-media
].freeze
ALLOWED_ENGINES =
%w[xelatex pdflatex lualatex].freeze

Constants inherited from BaseArgvValidator

BaseArgvValidator::UNIVERSAL_FORBIDDEN

Class Method Summary collapse

Methods inherited from BaseArgvValidator

validate!

Class Method Details

.validate_engine!(engine) ⇒ Object

Raises:



81
82
83
84
85
86
87
# File 'lib/kairos_mcp/daemon/restricted_shell/argv_validators.rb', line 81

def self.validate_engine!(engine)
  # R2 fix: reject any path — bare name only
  raise PolicyViolation, "pandoc engine must be bare name, got: #{engine}" if engine.include?('/')
  unless ALLOWED_ENGINES.include?(engine)
    raise PolicyViolation, "pandoc engine not allowed: #{engine} (allowed: #{ALLOWED_ENGINES})"
  end
end

.validate_engine_opt!(opt) ⇒ Object



89
90
91
92
93
94
# File 'lib/kairos_mcp/daemon/restricted_shell/argv_validators.rb', line 89

def self.validate_engine_opt!(opt)
  allowed = ['-no-shell-escape', '-output-directory']
  unless allowed.any? { |a| opt == a || opt.start_with?("#{a}=") }
    raise PolicyViolation, "pandoc engine option not allowed: #{opt}"
  end
end

.validate_specific!(argv) ⇒ Object



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/kairos_mcp/daemon/restricted_shell/argv_validators.rb', line 56

def self.validate_specific!(argv)
  argv.each_with_index do |arg, i|
    FORBIDDEN_FLAGS.each do |f|
      raise PolicyViolation, "pandoc #{f} forbidden" if arg == f || arg.start_with?("#{f}=")
    end

    # R2 residual: --pdf-engine must be bare name only (no path separators)
    if arg.start_with?('--pdf-engine=')
      engine = arg.split('=', 2).last
      validate_engine!(engine)
    elsif arg == '--pdf-engine' && i + 1 < argv.size
      validate_engine!(argv[i + 1])
    end

    # --pdf-engine-opt: strict allowlist
    if arg.start_with?('--pdf-engine-opt=')
      validate_engine_opt!(arg.split('=', 2).last)
    elsif arg == '--pdf-engine-opt' && i + 1 < argv.size
      validate_engine_opt!(argv[i + 1])
    end

    raise PolicyViolation, "pandoc URL argument forbidden" if arg.match?(%r{\Ahttps?://})
  end
end