Skip to content

Commit

Permalink
Provide all components as input to policy check
Browse files Browse the repository at this point in the history
ec-cli spawns workers with individual components of the input
to perform policy check. This commit adds all input components
when performing the policy check as an additional parameter. So
each worker has access to all input components during policy check

resolves: CVP-4191

Signed-off-by: Yashvardhan Nanavati <[email protected]>
  • Loading branch information
yashvardhannanavati committed Jul 3, 2024
1 parent 4c80081 commit 1270117
Show file tree
Hide file tree
Showing 8 changed files with 143 additions and 28 deletions.
9 changes: 5 additions & 4 deletions cmd/validate/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ import (
validate_utils "github.com/enterprise-contract/ec-cli/internal/validate"
)

type imageValidationFunc func(context.Context, app.SnapshotComponent, policy.Policy, []evaluator.Evaluator, bool) (*output.Output, error)
type imageValidationFunc func(context.Context, app.SnapshotComponent, policy.Policy, []evaluator.Evaluator, bool, []app.SnapshotComponent) (*output.Output, error)

var newConftestEvaluator = evaluator.NewConftestEvaluator

Expand Down Expand Up @@ -315,12 +315,13 @@ func validateImageCmd(validate imageValidationFunc) *cobra.Command {

// worker is responsible for processing one component at a time from the jobs channel,
// and for emitting a corresponding result for the component on the results channel.
worker := func(id int, jobs <-chan app.SnapshotComponent, results chan<- result) {
worker := func(id int, jobs <-chan app.SnapshotComponent, results chan<- result, appComponents []app.SnapshotComponent) {
log.Debugf("Starting worker %d", id)
for comp := range jobs {
log.Debugf("Worker %d got a component %q", id, comp.ContainerImage)
ctx := cmd.Context()
out, err := validate(ctx, comp, data.policy, evaluators, data.info)
log.Debugf("Worker %d got appComponents %v", id, appComponents)
out, err := validate(ctx, comp, data.policy, evaluators, data.info, appComponents)
res := result{
err: err,
component: applicationsnapshot.Component{
Expand Down Expand Up @@ -365,7 +366,7 @@ func validateImageCmd(validate imageValidationFunc) *cobra.Command {
// Initialize each worker. They will wait patiently until a job is sent to the jobs
// channel, or the jobs channel is closed.
for i := 0; i <= numWorkers; i++ {
go worker(i, jobs, results)
go worker(i, jobs, results, appComponents)
}
// Initialize all the jobs. Each worker will pick a job from the channel when the worker
// is ready to consume a new job.
Expand Down
2 changes: 1 addition & 1 deletion cmd/validate/image_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ func TestEvaluatorLifecycle(t *testing.T) {
newConftestEvaluator = evaluator.NewConftestEvaluator
})

validate := func(_ context.Context, component app.SnapshotComponent, _ policy.Policy, evaluators []evaluator.Evaluator, _ bool) (*output.Output, error) {
validate := func(_ context.Context, component app.SnapshotComponent, _ policy.Policy, evaluators []evaluator.Evaluator, _ bool, _ []app.SnapshotComponent) (*output.Output, error) {
for _, e := range evaluators {
_, _, err := e.Evaluate(ctx, []string{})
require.NoError(t, err)
Expand Down
28 changes: 14 additions & 14 deletions cmd/validate/image_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ func Test_determineInputSpec(t *testing.T) {
}

func Test_ValidateImageCommand(t *testing.T) {
validate := func(_ context.Context, component app.SnapshotComponent, _ policy.Policy, _ []evaluator.Evaluator, _ bool) (*output.Output, error) {
validate := func(_ context.Context, component app.SnapshotComponent, _ policy.Policy, _ []evaluator.Evaluator, _ bool, _ []app.SnapshotComponent) (*output.Output, error) {
return &output.Output{
ImageSignatureCheck: output.VerificationStatus{
Passed: true,
Expand Down Expand Up @@ -336,7 +336,7 @@ func Test_ValidateImageCommand(t *testing.T) {
}

func Test_ValidateImageCommandImages(t *testing.T) {
validate := func(_ context.Context, component app.SnapshotComponent, _ policy.Policy, _ []evaluator.Evaluator, _ bool) (*output.Output, error) {
validate := func(_ context.Context, component app.SnapshotComponent, _ policy.Policy, _ []evaluator.Evaluator, _ bool, _ []app.SnapshotComponent) (*output.Output, error) {
return &output.Output{
ImageSignatureCheck: output.VerificationStatus{
Passed: true,
Expand Down Expand Up @@ -458,7 +458,7 @@ func Test_ValidateImageCommandImages(t *testing.T) {

func Test_ValidateImageCommandKeyless(t *testing.T) {
called := false
validateImageCmd := validateImageCmd(func(_ context.Context, _ app.SnapshotComponent, p policy.Policy, _ []evaluator.Evaluator, _ bool) (*output.Output, error) {
validateImageCmd := validateImageCmd(func(_ context.Context, _ app.SnapshotComponent, p policy.Policy, _ []evaluator.Evaluator, _ bool, _ []app.SnapshotComponent) (*output.Output, error) {
assert.Equal(t, cosign.Identity{
Issuer: "my-certificate-oidc-issuer",
Subject: "my-certificate-identity",
Expand Down Expand Up @@ -503,7 +503,7 @@ func Test_ValidateImageCommandKeyless(t *testing.T) {
}

func Test_ValidateImageCommandYAMLPolicyFile(t *testing.T) {
validate := func(_ context.Context, component app.SnapshotComponent, _ policy.Policy, _ []evaluator.Evaluator, _ bool) (*output.Output, error) {
validate := func(_ context.Context, component app.SnapshotComponent, _ policy.Policy, _ []evaluator.Evaluator, _ bool, _ []app.SnapshotComponent) (*output.Output, error) {
return &output.Output{
ImageSignatureCheck: output.VerificationStatus{
Passed: true,
Expand Down Expand Up @@ -621,7 +621,7 @@ spec:
}

func Test_ValidateImageCommandJSONPolicyFile(t *testing.T) {
validate := func(_ context.Context, component app.SnapshotComponent, _ policy.Policy, _ []evaluator.Evaluator, _ bool) (*output.Output, error) {
validate := func(_ context.Context, component app.SnapshotComponent, _ policy.Policy, _ []evaluator.Evaluator, _ bool, _ []app.SnapshotComponent) (*output.Output, error) {
return &output.Output{
ImageSignatureCheck: output.VerificationStatus{
Passed: true,
Expand Down Expand Up @@ -700,7 +700,7 @@ configuration:
}

func Test_ValidateImageCommandExtraData(t *testing.T) {
validate := func(_ context.Context, component app.SnapshotComponent, _ policy.Policy, _ []evaluator.Evaluator, _ bool) (*output.Output, error) {
validate := func(_ context.Context, component app.SnapshotComponent, _ policy.Policy, _ []evaluator.Evaluator, _ bool, _ []app.SnapshotComponent) (*output.Output, error) {
return &output.Output{
ImageSignatureCheck: output.VerificationStatus{
Passed: true,
Expand Down Expand Up @@ -825,7 +825,7 @@ spec:
}

func Test_ValidateImageCommandEmptyPolicyFile(t *testing.T) {
validate := func(_ context.Context, component app.SnapshotComponent, _ policy.Policy, _ []evaluator.Evaluator, _ bool) (*output.Output, error) {
validate := func(_ context.Context, component app.SnapshotComponent, _ policy.Policy, _ []evaluator.Evaluator, _ bool, _ []app.SnapshotComponent) (*output.Output, error) {
return &output.Output{
ImageSignatureCheck: output.VerificationStatus{
Passed: true,
Expand Down Expand Up @@ -893,7 +893,7 @@ func Test_ValidateImageCommandEmptyPolicyFile(t *testing.T) {

func Test_ValidateImageErrorLog(t *testing.T) {
// TODO: Enhance this test to cover other Error Log messages
validate := func(_ context.Context, component app.SnapshotComponent, _ policy.Policy, _ []evaluator.Evaluator, _ bool) (*output.Output, error) {
validate := func(_ context.Context, component app.SnapshotComponent, _ policy.Policy, _ []evaluator.Evaluator, _ bool, _ []app.SnapshotComponent) (*output.Output, error) {
return &output.Output{
ImageSignatureCheck: output.VerificationStatus{
Passed: true,
Expand Down Expand Up @@ -1057,7 +1057,7 @@ func Test_ValidateErrorCommand(t *testing.T) {
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
validate := func(context.Context, app.SnapshotComponent, policy.Policy, []evaluator.Evaluator, bool) (*output.Output, error) {
validate := func(context.Context, app.SnapshotComponent, policy.Policy, []evaluator.Evaluator, bool, []app.SnapshotComponent) (*output.Output, error) {
return nil, errors.New("expected")
}

Expand Down Expand Up @@ -1087,7 +1087,7 @@ func Test_ValidateErrorCommand(t *testing.T) {
}

func Test_FailureImageAccessibility(t *testing.T) {
validate := func(_ context.Context, component app.SnapshotComponent, _ policy.Policy, _ []evaluator.Evaluator, _ bool) (*output.Output, error) {
validate := func(_ context.Context, component app.SnapshotComponent, _ policy.Policy, _ []evaluator.Evaluator, _ bool, _ []app.SnapshotComponent) (*output.Output, error) {
return &output.Output{
ImageSignatureCheck: output.VerificationStatus{
Passed: false,
Expand Down Expand Up @@ -1158,7 +1158,7 @@ func Test_FailureImageAccessibility(t *testing.T) {
}

func Test_FailureOutput(t *testing.T) {
validate := func(_ context.Context, component app.SnapshotComponent, _ policy.Policy, _ []evaluator.Evaluator, _ bool) (*output.Output, error) {
validate := func(_ context.Context, component app.SnapshotComponent, _ policy.Policy, _ []evaluator.Evaluator, _ bool, _ []app.SnapshotComponent) (*output.Output, error) {
return &output.Output{
ImageSignatureCheck: output.VerificationStatus{
Passed: false,
Expand Down Expand Up @@ -1227,7 +1227,7 @@ func Test_FailureOutput(t *testing.T) {
}

func Test_WarningOutput(t *testing.T) {
validate := func(_ context.Context, component app.SnapshotComponent, _ policy.Policy, _ []evaluator.Evaluator, _ bool) (*output.Output, error) {
validate := func(_ context.Context, component app.SnapshotComponent, _ policy.Policy, _ []evaluator.Evaluator, _ bool, _ []app.SnapshotComponent) (*output.Output, error) {
return &output.Output{
ImageSignatureCheck: output.VerificationStatus{
Passed: true,
Expand Down Expand Up @@ -1301,7 +1301,7 @@ func Test_WarningOutput(t *testing.T) {
}

func Test_FailureImageAccessibilityNonStrict(t *testing.T) {
validate := func(_ context.Context, component app.SnapshotComponent, _ policy.Policy, _ []evaluator.Evaluator, _ bool) (*output.Output, error) {
validate := func(_ context.Context, component app.SnapshotComponent, _ policy.Policy, _ []evaluator.Evaluator, _ bool, _ []app.SnapshotComponent) (*output.Output, error) {
return &output.Output{
ImageSignatureCheck: output.VerificationStatus{
Passed: true,
Expand Down Expand Up @@ -1369,7 +1369,7 @@ func Test_FailureImageAccessibilityNonStrict(t *testing.T) {
}

func TestValidateImageCommand_RunE(t *testing.T) {
validate := func(_ context.Context, component app.SnapshotComponent, _ policy.Policy, _ []evaluator.Evaluator, _ bool) (*output.Output, error) {
validate := func(_ context.Context, component app.SnapshotComponent, _ policy.Policy, _ []evaluator.Evaluator, _ bool, _ []app.SnapshotComponent) (*output.Output, error) {
return &output.Output{
ImageSignatureCheck: output.VerificationStatus{
Passed: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,18 @@

[TestWriteInputFile/single_attestations - 1]
{
"allcomponents": [
{
"containerImage": "registry.io/repository/image:tag",
"name": "",
"source": {}
},
{
"containerImage": "registry.io/other-repository/image2:tag",
"name": "",
"source": {}
}
],
"attestations": [
{
"statement": {
Expand Down Expand Up @@ -40,6 +52,18 @@

[TestWriteInputFile/multiple_attestations - 1]
{
"allcomponents": [
{
"containerImage": "registry.io/repository/image:tag",
"name": "",
"source": {}
},
{
"containerImage": "registry.io/other-repository/image2:tag",
"name": "",
"source": {}
}
],
"attestations": [
{
"statement": {
Expand Down Expand Up @@ -83,6 +107,18 @@

[TestWriteInputFile/image_signatures - 1]
{
"allcomponents": [
{
"containerImage": "registry.io/repository/image:tag",
"name": "",
"source": {}
},
{
"containerImage": "registry.io/other-repository/image2:tag",
"name": "",
"source": {}
}
],
"attestations": [
{
"statement": {
Expand Down Expand Up @@ -124,6 +160,18 @@

[TestWriteInputFile/image_config - 1]
{
"allcomponents": [
{
"containerImage": "registry.io/repository/image:tag",
"name": "",
"source": {}
},
{
"containerImage": "registry.io/other-repository/image2:tag",
"name": "",
"source": {}
}
],
"attestations": null,
"image": {
"config": {
Expand All @@ -139,6 +187,18 @@

[TestWriteInputFile/parent_image_config - 1]
{
"allcomponents": [
{
"containerImage": "registry.io/repository/image:tag",
"name": "",
"source": {}
},
{
"containerImage": "registry.io/other-repository/image2:tag",
"name": "",
"source": {}
}
],
"attestations": null,
"image": {
"parent": {
Expand All @@ -157,6 +217,18 @@

[TestWriteInputFile/attestation_with_signature - 1]
{
"allcomponents": [
{
"containerImage": "registry.io/repository/image:tag",
"name": "",
"source": {}
},
{
"containerImage": "registry.io/other-repository/image2:tag",
"name": "",
"source": {}
}
],
"attestations": [
{
"signatures": [
Expand Down Expand Up @@ -200,6 +272,18 @@

[TestWriteInputFileMultipleAttestations - 1]
{
"allcomponents": [
{
"containerImage": "registry.io/repository/image:tag",
"name": "",
"source": {}
},
{
"containerImage": "registry.io/other-repository/image2:tag",
"name": "",
"source": {}
}
],
"attestations": [
{
"statement": {
Expand Down Expand Up @@ -227,6 +311,18 @@

[TestWriteInputFile/component_with_source - 1]
{
"allcomponents": [
{
"containerImage": "registry.io/repository/image:tag",
"name": "",
"source": {}
},
{
"containerImage": "registry.io/other-repository/image2:tag",
"name": "",
"source": {}
}
],
"attestations": null,
"image": {
"ref": "registry.io/repository/image:tag",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -324,12 +324,13 @@ type image struct {
}

type Input struct {
Attestations []attestationData `json:"attestations"`
Image image `json:"image"`
Attestations []attestationData `json:"attestations"`
Image image `json:"image"`
AllComponents []app.SnapshotComponent `json:"allcomponents"`
}

// WriteInputFile writes the JSON from the attestations to input.json in a random temp dir
func (a *ApplicationSnapshotImage) WriteInputFile(ctx context.Context) (string, []byte, error) {
func (a *ApplicationSnapshotImage) WriteInputFile(ctx context.Context, allcomp []app.SnapshotComponent) (string, []byte, error) {
log.Debugf("Attempting to write %d attestations to input file", len(a.attestations))

var attestations []attestationData
Expand All @@ -349,6 +350,7 @@ func (a *ApplicationSnapshotImage) WriteInputFile(ctx context.Context) (string,
Files: a.files,
Source: a.component.Source,
},
AllComponents: allcomp,
}

if a.parentRef != nil {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,15 @@ func TestWriteInputFile(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
fs := afero.NewMemMapFs()
ctx := utils.WithFS(context.Background(), fs)
inputPath, inputJSON, err := tt.snapshot.WriteInputFile(ctx)
allComps := []app.SnapshotComponent{
{
ContainerImage: "registry.io/repository/image:tag",
},
{
ContainerImage: "registry.io/other-repository/image2:tag",
},
}
inputPath, inputJSON, err := tt.snapshot.WriteInputFile(ctx, allComps)

assert.NoError(t, err)
assert.NotEmpty(t, inputPath)
Expand All @@ -241,7 +249,15 @@ func TestWriteInputFileMultipleAttestations(t *testing.T) {

fs := afero.NewMemMapFs()
ctx := utils.WithFS(context.Background(), fs)
inputPath, inputJSON, err := a.WriteInputFile(ctx)
allComps := []app.SnapshotComponent{
{
ContainerImage: "registry.io/repository/image:tag",
},
{
ContainerImage: "registry.io/other-repository/image2:tag",
},
}
inputPath, inputJSON, err := a.WriteInputFile(ctx, allComps)

assert.NoError(t, err)
assert.NotEmpty(t, inputPath)
Expand Down
4 changes: 2 additions & 2 deletions internal/image/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import (

// ValidateImage executes the required method calls to evaluate a given policy
// against a given image url.
func ValidateImage(ctx context.Context, comp app.SnapshotComponent, p policy.Policy, evaluators []evaluator.Evaluator, detailed bool) (*output.Output, error) {
func ValidateImage(ctx context.Context, comp app.SnapshotComponent, p policy.Policy, evaluators []evaluator.Evaluator, detailed bool, allcomp []app.SnapshotComponent) (*output.Output, error) {
log.Debugf("Validating image %s", comp.ContainerImage)

out := &output.Output{ImageURL: comp.ContainerImage, Detailed: detailed, Policy: p}
Expand Down Expand Up @@ -99,7 +99,7 @@ func ValidateImage(ctx context.Context, comp app.SnapshotComponent, p policy.Pol
return out, nil
}

inputPath, inputJSON, err := a.WriteInputFile(ctx)
inputPath, inputJSON, err := a.WriteInputFile(ctx, allcomp)
if err != nil {
log.Debug("Problem writing input files!")
return nil, err
Expand Down
Loading

0 comments on commit 1270117

Please sign in to comment.