github-advanced-security[bot] commented on code in PR #655:
URL: https://github.com/apache/creadur-rat/pull/655#discussion_r3334750482


##########
apache-rat-core/src/main/java/org/apache/rat/Reporter.java:
##########
@@ -76,83 +82,39 @@
 
     /**
      * Executes the report and builds the output.
-     * This method will build the internal XML document if it does not already 
exist.
-     * If this method or either of the {@link #output()} methods have already 
been called this method will return
-     * the previous results.
-     * @return the claim statistics.
+     * @return the Output object.
      * @throws RatException on error.
      */
-    public ClaimStatistic execute() throws RatException  {
-        if (document == null || statistic == null) {
-            try {
-                if (configuration.hasSource()) {
-                    ByteArrayOutputStream outputStream = new 
ByteArrayOutputStream();
-                    Writer outputWriter = new OutputStreamWriter(outputStream, 
StandardCharsets.UTF_8);
-                    try (IXmlWriter writer = new XmlWriter(outputWriter)) {
-                        statistic = new ClaimStatistic();
-                        RatReport report = 
XmlReportFactory.createStandardReport(writer, statistic, configuration);
-                        report.startReport();
-                        configuration.getSources().build().run(report);
-                        report.endReport();
-                    }
-                    InputStream inputStream = new 
ByteArrayInputStream(outputStream.toByteArray());
-                    document = 
DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(inputStream);
-                } else {
-                    document = 
DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
-                    statistic = new ClaimStatistic();
+    public Output execute() throws RatException {
+        try {
+            Output.Builder builder = 
Output.builder().configuration(configuration);
+            if (configuration.hasSource()) {
+                StringBuilder sb = new StringBuilder();
+                try (IXmlWriter writer = new XmlWriter(sb)) {
+                    writer.startDocument();
+                    ClaimStatistic statistic = new ClaimStatistic();
+                    builder.statistic(statistic);
+                    RatReport report = 
XmlReportFactory.createStandardReport(writer, statistic, configuration);
+                    report.startReport();
+                    configuration.getSources().build().run(report);
+                    report.endReport();
+                    InputSource inputSource = new InputSource(new 
StringReader(sb.toString()));
+                    
builder.document(DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(inputSource));

Review Comment:
   ## SonarCloud / XML parsers should not be vulnerable to XXE attacks
   
   <!--SONAR_ISSUE_KEY:AZ6DedhBTlzZN0sxhTQc-->Disable access to external 
entities in XML parsing. <p>See more on <a 
href="https://sonarcloud.io/project/issues?id=apache_creadur-rat&issues=AZ6DedhBTlzZN0sxhTQc&open=AZ6DedhBTlzZN0sxhTQc&pullRequest=655";>SonarQube
 Cloud</a></p>
   
   [Show more 
details](https://github.com/apache/creadur-rat/security/code-scanning/12)



##########
apache-rat-core/src/main/java/org/apache/rat/ReportConfiguration.java:
##########
@@ -827,19 +865,162 @@
 
     /**
      * Validates that the configuration is valid.
-     * @param logger String consumer to log warning messages to.
      * @throws ConfigurationException on configuration error.
      */
-    public void validate(final Consumer<String> logger) {
+    public void validate() {
         if (!hasSource()) {
             String msg = "At least one source must be specified";
-            logger.accept(msg);
+            DefaultLog.getInstance().error(msg);
             throw new ConfigurationException(msg);
         }
-        if (licenseSetFactory.getLicenses(LicenseFilter.ALL).isEmpty()) {
-            String msg = "You must specify at least one license";
-            logger.accept(msg);
-            throw new ConfigurationException(msg);
+        licenseSetFactory.validate();
+    }
+
+    /**
+     * Serializes the ReportConfiguration into an XML document that can be 
deserialzed by the Serde.
+     * Deserialized ReportConfigurations can not be executed as the reportable 
objects a simply named placeholders
+     * and do not have access to the original object.
+     */
+    @SuppressFBWarnings({"MALICIOUS_XSLT", "XXE_DOCUMENT"})
+    public class Serde {
+        /**
+         * Writes the configuration as an XML document to the appendable.
+         *
+         * @param appendable the Appendable to write to.
+         * @throws IOException on error.
+         */
+        public void serialize(final Appendable appendable) throws IOException {
+            try (IXmlWriter writer = new XmlWriter(appendable)) {
+                writer.openElement("ReportConfiguration")
+                        .attribute("addingLicenses", 
Boolean.toString(addingLicenses))
+                        .attribute("addingLicensesForced", 
Boolean.toString(addingLicensesForced))
+                        .attribute("listFamilies", listFamilies.name())
+                        .attribute("listLicenses", listLicenses.name())
+                        .attribute("dryRun", Boolean.toString(dryRun))
+                        .attribute("archiveProcessing", 
getArchiveProcessing().name())
+                        .attribute("standardProcessing", 
getStandardProcessing().name())
+                        .attribute("stylesheet", styleSheet.name())
+                        .attribute("output", out.name());
+                if (StringUtils.isNotEmpty(copyrightMessage)) {
+                    
writer.openElement("copyrightMessage").content(copyrightMessage).closeElement();
+                }
+                writer.openElement("sources");
+                for (File f : sources) {
+                    writer.openElement("source").attribute("name", 
f.getName()).closeElement();
+                }
+                writer.closeElement("sources").openElement("reportables");
+                for (IReportable reportable : reportables) {
+                    writer.openElement("reportable")
+                            .attribute("baseName", 
reportable.name().getBaseName())
+                            .attribute("name", reportable.name().toString())
+                            .attribute("class", 
reportable.getClass().getName()).closeElement();
+                }
+                writer.closeElement();
+
+                exclusionProcessor.serde().serialize(writer);
+
+                writer.openElement("claimValidator");
+                for (ClaimStatistic.Counter counter : 
ClaimStatistic.Counter.values()) {
+                    writer.openElement("claimCounter")
+                            .attribute("name", 
counter.name()).attribute("min", 
Integer.toString(claimValidator.getMin(counter)))
+                            .attribute("max", 
Integer.toString(claimValidator.getMax(counter))).closeElement();
+                }
+                writer.closeElement();
+            } catch (IOException e) {
+                throw e;
+            } catch (Exception e) {
+                throw new IOException(e);
+            }
+        }
+
+        public void deserialize(final IOSupplier<InputStream> 
inputStreamSupplier, final DocumentName workingDirectory) throws IOException {
+            DocumentBuilder builder;
+            try {
+                builder = 
DocumentBuilderFactory.newInstance().newDocumentBuilder();

Review Comment:
   ## SonarCloud / XML parsers should not be vulnerable to XXE attacks
   
   <!--SONAR_ISSUE_KEY:AZ6DedlzTlzZN0sxhTQr-->Disable access to external 
entities in XML parsing. <p>See more on <a 
href="https://sonarcloud.io/project/issues?id=apache_creadur-rat&issues=AZ6DedlzTlzZN0sxhTQr&open=AZ6DedlzTlzZN0sxhTQr&pullRequest=655";>SonarQube
 Cloud</a></p>
   
   [Show more 
details](https://github.com/apache/creadur-rat/security/code-scanning/13)



##########
apache-rat-core/src/main/java/org/apache/rat/report/claim/ClaimStatistic.java:
##########
@@ -288,5 +312,96 @@
         public int value() {
             return value;
         }
+
+        @Override
+        public String toString() {
+            return String.valueOf(value);
+        }
+    }
+
+    /**
+     * Serialze and deserialze the claim Statistic.
+     */
+    public class Serde {
+
+        public void serialize(final Appendable appendable) throws IOException {
+            try (XmlWriter writer = new XmlWriter(appendable)) {
+                writer.startDocument().openElement("ClaimStatistic")
+                        .openElement("licenseNameMap");
+                for (Map.Entry<String, IntCounter> entry : 
licenseNameMap.entrySet()) {
+                    if (entry.getValue().value > 0) {
+                        writer.openElement("licenseName")
+                                .attribute("count", 
entry.getValue().toString())
+                                .attribute("name", 
entry.getKey()).closeElement();
+                    }
+                }
+                writer.closeElement()
+                        .openElement("licenseFamilyCategoryMap");
+                for (Map.Entry<String, IntCounter> entry : 
licenseFamilyCategoryMap.entrySet()) {
+                    if (entry.getValue().value > 0) {
+                        writer.openElement("familyCategory")
+                                .attribute("count", 
entry.getValue().toString())
+                                .attribute("name", 
entry.getKey()).closeElement();
+                    }
+                }
+                writer.closeElement()
+                        .openElement("documentTypeMap");
+                for (Map.Entry<Document.Type, IntCounter> entry : 
documentTypeMap.entrySet()) {
+                    if (entry.getValue().value > 0) {
+                        writer.openElement("documentType")
+                                .attribute("count", 
entry.getValue().toString())
+                                .attribute("name", 
entry.getKey().name()).closeElement();
+                    }
+                }
+                writer.closeElement()
+                        .openElement("counterMap");
+                for (Map.Entry<ClaimStatistic.Counter, IntCounter> entry : 
counterMap.entrySet()) {
+                    if (entry.getValue().value > 0) {
+                        writer.openElement("counter")
+                                .attribute("count", 
entry.getValue().toString())
+                                .attribute("name", 
entry.getKey().name()).closeElement();
+                    }
+                }
+                writer.closeElement();
+            }
+        }
+
+        public void deserialize(final IOSupplier<InputStream> 
inputStreamSupplier) throws IOException {
+            DocumentBuilder builder;
+            try {
+                builder = 
DocumentBuilderFactory.newInstance().newDocumentBuilder();

Review Comment:
   ## SonarCloud / XML parsers should not be vulnerable to XXE attacks
   
   <!--SONAR_ISSUE_KEY:AZ6DedboTlzZN0sxhTQW-->Disable access to external 
entities in XML parsing. <p>See more on <a 
href="https://sonarcloud.io/project/issues?id=apache_creadur-rat&issues=AZ6DedboTlzZN0sxhTQW&open=AZ6DedboTlzZN0sxhTQW&pullRequest=655";>SonarQube
 Cloud</a></p>
   
   [Show more 
details](https://github.com/apache/creadur-rat/security/code-scanning/10)



##########
apache-rat-core/src/main/java/org/apache/rat/Reporter.java:
##########
@@ -172,24 +134,174 @@
     }
 
     /**
-     * Writes a text summary of issues with the run.
-     * @param appendable the appendable to write to.
-     * @throws IOException on error.
+     * The output from a report run.
      */
-    public void writeSummary(final Appendable appendable) throws IOException {
-        appendable.append("RAT summary:").append(System.lineSeparator());
-        for (ClaimStatistic.Counter counter : ClaimStatistic.Counter.values()) 
{
-            appendable.append("  ").append(counter.displayName()).append(":  ")
-                    
.append(Integer.toString(getClaimsStatistic().getCounter(counter)))
-                    .append(System.lineSeparator());
+    public static final class Output {
+        /** The XML output document */
+        private final Document document;
+        /**
+         * The claim statics from the execution that generated the document.
+         * May be empty if the Document was read from disk.
+         */
+        private final ClaimStatistic statistic;
+        /**
+         * The configuration that generated the document
+         */
+        private final ReportConfiguration configuration;
+
+        /**
+         * Create an output with statistics.
+         * @param builder the Builder
+         */
+        private Output(final Builder builder) {
+            this.document = builder.document;
+            this.statistic = builder.statistic == null ? new ClaimStatistic() 
: builder.statistic;
+            this.configuration = builder.configuration == null ? new 
ReportConfiguration() : builder.configuration;
         }
-    }
 
-    /**
-     * Gets the document that was generated during execution.
-     * @return the document that was generated during execution.
-     */
-    public Document getDocument() {
-        return document;
+        public static Builder builder() {
+            return new Builder();
+        }
+
+        /**
+         * Gets the document that was generated during execution.
+         * @return the document that was generated during execution.
+         */
+        public Document getDocument() {
+            return document;
+        }
+
+        public ClaimStatistic getStatistic() {
+            return statistic;
+        }
+
+        public ReportConfiguration getConfiguration() {
+            return configuration;
+        }
+        /**
+         * Formats the report to the output and using the stylesheet found in 
the report configuration.
+         *
+         * @param config s RAT report configuration.
+         * @throws RatException on error.
+         */
+        public void format(final ReportConfiguration config) throws 
RatException {
+            format(config.getStyleSheet(), config.getOutput());
+        }
+
+        /**
+         * Formats the report to the specified output using the stylesheet. It 
is safe to call this method more than once
+         * in order to generate multiple reports from the same run.
+         *
+         * @param stylesheet the style sheet to use for XSLT formatting.
+         * @param output the output stream to write to.
+         * @throws RatException on error.
+         */
+        @SuppressFBWarnings({"MALICIOUS_XSLT", "XXE_DTD_TRANSFORM_FACTORY", " 
XXE_XSLT_TRANSFORM_FACTORY"})
+        public void format(final IOSupplier<InputStream> stylesheet, final 
IOSupplier<OutputStream> output) throws RatException {
+            TransformerFactory tf = TransformerFactory.newInstance();
+            Transformer transformer;
+            try (OutputStream out = output.get();
+                 InputStream styleIn = stylesheet.get()) {
+                transformer = tf.newTransformer(new StreamSource(styleIn));
+                transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, 
"yes");
+                transformer.setOutputProperty(OutputKeys.METHOD, "xml");
+                transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+                transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
+                
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount";, "4");
+                transformer.transform(new DOMSource(document),
+                        new StreamResult(new OutputStreamWriter(out, 
StandardCharsets.UTF_8)));
+            } catch (TransformerException | IOException e) {
+                throw new RatException(e);
+            }
+        }
+
+        /**
+         * Writes a text summary of issues with the run.
+         * @param appendable the appendable to write to.
+         * @throws IOException on error.
+         */
+        public void writeSummary(final Appendable appendable) throws 
IOException {
+            appendable.append("RAT summary:").append(System.lineSeparator());
+            for (ClaimStatistic.Counter counter : 
ClaimStatistic.Counter.values()) {
+                appendable.append("  
").append(counter.displayName()).append(":  ")
+                        
.append(Integer.toString(statistic.getCounter(counter)))
+                        .append(System.lineSeparator());
+            }
+        }
+
+        @SuppressFBWarnings("EI_EXPOSE_REP2")
+        public static final class Builder {
+            /** The document that was generated */
+            private Document document;
+            /**
+             * The claim statistic from the execution that generated the 
document.
+             * May be empty if the Document was read from disk.
+             */
+            private ClaimStatistic statistic;
+            /**
+             * The configuration that generated the document
+             */
+            private ReportConfiguration configuration;
+
+            public Builder document(final Document document) {
+                this.document = document;
+                return this;
+            }
+            @SuppressFBWarnings("XXE_DOCUMENT")
+            public Builder document(final String fileName, final DocumentName 
workingDirectory) {
+                DocumentBuilder builder;
+                try {
+                    builder = 
DocumentBuilderFactory.newInstance().newDocumentBuilder();

Review Comment:
   ## SonarCloud / XML parsers should not be vulnerable to XXE attacks
   
   <!--SONAR_ISSUE_KEY:AZ6DedhBTlzZN0sxhTQb-->Disable access to external 
entities in XML parsing. <p>See more on <a 
href="https://sonarcloud.io/project/issues?id=apache_creadur-rat&issues=AZ6DedhBTlzZN0sxhTQb&open=AZ6DedhBTlzZN0sxhTQb&pullRequest=655";>SonarQube
 Cloud</a></p>
   
   [Show more 
details](https://github.com/apache/creadur-rat/security/code-scanning/11)



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to