1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.owasp.dependencycheck.taskdefs;
19
20 import java.io.File;
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.util.List;
24 import org.apache.tools.ant.BuildException;
25 import org.apache.tools.ant.Project;
26 import org.apache.tools.ant.Task;
27 import org.apache.tools.ant.types.EnumeratedAttribute;
28 import org.apache.tools.ant.types.Reference;
29 import org.apache.tools.ant.types.Resource;
30 import org.apache.tools.ant.types.ResourceCollection;
31 import org.apache.tools.ant.types.resources.FileProvider;
32 import org.apache.tools.ant.types.resources.Resources;
33 import org.owasp.dependencycheck.Engine;
34 import org.owasp.dependencycheck.data.nvdcve.CveDB;
35 import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
36 import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
37 import org.owasp.dependencycheck.dependency.Dependency;
38 import org.owasp.dependencycheck.dependency.Identifier;
39 import org.owasp.dependencycheck.dependency.Vulnerability;
40 import org.owasp.dependencycheck.reporting.ReportGenerator;
41 import org.owasp.dependencycheck.reporting.ReportGenerator.Format;
42 import org.owasp.dependencycheck.utils.Settings;
43 import org.slf4j.impl.StaticLoggerBinder;
44
45
46
47
48
49
50 public class DependencyCheckTask extends Task {
51
52
53
54
55 private static final String PROPERTIES_FILE = "task.properties";
56
57
58
59 private static final String NEW_LINE = System.getProperty("line.separator", "\n").intern();
60
61
62
63
64 public DependencyCheckTask() {
65 super();
66
67
68 StaticLoggerBinder.getSingleton().setTask(this);
69 }
70
71
72
73
74
75 private Resources path = null;
76
77
78
79 private Reference refid = null;
80
81
82
83
84
85
86
87 public void add(ResourceCollection rc) {
88 if (isReference()) {
89 throw new BuildException("Nested elements are not allowed when using the refid attribute.");
90 }
91 getPath().add(rc);
92 }
93
94
95
96
97
98
99
100 private synchronized Resources getPath() {
101 if (path == null) {
102 path = new Resources(getProject());
103 path.setCache(true);
104 }
105 return path;
106 }
107
108
109
110
111
112
113 public boolean isReference() {
114 return refid != null;
115 }
116
117
118
119
120
121
122 public void setRefid(Reference r) {
123 if (path != null) {
124 throw new BuildException("Nested elements are not allowed when using the refid attribute.");
125 }
126 refid = r;
127 }
128
129
130
131
132
133
134 private void dealWithReferences() throws BuildException {
135 if (isReference()) {
136 final Object o = refid.getReferencedObject(getProject());
137 if (!(o instanceof ResourceCollection)) {
138 throw new BuildException("refid '" + refid.getRefId()
139 + "' does not refer to a resource collection.");
140 }
141 getPath().add((ResourceCollection) o);
142 }
143 }
144
145
146
147
148 private String applicationName = "Dependency-Check";
149
150
151
152
153
154
155 public String getApplicationName() {
156 return applicationName;
157 }
158
159
160
161
162
163
164 public void setApplicationName(String applicationName) {
165 this.applicationName = applicationName;
166 }
167
168
169
170 private String dataDirectory = null;
171
172
173
174
175
176
177 public String getDataDirectory() {
178 return dataDirectory;
179 }
180
181
182
183
184
185
186 public void setDataDirectory(String dataDirectory) {
187 this.dataDirectory = dataDirectory;
188 }
189
190
191
192 private String reportOutputDirectory = ".";
193
194
195
196
197
198
199 public String getReportOutputDirectory() {
200 return reportOutputDirectory;
201 }
202
203
204
205
206
207
208 public void setReportOutputDirectory(String reportOutputDirectory) {
209 this.reportOutputDirectory = reportOutputDirectory;
210 }
211
212
213
214
215
216 private float failBuildOnCVSS = 11;
217
218
219
220
221
222
223 public float getFailBuildOnCVSS() {
224 return failBuildOnCVSS;
225 }
226
227
228
229
230
231
232 public void setFailBuildOnCVSS(float failBuildOnCVSS) {
233 this.failBuildOnCVSS = failBuildOnCVSS;
234 }
235
236
237
238
239 private boolean autoUpdate = true;
240
241
242
243
244
245
246 public boolean isAutoUpdate() {
247 return autoUpdate;
248 }
249
250
251
252
253
254
255 public void setAutoUpdate(boolean autoUpdate) {
256 this.autoUpdate = autoUpdate;
257 }
258
259
260
261 private boolean updateOnly = false;
262
263
264
265
266
267
268 public boolean isUpdateOnly() {
269 return updateOnly;
270 }
271
272
273
274
275
276
277 public void setUpdateOnly(boolean updateOnly) {
278 this.updateOnly = updateOnly;
279 }
280
281
282
283
284
285 private String reportFormat = "HTML";
286
287
288
289
290
291
292 public String getReportFormat() {
293 return reportFormat;
294 }
295
296
297
298
299
300
301 public void setReportFormat(ReportFormats reportFormat) {
302 this.reportFormat = reportFormat.getValue();
303 }
304
305
306
307 private String proxyServer;
308
309
310
311
312
313
314 public String getProxyServer() {
315 return proxyServer;
316 }
317
318
319
320
321
322
323 public void setProxyServer(String server) {
324 this.proxyServer = server;
325 }
326
327
328
329
330
331
332
333 @Deprecated
334 public String getProxyUrl() {
335 return proxyServer;
336 }
337
338
339
340
341
342
343
344 @Deprecated
345 public void setProxyUrl(String proxyUrl) {
346 log("A deprecated configuration option 'proxyUrl' was detected; use 'proxyServer' instead.", Project.MSG_WARN);
347 this.proxyServer = proxyUrl;
348 }
349
350
351
352 private String proxyPort;
353
354
355
356
357
358
359 public String getProxyPort() {
360 return proxyPort;
361 }
362
363
364
365
366
367
368 public void setProxyPort(String proxyPort) {
369 this.proxyPort = proxyPort;
370 }
371
372
373
374 private String proxyUsername;
375
376
377
378
379
380
381 public String getProxyUsername() {
382 return proxyUsername;
383 }
384
385
386
387
388
389
390 public void setProxyUsername(String proxyUsername) {
391 this.proxyUsername = proxyUsername;
392 }
393
394
395
396 private String proxyPassword;
397
398
399
400
401
402
403 public String getProxyPassword() {
404 return proxyPassword;
405 }
406
407
408
409
410
411
412 public void setProxyPassword(String proxyPassword) {
413 this.proxyPassword = proxyPassword;
414 }
415
416
417
418 private String connectionTimeout;
419
420
421
422
423
424
425 public String getConnectionTimeout() {
426 return connectionTimeout;
427 }
428
429
430
431
432
433
434 public void setConnectionTimeout(String connectionTimeout) {
435 this.connectionTimeout = connectionTimeout;
436 }
437
438
439
440 private String suppressionFile;
441
442
443
444
445
446
447 public String getSuppressionFile() {
448 return suppressionFile;
449 }
450
451
452
453
454
455
456 public void setSuppressionFile(String suppressionFile) {
457 this.suppressionFile = suppressionFile;
458 }
459
460
461
462 private boolean showSummary = true;
463
464
465
466
467
468
469 public boolean isShowSummary() {
470 return showSummary;
471 }
472
473
474
475
476
477
478 public void setShowSummary(boolean showSummary) {
479 this.showSummary = showSummary;
480 }
481
482
483
484
485
486
487 public void setJarAnalyzerEnabled(boolean jarAnalyzerEnabled) {
488 this.jarAnalyzerEnabled = jarAnalyzerEnabled;
489 }
490
491
492
493 private boolean archiveAnalyzerEnabled = true;
494
495
496
497
498
499
500 public boolean isArchiveAnalyzerEnabled() {
501 return archiveAnalyzerEnabled;
502 }
503
504
505
506 private boolean assemblyAnalyzerEnabled = true;
507
508
509
510
511
512
513 public void setArchiveAnalyzerEnabled(boolean archiveAnalyzerEnabled) {
514 this.archiveAnalyzerEnabled = archiveAnalyzerEnabled;
515 }
516
517
518
519
520
521
522 public boolean isAssemblyAnalyzerEnabled() {
523 return assemblyAnalyzerEnabled;
524 }
525
526
527
528
529
530
531 public void setAssemblyAnalyzerEnabled(boolean assemblyAnalyzerEnabled) {
532 this.assemblyAnalyzerEnabled = assemblyAnalyzerEnabled;
533 }
534
535
536
537 private boolean nuspecAnalyzerEnabled = true;
538
539
540
541
542
543
544 public boolean isNuspecAnalyzerEnabled() {
545 return nuspecAnalyzerEnabled;
546 }
547
548
549
550
551
552
553 public void setNuspecAnalyzerEnabled(boolean nuspecAnalyzerEnabled) {
554 this.nuspecAnalyzerEnabled = nuspecAnalyzerEnabled;
555 }
556
557
558
559 private boolean centralAnalyzerEnabled = false;
560
561
562
563
564
565
566 public boolean isCentralAnalyzerEnabled() {
567 return centralAnalyzerEnabled;
568 }
569
570
571
572
573
574
575 public void setCentralAnalyzerEnabled(boolean centralAnalyzerEnabled) {
576 this.centralAnalyzerEnabled = centralAnalyzerEnabled;
577 }
578
579
580
581
582 private boolean nexusAnalyzerEnabled = true;
583
584
585
586
587
588
589 public boolean isNexusAnalyzerEnabled() {
590 return nexusAnalyzerEnabled;
591 }
592
593
594
595
596
597
598 public void setNexusAnalyzerEnabled(boolean nexusAnalyzerEnabled) {
599 this.nexusAnalyzerEnabled = nexusAnalyzerEnabled;
600 }
601
602
603
604
605 private String nexusUrl;
606
607
608
609
610
611
612 public String getNexusUrl() {
613 return nexusUrl;
614 }
615
616
617
618
619
620
621 public void setNexusUrl(String nexusUrl) {
622 this.nexusUrl = nexusUrl;
623 }
624
625
626
627 private boolean nexusUsesProxy = true;
628
629
630
631
632
633
634 public boolean isNexusUsesProxy() {
635 return nexusUsesProxy;
636 }
637
638
639
640
641
642
643 public void setNexusUsesProxy(boolean nexusUsesProxy) {
644 this.nexusUsesProxy = nexusUsesProxy;
645 }
646
647
648
649
650 private String databaseDriverName;
651
652
653
654
655
656
657 public String getDatabaseDriverName() {
658 return databaseDriverName;
659 }
660
661
662
663
664
665
666 public void setDatabaseDriverName(String databaseDriverName) {
667 this.databaseDriverName = databaseDriverName;
668 }
669
670
671
672
673 private String databaseDriverPath;
674
675
676
677
678
679
680 public String getDatabaseDriverPath() {
681 return databaseDriverPath;
682 }
683
684
685
686
687
688
689 public void setDatabaseDriverPath(String databaseDriverPath) {
690 this.databaseDriverPath = databaseDriverPath;
691 }
692
693
694
695 private String connectionString;
696
697
698
699
700
701
702 public String getConnectionString() {
703 return connectionString;
704 }
705
706
707
708
709
710
711 public void setConnectionString(String connectionString) {
712 this.connectionString = connectionString;
713 }
714
715
716
717 private String databaseUser;
718
719
720
721
722
723
724 public String getDatabaseUser() {
725 return databaseUser;
726 }
727
728
729
730
731
732
733 public void setDatabaseUser(String databaseUser) {
734 this.databaseUser = databaseUser;
735 }
736
737
738
739
740 private String databasePassword;
741
742
743
744
745
746
747 public String getDatabasePassword() {
748 return databasePassword;
749 }
750
751
752
753
754
755
756 public void setDatabasePassword(String databasePassword) {
757 this.databasePassword = databasePassword;
758 }
759
760
761
762
763
764 private String zipExtensions;
765
766
767
768
769
770
771 public String getZipExtensions() {
772 return zipExtensions;
773 }
774
775
776
777
778
779
780 public void setZipExtensions(String zipExtensions) {
781 this.zipExtensions = zipExtensions;
782 }
783
784
785
786
787 private String cveUrl12Modified;
788
789
790
791
792
793
794 public String getCveUrl12Modified() {
795 return cveUrl12Modified;
796 }
797
798
799
800
801
802
803 public void setCveUrl12Modified(String cveUrl12Modified) {
804 this.cveUrl12Modified = cveUrl12Modified;
805 }
806
807
808
809
810 private String cveUrl20Modified;
811
812
813
814
815
816
817 public String getCveUrl20Modified() {
818 return cveUrl20Modified;
819 }
820
821
822
823
824
825
826 public void setCveUrl20Modified(String cveUrl20Modified) {
827 this.cveUrl20Modified = cveUrl20Modified;
828 }
829
830
831
832
833 private String cveUrl12Base;
834
835
836
837
838
839
840 public String getCveUrl12Base() {
841 return cveUrl12Base;
842 }
843
844
845
846
847
848
849 public void setCveUrl12Base(String cveUrl12Base) {
850 this.cveUrl12Base = cveUrl12Base;
851 }
852
853
854
855
856 private String cveUrl20Base;
857
858
859
860
861
862
863 public String getCveUrl20Base() {
864 return cveUrl20Base;
865 }
866
867
868
869
870
871
872 public void setCveUrl20Base(String cveUrl20Base) {
873 this.cveUrl20Base = cveUrl20Base;
874 }
875
876
877
878 private String pathToMono;
879
880
881
882
883
884
885 public String getPathToMono() {
886 return pathToMono;
887 }
888
889
890
891
892
893
894 public void setPathToMono(String pathToMono) {
895 this.pathToMono = pathToMono;
896 }
897
898 @Override
899 public void execute() throws BuildException {
900 dealWithReferences();
901 validateConfiguration();
902 populateSettings();
903
904 Engine engine = null;
905 try {
906 engine = new Engine(DependencyCheckTask.class.getClassLoader());
907
908 if (updateOnly) {
909 engine.doUpdates();
910 } else {
911 try {
912 for (Resource resource : path) {
913 final FileProvider provider = resource.as(FileProvider.class);
914 if (provider != null) {
915 final File file = provider.getFile();
916 if (file != null && file.exists()) {
917 engine.scan(file);
918 }
919 }
920 }
921
922 engine.analyzeDependencies();
923 DatabaseProperties prop = null;
924 CveDB cve = null;
925 try {
926 cve = new CveDB();
927 cve.open();
928 prop = cve.getDatabaseProperties();
929 } catch (DatabaseException ex) {
930 log("Unable to retrieve DB Properties", ex, Project.MSG_DEBUG);
931 } finally {
932 if (cve != null) {
933 cve.close();
934 }
935 }
936 final ReportGenerator reporter = new ReportGenerator(applicationName, engine.getDependencies(), engine.getAnalyzers(), prop);
937 reporter.generateReports(reportOutputDirectory, reportFormat);
938
939 if (this.failBuildOnCVSS <= 10) {
940 checkForFailure(engine.getDependencies());
941 }
942 if (this.showSummary) {
943 showSummary(engine.getDependencies());
944 }
945 } catch (IOException ex) {
946 log("Unable to generate dependency-check report", ex, Project.MSG_DEBUG);
947 throw new BuildException("Unable to generate dependency-check report", ex);
948 } catch (Exception ex) {
949 log("An exception occurred; unable to continue task", ex, Project.MSG_DEBUG);
950 throw new BuildException("An exception occurred; unable to continue task", ex);
951 }
952 }
953 } catch (DatabaseException ex) {
954 log("Unable to connect to the dependency-check database; analysis has stopped", ex, Project.MSG_ERR);
955 } finally {
956 Settings.cleanup(true);
957 if (engine != null) {
958 engine.cleanup();
959 }
960 }
961 }
962
963
964
965
966
967
968 private void validateConfiguration() throws BuildException {
969 if (path == null) {
970 throw new BuildException("No project dependencies have been defined to analyze.");
971 }
972 if (failBuildOnCVSS < 0 || failBuildOnCVSS > 11) {
973 throw new BuildException("Invalid configuration, failBuildOnCVSS must be between 0 and 11.");
974 }
975 }
976
977
978
979
980
981 private void populateSettings() {
982 Settings.initialize();
983 InputStream taskProperties = null;
984 try {
985 taskProperties = this.getClass().getClassLoader().getResourceAsStream(PROPERTIES_FILE);
986 Settings.mergeProperties(taskProperties);
987 } catch (IOException ex) {
988 log("Unable to load the dependency-check ant task.properties file.", ex, Project.MSG_WARN);
989 } finally {
990 if (taskProperties != null) {
991 try {
992 taskProperties.close();
993 } catch (IOException ex) {
994 log("", ex, Project.MSG_DEBUG);
995 }
996 }
997 }
998 if (dataDirectory != null) {
999 Settings.setString(Settings.KEYS.DATA_DIRECTORY, dataDirectory);
1000 } else {
1001 final File jarPath = new File(DependencyCheckTask.class.getProtectionDomain().getCodeSource().getLocation().getPath());
1002 final File base = jarPath.getParentFile();
1003 final String sub = Settings.getString(Settings.KEYS.DATA_DIRECTORY);
1004 final File dataDir = new File(base, sub);
1005 Settings.setString(Settings.KEYS.DATA_DIRECTORY, dataDir.getAbsolutePath());
1006 }
1007
1008 Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, autoUpdate);
1009
1010 if (proxyServer != null && !proxyServer.isEmpty()) {
1011 Settings.setString(Settings.KEYS.PROXY_SERVER, proxyServer);
1012 }
1013 if (proxyPort != null && !proxyPort.isEmpty()) {
1014 Settings.setString(Settings.KEYS.PROXY_PORT, proxyPort);
1015 }
1016 if (proxyUsername != null && !proxyUsername.isEmpty()) {
1017 Settings.setString(Settings.KEYS.PROXY_USERNAME, proxyUsername);
1018 }
1019 if (proxyPassword != null && !proxyPassword.isEmpty()) {
1020 Settings.setString(Settings.KEYS.PROXY_PASSWORD, proxyPassword);
1021 }
1022 if (connectionTimeout != null && !connectionTimeout.isEmpty()) {
1023 Settings.setString(Settings.KEYS.CONNECTION_TIMEOUT, connectionTimeout);
1024 }
1025 if (suppressionFile != null && !suppressionFile.isEmpty()) {
1026 Settings.setString(Settings.KEYS.SUPPRESSION_FILE, suppressionFile);
1027 }
1028
1029
1030
1031 Settings.setBoolean(Settings.KEYS.ANALYZER_JAR_ENABLED, jarAnalyzerEnabled);
1032
1033 Settings.setBoolean(Settings.KEYS.ANALYZER_NUSPEC_ENABLED, nuspecAnalyzerEnabled);
1034
1035 Settings.setBoolean(Settings.KEYS.ANALYZER_CENTRAL_ENABLED, centralAnalyzerEnabled);
1036
1037 Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED, nexusAnalyzerEnabled);
1038 if (nexusUrl != null && !nexusUrl.isEmpty()) {
1039 Settings.setString(Settings.KEYS.ANALYZER_NEXUS_URL, nexusUrl);
1040 }
1041 Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_PROXY, nexusUsesProxy);
1042
1043 Settings.setBoolean(Settings.KEYS.ANALYZER_ARCHIVE_ENABLED, archiveAnalyzerEnabled);
1044 if (zipExtensions != null && !zipExtensions.isEmpty()) {
1045 Settings.setString(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS, zipExtensions);
1046 }
1047
1048 Settings.setBoolean(Settings.KEYS.ANALYZER_ASSEMBLY_ENABLED, assemblyAnalyzerEnabled);
1049 if (pathToMono != null && !pathToMono.isEmpty()) {
1050 Settings.setString(Settings.KEYS.ANALYZER_ASSEMBLY_MONO_PATH, pathToMono);
1051 }
1052
1053 if (databaseDriverName != null && !databaseDriverName.isEmpty()) {
1054 Settings.setString(Settings.KEYS.DB_DRIVER_NAME, databaseDriverName);
1055 }
1056 if (databaseDriverPath != null && !databaseDriverPath.isEmpty()) {
1057 Settings.setString(Settings.KEYS.DB_DRIVER_PATH, databaseDriverPath);
1058 }
1059 if (connectionString != null && !connectionString.isEmpty()) {
1060 Settings.setString(Settings.KEYS.DB_CONNECTION_STRING, connectionString);
1061 }
1062 if (databaseUser != null && !databaseUser.isEmpty()) {
1063 Settings.setString(Settings.KEYS.DB_USER, databaseUser);
1064 }
1065 if (databasePassword != null && !databasePassword.isEmpty()) {
1066 Settings.setString(Settings.KEYS.DB_PASSWORD, databasePassword);
1067 }
1068 if (cveUrl12Modified != null && !cveUrl12Modified.isEmpty()) {
1069 Settings.setString(Settings.KEYS.CVE_MODIFIED_12_URL, cveUrl12Modified);
1070 }
1071 if (cveUrl20Modified != null && !cveUrl20Modified.isEmpty()) {
1072 Settings.setString(Settings.KEYS.CVE_MODIFIED_20_URL, cveUrl20Modified);
1073 }
1074 if (cveUrl12Base != null && !cveUrl12Base.isEmpty()) {
1075 Settings.setString(Settings.KEYS.CVE_SCHEMA_1_2, cveUrl12Base);
1076 }
1077 if (cveUrl20Base != null && !cveUrl20Base.isEmpty()) {
1078 Settings.setString(Settings.KEYS.CVE_SCHEMA_2_0, cveUrl20Base);
1079 }
1080 }
1081
1082
1083
1084
1085
1086
1087
1088
1089 private void checkForFailure(List<Dependency> dependencies) throws BuildException {
1090 final StringBuilder ids = new StringBuilder();
1091 for (Dependency d : dependencies) {
1092 for (Vulnerability v : d.getVulnerabilities()) {
1093 if (v.getCvssScore() >= failBuildOnCVSS) {
1094 if (ids.length() == 0) {
1095 ids.append(v.getName());
1096 } else {
1097 ids.append(", ").append(v.getName());
1098 }
1099 }
1100 }
1101 }
1102 if (ids.length() > 0) {
1103 final String msg = String.format("%n%nDependency-Check Failure:%n"
1104 + "One or more dependencies were identified with vulnerabilities that have a CVSS score greater then '%.1f': %s%n"
1105 + "See the dependency-check report for more details.%n%n", failBuildOnCVSS, ids.toString());
1106 throw new BuildException(msg);
1107 }
1108 }
1109
1110
1111
1112
1113
1114
1115 private void showSummary(List<Dependency> dependencies) {
1116 final StringBuilder summary = new StringBuilder();
1117 for (Dependency d : dependencies) {
1118 boolean firstEntry = true;
1119 final StringBuilder ids = new StringBuilder();
1120 for (Vulnerability v : d.getVulnerabilities()) {
1121 if (firstEntry) {
1122 firstEntry = false;
1123 } else {
1124 ids.append(", ");
1125 }
1126 ids.append(v.getName());
1127 }
1128 if (ids.length() > 0) {
1129 summary.append(d.getFileName()).append(" (");
1130 firstEntry = true;
1131 for (Identifier id : d.getIdentifiers()) {
1132 if (firstEntry) {
1133 firstEntry = false;
1134 } else {
1135 summary.append(", ");
1136 }
1137 summary.append(id.getValue());
1138 }
1139 summary.append(") : ").append(ids).append(NEW_LINE);
1140 }
1141 }
1142 if (summary.length() > 0) {
1143 final String msg = String.format("%n%n"
1144 + "One or more dependencies were identified with known vulnerabilities:%n%n%s"
1145 + "%n%nSee the dependency-check report for more details.%n%n", summary.toString());
1146 log(msg, Project.MSG_WARN);
1147 }
1148 }
1149
1150
1151
1152
1153 public static class ReportFormats extends EnumeratedAttribute {
1154
1155
1156
1157
1158
1159
1160 @Override
1161 public String[] getValues() {
1162 int i = 0;
1163 final Format[] formats = Format.values();
1164 final String[] values = new String[formats.length];
1165 for (Format format : formats) {
1166 values[i++] = format.name();
1167 }
1168 return values;
1169 }
1170 }
1171
1172
1173
1174
1175 private boolean jarAnalyzerEnabled = true;
1176
1177
1178
1179
1180
1181
1182 public boolean isJarAnalyzerEnabled() {
1183 return jarAnalyzerEnabled;
1184 }
1185 }