Class: QueryGuard::Core::Finding
- Inherits:
-
Object
- Object
- QueryGuard::Core::Finding
- Defined in:
- lib/query_guard/core/finding.rb
Overview
Immutable result of a rule analysis. Represents a single violation or finding detected by an analyzer.
A Finding encapsulates all information about a detected issue:
- What rule triggered (analyzer_name, rule_name)
- How severe it is (severity)
- Where it occurred (file_path, line_number, sql)
- Why it matters (title, description, recommendations)
- Context data (metadata)
Constant Summary collapse
- SEVERITIES =
i[info warn error].freeze
Instance Attribute Summary collapse
-
#analyzer_name ⇒ Object
readonly
Core identification.
-
#created_at ⇒ Object
readonly
Additional context.
-
#description ⇒ Object
readonly
Message and description (user-facing).
-
#file_path ⇒ Object
readonly
Location information.
-
#id ⇒ Object
readonly
Internal ID for tracking/deduplication.
-
#line_number ⇒ Object
readonly
Location information.
-
#message ⇒ Object
readonly
Message and description (user-facing).
-
#metadata ⇒ Object
readonly
Additional context.
-
#query ⇒ Object
readonly
Additional context.
-
#recommendations ⇒ Object
readonly
Message and description (user-facing).
-
#rule_name ⇒ Object
readonly
Core identification.
-
#severity ⇒ Object
readonly
Core identification.
-
#sql ⇒ Object
readonly
Location information.
-
#title ⇒ Object
readonly
Message and description (user-facing).
Instance Method Summary collapse
-
#==(other) ⇒ Object
(also: #eql?)
Compare findings by key attributes.
-
#has_location? ⇒ Boolean
Check if finding has location information.
-
#hash ⇒ Object
Hash based on ID for Set operations.
-
#initialize(analyzer_name:, rule_name:, severity: :warn, title: nil, description: nil, message: nil, file_path: nil, line_number: nil, sql: nil, metadata: {}, query: nil, recommendations: []) ⇒ Finding
constructor
A new instance of Finding.
-
#inspect ⇒ Object
Inspection string.
-
#to_h ⇒ Object
Serialize to hash for reporting/API Useful for JSON output, CI integration, and telemetry.
-
#to_json_h ⇒ Object
Serialize to JSON-friendly hash (excludes large/binary data).
-
#to_log_s ⇒ Object
Detailed log format.
-
#to_s ⇒ Object
Human-readable string for logs.
Constructor Details
#initialize(analyzer_name:, rule_name:, severity: :warn, title: nil, description: nil, message: nil, file_path: nil, line_number: nil, sql: nil, metadata: {}, query: nil, recommendations: []) ⇒ Finding
Returns a new instance of Finding.
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/query_guard/core/finding.rb', line 32 def initialize( analyzer_name:, rule_name:, severity: :warn, title: nil, description: nil, message: nil, file_path: nil, line_number: nil, sql: nil, metadata: {}, query: nil, recommendations: [] ) @analyzer_name = analyzer_name.to_sym @rule_name = rule_name.to_sym @severity = validate_severity(severity) # Message handling: use title/description or fall back to message @title = title.to_s.freeze if title @description = description.to_s.freeze if description = ( || @title || "").to_s.freeze # Location info @file_path = file_path.to_s.freeze if file_path @line_number = line_number.to_i if line_number @sql = sql.to_s.freeze if sql # Recommendations @recommendations = Array(recommendations).map { |r| r.to_s.freeze }.freeze # Metadata = .freeze @query = query @created_at = Time.now.freeze # Generate deterministic ID based on analyzer, rule, and sql for deduplication @id = generate_id end |
Instance Attribute Details
#analyzer_name ⇒ Object (readonly)
Core identification
18 19 20 |
# File 'lib/query_guard/core/finding.rb', line 18 def analyzer_name @analyzer_name end |
#created_at ⇒ Object (readonly)
Additional context
27 28 29 |
# File 'lib/query_guard/core/finding.rb', line 27 def created_at @created_at end |
#description ⇒ Object (readonly)
Message and description (user-facing)
21 22 23 |
# File 'lib/query_guard/core/finding.rb', line 21 def description @description end |
#file_path ⇒ Object (readonly)
Location information
24 25 26 |
# File 'lib/query_guard/core/finding.rb', line 24 def file_path @file_path end |
#id ⇒ Object (readonly)
Internal ID for tracking/deduplication
30 31 32 |
# File 'lib/query_guard/core/finding.rb', line 30 def id @id end |
#line_number ⇒ Object (readonly)
Location information
24 25 26 |
# File 'lib/query_guard/core/finding.rb', line 24 def line_number @line_number end |
#message ⇒ Object (readonly)
Message and description (user-facing)
21 22 23 |
# File 'lib/query_guard/core/finding.rb', line 21 def end |
#metadata ⇒ Object (readonly)
Additional context
27 28 29 |
# File 'lib/query_guard/core/finding.rb', line 27 def end |
#query ⇒ Object (readonly)
Additional context
27 28 29 |
# File 'lib/query_guard/core/finding.rb', line 27 def query @query end |
#recommendations ⇒ Object (readonly)
Message and description (user-facing)
21 22 23 |
# File 'lib/query_guard/core/finding.rb', line 21 def recommendations @recommendations end |
#rule_name ⇒ Object (readonly)
Core identification
18 19 20 |
# File 'lib/query_guard/core/finding.rb', line 18 def rule_name @rule_name end |
#severity ⇒ Object (readonly)
Core identification
18 19 20 |
# File 'lib/query_guard/core/finding.rb', line 18 def severity @severity end |
#sql ⇒ Object (readonly)
Location information
24 25 26 |
# File 'lib/query_guard/core/finding.rb', line 24 def sql @sql end |
#title ⇒ Object (readonly)
Message and description (user-facing)
21 22 23 |
# File 'lib/query_guard/core/finding.rb', line 21 def title @title end |
Instance Method Details
#==(other) ⇒ Object Also known as: eql?
Compare findings by key attributes
73 74 75 76 77 78 79 |
# File 'lib/query_guard/core/finding.rb', line 73 def ==(other) other.is_a?(Finding) && analyzer_name == other.analyzer_name && rule_name == other.rule_name && severity == other.severity && == other. end |
#has_location? ⇒ Boolean
Check if finding has location information
136 137 138 |
# File 'lib/query_guard/core/finding.rb', line 136 def has_location? !file_path.nil? end |
#hash ⇒ Object
Hash based on ID for Set operations
82 83 84 |
# File 'lib/query_guard/core/finding.rb', line 82 def hash id.hash end |
#inspect ⇒ Object
Inspection string
131 132 133 |
# File 'lib/query_guard/core/finding.rb', line 131 def inspect "#<Finding id=#{id[0, 8]} #{analyzer_name}:#{rule_name} severity=#{severity}>" end |
#to_h ⇒ Object
Serialize to hash for reporting/API Useful for JSON output, CI integration, and telemetry
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
# File 'lib/query_guard/core/finding.rb', line 90 def to_h { id: id, analyzer: analyzer_name, rule: rule_name, severity: severity, title: title, description: description, message: , file_path: file_path, line_number: line_number, sql: sql, metadata: , recommendations: recommendations, created_at: created_at&.iso8601, query: query&.to_h }.compact end |
#to_json_h ⇒ Object
Serialize to JSON-friendly hash (excludes large/binary data)
110 111 112 113 114 115 |
# File 'lib/query_guard/core/finding.rb', line 110 def to_json_h h = to_h # Optionally truncate SQL for JSON payloads h[:sql] = truncate_sql(h[:sql], 500) if h[:sql] h.except(:query) # Exclude full query object from JSON end |
#to_log_s ⇒ Object
Detailed log format
123 124 125 126 127 128 |
# File 'lib/query_guard/core/finding.rb', line 123 def to_log_s parts = [to_s] parts << "File: #{file_path}:#{line_number}" if file_path parts << "SQL: #{truncate_sql(sql, 100)}" if sql parts.join(" | ") end |
#to_s ⇒ Object
Human-readable string for logs
118 119 120 |
# File 'lib/query_guard/core/finding.rb', line 118 def to_s "[#{severity.upcase}] #{analyzer_name}:#{rule_name} - #{message}" end |