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

Included Tests for memory.go LoadEnvelope and Search #59

Merged
merged 8 commits into from
Jan 22, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ test/scorecard.json
log
sarif-report.json
test/log
.idea/
317 changes: 317 additions & 0 deletions source/memory_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,317 @@
// Copyright 2021 The Witness Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package source

import (
"context"
"encoding/json"
"fmt"
"reflect"
"testing"

"github.com/in-toto/go-witness/attestation"
"github.com/in-toto/go-witness/dsse"
intoto "github.com/in-toto/go-witness/intoto"
)

func TestLoadEnvelope(t *testing.T) {
// Marshal the attestation.Collection into a JSON byte array
predicate, err := json.Marshal(attestation.Collection{})
ChaosInTheCRD marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
t.Fatalf("failed to marshal predicate, err = %v", err)
}

// Define the test cases
tests := []struct {
name string
reference string
intotoStatment intoto.Statement
mSource *MemorySource
attCol attestation.Collection
wantLoadEnvelopeErr bool
wantPredicateErr bool
wantMemorySourceErr bool
wantReferenceExistErr bool
}{
{
name: "Valid intotoStatment",
reference: "ref",
intotoStatment: intoto.Statement{
Type: "https://in-toto.io/Statement/v0.1",
Subject: []intoto.Subject{{Name: "example", Digest: map[string]string{"sha256": "exampledigest"}}},
PredicateType: "https://slsa.dev/provenance/v0.2",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if this is the predicate type we should be setting

ChaosInTheCRD marked this conversation as resolved.
Show resolved Hide resolved
ChaosInTheCRD marked this conversation as resolved.
Show resolved Hide resolved
ChaosInTheCRD marked this conversation as resolved.
Show resolved Hide resolved
Predicate: json.RawMessage(predicate),
},
attCol: attestation.Collection{},
mSource: NewMemorySource(),
},
{
name: "Empty Invalid intotoStatment",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand that an empty in-toto statement has been provided, but maybe thinking "Invalid" in the test name might not be necessary. A bit of a nit though.

ChaosInTheCRD marked this conversation as resolved.
Show resolved Hide resolved
reference: "ref",
intotoStatment: intoto.Statement{},
mSource: NewMemorySource(),
attCol: attestation.Collection{},
wantPredicateErr: true,
wantMemorySourceErr: true,
},
{
name: "Invalid intotoStatment Predicate",
reference: "ref",
intotoStatment: intoto.Statement{
Type: "https://in-toto.io/Statement/v0.1",
Subject: []intoto.Subject{{Name: "example", Digest: map[string]string{"sha256": "exampledigest"}}},
PredicateType: "https://slsa.dev/provenance/v0.2",
ChaosInTheCRD marked this conversation as resolved.
Show resolved Hide resolved
Predicate: json.RawMessage("invalid-predicate"),
},
attCol: attestation.Collection{},
mSource: NewMemorySource(),
wantLoadEnvelopeErr: true,
wantMemorySourceErr: true,
},
{
name: "Valid intotoStatment",
reference: "ref",
intotoStatment: intoto.Statement{
Type: "https://in-toto.io/Statement/v0.1",
Subject: []intoto.Subject{{Name: "example", Digest: map[string]string{"sha256": "exampledigest"}}},
PredicateType: "https://slsa.dev/provenance/v0.2",
ChaosInTheCRD marked this conversation as resolved.
Show resolved Hide resolved
Predicate: json.RawMessage(predicate),
},
mSource: NewMemorySource(),
wantLoadEnvelopeErr: true,
wantReferenceExistErr: true,
},
}

// Run the test cases
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Marshal the intoto.Statement into a JSON byte array
statementBytes, _ := json.Marshal(tt.intotoStatment)

// Create a new dsse.Envelope with the marshalled intoto.Statement as the payload
envelope := dsse.Envelope{
Payload: statementBytes,
PayloadType: "application/vnd.in-toto+json",
}

// Initialize a new MemorySource
memorySource := NewMemorySource()
if tt.wantReferenceExistErr {
collEnv, err := envelopeToCollectionEnvelope(tt.reference, envelope)
if err != nil {
t.Fatalf("Invalid intotoStatment, err = %v", err)
}
// since this envelope is not in the MemorySource, we can add the collection envelope into the map
memorySource.envelopesByReference[tt.reference] = collEnv
}

