diff --git a/src/cmd/generate/generate.go b/src/cmd/generate/generate.go index 4ef0ebe7..5fb08e35 100644 --- a/src/cmd/generate/generate.go +++ b/src/cmd/generate/generate.go @@ -67,6 +67,12 @@ var generateComponentCmd = &cobra.Command{ var remarks []string var title = "Component Title" + // Check if output file contains a valid OSCAL model + _, err := oscal.ValidOSCALModelAtPath(opts.OutputFile) + if err != nil { + message.Fatalf(err, "Output file %s is not a valid OSCAL model: %v", opts.OutputFile, err) + } + // check for Catalog Source - this field is required if componentOpts.CatalogSource == "" { message.Fatal(fmt.Errorf("no catalog source provided"), "generate component requires a catalog input source") diff --git a/src/cmd/tools/compose.go b/src/cmd/tools/compose.go index 1668ae4b..c1853f63 100644 --- a/src/cmd/tools/compose.go +++ b/src/cmd/tools/compose.go @@ -47,7 +47,13 @@ var composeCmd = &cobra.Command{ outputFile = GetDefaultOutputFile(composeOpts.InputFile) } - err := Compose(composeOpts.InputFile, outputFile) + // Check if output file contains a valid OSCAL model + _, err := oscal.ValidOSCALModelAtPath(outputFile) + if err != nil { + message.Fatalf(err, "Output file %s is not a valid OSCAL model: %v", outputFile, err) + } + + err = Compose(composeOpts.InputFile, outputFile) if err != nil { message.Fatalf(err, "Composition error: %s", err) } diff --git a/src/cmd/validate/validate.go b/src/cmd/validate/validate.go index 7ca481e9..8d05927d 100644 --- a/src/cmd/validate/validate.go +++ b/src/cmd/validate/validate.go @@ -52,6 +52,12 @@ var validateCmd = &cobra.Command{ outputFile = getDefaultOutputFile(opts.InputFile) } + // Check if output file contains a valid OSCAL model + _, err := oscal.ValidOSCALModelAtPath(outputFile) + if err != nil { + message.Fatalf(err, "Output file %s is not a valid OSCAL model: %v", outputFile, err) + } + if SaveResources { ResourcesDir = filepath.Join(filepath.Dir(outputFile)) } @@ -261,7 +267,7 @@ func ValidateOnControlImplementations(controlImplementations *[]oscalTypes_1_1_2 return findings, observations, nil } -// GetDefaultOutputFile returns the default output file name +// getDefaultOutputFile returns the default output file name and checks if the file already exists func getDefaultOutputFile(inputFile string) string { dirPath := filepath.Dir(inputFile) filename := "assessment-results" + filepath.Ext(inputFile) diff --git a/src/pkg/common/oscal/complete-schema.go b/src/pkg/common/oscal/complete-schema.go index 0d768f62..792e0d37 100644 --- a/src/pkg/common/oscal/complete-schema.go +++ b/src/pkg/common/oscal/complete-schema.go @@ -52,16 +52,16 @@ func WriteOscalModel(filePath string, model *oscalTypes_1_1_2.OscalModels) error // If the file exists - read the data into the model existingFileBytes, err := os.ReadFile(filePath) if err != nil { - return err + return fmt.Errorf("error reading file: %v", err) } existingModel, err := NewOscalModel(existingFileBytes) if err != nil { - return err + return fmt.Errorf("error getting existing model: %v", err) } existingModelType, err := GetOscalModel(existingModel) if err != nil { - return nil + return fmt.Errorf("error getting existing model type: %v", err) } if existingModelType != modelType { @@ -224,6 +224,27 @@ func GetOscalModel(model *oscalTypes_1_1_2.OscalModels) (modelType string, err e } +// ValidOSCALModelAtPath takes a path and returns a bool indicating if the model exists/is valid +// bool = T/F that oscal model exists, error = if not nil OSCAL model is invalid +func ValidOSCALModelAtPath(path string) (bool, error) { + _, err := os.Stat(path) + if err != nil { + return false, nil + } + + data, err := os.ReadFile(path) + if err != nil { + return true, err + } + + _, err = NewOscalModel(data) + if err != nil { + return true, err + } + + return true, nil +} + // InjectIntoOSCALModel takes a model target and a map[string]interface{} of values to inject into the model func InjectIntoOSCALModel(target *oscalTypes_1_1_2.OscalModels, values map[string]interface{}, path string) (*oscalTypes_1_1_2.OscalModels, error) { // If the target is nil, return an error