diff --git a/src/main/java/gov/nist/secauto/oscal/tools/cli/core/commands/metaschema/MetaschemaCommand.java b/src/main/java/gov/nist/secauto/oscal/tools/cli/core/commands/metaschema/MetaschemaCommand.java index f7165e0..9c1f0a3 100644 --- a/src/main/java/gov/nist/secauto/oscal/tools/cli/core/commands/metaschema/MetaschemaCommand.java +++ b/src/main/java/gov/nist/secauto/oscal/tools/cli/core/commands/metaschema/MetaschemaCommand.java @@ -28,9 +28,7 @@ import com.google.auto.service.AutoService; -import gov.nist.secauto.metaschema.cli.commands.GenerateSchemaCommand; -import gov.nist.secauto.metaschema.cli.commands.ValidateContentUsingModuleCommand; -import gov.nist.secauto.metaschema.cli.commands.ValidateModuleCommand; +import gov.nist.secauto.metaschema.cli.commands.MetaschemaCommands; import gov.nist.secauto.metaschema.cli.processor.command.AbstractParentCommand; import gov.nist.secauto.metaschema.cli.processor.command.ICommand; @@ -41,9 +39,7 @@ public class MetaschemaCommand public MetaschemaCommand() { super(true); - addCommandHandler(new GenerateSchemaCommand()); - addCommandHandler(new ValidateModuleCommand()); - addCommandHandler(new ValidateContentUsingModuleCommand()); + MetaschemaCommands.COMMANDS.forEach(this::addCommandHandler); } @Override diff --git a/src/main/java/gov/nist/secauto/oscal/tools/cli/core/commands/profile/ResolveSubcommand.java b/src/main/java/gov/nist/secauto/oscal/tools/cli/core/commands/profile/ResolveSubcommand.java index 3c682b6..0491681 100644 --- a/src/main/java/gov/nist/secauto/oscal/tools/cli/core/commands/profile/ResolveSubcommand.java +++ b/src/main/java/gov/nist/secauto/oscal/tools/cli/core/commands/profile/ResolveSubcommand.java @@ -274,49 +274,58 @@ protected ExitStatus executeCommand( return ExitCode.IO_ERROR.exit().withThrowable(ex); } Object object = document.getValue(); + if (object == null) { + return ExitCode.INVALID_ARGUMENTS.exitMessage("The target profile contained no data"); + } + if (object instanceof Catalog) { // this is a catalog - return ExitCode.INVALID_ARGUMENTS.exitMessage("The target file is already a catalog"); - } else if (object instanceof Profile) { - // this is a profile - URI sourceUri = ObjectUtils.notNull(source.toUri()); + return ExitCode.INVALID_ARGUMENTS.exitMessage("The target is already a catalog"); + } - DynamicContext dynamicContext = new DynamicContext( - StaticContext.builder() - .baseUri(sourceUri) - .defaultModelNamespace(document.getNamespace()) - .build()); - dynamicContext.setDocumentLoader(loader); - ProfileResolver resolver = new ProfileResolver(); - resolver.setDynamicContext(dynamicContext); + if (!(object instanceof Profile)) { + // this is something else + return ExitCode.INVALID_ARGUMENTS.exitMessage("The target is not a profile"); + } - IDocumentNodeItem resolvedProfile; - try { - resolvedProfile = resolver.resolve(document); - } catch (IOException | ProfileResolutionException ex) { - return ExitCode.PROCESSING_ERROR - .exitMessage( - String.format("Unable to resolve profile '%s'. %s", document.getDocumentUri(), ex.getMessage())) - .withThrowable(ex); - } + // this is a profile + URI sourceUri = ObjectUtils.notNull(source.toUri()); - // DefaultConstraintValidator validator = new - // DefaultConstraintValidator(dynamicContext); - // ((IBoundXdmNodeItem)resolvedProfile).validate(validator); - // validator.finalizeValidation(); + DynamicContext dynamicContext = new DynamicContext( + StaticContext.builder() + .baseUri(sourceUri) + .defaultModelNamespace(document.getNamespace()) + .build()); + dynamicContext.setDocumentLoader(loader); + ProfileResolver resolver = new ProfileResolver(); + resolver.setDynamicContext(dynamicContext); - ISerializer serializer - = OscalBindingContext.instance().newSerializer(toFormat, Catalog.class); - try { - if (destination == null) { - @SuppressWarnings({ "resource", "PMD.CloseResource" }) PrintStream stdOut = ObjectUtils.notNull(System.out); - serializer.serialize((Catalog) INodeItem.toValue(resolvedProfile), stdOut); - } else { - serializer.serialize((Catalog) INodeItem.toValue(resolvedProfile), destination); - } - } catch (IOException ex) { - return ExitCode.PROCESSING_ERROR.exit().withThrowable(ex); + IDocumentNodeItem resolvedProfile; + try { + resolvedProfile = resolver.resolve(document); + } catch (IOException | ProfileResolutionException ex) { + return ExitCode.PROCESSING_ERROR + .exitMessage( + String.format("Unable to resolve profile '%s'. %s", document.getDocumentUri(), ex.getMessage())) + .withThrowable(ex); + } + + // DefaultConstraintValidator validator = new + // DefaultConstraintValidator(dynamicContext); + // ((IBoundXdmNodeItem)resolvedProfile).validate(validator); + // validator.finalizeValidation(); + + ISerializer serializer + = OscalBindingContext.instance().newSerializer(toFormat, Catalog.class); + try { + if (destination == null) { + @SuppressWarnings({ "resource", "PMD.CloseResource" }) PrintStream stdOut = ObjectUtils.notNull(System.out); + serializer.serialize((Catalog) INodeItem.toValue(resolvedProfile), stdOut); + } else { + serializer.serialize((Catalog) INodeItem.toValue(resolvedProfile), destination); } + } catch (IOException ex) { + return ExitCode.PROCESSING_ERROR.exit().withThrowable(ex); } return ExitCode.OK.exit(); } diff --git a/src/test/java/gov/nist/secauto/oscal/tools/cli/core/CLITest.java b/src/test/java/gov/nist/secauto/oscal/tools/cli/core/CLITest.java index 80351e4..d2fa91b 100644 --- a/src/test/java/gov/nist/secauto/oscal/tools/cli/core/CLITest.java +++ b/src/test/java/gov/nist/secauto/oscal/tools/cli/core/CLITest.java @@ -30,15 +30,18 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; -import gov.nist.secauto.metaschema.binding.io.Format; import gov.nist.secauto.metaschema.cli.processor.ExitCode; import gov.nist.secauto.metaschema.cli.processor.ExitStatus; +import gov.nist.secauto.metaschema.core.util.ObjectUtils; +import gov.nist.secauto.metaschema.databind.io.Format; import gov.nist.secauto.oscal.lib.profile.resolver.ProfileResolutionException; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; +import java.io.IOException; +import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; @@ -61,13 +64,26 @@ void evaluateResult(@NonNull ExitStatus status, @NonNull ExitCode expectedCode, @NonNull Class thrownClass) { status.generateMessage(true); Throwable thrown = status.getThrowable(); - assert thrown != null; assertAll( () -> assertEquals(expectedCode, status.getExitCode(), "exit code mismatch"), - () -> assertEquals(thrownClass, thrown.getClass(), "expected Throwable mismatch")); + () -> assertEquals( + thrownClass, + thrown == null ? null : thrown.getClass(), + "Throwable mismatch")); } - private static Stream providesValues() { + private static String generateOutputPath(@NonNull Path source, @NonNull Format targetFormat) throws IOException { + String filename = ObjectUtils.notNull(source.getFileName()).toString(); + + int pos = filename.lastIndexOf('.'); + filename = filename.substring(0, pos) + "_converted" + targetFormat.getDefaultExtension(); + + Path dir = Files.createDirectories(Path.of("target/oscal-cli-convert")); + + return dir.resolve(filename).toString(); + } + + private static Stream providesValues() throws IOException { final String[] commands = { "ap", "ar", "catalog", "component-definition", "profile", "poam", "ssp" }; final Map> formatEntries = Map.of( Format.XML, Arrays.asList(Format.JSON, Format.YAML), @@ -76,42 +92,83 @@ private static Stream providesValues() { List values = new ArrayList<>(); values.add(Arguments.of(new String[] { "--version" }, ExitCode.OK, null)); - // TODO: Test all data formats once usnistgov/oscal-cli#216 fix merged. - Path path = Paths.get("src/test/resources/cli/example_profile_invalid" + Format.XML.getDefaultExtension()); - values.add( - Arguments.of(new String[] { "profile", "resolve", "--to=" + Format.XML.name().toLowerCase(), path.toString() }, - ExitCode.PROCESSING_ERROR, ProfileResolutionException.class)); - for (String cmd : commands) { + // test helps values.add(Arguments.of(new String[] { cmd, "validate", "-h" }, ExitCode.OK, null)); - // TODO: Update when usnistgov/oscal-cli#210 fix merged. - values.add(Arguments.of(new String[] { cmd, "convert", "-h" }, ExitCode.INVALID_COMMAND, null)); + values.add(Arguments.of(new String[] { cmd, "convert", "-h" }, ExitCode.OK, null)); for (Format format : Format.values()) { - path = Paths.get("src/test/resources/cli/example_" + cmd + "_invalid" + format.getDefaultExtension()); - values.add(Arguments.of(new String[] { cmd, "validate", path.toString() }, ExitCode.FAIL, null)); - path = Paths.get("src/test/resources/cli/example_" + cmd + "_valid" + format.getDefaultExtension()); - values.add(Arguments.of(new String[] { cmd, "validate", path.toString() }, ExitCode.OK, null)); - path = Paths.get("src/test/resources/cli/example_profile_valid" + format.getDefaultExtension()); - List targetFormats = formatEntries.get(format); - for (Format targetFormat : targetFormats) { - path = Paths.get("src/test/resources/cli/example_" + cmd + "_valid" + format.getDefaultExtension()); - String outputPath = path.toString().replace(format.getDefaultExtension(), - "_converted" + targetFormat.getDefaultExtension()); - values.add(Arguments.of(new String[] { cmd, "convert", "--to=" + targetFormat.name().toLowerCase(), - path.toString(), outputPath, "--overwrite" }, ExitCode.OK, null)); + String sourceExtension = format.getDefaultExtension(); + values.add( + Arguments.of( + new String[] { + cmd, + "validate", + Paths.get("src/test/resources/cli/example_" + cmd + "_invalid" + sourceExtension).toString() + }, + ExitCode.FAIL, + null)); + values.add( + Arguments.of( + new String[] { + cmd, + "validate", + Paths.get("src/test/resources/cli/example_" + cmd + "_valid" + sourceExtension).toString() + }, + ExitCode.OK, + null)); + + for (Format targetFormat : formatEntries.get(format)) { + Path path = Paths.get("src/test/resources/cli/example_" + cmd + "_valid" + sourceExtension); + values.add( + Arguments.of( + new String[] { + cmd, + "convert", + "--to=" + targetFormat.name().toLowerCase(), + path.toString(), + generateOutputPath(path, targetFormat), + "--overwrite" + }, + ExitCode.OK, + null)); + // TODO: Update when usnistgov/oscal#217 fix merged. - path = Paths.get("src/test/resources/cli/example_" + cmd + "_invalid" + format.getDefaultExtension()); - outputPath = path.toString().replace(format.getDefaultExtension(), - "_converted" + targetFormat.getDefaultExtension()); - values.add(Arguments.of(new String[] { cmd, "convert", "--to=" + targetFormat.name().toLowerCase(), - path.toString(), outputPath, "--overwrite" }, ExitCode.OK, null)); + path = Paths.get("src/test/resources/cli/example_" + cmd + "_invalid" + sourceExtension); + values.add( + Arguments.of( + new String[] { + cmd, + "convert", + "--to=" + targetFormat.name().toLowerCase(), + path.toString(), + generateOutputPath(path, targetFormat), + "--overwrite" + }, + ExitCode.OK, + null)); } if (cmd == "profile") { - path = Paths.get("src/test/resources/cli/example_profile_valid" + format.getDefaultExtension()); - values - .add(Arguments.of(new String[] { cmd, "resolve", "--to=" + format.name().toLowerCase(), path.toString() }, - ExitCode.OK, null)); + values.add( + Arguments.of( + new String[] { + cmd, + "resolve", + "--to=" + format.name().toLowerCase(), + Paths.get("src/test/resources/cli/example_profile_valid" + sourceExtension).toString() + }, + ExitCode.OK, + null)); + values.add( + Arguments.of( + new String[] { + "profile", + "resolve", + "--to=" + format.name().toLowerCase(), + Paths.get("src/test/resources/cli/example_profile_invalid" + sourceExtension).toString() + }, + ExitCode.PROCESSING_ERROR, + ProfileResolutionException.class)); } } } diff --git a/src/test/resources/cli/example_ap_invalid.yml b/src/test/resources/cli/example_ap_invalid.yaml similarity index 100% rename from src/test/resources/cli/example_ap_invalid.yml rename to src/test/resources/cli/example_ap_invalid.yaml diff --git a/src/test/resources/cli/example_ap_valid.yml b/src/test/resources/cli/example_ap_valid.yaml similarity index 100% rename from src/test/resources/cli/example_ap_valid.yml rename to src/test/resources/cli/example_ap_valid.yaml diff --git a/src/test/resources/cli/example_ar_invalid.yml b/src/test/resources/cli/example_ar_invalid.yaml similarity index 100% rename from src/test/resources/cli/example_ar_invalid.yml rename to src/test/resources/cli/example_ar_invalid.yaml diff --git a/src/test/resources/cli/example_ar_valid.yml b/src/test/resources/cli/example_ar_valid.yaml similarity index 100% rename from src/test/resources/cli/example_ar_valid.yml rename to src/test/resources/cli/example_ar_valid.yaml diff --git a/src/test/resources/cli/example_catalog_invalid.yml b/src/test/resources/cli/example_catalog_invalid.yaml similarity index 100% rename from src/test/resources/cli/example_catalog_invalid.yml rename to src/test/resources/cli/example_catalog_invalid.yaml diff --git a/src/test/resources/cli/example_catalog_valid.yml b/src/test/resources/cli/example_catalog_valid.yaml similarity index 100% rename from src/test/resources/cli/example_catalog_valid.yml rename to src/test/resources/cli/example_catalog_valid.yaml diff --git a/src/test/resources/cli/example_component-definition_invalid.yml b/src/test/resources/cli/example_component-definition_invalid.yaml similarity index 100% rename from src/test/resources/cli/example_component-definition_invalid.yml rename to src/test/resources/cli/example_component-definition_invalid.yaml diff --git a/src/test/resources/cli/example_component-definition_valid.yml b/src/test/resources/cli/example_component-definition_valid.yaml similarity index 100% rename from src/test/resources/cli/example_component-definition_valid.yml rename to src/test/resources/cli/example_component-definition_valid.yaml diff --git a/src/test/resources/cli/example_poam_invalid.yml b/src/test/resources/cli/example_poam_invalid.yaml similarity index 100% rename from src/test/resources/cli/example_poam_invalid.yml rename to src/test/resources/cli/example_poam_invalid.yaml diff --git a/src/test/resources/cli/example_poam_valid.yml b/src/test/resources/cli/example_poam_valid.yaml similarity index 100% rename from src/test/resources/cli/example_poam_valid.yml rename to src/test/resources/cli/example_poam_valid.yaml diff --git a/src/test/resources/cli/example_profile_invalid.yml b/src/test/resources/cli/example_profile_invalid.yaml similarity index 100% rename from src/test/resources/cli/example_profile_invalid.yml rename to src/test/resources/cli/example_profile_invalid.yaml diff --git a/src/test/resources/cli/example_profile_valid.yml b/src/test/resources/cli/example_profile_valid.yaml similarity index 100% rename from src/test/resources/cli/example_profile_valid.yml rename to src/test/resources/cli/example_profile_valid.yaml diff --git a/src/test/resources/cli/example_ssp_invalid.yml b/src/test/resources/cli/example_ssp_invalid.yaml similarity index 100% rename from src/test/resources/cli/example_ssp_invalid.yml rename to src/test/resources/cli/example_ssp_invalid.yaml diff --git a/src/test/resources/cli/example_ssp_valid.yml b/src/test/resources/cli/example_ssp_valid.yaml similarity index 100% rename from src/test/resources/cli/example_ssp_valid.yml rename to src/test/resources/cli/example_ssp_valid.yaml