2024-10-17 13:40:17 -05:00
/ *
Copyright 2024 Docker attest authors
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 .
* /
2024-04-29 15:02:21 -05:00
package attest
import (
"path/filepath"
"testing"
2024-09-02 16:17:50 +01:00
"github.com/docker/attest/attestation"
2024-04-29 15:02:21 -05:00
"github.com/docker/attest/internal/test"
2024-09-02 16:17:50 +01:00
"github.com/docker/attest/oci"
"github.com/docker/attest/policy"
2024-04-29 15:02:21 -05:00
intoto "github.com/in-toto/in-toto-golang/in_toto"
v02 "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.2"
"github.com/stretchr/testify/assert"
2024-05-22 14:49:23 +01:00
"github.com/stretchr/testify/require"
2024-04-29 15:02:21 -05:00
)
var (
2024-09-30 20:53:13 +01:00
NoProvenanceImage = filepath . Join ( "test" , "testdata" , "no-provenance-index" )
2024-09-02 16:17:50 +01:00
PassPolicyDir = filepath . Join ( "test" , "testdata" , "local-policy-pass" )
PassMirrorPolicyDir = filepath . Join ( "test" , "testdata" , "local-policy-mirror" )
PassNoTLPolicyDir = filepath . Join ( "test" , "testdata" , "local-policy-no-tl" )
FailPolicyDir = filepath . Join ( "test" , "testdata" , "local-policy-fail" )
InputsPolicyDir = filepath . Join ( "test" , "testdata" , "local-policy-inputs" )
EmptyPolicyDir = filepath . Join ( "test" , "testdata" , "local-policy-no-policies" )
2024-07-12 17:09:41 +01:00
TestTempDir = "attest-sign-test"
2024-04-29 15:02:21 -05:00
)
func TestSignVerifyOCILayout ( t * testing . T ) {
ctx , signer := test . Setup ( t )
testCases := [ ] struct {
name string
TestImage string
expectedStatements int
expectedAttestations int
replace bool
} {
2024-09-30 20:53:13 +01:00
{ "signed replaced" , test . UnsignedTestIndex ( ) , 0 , 4 , true } ,
{ "without replace" , test . UnsignedTestIndex ( ) , 4 , 4 , false } ,
2024-04-29 15:02:21 -05:00
// image without provenance doesn't fail
2024-05-22 14:49:23 +01:00
{ "no provenance (replace)" , NoProvenanceImage , 0 , 2 , true } ,
{ "no provenance (no replace)" , NoProvenanceImage , 2 , 2 , false } ,
2024-04-29 15:02:21 -05:00
}
2024-08-01 15:35:15 +01:00
policyOpts := & policy . Options {
2024-05-22 14:49:23 +01:00
LocalPolicyDir : PassPolicyDir ,
2024-08-28 09:53:52 +01:00
DisableTUF : true ,
2024-04-29 15:02:21 -05:00
}
for _ , tc := range testCases {
t . Run ( tc . name , func ( t * testing . T ) {
2024-05-22 14:49:23 +01:00
outputLayout := test . CreateTempDir ( t , "" , TestTempDir )
2024-07-16 10:05:17 +01:00
opts := & attestation . SigningOptions { }
2024-07-05 09:29:14 +01:00
attIdx , err := oci . IndexFromPath ( tc . TestImage )
2024-05-22 14:49:23 +01:00
require . NoError ( t , err )
2024-07-05 09:29:14 +01:00
signedManifests , err := SignStatements ( ctx , attIdx . Index , signer , opts )
require . NoError ( t , err )
signedIndex := attIdx . Index
2024-07-16 10:05:17 +01:00
signedIndex , err = attestation . UpdateIndexImages ( signedIndex , signedManifests , attestation . WithReplacedLayers ( tc . replace ) )
2024-05-22 14:49:23 +01:00
require . NoError ( t , err )
2024-08-05 11:23:32 -05:00
spec , err := oci . ParseImageSpec ( oci . LocalPrefix + outputLayout )
2024-05-22 14:49:23 +01:00
require . NoError ( t , err )
2024-09-09 14:22:17 +01:00
err = oci . SaveIndex ( ctx , [ ] * oci . ImageSpec { spec } , signedIndex , attIdx . Name )
2024-05-30 17:38:58 +01:00
require . NoError ( t , err )
2024-08-05 11:23:32 -05:00
policy , err := Verify ( ctx , spec , policyOpts )
2024-05-22 14:49:23 +01:00
require . NoError ( t , err )
assert . Equalf ( t , OutcomeSuccess , policy . Outcome , "Policy should have been found" )
2024-04-29 15:02:21 -05:00
2024-08-12 14:49:52 -05:00
var allEnvelopes [ ] * attestation . AnnotatedStatement
2024-04-30 09:34:17 -05:00
for _ , predicate := range [ ] string { intoto . PredicateSPDX , v02 . PredicateSLSAProvenance , attestation . VSAPredicateType } {
mt , _ := attestation . DSSEMediaType ( predicate )
2024-08-12 14:49:52 -05:00
statements , err := attestation . ExtractAnnotatedStatements ( outputLayout , mt )
2024-05-22 14:49:23 +01:00
require . NoError ( t , err )
2024-04-30 09:34:17 -05:00
allEnvelopes = append ( allEnvelopes , statements ... )
2024-04-29 15:02:21 -05:00
2024-04-30 09:34:17 -05:00
for _ , stmt := range statements {
2024-07-05 09:29:14 +01:00
assert . Equalf ( t , predicate , stmt . Annotations [ attestation . InTotoPredicateType ] , "expected predicate-type annotation to be set to %s, got %s" , predicate , stmt . Annotations [ attestation . InTotoPredicateType ] )
assert . Equalf ( t , attestation . LifecycleStageExperimental , stmt . Annotations [ attestation . InTotoReferenceLifecycleStage ] , "expected reference lifecycle stage annotation to be set to %s, got %s" , attestation . LifecycleStageExperimental , stmt . Annotations [ attestation . InTotoReferenceLifecycleStage ] )
2024-04-29 15:02:21 -05:00
}
}
2024-04-30 09:34:17 -05:00
assert . Equalf ( t , tc . expectedAttestations , len ( allEnvelopes ) , "expected %d attestations, got %d" , tc . expectedAttestations , len ( allEnvelopes ) )
2024-08-12 14:49:52 -05:00
statements , err := attestation . ExtractAnnotatedStatements ( outputLayout , intoto . PayloadType )
2024-05-22 14:49:23 +01:00
require . NoError ( t , err )
2024-04-30 09:34:17 -05:00
assert . Equalf ( t , tc . expectedStatements , len ( statements ) , "expected %d statement, got %d" , tc . expectedStatements , len ( statements ) )
2024-04-29 15:02:21 -05:00
} )
}
}