Module: RailVerdict::MCP::Validators

Defined in:
lib/rail_verdict/mcp/validators.rb

Constant Summary collapse

FINDING_REF_PATTERN =
/\A(?:rv:[0-9a-f]{20}|sha256:[0-9a-f]{64})\z/
BASE_REVISION_PATTERN =
/\A[0-9a-f]{7,64}\z/
MAX_FINDING_REF_BYTES =
512

Class Method Summary collapse

Class Method Details

.scrub_text(value) ⇒ Object



76
77
78
# File 'lib/rail_verdict/mcp/validators.rb', line 76

def self.scrub_text(value)
  value.to_s.encode(Encoding::UTF_8, invalid: :replace, undef: :replace, replace: "\uFFFD").gsub(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/, "?")
end

.validate_base_revision(value) ⇒ Object

Raises:

  • (ArgumentError)


36
37
38
39
40
41
42
43
44
# File 'lib/rail_verdict/mcp/validators.rb', line 36

def self.validate_base_revision(value)
  return nil if value.nil?
  str = value.to_s.strip
  return nil if str.empty?
  raise ArgumentError, "base revision contains NUL byte" if str.include?("\u0000")
  raise ArgumentError, "base revision has invalid format" unless str.match?(BASE_REVISION_PATTERN)

  str
end

.validate_boolean(value, name) ⇒ Object

Raises:

  • (ArgumentError)


46
47
48
49
50
51
# File 'lib/rail_verdict/mcp/validators.rb', line 46

def self.validate_boolean(value, name)
  return false if value.nil?
  return value if value == true || value == false

  raise ArgumentError, "#{name} must be a boolean"
end

.validate_finding_ref(value) ⇒ Object

Raises:

  • (ArgumentError)


10
11
12
13
14
15
16
17
# File 'lib/rail_verdict/mcp/validators.rb', line 10

def self.validate_finding_ref(value)
  raise ArgumentError, "finding_ref must be a non-empty string" unless value.is_a?(String) && !value.strip.empty?
  raise ArgumentError, "finding_ref exceeds #{MAX_FINDING_REF_BYTES} bytes" if value.bytesize > MAX_FINDING_REF_BYTES
  raise ArgumentError, "finding_ref contains NUL byte" if value.include?("\u0000")
  raise ArgumentError, "finding_ref has invalid format" unless value.strip.match?(FINDING_REF_PATTERN)

  value.strip
end

.validate_limit(value, default: 50, max: 100) ⇒ Object

Raises:

  • (ArgumentError)


19
20
21
22
23
24
25
26
# File 'lib/rail_verdict/mcp/validators.rb', line 19

def self.validate_limit(value, default: 50, max: 100)
  return default if value.nil?

  raise ArgumentError, "limit must be an integer" unless value.is_a?(Integer)
  raise ArgumentError, "limit must be between 1 and #{max}" unless value.between?(1, max)

  value
end

.validate_offset(value) ⇒ Object

Raises:

  • (ArgumentError)


28
29
30
31
32
33
34
# File 'lib/rail_verdict/mcp/validators.rb', line 28

def self.validate_offset(value)
  return 0 if value.nil?

  raise ArgumentError, "offset must be an integer >= 0" unless value.is_a?(Integer) && value >= 0

  value
end

.validate_packet_id(value) ⇒ Object

Raises:

  • (ArgumentError)


69
70
71
72
73
74
# File 'lib/rail_verdict/mcp/validators.rb', line 69

def self.validate_packet_id(value)
  raise ArgumentError, "packet_id must be a non-empty string" unless value.is_a?(String) && !value.strip.empty?
  raise ArgumentError, "packet_id has invalid format" unless value.strip.match?(/\Asha256:[0-9a-f]{64}\z/)

  value.strip
end

.validate_severity(value) ⇒ Object

Raises:

  • (ArgumentError)


53
54
55
56
57
58
59
# File 'lib/rail_verdict/mcp/validators.rb', line 53

def self.validate_severity(value)
  return nil if value.nil?
  allowed = %w[info low medium high critical]
  raise ArgumentError, "severity must be one of #{allowed.join(', ')}" unless allowed.include?(value)

  value
end

.validate_state(value) ⇒ Object

Raises:

  • (ArgumentError)


61
62
63
64
65
66
67
# File 'lib/rail_verdict/mcp/validators.rb', line 61

def self.validate_state(value)
  return nil if value.nil?
  allowed = %w[observed introduced existing resolved changed moved suppressed waived]
  raise ArgumentError, "state must be one of #{allowed.join(', ')}" unless allowed.include?(value)

  value
end