Parsing & Validation
sarif.cr can read existing SARIF JSON and validate documents against the specification.
Parsing SARIF JSON
Parse a JSON string into a SarifLog:
json = File.read("results.sarif")
log = Sarif.parse(json)
log.runs.each do |run|
puts "Tool: #{run.tool.driver.name}"
run.results.try &.each do |result|
puts " #{result.level}: #{result.message.text}"
end
end
Reading from a File
Use the convenience method to read and parse in one step:
log = Sarif.from_file("results.sarif")
Parsing with Validation
Use parse! or from_file! to parse and validate in one step. These raise an exception if validation fails:
begin
log = Sarif.parse!(json)
rescue ex
puts "Invalid SARIF: #{ex.message}"
end
begin
log = Sarif.from_file!("results.sarif")
rescue ex
puts "Invalid SARIF: #{ex.message}"
end
Manual Validation
Run validation separately using Sarif::Validator:
log = Sarif.parse(json)
result = Sarif::Validator.new.validate(log)
if result.valid?
puts "Valid SARIF document"
else
result.errors.each do |error|
puts "#{error.path}: #{error.message}"
end
end
Validation Checks
The validator checks for:
- Version -- Must be
"2.1.0" - Tool driver name -- Must not be empty
- Result message -- Must have either
textorid - Rule index --
ruleIndexmust reference a valid rule in the driver - Rule ID consistency --
ruleIdmust match the rule atruleIndex
Working with Parsed Data
After parsing, you can navigate the full object graph:
log = Sarif.from_file("eslint-results.sarif")
run = log.runs[0]
# Access tool info
puts run.tool.driver.name # => "ESLint"
puts run.tool.driver.version # => "8.0.0"
# Access rules
run.tool.driver.rules.try &.each do |rule|
puts "#{rule.id}: #{rule.short_description.try &.text}"
end
# Access results
run.results.try &.each do |result|
loc = result.locations.try &.[0]?
if phys = loc.try &.physical_location
uri = phys.artifact_location.try &.uri
line = phys.region.try &.start_line
puts "#{uri}:#{line} - #{result.message.text}"
end
end
Error Handling
JSON parsing errors from malformed input are raised as standard Crystal exceptions:
begin
log = Sarif.parse("invalid json")
rescue ex : JSON::ParseException
puts "Malformed JSON: #{ex.message}"
end
Validation errors from structurally invalid SARIF are raised by the ! variants:
begin
log = Sarif.parse!(%({ "version": "1.0", "runs": [] }))
rescue ex
puts ex.message
# => "SARIF validation failed: $.version: Unsupported SARIF version: 1.0. Expected 2.1.0"
end