Skip to content

Commit

Permalink
feat(tools): add looping for lint (#481)
Browse files Browse the repository at this point in the history
* feat: add looping for lint

* updated to handle errors without exiting.

* added conditional for success/fail

* need a wrapper in go-oscal but should work

* feat(validate)!: #408 create resources in kubernetes domain (#415)

* refactor!(common): #388 update common/types (and all references) to use pointers

* refactor!(common): #388 update Domain struct to use pointers

* refactor!(common): #388 update Provider struct to use pointers

* refactor!(evaluate): #388 EvaluateResults now uses pointers
refactor!(component): change NewOscalComponentDefinitionFromBytes to return a pointer

* refactor!(resource-store): #388 changed AddFromLink params to use pointers, updated references

* refactor!(assessment-results): #388 NewAssessmentResults now returns a pointer

* refactor!(catalog): now runs validation rather than requiring the source for the extension

refactor!(catalog): now uses pointers

* refactor!(component): #388 NewOscalComponentDefinition no longer uses source in favor of oscal validation
refactor!(component): delete the NewOscalComponentDefinitionFromBytes method in favor of NewOscalComponentDefinition
refactor!(common): rename WriteFile -> WriteOscalModel
refactor(generate): WriteFile -> WriteOscalModel
refactor(composition): removed validation logic in favor of NewOscalCOmponentDefinition handling it
feat(common): WriteOscalModel now handles json file extensions
feat(evaluate): now runs file extension validation for json/yaml
feat(validate): now checks input file for extension
tests: update tests, update test data to pass oscal validation

* refactor!(common): #388 moved WriteOscalModel to the oscal package (complete-schema)

* feat(oscal): create the multiModelValidate method for use in oscal constructors and updated all relavant constructors

* refactor!(component): #388 update mergeComponents and ComponentFromCatalog to use pointers
refactor(generate): update all refs to ComponentFromCatalog

* initial resource creation

* refactor(component): pointer refactor

* fix(component): failing e2e

* refactor(component): ControlToImplementRequirement now takes pointer to control

* fix(common): add omitempty to the marshalling for Validation

* refactor!(domains/kubernetes): #388 KubernetesSpec.Wait and Resource.ResourceRule are now pointers and have omitempty, updated all references

* refactor!(domains/kubernetes): #388 ResourceRule.Field is now a pointer and has omitempty tag

* refactor!(providers/kyverno): #388 KyvernoSpec is now a pointer

* refactor!(providers/opa): #388 OpaSpec is now a pointer

* refactor(providers): add omitempty to Kyverno and opa spec tags

* refactor!(providers): update output fields to be pointers

* refactor!(domains): update api and k8s domain specs to be pointers

* refactor!(types): #388 update LulaValidation provider, domain, domain-resources and result to use pointers

* fix(evaluate): add nil check on thresholdResult and newResult to top of method to prevent nil pointer

* chore(validate): add TODO to remove WriteReport as it is unused (question)

* fix: graceful exit conditions, empty result pointer

* feat: merged pointers

* feat: updated error handling, initial docs and flag functions

* feat: added flags to lula validate

* feat: added requirement-store, updated validation

* feat(validate): updated validation refactor, other small fixes

* feat: added tests, dev command updates

* fix(dev): updated tests, fixed dev cmd issues

* fix: refactor yaml multi doc functionality

* fix: get-resources read from stdin

* fix: remove debug file

* fix: clean-up per comments

* Update src/pkg/message/interactive.go

clarifying confirmation text

Co-authored-by: Brandt Keller <[email protected]>

* docs: description of assessments and failure conditions

* feat(validate): non-interactive flag added

* fix(dev): get-resources missing validation opt

* fix: clean-up create resources

* add staticResources check before execution

* fix: updated create observation fcn and usage

---------

Co-authored-by: Cole (Mike) Winberry <[email protected]>
Co-authored-by: Cole (Mike) Winberry <[email protected]>
Co-authored-by: Brandt Keller <[email protected]>

* chore(deps): update module github.com/spf13/cobra to v1.8.1 (#485)

| datasource | package                | from   | to     |
| ---------- | ---------------------- | ------ | ------ |
| go         | github.com/spf13/cobra | v1.8.0 | v1.8.1 |

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* chore(deps): update googleapis/release-please-action digest to 7987652 (#472)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* chore(deps): update github/codeql-action action to v3.25.10 (#476)

| datasource  | package              | from    | to       |
| ----------- | -------------------- | ------- | -------- |
| github-tags | github/codeql-action | v3.25.8 | v3.25.10 |

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* chore: fix documentation links (#487)

* chore(docs): cleanup unused readme conflicting in docs build (#489)

* chore(deps): update module github.com/defenseunicorns/go-oscal to v0.4.3 (#470)

| datasource | package                             | from   | to     |
| ---------- | ----------------------------------- | ------ | ------ |
| go         | github.com/defenseunicorns/go-oscal | v0.4.1 | v0.4.3 |

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* chore(deps): update actions/checkout action to v4.1.7 (#479)

| datasource  | package          | from   | to     |
| ----------- | ---------------- | ------ | ------ |
| github-tags | actions/checkout | v4.1.6 | v4.1.7 |

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* chore(deps): update module github.com/defenseunicorns/go-oscal to v0.5.0 (#492)

* chore(deps): update module github.com/defenseunicorns/go-oscal to v0.5.0

| datasource | package                             | from   | to     |
| ---------- | ----------------------------------- | ------ | ------ |
| go         | github.com/defenseunicorns/go-oscal | v0.4.3 | v0.5.0 |

* chore(lint): update lint with new go-oscal ValidationCommand changes

* chore(tests): update pod_validation_test with new usage of ValidationCommand

* chore(tests): update e2e pod_validation_test to use JsonSchemaError for validation failures

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Cole (Mike) Winberry <[email protected]>

* added conditional for success/fail

* need a wrapper in go-oscal but should work

* updating loop

* fixing local branch

* fixed my loop logic

* fix(lint): lint now waits until exiting the loop to write to file and now handles multiple validation results

* fix(tools): lint command properly handles attempting all validations prior to deciding exit state, still bails on non-validation errors as they happen

* fix(tools): lint fatal error message validation -> linting

* fix(tools): lint messaging updated with linting where it makes sense

---------

Co-authored-by: Megan Wolf <[email protected]>
Co-authored-by: Cole (Mike) Winberry <[email protected]>
Co-authored-by: Cole (Mike) Winberry <[email protected]>
Co-authored-by: Brandt Keller <[email protected]>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Bryan Finster <[email protected]>
  • Loading branch information
7 people authored Jun 28, 2024
1 parent 7692e33 commit 0d69a45
Showing 1 changed file with 60 additions and 25 deletions.
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")
}

0 comments on commit 0d69a45

Please sign in to comment.