Add polling to security widget GraphQL

What does this MR do and why?

Implements polling mechanism for the security widget's GraphQL query. When the report status is PARSING, the widget returns polling headers with a interval to trigger automatic re-fetching until the report is fully parsed (response is PARSED. This ensures the security widget displays up-to-date scan results without requiring manual refresh.

Changes Issue
Make GraphQL query available Make GraphQL query available in the security wi... (!211509 - merged)
Add polling 👈 This MR
Transform GraphQL data to match REST format [FE] Transform GraphQL data to match REST endpo... (#579662)
Add error handling [FE] Implement error handling for GraphQL (#579611)

References

Screenshots or screen recordings

Recording Screenshot
parsing-parsed Parsing image
Parsed image

How to set up and validate locally

  1. Enable FF mr_security_widget_graphql
  2. Clone this project > https://gitlab.com/gitlab-org/govern/threat-insights-demos/frontend/validity-checks
  3. Create a MR similar to this > gitlab-org/govern/threat-insights-demos/frontend/validity-checks!8
  4. The loading will appear (parsing) and request is continuously made until there is a response (parsed)

Apply this patch to see the loading effect:

  1. This patches will deliberately return parsing if request is less than 3
  2. Once it hits 3, the request will return it's normal response which should be parsed.
  3. It could potentially be still loading depending on your pipeline result.
  4. Note the cache key expires in 2 mins. So wait after that to see the loading effect again.
diff --git a/ee/app/services/security/merge_request_security_report_generation_service.rb b/ee/app/services/security/merge_request_security_report_generation_service.rb
index 5167a3f9a45e..69ece16a2d0d 100644
--- a/ee/app/services/security/merge_request_security_report_generation_service.rb
+++ b/ee/app/services/security/merge_request_security_report_generation_service.rb
@@ -105,6 +105,7 @@ def fixed_findings
 
     strong_memoize_attr def report
       validate_report_type!
+      return { status: :parsing } if request_count < 3
 
       with_reactive_cache(params.stringify_keys) do |data|
         latest = Vulnerabilities::CompareSecurityReportsService.new(project, nil, params).latest?(base_pipeline,
@@ -132,5 +133,14 @@ def base_pipeline
     def head_pipeline
       merge_request.diff_head_pipeline
     end
+
+    private
+
+    def request_count
+      cache_key = "security_report_simulation_#{merge_request.id}_#{report_type}"
+      current_count = Rails.cache.fetch(cache_key, expires_in: 2.minutes) { 0 }
+      Rails.cache.write(cache_key, current_count + 1, expires_in: 2.minutes)
+      current_count
+    end
   end
 end

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

Related to #579610

Edited by Samantha Ming

Merge request reports

Loading