sarif-ruby 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +10 -0
- data/LICENSE +21 -0
- data/README.md +191 -0
- data/Rakefile +10 -0
- data/lib/sarif/address.rb +67 -0
- data/lib/sarif/artifact.rb +76 -0
- data/lib/sarif/artifact_change.rb +46 -0
- data/lib/sarif/artifact_content.rb +49 -0
- data/lib/sarif/artifact_location.rb +52 -0
- data/lib/sarif/attachment.rb +52 -0
- data/lib/sarif/code_flow.rb +46 -0
- data/lib/sarif/configuration_override.rb +46 -0
- data/lib/sarif/conversion.rb +49 -0
- data/lib/sarif/edge.rb +52 -0
- data/lib/sarif/edge_traversal.rb +52 -0
- data/lib/sarif/exception.rb +52 -0
- data/lib/sarif/external_properties.rb +100 -0
- data/lib/sarif/external_property_file_reference.rb +49 -0
- data/lib/sarif/external_property_file_references.rb +88 -0
- data/lib/sarif/fix.rb +46 -0
- data/lib/sarif/graph.rb +49 -0
- data/lib/sarif/graph_traversal.rb +58 -0
- data/lib/sarif/invocation.rb +115 -0
- data/lib/sarif/location.rb +58 -0
- data/lib/sarif/location_relationship.rb +49 -0
- data/lib/sarif/log.rb +52 -0
- data/lib/sarif/logical_location.rb +58 -0
- data/lib/sarif/message.rb +52 -0
- data/lib/sarif/multiformat_message_string.rb +46 -0
- data/lib/sarif/node.rb +52 -0
- data/lib/sarif/notification.rb +64 -0
- data/lib/sarif/physical_location.rb +52 -0
- data/lib/sarif/property_bag.rb +40 -0
- data/lib/sarif/rectangle.rb +55 -0
- data/lib/sarif/region.rb +73 -0
- data/lib/sarif/replacement.rb +46 -0
- data/lib/sarif/reporting_configuration.rb +52 -0
- data/lib/sarif/reporting_descriptor.rb +79 -0
- data/lib/sarif/reporting_descriptor_reference.rb +52 -0
- data/lib/sarif/reporting_descriptor_relationship.rb +49 -0
- data/lib/sarif/result.rb +127 -0
- data/lib/sarif/result_provenance.rb +58 -0
- data/lib/sarif/run.rb +121 -0
- data/lib/sarif/run_automation_details.rb +52 -0
- data/lib/sarif/schema/sarif-schema-2.1.0.json +3389 -0
- data/lib/sarif/special_locations.rb +43 -0
- data/lib/sarif/stack.rb +46 -0
- data/lib/sarif/stack_frame.rb +52 -0
- data/lib/sarif/suppression.rb +55 -0
- data/lib/sarif/thread_flow.rb +55 -0
- data/lib/sarif/thread_flow_location.rb +79 -0
- data/lib/sarif/tool.rb +46 -0
- data/lib/sarif/tool_component.rb +121 -0
- data/lib/sarif/tool_component_reference.rb +49 -0
- data/lib/sarif/translation_metadata.rb +58 -0
- data/lib/sarif/version.rb +5 -0
- data/lib/sarif/version_control_details.rb +58 -0
- data/lib/sarif/web_request.rb +64 -0
- data/lib/sarif/web_response.rb +64 -0
- data/lib/sarif.rb +121 -0
- data/sig/sarif.rbs +4 -0
- metadata +106 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Sarif
|
|
4
|
+
# An area within an image.
|
|
5
|
+
class Rectangle
|
|
6
|
+
attr_accessor :top, :left, :bottom, :right, :message, :properties
|
|
7
|
+
|
|
8
|
+
def initialize(top: nil, left: nil, bottom: nil, right: nil, message: nil, properties: nil)
|
|
9
|
+
@top = top
|
|
10
|
+
@left = left
|
|
11
|
+
@bottom = bottom
|
|
12
|
+
@right = right
|
|
13
|
+
@message = message
|
|
14
|
+
@properties = properties
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def to_h
|
|
18
|
+
h = {}
|
|
19
|
+
h["top"] = @top unless @top.nil?
|
|
20
|
+
h["left"] = @left unless @left.nil?
|
|
21
|
+
h["bottom"] = @bottom unless @bottom.nil?
|
|
22
|
+
h["right"] = @right unless @right.nil?
|
|
23
|
+
h["message"] = @message&.to_h unless @message.nil?
|
|
24
|
+
h["properties"] = @properties unless @properties.nil?
|
|
25
|
+
h
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def to_json(pretty: false)
|
|
29
|
+
pretty ? JSON.pretty_generate(to_h) : JSON.generate(to_h)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def self.from_hash(h)
|
|
33
|
+
return nil if h.nil?
|
|
34
|
+
new(
|
|
35
|
+
top: h["top"],
|
|
36
|
+
left: h["left"],
|
|
37
|
+
bottom: h["bottom"],
|
|
38
|
+
right: h["right"],
|
|
39
|
+
message: Message.from_hash(h["message"]),
|
|
40
|
+
properties: h["properties"]
|
|
41
|
+
)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def ==(other)
|
|
45
|
+
return false unless other.is_a?(Rectangle)
|
|
46
|
+
@top == other.top && @left == other.left && @bottom == other.bottom && @right == other.right && @message == other.message && @properties == other.properties
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
alias eql? ==
|
|
50
|
+
|
|
51
|
+
def hash
|
|
52
|
+
[@top, @left, @bottom, @right, @message, @properties].hash
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
data/lib/sarif/region.rb
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Sarif
|
|
4
|
+
# A region within an artifact where a result was detected.
|
|
5
|
+
class Region
|
|
6
|
+
attr_accessor :start_line, :start_column, :end_line, :end_column, :char_offset, :char_length, :byte_offset, :byte_length, :snippet, :message, :source_language, :properties
|
|
7
|
+
|
|
8
|
+
def initialize(start_line: nil, start_column: nil, end_line: nil, end_column: nil, char_offset: -1, char_length: nil, byte_offset: -1, byte_length: nil, snippet: nil, message: nil, source_language: nil, properties: nil)
|
|
9
|
+
@start_line = start_line
|
|
10
|
+
@start_column = start_column
|
|
11
|
+
@end_line = end_line
|
|
12
|
+
@end_column = end_column
|
|
13
|
+
@char_offset = char_offset
|
|
14
|
+
@char_length = char_length
|
|
15
|
+
@byte_offset = byte_offset
|
|
16
|
+
@byte_length = byte_length
|
|
17
|
+
@snippet = snippet
|
|
18
|
+
@message = message
|
|
19
|
+
@source_language = source_language
|
|
20
|
+
@properties = properties
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def to_h
|
|
24
|
+
h = {}
|
|
25
|
+
h["startLine"] = @start_line unless @start_line.nil?
|
|
26
|
+
h["startColumn"] = @start_column unless @start_column.nil?
|
|
27
|
+
h["endLine"] = @end_line unless @end_line.nil?
|
|
28
|
+
h["endColumn"] = @end_column unless @end_column.nil?
|
|
29
|
+
h["charOffset"] = @char_offset if @char_offset && @char_offset != -1
|
|
30
|
+
h["charLength"] = @char_length unless @char_length.nil?
|
|
31
|
+
h["byteOffset"] = @byte_offset if @byte_offset && @byte_offset != -1
|
|
32
|
+
h["byteLength"] = @byte_length unless @byte_length.nil?
|
|
33
|
+
h["snippet"] = @snippet&.to_h unless @snippet.nil?
|
|
34
|
+
h["message"] = @message&.to_h unless @message.nil?
|
|
35
|
+
h["sourceLanguage"] = @source_language unless @source_language.nil?
|
|
36
|
+
h["properties"] = @properties unless @properties.nil?
|
|
37
|
+
h
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def to_json(pretty: false)
|
|
41
|
+
pretty ? JSON.pretty_generate(to_h) : JSON.generate(to_h)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def self.from_hash(h)
|
|
45
|
+
return nil if h.nil?
|
|
46
|
+
new(
|
|
47
|
+
start_line: h["startLine"],
|
|
48
|
+
start_column: h["startColumn"],
|
|
49
|
+
end_line: h["endLine"],
|
|
50
|
+
end_column: h["endColumn"],
|
|
51
|
+
char_offset: h["charOffset"] || -1,
|
|
52
|
+
char_length: h["charLength"],
|
|
53
|
+
byte_offset: h["byteOffset"] || -1,
|
|
54
|
+
byte_length: h["byteLength"],
|
|
55
|
+
snippet: ArtifactContent.from_hash(h["snippet"]),
|
|
56
|
+
message: Message.from_hash(h["message"]),
|
|
57
|
+
source_language: h["sourceLanguage"],
|
|
58
|
+
properties: h["properties"]
|
|
59
|
+
)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def ==(other)
|
|
63
|
+
return false unless other.is_a?(Region)
|
|
64
|
+
@start_line == other.start_line && @start_column == other.start_column && @end_line == other.end_line && @end_column == other.end_column && @char_offset == other.char_offset && @char_length == other.char_length && @byte_offset == other.byte_offset && @byte_length == other.byte_length && @snippet == other.snippet && @message == other.message && @source_language == other.source_language && @properties == other.properties
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
alias eql? ==
|
|
68
|
+
|
|
69
|
+
def hash
|
|
70
|
+
[@start_line, @start_column, @end_line, @end_column, @char_offset, @char_length, @byte_offset, @byte_length, @snippet, @message, @source_language, @properties].hash
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Sarif
|
|
4
|
+
# The replacement of a single region of an artifact.
|
|
5
|
+
class Replacement
|
|
6
|
+
attr_accessor :deleted_region, :inserted_content, :properties
|
|
7
|
+
|
|
8
|
+
def initialize(deleted_region:, inserted_content: nil, properties: nil)
|
|
9
|
+
@deleted_region = deleted_region
|
|
10
|
+
@inserted_content = inserted_content
|
|
11
|
+
@properties = properties
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def to_h
|
|
15
|
+
h = {}
|
|
16
|
+
h["deletedRegion"] = @deleted_region&.to_h
|
|
17
|
+
h["insertedContent"] = @inserted_content&.to_h unless @inserted_content.nil?
|
|
18
|
+
h["properties"] = @properties unless @properties.nil?
|
|
19
|
+
h
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def to_json(pretty: false)
|
|
23
|
+
pretty ? JSON.pretty_generate(to_h) : JSON.generate(to_h)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def self.from_hash(h)
|
|
27
|
+
return nil if h.nil?
|
|
28
|
+
new(
|
|
29
|
+
deleted_region: Region.from_hash(h["deletedRegion"]),
|
|
30
|
+
inserted_content: ArtifactContent.from_hash(h["insertedContent"]),
|
|
31
|
+
properties: h["properties"]
|
|
32
|
+
)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def ==(other)
|
|
36
|
+
return false unless other.is_a?(Replacement)
|
|
37
|
+
@deleted_region == other.deleted_region && @inserted_content == other.inserted_content && @properties == other.properties
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
alias eql? ==
|
|
41
|
+
|
|
42
|
+
def hash
|
|
43
|
+
[@deleted_region, @inserted_content, @properties].hash
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Sarif
|
|
4
|
+
# Information about a rule or notification that can be configured at runtime.
|
|
5
|
+
class ReportingConfiguration
|
|
6
|
+
attr_accessor :enabled, :level, :rank, :parameters, :properties
|
|
7
|
+
|
|
8
|
+
def initialize(enabled: true, level: "warning", rank: -1.0, parameters: nil, properties: nil)
|
|
9
|
+
@enabled = enabled
|
|
10
|
+
@level = level
|
|
11
|
+
@rank = rank
|
|
12
|
+
@parameters = parameters
|
|
13
|
+
@properties = properties
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def to_h
|
|
17
|
+
h = {}
|
|
18
|
+
h["enabled"] = @enabled unless @enabled
|
|
19
|
+
h["level"] = @level&.to_s if @level && @level != "warning"
|
|
20
|
+
h["rank"] = @rank if @rank && @rank != -1
|
|
21
|
+
h["parameters"] = @parameters unless @parameters.nil?
|
|
22
|
+
h["properties"] = @properties unless @properties.nil?
|
|
23
|
+
h
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def to_json(pretty: false)
|
|
27
|
+
pretty ? JSON.pretty_generate(to_h) : JSON.generate(to_h)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def self.from_hash(h)
|
|
31
|
+
return nil if h.nil?
|
|
32
|
+
new(
|
|
33
|
+
enabled: h.key?("enabled") ? h["enabled"] : true,
|
|
34
|
+
level: h["level"] || "warning",
|
|
35
|
+
rank: h["rank"] || -1.0,
|
|
36
|
+
parameters: h["parameters"],
|
|
37
|
+
properties: h["properties"]
|
|
38
|
+
)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def ==(other)
|
|
42
|
+
return false unless other.is_a?(ReportingConfiguration)
|
|
43
|
+
@enabled == other.enabled && @level == other.level && @rank == other.rank && @parameters == other.parameters && @properties == other.properties
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
alias eql? ==
|
|
47
|
+
|
|
48
|
+
def hash
|
|
49
|
+
[@enabled, @level, @rank, @parameters, @properties].hash
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Sarif
|
|
4
|
+
# Metadata that describes a specific report produced by the tool, as part of the analysis it provides or its runtime reporting.
|
|
5
|
+
class ReportingDescriptor
|
|
6
|
+
attr_accessor :id, :deprecated_ids, :guid, :deprecated_guids, :name, :deprecated_names, :short_description, :full_description, :message_strings, :default_configuration, :help_uri, :help, :relationships, :properties
|
|
7
|
+
|
|
8
|
+
def initialize(id:, deprecated_ids: nil, guid: nil, deprecated_guids: nil, name: nil, deprecated_names: nil, short_description: nil, full_description: nil, message_strings: nil, default_configuration: nil, help_uri: nil, help: nil, relationships: [], properties: nil)
|
|
9
|
+
@id = id
|
|
10
|
+
@deprecated_ids = deprecated_ids
|
|
11
|
+
@guid = guid
|
|
12
|
+
@deprecated_guids = deprecated_guids
|
|
13
|
+
@name = name
|
|
14
|
+
@deprecated_names = deprecated_names
|
|
15
|
+
@short_description = short_description
|
|
16
|
+
@full_description = full_description
|
|
17
|
+
@message_strings = message_strings
|
|
18
|
+
@default_configuration = default_configuration
|
|
19
|
+
@help_uri = help_uri
|
|
20
|
+
@help = help
|
|
21
|
+
@relationships = relationships
|
|
22
|
+
@properties = properties
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def to_h
|
|
26
|
+
h = {}
|
|
27
|
+
h["id"] = @id
|
|
28
|
+
h["deprecatedIds"] = @deprecated_ids if @deprecated_ids&.any?
|
|
29
|
+
h["guid"] = @guid unless @guid.nil?
|
|
30
|
+
h["deprecatedGuids"] = @deprecated_guids if @deprecated_guids&.any?
|
|
31
|
+
h["name"] = @name unless @name.nil?
|
|
32
|
+
h["deprecatedNames"] = @deprecated_names if @deprecated_names&.any?
|
|
33
|
+
h["shortDescription"] = @short_description&.to_h unless @short_description.nil?
|
|
34
|
+
h["fullDescription"] = @full_description&.to_h unless @full_description.nil?
|
|
35
|
+
h["messageStrings"] = @message_strings unless @message_strings.nil?
|
|
36
|
+
h["defaultConfiguration"] = @default_configuration&.to_h unless @default_configuration.nil?
|
|
37
|
+
h["helpUri"] = @help_uri unless @help_uri.nil?
|
|
38
|
+
h["help"] = @help&.to_h unless @help.nil?
|
|
39
|
+
h["relationships"] = @relationships&.map(&:to_h) if @relationships&.any?
|
|
40
|
+
h["properties"] = @properties unless @properties.nil?
|
|
41
|
+
h
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def to_json(pretty: false)
|
|
45
|
+
pretty ? JSON.pretty_generate(to_h) : JSON.generate(to_h)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def self.from_hash(h)
|
|
49
|
+
return nil if h.nil?
|
|
50
|
+
new(
|
|
51
|
+
id: h["id"],
|
|
52
|
+
deprecated_ids: h["deprecatedIds"],
|
|
53
|
+
guid: h["guid"],
|
|
54
|
+
deprecated_guids: h["deprecatedGuids"],
|
|
55
|
+
name: h["name"],
|
|
56
|
+
deprecated_names: h["deprecatedNames"],
|
|
57
|
+
short_description: MultiformatMessageString.from_hash(h["shortDescription"]),
|
|
58
|
+
full_description: MultiformatMessageString.from_hash(h["fullDescription"]),
|
|
59
|
+
message_strings: h["messageStrings"],
|
|
60
|
+
default_configuration: ReportingConfiguration.from_hash(h["defaultConfiguration"]),
|
|
61
|
+
help_uri: h["helpUri"],
|
|
62
|
+
help: MultiformatMessageString.from_hash(h["help"]),
|
|
63
|
+
relationships: h["relationships"]&.map { |v| ReportingDescriptorRelationship.from_hash(v) } || [],
|
|
64
|
+
properties: h["properties"]
|
|
65
|
+
)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def ==(other)
|
|
69
|
+
return false unless other.is_a?(ReportingDescriptor)
|
|
70
|
+
@id == other.id && @deprecated_ids == other.deprecated_ids && @guid == other.guid && @deprecated_guids == other.deprecated_guids && @name == other.name && @deprecated_names == other.deprecated_names && @short_description == other.short_description && @full_description == other.full_description && @message_strings == other.message_strings && @default_configuration == other.default_configuration && @help_uri == other.help_uri && @help == other.help && @relationships == other.relationships && @properties == other.properties
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
alias eql? ==
|
|
74
|
+
|
|
75
|
+
def hash
|
|
76
|
+
[@id, @deprecated_ids, @guid, @deprecated_guids, @name, @deprecated_names, @short_description, @full_description, @message_strings, @default_configuration, @help_uri, @help, @relationships, @properties].hash
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Sarif
|
|
4
|
+
# Information about how to locate a relevant reporting descriptor.
|
|
5
|
+
class ReportingDescriptorReference
|
|
6
|
+
attr_accessor :id, :index, :guid, :tool_component, :properties
|
|
7
|
+
|
|
8
|
+
def initialize(id: nil, index: -1, guid: nil, tool_component: nil, properties: nil)
|
|
9
|
+
@id = id
|
|
10
|
+
@index = index
|
|
11
|
+
@guid = guid
|
|
12
|
+
@tool_component = tool_component
|
|
13
|
+
@properties = properties
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def to_h
|
|
17
|
+
h = {}
|
|
18
|
+
h["id"] = @id unless @id.nil?
|
|
19
|
+
h["index"] = @index if @index && @index != -1
|
|
20
|
+
h["guid"] = @guid unless @guid.nil?
|
|
21
|
+
h["toolComponent"] = @tool_component&.to_h unless @tool_component.nil?
|
|
22
|
+
h["properties"] = @properties unless @properties.nil?
|
|
23
|
+
h
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def to_json(pretty: false)
|
|
27
|
+
pretty ? JSON.pretty_generate(to_h) : JSON.generate(to_h)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def self.from_hash(h)
|
|
31
|
+
return nil if h.nil?
|
|
32
|
+
new(
|
|
33
|
+
id: h["id"],
|
|
34
|
+
index: h["index"] || -1,
|
|
35
|
+
guid: h["guid"],
|
|
36
|
+
tool_component: ToolComponentReference.from_hash(h["toolComponent"]),
|
|
37
|
+
properties: h["properties"]
|
|
38
|
+
)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def ==(other)
|
|
42
|
+
return false unless other.is_a?(ReportingDescriptorReference)
|
|
43
|
+
@id == other.id && @index == other.index && @guid == other.guid && @tool_component == other.tool_component && @properties == other.properties
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
alias eql? ==
|
|
47
|
+
|
|
48
|
+
def hash
|
|
49
|
+
[@id, @index, @guid, @tool_component, @properties].hash
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Sarif
|
|
4
|
+
# Information about the relation of one reporting descriptor to another.
|
|
5
|
+
class ReportingDescriptorRelationship
|
|
6
|
+
attr_accessor :target, :kinds, :description, :properties
|
|
7
|
+
|
|
8
|
+
def initialize(target:, kinds: ["relevant"], description: nil, properties: nil)
|
|
9
|
+
@target = target
|
|
10
|
+
@kinds = kinds
|
|
11
|
+
@description = description
|
|
12
|
+
@properties = properties
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def to_h
|
|
16
|
+
h = {}
|
|
17
|
+
h["target"] = @target&.to_h
|
|
18
|
+
h["kinds"] = @kinds if @kinds&.any?
|
|
19
|
+
h["description"] = @description&.to_h unless @description.nil?
|
|
20
|
+
h["properties"] = @properties unless @properties.nil?
|
|
21
|
+
h
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def to_json(pretty: false)
|
|
25
|
+
pretty ? JSON.pretty_generate(to_h) : JSON.generate(to_h)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def self.from_hash(h)
|
|
29
|
+
return nil if h.nil?
|
|
30
|
+
new(
|
|
31
|
+
target: ReportingDescriptorReference.from_hash(h["target"]),
|
|
32
|
+
kinds: h.key?("kinds") ? h["kinds"] : ["relevant"],
|
|
33
|
+
description: Message.from_hash(h["description"]),
|
|
34
|
+
properties: h["properties"]
|
|
35
|
+
)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def ==(other)
|
|
39
|
+
return false unless other.is_a?(ReportingDescriptorRelationship)
|
|
40
|
+
@target == other.target && @kinds == other.kinds && @description == other.description && @properties == other.properties
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
alias eql? ==
|
|
44
|
+
|
|
45
|
+
def hash
|
|
46
|
+
[@target, @kinds, @description, @properties].hash
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
data/lib/sarif/result.rb
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Sarif
|
|
4
|
+
# A result produced by an analysis tool.
|
|
5
|
+
class Result
|
|
6
|
+
attr_accessor :rule_id, :rule_index, :rule, :kind, :level, :message, :analysis_target, :locations, :guid, :correlation_guid, :occurrence_count, :partial_fingerprints, :fingerprints, :stacks, :code_flows, :graphs, :graph_traversals, :related_locations, :suppressions, :baseline_state, :rank, :attachments, :hosted_viewer_uri, :work_item_uris, :provenance, :fixes, :taxa, :web_request, :web_response, :properties
|
|
7
|
+
|
|
8
|
+
def initialize(rule_id: nil, rule_index: -1, rule: nil, kind: "fail", level: "warning", message:, analysis_target: nil, locations: [], guid: nil, correlation_guid: nil, occurrence_count: nil, partial_fingerprints: nil, fingerprints: nil, stacks: [], code_flows: [], graphs: [], graph_traversals: [], related_locations: [], suppressions: nil, baseline_state: nil, rank: -1.0, attachments: [], hosted_viewer_uri: nil, work_item_uris: nil, provenance: nil, fixes: [], taxa: [], web_request: nil, web_response: nil, properties: nil)
|
|
9
|
+
@rule_id = rule_id
|
|
10
|
+
@rule_index = rule_index
|
|
11
|
+
@rule = rule
|
|
12
|
+
@kind = kind
|
|
13
|
+
@level = level
|
|
14
|
+
@message = message
|
|
15
|
+
@analysis_target = analysis_target
|
|
16
|
+
@locations = locations
|
|
17
|
+
@guid = guid
|
|
18
|
+
@correlation_guid = correlation_guid
|
|
19
|
+
@occurrence_count = occurrence_count
|
|
20
|
+
@partial_fingerprints = partial_fingerprints
|
|
21
|
+
@fingerprints = fingerprints
|
|
22
|
+
@stacks = stacks
|
|
23
|
+
@code_flows = code_flows
|
|
24
|
+
@graphs = graphs
|
|
25
|
+
@graph_traversals = graph_traversals
|
|
26
|
+
@related_locations = related_locations
|
|
27
|
+
@suppressions = suppressions
|
|
28
|
+
@baseline_state = baseline_state
|
|
29
|
+
@rank = rank
|
|
30
|
+
@attachments = attachments
|
|
31
|
+
@hosted_viewer_uri = hosted_viewer_uri
|
|
32
|
+
@work_item_uris = work_item_uris
|
|
33
|
+
@provenance = provenance
|
|
34
|
+
@fixes = fixes
|
|
35
|
+
@taxa = taxa
|
|
36
|
+
@web_request = web_request
|
|
37
|
+
@web_response = web_response
|
|
38
|
+
@properties = properties
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def to_h
|
|
42
|
+
h = {}
|
|
43
|
+
h["ruleId"] = @rule_id unless @rule_id.nil?
|
|
44
|
+
h["ruleIndex"] = @rule_index if @rule_index && @rule_index != -1
|
|
45
|
+
h["rule"] = @rule&.to_h unless @rule.nil?
|
|
46
|
+
h["kind"] = @kind&.to_s if @kind && @kind != "fail"
|
|
47
|
+
h["level"] = @level&.to_s if @level && @level != "warning"
|
|
48
|
+
h["message"] = @message&.to_h
|
|
49
|
+
h["analysisTarget"] = @analysis_target&.to_h unless @analysis_target.nil?
|
|
50
|
+
h["locations"] = @locations&.map(&:to_h) if @locations&.any?
|
|
51
|
+
h["guid"] = @guid unless @guid.nil?
|
|
52
|
+
h["correlationGuid"] = @correlation_guid unless @correlation_guid.nil?
|
|
53
|
+
h["occurrenceCount"] = @occurrence_count unless @occurrence_count.nil?
|
|
54
|
+
h["partialFingerprints"] = @partial_fingerprints unless @partial_fingerprints.nil?
|
|
55
|
+
h["fingerprints"] = @fingerprints unless @fingerprints.nil?
|
|
56
|
+
h["stacks"] = @stacks&.map(&:to_h) if @stacks&.any?
|
|
57
|
+
h["codeFlows"] = @code_flows&.map(&:to_h) if @code_flows&.any?
|
|
58
|
+
h["graphs"] = @graphs&.map(&:to_h) if @graphs&.any?
|
|
59
|
+
h["graphTraversals"] = @graph_traversals&.map(&:to_h) if @graph_traversals&.any?
|
|
60
|
+
h["relatedLocations"] = @related_locations&.map(&:to_h) if @related_locations&.any?
|
|
61
|
+
h["suppressions"] = @suppressions&.map(&:to_h) if @suppressions&.any?
|
|
62
|
+
h["baselineState"] = @baseline_state&.to_s unless @baseline_state.nil?
|
|
63
|
+
h["rank"] = @rank if @rank && @rank != -1
|
|
64
|
+
h["attachments"] = @attachments&.map(&:to_h) if @attachments&.any?
|
|
65
|
+
h["hostedViewerUri"] = @hosted_viewer_uri unless @hosted_viewer_uri.nil?
|
|
66
|
+
h["workItemUris"] = @work_item_uris if @work_item_uris&.any?
|
|
67
|
+
h["provenance"] = @provenance&.to_h unless @provenance.nil?
|
|
68
|
+
h["fixes"] = @fixes&.map(&:to_h) if @fixes&.any?
|
|
69
|
+
h["taxa"] = @taxa&.map(&:to_h) if @taxa&.any?
|
|
70
|
+
h["webRequest"] = @web_request&.to_h unless @web_request.nil?
|
|
71
|
+
h["webResponse"] = @web_response&.to_h unless @web_response.nil?
|
|
72
|
+
h["properties"] = @properties unless @properties.nil?
|
|
73
|
+
h
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def to_json(pretty: false)
|
|
77
|
+
pretty ? JSON.pretty_generate(to_h) : JSON.generate(to_h)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def self.from_hash(h)
|
|
81
|
+
return nil if h.nil?
|
|
82
|
+
new(
|
|
83
|
+
rule_id: h["ruleId"],
|
|
84
|
+
rule_index: h["ruleIndex"] || -1,
|
|
85
|
+
rule: ReportingDescriptorReference.from_hash(h["rule"]),
|
|
86
|
+
kind: h["kind"] || "fail",
|
|
87
|
+
level: h["level"] || "warning",
|
|
88
|
+
message: Message.from_hash(h["message"]),
|
|
89
|
+
analysis_target: ArtifactLocation.from_hash(h["analysisTarget"]),
|
|
90
|
+
locations: h["locations"]&.map { |v| Location.from_hash(v) } || [],
|
|
91
|
+
guid: h["guid"],
|
|
92
|
+
correlation_guid: h["correlationGuid"],
|
|
93
|
+
occurrence_count: h["occurrenceCount"],
|
|
94
|
+
partial_fingerprints: h["partialFingerprints"],
|
|
95
|
+
fingerprints: h["fingerprints"],
|
|
96
|
+
stacks: h["stacks"]&.map { |v| Stack.from_hash(v) } || [],
|
|
97
|
+
code_flows: h["codeFlows"]&.map { |v| CodeFlow.from_hash(v) } || [],
|
|
98
|
+
graphs: h["graphs"]&.map { |v| Graph.from_hash(v) } || [],
|
|
99
|
+
graph_traversals: h["graphTraversals"]&.map { |v| GraphTraversal.from_hash(v) } || [],
|
|
100
|
+
related_locations: h["relatedLocations"]&.map { |v| Location.from_hash(v) } || [],
|
|
101
|
+
suppressions: h["suppressions"]&.map { |v| Suppression.from_hash(v) },
|
|
102
|
+
baseline_state: h["baselineState"],
|
|
103
|
+
rank: h["rank"] || -1.0,
|
|
104
|
+
attachments: h["attachments"]&.map { |v| Attachment.from_hash(v) } || [],
|
|
105
|
+
hosted_viewer_uri: h["hostedViewerUri"],
|
|
106
|
+
work_item_uris: h["workItemUris"],
|
|
107
|
+
provenance: ResultProvenance.from_hash(h["provenance"]),
|
|
108
|
+
fixes: h["fixes"]&.map { |v| Fix.from_hash(v) } || [],
|
|
109
|
+
taxa: h["taxa"]&.map { |v| ReportingDescriptorReference.from_hash(v) } || [],
|
|
110
|
+
web_request: WebRequest.from_hash(h["webRequest"]),
|
|
111
|
+
web_response: WebResponse.from_hash(h["webResponse"]),
|
|
112
|
+
properties: h["properties"]
|
|
113
|
+
)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def ==(other)
|
|
117
|
+
return false unless other.is_a?(Result)
|
|
118
|
+
@rule_id == other.rule_id && @rule_index == other.rule_index && @rule == other.rule && @kind == other.kind && @level == other.level && @message == other.message && @analysis_target == other.analysis_target && @locations == other.locations && @guid == other.guid && @correlation_guid == other.correlation_guid && @occurrence_count == other.occurrence_count && @partial_fingerprints == other.partial_fingerprints && @fingerprints == other.fingerprints && @stacks == other.stacks && @code_flows == other.code_flows && @graphs == other.graphs && @graph_traversals == other.graph_traversals && @related_locations == other.related_locations && @suppressions == other.suppressions && @baseline_state == other.baseline_state && @rank == other.rank && @attachments == other.attachments && @hosted_viewer_uri == other.hosted_viewer_uri && @work_item_uris == other.work_item_uris && @provenance == other.provenance && @fixes == other.fixes && @taxa == other.taxa && @web_request == other.web_request && @web_response == other.web_response && @properties == other.properties
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
alias eql? ==
|
|
122
|
+
|
|
123
|
+
def hash
|
|
124
|
+
[@rule_id, @rule_index, @rule, @kind, @level, @message, @analysis_target, @locations, @guid, @correlation_guid, @occurrence_count, @partial_fingerprints, @fingerprints, @stacks, @code_flows, @graphs, @graph_traversals, @related_locations, @suppressions, @baseline_state, @rank, @attachments, @hosted_viewer_uri, @work_item_uris, @provenance, @fixes, @taxa, @web_request, @web_response, @properties].hash
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Sarif
|
|
4
|
+
# Contains information about how and when a result was detected.
|
|
5
|
+
class ResultProvenance
|
|
6
|
+
attr_accessor :first_detection_time_utc, :last_detection_time_utc, :first_detection_run_guid, :last_detection_run_guid, :invocation_index, :conversion_sources, :properties
|
|
7
|
+
|
|
8
|
+
def initialize(first_detection_time_utc: nil, last_detection_time_utc: nil, first_detection_run_guid: nil, last_detection_run_guid: nil, invocation_index: -1, conversion_sources: [], properties: nil)
|
|
9
|
+
@first_detection_time_utc = first_detection_time_utc
|
|
10
|
+
@last_detection_time_utc = last_detection_time_utc
|
|
11
|
+
@first_detection_run_guid = first_detection_run_guid
|
|
12
|
+
@last_detection_run_guid = last_detection_run_guid
|
|
13
|
+
@invocation_index = invocation_index
|
|
14
|
+
@conversion_sources = conversion_sources
|
|
15
|
+
@properties = properties
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def to_h
|
|
19
|
+
h = {}
|
|
20
|
+
h["firstDetectionTimeUtc"] = @first_detection_time_utc unless @first_detection_time_utc.nil?
|
|
21
|
+
h["lastDetectionTimeUtc"] = @last_detection_time_utc unless @last_detection_time_utc.nil?
|
|
22
|
+
h["firstDetectionRunGuid"] = @first_detection_run_guid unless @first_detection_run_guid.nil?
|
|
23
|
+
h["lastDetectionRunGuid"] = @last_detection_run_guid unless @last_detection_run_guid.nil?
|
|
24
|
+
h["invocationIndex"] = @invocation_index if @invocation_index && @invocation_index != -1
|
|
25
|
+
h["conversionSources"] = @conversion_sources&.map(&:to_h) if @conversion_sources&.any?
|
|
26
|
+
h["properties"] = @properties unless @properties.nil?
|
|
27
|
+
h
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def to_json(pretty: false)
|
|
31
|
+
pretty ? JSON.pretty_generate(to_h) : JSON.generate(to_h)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def self.from_hash(h)
|
|
35
|
+
return nil if h.nil?
|
|
36
|
+
new(
|
|
37
|
+
first_detection_time_utc: h["firstDetectionTimeUtc"],
|
|
38
|
+
last_detection_time_utc: h["lastDetectionTimeUtc"],
|
|
39
|
+
first_detection_run_guid: h["firstDetectionRunGuid"],
|
|
40
|
+
last_detection_run_guid: h["lastDetectionRunGuid"],
|
|
41
|
+
invocation_index: h["invocationIndex"] || -1,
|
|
42
|
+
conversion_sources: h["conversionSources"]&.map { |v| PhysicalLocation.from_hash(v) } || [],
|
|
43
|
+
properties: h["properties"]
|
|
44
|
+
)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def ==(other)
|
|
48
|
+
return false unless other.is_a?(ResultProvenance)
|
|
49
|
+
@first_detection_time_utc == other.first_detection_time_utc && @last_detection_time_utc == other.last_detection_time_utc && @first_detection_run_guid == other.first_detection_run_guid && @last_detection_run_guid == other.last_detection_run_guid && @invocation_index == other.invocation_index && @conversion_sources == other.conversion_sources && @properties == other.properties
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
alias eql? ==
|
|
53
|
+
|
|
54
|
+
def hash
|
|
55
|
+
[@first_detection_time_utc, @last_detection_time_utc, @first_detection_run_guid, @last_detection_run_guid, @invocation_index, @conversion_sources, @properties].hash
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|