// Load the dsse.Envelope into the MemorySource
err = memorySource.LoadEnvelope(tt.reference, envelope)
if err != nil {
// if we did not want the error
if !tt.wantLoadEnvelopeErr {
t.Fatalf("LoadEnvelope() error = %v, wantErr %v", err, tt.wantLoadEnvelopeErr)
}
return

}

// Check if the loaded envelope matches the expected CollectionEnvelope

expectedCollectionEnvelope := CollectionEnvelope{
Envelope: envelope,
Statement: tt.intotoStatment,
Collection: tt.attCol,
Reference: tt.reference,
}
if !reflect.DeepEqual(memorySource.envelopesByReference[tt.reference], expectedCollectionEnvelope) != tt.wantMemorySourceErr {
t.Fatalf("Mismatch or non-existence of collection envelope for reference in envelopesByReference map.")
}
// Verify if the subjects and attestations are present in the loaded envelope
for _, sub := range tt.intotoStatment.Subject {
for _, digest := range sub.Digest {
if _, ok := memorySource.subjectDigestsByReference[tt.reference][digest]; !ok != tt.wantMemorySourceErr {
t.Fatalf("memorySource does not contain passed in digest = %v", digest)
}
}
}
for _, att := range tt.attCol.Attestations {
if _, ok := memorySource.attestationsByReference[tt.reference][att.Attestation.Type()]; !ok != tt.wantMemorySourceErr {
t.Fatalf("memorySource does not contain passed in attestation = %v", att.Attestation.Name())
}
}
})
}
}

