@@ -75,7 +75,7 @@ func CompareJasResults(targetResults, sourceResults *SecurityCommandResults) *Se
7575 }
7676 }
7777
78- diffJasResults := filterExistingFindings ( allTargetJasResults , sourceTarget .JasResults )
78+ diffJasResults := excludeExistingFindingsInTargets ( sourceTarget .JasResults , allTargetJasResults ... )
7979
8080 diffTarget := & TargetResults {
8181 ScanTarget : sourceTarget .ScanTarget ,
@@ -88,49 +88,20 @@ func CompareJasResults(targetResults, sourceResults *SecurityCommandResults) *Se
8888 return diffResults
8989}
9090
91- // filterExistingFindings removes findings from source that already exist in target.
92- func filterExistingFindings (allTargetJasResults []* JasScansResults , sourceJasResults * JasScansResults ) * JasScansResults {
91+ // excludeExistingFindingsInTargets removes findings from source that already exist in any of the target results.
92+ // Returns a new JasScansResults containing only findings that are NEW in source (not present in targets).
93+ func excludeExistingFindingsInTargets (sourceJasResults * JasScansResults , targetJasResultsToExclude ... * JasScansResults ) * JasScansResults {
9394 if sourceJasResults == nil {
9495 return nil
9596 }
9697
97- if len (allTargetJasResults ) == 0 {
98+ if len (targetJasResultsToExclude ) == 0 {
9899 return sourceJasResults
99100 }
100101
101- targetKeys := make ( map [ string ] bool )
102+ targetKeys := extractAllJasResultKeys ( targetJasResultsToExclude ... )
102103
103- for _ , targetJasResults := range allTargetJasResults {
104- if targetJasResults == nil {
105- continue
106- }
107-
108- for _ , targetRun := range targetJasResults .GetVulnerabilitiesResults (jasutils .Secrets ) {
109- extractLocationsOnly (targetRun , targetKeys )
110- }
111- for _ , targetRun := range targetJasResults .GetViolationsResults (jasutils .Secrets ) {
112- extractLocationsOnly (targetRun , targetKeys )
113- }
114- for _ , targetRun := range targetJasResults .GetVulnerabilitiesResults (jasutils .IaC ) {
115- extractLocationsOnly (targetRun , targetKeys )
116- }
117- for _ , targetRun := range targetJasResults .GetViolationsResults (jasutils .IaC ) {
118- extractLocationsOnly (targetRun , targetKeys )
119- }
120- for _ , targetRun := range targetJasResults .GetVulnerabilitiesResults (jasutils .Sast ) {
121- extractFingerprints (targetRun , targetKeys )
122- }
123- for _ , targetRun := range targetJasResults .GetViolationsResults (jasutils .Sast ) {
124- extractFingerprints (targetRun , targetKeys )
125- }
126- }
127-
128- sourceSecrets := countSarifResults (sourceJasResults .JasVulnerabilities .SecretsScanResults ) +
129- countSarifResults (sourceJasResults .JasViolations .SecretsScanResults )
130- sourceIac := countSarifResults (sourceJasResults .JasVulnerabilities .IacScanResults ) +
131- countSarifResults (sourceJasResults .JasViolations .IacScanResults )
132- sourceSast := countSarifResults (sourceJasResults .JasVulnerabilities .SastScanResults ) +
133- countSarifResults (sourceJasResults .JasViolations .SastScanResults )
104+ sourceSecrets , sourceIac , sourceSast := countJasFindings (sourceJasResults )
134105
135106 log .Debug ("[DIFF] Source findings before diff - Secrets:" , sourceSecrets , "| IaC:" , sourceIac , "| SAST:" , sourceSast )
136107
@@ -150,19 +121,28 @@ func filterExistingFindings(allTargetJasResults []*JasScansResults, sourceJasRes
150121 filteredJasResults .JasViolations .SastScanResults = filterNewSarifFindings (
151122 sourceJasResults .JasViolations .SastScanResults , targetKeys )
152123
153- diffSecrets := countSarifResults (filteredJasResults .JasVulnerabilities .SecretsScanResults ) +
154- countSarifResults (filteredJasResults .JasViolations .SecretsScanResults )
155- diffIac := countSarifResults (filteredJasResults .JasVulnerabilities .IacScanResults ) +
156- countSarifResults (filteredJasResults .JasViolations .IacScanResults )
157- diffSast := countSarifResults (filteredJasResults .JasVulnerabilities .SastScanResults ) +
158- countSarifResults (filteredJasResults .JasViolations .SastScanResults )
124+ diffSecrets , diffIac , diffSast := countJasFindings (filteredJasResults )
159125
160126 log .Info ("[DIFF] New findings after diff - Secrets:" , diffSecrets , "| IaC:" , diffIac , "| SAST:" , diffSast )
161127 log .Info ("[DIFF] Filtered out - Secrets:" , sourceSecrets - diffSecrets , "| IaC:" , sourceIac - diffIac , "| SAST:" , sourceSast - diffSast )
162128
163129 return filteredJasResults
164130}
165131
132+ // countJasFindings returns the count of (secrets, iac, sast) findings in the JAS results.
133+ func countJasFindings (jasResults * JasScansResults ) (secrets , iac , sast int ) {
134+ if jasResults == nil {
135+ return
136+ }
137+ secrets = countSarifResults (jasResults .JasVulnerabilities .SecretsScanResults ) +
138+ countSarifResults (jasResults .JasViolations .SecretsScanResults )
139+ iac = countSarifResults (jasResults .JasVulnerabilities .IacScanResults ) +
140+ countSarifResults (jasResults .JasViolations .IacScanResults )
141+ sast = countSarifResults (jasResults .JasVulnerabilities .SastScanResults ) +
142+ countSarifResults (jasResults .JasViolations .SastScanResults )
143+ return
144+ }
145+
166146func countSarifResults (runs []* sarif.Run ) int {
167147 count := 0
168148 for _ , run := range runs {
@@ -173,41 +153,62 @@ func countSarifResults(runs []*sarif.Run) int {
173153 return count
174154}
175155
176- func extractFingerprints (run * sarif.Run , targetKeys map [string ]bool ) {
177- for _ , result := range run .Results {
178- if sarifutils .IsFingerprintsExists (result ) {
179- key := getSastFingerprint (result )
180- if key != "" {
181- targetKeys [key ] = true
182- }
183- } else {
184- for _ , location := range result .Locations {
185- key := sarifutils .GetRelativeLocationFileName (location , run .Invocations ) + sarifutils .GetLocationSnippetText (location )
186- targetKeys [key ] = true
187- }
156+ // extractAllJasResultKeys extracts unique identifiers from all JAS results for diff comparison.
157+ // For Secrets/IaC: uses file path + snippet as key (location-based matching).
158+ // For SAST: uses fingerprint when available, falls back to location-based matching.
159+ func extractAllJasResultKeys (jasResults ... * JasScansResults ) map [string ]bool {
160+ targetKeys := make (map [string ]bool )
161+ for _ , jasResult := range jasResults {
162+ if jasResult == nil {
163+ continue
188164 }
165+ // Secrets and IaC use location-based matching
166+ extractLocationsOnly (targetKeys ,
167+ jasResult .GetVulnerabilitiesResults (jasutils .Secrets )... )
168+ extractLocationsOnly (targetKeys ,
169+ jasResult .GetViolationsResults (jasutils .Secrets )... )
170+ extractLocationsOnly (targetKeys ,
171+ jasResult .GetVulnerabilitiesResults (jasutils .IaC )... )
172+ extractLocationsOnly (targetKeys ,
173+ jasResult .GetViolationsResults (jasutils .IaC )... )
174+ // SAST uses fingerprint-based matching when available
175+ extractFingerprints (targetKeys ,
176+ jasResult .GetVulnerabilitiesResults (jasutils .Sast )... )
177+ extractFingerprints (targetKeys ,
178+ jasResult .GetViolationsResults (jasutils .Sast )... )
189179 }
180+ return targetKeys
190181}
191182
192- func extractLocationsOnly (run * sarif.Run , targetKeys map [string ]bool ) {
193- for _ , result := range run .Results {
194- for _ , location := range result .Locations {
195- key := sarifutils .GetRelativeLocationFileName (location , run .Invocations ) + sarifutils .GetLocationSnippetText (location )
196- targetKeys [key ] = true
183+ // extractFingerprints extracts SAST fingerprints (or falls back to locations) for diff matching.
184+ func extractFingerprints (targetKeys map [string ]bool , runs ... * sarif.Run ) {
185+ for _ , run := range runs {
186+ for _ , result := range run .Results {
187+ if sarifutils .IsFingerprintsExists (result ) {
188+ key := sarifutils .GetSastDiffFingerprint (result )
189+ if key != "" {
190+ targetKeys [key ] = true
191+ }
192+ } else {
193+ for _ , location := range result .Locations {
194+ key := sarifutils .GetRelativeLocationFileName (location , run .Invocations ) + sarifutils .GetLocationSnippetText (location )
195+ targetKeys [key ] = true
196+ }
197+ }
197198 }
198199 }
199200}
200201
201- // getSastFingerprint extracts the SAST fingerprint used for diff matching.
202- // Note: Uses "precise_sink_and_sink_function" key (from Analyzer Manager for diff purposes),
203- // which differs from jasutils.SastFingerprintKey ("significant_full_path") used elsewhere.
204- func getSastFingerprint (result * sarif.Result ) string {
205- if result .Fingerprints != nil {
206- if value , ok := result .Fingerprints ["precise_sink_and_sink_function" ]; ok {
207- return value
202+ // extractLocationsOnly extracts location-based keys (file path + snippet) for diff matching.
203+ func extractLocationsOnly (targetKeys map [string ]bool , runs ... * sarif.Run ) {
204+ for _ , run := range runs {
205+ for _ , result := range run .Results {
206+ for _ , location := range result .Locations {
207+ key := sarifutils .GetRelativeLocationFileName (location , run .Invocations ) + sarifutils .GetLocationSnippetText (location )
208+ targetKeys [key ] = true
209+ }
208210 }
209211 }
210- return ""
211212}
212213
213214// filterNewSarifFindings removes findings from sourceRuns that already exist in targetKeys.
@@ -221,7 +222,7 @@ func filterNewSarifFindings(sourceRuns []*sarif.Run, targetKeys map[string]bool)
221222
222223 for _ , result := range run .Results {
223224 if sarifutils .IsFingerprintsExists (result ) {
224- if ! targetKeys [getSastFingerprint (result )] {
225+ if ! targetKeys [sarifutils . GetSastDiffFingerprint (result )] {
225226 filteredResults = append (filteredResults , result )
226227 }
227228 } else {
0 commit comments