diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..400c729 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,5 @@ +# To list all file extensions: +# git ls-files | awk -F . {'print $NF'}|sort -u +# +# Set the default behavior, in case people don't have core.autocrlf set. +* text=auto diff --git a/pom.xml b/pom.xml index 7b92afc..81ee4ff 100644 --- a/pom.xml +++ b/pom.xml @@ -1,14 +1,16 @@ - + 4.0.0 gov.nist.secauto oss-parent - 27 + 28-SNAPSHOT gov.nist.secauto.oscal.tools.oscal-cli cli-core - 1.0.4-SNAPSHOT + 1.1.0-SNAPSHOT jar @@ -78,8 +80,8 @@ - 0.12.2 - 3.0.3 + 1.0.0-M2-SNAPSHOT + 3.0.4-SNAPSHOT https://pages.nist.gov/metaschema-java/ @@ -109,16 +111,23 @@ 1.1.1 - 1.5.0 - 2.15.1 + 1.7.0 + 2.16.1 1.14.4 + 2.4.1 3.21.0 - 2.20.0 - 4.7.3 + 20240303 + 2.23.1 + 7.1.0 + 4.8.3 12.4 - 6.0.2 + 5.2.0 + 5.2.2 4.2 + 3.1.0 + 3.22.0 + 4.8.4.0 @@ -215,11 +224,22 @@ data ${dependency.xmlresolver.version} + + org.apache.xmlbeans + xmlbeans + ${dependency.xmlbeans.version} + com.github.erosb everit-json-schema ${dependency.everit-json.version} + + + org.json + json + ${dependency.json.version} + com.github.spotbugs spotbugs-annotations @@ -228,12 +248,7 @@ org.junit.jupiter - junit-jupiter-api - test - - - org.junit.jupiter - junit-jupiter-engine + junit-jupiter test @@ -260,6 +275,27 @@ + + org.apache.maven.plugins + maven-toolchains-plugin + ${plugin.maven-toolchains.version} + + + + toolchain + + + + + + + 11 + temurin + + + + + org.apache.maven.plugins maven-site-plugin @@ -282,13 +318,50 @@ com.github.spotbugs spotbugs-maven-plugin + ${plugin.spotbugs.version} spotbugs-exclude.xml + + org.apache.maven.plugins + maven-pmd-plugin + ${plugin.pmd.version} + + + net.sourceforge.pmd + pmd-core + ${dependency.pmd.version} + + + net.sourceforge.pmd + pmd-java + ${dependency.pmd.version} + + + + + pmd-verify + + check + + + 2 + + true + true + sarif + + + + + + org.apache.maven.plugins + maven-toolchains-plugin + io.github.git-commit-id git-commit-id-maven-plugin @@ -428,9 +501,8 @@ LICENSE-THIRD-PARTY.txt The Apache Software License, - Version 2.0|Apache - License, Version 2.0|Apache Public License - 2.0 + Version 2.0|Apache License, Version + 2.0|Apache Public License 2.0 diff --git a/src/main/assembly/bin.xml b/src/main/assembly/bin.xml index 4e60d18..e4cbca6 100644 --- a/src/main/assembly/bin.xml +++ b/src/main/assembly/bin.xml @@ -14,6 +14,9 @@ /lib ${artifact.groupId}.${artifact.artifactId}-${artifact.version}.${artifact.extension} true + + org.jetbrains:annotations + diff --git a/src/main/java-templates/gov/nist/secauto/oscal/tools/cli/core/OscalCliVersion.java b/src/main/java-templates/gov/nist/secauto/oscal/tools/cli/core/OscalCliVersion.java index a447b8c..7d1af53 100644 --- a/src/main/java-templates/gov/nist/secauto/oscal/tools/cli/core/OscalCliVersion.java +++ b/src/main/java-templates/gov/nist/secauto/oscal/tools/cli/core/OscalCliVersion.java @@ -26,7 +26,7 @@ package gov.nist.secauto.oscal.tools.cli.core; -import gov.nist.secauto.metaschema.model.common.util.IVersionInfo; +import gov.nist.secauto.metaschema.core.util.IVersionInfo; public class OscalCliVersion implements IVersionInfo { diff --git a/src/main/java/gov/nist/secauto/oscal/tools/cli/core/CLI.java b/src/main/java/gov/nist/secauto/oscal/tools/cli/core/CLI.java index 1b10921..c48dab6 100644 --- a/src/main/java/gov/nist/secauto/oscal/tools/cli/core/CLI.java +++ b/src/main/java/gov/nist/secauto/oscal/tools/cli/core/CLI.java @@ -28,12 +28,15 @@ import gov.nist.secauto.metaschema.cli.processor.CLIProcessor; import gov.nist.secauto.metaschema.cli.processor.ExitStatus; -import gov.nist.secauto.metaschema.model.MetaschemaVersion; -import gov.nist.secauto.metaschema.model.common.util.IVersionInfo; -import gov.nist.secauto.metaschema.model.common.util.MetaschemaJavaVersion; -import gov.nist.secauto.metaschema.model.common.util.ObjectUtils; +import gov.nist.secauto.metaschema.core.MetaschemaJavaVersion; +import gov.nist.secauto.metaschema.core.model.MetaschemaVersion; +import gov.nist.secauto.metaschema.core.util.IVersionInfo; +import gov.nist.secauto.metaschema.core.util.ObjectUtils; import gov.nist.secauto.oscal.lib.LibOscalVersion; import gov.nist.secauto.oscal.lib.OscalVersion; +import gov.nist.secauto.oscal.tools.cli.core.commands.ConvertCommand; +import gov.nist.secauto.oscal.tools.cli.core.commands.ResolveCommand; +import gov.nist.secauto.oscal.tools.cli.core.commands.ValidateCommand; import gov.nist.secauto.oscal.tools.cli.core.commands.assessmentplan.AssessmentPlanCommand; import gov.nist.secauto.oscal.tools.cli.core.commands.assessmentresults.AssessmentResultsCommand; import gov.nist.secauto.oscal.tools.cli.core.commands.catalog.CatalogCommand; @@ -43,7 +46,8 @@ import gov.nist.secauto.oscal.tools.cli.core.commands.profile.ProfileCommand; import gov.nist.secauto.oscal.tools.cli.core.commands.ssp.SystemSecurityPlanCommand; -import java.util.List; +import java.util.LinkedHashMap; +import java.util.Map; import edu.umd.cs.findbugs.annotations.NonNull; @@ -59,13 +63,16 @@ public static void main(String[] args) { @NonNull public static ExitStatus runCli(String... args) { - List versions = ObjectUtils.notNull( - List.of( - new OscalCliVersion(), - new LibOscalVersion(), - new OscalVersion(), - new MetaschemaJavaVersion(), - new MetaschemaVersion())); + @SuppressWarnings("serial") Map versions = ObjectUtils.notNull( + new LinkedHashMap<>() { + { + put(CLIProcessor.COMMAND_VERSION, new OscalCliVersion()); + put("https://github.com/usnistgov/liboscal-java", new LibOscalVersion()); + put("https://github.com/usnistgov/OSCAL", new OscalVersion()); + put("https://github.com/usnistgov/metaschema-java", new MetaschemaJavaVersion()); + put("https://github.com/usnistgov/metaschema", new MetaschemaVersion()); + } + }); CLIProcessor processor = new CLIProcessor("oscal-cli", versions); processor.addCommandHandler(new CatalogCommand()); processor.addCommandHandler(new ProfileCommand()); @@ -75,6 +82,9 @@ public static ExitStatus runCli(String... args) { processor.addCommandHandler(new AssessmentResultsCommand()); processor.addCommandHandler(new PlanOfActionsAndMilestonesCommand()); processor.addCommandHandler(new MetaschemaCommand()); + processor.addCommandHandler(new ValidateCommand()); + processor.addCommandHandler(new ConvertCommand()); + processor.addCommandHandler(new ResolveCommand()); return processor.process(args); } diff --git a/src/main/java/gov/nist/secauto/oscal/tools/cli/core/commands/AbstractOscalConvertSubcommand.java b/src/main/java/gov/nist/secauto/oscal/tools/cli/core/commands/AbstractOscalConvertSubcommand.java new file mode 100644 index 0000000..729263c --- /dev/null +++ b/src/main/java/gov/nist/secauto/oscal/tools/cli/core/commands/AbstractOscalConvertSubcommand.java @@ -0,0 +1,90 @@ +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.oscal.tools.cli.core.commands; + +import gov.nist.secauto.metaschema.cli.commands.AbstractConvertSubcommand; +import gov.nist.secauto.metaschema.cli.processor.CLIProcessor.CallingContext; +import gov.nist.secauto.metaschema.cli.processor.ExitStatus; +import gov.nist.secauto.metaschema.cli.processor.command.ICommandExecutor; +import gov.nist.secauto.metaschema.core.model.IBoundObject; +import gov.nist.secauto.metaschema.databind.IBindingContext; +import gov.nist.secauto.metaschema.databind.io.Format; +import gov.nist.secauto.metaschema.databind.io.IBoundLoader; +import gov.nist.secauto.oscal.lib.OscalBindingContext; + +import org.apache.commons.cli.CommandLine; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.Writer; +import java.net.URI; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public abstract class AbstractOscalConvertSubcommand + extends AbstractConvertSubcommand { + private static final Logger LOGGER = LogManager.getLogger(AbstractOscalConvertSubcommand.class); + + @NonNull + public abstract Class getOscalClass(); + + @Override + public ICommandExecutor newExecutor(CallingContext callingContext, CommandLine commandLine) { + return new OscalCommandExecutor(callingContext, commandLine); + } + + private final class OscalCommandExecutor + extends AbstractConversionCommandExecutor { + + private OscalCommandExecutor( + @NonNull CallingContext callingContext, + @NonNull CommandLine commandLine) { + super(callingContext, commandLine); + } + + @Override + protected IBindingContext getBindingContext() { + return OscalBindingContext.instance(); + } + + @Override + public ExitStatus execute() { + LOGGER.atWarn().log("This command path is deprecated. Please use 'convert'."); + + return super.execute(); + } + + @Override + protected void handleConversion(URI source, Format toFormat, Writer writer, IBoundLoader loader) + throws FileNotFoundException, IOException { + Class clazz = getOscalClass(); + loader.convert(source, writer, toFormat, clazz); + } + } +} diff --git a/src/main/java/gov/nist/secauto/oscal/tools/cli/core/commands/oscal/AbstractOscalValidationSubcommand.java b/src/main/java/gov/nist/secauto/oscal/tools/cli/core/commands/AbstractOscalValidationSubcommand.java similarity index 74% rename from src/main/java/gov/nist/secauto/oscal/tools/cli/core/commands/oscal/AbstractOscalValidationSubcommand.java rename to src/main/java/gov/nist/secauto/oscal/tools/cli/core/commands/AbstractOscalValidationSubcommand.java index 30c1951..8b0b6c6 100644 --- a/src/main/java/gov/nist/secauto/oscal/tools/cli/core/commands/oscal/AbstractOscalValidationSubcommand.java +++ b/src/main/java/gov/nist/secauto/oscal/tools/cli/core/commands/AbstractOscalValidationSubcommand.java @@ -24,19 +24,22 @@ * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. */ -package gov.nist.secauto.oscal.tools.cli.core.commands.oscal; +package gov.nist.secauto.oscal.tools.cli.core.commands; -import gov.nist.secauto.metaschema.binding.IBindingContext; import gov.nist.secauto.metaschema.cli.commands.AbstractValidateContentCommand; import gov.nist.secauto.metaschema.cli.processor.CLIProcessor.CallingContext; import gov.nist.secauto.metaschema.cli.processor.command.ICommandExecutor; -import gov.nist.secauto.metaschema.model.common.constraint.IConstraintSet; +import gov.nist.secauto.metaschema.core.model.constraint.IConstraintSet; +import gov.nist.secauto.metaschema.core.model.xml.ExternalConstraintsModulePostProcessor; +import gov.nist.secauto.metaschema.core.util.CollectionUtil; +import gov.nist.secauto.metaschema.databind.IBindingContext; import gov.nist.secauto.oscal.lib.OscalBindingContext; import org.apache.commons.cli.CommandLine; import org.json.JSONObject; import java.io.IOException; +import java.net.URL; import java.util.List; import java.util.Set; @@ -51,17 +54,17 @@ public abstract class AbstractOscalValidationSubcommand protected abstract List getOscalXmlSchemas() throws IOException; @NonNull - protected abstract JSONObject getOscalJsonSchema(); + protected abstract JSONObject getOscalJsonSchema() throws IOException; @Override public ICommandExecutor newExecutor(CallingContext callingContext, CommandLine commandLine) { return new OscalCommandExecutor(callingContext, commandLine); } - private class OscalCommandExecutor + protected class OscalCommandExecutor extends AbstractValidationCommandExecutor { - private OscalCommandExecutor( + protected OscalCommandExecutor( @NonNull CallingContext callingContext, @NonNull CommandLine commandLine) { super(callingContext, commandLine); @@ -69,18 +72,27 @@ private OscalCommandExecutor( @Override protected IBindingContext getBindingContext(@NonNull Set constraintSets) { - return constraintSets.isEmpty() ? OscalBindingContext.instance() : new OscalBindingContext(constraintSets); + IBindingContext retval; + if (constraintSets.isEmpty()) { + retval = OscalBindingContext.instance(); + } else { + ExternalConstraintsModulePostProcessor postProcessor + = new ExternalConstraintsModulePostProcessor(constraintSets); + + retval = new OscalBindingContext(CollectionUtil.singletonList(postProcessor)); + } + return retval; } @Override @NonNull - public List getXmlSchemas() throws IOException { + public List getXmlSchemas(URL targetResource) throws IOException { return getOscalXmlSchemas(); } @Override @NonNull - public JSONObject getJsonSchema() { + public JSONObject getJsonSchema(JSONObject json) throws IOException { return getOscalJsonSchema(); } } diff --git a/src/main/java/gov/nist/secauto/oscal/tools/cli/core/commands/AbstractRenderSubcommand.java b/src/main/java/gov/nist/secauto/oscal/tools/cli/core/commands/AbstractRenderSubcommand.java index 69242fc..87ed59a 100644 --- a/src/main/java/gov/nist/secauto/oscal/tools/cli/core/commands/AbstractRenderSubcommand.java +++ b/src/main/java/gov/nist/secauto/oscal/tools/cli/core/commands/AbstractRenderSubcommand.java @@ -35,7 +35,7 @@ import gov.nist.secauto.metaschema.cli.processor.command.DefaultExtraArgument; import gov.nist.secauto.metaschema.cli.processor.command.ExtraArgument; import gov.nist.secauto.metaschema.cli.processor.command.ICommandExecutor; -import gov.nist.secauto.metaschema.model.common.util.ObjectUtils; +import gov.nist.secauto.metaschema.core.util.ObjectUtils; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.Option; diff --git a/src/main/java/gov/nist/secauto/oscal/tools/cli/core/commands/AbstractResolveCommand.java b/src/main/java/gov/nist/secauto/oscal/tools/cli/core/commands/AbstractResolveCommand.java new file mode 100644 index 0000000..1c68324 --- /dev/null +++ b/src/main/java/gov/nist/secauto/oscal/tools/cli/core/commands/AbstractResolveCommand.java @@ -0,0 +1,322 @@ +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.oscal.tools.cli.core.commands; + +import gov.nist.secauto.metaschema.cli.processor.CLIProcessor.CallingContext; +import gov.nist.secauto.metaschema.cli.processor.ExitCode; +import gov.nist.secauto.metaschema.cli.processor.ExitStatus; +import gov.nist.secauto.metaschema.cli.processor.InvalidArgumentException; +import gov.nist.secauto.metaschema.cli.processor.OptionUtils; +import gov.nist.secauto.metaschema.cli.processor.command.AbstractTerminalCommand; +import gov.nist.secauto.metaschema.cli.processor.command.DefaultExtraArgument; +import gov.nist.secauto.metaschema.cli.processor.command.ExtraArgument; +import gov.nist.secauto.metaschema.cli.processor.command.ICommandExecutor; +import gov.nist.secauto.metaschema.core.metapath.DynamicContext; +import gov.nist.secauto.metaschema.core.metapath.StaticContext; +import gov.nist.secauto.metaschema.core.metapath.item.node.IDocumentNodeItem; +import gov.nist.secauto.metaschema.core.metapath.item.node.INodeItem; +import gov.nist.secauto.metaschema.core.util.CustomCollectors; +import gov.nist.secauto.metaschema.core.util.ObjectUtils; +import gov.nist.secauto.metaschema.databind.io.DeserializationFeature; +import gov.nist.secauto.metaschema.databind.io.Format; +import gov.nist.secauto.metaschema.databind.io.IBoundLoader; +import gov.nist.secauto.metaschema.databind.io.ISerializer; +import gov.nist.secauto.oscal.lib.OscalBindingContext; +import gov.nist.secauto.oscal.lib.model.Catalog; +import gov.nist.secauto.oscal.lib.model.Profile; +import gov.nist.secauto.oscal.lib.profile.resolver.ProfileResolutionException; +import gov.nist.secauto.oscal.lib.profile.resolver.ProfileResolver; + +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.Option; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.PrintStream; +import java.net.URI; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Locale; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public abstract class AbstractResolveCommand + extends AbstractTerminalCommand { + @NonNull + private static final List EXTRA_ARGUMENTS = ObjectUtils.notNull(List.of( + new DefaultExtraArgument("file to resolve", true), + new DefaultExtraArgument("destination file", false))); + @NonNull + private static final Option AS_OPTION = ObjectUtils.notNull( + Option.builder() + .longOpt("as") + .hasArg() + .argName("FORMAT") + .desc("source format: xml, json, or yaml") + .build()); + @NonNull + private static final Option TO_OPTION = ObjectUtils.notNull( + Option.builder() + .longOpt("to") + .required() + .hasArg().argName("FORMAT") + .desc("convert to format: xml, json, or yaml") + .build()); + @NonNull + private static final Option OVERWRITE_OPTION = ObjectUtils.notNull( + Option.builder() + .longOpt("overwrite") + .desc("overwrite the destination if it exists") + .build()); + @NonNull + private static final List