diff --git a/policy/policy.go b/policy/policy.go index 908aefab..5ab2408e 100644 --- a/policy/policy.go +++ b/policy/policy.go @@ -239,30 +239,30 @@ func (p Policy) Verify(ctx context.Context, opts ...VerifyOption) (bool, map[str resultsByStep := make(map[string]StepResult) for depth := 0; depth < vo.searchDepth; depth++ { for stepName, step := range p.Steps { - // initialize the result for this step if it hasn't been already - if _, ok := resultsByStep[stepName]; !ok { - resultsByStep[stepName] = StepResult{Step: stepName} - } - + // Use search to get all the attestations that match the supplied step name and subjects collections, err := vo.verifiedSource.Search(ctx, stepName, vo.subjectDigests, attestationsByStep[stepName]) if err != nil { return false, nil, err } if len(collections) == 0 { - continue + collections = append(collections, source.CollectionVerificationResult{Errors: []error{ErrNoCollections{Step: stepName}}}) } - // Verify the functionaries and validate attestations + // Verify the functionaries collections = step.checkFunctionaries(collections, trustBundles) - stepResult := step.validateAttestations(collections) - // Merge the results - if result, ok := resultsByStep[stepName]; ok { - result.Passed = append(result.Passed, stepResult.Passed...) - result.Rejected = append(result.Rejected, stepResult.Rejected...) + stepResult := step.validateAttestations(collections) - resultsByStep[stepName] = result + // We perform many searches against the same step, so we need to merge the relevant fields + if resultsByStep[stepName].Step == "" { + resultsByStep[stepName] = stepResult + } else { + if result, ok := resultsByStep[stepName]; ok { + result.Passed = append(result.Passed, stepResult.Passed...) + result.Rejected = append(result.Rejected, stepResult.Rejected...) + resultsByStep[stepName] = result + } } for _, coll := range stepResult.Passed { @@ -325,6 +325,13 @@ func (p Policy) verifyArtifacts(resultsByStep map[string]StepResult) (map[string for _, step := range p.Steps { accepted := false if len(resultsByStep[step.Name].Passed) == 0 { + if result, ok := resultsByStep[step.Name]; ok { + result.Rejected = append(result.Rejected, RejectedCollection{Reason: fmt.Errorf("failed to verify artifacts for step %s: no passed collections present", step.Name)}) + resultsByStep[step.Name] = result + } else { + return nil, fmt.Errorf("failed to find step %s in step results map", step.Name) + } + continue } diff --git a/policy/step.go b/policy/step.go index 1dae6fd7..5cd5630d 100644 --- a/policy/step.go +++ b/policy/step.go @@ -184,7 +184,7 @@ func (s Step) validateAttestations(collectionResults []source.CollectionVerifica if passed { result.Passed = append(result.Passed, collection) } else { - r := strings.Join(reasons, "\n - ") + r := strings.Join(reasons, ",\n - ") reason := fmt.Sprintf("collection validation failed:\n - %s", r) result.Rejected = append(result.Rejected, RejectedCollection{ Collection: collection, diff --git a/source/memory.go b/source/memory.go index ee40f43e..8f7450e7 100644 --- a/source/memory.go +++ b/source/memory.go @@ -22,7 +22,6 @@ import ( "os" "github.com/in-toto/go-witness/dsse" - "github.com/in-toto/go-witness/log" ) type ErrDuplicateReference string @@ -32,7 +31,6 @@ func (e ErrDuplicateReference) Error() string { } type MemorySource struct { - searched bool envelopesByReference map[string]CollectionEnvelope referencesByCollectionName map[string][]string subjectDigestsByReference map[string]map[string]struct{} @@ -41,7 +39,6 @@ type MemorySource struct { func NewMemorySource() *MemorySource { return &MemorySource{ - searched: false, envelopesByReference: make(map[string]CollectionEnvelope), referencesByCollectionName: make(map[string][]string), subjectDigestsByReference: make(map[string]map[string]struct{}), @@ -107,13 +104,6 @@ func (s *MemorySource) LoadEnvelope(reference string, env dsse.Envelope) error { } func (s *MemorySource) Search(ctx context.Context, collectionName string, subjectDigests, attestations []string) ([]CollectionEnvelope, error) { - if s.searched { - log.Debug("skipping memory source search: already performed") - return []CollectionEnvelope{}, nil - } else { - s.searched = true - } - matches := make([]CollectionEnvelope, 0) for _, potentialMatchReference := range s.referencesByCollectionName[collectionName] { env, ok := s.envelopesByReference[potentialMatchReference] @@ -135,6 +125,20 @@ func (s *MemorySource) Search(ctx context.Context, collectionName string, subjec continue } + // make sure all the expected attestations appear in the collection + attestationsMatched := true + indexAttestations := s.attestationsByReference[potentialMatchReference] + for _, checkAttestation := range attestations { + if _, ok := indexAttestations[checkAttestation]; !ok { + attestationsMatched = false + break + } + } + + if !attestationsMatched { + continue + } + matches = append(matches, env) }