func TestSearch(t *testing.T) {
// Marshal the attestation.Collection into a JSON byte array
validPredicate, err := json.Marshal(attestation.Collection{Name: "t"})
if err != nil {
t.Fatalf("failed to marshal predicate, err = %v", err)
}

// Define the arguments for the test cases
type args struct {
ctx context.Context
collectionName string
subDigest []string
attestations []string
}
// Define the test cases
tests := []struct {
name string
statements []intoto.Statement
searchQuery args
wantReferences map[string]struct{}
wantErr bool
}{
{
name: "all match given query",
statements: []intoto.Statement{
{
Type: "1",
Subject: []intoto.Subject{{Name: "example1", Digest: map[string]string{"a": "exampledigest", "b": "exampledigest2", "c": "exampledigest3"}}},
PredicateType: "https://slsa.dev/provenance/v0.2",
ChaosInTheCRD marked this conversation as resolved.
Show resolved Hide resolved
Predicate: json.RawMessage(validPredicate),
},
{
Type: "2",
Subject: []intoto.Subject{{Name: "example2", Digest: map[string]string{"a": "exampledigest", "b": "exampledigest2"}}},
PredicateType: "https://slsa.dev/provenance/v0.2",
ChaosInTheCRD marked this conversation as resolved.
Show resolved Hide resolved
Predicate: json.RawMessage(validPredicate),
},
{
Type: "3",
Subject: []intoto.Subject{{Name: "example3", Digest: map[string]string{"a": "exampledigest"}}},
PredicateType: "https://slsa.dev/provenance/v0.2",
ChaosInTheCRD marked this conversation as resolved.
Show resolved Hide resolved
Predicate: json.RawMessage(validPredicate),
},
},
searchQuery: args{
collectionName: "t",
subDigest: []string{"exampledigest", "notincluded"},
attestations: []string{},
},
wantReferences: map[string]struct{}{"ref0": {}, "ref1": {}, "ref2": {}},
wantErr: false,
},
{
name: "some match",
statements: []intoto.Statement{
{
Type: "1",
Subject: []intoto.Subject{{Name: "example1", Digest: map[string]string{"a": "exampledigest", "b": "exampledigest2", "c": "exampledigest3"}}},
PredicateType: "https://slsa.dev/provenance/v0.2",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again I think the Predicate Type here is incorrect.

ChaosInTheCRD marked this conversation as resolved.
Show resolved Hide resolved
Predicate: json.RawMessage(validPredicate),
},
{
Type: "2",
Subject: []intoto.Subject{{Name: "example2", Digest: map[string]string{"a": "exampledigest", "b": "exampledigest2"}}},
PredicateType: "https://slsa.dev/provenance/v0.2",
ChaosInTheCRD marked this conversation as resolved.
Show resolved Hide resolved
Predicate: json.RawMessage(validPredicate),
},
{
Type: "3",
Subject: []intoto.Subject{{Name: "example3", Digest: map[string]string{"a": "exampledigest"}}},
PredicateType: "https://slsa.dev/provenance/v0.2",
ChaosInTheCRD marked this conversation as resolved.
Show resolved Hide resolved
Predicate: json.RawMessage(validPredicate),
},
{
Type: "4",
Subject: []intoto.Subject{{Name: "example1", Digest: map[string]string{"a": "not included"}}},
PredicateType: "https://slsa.dev/provenance/v0.2",
ChaosInTheCRD marked this conversation as resolved.
Show resolved Hide resolved
Predicate: json.RawMessage(validPredicate),
},
},
searchQuery: args{
collectionName: "t",
subDigest: []string{"exampledigest"},
attestations: []string{},
},
wantReferences: map[string]struct{}{"ref0": {}, "ref1": {}, "ref2": {}},
wantErr: false,
},
{
name: "no matches",
statements: []intoto.Statement{
{
Type: "1",
Subject: []intoto.Subject{{Name: "example1", Digest: map[string]string{"a": "exampledigest", "b": "exampledigest2", "c": "exampledigest3"}}},
PredicateType: "https://slsa.dev/provenance/v0.2",
ChaosInTheCRD marked this conversation as resolved.
Show resolved Hide resolved
Predicate: json.RawMessage(validPredicate),
},
{
Type: "2",
Subject: []intoto.Subject{{Name: "example2", Digest: map[string]string{"a": "exampledigest", "b": "exampledigest2"}}},
PredicateType: "https://slsa.dev/provenance/v0.2",
ChaosInTheCRD marked this conversation as resolved.
Show resolved Hide resolved
Predicate: json.RawMessage(validPredicate),
},
{
Type: "3",
Subject: []intoto.Subject{{Name: "example3", Digest: map[string]string{"a": "exampledigest"}}},
PredicateType: "https://slsa.dev/provenance/v0.2",
ChaosInTheCRD marked this conversation as resolved.
Show resolved Hide resolved
Predicate: json.RawMessage(validPredicate),
},
},
searchQuery: args{
collectionName: "t",
subDigest: []string{},
attestations: []string{},
},
wantReferences: map[string]struct{}{},
wantErr: false,
},
}

// Run the test cases
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Initialize a new MemorySource
s := NewMemorySource()
expectedResult := []CollectionEnvelope{}
for i := range tt.statements {
// Marshal the intoto.Statement into a JSON byte array
payload, _ := json.Marshal(tt.statements[i])
// Create a new dsse.Envelope with the marshalled intoto.Statement as the payload
dsseEnv := dsse.Envelope{
Payload: payload,
PayloadType: "application/vnd.in-toto+json",
}
// Load the dsse.Envelope into the MemorySource
err := s.LoadEnvelope("ref"+fmt.Sprint(i), dsseEnv)
if err != nil {
t.Fatalf("invalid intoto statment, err = %v", err)
}

if _, ok := tt.wantReferences["ref"+fmt.Sprint(i)]; ok {
collEnv, _ := envelopeToCollectionEnvelope("ref"+fmt.Sprint(i), dsseEnv)
expectedResult = append(expectedResult, collEnv)
}
}

// Run the search query on the MemorySource
got, err := s.Search(tt.searchQuery.ctx, tt.searchQuery.collectionName, tt.searchQuery.subDigest, tt.searchQuery.attestations)
if (err != nil) != tt.wantErr {
t.Fatalf("MemorySource.Search() error = %v, wantErr %v", err, tt.wantErr)
}
// Check if the search results match the expected results
if !reflect.DeepEqual(got, expectedResult) {
t.Fatalf("MemorySource.Search() = %v, want %v", got, expectedResult)
}
})
}
}
Loading