Files
attest/internal/test/test.go
James Carnegie 9582e69968 fix: standardize casing of initialisms (#112)
* fix: standardize casing of initialisms
* fix: rename intoto -> inToto and Intoto to InToto
* fix: fix all linting errors
2024-08-01 15:35:15 +01:00

188 lines
4.9 KiB
Go

package test
import (
"context"
"encoding/base64"
"encoding/json"
"fmt"
"os"
"strings"
"testing"
"github.com/docker/attest/pkg/attestation"
"github.com/docker/attest/pkg/policy"
"github.com/docker/attest/pkg/signerverifier"
"github.com/docker/attest/pkg/tlog"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/layout"
"github.com/google/go-containerregistry/pkg/v1/partial"
intoto "github.com/in-toto/in-toto-golang/in_toto"
"github.com/secure-systems-lab/go-securesystemslib/dsse"
)
const (
UseMockTL = true
UseMockKMS = true
UseMockPolicy = true
AWSRegion = "us-east-1"
AWSKMSKeyARN = "arn:aws:kms:us-east-1:175142243308:alias/doi-signing" // sandbox
)
func CreateTempDir(t *testing.T, dir, pattern string) string {
// Create a temporary directory for output oci layout
tempDir, err := os.MkdirTemp(dir, pattern)
if err != nil {
t.Fatalf("Failed to create temp directory: %v", err)
}
// Register a cleanup function to delete the temp directory when the test exits
t.Cleanup(func() {
if err := os.RemoveAll(tempDir); err != nil {
t.Errorf("Failed to remove temp directory: %v", err)
}
})
return tempDir
}
func Setup(t *testing.T) (context.Context, dsse.SignerVerifier) {
var tl tlog.TL
if UseMockTL {
tl = tlog.GetMockTL()
} else {
tl = &tlog.RekorTL{}
}
ctx := tlog.WithTL(context.Background(), tl)
var policyEvaluator policy.Evaluator
if UseMockPolicy {
policyEvaluator = policy.GetMockPolicy()
} else {
policyEvaluator = policy.NewRegoEvaluator(true)
}
ctx = policy.WithPolicyEvaluator(ctx, policyEvaluator)
var signer dsse.SignerVerifier
var err error
if UseMockKMS {
signer, err = GetMockSigner(ctx)
if err != nil {
t.Fatal(err)
}
} else {
signer, err = signerverifier.GetAWSSigner(ctx, AWSKMSKeyARN, AWSRegion)
if err != nil {
t.Fatal(err)
}
}
return ctx, signer
}
type AnnotatedStatement struct {
OCIDescriptor *v1.Descriptor
InTotoStatement *intoto.Statement
Annotations map[string]string
}
func ExtractStatementsFromIndex(idx v1.ImageIndex, mediaType string) ([]*AnnotatedStatement, error) {
mfs2, err := idx.IndexManifest()
if err != nil {
return nil, fmt.Errorf("failed to extract IndexManifest from ImageIndex: %w", err)
}
var statements []*AnnotatedStatement
for i := range mfs2.Manifests {
mf := &mfs2.Manifests[i]
if mf.Annotations[attestation.DockerReferenceType] != "attestation-manifest" {
continue
}
attestationImage, err := idx.Image(mf.Digest)
if err != nil {
return nil, fmt.Errorf("failed to extract attestation image with digest %s: %w", mf.Digest.String(), err)
}
layers, err := attestationImage.Layers()
if err != nil {
return nil, fmt.Errorf("failed to extract layers from attestation image: %w", err)
}
for _, layer := range layers {
// parse layer blob as json
mt, err := layer.MediaType()
if err != nil {
return nil, fmt.Errorf("failed to get layer media type: %w", err)
}
if string(mt) != mediaType {
continue
}
r, err := layer.Uncompressed()
if err != nil {
return nil, fmt.Errorf("failed to get layer contents: %w", err)
}
defer r.Close()
inTotoStatement := new(intoto.Statement)
var desc *v1.Descriptor
if strings.HasSuffix(string(mt), "+dsse") {
env := new(attestation.Envelope)
err = json.NewDecoder(r).Decode(env)
if err != nil {
return nil, fmt.Errorf("failed to decode env: %w", err)
}
payload, err := base64.StdEncoding.Strict().DecodeString(env.Payload)
if err != nil {
return nil, fmt.Errorf("failed to decode payload: %w", err)
}
err = json.Unmarshal([]byte(payload), inTotoStatement)
if err != nil {
return nil, fmt.Errorf("failed to decode %s statement: %w", mediaType, err)
}
} else {
desc := new(v1.Descriptor)
err = json.NewDecoder(r).Decode(desc)
if err != nil {
return nil, fmt.Errorf("failed to decode statement: %w", err)
}
}
layerDesc, err := partial.Descriptor(layer)
if err != nil {
return nil, fmt.Errorf("failed to get descriptor for layer: %w", err)
}
annotations := make(map[string]string)
for k, v := range layerDesc.Annotations {
annotations[k] = v
}
statements = append(statements, &AnnotatedStatement{
OCIDescriptor: desc,
InTotoStatement: inTotoStatement,
Annotations: annotations,
})
}
}
return statements, nil
}
func ExtractAnnotatedStatements(path string, mediaType string) ([]*AnnotatedStatement, error) {
idx, err := layout.ImageIndexFromPath(path)
if err != nil {
return nil, fmt.Errorf("failed to load image index: %w", err)
}
idxm, err := idx.IndexManifest()
if err != nil {
return nil, fmt.Errorf("failed to get digest: %w", err)
}
idxDigest := idxm.Manifests[0].Digest
mfs, err := idx.ImageIndex(idxDigest)
if err != nil {
return nil, fmt.Errorf("failed to extract ImageIndex for digest %s: %w", idxDigest.String(), err)
}
return ExtractStatementsFromIndex(mfs, mediaType)
}