# frozen_string_literal: true module VulnerabilityFindingHelpers extend ActiveSupport::Concern # Manually resolvable report types cannot be considered fixed once removed from the # target branch due to requiring active triage, such as rotation of an exposed token. REPORT_TYPES_REQUIRING_MANUAL_RESOLUTION = %w[secret_detection].freeze def requires_manual_resolution? REPORT_TYPES_REQUIRING_MANUAL_RESOLUTION.include?(report_type) end def matches_signatures(other_signatures, other_uuid) other_signature_types = other_signatures.index_by(&:algorithm_type) # highest first match_result = nil signatures.sort_by(&:priority).reverse_each do |signature| matching_other_signature = other_signature_types[signature.algorithm_type] next if matching_other_signature.nil? match_result = matching_other_signature == signature break end if match_result.nil? [uuid, *signature_uuids].include?(other_uuid) else match_result end end def signature_uuids signatures.map do |signature| hex_sha = signature.signature_hex ::Security::VulnerabilityUUID.generate( report_type: report_type, location_fingerprint: hex_sha, primary_identifier_fingerprint: primary_identifier&.fingerprint, project_id: project_id ) end end def build_vulnerability_finding(security_finding) report_finding = report_finding_for(security_finding) return Vulnerabilities::Finding.new unless report_finding finding_data = report_finding.to_hash.except(:compare_key, :identifiers, :location, :scanner, :links, :signatures, :flags, :evidence) identifiers = report_finding.identifiers.uniq(&:fingerprint).map do |identifier| Vulnerabilities::Identifier.new(identifier.to_hash.merge({ project: project })) end signatures = report_finding.signatures.map do |signature| Vulnerabilities::FindingSignature.new(signature.to_hash) end evidence = Vulnerabilities::Finding::Evidence.new(data: report_finding.evidence.data) if report_finding.evidence Vulnerabilities::Finding.new(finding_data).tap do |finding| finding.location_fingerprint = report_finding.location.fingerprint finding.vulnerability = vulnerability_for(security_finding.uuid) finding.project = project finding.sha = pipeline.sha finding.scanner = security_finding.scanner finding.finding_evidence = evidence if calculate_false_positive? finding.vulnerability_flags = report_finding.flags.map do |flag| Vulnerabilities::Flag.new(flag) end end finding.identifiers = identifiers finding.primary_identifier = identifiers.first finding.signatures = signatures end end def calculate_false_positive? project.licensed_feature_available?(:sast_fp_reduction) end end