Skip to content

Commit 9ca7763

Browse files
authored
Merge pull request #3025 from joejstuart/EC-1535
Refine validate vsa output
2 parents 8e97e70 + 99367a0 commit 9ca7763

File tree

12 files changed

+3558
-1057
lines changed

12 files changed

+3558
-1057
lines changed

cmd/validate/image.go

Lines changed: 33 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import (
2222
"errors"
2323
"fmt"
2424
"runtime/trace"
25-
"sort"
2625
"strings"
2726
"time"
2827

@@ -36,7 +35,6 @@ import (
3635

3736
"github.com/conforma/cli/internal/applicationsnapshot"
3837
"github.com/conforma/cli/internal/evaluator"
39-
"github.com/conforma/cli/internal/format"
4038
"github.com/conforma/cli/internal/image"
4139
"github.com/conforma/cli/internal/output"
4240
"github.com/conforma/cli/internal/policy"
@@ -321,12 +319,6 @@ func validateImageCmd(validate imageValidationFunc) *cobra.Command {
321319
defer task.End()
322320
}
323321

324-
type result struct {
325-
err error
326-
component applicationsnapshot.Component
327-
policyInput []byte
328-
}
329-
330322
appComponents := data.spec.Components
331323
evaluators := []evaluator.Evaluator{}
332324

@@ -364,7 +356,7 @@ func validateImageCmd(validate imageValidationFunc) *cobra.Command {
364356

365357
// worker is responsible for processing one component at a time from the jobs channel,
366358
// and for emitting a corresponding result for the component on the results channel.
367-
worker := func(id int, jobs <-chan app.SnapshotComponent, results chan<- result) {
359+
worker := func(id int, jobs <-chan app.SnapshotComponent, results chan<- validate_utils.Result) {
368360
log.Debugf("Starting worker %d", id)
369361
for comp := range jobs {
370362
ctx := cmd.Context()
@@ -391,46 +383,11 @@ func validateImageCmd(validate imageValidationFunc) *cobra.Command {
391383
// Use original validation when VSA checking is disabled
392384
out, err = validate(ctx, comp, data.spec, data.policy, evaluators, data.info)
393385
}
394-
res := result{
395-
err: err,
396-
component: applicationsnapshot.Component{
397-
SnapshotComponent: comp,
398-
Success: err == nil,
399-
},
400-
}
401-
402-
// Skip on err to not panic. Error is return on routine completion.
403-
if err == nil {
404-
if out != nil {
405-
// Normal validation completed
406-
res.component.Violations = out.Violations()
407-
res.component.Warnings = out.Warnings()
408-
409-
successes := out.Successes()
410-
res.component.SuccessCount = len(successes)
411-
if showSuccesses {
412-
res.component.Successes = successes
413-
}
414-
415-
res.component.Signatures = out.Signatures
416-
// Create a new result object for attestations. The point is to only keep the data that's needed.
417-
// For example, the Statement is only needed when the full attestation is printed.
418-
for _, att := range out.Attestations {
419-
attResult := applicationsnapshot.NewAttestationResult(att)
420-
if containsOutput(data.output, "attestation") {
421-
attResult.Statement = att.Statement()
422-
}
423-
res.component.Attestations = append(res.component.Attestations, attResult)
424-
}
425-
res.component.ContainerImage = out.ImageURL
426-
res.policyInput = out.PolicyInput
427-
} else {
428-
// Validation was skipped due to valid VSA - no violations, no processing needed
429-
log.Debugf("Validation skipped for %s due to valid VSA", comp.ContainerImage)
430-
res.component.ContainerImage = comp.ContainerImage
431-
}
386+
res := validate_utils.PopulateResultFromOutput(out, err, comp, showSuccesses, data.output)
387+
if err == nil && out == nil {
388+
// Validation was skipped due to valid VSA - no violations, no processing needed
389+
log.Debugf("Validation skipped for %s due to valid VSA", comp.ContainerImage)
432390
}
433-
res.component.Success = err == nil && len(res.component.Violations) == 0
434391

435392
if task != nil {
436393
task.End()
@@ -446,7 +403,7 @@ func validateImageCmd(validate imageValidationFunc) *cobra.Command {
446403
numWorkers := data.workers
447404

448405
jobs := make(chan app.SnapshotComponent, numComponents)
449-
results := make(chan result, numComponents)
406+
results := make(chan validate_utils.Result, numComponents)
450407
// Initialize each worker. They will wait patiently until a job is sent to the jobs
451408
// channel, or the jobs channel is closed.
452409
for i := 0; i <= numWorkers; i++ {
@@ -459,40 +416,43 @@ func validateImageCmd(validate imageValidationFunc) *cobra.Command {
459416
}
460417
close(jobs)
461418

462-
var components []applicationsnapshot.Component
463-
var manyPolicyInput [][]byte
464-
var allErrors error = nil
419+
// Collect all results from the channel
420+
var allResults []validate_utils.Result
465421
for i := 0; i < numComponents; i++ {
466-
r := <-results
467-
if r.err != nil {
468-
e := fmt.Errorf("error validating image %s of component %s: %w", r.component.ContainerImage, r.component.Name, r.err)
469-
allErrors = errors.Join(allErrors, e)
470-
} else {
471-
components = append(components, r.component)
472-
manyPolicyInput = append(manyPolicyInput, r.policyInput)
473-
}
422+
allResults = append(allResults, <-results)
474423
}
475424
close(results)
476-
if allErrors != nil {
477-
return allErrors
478-
}
479425

480-
// Ensure some consistency in output.
481-
sort.Slice(components, func(i, j int) bool {
482-
return components[i].ContainerImage > components[j].ContainerImage
483-
})
426+
components, manyPolicyInput, err := validate_utils.CollectComponentResults(
427+
allResults,
428+
func(r validate_utils.Result) error {
429+
return fmt.Errorf("error validating image %s of component %s: %w", r.Component.ContainerImage, r.Component.Name, r.Err)
430+
},
431+
)
432+
if err != nil {
433+
return err
434+
}
484435

485436
if len(data.outputFile) > 0 {
486437
data.output = append(data.output, fmt.Sprintf("%s=%s", applicationsnapshot.JSON, data.outputFile))
487438
}
488439

489-
report, err := applicationsnapshot.NewReport(data.snapshot, components, data.policy, manyPolicyInput, showSuccesses, showWarnings, data.expansion)
490-
if err != nil {
491-
return err
440+
reportData := validate_utils.ReportData{
441+
Snapshot: data.snapshot,
442+
Components: components,
443+
Policy: data.policy,
444+
PolicyInputs: manyPolicyInput,
445+
Expansion: data.expansion,
446+
ShowSuccesses: showSuccesses,
447+
ShowWarnings: showWarnings,
492448
}
493-
p := format.NewTargetParser(applicationsnapshot.JSON, format.Options{ShowSuccesses: showSuccesses, ShowWarnings: showWarnings}, cmd.OutOrStdout(), utils.FS(cmd.Context()))
494-
utils.SetColorEnabled(data.noColor, data.forceColor)
495-
if err := report.WriteAll(data.output, p); err != nil {
449+
outputOpts := validate_utils.ReportOutputOptions{
450+
Output: data.output,
451+
NoColor: data.noColor,
452+
ForceColor: data.forceColor,
453+
}
454+
report, err := validate_utils.WriteReport(reportData, outputOpts, cmd)
455+
if err != nil {
496456
return err
497457
}
498458

@@ -684,12 +644,3 @@ func validateImageCmd(validate imageValidationFunc) *cobra.Command {
684644
}
685645

686646
// find if the slice contains "value" output
687-
func containsOutput(data []string, value string) bool {
688-
for _, item := range data {
689-
newItem := strings.Split(item, "=")
690-
if newItem[0] == value {
691-
return true
692-
}
693-
}
694-
return false
695-
}

cmd/validate/image_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ import (
5252
"github.com/conforma/cli/internal/utils"
5353
"github.com/conforma/cli/internal/utils/oci"
5454
"github.com/conforma/cli/internal/utils/oci/fake"
55+
validate_utils "github.com/conforma/cli/internal/validate"
5556
"github.com/conforma/cli/internal/validate/vsa"
5657
)
5758

@@ -1399,7 +1400,7 @@ func TestContainsData(t *testing.T) {
13991400
}
14001401

14011402
for _, test := range tests {
1402-
result := containsOutput(test.input, "data")
1403+
result := validate_utils.ContainsOutputFormat(test.input, "data")
14031404
assert.Equal(t, test.expected, result, test.name)
14041405
}
14051406
}
@@ -1422,7 +1423,7 @@ func TestContainsAttestation(t *testing.T) {
14221423
}
14231424

14241425
for _, test := range tests {
1425-
result := containsOutput(test.input, "attestation")
1426+
result := validate_utils.ContainsOutputFormat(test.input, "attestation")
14261427
assert.Equal(t, test.expected, result, test.name)
14271428
}
14281429
}

0 commit comments

Comments
 (0)