Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add looping for lint #481

Merged
merged 27 commits into from
Jun 28, 2024
Merged
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
301ad98
feat: add looping for lint
CloudBeard Jun 13, 2024
89674b8
Merge branch 'main' into 480-feat-add-lint--loop
CloudBeard Jun 14, 2024
17e26da
updated to handle errors without exiting.
CloudBeard Jun 14, 2024
cdabadf
added conditional for success/fail
CloudBeard Jun 17, 2024
bb0be3f
need a wrapper in go-oscal but should work
CloudBeard Jun 17, 2024
31e1e8c
feat(validate)!: #408 create resources in kubernetes domain (#415)
meganwolf0 Jun 17, 2024
34927e8
chore(deps): update module github.com/spf13/cobra to v1.8.1 (#485)
renovate[bot] Jun 17, 2024
800792f
chore(deps): update googleapis/release-please-action digest to 798765…
renovate[bot] Jun 17, 2024
d38a531
chore(deps): update github/codeql-action action to v3.25.10 (#476)
renovate[bot] Jun 17, 2024
34163e6
chore: fix documentation links (#487)
bdfinst Jun 17, 2024
a7901de
chore(docs): cleanup unused readme conflicting in docs build (#489)
brandtkeller Jun 18, 2024
7720aab
chore(deps): update module github.com/defenseunicorns/go-oscal to v0.…
renovate[bot] Jun 18, 2024
7319b6c
chore(deps): update actions/checkout action to v4.1.7 (#479)
renovate[bot] Jun 18, 2024
425cf8b
chore(deps): update module github.com/defenseunicorns/go-oscal to v0.…
renovate[bot] Jun 20, 2024
ce166f8
added conditional for success/fail
CloudBeard Jun 17, 2024
94f969b
need a wrapper in go-oscal but should work
CloudBeard Jun 17, 2024
32243e9
updating loop
CloudBeard Jun 24, 2024
f54b463
fixing local branch
CloudBeard Jun 24, 2024
e1c9067
fixed my loop logic
CloudBeard Jun 25, 2024
7ed198f
Merge branch 'main' into 480-feat-add-lint--loop
CloudBeard Jun 25, 2024
8b9e420
fix(lint): lint now waits until exiting the loop to write to file and…
Jun 27, 2024
7753094
fix(tools): lint command properly handles attempting all validations …
Jun 27, 2024
109ae6a
fix(tools): lint fatal error message validation -> linting
Jun 27, 2024
13417f4
fix(tools): lint messaging updated with linting where it makes sense
Jun 27, 2024
b80d607
Merge pull request #504 from defenseunicorns/cole-noodle
CloudBeard Jun 27, 2024
a4b821a
Merge branch 'main' into 480-feat-add-lint--loop
CloudBeard Jun 27, 2024
0546f24
Merge branch 'main' into 480-feat-add-lint--loop
brandtkeller Jun 28, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 60 additions & 25 deletions src/cmd/tools/lint.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package tools

import (
"encoding/json"
"fmt"
"strings"

"github.com/defenseunicorns/go-oscal/src/pkg/validation"
"github.com/defenseunicorns/lula/src/config"
Expand All @@ -10,15 +12,15 @@ import (
)

type flags struct {
InputFile string // -f --input-file
ResultFile string // -r --result-file
InputFiles []string // -f --input-files
ResultFile string // -r --result-file
}

var opts = &flags{}

var lintHelp = `
To lint an existing OSCAL file:
lula tools lint -f <path to oscal>
To lint existing OSCAL files:
lula tools lint -f <path1>,<path2>,<path3>
`

func init() {
Expand All @@ -28,42 +30,75 @@ func init() {
PersistentPreRun: func(cmd *cobra.Command, args []string) {
config.SkipLogFile = true
},
Long: "Validate an OSCAL document is properly configured against the OSCAL schema",
Long: "Validate OSCAL documents are properly configured against the OSCAL schema",
Example: lintHelp,
Run: func(cmd *cobra.Command, args []string) {
spinner := message.NewProgressSpinner("Linting %s", opts.InputFile)
defer spinner.Stop()

validationResp, err := validation.ValidationCommand(opts.InputFile)
// fatal for non-validation errors
if err != nil {
message.Fatalf(err, "Failed to lint %s: %s", opts.InputFile, err)
var validationResults []validation.ValidationResult
if len(opts.InputFiles) == 0 {
message.Fatalf(nil, "No input files specified")
}

for _, warning := range validationResp.Warnings {
message.Warn(warning)
for _, inputFile := range opts.InputFiles {
spinner := message.NewProgressSpinner("Linting %s", inputFile)
defer spinner.Stop()

validationResp, err := validation.ValidationCommand(inputFile)
// fatal for non-validation errors
if err != nil {
message.Fatalf(err, "Failed to lint %s: %s", inputFile, err)
}

for _, warning := range validationResp.Warnings {
message.Warn(warning)
}

// append the validation result to the results array
validationResults = append(validationResults, validationResp.Result)

// If result file is not specified, print the validation result
if opts.ResultFile == "" {
jsonBytes, err := json.MarshalIndent(validationResp.Result, "", " ")
if err != nil {
message.Fatalf(err, "Failed to marshal validation result")
}
message.Infof("Validation result for %s: %s", inputFile, string(jsonBytes))
}
// New conditional for logging success or failed linting
if validationResp.Result.Valid {
message.Infof("Successfully validated %s is valid OSCAL version %s %s\n", inputFile, validationResp.Validator.GetSchemaVersion(), validationResp.Validator.GetModelType())
spinner.Success()
} else {
message.WarnErrf(nil, "Failed to lint %s", inputFile)
spinner.Stop()
}
}

// If result file is specified, write the validation results to the file
if opts.ResultFile != "" {
validation.WriteValidationResult(validationResp.Result, opts.ResultFile)
} else {
jsonBytes, err := json.MarshalIndent(validationResp.Result, "", " ")
if err != nil {
message.Fatalf(err, "Failed to marshal validation result")
// If there is only one validation result, write it to the file
if len(validationResults) == 1 {
validation.WriteValidationResult(validationResults[0], opts.ResultFile)
} else {
// If there are multiple validation results, write them to the file
validation.WriteValidationResults(validationResults, opts.ResultFile)
}
message.Infof("Validation result: %s", string(jsonBytes))
}

if validationResp.JsonSchemaError != nil {
message.Fatalf(err, "Failed to lint %s", opts.InputFile)
// If there is at least one validation result that is not valid, exit with a fatal error
failedFiles := []string{}
for _, result := range validationResults {
if !result.Valid {
failedFiles = append(failedFiles, result.Metadata.DocumentPath)
}
}
if len(failedFiles) > 0 {
message.Fatal(nil, fmt.Sprintf("The following files failed linting: %s", strings.Join(failedFiles, ", ")))
}
message.Infof("Successfully validated %s is valid OSCAL version %s %s\n", opts.InputFile, validationResp.Validator.GetSchemaVersion(), validationResp.Validator.GetModelType())
spinner.Success()
},
}

toolsCmd.AddCommand(lintCmd)

lintCmd.Flags().StringVarP(&opts.InputFile, "input-file", "f", "", "the path to a oscal json schema file")
lintCmd.Flags().StringSliceVarP(&opts.InputFiles, "input-files", "f", []string{}, "the paths to oscal json schema files (comma-separated)")
lintCmd.Flags().StringVarP(&opts.ResultFile, "result-file", "r", "", "the path to write the validation result")
}