16
16
import java .util .Optional ;
17
17
import java .util .Set ;
18
18
import java .util .TreeSet ;
19
- import java .util .function .Function ;
20
19
import java .util .stream .Collectors ;
21
20
import se .bjurr .violations .lib .ViolationsLogger ;
22
21
import se .bjurr .violations .lib .model .SEVERITY ;
31
30
import se .bjurr .violations .lib .model .generated .sarif .Region ;
32
31
import se .bjurr .violations .lib .model .generated .sarif .ReportingConfiguration ;
33
32
import se .bjurr .violations .lib .model .generated .sarif .ReportingDescriptor ;
33
+ import se .bjurr .violations .lib .model .generated .sarif .ReportingDescriptorReference ;
34
34
import se .bjurr .violations .lib .model .generated .sarif .Result ;
35
35
import se .bjurr .violations .lib .model .generated .sarif .Result .Level ;
36
36
import se .bjurr .violations .lib .model .generated .sarif .Run ;
37
37
import se .bjurr .violations .lib .model .generated .sarif .SarifSchema ;
38
+ import se .bjurr .violations .lib .model .generated .sarif .ToolComponent ;
39
+ import se .bjurr .violations .lib .model .generated .sarif .ToolComponentReference ;
38
40
import se .bjurr .violations .lib .reports .Parser ;
39
41
import se .bjurr .violations .lib .util .Utils ;
40
42
41
43
public class SarifParser implements ViolationsParser {
44
+ /** 3.52.3 */
45
+ public enum DescriptorElementOf {
46
+ RULES ,
47
+ NOTIFICATIONS
48
+ }
49
+
42
50
public static final String SARIF_RESULTS_CORRELATION_GUID = "correlationGuid" ;
43
51
44
52
public class ParsedPhysicalLocation {
@@ -127,7 +135,6 @@ ReportingConfiguration.Level.class, new ReportingConfigurationDeserializer())
127
135
128
136
private Set <Violation > parseResults (final Run run ) {
129
137
final Set <Violation > violations = new TreeSet <>();
130
- final Map <String , ReportingDescriptor > rulesById = this .getRulesById (run );
131
138
final String reporter = this .getReporter (run );
132
139
for (final Result result : run .getResults ()) {
133
140
final String ruleId = result .getRuleId ();
@@ -143,8 +150,8 @@ private Set<Violation> parseResults(final Run run) {
143
150
if (!isNullOrEmpty (correlationGuid )) {
144
151
specifics .put (SARIF_RESULTS_CORRELATION_GUID , correlationGuid );
145
152
}
146
-
147
- final ReportingDescriptor reportingDescriptor = rulesById . get ( ruleId );
153
+ final ReportingDescriptor reportingDescriptor =
154
+ this . findReportingDescriptor ( run , result , DescriptorElementOf . RULES ). orElse ( null );
148
155
final String category = this .getCategory (reportingDescriptor );
149
156
150
157
final Optional <String > helpTextOpt = this .findHelpText (reportingDescriptor );
@@ -189,12 +196,18 @@ private Set<Violation> parseResults(final Run run) {
189
196
190
197
private Set <Violation > parseNotifications (final Run run ) {
191
198
final Set <Violation > violations = new TreeSet <>();
192
- final List < ReportingDescriptor > notifications = this .getNotifications (run );
199
+ this .getNotifications (run );
193
200
final String reporter = this .getReporter (run );
194
201
for (final Invocation invocation : run .getInvocations ()) {
195
202
for (final Notification notification : invocation .getToolConfigurationNotifications ()) {
203
+ final ReportingDescriptorReference ref = notification .getAssociatedRule ();
204
+ final Integer ruleIndex = this .getRuleIndex (ref );
205
+ final String ruleId = null ;
196
206
final ReportingDescriptor reportingDescriptor =
197
- this .getReportingDescriptor (notifications , notification );
207
+ this .findReportingDescriptor (
208
+ run , DescriptorElementOf .NOTIFICATIONS , ref , ruleIndex , ruleId )
209
+ .orElse (null );
210
+
198
211
final String reportingDescriptorName = this .getName (reportingDescriptor );
199
212
final SEVERITY severity = this .toSeverity (notification .getLevel (), reportingDescriptor );
200
213
final List <Location > locations = this .filter (notification .getLocations ());
@@ -221,13 +234,18 @@ private Set<Violation> parseNotifications(final Run run) {
221
234
.build ());
222
235
}
223
236
} else {
237
+ final String message =
238
+ this .extractMessage (notification .getMessage (), reportingDescriptor );
239
+ if (message .isEmpty ()) {
240
+ continue ;
241
+ }
224
242
violations .add (
225
243
violationBuilder ()
226
244
.setParser (Parser .SARIF )
227
245
.setFile (Violation .NO_FILE )
228
246
.setStartLine (Violation .NO_LINE )
229
247
.setRule (reportingDescriptorName )
230
- .setMessage (this . extractMessage ( notification . getMessage (), reportingDescriptor ) )
248
+ .setMessage (message )
231
249
.setSeverity (severity )
232
250
.setReporter (reporter )
233
251
.build ());
@@ -237,6 +255,17 @@ private Set<Violation> parseNotifications(final Run run) {
237
255
return violations ;
238
256
}
239
257
258
+ private Integer getRuleIndex (final ReportingDescriptorReference ref ) {
259
+ Integer ruleIndex = null ;
260
+ if (ref != null ) {
261
+ ruleIndex = ref .getIndex ();
262
+ }
263
+ if (ruleIndex == null || ruleIndex == -1 ) {
264
+ return null ;
265
+ }
266
+ return ruleIndex ;
267
+ }
268
+
240
269
private String getName (final ReportingDescriptor reportingDescriptor ) {
241
270
if (reportingDescriptor != null ) {
242
271
return reportingDescriptor .getName ();
@@ -295,18 +324,6 @@ private List<Location> filterLocations(final List<Location> locations) {
295
324
.collect (Collectors .toList ());
296
325
}
297
326
298
- private ReportingDescriptor getReportingDescriptor (
299
- final List <ReportingDescriptor > notifications , final Notification notification ) {
300
- if (notification .getDescriptor () == null ) {
301
- return null ;
302
- }
303
- final Integer notificationIndex = notification .getDescriptor ().getIndex ();
304
- if (notificationIndex == null ) {
305
- return null ;
306
- }
307
- return notifications .get (notificationIndex );
308
- }
309
-
310
327
private String toMessage (
311
328
final Message message ,
312
329
final Optional <String > helpTextOpt ,
@@ -392,16 +409,6 @@ private String extractMessage(
392
409
return "" ;
393
410
}
394
411
395
- private Map <String , ReportingDescriptor > getRulesById (final Run run ) {
396
- if (run .getTool () != null
397
- && run .getTool ().getDriver () != null
398
- && run .getTool ().getDriver ().getRules () != null ) {
399
- return run .getTool ().getDriver ().getRules ().stream ()
400
- .collect (Collectors .toMap (ReportingDescriptor ::getId , Function .identity ()));
401
- }
402
- return new HashMap <>();
403
- }
404
-
405
412
private Optional <String > findHelpText (final ReportingDescriptor r ) {
406
413
if (r == null ) {
407
414
return Optional .empty ();
@@ -461,4 +468,115 @@ private Optional<SEVERITY> toSeverity(final ReportingDescriptor reportingDescrip
461
468
}
462
469
return Optional .empty ();
463
470
}
471
+
472
+ private Optional <ReportingDescriptor > findReportingDescriptor (
473
+ final Run run , final Result result , final DescriptorElementOf lookIn ) {
474
+ final ReportingDescriptorReference ref = result .getRule ();
475
+ final Integer ruleIndex = this .findRuleIndex (result , ref );
476
+ final String ruleId = result .getRuleId ();
477
+ return this .findReportingDescriptor (run , lookIn , ref , ruleIndex , ruleId );
478
+ }
479
+
480
+ private Optional <ReportingDescriptor > findReportingDescriptor (
481
+ final Run run ,
482
+ final DescriptorElementOf lookIn ,
483
+ final ReportingDescriptorReference ref ,
484
+ final Integer ruleIndex ,
485
+ final String ruleId ) {
486
+ final ToolComponent tool = this .findToolComponent (run , ref );
487
+ if (tool == null ) {
488
+ return Optional .empty ();
489
+ }
490
+ if (ruleIndex != null ) {
491
+ return Optional .of (this .getReportingDescriptorByIndex (tool , ruleIndex , lookIn ));
492
+ }
493
+
494
+ if (ref != null && ref .getGuid () != null ) {
495
+ return this .findReportingDescriptorByGui (tool , ref .getGuid (), lookIn );
496
+ }
497
+ if (ruleId != null ) {
498
+ return this .findReportingDescriptorByRuleId (tool , ruleId , lookIn );
499
+ }
500
+ return Optional .empty ();
501
+ }
502
+
503
+ private Integer findRuleIndex (final Result result , final ReportingDescriptorReference ref ) {
504
+ Integer ruleIndex = result .getRuleIndex ();
505
+ if (ruleIndex == -1 ) {
506
+ ruleIndex = null ;
507
+ }
508
+ if (ruleIndex == null && ref != null ) {
509
+ ruleIndex = ref .getIndex ();
510
+ }
511
+ return ruleIndex ;
512
+ }
513
+
514
+ private ToolComponent findToolComponent (final Run run , final ReportingDescriptorReference ref ) {
515
+ if (run .getTool () == null ) {
516
+ return null ;
517
+ }
518
+ if (ref == null ) {
519
+ return run .getTool ().getDriver ();
520
+ }
521
+ final ToolComponentReference toolRef = ref .getToolComponent ();
522
+ if (toolRef .getGuid () != null ) {
523
+ return this .getToolComponentByGui (run , toolRef .getGuid ());
524
+ }
525
+ if (toolRef .getIndex () != null ) {
526
+ return this .getToolComponentByIndex (run , toolRef .getIndex ());
527
+ }
528
+ return run .getTool ().getDriver ();
529
+ }
530
+
531
+ private ReportingDescriptor getReportingDescriptorByIndex (
532
+ final ToolComponent tool , final Integer index , final DescriptorElementOf lookIn ) {
533
+ if (lookIn == DescriptorElementOf .RULES ) {
534
+ return new ArrayList <>(tool .getRules ()).get (index );
535
+ }
536
+ if (lookIn == DescriptorElementOf .NOTIFICATIONS ) {
537
+ return new ArrayList <>(tool .getNotifications ()).get (index );
538
+ }
539
+ throw new IllegalStateException (lookIn + " cannot find ReportingDescriptor" );
540
+ }
541
+
542
+ private Optional <ReportingDescriptor > findReportingDescriptorByGui (
543
+ final ToolComponent tool , final String guid , final DescriptorElementOf lookIn ) {
544
+ if (lookIn == DescriptorElementOf .RULES ) {
545
+ return tool .getRules ().stream ()
546
+ .filter ((it ) -> it .getGuid () != null && it .getGuid ().equals (guid ))
547
+ .findFirst ();
548
+ }
549
+ if (lookIn == DescriptorElementOf .NOTIFICATIONS ) {
550
+ return tool .getNotifications ().stream ()
551
+ .filter ((it ) -> it .getGuid () != null && it .getGuid ().equals (guid ))
552
+ .findFirst ();
553
+ }
554
+ return Optional .empty ();
555
+ }
556
+
557
+ private Optional <ReportingDescriptor > findReportingDescriptorByRuleId (
558
+ final ToolComponent tool , final String ruleId , final DescriptorElementOf lookIn ) {
559
+ if (lookIn == DescriptorElementOf .RULES ) {
560
+ return tool .getRules ().stream ()
561
+ .filter ((it ) -> it .getId () != null && it .getId ().equals (ruleId ))
562
+ .findFirst ();
563
+ }
564
+ if (lookIn == DescriptorElementOf .NOTIFICATIONS ) {
565
+ return tool .getNotifications ().stream ()
566
+ .filter ((it ) -> it .getId () != null && it .getId ().equals (ruleId ))
567
+ .findFirst ();
568
+ }
569
+ throw new IllegalStateException (lookIn + " cannot find ReportingDescriptor" );
570
+ }
571
+
572
+ private ToolComponent getToolComponentByIndex (final Run run , final Integer index ) {
573
+ return new ArrayList <>(run .getTool ().getExtensions ()).get (index );
574
+ }
575
+
576
+ private ToolComponent getToolComponentByGui (final Run run , final String guid ) {
577
+ return run .getTool ().getExtensions ().stream ()
578
+ .filter ((it ) -> it .getGuid () != null && it .getGuid ().equals (guid ))
579
+ .findFirst ()
580
+ .get ();
581
+ }
464
582
}
0 commit comments