Module: FiberAudit::Runtime::Validation

Defined in:
lib/fiber_audit/runtime/validation.rb

Constant Summary collapse

IDENTIFIER =
/\A[a-z][a-z0-9_]*\z/
UUID =
/\A[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}\z/
CONTROL =
/[[:cntrl:]]/
OPERATION =
/\A(?:::)?[A-Z][A-Za-z0-9_]*(?:::[A-Z][A-Za-z0-9_]*)*(?:[.#](?:[a-zA-Z_][a-zA-Z0-9_]*[!?=]?|\[\]=?))\z/
SPECIAL_OPERATIONS =
%w[Thread.current.[] Thread.current.[]=].freeze

Class Method Summary collapse

Class Method Details

.finite_number(value, field) ⇒ Object



55
56
57
58
59
# File 'lib/fiber_audit/runtime/validation.rb', line 55

def finite_number(value, field)
  raise RuntimeContractError, "#{field} must be a finite number" unless value.is_a?(Numeric) && value.finite?

  value
end

.identifier(value, field, max_bytes: 64) ⇒ Object



16
17
18
19
20
21
22
23
# File 'lib/fiber_audit/runtime/validation.rb', line 16

def identifier(value, field, max_bytes: 64)
  normalized = value.is_a?(String) || value.is_a?(Symbol) ? value.to_s : nil
  unless normalized&.match?(IDENTIFIER) && normalized.bytesize <= max_bytes
    raise RuntimeContractError, "#{field} must be a snake-case identifier"
  end

  normalized.to_sym
end

.integer(value, field, minimum: 0, allow_nil: false) ⇒ Object



46
47
48
49
50
51
52
53
# File 'lib/fiber_audit/runtime/validation.rb', line 46

def integer(value, field, minimum: 0, allow_nil: false)
  return if value.nil? && allow_nil
  unless value.is_a?(Integer) && value >= minimum
    raise RuntimeContractError, "#{field} must be an Integer >= #{minimum}"
  end

  value
end

.operation(value, allow_nil: false) ⇒ Object



35
36
37
38
39
40
41
42
43
44
# File 'lib/fiber_audit/runtime/validation.rb', line 35

def operation(value, allow_nil: false)
  return if value.nil? && allow_nil

  normalized = string(value, 'operation', max_bytes: 256)
  unless normalized == '[redacted]' || SPECIAL_OPERATIONS.include?(normalized) || normalized.match?(OPERATION)
    raise RuntimeContractError, 'operation must be canonical or redacted'
  end

  normalized
end

.string(value, field, max_bytes:, allow_nil: false) ⇒ Object



25
26
27
28
29
30
31
32
33
# File 'lib/fiber_audit/runtime/validation.rb', line 25

def string(value, field, max_bytes:, allow_nil: false)
  return if value.nil? && allow_nil
  unless value.is_a?(String) && value.valid_encoding? && !value.empty? &&
         value.bytesize <= max_bytes && !value.match?(CONTROL)
    raise RuntimeContractError, "#{field} must be a non-empty UTF-8 String without control characters"
  end

  value.dup.freeze
end

.utc_time(value, field) ⇒ Object



61
62
63
64
65
# File 'lib/fiber_audit/runtime/validation.rb', line 61

def utc_time(value, field)
  raise RuntimeContractError, "#{field} must be a Time" unless value.is_a?(Time)

  value.getutc.freeze
end