Fix NoMethodError when security report has no scanner information
## Summary The `Security::StoreScanService` raises a `NoMethodError` when processing security reports that lack scanner information, causing scan ingestion to fail. **Sentry Error:** https://new-sentry.gitlab.net/organizations/gitlab/issues/3010954 ## Error Details ``` NoMethodError: undefined method `external_id' for nil:NilClass (NoMethodError) project.vulnerability_scanners.safe_find_or_create_by!(external_id: security_report.scanner.external_id) do |scanner| ^^^^^^^^^^^^ from security/store_scan_service.rb:154:in `vulnerability_scanner' from security/store_scan_service.rb:97:in `store_findings' from security/store_scan_service.rb:38:in `execute' ``` ## Root Cause In `ee/app/services/security/store_scan_service.rb`, the `vulnerability_scanner` method (line 154) attempts to access `security_report.scanner.external_id` without checking if `security_report.scanner` is `nil`. Security reports can have missing scanner information when: - The report JSON lacks both top-level scanner data (`scan.scanner`) and finding-level scanner data - The scanner data is malformed and fails validation during parsing The parser in `lib/gitlab/ci/parsers/security/common.rb` only sets `report.scanner` if valid scanner data exists, otherwise it remains `nil`. ## Proposed Solution ### 1. Add nil check in `vulnerability_scanner` method ```ruby def vulnerability_scanner return unless security_report.scanner project.vulnerability_scanners.safe_find_or_create_by!(external_id: security_report.scanner.external_id) do |scanner| scanner.assign_attributes(security_report.scanner.to_hash) end end ``` ### 2. Handle nil scanner in `store_findings` method ```ruby def store_findings scanner = vulnerability_scanner if scanner.nil? mark_scan_as_failed! Gitlab::AppLogger.warn( message: "Security scan missing scanner information", scan_id: security_scan.id, report_type: security_report.type ) return end StoreFindingsService.execute(security_scan, scanner, security_report, register_finding_keys).then do |result| update_deduplicated_findings if result[:status] == :error && deduplicate_findings? end security_scan.succeeded! rescue StandardError => error mark_scan_as_failed! Gitlab::ErrorTracking.track_exception(error) end ``` ## Testing Add test coverage in `ee/spec/services/security/store_scan_service_spec.rb` using the existing `:sast_with_missing_scanner` fixture (`spec/fixtures/security_reports/master/gl-sast-missing-scanner.json`). The test should verify: - No `NoMethodError` is raised - Scan is marked as `preparation_failed` - `StoreFindingsService` is not called - Processing error is added to the scan - No vulnerability scanner record is created - Error is tracked via `Gitlab::ErrorTracking` ## Impact This bug prevents security scan ingestion for reports with missing scanner information, resulting in: - Failed security scans not being recorded properly - Missing vulnerability data in the vulnerability report - Incomplete security posture visibility ## Related Files - `ee/app/services/security/store_scan_service.rb` - `ee/spec/services/security/store_scan_service_spec.rb` - `lib/gitlab/ci/parsers/security/common.rb` - `spec/fixtures/security_reports/master/gl-sast-missing-scanner.json`
issue