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.
Files changed (64) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +5 -0
  3. data/CODE_OF_CONDUCT.md +10 -0
  4. data/LICENSE +21 -0
  5. data/README.md +191 -0
  6. data/Rakefile +10 -0
  7. data/lib/sarif/address.rb +67 -0
  8. data/lib/sarif/artifact.rb +76 -0
  9. data/lib/sarif/artifact_change.rb +46 -0
  10. data/lib/sarif/artifact_content.rb +49 -0
  11. data/lib/sarif/artifact_location.rb +52 -0
  12. data/lib/sarif/attachment.rb +52 -0
  13. data/lib/sarif/code_flow.rb +46 -0
  14. data/lib/sarif/configuration_override.rb +46 -0
  15. data/lib/sarif/conversion.rb +49 -0
  16. data/lib/sarif/edge.rb +52 -0
  17. data/lib/sarif/edge_traversal.rb +52 -0
  18. data/lib/sarif/exception.rb +52 -0
  19. data/lib/sarif/external_properties.rb +100 -0
  20. data/lib/sarif/external_property_file_reference.rb +49 -0
  21. data/lib/sarif/external_property_file_references.rb +88 -0
  22. data/lib/sarif/fix.rb +46 -0
  23. data/lib/sarif/graph.rb +49 -0
  24. data/lib/sarif/graph_traversal.rb +58 -0
  25. data/lib/sarif/invocation.rb +115 -0
  26. data/lib/sarif/location.rb +58 -0
  27. data/lib/sarif/location_relationship.rb +49 -0
  28. data/lib/sarif/log.rb +52 -0
  29. data/lib/sarif/logical_location.rb +58 -0
  30. data/lib/sarif/message.rb +52 -0
  31. data/lib/sarif/multiformat_message_string.rb +46 -0
  32. data/lib/sarif/node.rb +52 -0
  33. data/lib/sarif/notification.rb +64 -0
  34. data/lib/sarif/physical_location.rb +52 -0
  35. data/lib/sarif/property_bag.rb +40 -0
  36. data/lib/sarif/rectangle.rb +55 -0
  37. data/lib/sarif/region.rb +73 -0
  38. data/lib/sarif/replacement.rb +46 -0
  39. data/lib/sarif/reporting_configuration.rb +52 -0
  40. data/lib/sarif/reporting_descriptor.rb +79 -0
  41. data/lib/sarif/reporting_descriptor_reference.rb +52 -0
  42. data/lib/sarif/reporting_descriptor_relationship.rb +49 -0
  43. data/lib/sarif/result.rb +127 -0
  44. data/lib/sarif/result_provenance.rb +58 -0
  45. data/lib/sarif/run.rb +121 -0
  46. data/lib/sarif/run_automation_details.rb +52 -0
  47. data/lib/sarif/schema/sarif-schema-2.1.0.json +3389 -0
  48. data/lib/sarif/special_locations.rb +43 -0
  49. data/lib/sarif/stack.rb +46 -0
  50. data/lib/sarif/stack_frame.rb +52 -0
  51. data/lib/sarif/suppression.rb +55 -0
  52. data/lib/sarif/thread_flow.rb +55 -0
  53. data/lib/sarif/thread_flow_location.rb +79 -0
  54. data/lib/sarif/tool.rb +46 -0
  55. data/lib/sarif/tool_component.rb +121 -0
  56. data/lib/sarif/tool_component_reference.rb +49 -0
  57. data/lib/sarif/translation_metadata.rb +58 -0
  58. data/lib/sarif/version.rb +5 -0
  59. data/lib/sarif/version_control_details.rb +58 -0
  60. data/lib/sarif/web_request.rb +64 -0
  61. data/lib/sarif/web_response.rb +64 -0
  62. data/lib/sarif.rb +121 -0
  63. data/sig/sarif.rbs +4 -0
  64. metadata +106 -0
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sarif
4
+ # Describes how a converter transformed the output of a static analysis tool from the analysis tool's native output format into the SARIF format.
5
+ class Conversion
6
+ attr_accessor :tool, :invocation, :analysis_tool_log_files, :properties
7
+
8
+ def initialize(tool:, invocation: nil, analysis_tool_log_files: [], properties: nil)
9
+ @tool = tool
10
+ @invocation = invocation
11
+ @analysis_tool_log_files = analysis_tool_log_files
12
+ @properties = properties
13
+ end
14
+
15
+ def to_h
16
+ h = {}
17
+ h["tool"] = @tool&.to_h
18
+ h["invocation"] = @invocation&.to_h unless @invocation.nil?
19
+ h["analysisToolLogFiles"] = @analysis_tool_log_files&.map(&:to_h) if @analysis_tool_log_files&.any?
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
+ tool: Tool.from_hash(h["tool"]),
32
+ invocation: Invocation.from_hash(h["invocation"]),
33
+ analysis_tool_log_files: h["analysisToolLogFiles"]&.map { |v| ArtifactLocation.from_hash(v) } || [],
34
+ properties: h["properties"]
35
+ )
36
+ end
37
+
38
+ def ==(other)
39
+ return false unless other.is_a?(Conversion)
40
+ @tool == other.tool && @invocation == other.invocation && @analysis_tool_log_files == other.analysis_tool_log_files && @properties == other.properties
41
+ end
42
+
43
+ alias eql? ==
44
+
45
+ def hash
46
+ [@tool, @invocation, @analysis_tool_log_files, @properties].hash
47
+ end
48
+ end
49
+ end
data/lib/sarif/edge.rb ADDED
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sarif
4
+ # Represents a directed edge in a graph.
5
+ class Edge
6
+ attr_accessor :id, :label, :source_node_id, :target_node_id, :properties
7
+
8
+ def initialize(id:, label: nil, source_node_id:, target_node_id:, properties: nil)
9
+ @id = id
10
+ @label = label
11
+ @source_node_id = source_node_id
12
+ @target_node_id = target_node_id
13
+ @properties = properties
14
+ end
15
+
16
+ def to_h
17
+ h = {}
18
+ h["id"] = @id
19
+ h["label"] = @label&.to_h unless @label.nil?
20
+ h["sourceNodeId"] = @source_node_id
21
+ h["targetNodeId"] = @target_node_id
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
+ label: Message.from_hash(h["label"]),
35
+ source_node_id: h["sourceNodeId"],
36
+ target_node_id: h["targetNodeId"],
37
+ properties: h["properties"]
38
+ )
39
+ end
40
+
41
+ def ==(other)
42
+ return false unless other.is_a?(Edge)
43
+ @id == other.id && @label == other.label && @source_node_id == other.source_node_id && @target_node_id == other.target_node_id && @properties == other.properties
44
+ end
45
+
46
+ alias eql? ==
47
+
48
+ def hash
49
+ [@id, @label, @source_node_id, @target_node_id, @properties].hash
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sarif
4
+ # Represents the traversal of a single edge during a graph traversal.
5
+ class EdgeTraversal
6
+ attr_accessor :edge_id, :message, :final_state, :step_over_edge_count, :properties
7
+
8
+ def initialize(edge_id:, message: nil, final_state: nil, step_over_edge_count: nil, properties: nil)
9
+ @edge_id = edge_id
10
+ @message = message
11
+ @final_state = final_state
12
+ @step_over_edge_count = step_over_edge_count
13
+ @properties = properties
14
+ end
15
+
16
+ def to_h
17
+ h = {}
18
+ h["edgeId"] = @edge_id
19
+ h["message"] = @message&.to_h unless @message.nil?
20
+ h["finalState"] = @final_state unless @final_state.nil?
21
+ h["stepOverEdgeCount"] = @step_over_edge_count unless @step_over_edge_count.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
+ edge_id: h["edgeId"],
34
+ message: Message.from_hash(h["message"]),
35
+ final_state: h["finalState"],
36
+ step_over_edge_count: h["stepOverEdgeCount"],
37
+ properties: h["properties"]
38
+ )
39
+ end
40
+
41
+ def ==(other)
42
+ return false unless other.is_a?(EdgeTraversal)
43
+ @edge_id == other.edge_id && @message == other.message && @final_state == other.final_state && @step_over_edge_count == other.step_over_edge_count && @properties == other.properties
44
+ end
45
+
46
+ alias eql? ==
47
+
48
+ def hash
49
+ [@edge_id, @message, @final_state, @step_over_edge_count, @properties].hash
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sarif
4
+ # Describes a runtime exception encountered during the execution of an analysis tool.
5
+ class Exception
6
+ attr_accessor :kind, :message, :stack, :inner_exceptions, :properties
7
+
8
+ def initialize(kind: nil, message: nil, stack: nil, inner_exceptions: [], properties: nil)
9
+ @kind = kind
10
+ @message = message
11
+ @stack = stack
12
+ @inner_exceptions = inner_exceptions
13
+ @properties = properties
14
+ end
15
+
16
+ def to_h
17
+ h = {}
18
+ h["kind"] = @kind unless @kind.nil?
19
+ h["message"] = @message unless @message.nil?
20
+ h["stack"] = @stack&.to_h unless @stack.nil?
21
+ h["innerExceptions"] = @inner_exceptions&.map(&:to_h) if @inner_exceptions&.any?
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
+ kind: h["kind"],
34
+ message: h["message"],
35
+ stack: Stack.from_hash(h["stack"]),
36
+ inner_exceptions: h["innerExceptions"]&.map { |v| Exception.from_hash(v) } || [],
37
+ properties: h["properties"]
38
+ )
39
+ end
40
+
41
+ def ==(other)
42
+ return false unless other.is_a?(Exception)
43
+ @kind == other.kind && @message == other.message && @stack == other.stack && @inner_exceptions == other.inner_exceptions && @properties == other.properties
44
+ end
45
+
46
+ alias eql? ==
47
+
48
+ def hash
49
+ [@kind, @message, @stack, @inner_exceptions, @properties].hash
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sarif
4
+ # The top-level element of an external property file.
5
+ class ExternalProperties
6
+ attr_accessor :schema, :version, :guid, :run_guid, :conversion, :graphs, :externalized_properties, :artifacts, :invocations, :logical_locations, :thread_flow_locations, :results, :taxonomies, :driver, :extensions, :policies, :translations, :addresses, :web_requests, :web_responses, :properties
7
+
8
+ def initialize(schema: nil, version: nil, guid: nil, run_guid: nil, conversion: nil, graphs: [], externalized_properties: nil, artifacts: nil, invocations: [], logical_locations: [], thread_flow_locations: [], results: [], taxonomies: [], driver: nil, extensions: [], policies: [], translations: [], addresses: [], web_requests: [], web_responses: [], properties: nil)
9
+ @schema = schema
10
+ @version = version
11
+ @guid = guid
12
+ @run_guid = run_guid
13
+ @conversion = conversion
14
+ @graphs = graphs
15
+ @externalized_properties = externalized_properties
16
+ @artifacts = artifacts
17
+ @invocations = invocations
18
+ @logical_locations = logical_locations
19
+ @thread_flow_locations = thread_flow_locations
20
+ @results = results
21
+ @taxonomies = taxonomies
22
+ @driver = driver
23
+ @extensions = extensions
24
+ @policies = policies
25
+ @translations = translations
26
+ @addresses = addresses
27
+ @web_requests = web_requests
28
+ @web_responses = web_responses
29
+ @properties = properties
30
+ end
31
+
32
+ def to_h
33
+ h = {}
34
+ h["schema"] = @schema unless @schema.nil?
35
+ h["version"] = @version&.to_s unless @version.nil?
36
+ h["guid"] = @guid unless @guid.nil?
37
+ h["runGuid"] = @run_guid unless @run_guid.nil?
38
+ h["conversion"] = @conversion&.to_h unless @conversion.nil?
39
+ h["graphs"] = @graphs&.map(&:to_h) if @graphs&.any?
40
+ h["externalizedProperties"] = @externalized_properties unless @externalized_properties.nil?
41
+ h["artifacts"] = @artifacts&.map(&:to_h) if @artifacts&.any?
42
+ h["invocations"] = @invocations&.map(&:to_h) if @invocations&.any?
43
+ h["logicalLocations"] = @logical_locations&.map(&:to_h) if @logical_locations&.any?
44
+ h["threadFlowLocations"] = @thread_flow_locations&.map(&:to_h) if @thread_flow_locations&.any?
45
+ h["results"] = @results&.map(&:to_h) if @results&.any?
46
+ h["taxonomies"] = @taxonomies&.map(&:to_h) if @taxonomies&.any?
47
+ h["driver"] = @driver&.to_h unless @driver.nil?
48
+ h["extensions"] = @extensions&.map(&:to_h) if @extensions&.any?
49
+ h["policies"] = @policies&.map(&:to_h) if @policies&.any?
50
+ h["translations"] = @translations&.map(&:to_h) if @translations&.any?
51
+ h["addresses"] = @addresses&.map(&:to_h) if @addresses&.any?
52
+ h["webRequests"] = @web_requests&.map(&:to_h) if @web_requests&.any?
53
+ h["webResponses"] = @web_responses&.map(&:to_h) if @web_responses&.any?
54
+ h["properties"] = @properties unless @properties.nil?
55
+ h
56
+ end
57
+
58
+ def to_json(pretty: false)
59
+ pretty ? JSON.pretty_generate(to_h) : JSON.generate(to_h)
60
+ end
61
+
62
+ def self.from_hash(h)
63
+ return nil if h.nil?
64
+ new(
65
+ schema: h["schema"],
66
+ version: h["version"],
67
+ guid: h["guid"],
68
+ run_guid: h["runGuid"],
69
+ conversion: Conversion.from_hash(h["conversion"]),
70
+ graphs: h["graphs"]&.map { |v| Graph.from_hash(v) } || [],
71
+ externalized_properties: h["externalizedProperties"],
72
+ artifacts: h["artifacts"]&.map { |v| Artifact.from_hash(v) },
73
+ invocations: h["invocations"]&.map { |v| Invocation.from_hash(v) } || [],
74
+ logical_locations: h["logicalLocations"]&.map { |v| LogicalLocation.from_hash(v) } || [],
75
+ thread_flow_locations: h["threadFlowLocations"]&.map { |v| ThreadFlowLocation.from_hash(v) } || [],
76
+ results: h["results"]&.map { |v| Result.from_hash(v) } || [],
77
+ taxonomies: h["taxonomies"]&.map { |v| ToolComponent.from_hash(v) } || [],
78
+ driver: ToolComponent.from_hash(h["driver"]),
79
+ extensions: h["extensions"]&.map { |v| ToolComponent.from_hash(v) } || [],
80
+ policies: h["policies"]&.map { |v| ToolComponent.from_hash(v) } || [],
81
+ translations: h["translations"]&.map { |v| ToolComponent.from_hash(v) } || [],
82
+ addresses: h["addresses"]&.map { |v| Address.from_hash(v) } || [],
83
+ web_requests: h["webRequests"]&.map { |v| WebRequest.from_hash(v) } || [],
84
+ web_responses: h["webResponses"]&.map { |v| WebResponse.from_hash(v) } || [],
85
+ properties: h["properties"]
86
+ )
87
+ end
88
+
89
+ def ==(other)
90
+ return false unless other.is_a?(ExternalProperties)
91
+ @schema == other.schema && @version == other.version && @guid == other.guid && @run_guid == other.run_guid && @conversion == other.conversion && @graphs == other.graphs && @externalized_properties == other.externalized_properties && @artifacts == other.artifacts && @invocations == other.invocations && @logical_locations == other.logical_locations && @thread_flow_locations == other.thread_flow_locations && @results == other.results && @taxonomies == other.taxonomies && @driver == other.driver && @extensions == other.extensions && @policies == other.policies && @translations == other.translations && @addresses == other.addresses && @web_requests == other.web_requests && @web_responses == other.web_responses && @properties == other.properties
92
+ end
93
+
94
+ alias eql? ==
95
+
96
+ def hash
97
+ [@schema, @version, @guid, @run_guid, @conversion, @graphs, @externalized_properties, @artifacts, @invocations, @logical_locations, @thread_flow_locations, @results, @taxonomies, @driver, @extensions, @policies, @translations, @addresses, @web_requests, @web_responses, @properties].hash
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sarif
4
+ # Contains information that enables a SARIF consumer to locate the external property file that contains the value of an externalized property associated with the run.
5
+ class ExternalPropertyFileReference
6
+ attr_accessor :location, :guid, :item_count, :properties
7
+
8
+ def initialize(location: nil, guid: nil, item_count: -1, properties: nil)
9
+ @location = location
10
+ @guid = guid
11
+ @item_count = item_count
12
+ @properties = properties
13
+ end
14
+
15
+ def to_h
16
+ h = {}
17
+ h["location"] = @location&.to_h unless @location.nil?
18
+ h["guid"] = @guid unless @guid.nil?
19
+ h["itemCount"] = @item_count if @item_count && @item_count != -1
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
+ location: ArtifactLocation.from_hash(h["location"]),
32
+ guid: h["guid"],
33
+ item_count: h["itemCount"] || -1,
34
+ properties: h["properties"]
35
+ )
36
+ end
37
+
38
+ def ==(other)
39
+ return false unless other.is_a?(ExternalPropertyFileReference)
40
+ @location == other.location && @guid == other.guid && @item_count == other.item_count && @properties == other.properties
41
+ end
42
+
43
+ alias eql? ==
44
+
45
+ def hash
46
+ [@location, @guid, @item_count, @properties].hash
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sarif
4
+ # References to external property files that should be inlined with the content of a root log file.
5
+ class ExternalPropertyFileReferences
6
+ attr_accessor :conversion, :graphs, :externalized_properties, :artifacts, :invocations, :logical_locations, :thread_flow_locations, :results, :taxonomies, :addresses, :driver, :extensions, :policies, :translations, :web_requests, :web_responses, :properties
7
+
8
+ def initialize(conversion: nil, graphs: [], externalized_properties: nil, artifacts: [], invocations: [], logical_locations: [], thread_flow_locations: [], results: [], taxonomies: [], addresses: [], driver: nil, extensions: [], policies: [], translations: [], web_requests: [], web_responses: [], properties: nil)
9
+ @conversion = conversion
10
+ @graphs = graphs
11
+ @externalized_properties = externalized_properties
12
+ @artifacts = artifacts
13
+ @invocations = invocations
14
+ @logical_locations = logical_locations
15
+ @thread_flow_locations = thread_flow_locations
16
+ @results = results
17
+ @taxonomies = taxonomies
18
+ @addresses = addresses
19
+ @driver = driver
20
+ @extensions = extensions
21
+ @policies = policies
22
+ @translations = translations
23
+ @web_requests = web_requests
24
+ @web_responses = web_responses
25
+ @properties = properties
26
+ end
27
+
28
+ def to_h
29
+ h = {}
30
+ h["conversion"] = @conversion&.to_h unless @conversion.nil?
31
+ h["graphs"] = @graphs&.map(&:to_h) if @graphs&.any?
32
+ h["externalizedProperties"] = @externalized_properties&.to_h unless @externalized_properties.nil?
33
+ h["artifacts"] = @artifacts&.map(&:to_h) if @artifacts&.any?
34
+ h["invocations"] = @invocations&.map(&:to_h) if @invocations&.any?
35
+ h["logicalLocations"] = @logical_locations&.map(&:to_h) if @logical_locations&.any?
36
+ h["threadFlowLocations"] = @thread_flow_locations&.map(&:to_h) if @thread_flow_locations&.any?
37
+ h["results"] = @results&.map(&:to_h) if @results&.any?
38
+ h["taxonomies"] = @taxonomies&.map(&:to_h) if @taxonomies&.any?
39
+ h["addresses"] = @addresses&.map(&:to_h) if @addresses&.any?
40
+ h["driver"] = @driver&.to_h unless @driver.nil?
41
+ h["extensions"] = @extensions&.map(&:to_h) if @extensions&.any?
42
+ h["policies"] = @policies&.map(&:to_h) if @policies&.any?
43
+ h["translations"] = @translations&.map(&:to_h) if @translations&.any?
44
+ h["webRequests"] = @web_requests&.map(&:to_h) if @web_requests&.any?
45
+ h["webResponses"] = @web_responses&.map(&:to_h) if @web_responses&.any?
46
+ h["properties"] = @properties unless @properties.nil?
47
+ h
48
+ end
49
+
50
+ def to_json(pretty: false)
51
+ pretty ? JSON.pretty_generate(to_h) : JSON.generate(to_h)
52
+ end
53
+
54
+ def self.from_hash(h)
55
+ return nil if h.nil?
56
+ new(
57
+ conversion: ExternalPropertyFileReference.from_hash(h["conversion"]),
58
+ graphs: h["graphs"]&.map { |v| ExternalPropertyFileReference.from_hash(v) } || [],
59
+ externalized_properties: ExternalPropertyFileReference.from_hash(h["externalizedProperties"]),
60
+ artifacts: h["artifacts"]&.map { |v| ExternalPropertyFileReference.from_hash(v) } || [],
61
+ invocations: h["invocations"]&.map { |v| ExternalPropertyFileReference.from_hash(v) } || [],
62
+ logical_locations: h["logicalLocations"]&.map { |v| ExternalPropertyFileReference.from_hash(v) } || [],
63
+ thread_flow_locations: h["threadFlowLocations"]&.map { |v| ExternalPropertyFileReference.from_hash(v) } || [],
64
+ results: h["results"]&.map { |v| ExternalPropertyFileReference.from_hash(v) } || [],
65
+ taxonomies: h["taxonomies"]&.map { |v| ExternalPropertyFileReference.from_hash(v) } || [],
66
+ addresses: h["addresses"]&.map { |v| ExternalPropertyFileReference.from_hash(v) } || [],
67
+ driver: ExternalPropertyFileReference.from_hash(h["driver"]),
68
+ extensions: h["extensions"]&.map { |v| ExternalPropertyFileReference.from_hash(v) } || [],
69
+ policies: h["policies"]&.map { |v| ExternalPropertyFileReference.from_hash(v) } || [],
70
+ translations: h["translations"]&.map { |v| ExternalPropertyFileReference.from_hash(v) } || [],
71
+ web_requests: h["webRequests"]&.map { |v| ExternalPropertyFileReference.from_hash(v) } || [],
72
+ web_responses: h["webResponses"]&.map { |v| ExternalPropertyFileReference.from_hash(v) } || [],
73
+ properties: h["properties"]
74
+ )
75
+ end
76
+
77
+ def ==(other)
78
+ return false unless other.is_a?(ExternalPropertyFileReferences)
79
+ @conversion == other.conversion && @graphs == other.graphs && @externalized_properties == other.externalized_properties && @artifacts == other.artifacts && @invocations == other.invocations && @logical_locations == other.logical_locations && @thread_flow_locations == other.thread_flow_locations && @results == other.results && @taxonomies == other.taxonomies && @addresses == other.addresses && @driver == other.driver && @extensions == other.extensions && @policies == other.policies && @translations == other.translations && @web_requests == other.web_requests && @web_responses == other.web_responses && @properties == other.properties
80
+ end
81
+
82
+ alias eql? ==
83
+
84
+ def hash
85
+ [@conversion, @graphs, @externalized_properties, @artifacts, @invocations, @logical_locations, @thread_flow_locations, @results, @taxonomies, @addresses, @driver, @extensions, @policies, @translations, @web_requests, @web_responses, @properties].hash
86
+ end
87
+ end
88
+ end
data/lib/sarif/fix.rb ADDED
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sarif
4
+ # A proposed fix for the problem represented by a result object. A fix specifies a set of artifacts to modify. For each artifact, it specifies a set of bytes to remove, and provides a set of new bytes to replace them.
5
+ class Fix
6
+ attr_accessor :description, :artifact_changes, :properties
7
+
8
+ def initialize(description: nil, artifact_changes:, properties: nil)
9
+ @description = description
10
+ @artifact_changes = artifact_changes
11
+ @properties = properties
12
+ end
13
+
14
+ def to_h
15
+ h = {}
16
+ h["description"] = @description&.to_h unless @description.nil?
17
+ h["artifactChanges"] = @artifact_changes&.map(&:to_h)
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
+ description: Message.from_hash(h["description"]),
30
+ artifact_changes: h["artifactChanges"]&.map { |v| ArtifactChange.from_hash(v) },
31
+ properties: h["properties"]
32
+ )
33
+ end
34
+
35
+ def ==(other)
36
+ return false unless other.is_a?(Fix)
37
+ @description == other.description && @artifact_changes == other.artifact_changes && @properties == other.properties
38
+ end
39
+
40
+ alias eql? ==
41
+
42
+ def hash
43
+ [@description, @artifact_changes, @properties].hash
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sarif
4
+ # A network of nodes and directed edges that describes some aspect of the structure of the code (for example, a call graph).
5
+ class Graph
6
+ attr_accessor :description, :nodes, :edges, :properties
7
+
8
+ def initialize(description: nil, nodes: [], edges: [], properties: nil)
9
+ @description = description
10
+ @nodes = nodes
11
+ @edges = edges
12
+ @properties = properties
13
+ end
14
+
15
+ def to_h
16
+ h = {}
17
+ h["description"] = @description&.to_h unless @description.nil?
18
+ h["nodes"] = @nodes&.map(&:to_h) if @nodes&.any?
19
+ h["edges"] = @edges&.map(&:to_h) if @edges&.any?
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
+ description: Message.from_hash(h["description"]),
32
+ nodes: h["nodes"]&.map { |v| Node.from_hash(v) } || [],
33
+ edges: h["edges"]&.map { |v| Edge.from_hash(v) } || [],
34
+ properties: h["properties"]
35
+ )
36
+ end
37
+
38
+ def ==(other)
39
+ return false unless other.is_a?(Graph)
40
+ @description == other.description && @nodes == other.nodes && @edges == other.edges && @properties == other.properties
41
+ end
42
+
43
+ alias eql? ==
44
+
45
+ def hash
46
+ [@description, @nodes, @edges, @properties].hash
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sarif
4
+ # Represents a path through a graph.
5
+ class GraphTraversal
6
+ attr_accessor :run_graph_index, :result_graph_index, :description, :initial_state, :immutable_state, :edge_traversals, :properties
7
+
8
+ def initialize(run_graph_index: -1, result_graph_index: -1, description: nil, initial_state: nil, immutable_state: nil, edge_traversals: [], properties: nil)
9
+ @run_graph_index = run_graph_index
10
+ @result_graph_index = result_graph_index
11
+ @description = description
12
+ @initial_state = initial_state
13
+ @immutable_state = immutable_state
14
+ @edge_traversals = edge_traversals
15
+ @properties = properties
16
+ end
17
+
18
+ def to_h
19
+ h = {}
20
+ h["runGraphIndex"] = @run_graph_index if @run_graph_index && @run_graph_index != -1
21
+ h["resultGraphIndex"] = @result_graph_index if @result_graph_index && @result_graph_index != -1
22
+ h["description"] = @description&.to_h unless @description.nil?
23
+ h["initialState"] = @initial_state unless @initial_state.nil?
24
+ h["immutableState"] = @immutable_state unless @immutable_state.nil?
25
+ h["edgeTraversals"] = @edge_traversals&.map(&:to_h) if @edge_traversals&.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
+ run_graph_index: h["runGraphIndex"] || -1,
38
+ result_graph_index: h["resultGraphIndex"] || -1,
39
+ description: Message.from_hash(h["description"]),
40
+ initial_state: h["initialState"],
41
+ immutable_state: h["immutableState"],
42
+ edge_traversals: h["edgeTraversals"]&.map { |v| EdgeTraversal.from_hash(v) } || [],
43
+ properties: h["properties"]
44
+ )
45
+ end
46
+
47
+ def ==(other)
48
+ return false unless other.is_a?(GraphTraversal)
49
+ @run_graph_index == other.run_graph_index && @result_graph_index == other.result_graph_index && @description == other.description && @initial_state == other.initial_state && @immutable_state == other.immutable_state && @edge_traversals == other.edge_traversals && @properties == other.properties
50
+ end
51
+
52
+ alias eql? ==
53
+
54
+ def hash
55
+ [@run_graph_index, @result_graph_index, @description, @initial_state, @immutable_state, @edge_traversals, @properties].hash
56
+ end
57
+ end
58
+ end