diff --git a/cli/slsa-verifier/main.go b/cli/slsa-verifier/main.go index f38d35502..c7f7de5e0 100644 --- a/cli/slsa-verifier/main.go +++ b/cli/slsa-verifier/main.go @@ -11,6 +11,7 @@ import ( "strings" serrors "github.com/slsa-framework/slsa-verifier/errors" + "github.com/slsa-framework/slsa-verifier/options" "github.com/slsa-framework/slsa-verifier/verifiers" "github.com/slsa-framework/slsa-verifier/verifiers/container" @@ -74,14 +75,8 @@ func main() { "[optional] a workflow input provided by a user at trigger time in the format 'key=value'. (Only for 'workflow_dispatch' events).") flag.Parse() - if (provenancePath == "" || artifactPath == "") && artifactImage == "" { - fmt.Fprintf(os.Stderr, "either 'provenance' and 'artifact-path' or 'artifact-image' must be specified\n") - flag.Usage() - os.Exit(1) - } - - if artifactImage != "" && (provenancePath != "" || artifactPath != "") { - fmt.Fprintf(os.Stderr, "'provenance' and 'artifact-path' should not be specified when 'artifact-image' is provided\n") + if artifactImage != "" && artifactPath != "" { + fmt.Fprintf(os.Stderr, "'artifact-image' and 'artifact-path' cannot be specified together\n") flag.Usage() os.Exit(1) } diff --git a/cli/slsa-verifier/main_test.go b/cli/slsa-verifier/main_test.go index 9fb8f781f..d1cf48af8 100644 --- a/cli/slsa-verifier/main_test.go +++ b/cli/slsa-verifier/main_test.go @@ -32,12 +32,15 @@ func pString(s string) *string { const TEST_DIR = "./testdata" -var ARTIFACT_PATH_BUILDERS = []string{"go", "generic"} -var ARTIFACT_IMAGE_BUILDERS = []string{"generic_container"} +var ( + ARTIFACT_PATH_BUILDERS = []string{"go", "generic"} + ARTIFACT_IMAGE_BUILDERS = []string{"generic_container"} +) func getBuildersAndVersions(t *testing.T, optionalMinVersion string, specifiedBuilders []string, - defaultBuilders []string) []string { + defaultBuilders []string, +) []string { res := []string{} builders := specifiedBuilders if len(builders) == 0 { @@ -473,6 +476,7 @@ func Test_runVerifyArtifactPath(t *testing.T) { for _, tt := range tests { tt := tt // Re-initializing variable so it is not changed while executing the closure below t.Run(tt.name, func(t *testing.T) { + // Avoid rate limiting by not running the tests in parallel. // t.Parallel() checkVersions := getBuildersAndVersions(t, tt.minversion, tt.builders, ARTIFACT_PATH_BUILDERS) @@ -484,8 +488,7 @@ func Test_runVerifyArtifactPath(t *testing.T) { artifactPath := filepath.Clean(filepath.Join(TEST_DIR, v, tt.artifact)) provenancePath := fmt.Sprintf("%s.intoto.jsonl", artifactPath) - - _, outBuilderId, err := runVerify("", artifactPath, + _, outBuilderID, err := runVerify("", artifactPath, provenancePath, tt.source, tt.pbranch, tt.pbuilderID, tt.ptag, tt.pversiontag, tt.inputs) @@ -498,8 +501,8 @@ func Test_runVerifyArtifactPath(t *testing.T) { return } - if tt.outBuilderID != "" && outBuilderId != tt.outBuilderID { - t.Errorf(cmp.Diff(outBuilderId, tt.outBuilderID)) + if tt.outBuilderID != "" && outBuilderID != tt.outBuilderID { + t.Errorf(cmp.Diff(outBuilderID, tt.outBuilderID)) } } }) @@ -511,7 +514,8 @@ func Test_runVerifyArtifactImage(t *testing.T) { // Override cosign image verification function for local image testing. container.RunCosignImageVerification = func(ctx context.Context, - image string, co *cosign.CheckOpts) ([]oci.Signature, bool, error) { + image string, co *cosign.CheckOpts, + ) ([]oci.Signature, bool, error) { return cosign.VerifyLocalImageAttestations(ctx, image, co) } diff --git a/errors/errors.go b/errors/errors.go index 4f63d2f9b..4d71cb0d2 100644 --- a/errors/errors.go +++ b/errors/errors.go @@ -13,11 +13,15 @@ var ( ErrorMismatchVersionedTag = errors.New("tag used to generate the binary does not match provenance") ErrorInvalidSemver = errors.New("invalid semantic version") ErrorRekorSearch = errors.New("error searching rekor entries") - ErrorMismatchHash = errors.New("binary artifact hash does not match provenance subject") + ErrorMismatchHash = errors.New("artifact hash does not match provenance subject") ErrorInvalidRef = errors.New("invalid ref") ErrorUntrustedReusableWorkflow = errors.New("untrusted reusable workflow") ErrorNoValidRekorEntries = errors.New("could not find a matching valid signature entry") ErrorVerifierNotSupported = errors.New("no verifier support the builder") ErrorNotSupported = errors.New("not supported") ErrorInvalidFormat = errors.New("invalid format") + ErrorInvalidPEM = errors.New("invalid PEM") + ErrorInvalidSignature = errors.New("invalid signature") + ErrorNoValidSignature = errors.New("no valid signature") + ErrorInternal = errors.New("internal error") ) diff --git a/register/register.go b/register/register.go index 920891542..32622cbb1 100644 --- a/register/register.go +++ b/register/register.go @@ -23,7 +23,7 @@ type SLSAVerifier interface { // VerifyImage verifies a provenance for a supplied OCI image. VerifyImage(ctx context.Context, - artifactImage string, + provenance []byte, artifactImage string, provenanceOpts *options.ProvenanceOpts, builderOpts *options.BuilderOpts, ) ([]byte, string, error) diff --git a/verifiers/internal/gcb/keys/README.md b/verifiers/internal/gcb/keys/README.md new file mode 100644 index 000000000..111f53caf --- /dev/null +++ b/verifiers/internal/gcb/keys/README.md @@ -0,0 +1,12 @@ +# Download the GCB keys + +This is a temporary solution. We should try to automate key verification on pre-submits. +We should pin the CA certificate when downloading them, maybe using curl and the googlecloudapi REST endpoint. +See discussion in [#181](https://github.com/slsa-framework/slsa-verifier/issues/181). + +For now, you can verify the keys we downloaded by downloading them yourself. + +```shell +cd verifiers/internal/gcb/keys +gcloud compute regions list | grep -v NAME | xargs -0 | cut -d ' ' -f1 | xargs -i gcloud kms keys versions get-public-key 1 --location {} --keyring attestor --key builtByGCB --project verified-builder --output-file {}.key +``` \ No newline at end of file diff --git a/verifiers/internal/gcb/keys/keys.go b/verifiers/internal/gcb/keys/keys.go new file mode 100644 index 000000000..e7d8367e6 --- /dev/null +++ b/verifiers/internal/gcb/keys/keys.go @@ -0,0 +1,63 @@ +package keys + +import ( + "crypto/ecdsa" + "crypto/x509" + "embed" + "encoding/pem" + "fmt" + "io/fs" + "path" + + serrors "github.com/slsa-framework/slsa-verifier/errors" +) + +//go:embed materials/* +var publicKeys embed.FS + +type PublicKey struct { + value []byte + pubKey *ecdsa.PublicKey + region string + // TODO: key type and size +} + +func PublicKeyNew(region string) (*PublicKey, error) { + content, err := fs.ReadFile(publicKeys, path.Join("materials", region+".key")) + if err != nil { + return nil, fmt.Errorf("%w: cannot read key materials", err) + } + + block, _ := pem.Decode(content) + if block == nil { + return nil, fmt.Errorf("%w: %s", serrors.ErrorInvalidPEM, content) + } + + key, err := x509.ParsePKIXPublicKey(block.Bytes) + if err != nil { + return nil, fmt.Errorf("x509.ParsePKIXPublicKey: %w", err) + } + + pubKey, ok := key.(*ecdsa.PublicKey) + if !ok { + return nil, fmt.Errorf("%w: public key not of type ECDSA", err) + } + + return &PublicKey{ + value: content, + pubKey: pubKey, + region: region, + }, nil +} + +func (self *PublicKey) VerifySignature(digest [32]byte, sig []byte) error { + if self.pubKey == nil { + return fmt.Errorf("%w: key is empty", serrors.ErrorInternal) + } + if !ecdsa.VerifyASN1(self.pubKey, digest[:], sig) { + return fmt.Errorf("%w: cannot verify with public key '%v'", + serrors.ErrorInvalidSignature, string(self.region)) + } + + return nil +} diff --git a/verifiers/internal/gcb/keys/materials/asia-east1.key b/verifiers/internal/gcb/keys/materials/asia-east1.key new file mode 100644 index 000000000..f878f2e38 --- /dev/null +++ b/verifiers/internal/gcb/keys/materials/asia-east1.key @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAED19/xPzO6sLFZxDzsItbVQSLMPBS +w7iVGtkXyNicWdplf4pXm6wFyZ/HyqL0Acd4Q3gfJvtVIY3HiAzjohx0cw== +-----END PUBLIC KEY----- diff --git a/verifiers/internal/gcb/keys/materials/asia-northeast1.key b/verifiers/internal/gcb/keys/materials/asia-northeast1.key new file mode 100644 index 000000000..6afa7df72 --- /dev/null +++ b/verifiers/internal/gcb/keys/materials/asia-northeast1.key @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE4RlI/MHfE9ZjKba6rMSGu3A/M0FH +UPBu4anB9yXC+8ubmMBAWIoqgXr7CYGBenw27YasBOQhyGgZQSe9sF+DhQ== +-----END PUBLIC KEY----- diff --git a/verifiers/internal/gcb/keys/materials/asia-southeast1.key b/verifiers/internal/gcb/keys/materials/asia-southeast1.key new file mode 100644 index 000000000..62f36abec --- /dev/null +++ b/verifiers/internal/gcb/keys/materials/asia-southeast1.key @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEQGLAkRjCFqZbdd4BjhNFNS8l9xMJ +K1MVNpTA/K+sGl9+HG0r43MMAIXt6QUst9kCiqiXRp+Oqc0HIGRFZMBFcg== +-----END PUBLIC KEY----- diff --git a/verifiers/internal/gcb/keys/materials/australia-southeast1.key b/verifiers/internal/gcb/keys/materials/australia-southeast1.key new file mode 100644 index 000000000..dfe3fe448 --- /dev/null +++ b/verifiers/internal/gcb/keys/materials/australia-southeast1.key @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEcYAxYYze8pKKoggou7Pz5oAfFv/Y +gWN1HAjtT0v0L6sOOKOXvFNTpjQ8nDz1ooNfuxv8pva6l8ZLICTH10CJog== +-----END PUBLIC KEY----- diff --git a/verifiers/internal/gcb/keys/materials/europe-north1.key b/verifiers/internal/gcb/keys/materials/europe-north1.key new file mode 100644 index 000000000..a9afafd57 --- /dev/null +++ b/verifiers/internal/gcb/keys/materials/europe-north1.key @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEoKSuwi41RBzyWlwYBu61xgVrO6zw +G8yjVsbyha4FfDSPMQ0V8BIJbqOphh40ACwzEKCszMY36d22FJHSLDiNvg== +-----END PUBLIC KEY----- diff --git a/verifiers/internal/gcb/keys/materials/europe-west1.key b/verifiers/internal/gcb/keys/materials/europe-west1.key new file mode 100644 index 000000000..ff688d5da --- /dev/null +++ b/verifiers/internal/gcb/keys/materials/europe-west1.key @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEDmJxa2BxOnfra0/J4FHf/2yIOElN +p6+ah2tcpK0W8FGFFU3TaC4XEXFKVV/bWmormNDvZGtN710Qi4VforgRzg== +-----END PUBLIC KEY----- diff --git a/verifiers/internal/gcb/keys/materials/europe-west2.key b/verifiers/internal/gcb/keys/materials/europe-west2.key new file mode 100644 index 000000000..69be65e95 --- /dev/null +++ b/verifiers/internal/gcb/keys/materials/europe-west2.key @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEfDuhy/obSeBa+RwcAZ3EYFvRJmIT +1+lcAk/yINf0PBysMV9Lg482EEKmq8ce2rTZXuNFxLLMiHENunJ3oGlJIg== +-----END PUBLIC KEY----- diff --git a/verifiers/internal/gcb/keys/materials/europe-west3.key b/verifiers/internal/gcb/keys/materials/europe-west3.key new file mode 100644 index 000000000..d5332e5f7 --- /dev/null +++ b/verifiers/internal/gcb/keys/materials/europe-west3.key @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEWNPQh5Z5gTBJGwINV7nja+uJ0qCD +Pek4yIfgjrhmqM3Cu06kdpfod8TCL7z32uIQTb5VysO4XVhbAY2bN0BAkg== +-----END PUBLIC KEY----- diff --git a/verifiers/internal/gcb/keys/materials/europe-west4.key b/verifiers/internal/gcb/keys/materials/europe-west4.key new file mode 100644 index 000000000..1c7270fa3 --- /dev/null +++ b/verifiers/internal/gcb/keys/materials/europe-west4.key @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEOHbdm8kpkMdEeD0i2WcWFCss620T +ts1x82wakzDELaS4rxDfJ7eSTQOyfQupjDl9M9k99uY8DoX2vAABI8DdoA== +-----END PUBLIC KEY----- diff --git a/verifiers/internal/gcb/keys/materials/global.key b/verifiers/internal/gcb/keys/materials/global.key new file mode 100644 index 000000000..e1671c5f9 --- /dev/null +++ b/verifiers/internal/gcb/keys/materials/global.key @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAECGIoAk3mHV8xq/P1x6doSzAJlTaW +YhrmI3rfN5zfk3/Dq6nPpm8D0CMVNyc4HZ5ChTDqTV8EyaR56nLqjvMYUA== +-----END PUBLIC KEY----- diff --git a/verifiers/internal/gcb/keys/materials/southamerica-west1.key b/verifiers/internal/gcb/keys/materials/southamerica-west1.key new file mode 100644 index 000000000..f1eac8b6e --- /dev/null +++ b/verifiers/internal/gcb/keys/materials/southamerica-west1.key @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAExvyU8IkmPjrV8V8dkuBMcOtvJykf +WZhaTuYcOS5KXMVpEllJ3jh9WFyuoG54mVLgFJUQwrYLhUWORRVGH1kskw== +-----END PUBLIC KEY----- diff --git a/verifiers/internal/gcb/keys/materials/us-central1.key b/verifiers/internal/gcb/keys/materials/us-central1.key new file mode 100644 index 000000000..2bb7c3def --- /dev/null +++ b/verifiers/internal/gcb/keys/materials/us-central1.key @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEAUqas+Xhfss+NCsiL8ayl1Sxz9TF +bDxLuokg59lGmpm4ca2Idmh1aYt04ZkM8sgXq/FMTXxqISA4dQapp0utZg== +-----END PUBLIC KEY----- diff --git a/verifiers/internal/gcb/keys/materials/us-central2.key b/verifiers/internal/gcb/keys/materials/us-central2.key new file mode 100644 index 000000000..0ecc7daf3 --- /dev/null +++ b/verifiers/internal/gcb/keys/materials/us-central2.key @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEOBZl8kLzGV63W0ERoHAG0xpkOu+T +zDUzk6kISDonvno/emAacWmrTMxbhDQwRcnTtT9TpUG98+WukL2PDPQ61g== +-----END PUBLIC KEY----- diff --git a/verifiers/internal/gcb/keys/materials/us-east1.key b/verifiers/internal/gcb/keys/materials/us-east1.key new file mode 100644 index 000000000..eb8d1b0fe --- /dev/null +++ b/verifiers/internal/gcb/keys/materials/us-east1.key @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEyWUk6LGBm/wTWioZ7pTA7Ds0sXQd +3Y4HYyF3/Hl/UYNveSBhMdkM4yReQPU2fNh5CkK77+JzGU8NypnvFWYSVQ== +-----END PUBLIC KEY----- diff --git a/verifiers/internal/gcb/keys/materials/us-east4.key b/verifiers/internal/gcb/keys/materials/us-east4.key new file mode 100644 index 000000000..a88cfb4b0 --- /dev/null +++ b/verifiers/internal/gcb/keys/materials/us-east4.key @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE88g3xqG/UtPE5LFG3Z6MWpZ/ofJR +E9VHeavlxhNSzV6USMUBJEU3I9/xfanRJUTT4oNdMi7cv5BeCaS2Q3mZ3w== +-----END PUBLIC KEY----- diff --git a/verifiers/internal/gcb/keys/materials/us-west1.key b/verifiers/internal/gcb/keys/materials/us-west1.key new file mode 100644 index 000000000..a86b18580 --- /dev/null +++ b/verifiers/internal/gcb/keys/materials/us-west1.key @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIZhFqz97qH9dFn23yWYVkwZVYXOA +Hllzqzr14tRkXesHcZoVnekBMBkkIkP+jgechjkjZG3NPssdmIZFZ6+oyA== +-----END PUBLIC KEY----- diff --git a/verifiers/internal/gcb/keys/materials/us-west2.key b/verifiers/internal/gcb/keys/materials/us-west2.key new file mode 100644 index 000000000..7908f8fea --- /dev/null +++ b/verifiers/internal/gcb/keys/materials/us-west2.key @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEw/gdczl7qDD4ww9B6WmJ6++/hQ5S +mdw/1RBcwNNQE9qN0O+DilRE9/AjH7OvJUhNznOzEzH7mFq5mNdmUjYlXg== +-----END PUBLIC KEY----- diff --git a/verifiers/internal/gcb/keys/materials/us-west3.key b/verifiers/internal/gcb/keys/materials/us-west3.key new file mode 100644 index 000000000..b78549b6e --- /dev/null +++ b/verifiers/internal/gcb/keys/materials/us-west3.key @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEolPSVMeD5XcXCa5gNIdSj51Z4VE7 +u3uie+EeCOAAi//g2zj+hsEchXjYA5edo9eH6iv2w1g2DMrNWutW45nRkg== +-----END PUBLIC KEY----- diff --git a/verifiers/internal/gcb/keys/materials/us-west4.key b/verifiers/internal/gcb/keys/materials/us-west4.key new file mode 100644 index 000000000..018db5685 --- /dev/null +++ b/verifiers/internal/gcb/keys/materials/us-west4.key @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAERM4hS/6KZNbEootGWRBc8lmTzIGp +FvCKxVQL2xRU87d4OCyp1iP0IsSe2a1GQPQuK8SD0vwEb9hJDBZaEOF15g== +-----END PUBLIC KEY----- diff --git a/verifiers/internal/gcb/provenance.go b/verifiers/internal/gcb/provenance.go new file mode 100644 index 000000000..7434a20c7 --- /dev/null +++ b/verifiers/internal/gcb/provenance.go @@ -0,0 +1,379 @@ +package gcb + +import ( + "crypto/sha256" + "encoding/base64" + "encoding/json" + "fmt" + "os" + "regexp" + "strings" + + intoto "github.com/in-toto/in-toto-golang/in_toto" + slsa01 "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.1" + dsselib "github.com/secure-systems-lab/go-securesystemslib/dsse" + + serrors "github.com/slsa-framework/slsa-verifier/errors" + "github.com/slsa-framework/slsa-verifier/options" + "github.com/slsa-framework/slsa-verifier/verifiers/internal/gcb/keys" +) + +var GCBBuilderIDs = []string{"https://cloudbuild.googleapis.com/GoogleHostedWorker@v0.2"} + +type v01IntotoStatement struct { + intoto.StatementHeader + Predicate slsa01.ProvenancePredicate `json:"predicate"` +} + +type provenance struct { + Build struct { + // TODO: compare to verified provenance. + // IntotoStatement v01IntotoStatement `json:"intotoStatement"` + } `json:"build"` + Kind string `json:"kind"` + ResourceURI string `json:"resourceUri"` + Envelope dsselib.Envelope `json:"envelope"` +} + +type gloudProvenance struct { + ImageSummary struct { + Digest string `json:"digest"` + FullyQualifiedDigest string `json:"fully_qualified_digest"` + Registry string `json:"registry"` + Repsitory string `json:"repository"` + } `json:"image_summary"` + ProvenanceSummary struct { + Provenance []provenance `json:"provenance"` + } `json:"provenance_summary"` +} + +type Provenance struct { + gcloudProv *gloudProvenance + verifiedProvenance *provenance + verifiedIntotoStatement *v01IntotoStatement +} + +func ProvenanceFromBytes(payload []byte) (*Provenance, error) { + var prov gloudProvenance + err := json.Unmarshal(payload, &prov) + if err != nil { + return nil, fmt.Errorf("json.Unmarshal: %w", err) + } + + return &Provenance{ + gcloudProv: &prov, + }, nil +} + +func payloadFromEnvelope(env *dsselib.Envelope) ([]byte, error) { + payload, err := base64.StdEncoding.DecodeString(env.Payload) + if err != nil { + return nil, fmt.Errorf("%w: %s", serrors.ErrorInvalidDssePayload, err.Error()) + } + return payload, nil +} + +func (self *Provenance) isVerified() error { + // Check that the signature is verified. + if self.verifiedIntotoStatement == nil || + self.verifiedProvenance == nil { + return serrors.ErrorNoValidSignature + } + return nil +} + +func (self *Provenance) GetVerifiedIntotoStatement() ([]byte, error) { + if err := self.isVerified(); err != nil { + return nil, err + } + d, err := json.Marshal(self.verifiedIntotoStatement) + if err != nil { + return nil, fmt.Errorf("%w: %s", serrors.ErrorInvalidDssePayload, err.Error()) + } + return d, nil +} + +// VerifyMetadata verifies additional metadata contained in the provenance, which is not part +// of the DSSE payload or headers. It is part of the payload returned by +// `gcloud artifacts docker images describe image:tag --format json --show-provenance`. +func (self *Provenance) VerifyMetadata(provenanceOpts *options.ProvenanceOpts) error { + if err := self.isVerified(); err != nil { + return err + } + + if provenanceOpts == nil { + return nil + } + prov := self.verifiedProvenance + + if prov.Kind != "BUILD" { + return fmt.Errorf("%w: expected kind to be 'BUILD', got %s", serrors.ErrorInvalidFormat, prov.Kind) + } + + // Note: this could be verified in `VerifySourceURI`, but it is kept here + // because it is not part of the DSSE intoto payload. + // The `ResourceURI` is container@sha256:hash, without the tag. + // We only verify the URI's sha256 for simplicity. + if !strings.HasSuffix(prov.ResourceURI, "@sha256:"+provenanceOpts.ExpectedDigest) { + return fmt.Errorf("%w: expected resourceUri '%s', got '%s'", + serrors.ErrorMismatchHash, provenanceOpts.ExpectedDigest, prov.ResourceURI) + } + return nil +} + +// VerifySummary verifies the content of the `image_summary` structure +// returned by `gcloud artifacts docker images describe image:tag --format json --show-provenance`. +func (self *Provenance) VerifySummary(provenanceOpts *options.ProvenanceOpts) error { + if err := self.isVerified(); err != nil { + return err + } + + if provenanceOpts == nil { + return nil + } + + // Validate the digest. + if self.gcloudProv.ImageSummary.Digest != "sha256:"+provenanceOpts.ExpectedDigest { + return fmt.Errorf("%w: expected summary digest '%s', got '%s'", + serrors.ErrorMismatchHash, provenanceOpts.ExpectedDigest, + self.gcloudProv.ImageSummary.Digest) + } + + // Validate the qualified digest. + if !strings.HasSuffix(self.gcloudProv.ImageSummary.FullyQualifiedDigest, + "sha256:"+provenanceOpts.ExpectedDigest) { + return fmt.Errorf("%w: expected fully qualifiedd digest '%s', got '%s'", + serrors.ErrorMismatchHash, provenanceOpts.ExpectedDigest, + self.gcloudProv.ImageSummary.FullyQualifiedDigest) + } + return nil +} + +// VerifyIntotoHeaders verifies the headers are intoto format and the expected +// slsa predicate. +func (self *Provenance) VerifyIntotoHeaders() error { + if err := self.isVerified(); err != nil { + return err + } + + statement := self.verifiedIntotoStatement + // https://in-toto.io/Statement/v0.1 + if statement.StatementHeader.Type != intoto.StatementInTotoV01 { + return fmt.Errorf("%w: expected statement header type '%s', got '%s'", + serrors.ErrorInvalidDssePayload, intoto.StatementInTotoV01, statement.StatementHeader.Type) + } + + // https://slsa.dev/provenance/v0.1 + if statement.StatementHeader.PredicateType != slsa01.PredicateSLSAProvenance { + return fmt.Errorf("%w: expected statement predicate type '%s', got '%s'", + serrors.ErrorInvalidDssePayload, slsa01.PredicateSLSAProvenance, statement.StatementHeader.PredicateType) + } + + return nil +} + +func isValidBuilderID(id string) error { + for _, b := range GCBBuilderIDs { + if id == b { + return nil + } + } + return serrors.ErrorMismatchBuilderID +} + +// VerifyBuilder verifies the builder in the DSSE payload: +// - in the recipe type +// - the recipe argument type +// - the predicate builder ID +func (self *Provenance) VerifyBuilder(builderOpts *options.BuilderOpts) (string, error) { + if err := self.isVerified(); err != nil { + return "", err + } + + statement := self.verifiedIntotoStatement + predicateBuilderID := statement.Predicate.Builder.ID + + // Sanity check the builderID. + if err := isValidBuilderID(predicateBuilderID); err != nil { + return "", err + } + + // Validate with user-provided value. + if builderOpts != nil && builderOpts.ExpectedID != nil { + if *builderOpts.ExpectedID != predicateBuilderID { + return "", fmt.Errorf("%w: expected '%s', got '%s'", serrors.ErrorMismatchBuilderID, + *builderOpts.ExpectedID, predicateBuilderID) + } + } + + // Valiate that the recipe type is consistent. + if predicateBuilderID != statement.Predicate.Recipe.Type { + return "", fmt.Errorf("%w: expected '%s', got '%s'", serrors.ErrorMismatchBuilderID, + predicateBuilderID, statement.Predicate.Recipe.Type) + } + + // Validate the recipe argument type. + expectedType := "type.googleapis.com/google.devtools.cloudbuild.v1.Build" + args, ok := statement.Predicate.Recipe.Arguments.(map[string]interface{}) + if !ok { + return "", fmt.Errorf("%w: recipe arguments is not a map", serrors.ErrorInvalidDssePayload) + } + ts, err := getAsString(args, "@type") + if err != nil { + return "", err + } + + if ts != expectedType { + return "", fmt.Errorf("%w: expected '%s', got '%s'", serrors.ErrorMismatchBuilderID, + expectedType, ts) + } + + return predicateBuilderID, nil +} + +func getAsString(m map[string]interface{}, key string) (string, error) { + t, ok := m["@type"] + if !ok { + return "", fmt.Errorf("%w: '%s' field is absent", serrors.ErrorInvalidDssePayload, key) + } + ts, ok := t.(string) + if !ok { + return "", fmt.Errorf("%w: '%s' is not a string", serrors.ErrorInvalidDssePayload, key) + } + return ts, nil +} + +// VerifySubjectDigest verifies the sha256 of the subject. +func (self *Provenance) VerifySubjectDigest(expectedHash string) error { + if err := self.isVerified(); err != nil { + return err + } + + statement := self.verifiedIntotoStatement + for _, subject := range statement.StatementHeader.Subject { + digestSet := subject.Digest + hash, exists := digestSet["sha256"] + if !exists { + return fmt.Errorf("%w: %s", serrors.ErrorInvalidDssePayload, "no sha256 subject digest") + } + + if hash == expectedHash { + return nil + } + } + + return fmt.Errorf("expected hash '%s' not found: %w", expectedHash, serrors.ErrorMismatchHash) +} + +// Verify source URI in provenance statement. +func (self *Provenance) VerifySourceURI(expectedSourceURI string) error { + if err := self.isVerified(); err != nil { + return err + } + + statement := self.verifiedIntotoStatement + materials := statement.Predicate.Materials + if len(materials) == 0 { + return fmt.Errorf("%w: no materials", serrors.ErrorInvalidDssePayload) + } + uri := materials[0].URI + if !strings.HasPrefix(expectedSourceURI, "https://") { + expectedSourceURI = "https://" + expectedSourceURI + } + if !strings.HasPrefix(uri, expectedSourceURI+"/commit/") { + return fmt.Errorf("%w: expected '%s', got '%s'", + serrors.ErrorMismatchSource, expectedSourceURI, uri) + } + + return nil +} + +func (self *Provenance) VerifyBranch(branch string) error { + return fmt.Errorf("%w: GCB branch verification", serrors.ErrorNotSupported) +} + +func (self *Provenance) VerifyTag(tag string) error { + return fmt.Errorf("%w: GCB tag verification", serrors.ErrorNotSupported) +} + +func (self *Provenance) VerifyVersionedTag(tag string) error { + return fmt.Errorf("%w: GCB versioned-tag verification", serrors.ErrorNotSupported) +} + +// verifySignatures iterates over all the signatures in the DSSE and verifies them. +// It succeeds if one of them can ne verified. +func (self *Provenance) verifySignatures(prov *provenance) error { + // Verify the envelope type. It should be an intoto type. + if prov.Envelope.PayloadType != intoto.PayloadType { + return fmt.Errorf("%w: expected payload type '%s', got %s", + serrors.ErrorInvalidDssePayload, intoto.PayloadType, prov.Envelope.PayloadType) + } + + payload, err := payloadFromEnvelope(&prov.Envelope) + if err != nil { + return err + } + + payloadHash := sha256.Sum256(payload) + + var errs []error + regex := regexp.MustCompile(`^projects\/verified-builder\/locations\/(.*)\/keyRings\/attestor\/cryptoKeys\/builtByGCB\/cryptoKeyVersions\/1$`) + + for _, sig := range prov.Envelope.Signatures { + match := regex.FindStringSubmatch(sig.KeyID) + if len(match) == 2 { + // Create a public key instance for this region. + region := match[1] + pubKey, err := keys.PublicKeyNew(region) + if err != nil { + errs = append(errs, err) + continue + } + + // Decode the signature. + rsig, err := base64.RawURLEncoding.DecodeString(sig.Sig) + if err != nil { + errs = append(errs, err) + continue + } + + // Verify the signature. + err = pubKey.VerifySignature(payloadHash, rsig) + if err != nil { + errs = append(errs, err) + continue + } + + var statement v01IntotoStatement + if err := json.Unmarshal(payload, &statement); err != nil { + return fmt.Errorf("%w: %s", serrors.ErrorInvalidDssePayload, err.Error()) + } + self.verifiedIntotoStatement = &statement + self.verifiedProvenance = prov + fmt.Fprintf(os.Stderr, "Verification succeeded with region key '%s'\n", region) + return nil + } + } + + return fmt.Errorf("%w: %v", serrors.ErrorNoValidSignature, errs) +} + +// VerifySignature verifiers the signature for a provenance. +func (self *Provenance) VerifySignature() error { + if len(self.gcloudProv.ProvenanceSummary.Provenance) == 0 { + return fmt.Errorf("%w: no provenance found", serrors.ErrorInvalidDssePayload) + } + // Iterate over all provenances available. + var errs []error + for i := range self.gcloudProv.ProvenanceSummary.Provenance { + err := self.verifySignatures(&self.gcloudProv.ProvenanceSummary.Provenance[i]) + if err != nil { + errs = append(errs, err) + continue + } + + return nil + } + + return fmt.Errorf("%w: %v", serrors.ErrorNoValidSignature, errs) +} diff --git a/verifiers/internal/gcb/testdata/gcloud-container-github.json b/verifiers/internal/gcb/testdata/gcloud-container-github.json new file mode 100644 index 000000000..bf65621dc --- /dev/null +++ b/verifiers/internal/gcb/testdata/gcloud-container-github.json @@ -0,0 +1,94 @@ +{ + "image_summary": { + "digest": "sha256:1a033b002f89ed2b8ea733162497fb70f1a4049a7f8602d6a33682b4ad9921fd", + "fully_qualified_digest": "us-west2-docker.pkg.dev/gosst-scare-sandbox/quickstart-docker-repo/quickstart-image@sha256:1a033b002f89ed2b8ea733162497fb70f1a4049a7f8602d6a33682b4ad9921fd", + "registry": "us-west2-docker.pkg.dev", + "repository": "quickstart-docker-repo" + }, + "provenance_summary": { + "provenance": [ + { + "build": { + "intotoStatement": { + "_type": "https://in-toto.io/Statement/v0.1", + "predicateType": "https://slsa.dev/provenance/v0.1", + "slsaProvenance": { + "builder": { + "id": "https://cloudbuild.googleapis.com/GoogleHostedWorker@v0.2" + }, + "materials": [ + { + "uri": "https://github.com/laurentsimon/gcb-tests/commit/fbbb98765e85ad464302dc5977968104d36e455e" + } + ], + "metadata": { + "buildFinishedOn": "2022-08-15T22:43:34.366498Z", + "buildInvocationId": "b6e052a7-5aa4-41bf-a56b-9bc4e4f3058b", + "buildStartedOn": "2022-08-15T22:43:18.700638187Z" + }, + "recipe": { + "arguments": { + "@type": "type.googleapis.com/google.devtools.cloudbuild.v1.Build", + "id": "b6e052a7-5aa4-41bf-a56b-9bc4e4f3058b", + "options": { + "dynamicSubstitutions": true, + "logging": "LEGACY", + "pool": {}, + "substitutionOption": "ALLOW_LOOSE" + }, + "sourceProvenance": {}, + "steps": [ + { + "args": [ + "build", + "-t", + "us-west2-docker.pkg.dev/gosst-scare-sandbox/quickstart-docker-repo/quickstart-image:v14", + "." + ], + "name": "gcr.io/cloud-builders/docker", + "pullTiming": { + "endTime": "2022-08-15T22:43:21.662016533Z", + "startTime": "2022-08-15T22:43:21.657262492Z" + }, + "status": "SUCCESS", + "timing": { + "endTime": "2022-08-15T22:43:27.056377441Z", + "startTime": "2022-08-15T22:43:21.657262492Z" + } + } + ] + }, + "entryPoint": "cloudbuild.yaml", + "type": "https://cloudbuild.googleapis.com/GoogleHostedWorker@v0.2" + } + }, + "subject": [ + { + "digest": { + "sha256": "1a033b002f89ed2b8ea733162497fb70f1a4049a7f8602d6a33682b4ad9921fd" + }, + "name": "https://us-west2-docker.pkg.dev/gosst-scare-sandbox/quickstart-docker-repo/quickstart-image:v14" + } + ] + } + }, + "createTime": "2022-08-15T22:43:35.649016Z", + "envelope": { + "payload": "eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjAuMSIsInByZWRpY2F0ZSI6eyJidWlsZGVyIjp7ImlkIjoiaHR0cHM6Ly9jbG91ZGJ1aWxkLmdvb2dsZWFwaXMuY29tL0dvb2dsZUhvc3RlZFdvcmtlckB2MC4yIn0sIm1hdGVyaWFscyI6W3sidXJpIjoiaHR0cHM6Ly9naXRodWIuY29tL2xhdXJlbnRzaW1vbi9nY2ItdGVzdHMvY29tbWl0L2ZiYmI5ODc2NWU4NWFkNDY0MzAyZGM1OTc3OTY4MTA0ZDM2ZTQ1NWUifV0sIm1ldGFkYXRhIjp7ImJ1aWxkRmluaXNoZWRPbiI6IjIwMjItMDgtMTVUMjI6NDM6MzQuMzY2NDk4WiIsImJ1aWxkSW52b2NhdGlvbklkIjoiYjZlMDUyYTctNWFhNC00MWJmLWE1NmItOWJjNGU0ZjMwNThiIiwiYnVpbGRTdGFydGVkT24iOiIyMDIyLTA4LTE1VDIyOjQzOjE4LjcwMDYzODE4N1oifSwicmVjaXBlIjp7ImFyZ3VtZW50cyI6eyJAdHlwZSI6InR5cGUuZ29vZ2xlYXBpcy5jb20vZ29vZ2xlLmRldnRvb2xzLmNsb3VkYnVpbGQudjEuQnVpbGQiLCJpZCI6ImI2ZTA1MmE3LTVhYTQtNDFiZi1hNTZiLTliYzRlNGYzMDU4YiIsIm9wdGlvbnMiOnsiZHluYW1pY1N1YnN0aXR1dGlvbnMiOnRydWUsImxvZ2dpbmciOiJMRUdBQ1kiLCJwb29sIjp7fSwic3Vic3RpdHV0aW9uT3B0aW9uIjoiQUxMT1dfTE9PU0UifSwic291cmNlUHJvdmVuYW5jZSI6e30sInN0ZXBzIjpbeyJhcmdzIjpbImJ1aWxkIiwiLXQiLCJ1cy13ZXN0Mi1kb2NrZXIucGtnLmRldi9nb3NzdC1zY2FyZS1zYW5kYm94L3F1aWNrc3RhcnQtZG9ja2VyLXJlcG8vcXVpY2tzdGFydC1pbWFnZTp2MTQiLCIuIl0sIm5hbWUiOiJnY3IuaW8vY2xvdWQtYnVpbGRlcnMvZG9ja2VyIiwicHVsbFRpbWluZyI6eyJlbmRUaW1lIjoiMjAyMi0wOC0xNVQyMjo0MzoyMS42NjIwMTY1MzNaIiwic3RhcnRUaW1lIjoiMjAyMi0wOC0xNVQyMjo0MzoyMS42NTcyNjI0OTJaIn0sInN0YXR1cyI6IlNVQ0NFU1MiLCJ0aW1pbmciOnsiZW5kVGltZSI6IjIwMjItMDgtMTVUMjI6NDM6MjcuMDU2Mzc3NDQxWiIsInN0YXJ0VGltZSI6IjIwMjItMDgtMTVUMjI6NDM6MjEuNjU3MjYyNDkyWiJ9fV19LCJlbnRyeVBvaW50IjoiY2xvdWRidWlsZC55YW1sIiwidHlwZSI6Imh0dHBzOi8vY2xvdWRidWlsZC5nb29nbGVhcGlzLmNvbS9Hb29nbGVIb3N0ZWRXb3JrZXJAdjAuMiJ9fSwicHJlZGljYXRlVHlwZSI6Imh0dHBzOi8vc2xzYS5kZXYvcHJvdmVuYW5jZS92MC4xIiwic2xzYVByb3ZlbmFuY2UiOnsiYnVpbGRlciI6eyJpZCI6Imh0dHBzOi8vY2xvdWRidWlsZC5nb29nbGVhcGlzLmNvbS9Hb29nbGVIb3N0ZWRXb3JrZXJAdjAuMiJ9LCJtYXRlcmlhbHMiOlt7InVyaSI6Imh0dHBzOi8vZ2l0aHViLmNvbS9sYXVyZW50c2ltb24vZ2NiLXRlc3RzL2NvbW1pdC9mYmJiOTg3NjVlODVhZDQ2NDMwMmRjNTk3Nzk2ODEwNGQzNmU0NTVlIn1dLCJtZXRhZGF0YSI6eyJidWlsZEZpbmlzaGVkT24iOiIyMDIyLTA4LTE1VDIyOjQzOjM0LjM2NjQ5OFoiLCJidWlsZEludm9jYXRpb25JZCI6ImI2ZTA1MmE3LTVhYTQtNDFiZi1hNTZiLTliYzRlNGYzMDU4YiIsImJ1aWxkU3RhcnRlZE9uIjoiMjAyMi0wOC0xNVQyMjo0MzoxOC43MDA2MzgxODdaIn0sInJlY2lwZSI6eyJhcmd1bWVudHMiOnsiQHR5cGUiOiJ0eXBlLmdvb2dsZWFwaXMuY29tL2dvb2dsZS5kZXZ0b29scy5jbG91ZGJ1aWxkLnYxLkJ1aWxkIiwiaWQiOiJiNmUwNTJhNy01YWE0LTQxYmYtYTU2Yi05YmM0ZTRmMzA1OGIiLCJvcHRpb25zIjp7ImR5bmFtaWNTdWJzdGl0dXRpb25zIjp0cnVlLCJsb2dnaW5nIjoiTEVHQUNZIiwicG9vbCI6e30sInN1YnN0aXR1dGlvbk9wdGlvbiI6IkFMTE9XX0xPT1NFIn0sInNvdXJjZVByb3ZlbmFuY2UiOnt9LCJzdGVwcyI6W3siYXJncyI6WyJidWlsZCIsIi10IiwidXMtd2VzdDItZG9ja2VyLnBrZy5kZXYvZ29zc3Qtc2NhcmUtc2FuZGJveC9xdWlja3N0YXJ0LWRvY2tlci1yZXBvL3F1aWNrc3RhcnQtaW1hZ2U6djE0IiwiLiJdLCJuYW1lIjoiZ2NyLmlvL2Nsb3VkLWJ1aWxkZXJzL2RvY2tlciIsInB1bGxUaW1pbmciOnsiZW5kVGltZSI6IjIwMjItMDgtMTVUMjI6NDM6MjEuNjYyMDE2NTMzWiIsInN0YXJ0VGltZSI6IjIwMjItMDgtMTVUMjI6NDM6MjEuNjU3MjYyNDkyWiJ9LCJzdGF0dXMiOiJTVUNDRVNTIiwidGltaW5nIjp7ImVuZFRpbWUiOiIyMDIyLTA4LTE1VDIyOjQzOjI3LjA1NjM3NzQ0MVoiLCJzdGFydFRpbWUiOiIyMDIyLTA4LTE1VDIyOjQzOjIxLjY1NzI2MjQ5MloifX1dfSwiZW50cnlQb2ludCI6ImNsb3VkYnVpbGQueWFtbCIsInR5cGUiOiJodHRwczovL2Nsb3VkYnVpbGQuZ29vZ2xlYXBpcy5jb20vR29vZ2xlSG9zdGVkV29ya2VyQHYwLjIifX0sInN1YmplY3QiOlt7ImRpZ2VzdCI6eyJzaGEyNTYiOiIxYTAzM2IwMDJmODllZDJiOGVhNzMzMTYyNDk3ZmI3MGYxYTQwNDlhN2Y4NjAyZDZhMzM2ODJiNGFkOTkyMWZkIn0sIm5hbWUiOiJodHRwczovL3VzLXdlc3QyLWRvY2tlci5wa2cuZGV2L2dvc3N0LXNjYXJlLXNhbmRib3gvcXVpY2tzdGFydC1kb2NrZXItcmVwby9xdWlja3N0YXJ0LWltYWdlOnYxNCJ9XX0=", + "payloadType": "application/vnd.in-toto+json", + "signatures": [ + { + "keyid": "projects/verified-builder/locations/global/keyRings/attestor/cryptoKeys/builtByGCB/cryptoKeyVersions/1", + "sig": "MEYCIQD-0xUsdkYnsmKnQL_ndEvXknLfn82zsG-hGyYUd4aYsAIhAP4KSCxN2VPNc-dvfrQIGduMUNmAiHxLttdezqdrSf3F" + } + ] + }, + "kind": "BUILD", + "name": "projects/gosst-scare-sandbox/occurrences/8ce06798-f94d-4772-a224-04e473163790", + "noteName": "projects/verified-builder/notes/intoto_b6e052a7-5aa4-41bf-a56b-9bc4e4f3058b", + "resourceUri": "https://us-west2-docker.pkg.dev/gosst-scare-sandbox/quickstart-docker-repo/quickstart-image@sha256:1a033b002f89ed2b8ea733162497fb70f1a4049a7f8602d6a33682b4ad9921fd", + "updateTime": "2022-08-15T22:43:35.649016Z" + } + ] + } +} diff --git a/verifiers/internal/gcb/testdata/gcloud-container-invalid-fullyqualifieddigest.json b/verifiers/internal/gcb/testdata/gcloud-container-invalid-fullyqualifieddigest.json new file mode 100644 index 000000000..4cf806abd --- /dev/null +++ b/verifiers/internal/gcb/testdata/gcloud-container-invalid-fullyqualifieddigest.json @@ -0,0 +1,95 @@ +{ + "image_summary": { + "digest": "sha256:1a033b002f89ed2b8ea733162497fb70f1a4049a7f8602d6a33682b4ad9921fd", + "fully_qualified_digest": "us-west2-docker.pkg.dev/gosst-scare-sandbox/quickstart-docker-repo/quickstart-image@sha256:2a033b002f89ed2b8ea733162497fb70f1a4049a7f8602d6a33682b4ad9921fd", + "registry": "us-west2-docker.pkg.dev", + "repository": "quickstart-docker-repo" + }, + "provenance_summary": { + "provenance": [ + { + "build": { + "intotoStatement": { + "_type": "https://in-toto.io/Statement/v0.1", + "predicateType": "https://slsa.dev/provenance/v0.1", + "slsaProvenance": { + "builder": { + "id": "https://cloudbuild.googleapis.com/GoogleHostedWorker@v0.2" + }, + "materials": [ + { + "uri": "https://github.com/laurentsimon/gcb-tests/commit/fbbb98765e85ad464302dc5977968104d36e455e" + } + ], + "metadata": { + "buildFinishedOn": "2022-08-15T22:43:34.366498Z", + "buildInvocationId": "b6e052a7-5aa4-41bf-a56b-9bc4e4f3058b", + "buildStartedOn": "2022-08-15T22:43:18.700638187Z" + }, + "recipe": { + "arguments": { + "@type": "type.googleapis.com/google.devtools.cloudbuild.v1.Build", + "id": "b6e052a7-5aa4-41bf-a56b-9bc4e4f3058b", + "options": { + "dynamicSubstitutions": true, + "logging": "LEGACY", + "pool": {}, + "substitutionOption": "ALLOW_LOOSE" + }, + "sourceProvenance": {}, + "steps": [ + { + "args": [ + "build", + "-t", + "us-west2-docker.pkg.dev/gosst-scare-sandbox/quickstart-docker-repo/quickstart-image:v14", + "." + ], + "name": "gcr.io/cloud-builders/docker", + "pullTiming": { + "endTime": "2022-08-15T22:43:21.662016533Z", + "startTime": "2022-08-15T22:43:21.657262492Z" + }, + "status": "SUCCESS", + "timing": { + "endTime": "2022-08-15T22:43:27.056377441Z", + "startTime": "2022-08-15T22:43:21.657262492Z" + } + } + ] + }, + "entryPoint": "cloudbuild.yaml", + "type": "https://cloudbuild.googleapis.com/GoogleHostedWorker@v0.2" + } + }, + "subject": [ + { + "digest": { + "sha256": "1a033b002f89ed2b8ea733162497fb70f1a4049a7f8602d6a33682b4ad9921fd" + }, + "name": "https://us-west2-docker.pkg.dev/gosst-scare-sandbox/quickstart-docker-repo/quickstart-image:v14" + } + ] + } + }, + "createTime": "2022-08-15T22:43:35.649016Z", + "envelope": { + "payload": "eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjAuMSIsInByZWRpY2F0ZSI6eyJidWlsZGVyIjp7ImlkIjoiaHR0cHM6Ly9jbG91ZGJ1aWxkLmdvb2dsZWFwaXMuY29tL0dvb2dsZUhvc3RlZFdvcmtlckB2MC4yIn0sIm1hdGVyaWFscyI6W3sidXJpIjoiaHR0cHM6Ly9naXRodWIuY29tL2xhdXJlbnRzaW1vbi9nY2ItdGVzdHMvY29tbWl0L2ZiYmI5ODc2NWU4NWFkNDY0MzAyZGM1OTc3OTY4MTA0ZDM2ZTQ1NWUifV0sIm1ldGFkYXRhIjp7ImJ1aWxkRmluaXNoZWRPbiI6IjIwMjItMDgtMTVUMjI6NDM6MzQuMzY2NDk4WiIsImJ1aWxkSW52b2NhdGlvbklkIjoiYjZlMDUyYTctNWFhNC00MWJmLWE1NmItOWJjNGU0ZjMwNThiIiwiYnVpbGRTdGFydGVkT24iOiIyMDIyLTA4LTE1VDIyOjQzOjE4LjcwMDYzODE4N1oifSwicmVjaXBlIjp7ImFyZ3VtZW50cyI6eyJAdHlwZSI6InR5cGUuZ29vZ2xlYXBpcy5jb20vZ29vZ2xlLmRldnRvb2xzLmNsb3VkYnVpbGQudjEuQnVpbGQiLCJpZCI6ImI2ZTA1MmE3LTVhYTQtNDFiZi1hNTZiLTliYzRlNGYzMDU4YiIsIm9wdGlvbnMiOnsiZHluYW1pY1N1YnN0aXR1dGlvbnMiOnRydWUsImxvZ2dpbmciOiJMRUdBQ1kiLCJwb29sIjp7fSwic3Vic3RpdHV0aW9uT3B0aW9uIjoiQUxMT1dfTE9PU0UifSwic291cmNlUHJvdmVuYW5jZSI6e30sInN0ZXBzIjpbeyJhcmdzIjpbImJ1aWxkIiwiLXQiLCJ1cy13ZXN0Mi1kb2NrZXIucGtnLmRldi9nb3NzdC1zY2FyZS1zYW5kYm94L3F1aWNrc3RhcnQtZG9ja2VyLXJlcG8vcXVpY2tzdGFydC1pbWFnZTp2MTQiLCIuIl0sIm5hbWUiOiJnY3IuaW8vY2xvdWQtYnVpbGRlcnMvZG9ja2VyIiwicHVsbFRpbWluZyI6eyJlbmRUaW1lIjoiMjAyMi0wOC0xNVQyMjo0MzoyMS42NjIwMTY1MzNaIiwic3RhcnRUaW1lIjoiMjAyMi0wOC0xNVQyMjo0MzoyMS42NTcyNjI0OTJaIn0sInN0YXR1cyI6IlNVQ0NFU1MiLCJ0aW1pbmciOnsiZW5kVGltZSI6IjIwMjItMDgtMTVUMjI6NDM6MjcuMDU2Mzc3NDQxWiIsInN0YXJ0VGltZSI6IjIwMjItMDgtMTVUMjI6NDM6MjEuNjU3MjYyNDkyWiJ9fV19LCJlbnRyeVBvaW50IjoiY2xvdWRidWlsZC55YW1sIiwidHlwZSI6Imh0dHBzOi8vY2xvdWRidWlsZC5nb29nbGVhcGlzLmNvbS9Hb29nbGVIb3N0ZWRXb3JrZXJAdjAuMiJ9fSwicHJlZGljYXRlVHlwZSI6Imh0dHBzOi8vc2xzYS5kZXYvcHJvdmVuYW5jZS92MC4xIiwic2xzYVByb3ZlbmFuY2UiOnsiYnVpbGRlciI6eyJpZCI6Imh0dHBzOi8vY2xvdWRidWlsZC5nb29nbGVhcGlzLmNvbS9Hb29nbGVIb3N0ZWRXb3JrZXJAdjAuMiJ9LCJtYXRlcmlhbHMiOlt7InVyaSI6Imh0dHBzOi8vZ2l0aHViLmNvbS9sYXVyZW50c2ltb24vZ2NiLXRlc3RzL2NvbW1pdC9mYmJiOTg3NjVlODVhZDQ2NDMwMmRjNTk3Nzk2ODEwNGQzNmU0NTVlIn1dLCJtZXRhZGF0YSI6eyJidWlsZEZpbmlzaGVkT24iOiIyMDIyLTA4LTE1VDIyOjQzOjM0LjM2NjQ5OFoiLCJidWlsZEludm9jYXRpb25JZCI6ImI2ZTA1MmE3LTVhYTQtNDFiZi1hNTZiLTliYzRlNGYzMDU4YiIsImJ1aWxkU3RhcnRlZE9uIjoiMjAyMi0wOC0xNVQyMjo0MzoxOC43MDA2MzgxODdaIn0sInJlY2lwZSI6eyJhcmd1bWVudHMiOnsiQHR5cGUiOiJ0eXBlLmdvb2dsZWFwaXMuY29tL2dvb2dsZS5kZXZ0b29scy5jbG91ZGJ1aWxkLnYxLkJ1aWxkIiwiaWQiOiJiNmUwNTJhNy01YWE0LTQxYmYtYTU2Yi05YmM0ZTRmMzA1OGIiLCJvcHRpb25zIjp7ImR5bmFtaWNTdWJzdGl0dXRpb25zIjp0cnVlLCJsb2dnaW5nIjoiTEVHQUNZIiwicG9vbCI6e30sInN1YnN0aXR1dGlvbk9wdGlvbiI6IkFMTE9XX0xPT1NFIn0sInNvdXJjZVByb3ZlbmFuY2UiOnt9LCJzdGVwcyI6W3siYXJncyI6WyJidWlsZCIsIi10IiwidXMtd2VzdDItZG9ja2VyLnBrZy5kZXYvZ29zc3Qtc2NhcmUtc2FuZGJveC9xdWlja3N0YXJ0LWRvY2tlci1yZXBvL3F1aWNrc3RhcnQtaW1hZ2U6djE0IiwiLiJdLCJuYW1lIjoiZ2NyLmlvL2Nsb3VkLWJ1aWxkZXJzL2RvY2tlciIsInB1bGxUaW1pbmciOnsiZW5kVGltZSI6IjIwMjItMDgtMTVUMjI6NDM6MjEuNjYyMDE2NTMzWiIsInN0YXJ0VGltZSI6IjIwMjItMDgtMTVUMjI6NDM6MjEuNjU3MjYyNDkyWiJ9LCJzdGF0dXMiOiJTVUNDRVNTIiwidGltaW5nIjp7ImVuZFRpbWUiOiIyMDIyLTA4LTE1VDIyOjQzOjI3LjA1NjM3NzQ0MVoiLCJzdGFydFRpbWUiOiIyMDIyLTA4LTE1VDIyOjQzOjIxLjY1NzI2MjQ5MloifX1dfSwiZW50cnlQb2ludCI6ImNsb3VkYnVpbGQueWFtbCIsInR5cGUiOiJodHRwczovL2Nsb3VkYnVpbGQuZ29vZ2xlYXBpcy5jb20vR29vZ2xlSG9zdGVkV29ya2VyQHYwLjIifX0sInN1YmplY3QiOlt7ImRpZ2VzdCI6eyJzaGEyNTYiOiIxYTAzM2IwMDJmODllZDJiOGVhNzMzMTYyNDk3ZmI3MGYxYTQwNDlhN2Y4NjAyZDZhMzM2ODJiNGFkOTkyMWZkIn0sIm5hbWUiOiJodHRwczovL3VzLXdlc3QyLWRvY2tlci5wa2cuZGV2L2dvc3N0LXNjYXJlLXNhbmRib3gvcXVpY2tzdGFydC1kb2NrZXItcmVwby9xdWlja3N0YXJ0LWltYWdlOnYxNCJ9XX0=", + "payloadType": "application/vnd.in-toto+json", + "signatures": [ + { + "keyid": "projects/verified-builder/locations/global/keyRings/attestor/cryptoKeys/builtByGCB/cryptoKeyVersions/1", + "sig": "MEYCIQD-0xUsdkYnsmKnQL_ndEvXknLfn82zsG-hGyYUd4aYsAIhAP4KSCxN2VPNc-dvfrQIGduMUNmAiHxLttdezqdrSf3F" + } + ] + }, + "kind": "BUILD", + "name": "projects/gosst-scare-sandbox/occurrences/8ce06798-f94d-4772-a224-04e473163790", + "noteName": "projects/verified-builder/notes/intoto_b6e052a7-5aa4-41bf-a56b-9bc4e4f3058b", + "resourceUri": "https://us-west2-docker.pkg.dev/gosst-scare-sandbox/quickstart-docker-repo/quickstart-image@sha256:1a033b002f89ed2b8ea733162497fb70f1a4049a7f8602d6a33682b4ad9921fd", + "updateTime": "2022-08-15T22:43:35.649016Z" + } + ] + } + } + \ No newline at end of file diff --git a/verifiers/internal/gcb/testdata/gcloud-container-invalid-intotoheader.json b/verifiers/internal/gcb/testdata/gcloud-container-invalid-intotoheader.json new file mode 100644 index 000000000..bd2a38ebb --- /dev/null +++ b/verifiers/internal/gcb/testdata/gcloud-container-invalid-intotoheader.json @@ -0,0 +1,94 @@ +{ + "image_summary": { + "digest": "sha256:1a033b002f89ed2b8ea733162497fb70f1a4049a7f8602d6a33682b4ad9921fd", + "fully_qualified_digest": "us-west2-docker.pkg.dev/gosst-scare-sandbox/quickstart-docker-repo/quickstart-image@sha256:1a033b002f89ed2b8ea733162497fb70f1a4049a7f8602d6a33682b4ad9921fd", + "registry": "us-west2-docker.pkg.dev", + "repository": "quickstart-docker-repo" + }, + "provenance_summary": { + "provenance": [ + { + "build": { + "intotoStatement": { + "_type": "https://in-toto.io/Statement/v0.1", + "predicateType": "https://slsa.dev/provenance/v0.1", + "slsaProvenance": { + "builder": { + "id": "https://cloudbuild.googleapis.com/GoogleHostedWorker@v0.2" + }, + "materials": [ + { + "uri": "https://github.com/laurentsimon/gcb-tests/commit/fbbb98765e85ad464302dc5977968104d36e455e" + } + ], + "metadata": { + "buildFinishedOn": "2022-08-15T22:43:34.366498Z", + "buildInvocationId": "b6e052a7-5aa4-41bf-a56b-9bc4e4f3058b", + "buildStartedOn": "2022-08-15T22:43:18.700638187Z" + }, + "recipe": { + "arguments": { + "@type": "type.googleapis.com/google.devtools.cloudbuild.v1.Build", + "id": "b6e052a7-5aa4-41bf-a56b-9bc4e4f3058b", + "options": { + "dynamicSubstitutions": true, + "logging": "LEGACY", + "pool": {}, + "substitutionOption": "ALLOW_LOOSE" + }, + "sourceProvenance": {}, + "steps": [ + { + "args": [ + "build", + "-t", + "us-west2-docker.pkg.dev/gosst-scare-sandbox/quickstart-docker-repo/quickstart-image:v14", + "." + ], + "name": "gcr.io/cloud-builders/docker", + "pullTiming": { + "endTime": "2022-08-15T22:43:21.662016533Z", + "startTime": "2022-08-15T22:43:21.657262492Z" + }, + "status": "SUCCESS", + "timing": { + "endTime": "2022-08-15T22:43:27.056377441Z", + "startTime": "2022-08-15T22:43:21.657262492Z" + } + } + ] + }, + "entryPoint": "cloudbuild.yaml", + "type": "https://cloudbuild.googleapis.com/GoogleHostedWorker@v0.2" + } + }, + "subject": [ + { + "digest": { + "sha256": "1a033b002f89ed2b8ea733162497fb70f1a4049a7f8602d6a33682b4ad9921fd" + }, + "name": "https://us-west2-docker.pkg.dev/gosst-scare-sandbox/quickstart-docker-repo/quickstart-image:v14" + } + ] + } + }, + "createTime": "2022-08-15T22:43:35.649016Z", + "envelope": { + "payload": "ewogICJfdHlwZSI6ICJodHRwczovL2luLXRvdG8uaW8vU3RhdGVtZW50L3YwLjIiLAogICJwcmVkaWNhdGUiOiB7CiAgICAiYnVpbGRlciI6IHsKICAgICAgImlkIjogImh0dHBzOi8vY2xvdWRidWlsZC5nb29nbGVhcGlzLmNvbS9Hb29nbGVIb3N0ZWRXb3JrZXJAdjAuMiIKICAgIH0sCiAgICAibWF0ZXJpYWxzIjogWwogICAgICB7CiAgICAgICAgInVyaSI6ICJodHRwczovL2dpdGh1Yi5jb20vbGF1cmVudHNpbW9uL2djYi10ZXN0cy9jb21taXQvZmJiYjk4NzY1ZTg1YWQ0NjQzMDJkYzU5Nzc5NjgxMDRkMzZlNDU1ZSIKICAgICAgfQogICAgXSwKICAgICJtZXRhZGF0YSI6IHsKICAgICAgImJ1aWxkRmluaXNoZWRPbiI6ICIyMDIyLTA4LTE1VDIyOjQzOjM0LjM2NjQ5OFoiLAogICAgICAiYnVpbGRJbnZvY2F0aW9uSWQiOiAiYjZlMDUyYTctNWFhNC00MWJmLWE1NmItOWJjNGU0ZjMwNThiIiwKICAgICAgImJ1aWxkU3RhcnRlZE9uIjogIjIwMjItMDgtMTVUMjI6NDM6MTguNzAwNjM4MTg3WiIKICAgIH0sCiAgICAicmVjaXBlIjogewogICAgICAiYXJndW1lbnRzIjogewogICAgICAgICJAdHlwZSI6ICJ0eXBlLmdvb2dsZWFwaXMuY29tL2dvb2dsZS5kZXZ0b29scy5jbG91ZGJ1aWxkLnYxLkJ1aWxkIiwKICAgICAgICAiaWQiOiAiYjZlMDUyYTctNWFhNC00MWJmLWE1NmItOWJjNGU0ZjMwNThiIiwKICAgICAgICAib3B0aW9ucyI6IHsKICAgICAgICAgICJkeW5hbWljU3Vic3RpdHV0aW9ucyI6IHRydWUsCiAgICAgICAgICAibG9nZ2luZyI6ICJMRUdBQ1kiLAogICAgICAgICAgInBvb2wiOiB7fSwKICAgICAgICAgICJzdWJzdGl0dXRpb25PcHRpb24iOiAiQUxMT1dfTE9PU0UiCiAgICAgICAgfSwKICAgICAgICAic291cmNlUHJvdmVuYW5jZSI6IHt9LAogICAgICAgICJzdGVwcyI6IFsKICAgICAgICAgIHsKICAgICAgICAgICAgImFyZ3MiOiBbCiAgICAgICAgICAgICAgImJ1aWxkIiwKICAgICAgICAgICAgICAiLXQiLAogICAgICAgICAgICAgICJ1cy13ZXN0Mi1kb2NrZXIucGtnLmRldi9nb3NzdC1zY2FyZS1zYW5kYm94L3F1aWNrc3RhcnQtZG9ja2VyLXJlcG8vcXVpY2tzdGFydC1pbWFnZTp2MTQiLAogICAgICAgICAgICAgICIuIgogICAgICAgICAgICBdLAogICAgICAgICAgICAibmFtZSI6ICJnY3IuaW8vY2xvdWQtYnVpbGRlcnMvZG9ja2VyIiwKICAgICAgICAgICAgInB1bGxUaW1pbmciOiB7CiAgICAgICAgICAgICAgImVuZFRpbWUiOiAiMjAyMi0wOC0xNVQyMjo0MzoyMS42NjIwMTY1MzNaIiwKICAgICAgICAgICAgICAic3RhcnRUaW1lIjogIjIwMjItMDgtMTVUMjI6NDM6MjEuNjU3MjYyNDkyWiIKICAgICAgICAgICAgfSwKICAgICAgICAgICAgInN0YXR1cyI6ICJTVUNDRVNTIiwKICAgICAgICAgICAgInRpbWluZyI6IHsKICAgICAgICAgICAgICAiZW5kVGltZSI6ICIyMDIyLTA4LTE1VDIyOjQzOjI3LjA1NjM3NzQ0MVoiLAogICAgICAgICAgICAgICJzdGFydFRpbWUiOiAiMjAyMi0wOC0xNVQyMjo0MzoyMS42NTcyNjI0OTJaIgogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgXQogICAgICB9LAogICAgICAiZW50cnlQb2ludCI6ICJjbG91ZGJ1aWxkLnlhbWwiLAogICAgICAidHlwZSI6ICJodHRwczovL2Nsb3VkYnVpbGQuZ29vZ2xlYXBpcy5jb20vR29vZ2xlSG9zdGVkV29ya2VyQHYwLjIiCiAgICB9CiAgfSwKICAicHJlZGljYXRlVHlwZSI6ICJodHRwczovL3Nsc2EuZGV2L3Byb3ZlbmFuY2UvdjAuMSIsCiAgInNsc2FQcm92ZW5hbmNlIjogewogICAgImJ1aWxkZXIiOiB7CiAgICAgICJpZCI6ICJodHRwczovL2Nsb3VkYnVpbGQuZ29vZ2xlYXBpcy5jb20vR29vZ2xlSG9zdGVkV29ya2VyQHYwLjIiCiAgICB9LAogICAgIm1hdGVyaWFscyI6IFsKICAgICAgewogICAgICAgICJ1cmkiOiAiaHR0cHM6Ly9naXRodWIuY29tL2xhdXJlbnRzaW1vbi9nY2ItdGVzdHMvY29tbWl0L2ZiYmI5ODc2NWU4NWFkNDY0MzAyZGM1OTc3OTY4MTA0ZDM2ZTQ1NWUiCiAgICAgIH0KICAgIF0sCiAgICAibWV0YWRhdGEiOiB7CiAgICAgICJidWlsZEZpbmlzaGVkT24iOiAiMjAyMi0wOC0xNVQyMjo0MzozNC4zNjY0OThaIiwKICAgICAgImJ1aWxkSW52b2NhdGlvbklkIjogImI2ZTA1MmE3LTVhYTQtNDFiZi1hNTZiLTliYzRlNGYzMDU4YiIsCiAgICAgICJidWlsZFN0YXJ0ZWRPbiI6ICIyMDIyLTA4LTE1VDIyOjQzOjE4LjcwMDYzODE4N1oiCiAgICB9LAogICAgInJlY2lwZSI6IHsKICAgICAgImFyZ3VtZW50cyI6IHsKICAgICAgICAiQHR5cGUiOiAidHlwZS5nb29nbGVhcGlzLmNvbS9nb29nbGUuZGV2dG9vbHMuY2xvdWRidWlsZC52MS5CdWlsZCIsCiAgICAgICAgImlkIjogImI2ZTA1MmE3LTVhYTQtNDFiZi1hNTZiLTliYzRlNGYzMDU4YiIsCiAgICAgICAgIm9wdGlvbnMiOiB7CiAgICAgICAgICAiZHluYW1pY1N1YnN0aXR1dGlvbnMiOiB0cnVlLAogICAgICAgICAgImxvZ2dpbmciOiAiTEVHQUNZIiwKICAgICAgICAgICJwb29sIjoge30sCiAgICAgICAgICAic3Vic3RpdHV0aW9uT3B0aW9uIjogIkFMTE9XX0xPT1NFIgogICAgICAgIH0sCiAgICAgICAgInNvdXJjZVByb3ZlbmFuY2UiOiB7fSwKICAgICAgICAic3RlcHMiOiBbCiAgICAgICAgICB7CiAgICAgICAgICAgICJhcmdzIjogWwogICAgICAgICAgICAgICJidWlsZCIsCiAgICAgICAgICAgICAgIi10IiwKICAgICAgICAgICAgICAidXMtd2VzdDItZG9ja2VyLnBrZy5kZXYvZ29zc3Qtc2NhcmUtc2FuZGJveC9xdWlja3N0YXJ0LWRvY2tlci1yZXBvL3F1aWNrc3RhcnQtaW1hZ2U6djE0IiwKICAgICAgICAgICAgICAiLiIKICAgICAgICAgICAgXSwKICAgICAgICAgICAgIm5hbWUiOiAiZ2NyLmlvL2Nsb3VkLWJ1aWxkZXJzL2RvY2tlciIsCiAgICAgICAgICAgICJwdWxsVGltaW5nIjogewogICAgICAgICAgICAgICJlbmRUaW1lIjogIjIwMjItMDgtMTVUMjI6NDM6MjEuNjYyMDE2NTMzWiIsCiAgICAgICAgICAgICAgInN0YXJ0VGltZSI6ICIyMDIyLTA4LTE1VDIyOjQzOjIxLjY1NzI2MjQ5MloiCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgICJzdGF0dXMiOiAiU1VDQ0VTUyIsCiAgICAgICAgICAgICJ0aW1pbmciOiB7CiAgICAgICAgICAgICAgImVuZFRpbWUiOiAiMjAyMi0wOC0xNVQyMjo0MzoyNy4wNTYzNzc0NDFaIiwKICAgICAgICAgICAgICAic3RhcnRUaW1lIjogIjIwMjItMDgtMTVUMjI6NDM6MjEuNjU3MjYyNDkyWiIKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgIF0KICAgICAgfSwKICAgICAgImVudHJ5UG9pbnQiOiAiY2xvdWRidWlsZC55YW1sIiwKICAgICAgInR5cGUiOiAiaHR0cHM6Ly9jbG91ZGJ1aWxkLmdvb2dsZWFwaXMuY29tL0dvb2dsZUhvc3RlZFdvcmtlckB2MC4yIgogICAgfQogIH0sCiAgInN1YmplY3QiOiBbCiAgICB7CiAgICAgICJkaWdlc3QiOiB7CiAgICAgICAgInNoYTI1NiI6ICIxYTAzM2IwMDJmODllZDJiOGVhNzMzMTYyNDk3ZmI3MGYxYTQwNDlhN2Y4NjAyZDZhMzM2ODJiNGFkOTkyMWZkIgogICAgICB9LAogICAgICAibmFtZSI6ICJodHRwczovL3VzLXdlc3QyLWRvY2tlci5wa2cuZGV2L2dvc3N0LXNjYXJlLXNhbmRib3gvcXVpY2tzdGFydC1kb2NrZXItcmVwby9xdWlja3N0YXJ0LWltYWdlOnYxNCIKICAgIH0KICBdCn0K", + "payloadType": "application/vnd.in-toto+json", + "signatures": [ + { + "keyid": "projects/verified-builder/locations/global/keyRings/attestor/cryptoKeys/builtByGCB/cryptoKeyVersions/1", + "sig": "MEYCIQD-0xUsdkYnsmKnQL_ndEvXknLfn82zsG-hGyYUd4aYsAIhAP4KSCxN2VPNc-dvfrQIGduMUNmAiHxLttdezqdrSf3F" + } + ] + }, + "kind": "BUILD", + "name": "projects/gosst-scare-sandbox/occurrences/8ce06798-f94d-4772-a224-04e473163790", + "noteName": "projects/verified-builder/notes/intoto_b6e052a7-5aa4-41bf-a56b-9bc4e4f3058b", + "resourceUri": "https://us-west2-docker.pkg.dev/gosst-scare-sandbox/quickstart-docker-repo/quickstart-image@sha256:1a033b002f89ed2b8ea733162497fb70f1a4049a7f8602d6a33682b4ad9921fd", + "updateTime": "2022-08-15T22:43:35.649016Z" + } + ] + } +} \ No newline at end of file diff --git a/verifiers/internal/gcb/testdata/gcloud-container-invalid-kind.json b/verifiers/internal/gcb/testdata/gcloud-container-invalid-kind.json new file mode 100644 index 000000000..62e1e9d3d --- /dev/null +++ b/verifiers/internal/gcb/testdata/gcloud-container-invalid-kind.json @@ -0,0 +1,95 @@ +{ + "image_summary": { + "digest": "sha256:1a033b002f89ed2b8ea733162497fb70f1a4049a7f8602d6a33682b4ad9921fd", + "fully_qualified_digest": "us-west2-docker.pkg.dev/gosst-scare-sandbox/quickstart-docker-repo/quickstart-image@sha256:1a033b002f89ed2b8ea733162497fb70f1a4049a7f8602d6a33682b4ad9921fd", + "registry": "us-west2-docker.pkg.dev", + "repository": "quickstart-docker-repo" + }, + "provenance_summary": { + "provenance": [ + { + "build": { + "intotoStatement": { + "_type": "https://in-toto.io/Statement/v0.1", + "predicateType": "https://slsa.dev/provenance/v0.1", + "slsaProvenance": { + "builder": { + "id": "https://cloudbuild.googleapis.com/GoogleHostedWorker@v0.2" + }, + "materials": [ + { + "uri": "https://github.com/laurentsimon/gcb-tests/commit/fbbb98765e85ad464302dc5977968104d36e455e" + } + ], + "metadata": { + "buildFinishedOn": "2022-08-15T22:43:34.366498Z", + "buildInvocationId": "b6e052a7-5aa4-41bf-a56b-9bc4e4f3058b", + "buildStartedOn": "2022-08-15T22:43:18.700638187Z" + }, + "recipe": { + "arguments": { + "@type": "type.googleapis.com/google.devtools.cloudbuild.v1.Build", + "id": "b6e052a7-5aa4-41bf-a56b-9bc4e4f3058b", + "options": { + "dynamicSubstitutions": true, + "logging": "LEGACY", + "pool": {}, + "substitutionOption": "ALLOW_LOOSE" + }, + "sourceProvenance": {}, + "steps": [ + { + "args": [ + "build", + "-t", + "us-west2-docker.pkg.dev/gosst-scare-sandbox/quickstart-docker-repo/quickstart-image:v14", + "." + ], + "name": "gcr.io/cloud-builders/docker", + "pullTiming": { + "endTime": "2022-08-15T22:43:21.662016533Z", + "startTime": "2022-08-15T22:43:21.657262492Z" + }, + "status": "SUCCESS", + "timing": { + "endTime": "2022-08-15T22:43:27.056377441Z", + "startTime": "2022-08-15T22:43:21.657262492Z" + } + } + ] + }, + "entryPoint": "cloudbuild.yaml", + "type": "https://cloudbuild.googleapis.com/GoogleHostedWorker@v0.2" + } + }, + "subject": [ + { + "digest": { + "sha256": "1a033b002f89ed2b8ea733162497fb70f1a4049a7f8602d6a33682b4ad9921fd" + }, + "name": "https://us-west2-docker.pkg.dev/gosst-scare-sandbox/quickstart-docker-repo/quickstart-image:v14" + } + ] + } + }, + "createTime": "2022-08-15T22:43:35.649016Z", + "envelope": { + "payload": "eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjAuMSIsInByZWRpY2F0ZSI6eyJidWlsZGVyIjp7ImlkIjoiaHR0cHM6Ly9jbG91ZGJ1aWxkLmdvb2dsZWFwaXMuY29tL0dvb2dsZUhvc3RlZFdvcmtlckB2MC4yIn0sIm1hdGVyaWFscyI6W3sidXJpIjoiaHR0cHM6Ly9naXRodWIuY29tL2xhdXJlbnRzaW1vbi9nY2ItdGVzdHMvY29tbWl0L2ZiYmI5ODc2NWU4NWFkNDY0MzAyZGM1OTc3OTY4MTA0ZDM2ZTQ1NWUifV0sIm1ldGFkYXRhIjp7ImJ1aWxkRmluaXNoZWRPbiI6IjIwMjItMDgtMTVUMjI6NDM6MzQuMzY2NDk4WiIsImJ1aWxkSW52b2NhdGlvbklkIjoiYjZlMDUyYTctNWFhNC00MWJmLWE1NmItOWJjNGU0ZjMwNThiIiwiYnVpbGRTdGFydGVkT24iOiIyMDIyLTA4LTE1VDIyOjQzOjE4LjcwMDYzODE4N1oifSwicmVjaXBlIjp7ImFyZ3VtZW50cyI6eyJAdHlwZSI6InR5cGUuZ29vZ2xlYXBpcy5jb20vZ29vZ2xlLmRldnRvb2xzLmNsb3VkYnVpbGQudjEuQnVpbGQiLCJpZCI6ImI2ZTA1MmE3LTVhYTQtNDFiZi1hNTZiLTliYzRlNGYzMDU4YiIsIm9wdGlvbnMiOnsiZHluYW1pY1N1YnN0aXR1dGlvbnMiOnRydWUsImxvZ2dpbmciOiJMRUdBQ1kiLCJwb29sIjp7fSwic3Vic3RpdHV0aW9uT3B0aW9uIjoiQUxMT1dfTE9PU0UifSwic291cmNlUHJvdmVuYW5jZSI6e30sInN0ZXBzIjpbeyJhcmdzIjpbImJ1aWxkIiwiLXQiLCJ1cy13ZXN0Mi1kb2NrZXIucGtnLmRldi9nb3NzdC1zY2FyZS1zYW5kYm94L3F1aWNrc3RhcnQtZG9ja2VyLXJlcG8vcXVpY2tzdGFydC1pbWFnZTp2MTQiLCIuIl0sIm5hbWUiOiJnY3IuaW8vY2xvdWQtYnVpbGRlcnMvZG9ja2VyIiwicHVsbFRpbWluZyI6eyJlbmRUaW1lIjoiMjAyMi0wOC0xNVQyMjo0MzoyMS42NjIwMTY1MzNaIiwic3RhcnRUaW1lIjoiMjAyMi0wOC0xNVQyMjo0MzoyMS42NTcyNjI0OTJaIn0sInN0YXR1cyI6IlNVQ0NFU1MiLCJ0aW1pbmciOnsiZW5kVGltZSI6IjIwMjItMDgtMTVUMjI6NDM6MjcuMDU2Mzc3NDQxWiIsInN0YXJ0VGltZSI6IjIwMjItMDgtMTVUMjI6NDM6MjEuNjU3MjYyNDkyWiJ9fV19LCJlbnRyeVBvaW50IjoiY2xvdWRidWlsZC55YW1sIiwidHlwZSI6Imh0dHBzOi8vY2xvdWRidWlsZC5nb29nbGVhcGlzLmNvbS9Hb29nbGVIb3N0ZWRXb3JrZXJAdjAuMiJ9fSwicHJlZGljYXRlVHlwZSI6Imh0dHBzOi8vc2xzYS5kZXYvcHJvdmVuYW5jZS92MC4xIiwic2xzYVByb3ZlbmFuY2UiOnsiYnVpbGRlciI6eyJpZCI6Imh0dHBzOi8vY2xvdWRidWlsZC5nb29nbGVhcGlzLmNvbS9Hb29nbGVIb3N0ZWRXb3JrZXJAdjAuMiJ9LCJtYXRlcmlhbHMiOlt7InVyaSI6Imh0dHBzOi8vZ2l0aHViLmNvbS9sYXVyZW50c2ltb24vZ2NiLXRlc3RzL2NvbW1pdC9mYmJiOTg3NjVlODVhZDQ2NDMwMmRjNTk3Nzk2ODEwNGQzNmU0NTVlIn1dLCJtZXRhZGF0YSI6eyJidWlsZEZpbmlzaGVkT24iOiIyMDIyLTA4LTE1VDIyOjQzOjM0LjM2NjQ5OFoiLCJidWlsZEludm9jYXRpb25JZCI6ImI2ZTA1MmE3LTVhYTQtNDFiZi1hNTZiLTliYzRlNGYzMDU4YiIsImJ1aWxkU3RhcnRlZE9uIjoiMjAyMi0wOC0xNVQyMjo0MzoxOC43MDA2MzgxODdaIn0sInJlY2lwZSI6eyJhcmd1bWVudHMiOnsiQHR5cGUiOiJ0eXBlLmdvb2dsZWFwaXMuY29tL2dvb2dsZS5kZXZ0b29scy5jbG91ZGJ1aWxkLnYxLkJ1aWxkIiwiaWQiOiJiNmUwNTJhNy01YWE0LTQxYmYtYTU2Yi05YmM0ZTRmMzA1OGIiLCJvcHRpb25zIjp7ImR5bmFtaWNTdWJzdGl0dXRpb25zIjp0cnVlLCJsb2dnaW5nIjoiTEVHQUNZIiwicG9vbCI6e30sInN1YnN0aXR1dGlvbk9wdGlvbiI6IkFMTE9XX0xPT1NFIn0sInNvdXJjZVByb3ZlbmFuY2UiOnt9LCJzdGVwcyI6W3siYXJncyI6WyJidWlsZCIsIi10IiwidXMtd2VzdDItZG9ja2VyLnBrZy5kZXYvZ29zc3Qtc2NhcmUtc2FuZGJveC9xdWlja3N0YXJ0LWRvY2tlci1yZXBvL3F1aWNrc3RhcnQtaW1hZ2U6djE0IiwiLiJdLCJuYW1lIjoiZ2NyLmlvL2Nsb3VkLWJ1aWxkZXJzL2RvY2tlciIsInB1bGxUaW1pbmciOnsiZW5kVGltZSI6IjIwMjItMDgtMTVUMjI6NDM6MjEuNjYyMDE2NTMzWiIsInN0YXJ0VGltZSI6IjIwMjItMDgtMTVUMjI6NDM6MjEuNjU3MjYyNDkyWiJ9LCJzdGF0dXMiOiJTVUNDRVNTIiwidGltaW5nIjp7ImVuZFRpbWUiOiIyMDIyLTA4LTE1VDIyOjQzOjI3LjA1NjM3NzQ0MVoiLCJzdGFydFRpbWUiOiIyMDIyLTA4LTE1VDIyOjQzOjIxLjY1NzI2MjQ5MloifX1dfSwiZW50cnlQb2ludCI6ImNsb3VkYnVpbGQueWFtbCIsInR5cGUiOiJodHRwczovL2Nsb3VkYnVpbGQuZ29vZ2xlYXBpcy5jb20vR29vZ2xlSG9zdGVkV29ya2VyQHYwLjIifX0sInN1YmplY3QiOlt7ImRpZ2VzdCI6eyJzaGEyNTYiOiIxYTAzM2IwMDJmODllZDJiOGVhNzMzMTYyNDk3ZmI3MGYxYTQwNDlhN2Y4NjAyZDZhMzM2ODJiNGFkOTkyMWZkIn0sIm5hbWUiOiJodHRwczovL3VzLXdlc3QyLWRvY2tlci5wa2cuZGV2L2dvc3N0LXNjYXJlLXNhbmRib3gvcXVpY2tzdGFydC1kb2NrZXItcmVwby9xdWlja3N0YXJ0LWltYWdlOnYxNCJ9XX0=", + "payloadType": "application/vnd.in-toto+json", + "signatures": [ + { + "keyid": "projects/verified-builder/locations/global/keyRings/attestor/cryptoKeys/builtByGCB/cryptoKeyVersions/1", + "sig": "MEYCIQD-0xUsdkYnsmKnQL_ndEvXknLfn82zsG-hGyYUd4aYsAIhAP4KSCxN2VPNc-dvfrQIGduMUNmAiHxLttdezqdrSf3F" + } + ] + }, + "kind": "BUILDN", + "name": "projects/gosst-scare-sandbox/occurrences/8ce06798-f94d-4772-a224-04e473163790", + "noteName": "projects/verified-builder/notes/intoto_b6e052a7-5aa4-41bf-a56b-9bc4e4f3058b", + "resourceUri": "https://us-west2-docker.pkg.dev/gosst-scare-sandbox/quickstart-docker-repo/quickstart-image@sha256:1a033b002f89ed2b8ea733162497fb70f1a4049a7f8602d6a33682b4ad9921fd", + "updateTime": "2022-08-15T22:43:35.649016Z" + } + ] + } + } + \ No newline at end of file diff --git a/verifiers/internal/gcb/testdata/gcloud-container-invalid-recipe.arguments.type.json b/verifiers/internal/gcb/testdata/gcloud-container-invalid-recipe.arguments.type.json new file mode 100644 index 000000000..1b7a07dee --- /dev/null +++ b/verifiers/internal/gcb/testdata/gcloud-container-invalid-recipe.arguments.type.json @@ -0,0 +1,94 @@ +{ + "image_summary": { + "digest": "sha256:1a033b002f89ed2b8ea733162497fb70f1a4049a7f8602d6a33682b4ad9921fd", + "fully_qualified_digest": "us-west2-docker.pkg.dev/gosst-scare-sandbox/quickstart-docker-repo/quickstart-image@sha256:1a033b002f89ed2b8ea733162497fb70f1a4049a7f8602d6a33682b4ad9921fd", + "registry": "us-west2-docker.pkg.dev", + "repository": "quickstart-docker-repo" + }, + "provenance_summary": { + "provenance": [ + { + "build": { + "intotoStatement": { + "_type": "https://in-toto.io/Statement/v0.1", + "predicateType": "https://slsa.dev/provenance/v0.1", + "slsaProvenance": { + "builder": { + "id": "https://cloudbuild.googleapis.com/GoogleHostedWorker@v0.2" + }, + "materials": [ + { + "uri": "https://github.com/laurentsimon/gcb-tests/commit/fbbb98765e85ad464302dc5977968104d36e455e" + } + ], + "metadata": { + "buildFinishedOn": "2022-08-15T22:43:34.366498Z", + "buildInvocationId": "b6e052a7-5aa4-41bf-a56b-9bc4e4f3058b", + "buildStartedOn": "2022-08-15T22:43:18.700638187Z" + }, + "recipe": { + "arguments": { + "@type": "type.googleapis.com/google.devtools.cloudbuild.v1.Build", + "id": "b6e052a7-5aa4-41bf-a56b-9bc4e4f3058b", + "options": { + "dynamicSubstitutions": true, + "logging": "LEGACY", + "pool": {}, + "substitutionOption": "ALLOW_LOOSE" + }, + "sourceProvenance": {}, + "steps": [ + { + "args": [ + "build", + "-t", + "us-west2-docker.pkg.dev/gosst-scare-sandbox/quickstart-docker-repo/quickstart-image:v14", + "." + ], + "name": "gcr.io/cloud-builders/docker", + "pullTiming": { + "endTime": "2022-08-15T22:43:21.662016533Z", + "startTime": "2022-08-15T22:43:21.657262492Z" + }, + "status": "SUCCESS", + "timing": { + "endTime": "2022-08-15T22:43:27.056377441Z", + "startTime": "2022-08-15T22:43:21.657262492Z" + } + } + ] + }, + "entryPoint": "cloudbuild.yaml", + "type": "https://cloudbuild.googleapis.com/GoogleHostedWorker@v0.2" + } + }, + "subject": [ + { + "digest": { + "sha256": "1a033b002f89ed2b8ea733162497fb70f1a4049a7f8602d6a33682b4ad9921fd" + }, + "name": "https://us-west2-docker.pkg.dev/gosst-scare-sandbox/quickstart-docker-repo/quickstart-image:v14" + } + ] + } + }, + "createTime": "2022-08-15T22:43:35.649016Z", + "envelope": { + "payload": "ewogICAgIl90eXBlIjogImh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjAuMSIsCiAgICAicHJlZGljYXRlIjogewogICAgICAiYnVpbGRlciI6IHsKICAgICAgICAiaWQiOiAiaHR0cHM6Ly9jbG91ZGJ1aWxkLmdvb2dsZWFwaXMuY29tL0dvb2dsZUhvc3RlZFdvcmtlckB2MC4yIgogICAgICB9LAogICAgICAibWF0ZXJpYWxzIjogWwogICAgICAgIHsKICAgICAgICAgICJ1cmkiOiAiaHR0cHM6Ly9naXRodWIuY29tL2xhdXJlbnRzaW1vbi9nY2ItdGVzdHMvY29tbWl0L2ZiYmI5ODc2NWU4NWFkNDY0MzAyZGM1OTc3OTY4MTA0ZDM2ZTQ1NWUiCiAgICAgICAgfQogICAgICBdLAogICAgICAibWV0YWRhdGEiOiB7CiAgICAgICAgImJ1aWxkRmluaXNoZWRPbiI6ICIyMDIyLTA4LTE1VDIyOjQzOjM0LjM2NjQ5OFoiLAogICAgICAgICJidWlsZEludm9jYXRpb25JZCI6ICJiNmUwNTJhNy01YWE0LTQxYmYtYTU2Yi05YmM0ZTRmMzA1OGIiLAogICAgICAgICJidWlsZFN0YXJ0ZWRPbiI6ICIyMDIyLTA4LTE1VDIyOjQzOjE4LjcwMDYzODE4N1oiCiAgICAgIH0sCiAgICAgICJyZWNpcGUiOiB7CiAgICAgICAgImFyZ3VtZW50cyI6IHsKICAgICAgICAgICJAdHlwZSI6ICJ0eXBlLmdvb2dsZWFwaXMuY29tL2dvb2dsZS5kZXZ0b29scy5jbG91ZGJ1aWxkLnYyLkJ1aWxkIiwKICAgICAgICAgICJpZCI6ICJiNmUwNTJhNy01YWE0LTQxYmYtYTU2Yi05YmM0ZTRmMzA1OGIiLAogICAgICAgICAgIm9wdGlvbnMiOiB7CiAgICAgICAgICAgICJkeW5hbWljU3Vic3RpdHV0aW9ucyI6IHRydWUsCiAgICAgICAgICAgICJsb2dnaW5nIjogIkxFR0FDWSIsCiAgICAgICAgICAgICJwb29sIjoge30sCiAgICAgICAgICAgICJzdWJzdGl0dXRpb25PcHRpb24iOiAiQUxMT1dfTE9PU0UiCiAgICAgICAgICB9LAogICAgICAgICAgInNvdXJjZVByb3ZlbmFuY2UiOiB7fSwKICAgICAgICAgICJzdGVwcyI6IFsKICAgICAgICAgICAgewogICAgICAgICAgICAgICJhcmdzIjogWwogICAgICAgICAgICAgICAgImJ1aWxkIiwKICAgICAgICAgICAgICAgICItdCIsCiAgICAgICAgICAgICAgICAidXMtd2VzdDItZG9ja2VyLnBrZy5kZXYvZ29zc3Qtc2NhcmUtc2FuZGJveC9xdWlja3N0YXJ0LWRvY2tlci1yZXBvL3F1aWNrc3RhcnQtaW1hZ2U6djE0IiwKICAgICAgICAgICAgICAgICIuIgogICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgIm5hbWUiOiAiZ2NyLmlvL2Nsb3VkLWJ1aWxkZXJzL2RvY2tlciIsCiAgICAgICAgICAgICAgInB1bGxUaW1pbmciOiB7CiAgICAgICAgICAgICAgICAiZW5kVGltZSI6ICIyMDIyLTA4LTE1VDIyOjQzOjIxLjY2MjAxNjUzM1oiLAogICAgICAgICAgICAgICAgInN0YXJ0VGltZSI6ICIyMDIyLTA4LTE1VDIyOjQzOjIxLjY1NzI2MjQ5MloiCiAgICAgICAgICAgICAgfSwKICAgICAgICAgICAgICAic3RhdHVzIjogIlNVQ0NFU1MiLAogICAgICAgICAgICAgICJ0aW1pbmciOiB7CiAgICAgICAgICAgICAgICAiZW5kVGltZSI6ICIyMDIyLTA4LTE1VDIyOjQzOjI3LjA1NjM3NzQ0MVoiLAogICAgICAgICAgICAgICAgInN0YXJ0VGltZSI6ICIyMDIyLTA4LTE1VDIyOjQzOjIxLjY1NzI2MjQ5MloiCiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICBdCiAgICAgICAgfSwKICAgICAgICAiZW50cnlQb2ludCI6ICJjbG91ZGJ1aWxkLnlhbWwiLAogICAgICAgICJ0eXBlIjogImh0dHBzOi8vY2xvdWRidWlsZC5nb29nbGVhcGlzLmNvbS9Hb29nbGVIb3N0ZWRXb3JrZXJAdjAuMiIKICAgICAgfQogICAgfSwKICAgICJwcmVkaWNhdGVUeXBlIjogImh0dHBzOi8vc2xzYS5kZXYvcHJvdmVuYW5jZS92MC4xIiwKICAgICJzbHNhUHJvdmVuYW5jZSI6IHsKICAgICAgImJ1aWxkZXIiOiB7CiAgICAgICAgImlkIjogImh0dHBzOi8vY2xvdWRidWlsZC5nb29nbGVhcGlzLmNvbS9Hb29nbGVIb3N0ZWRXb3JrZXJAdjAuMiIKICAgICAgfSwKICAgICAgIm1hdGVyaWFscyI6IFsKICAgICAgICB7CiAgICAgICAgICAidXJpIjogImh0dHBzOi8vZ2l0aHViLmNvbS9sYXVyZW50c2ltb24vZ2NiLXRlc3RzL2NvbW1pdC9mYmJiOTg3NjVlODVhZDQ2NDMwMmRjNTk3Nzk2ODEwNGQzNmU0NTVlIgogICAgICAgIH0KICAgICAgXSwKICAgICAgIm1ldGFkYXRhIjogewogICAgICAgICJidWlsZEZpbmlzaGVkT24iOiAiMjAyMi0wOC0xNVQyMjo0MzozNC4zNjY0OThaIiwKICAgICAgICAiYnVpbGRJbnZvY2F0aW9uSWQiOiAiYjZlMDUyYTctNWFhNC00MWJmLWE1NmItOWJjNGU0ZjMwNThiIiwKICAgICAgICAiYnVpbGRTdGFydGVkT24iOiAiMjAyMi0wOC0xNVQyMjo0MzoxOC43MDA2MzgxODdaIgogICAgICB9LAogICAgICAicmVjaXBlIjogewogICAgICAgICJhcmd1bWVudHMiOiB7CiAgICAgICAgICAiQHR5cGUiOiAidHlwZS5nb29nbGVhcGlzLmNvbS9nb29nbGUuZGV2dG9vbHMuY2xvdWRidWlsZC52MS5CdWlsZCIsCiAgICAgICAgICAiaWQiOiAiYjZlMDUyYTctNWFhNC00MWJmLWE1NmItOWJjNGU0ZjMwNThiIiwKICAgICAgICAgICJvcHRpb25zIjogewogICAgICAgICAgICAiZHluYW1pY1N1YnN0aXR1dGlvbnMiOiB0cnVlLAogICAgICAgICAgICAibG9nZ2luZyI6ICJMRUdBQ1kiLAogICAgICAgICAgICAicG9vbCI6IHt9LAogICAgICAgICAgICAic3Vic3RpdHV0aW9uT3B0aW9uIjogIkFMTE9XX0xPT1NFIgogICAgICAgICAgfSwKICAgICAgICAgICJzb3VyY2VQcm92ZW5hbmNlIjoge30sCiAgICAgICAgICAic3RlcHMiOiBbCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAiYXJncyI6IFsKICAgICAgICAgICAgICAgICJidWlsZCIsCiAgICAgICAgICAgICAgICAiLXQiLAogICAgICAgICAgICAgICAgInVzLXdlc3QyLWRvY2tlci5wa2cuZGV2L2dvc3N0LXNjYXJlLXNhbmRib3gvcXVpY2tzdGFydC1kb2NrZXItcmVwby9xdWlja3N0YXJ0LWltYWdlOnYxNCIsCiAgICAgICAgICAgICAgICAiLiIKICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICJuYW1lIjogImdjci5pby9jbG91ZC1idWlsZGVycy9kb2NrZXIiLAogICAgICAgICAgICAgICJwdWxsVGltaW5nIjogewogICAgICAgICAgICAgICAgImVuZFRpbWUiOiAiMjAyMi0wOC0xNVQyMjo0MzoyMS42NjIwMTY1MzNaIiwKICAgICAgICAgICAgICAgICJzdGFydFRpbWUiOiAiMjAyMi0wOC0xNVQyMjo0MzoyMS42NTcyNjI0OTJaIgogICAgICAgICAgICAgIH0sCiAgICAgICAgICAgICAgInN0YXR1cyI6ICJTVUNDRVNTIiwKICAgICAgICAgICAgICAidGltaW5nIjogewogICAgICAgICAgICAgICAgImVuZFRpbWUiOiAiMjAyMi0wOC0xNVQyMjo0MzoyNy4wNTYzNzc0NDFaIiwKICAgICAgICAgICAgICAgICJzdGFydFRpbWUiOiAiMjAyMi0wOC0xNVQyMjo0MzoyMS42NTcyNjI0OTJaIgogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgXQogICAgICAgIH0sCiAgICAgICAgImVudHJ5UG9pbnQiOiAiY2xvdWRidWlsZC55YW1sIiwKICAgICAgICAidHlwZSI6ICJodHRwczovL2Nsb3VkYnVpbGQuZ29vZ2xlYXBpcy5jb20vR29vZ2xlSG9zdGVkV29ya2VyQHYwLjIiCiAgICAgIH0KICAgIH0sCiAgICAic3ViamVjdCI6IFsKICAgICAgewogICAgICAgICJkaWdlc3QiOiB7CiAgICAgICAgICAic2hhMjU2IjogIjFhMDMzYjAwMmY4OWVkMmI4ZWE3MzMxNjI0OTdmYjcwZjFhNDA0OWE3Zjg2MDJkNmEzMzY4MmI0YWQ5OTIxZmQiCiAgICAgICAgfSwKICAgICAgICAibmFtZSI6ICJodHRwczovL3VzLXdlc3QyLWRvY2tlci5wa2cuZGV2L2dvc3N0LXNjYXJlLXNhbmRib3gvcXVpY2tzdGFydC1kb2NrZXItcmVwby9xdWlja3N0YXJ0LWltYWdlOnYxNCIKICAgICAgfQogICAgXQogIH0KICA=", + "payloadType": "application/vnd.in-toto+json", + "signatures": [ + { + "keyid": "projects/verified-builder/locations/global/keyRings/attestor/cryptoKeys/builtByGCB/cryptoKeyVersions/1", + "sig": "MEYCIQD-0xUsdkYnsmKnQL_ndEvXknLfn82zsG-hGyYUd4aYsAIhAP4KSCxN2VPNc-dvfrQIGduMUNmAiHxLttdezqdrSf3F" + } + ] + }, + "kind": "BUILD", + "name": "projects/gosst-scare-sandbox/occurrences/8ce06798-f94d-4772-a224-04e473163790", + "noteName": "projects/verified-builder/notes/intoto_b6e052a7-5aa4-41bf-a56b-9bc4e4f3058b", + "resourceUri": "https://us-west2-docker.pkg.dev/gosst-scare-sandbox/quickstart-docker-repo/quickstart-image@sha256:1a033b002f89ed2b8ea733162497fb70f1a4049a7f8602d6a33682b4ad9921fd", + "updateTime": "2022-08-15T22:43:35.649016Z" + } + ] + } +} diff --git a/verifiers/internal/gcb/testdata/gcloud-container-invalid-recipe.type.json b/verifiers/internal/gcb/testdata/gcloud-container-invalid-recipe.type.json new file mode 100644 index 000000000..30e2371f2 --- /dev/null +++ b/verifiers/internal/gcb/testdata/gcloud-container-invalid-recipe.type.json @@ -0,0 +1,94 @@ +{ + "image_summary": { + "digest": "sha256:1a033b002f89ed2b8ea733162497fb70f1a4049a7f8602d6a33682b4ad9921fd", + "fully_qualified_digest": "us-west2-docker.pkg.dev/gosst-scare-sandbox/quickstart-docker-repo/quickstart-image@sha256:1a033b002f89ed2b8ea733162497fb70f1a4049a7f8602d6a33682b4ad9921fd", + "registry": "us-west2-docker.pkg.dev", + "repository": "quickstart-docker-repo" + }, + "provenance_summary": { + "provenance": [ + { + "build": { + "intotoStatement": { + "_type": "https://in-toto.io/Statement/v0.1", + "predicateType": "https://slsa.dev/provenance/v0.1", + "slsaProvenance": { + "builder": { + "id": "https://cloudbuild.googleapis.com/GoogleHostedWorker@v0.2" + }, + "materials": [ + { + "uri": "https://github.com/laurentsimon/gcb-tests/commit/fbbb98765e85ad464302dc5977968104d36e455e" + } + ], + "metadata": { + "buildFinishedOn": "2022-08-15T22:43:34.366498Z", + "buildInvocationId": "b6e052a7-5aa4-41bf-a56b-9bc4e4f3058b", + "buildStartedOn": "2022-08-15T22:43:18.700638187Z" + }, + "recipe": { + "arguments": { + "@type": "type.googleapis.com/google.devtools.cloudbuild.v1.Build", + "id": "b6e052a7-5aa4-41bf-a56b-9bc4e4f3058b", + "options": { + "dynamicSubstitutions": true, + "logging": "LEGACY", + "pool": {}, + "substitutionOption": "ALLOW_LOOSE" + }, + "sourceProvenance": {}, + "steps": [ + { + "args": [ + "build", + "-t", + "us-west2-docker.pkg.dev/gosst-scare-sandbox/quickstart-docker-repo/quickstart-image:v14", + "." + ], + "name": "gcr.io/cloud-builders/docker", + "pullTiming": { + "endTime": "2022-08-15T22:43:21.662016533Z", + "startTime": "2022-08-15T22:43:21.657262492Z" + }, + "status": "SUCCESS", + "timing": { + "endTime": "2022-08-15T22:43:27.056377441Z", + "startTime": "2022-08-15T22:43:21.657262492Z" + } + } + ] + }, + "entryPoint": "cloudbuild.yaml", + "type": "https://cloudbuild.googleapis.com/GoogleHostedWorker@v0.2" + } + }, + "subject": [ + { + "digest": { + "sha256": "1a033b002f89ed2b8ea733162497fb70f1a4049a7f8602d6a33682b4ad9921fd" + }, + "name": "https://us-west2-docker.pkg.dev/gosst-scare-sandbox/quickstart-docker-repo/quickstart-image:v14" + } + ] + } + }, + "createTime": "2022-08-15T22:43:35.649016Z", + "envelope": { + "payload": "ewogICAgIl90eXBlIjogImh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjAuMSIsCiAgICAicHJlZGljYXRlIjogewogICAgICAiYnVpbGRlciI6IHsKICAgICAgICAiaWQiOiAiaHR0cHM6Ly9jbG91ZGJ1aWxkLmdvb2dsZWFwaXMuY29tL0dvb2dsZUhvc3RlZFdvcmtlckB2MC4yIgogICAgICB9LAogICAgICAibWF0ZXJpYWxzIjogWwogICAgICAgIHsKICAgICAgICAgICJ1cmkiOiAiaHR0cHM6Ly9naXRodWIuY29tL2xhdXJlbnRzaW1vbi9nY2ItdGVzdHMvY29tbWl0L2ZiYmI5ODc2NWU4NWFkNDY0MzAyZGM1OTc3OTY4MTA0ZDM2ZTQ1NWUiCiAgICAgICAgfQogICAgICBdLAogICAgICAibWV0YWRhdGEiOiB7CiAgICAgICAgImJ1aWxkRmluaXNoZWRPbiI6ICIyMDIyLTA4LTE1VDIyOjQzOjM0LjM2NjQ5OFoiLAogICAgICAgICJidWlsZEludm9jYXRpb25JZCI6ICJiNmUwNTJhNy01YWE0LTQxYmYtYTU2Yi05YmM0ZTRmMzA1OGIiLAogICAgICAgICJidWlsZFN0YXJ0ZWRPbiI6ICIyMDIyLTA4LTE1VDIyOjQzOjE4LjcwMDYzODE4N1oiCiAgICAgIH0sCiAgICAgICJyZWNpcGUiOiB7CiAgICAgICAgImFyZ3VtZW50cyI6IHsKICAgICAgICAgICJAdHlwZSI6ICJ0eXBlLmdvb2dsZWFwaXMuY29tL2dvb2dsZS5kZXZ0b29scy5jbG91ZGJ1aWxkLnYxLkJ1aWxkIiwKICAgICAgICAgICJpZCI6ICJiNmUwNTJhNy01YWE0LTQxYmYtYTU2Yi05YmM0ZTRmMzA1OGIiLAogICAgICAgICAgIm9wdGlvbnMiOiB7CiAgICAgICAgICAgICJkeW5hbWljU3Vic3RpdHV0aW9ucyI6IHRydWUsCiAgICAgICAgICAgICJsb2dnaW5nIjogIkxFR0FDWSIsCiAgICAgICAgICAgICJwb29sIjoge30sCiAgICAgICAgICAgICJzdWJzdGl0dXRpb25PcHRpb24iOiAiQUxMT1dfTE9PU0UiCiAgICAgICAgICB9LAogICAgICAgICAgInNvdXJjZVByb3ZlbmFuY2UiOiB7fSwKICAgICAgICAgICJzdGVwcyI6IFsKICAgICAgICAgICAgewogICAgICAgICAgICAgICJhcmdzIjogWwogICAgICAgICAgICAgICAgImJ1aWxkIiwKICAgICAgICAgICAgICAgICItdCIsCiAgICAgICAgICAgICAgICAidXMtd2VzdDItZG9ja2VyLnBrZy5kZXYvZ29zc3Qtc2NhcmUtc2FuZGJveC9xdWlja3N0YXJ0LWRvY2tlci1yZXBvL3F1aWNrc3RhcnQtaW1hZ2U6djE0IiwKICAgICAgICAgICAgICAgICIuIgogICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgIm5hbWUiOiAiZ2NyLmlvL2Nsb3VkLWJ1aWxkZXJzL2RvY2tlciIsCiAgICAgICAgICAgICAgInB1bGxUaW1pbmciOiB7CiAgICAgICAgICAgICAgICAiZW5kVGltZSI6ICIyMDIyLTA4LTE1VDIyOjQzOjIxLjY2MjAxNjUzM1oiLAogICAgICAgICAgICAgICAgInN0YXJ0VGltZSI6ICIyMDIyLTA4LTE1VDIyOjQzOjIxLjY1NzI2MjQ5MloiCiAgICAgICAgICAgICAgfSwKICAgICAgICAgICAgICAic3RhdHVzIjogIlNVQ0NFU1MiLAogICAgICAgICAgICAgICJ0aW1pbmciOiB7CiAgICAgICAgICAgICAgICAiZW5kVGltZSI6ICIyMDIyLTA4LTE1VDIyOjQzOjI3LjA1NjM3NzQ0MVoiLAogICAgICAgICAgICAgICAgInN0YXJ0VGltZSI6ICIyMDIyLTA4LTE1VDIyOjQzOjIxLjY1NzI2MjQ5MloiCiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICBdCiAgICAgICAgfSwKICAgICAgICAiZW50cnlQb2ludCI6ICJjbG91ZGJ1aWxkLnlhbWwiLAogICAgICAgICJ0eXBlIjogImh0dHBzOi8vY2xvdWRidWlsZC5nb29nbGVhcGlzLmNvbS9Hb29nbGVIb3N0ZWRXb3JrZXJAdjAuMSIKICAgICAgfQogICAgfSwKICAgICJwcmVkaWNhdGVUeXBlIjogImh0dHBzOi8vc2xzYS5kZXYvcHJvdmVuYW5jZS92MC4xIiwKICAgICJzbHNhUHJvdmVuYW5jZSI6IHsKICAgICAgImJ1aWxkZXIiOiB7CiAgICAgICAgImlkIjogImh0dHBzOi8vY2xvdWRidWlsZC5nb29nbGVhcGlzLmNvbS9Hb29nbGVIb3N0ZWRXb3JrZXJAdjAuMiIKICAgICAgfSwKICAgICAgIm1hdGVyaWFscyI6IFsKICAgICAgICB7CiAgICAgICAgICAidXJpIjogImh0dHBzOi8vZ2l0aHViLmNvbS9sYXVyZW50c2ltb24vZ2NiLXRlc3RzL2NvbW1pdC9mYmJiOTg3NjVlODVhZDQ2NDMwMmRjNTk3Nzk2ODEwNGQzNmU0NTVlIgogICAgICAgIH0KICAgICAgXSwKICAgICAgIm1ldGFkYXRhIjogewogICAgICAgICJidWlsZEZpbmlzaGVkT24iOiAiMjAyMi0wOC0xNVQyMjo0MzozNC4zNjY0OThaIiwKICAgICAgICAiYnVpbGRJbnZvY2F0aW9uSWQiOiAiYjZlMDUyYTctNWFhNC00MWJmLWE1NmItOWJjNGU0ZjMwNThiIiwKICAgICAgICAiYnVpbGRTdGFydGVkT24iOiAiMjAyMi0wOC0xNVQyMjo0MzoxOC43MDA2MzgxODdaIgogICAgICB9LAogICAgICAicmVjaXBlIjogewogICAgICAgICJhcmd1bWVudHMiOiB7CiAgICAgICAgICAiQHR5cGUiOiAidHlwZS5nb29nbGVhcGlzLmNvbS9nb29nbGUuZGV2dG9vbHMuY2xvdWRidWlsZC52MS5CdWlsZCIsCiAgICAgICAgICAiaWQiOiAiYjZlMDUyYTctNWFhNC00MWJmLWE1NmItOWJjNGU0ZjMwNThiIiwKICAgICAgICAgICJvcHRpb25zIjogewogICAgICAgICAgICAiZHluYW1pY1N1YnN0aXR1dGlvbnMiOiB0cnVlLAogICAgICAgICAgICAibG9nZ2luZyI6ICJMRUdBQ1kiLAogICAgICAgICAgICAicG9vbCI6IHt9LAogICAgICAgICAgICAic3Vic3RpdHV0aW9uT3B0aW9uIjogIkFMTE9XX0xPT1NFIgogICAgICAgICAgfSwKICAgICAgICAgICJzb3VyY2VQcm92ZW5hbmNlIjoge30sCiAgICAgICAgICAic3RlcHMiOiBbCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAiYXJncyI6IFsKICAgICAgICAgICAgICAgICJidWlsZCIsCiAgICAgICAgICAgICAgICAiLXQiLAogICAgICAgICAgICAgICAgInVzLXdlc3QyLWRvY2tlci5wa2cuZGV2L2dvc3N0LXNjYXJlLXNhbmRib3gvcXVpY2tzdGFydC1kb2NrZXItcmVwby9xdWlja3N0YXJ0LWltYWdlOnYxNCIsCiAgICAgICAgICAgICAgICAiLiIKICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICJuYW1lIjogImdjci5pby9jbG91ZC1idWlsZGVycy9kb2NrZXIiLAogICAgICAgICAgICAgICJwdWxsVGltaW5nIjogewogICAgICAgICAgICAgICAgImVuZFRpbWUiOiAiMjAyMi0wOC0xNVQyMjo0MzoyMS42NjIwMTY1MzNaIiwKICAgICAgICAgICAgICAgICJzdGFydFRpbWUiOiAiMjAyMi0wOC0xNVQyMjo0MzoyMS42NTcyNjI0OTJaIgogICAgICAgICAgICAgIH0sCiAgICAgICAgICAgICAgInN0YXR1cyI6ICJTVUNDRVNTIiwKICAgICAgICAgICAgICAidGltaW5nIjogewogICAgICAgICAgICAgICAgImVuZFRpbWUiOiAiMjAyMi0wOC0xNVQyMjo0MzoyNy4wNTYzNzc0NDFaIiwKICAgICAgICAgICAgICAgICJzdGFydFRpbWUiOiAiMjAyMi0wOC0xNVQyMjo0MzoyMS42NTcyNjI0OTJaIgogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgXQogICAgICAgIH0sCiAgICAgICAgImVudHJ5UG9pbnQiOiAiY2xvdWRidWlsZC55YW1sIiwKICAgICAgICAidHlwZSI6ICJodHRwczovL2Nsb3VkYnVpbGQuZ29vZ2xlYXBpcy5jb20vR29vZ2xlSG9zdGVkV29ya2VyQHYwLjIiCiAgICAgIH0KICAgIH0sCiAgICAic3ViamVjdCI6IFsKICAgICAgewogICAgICAgICJkaWdlc3QiOiB7CiAgICAgICAgICAic2hhMjU2IjogIjFhMDMzYjAwMmY4OWVkMmI4ZWE3MzMxNjI0OTdmYjcwZjFhNDA0OWE3Zjg2MDJkNmEzMzY4MmI0YWQ5OTIxZmQiCiAgICAgICAgfSwKICAgICAgICAibmFtZSI6ICJodHRwczovL3VzLXdlc3QyLWRvY2tlci5wa2cuZGV2L2dvc3N0LXNjYXJlLXNhbmRib3gvcXVpY2tzdGFydC1kb2NrZXItcmVwby9xdWlja3N0YXJ0LWltYWdlOnYxNCIKICAgICAgfQogICAgXQogIH0=", + "payloadType": "application/vnd.in-toto+json", + "signatures": [ + { + "keyid": "projects/verified-builder/locations/global/keyRings/attestor/cryptoKeys/builtByGCB/cryptoKeyVersions/1", + "sig": "MEYCIQD-0xUsdkYnsmKnQL_ndEvXknLfn82zsG-hGyYUd4aYsAIhAP4KSCxN2VPNc-dvfrQIGduMUNmAiHxLttdezqdrSf3F" + } + ] + }, + "kind": "BUILD", + "name": "projects/gosst-scare-sandbox/occurrences/8ce06798-f94d-4772-a224-04e473163790", + "noteName": "projects/verified-builder/notes/intoto_b6e052a7-5aa4-41bf-a56b-9bc4e4f3058b", + "resourceUri": "https://us-west2-docker.pkg.dev/gosst-scare-sandbox/quickstart-docker-repo/quickstart-image@sha256:1a033b002f89ed2b8ea733162497fb70f1a4049a7f8602d6a33682b4ad9921fd", + "updateTime": "2022-08-15T22:43:35.649016Z" + } + ] + } + } \ No newline at end of file diff --git a/verifiers/internal/gcb/testdata/gcloud-container-invalid-signature-payloadtype.json b/verifiers/internal/gcb/testdata/gcloud-container-invalid-signature-payloadtype.json new file mode 100644 index 000000000..a6d2c5e88 --- /dev/null +++ b/verifiers/internal/gcb/testdata/gcloud-container-invalid-signature-payloadtype.json @@ -0,0 +1,95 @@ +{ + "image_summary": { + "digest": "sha256:1a033b002f89ed2b8ea733162497fb70f1a4049a7f8602d6a33682b4ad9921fd", + "fully_qualified_digest": "us-west2-docker.pkg.dev/gosst-scare-sandbox/quickstart-docker-repo/quickstart-image@sha256:1a033b002f89ed2b8ea733162497fb70f1a4049a7f8602d6a33682b4ad9921fd", + "registry": "us-west2-docker.pkg.dev", + "repository": "quickstart-docker-repo" + }, + "provenance_summary": { + "provenance": [ + { + "build": { + "intotoStatement": { + "_type": "https://in-toto.io/Statement/v0.1", + "predicateType": "https://slsa.dev/provenance/v0.1", + "slsaProvenance": { + "builder": { + "id": "https://cloudbuild.googleapis.com/GoogleHostedWorker@v0.2" + }, + "materials": [ + { + "uri": "https://github.com/laurentsimon/gcb-tests/commit/fbbb98765e85ad464302dc5977968104d36e455e" + } + ], + "metadata": { + "buildFinishedOn": "2022-08-15T22:43:34.366498Z", + "buildInvocationId": "b6e052a7-5aa4-41bf-a56b-9bc4e4f3058b", + "buildStartedOn": "2022-08-15T22:43:18.700638187Z" + }, + "recipe": { + "arguments": { + "@type": "type.googleapis.com/google.devtools.cloudbuild.v1.Build", + "id": "b6e052a7-5aa4-41bf-a56b-9bc4e4f3058b", + "options": { + "dynamicSubstitutions": true, + "logging": "LEGACY", + "pool": {}, + "substitutionOption": "ALLOW_LOOSE" + }, + "sourceProvenance": {}, + "steps": [ + { + "args": [ + "build", + "-t", + "us-west2-docker.pkg.dev/gosst-scare-sandbox/quickstart-docker-repo/quickstart-image:v14", + "." + ], + "name": "gcr.io/cloud-builders/docker", + "pullTiming": { + "endTime": "2022-08-15T22:43:21.662016533Z", + "startTime": "2022-08-15T22:43:21.657262492Z" + }, + "status": "SUCCESS", + "timing": { + "endTime": "2022-08-15T22:43:27.056377441Z", + "startTime": "2022-08-15T22:43:21.657262492Z" + } + } + ] + }, + "entryPoint": "cloudbuild.yaml", + "type": "https://cloudbuild.googleapis.com/GoogleHostedWorker@v0.2" + } + }, + "subject": [ + { + "digest": { + "sha256": "1a033b002f89ed2b8ea733162497fb70f1a4049a7f8602d6a33682b4ad9921fd" + }, + "name": "https://us-west2-docker.pkg.dev/gosst-scare-sandbox/quickstart-docker-repo/quickstart-image:v14" + } + ] + } + }, + "createTime": "2022-08-15T22:43:35.649016Z", + "envelope": { + "payload": "eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjAuMSIsInByZWRpY2F0ZSI6eyJidWlsZGVyIjp7ImlkIjoiaHR0cHM6Ly9jbG91ZGJ1aWxkLmdvb2dsZWFwaXMuY29tL0dvb2dsZUhvc3RlZFdvcmtlckB2MC4yIn0sIm1hdGVyaWFscyI6W3sidXJpIjoiaHR0cHM6Ly9naXRodWIuY29tL2xhdXJlbnRzaW1vbi9nY2ItdGVzdHMvY29tbWl0L2ZiYmI5ODc2NWU4NWFkNDY0MzAyZGM1OTc3OTY4MTA0ZDM2ZTQ1NWUifV0sIm1ldGFkYXRhIjp7ImJ1aWxkRmluaXNoZWRPbiI6IjIwMjItMDgtMTVUMjI6NDM6MzQuMzY2NDk4WiIsImJ1aWxkSW52b2NhdGlvbklkIjoiYjZlMDUyYTctNWFhNC00MWJmLWE1NmItOWJjNGU0ZjMwNThiIiwiYnVpbGRTdGFydGVkT24iOiIyMDIyLTA4LTE1VDIyOjQzOjE4LjcwMDYzODE4N1oifSwicmVjaXBlIjp7ImFyZ3VtZW50cyI6eyJAdHlwZSI6InR5cGUuZ29vZ2xlYXBpcy5jb20vZ29vZ2xlLmRldnRvb2xzLmNsb3VkYnVpbGQudjEuQnVpbGQiLCJpZCI6ImI2ZTA1MmE3LTVhYTQtNDFiZi1hNTZiLTliYzRlNGYzMDU4YiIsIm9wdGlvbnMiOnsiZHluYW1pY1N1YnN0aXR1dGlvbnMiOnRydWUsImxvZ2dpbmciOiJMRUdBQ1kiLCJwb29sIjp7fSwic3Vic3RpdHV0aW9uT3B0aW9uIjoiQUxMT1dfTE9PU0UifSwic291cmNlUHJvdmVuYW5jZSI6e30sInN0ZXBzIjpbeyJhcmdzIjpbImJ1aWxkIiwiLXQiLCJ1cy13ZXN0Mi1kb2NrZXIucGtnLmRldi9nb3NzdC1zY2FyZS1zYW5kYm94L3F1aWNrc3RhcnQtZG9ja2VyLXJlcG8vcXVpY2tzdGFydC1pbWFnZTp2MTQiLCIuIl0sIm5hbWUiOiJnY3IuaW8vY2xvdWQtYnVpbGRlcnMvZG9ja2VyIiwicHVsbFRpbWluZyI6eyJlbmRUaW1lIjoiMjAyMi0wOC0xNVQyMjo0MzoyMS42NjIwMTY1MzNaIiwic3RhcnRUaW1lIjoiMjAyMi0wOC0xNVQyMjo0MzoyMS42NTcyNjI0OTJaIn0sInN0YXR1cyI6IlNVQ0NFU1MiLCJ0aW1pbmciOnsiZW5kVGltZSI6IjIwMjItMDgtMTVUMjI6NDM6MjcuMDU2Mzc3NDQxWiIsInN0YXJ0VGltZSI6IjIwMjItMDgtMTVUMjI6NDM6MjEuNjU3MjYyNDkyWiJ9fV19LCJlbnRyeVBvaW50IjoiY2xvdWRidWlsZC55YW1sIiwidHlwZSI6Imh0dHBzOi8vY2xvdWRidWlsZC5nb29nbGVhcGlzLmNvbS9Hb29nbGVIb3N0ZWRXb3JrZXJAdjAuMiJ9fSwicHJlZGljYXRlVHlwZSI6Imh0dHBzOi8vc2xzYS5kZXYvcHJvdmVuYW5jZS92MC4xIiwic2xzYVByb3ZlbmFuY2UiOnsiYnVpbGRlciI6eyJpZCI6Imh0dHBzOi8vY2xvdWRidWlsZC5nb29nbGVhcGlzLmNvbS9Hb29nbGVIb3N0ZWRXb3JrZXJAdjAuMiJ9LCJtYXRlcmlhbHMiOlt7InVyaSI6Imh0dHBzOi8vZ2l0aHViLmNvbS9sYXVyZW50c2ltb24vZ2NiLXRlc3RzL2NvbW1pdC9mYmJiOTg3NjVlODVhZDQ2NDMwMmRjNTk3Nzk2ODEwNGQzNmU0NTVlIn1dLCJtZXRhZGF0YSI6eyJidWlsZEZpbmlzaGVkT24iOiIyMDIyLTA4LTE1VDIyOjQzOjM0LjM2NjQ5OFoiLCJidWlsZEludm9jYXRpb25JZCI6ImI2ZTA1MmE3LTVhYTQtNDFiZi1hNTZiLTliYzRlNGYzMDU4YiIsImJ1aWxkU3RhcnRlZE9uIjoiMjAyMi0wOC0xNVQyMjo0MzoxOC43MDA2MzgxODdaIn0sInJlY2lwZSI6eyJhcmd1bWVudHMiOnsiQHR5cGUiOiJ0eXBlLmdvb2dsZWFwaXMuY29tL2dvb2dsZS5kZXZ0b29scy5jbG91ZGJ1aWxkLnYxLkJ1aWxkIiwiaWQiOiJiNmUwNTJhNy01YWE0LTQxYmYtYTU2Yi05YmM0ZTRmMzA1OGIiLCJvcHRpb25zIjp7ImR5bmFtaWNTdWJzdGl0dXRpb25zIjp0cnVlLCJsb2dnaW5nIjoiTEVHQUNZIiwicG9vbCI6e30sInN1YnN0aXR1dGlvbk9wdGlvbiI6IkFMTE9XX0xPT1NFIn0sInNvdXJjZVByb3ZlbmFuY2UiOnt9LCJzdGVwcyI6W3siYXJncyI6WyJidWlsZCIsIi10IiwidXMtd2VzdDItZG9ja2VyLnBrZy5kZXYvZ29zc3Qtc2NhcmUtc2FuZGJveC9xdWlja3N0YXJ0LWRvY2tlci1yZXBvL3F1aWNrc3RhcnQtaW1hZ2U6djE0IiwiLiJdLCJuYW1lIjoiZ2NyLmlvL2Nsb3VkLWJ1aWxkZXJzL2RvY2tlciIsInB1bGxUaW1pbmciOnsiZW5kVGltZSI6IjIwMjItMDgtMTVUMjI6NDM6MjEuNjYyMDE2NTMzWiIsInN0YXJ0VGltZSI6IjIwMjItMDgtMTVUMjI6NDM6MjEuNjU3MjYyNDkyWiJ9LCJzdGF0dXMiOiJTVUNDRVNTIiwidGltaW5nIjp7ImVuZFRpbWUiOiIyMDIyLTA4LTE1VDIyOjQzOjI3LjA1NjM3NzQ0MVoiLCJzdGFydFRpbWUiOiIyMDIyLTA4LTE1VDIyOjQzOjIxLjY1NzI2MjQ5MloifX1dfSwiZW50cnlQb2ludCI6ImNsb3VkYnVpbGQueWFtbCIsInR5cGUiOiJodHRwczovL2Nsb3VkYnVpbGQuZ29vZ2xlYXBpcy5jb20vR29vZ2xlSG9zdGVkV29ya2VyQHYwLjIifX0sInN1YmplY3QiOlt7ImRpZ2VzdCI6eyJzaGEyNTYiOiIxYTAzM2IwMDJmODllZDJiOGVhNzMzMTYyNDk3ZmI3MGYxYTQwNDlhN2Y4NjAyZDZhMzM2ODJiNGFkOTkyMWZkIn0sIm5hbWUiOiJodHRwczovL3VzLXdlc3QyLWRvY2tlci5wa2cuZGV2L2dvc3N0LXNjYXJlLXNhbmRib3gvcXVpY2tzdGFydC1kb2NrZXItcmVwby9xdWlja3N0YXJ0LWltYWdlOnYxNCJ9XX0=", + "payloadType": "application/vnd.in-toto2+json", + "signatures": [ + { + "keyid": "projects/verified-builder/locations/global/keyRings/attestor/cryptoKeys/builtByGCB/cryptoKeyVersions/1", + "sig": "MEYCIQD-0xUsdkYnsmKnQL_ndEvXknLfn82zsG-hGyYUd4aYsAIhAP4KSCxN2VPNc-dvfrQIGduMUNmAiHxLttdezqdrSf3F" + } + ] + }, + "kind": "BUILD", + "name": "projects/gosst-scare-sandbox/occurrences/8ce06798-f94d-4772-a224-04e473163790", + "noteName": "projects/verified-builder/notes/intoto_b6e052a7-5aa4-41bf-a56b-9bc4e4f3058b", + "resourceUri": "https://us-west2-docker.pkg.dev/gosst-scare-sandbox/quickstart-docker-repo/quickstart-image@sha256:1a033b002f89ed2b8ea733162497fb70f1a4049a7f8602d6a33682b4ad9921fd", + "updateTime": "2022-08-15T22:43:35.649016Z" + } + ] + } + } + \ No newline at end of file diff --git a/verifiers/internal/gcb/testdata/gcloud-container-invalid-signature.json b/verifiers/internal/gcb/testdata/gcloud-container-invalid-signature.json new file mode 100644 index 000000000..720fc6c90 --- /dev/null +++ b/verifiers/internal/gcb/testdata/gcloud-container-invalid-signature.json @@ -0,0 +1,94 @@ +{ + "image_summary": { + "digest": "sha256:1a033b002f89ed2b8ea733162497fb70f1a4049a7f8602d6a33682b4ad9921fd", + "fully_qualified_digest": "us-west2-docker.pkg.dev/gosst-scare-sandbox/quickstart-docker-repo/quickstart-image@sha256:1a033b002f89ed2b8ea733162497fb70f1a4049a7f8602d6a33682b4ad9921fd", + "registry": "us-west2-docker.pkg.dev", + "repository": "quickstart-docker-repo" + }, + "provenance_summary": { + "provenance": [ + { + "build": { + "intotoStatement": { + "_type": "https://in-toto.io/Statement/v0.1", + "predicateType": "https://slsa.dev/provenance/v0.1", + "slsaProvenance": { + "builder": { + "id": "https://cloudbuild.googleapis.com/GoogleHostedWorker@v0.2" + }, + "materials": [ + { + "uri": "https://github.com/laurentsimon/gcb-tests/commit/fbbb98765e85ad464302dc5977968104d36e455e" + } + ], + "metadata": { + "buildFinishedOn": "2022-08-15T22:43:34.366498Z", + "buildInvocationId": "b6e052a7-5aa4-41bf-a56b-9bc4e4f3058b", + "buildStartedOn": "2022-08-15T22:43:18.700638187Z" + }, + "recipe": { + "arguments": { + "@type": "type.googleapis.com/google.devtools.cloudbuild.v1.Build", + "id": "b6e052a7-5aa4-41bf-a56b-9bc4e4f3058b", + "options": { + "dynamicSubstitutions": true, + "logging": "LEGACY", + "pool": {}, + "substitutionOption": "ALLOW_LOOSE" + }, + "sourceProvenance": {}, + "steps": [ + { + "args": [ + "build", + "-t", + "us-west2-docker.pkg.dev/gosst-scare-sandbox/quickstart-docker-repo/quickstart-image:v14", + "." + ], + "name": "gcr.io/cloud-builders/docker", + "pullTiming": { + "endTime": "2022-08-15T22:43:21.662016533Z", + "startTime": "2022-08-15T22:43:21.657262492Z" + }, + "status": "SUCCESS", + "timing": { + "endTime": "2022-08-15T22:43:27.056377441Z", + "startTime": "2022-08-15T22:43:21.657262492Z" + } + } + ] + }, + "entryPoint": "cloudbuild.yaml", + "type": "https://cloudbuild.googleapis.com/GoogleHostedWorker@v0.2" + } + }, + "subject": [ + { + "digest": { + "sha256": "1a033b002f89ed2b8ea733162497fb70f1a4049a7f8602d6a33682b4ad9921fd" + }, + "name": "https://us-west2-docker.pkg.dev/gosst-scare-sandbox/quickstart-docker-repo/quickstart-image:v14" + } + ] + } + }, + "createTime": "2022-08-15T22:43:35.649016Z", + "envelope": { + "payload": "ewogICJfdHlwZSI6ICJodHRwczovL2luLXRvdG8uaW8vU3RhdGVtZW50L3YwLjEiLAogICJwcmVkaWNhdGUiOiB7CiAgICAiYnVpbGRlciI6IHsKICAgICAgImlkIjogImh0dHBzOi8vY2xvdWRidWlsZC5nb29nbGVhcGlzLmNvbS9Hb29nbGVIb3N0ZWRXb3JrZXJAdjAuMiIKICAgIH0sCiAgICAibWF0ZXJpYWxzIjogWwogICAgICB7CiAgICAgICAgInVyaSI6ICJodHRwczovL2dpdGh1Yi5jb20vbGF1cmVudHNpbW9uL2djYi10ZXN0cy9jb21taXQvZmJiYjk4NzY1ZTg1YWQ0NjQzMDJkYzU5Nzc5NjgxMDRkMzZlNDU1ZSIKICAgICAgfQogICAgXSwKICAgICJtZXRhZGF0YSI6IHsKICAgICAgImJ1aWxkRmluaXNoZWRPbiI6ICIyMDIyLTA4LTE1VDIyOjQzOjM0LjM2NjQ5OFoiLAogICAgICAiYnVpbGRJbnZvY2F0aW9uSWQiOiAiYjZlMDUyYTctNWFhNC00MWJmLWE1NmItOWJjNGU0ZjMwNThiIiwKICAgICAgImJ1aWxkU3RhcnRlZE9uIjogIjIwMjItMDgtMTVUMjI6NDM6MTguNzAwNjM4MTg3WiIKICAgIH0sCiAgICAicmVjaXBlIjogewogICAgICAiYXJndW1lbnRzIjogewogICAgICAgICJAdHlwZSI6ICJ0eXBlLmdvb2dsZWFwaXMuY29tL2dvb2dsZS5kZXZ0b29scy5jbG91ZGJ1aWxkLnYxLkJ1aWxkIiwKICAgICAgICAiaWQiOiAiYjZlMDUyYTctNWFhNC00MWJmLWE1NmItOWJjNGU0ZjMwNThiIiwKICAgICAgICAib3B0aW9ucyI6IHsKICAgICAgICAgICJkeW5hbWljU3Vic3RpdHV0aW9ucyI6IHRydWUsCiAgICAgICAgICAibG9nZ2luZyI6ICJMRUdBQ1kiLAogICAgICAgICAgInBvb2wiOiB7fSwKICAgICAgICAgICJzdWJzdGl0dXRpb25PcHRpb24iOiAiQUxMT1dfTE9PU0UiCiAgICAgICAgfSwKICAgICAgICAic291cmNlUHJvdmVuYW5jZSI6IHt9LAogICAgICAgICJzdGVwcyI6IFsKICAgICAgICAgIHsKICAgICAgICAgICAgImFyZ3MiOiBbCiAgICAgICAgICAgICAgImJ1aWxkIiwKICAgICAgICAgICAgICAiLXQiLAogICAgICAgICAgICAgICJ1cy13ZXN0Mi1kb2NrZXIucGtnLmRldi9nb3NzdC1zY2FyZS1zYW5kYm94L3F1aWNrc3RhcnQtZG9ja2VyLXJlcG8vcXVpY2tzdGFydC1pbWFnZTp2MTUiLAogICAgICAgICAgICAgICIuIgogICAgICAgICAgICBdLAogICAgICAgICAgICAibmFtZSI6ICJnY3IuaW8vY2xvdWQtYnVpbGRlcnMvZG9ja2VyIiwKICAgICAgICAgICAgInB1bGxUaW1pbmciOiB7CiAgICAgICAgICAgICAgImVuZFRpbWUiOiAiMjAyMi0wOC0xNVQyMjo0MzoyMS42NjIwMTY1MzNaIiwKICAgICAgICAgICAgICAic3RhcnRUaW1lIjogIjIwMjItMDgtMTVUMjI6NDM6MjEuNjU3MjYyNDkyWiIKICAgICAgICAgICAgfSwKICAgICAgICAgICAgInN0YXR1cyI6ICJTVUNDRVNTIiwKICAgICAgICAgICAgInRpbWluZyI6IHsKICAgICAgICAgICAgICAiZW5kVGltZSI6ICIyMDIyLTA4LTE1VDIyOjQzOjI3LjA1NjM3NzQ0MVoiLAogICAgICAgICAgICAgICJzdGFydFRpbWUiOiAiMjAyMi0wOC0xNVQyMjo0MzoyMS42NTcyNjI0OTJaIgogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgXQogICAgICB9LAogICAgICAiZW50cnlQb2ludCI6ICJjbG91ZGJ1aWxkLnlhbWwiLAogICAgICAidHlwZSI6ICJodHRwczovL2Nsb3VkYnVpbGQuZ29vZ2xlYXBpcy5jb20vR29vZ2xlSG9zdGVkV29ya2VyQHYwLjIiCiAgICB9CiAgfSwKICAicHJlZGljYXRlVHlwZSI6ICJodHRwczovL3Nsc2EuZGV2L3Byb3ZlbmFuY2UvdjAuMSIsCiAgInNsc2FQcm92ZW5hbmNlIjogewogICAgImJ1aWxkZXIiOiB7CiAgICAgICJpZCI6ICJodHRwczovL2Nsb3VkYnVpbGQuZ29vZ2xlYXBpcy5jb20vR29vZ2xlSG9zdGVkV29ya2VyQHYwLjIiCiAgICB9LAogICAgIm1hdGVyaWFscyI6IFsKICAgICAgewogICAgICAgICJ1cmkiOiAiaHR0cHM6Ly9naXRodWIuY29tL2xhdXJlbnRzaW1vbi9nY2ItdGVzdHMvY29tbWl0L2ZiYmI5ODc2NWU4NWFkNDY0MzAyZGM1OTc3OTY4MTA0ZDM2ZTQ1NWUiCiAgICAgIH0KICAgIF0sCiAgICAibWV0YWRhdGEiOiB7CiAgICAgICJidWlsZEZpbmlzaGVkT24iOiAiMjAyMi0wOC0xNVQyMjo0MzozNC4zNjY0OThaIiwKICAgICAgImJ1aWxkSW52b2NhdGlvbklkIjogImI2ZTA1MmE3LTVhYTQtNDFiZi1hNTZiLTliYzRlNGYzMDU4YiIsCiAgICAgICJidWlsZFN0YXJ0ZWRPbiI6ICIyMDIyLTA4LTE1VDIyOjQzOjE4LjcwMDYzODE4N1oiCiAgICB9LAogICAgInJlY2lwZSI6IHsKICAgICAgImFyZ3VtZW50cyI6IHsKICAgICAgICAiQHR5cGUiOiAidHlwZS5nb29nbGVhcGlzLmNvbS9nb29nbGUuZGV2dG9vbHMuY2xvdWRidWlsZC52MS5CdWlsZCIsCiAgICAgICAgImlkIjogImI2ZTA1MmE3LTVhYTQtNDFiZi1hNTZiLTliYzRlNGYzMDU4YiIsCiAgICAgICAgIm9wdGlvbnMiOiB7CiAgICAgICAgICAiZHluYW1pY1N1YnN0aXR1dGlvbnMiOiB0cnVlLAogICAgICAgICAgImxvZ2dpbmciOiAiTEVHQUNZIiwKICAgICAgICAgICJwb29sIjoge30sCiAgICAgICAgICAic3Vic3RpdHV0aW9uT3B0aW9uIjogIkFMTE9XX0xPT1NFIgogICAgICAgIH0sCiAgICAgICAgInNvdXJjZVByb3ZlbmFuY2UiOiB7fSwKICAgICAgICAic3RlcHMiOiBbCiAgICAgICAgICB7CiAgICAgICAgICAgICJhcmdzIjogWwogICAgICAgICAgICAgICJidWlsZCIsCiAgICAgICAgICAgICAgIi10IiwKICAgICAgICAgICAgICAidXMtd2VzdDItZG9ja2VyLnBrZy5kZXYvZ29zc3Qtc2NhcmUtc2FuZGJveC9xdWlja3N0YXJ0LWRvY2tlci1yZXBvL3F1aWNrc3RhcnQtaW1hZ2U6djE0IiwKICAgICAgICAgICAgICAiLiIKICAgICAgICAgICAgXSwKICAgICAgICAgICAgIm5hbWUiOiAiZ2NyLmlvL2Nsb3VkLWJ1aWxkZXJzL2RvY2tlciIsCiAgICAgICAgICAgICJwdWxsVGltaW5nIjogewogICAgICAgICAgICAgICJlbmRUaW1lIjogIjIwMjItMDgtMTVUMjI6NDM6MjEuNjYyMDE2NTMzWiIsCiAgICAgICAgICAgICAgInN0YXJ0VGltZSI6ICIyMDIyLTA4LTE1VDIyOjQzOjIxLjY1NzI2MjQ5MloiCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgICJzdGF0dXMiOiAiU1VDQ0VTUyIsCiAgICAgICAgICAgICJ0aW1pbmciOiB7CiAgICAgICAgICAgICAgImVuZFRpbWUiOiAiMjAyMi0wOC0xNVQyMjo0MzoyNy4wNTYzNzc0NDFaIiwKICAgICAgICAgICAgICAic3RhcnRUaW1lIjogIjIwMjItMDgtMTVUMjI6NDM6MjEuNjU3MjYyNDkyWiIKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgIF0KICAgICAgfSwKICAgICAgImVudHJ5UG9pbnQiOiAiY2xvdWRidWlsZC55YW1sIiwKICAgICAgInR5cGUiOiAiaHR0cHM6Ly9jbG91ZGJ1aWxkLmdvb2dsZWFwaXMuY29tL0dvb2dsZUhvc3RlZFdvcmtlckB2MC4yIgogICAgfQogIH0sCiAgInN1YmplY3QiOiBbCiAgICB7CiAgICAgICJkaWdlc3QiOiB7CiAgICAgICAgInNoYTI1NiI6ICIxYTAzM2IwMDJmODllZDJiOGVhNzMzMTYyNDk3ZmI3MGYxYTQwNDlhN2Y4NjAyZDZhMzM2ODJiNGFkOTkyMWZkIgogICAgICB9LAogICAgICAibmFtZSI6ICJodHRwczovL3VzLXdlc3QyLWRvY2tlci5wa2cuZGV2L2dvc3N0LXNjYXJlLXNhbmRib3gvcXVpY2tzdGFydC1kb2NrZXItcmVwby9xdWlja3N0YXJ0LWltYWdlOnYxNCIKICAgIH0KICBdCn0K", + "payloadType": "application/vnd.in-toto+json", + "signatures": [ + { + "keyid": "projects/verified-builder/locations/global/keyRings/attestor/cryptoKeys/builtByGCB/cryptoKeyVersions/1", + "sig": "MEYCIQD-0xUsdkYnsmKnQL_ndEvXknLfn82zsG-hGyYUd4aYsAIhAP4KSCxN2VPNc-dvfrQIGduMUNmAiHxLttdezqdrSf3F" + } + ] + }, + "kind": "BUILD", + "name": "projects/gosst-scare-sandbox/occurrences/8ce06798-f94d-4772-a224-04e473163790", + "noteName": "projects/verified-builder/notes/intoto_b6e052a7-5aa4-41bf-a56b-9bc4e4f3058b", + "resourceUri": "https://us-west2-docker.pkg.dev/gosst-scare-sandbox/quickstart-docker-repo/quickstart-image@sha256:1a033b002f89ed2b8ea733162497fb70f1a4049a7f8602d6a33682b4ad9921fd", + "updateTime": "2022-08-15T22:43:35.649016Z" + } + ] + } + } \ No newline at end of file diff --git a/verifiers/internal/gcb/testdata/gcloud-container-invalid-slsaheader.json b/verifiers/internal/gcb/testdata/gcloud-container-invalid-slsaheader.json new file mode 100644 index 000000000..ad783b4b9 --- /dev/null +++ b/verifiers/internal/gcb/testdata/gcloud-container-invalid-slsaheader.json @@ -0,0 +1,94 @@ +{ + "image_summary": { + "digest": "sha256:1a033b002f89ed2b8ea733162497fb70f1a4049a7f8602d6a33682b4ad9921fd", + "fully_qualified_digest": "us-west2-docker.pkg.dev/gosst-scare-sandbox/quickstart-docker-repo/quickstart-image@sha256:1a033b002f89ed2b8ea733162497fb70f1a4049a7f8602d6a33682b4ad9921fd", + "registry": "us-west2-docker.pkg.dev", + "repository": "quickstart-docker-repo" + }, + "provenance_summary": { + "provenance": [ + { + "build": { + "intotoStatement": { + "_type": "https://in-toto.io/Statement/v0.1", + "predicateType": "https://slsa.dev/provenance/v0.1", + "slsaProvenance": { + "builder": { + "id": "https://cloudbuild.googleapis.com/GoogleHostedWorker@v0.2" + }, + "materials": [ + { + "uri": "https://github.com/laurentsimon/gcb-tests/commit/fbbb98765e85ad464302dc5977968104d36e455e" + } + ], + "metadata": { + "buildFinishedOn": "2022-08-15T22:43:34.366498Z", + "buildInvocationId": "b6e052a7-5aa4-41bf-a56b-9bc4e4f3058b", + "buildStartedOn": "2022-08-15T22:43:18.700638187Z" + }, + "recipe": { + "arguments": { + "@type": "type.googleapis.com/google.devtools.cloudbuild.v1.Build", + "id": "b6e052a7-5aa4-41bf-a56b-9bc4e4f3058b", + "options": { + "dynamicSubstitutions": true, + "logging": "LEGACY", + "pool": {}, + "substitutionOption": "ALLOW_LOOSE" + }, + "sourceProvenance": {}, + "steps": [ + { + "args": [ + "build", + "-t", + "us-west2-docker.pkg.dev/gosst-scare-sandbox/quickstart-docker-repo/quickstart-image:v14", + "." + ], + "name": "gcr.io/cloud-builders/docker", + "pullTiming": { + "endTime": "2022-08-15T22:43:21.662016533Z", + "startTime": "2022-08-15T22:43:21.657262492Z" + }, + "status": "SUCCESS", + "timing": { + "endTime": "2022-08-15T22:43:27.056377441Z", + "startTime": "2022-08-15T22:43:21.657262492Z" + } + } + ] + }, + "entryPoint": "cloudbuild.yaml", + "type": "https://cloudbuild.googleapis.com/GoogleHostedWorker@v0.2" + } + }, + "subject": [ + { + "digest": { + "sha256": "1a033b002f89ed2b8ea733162497fb70f1a4049a7f8602d6a33682b4ad9921fd" + }, + "name": "https://us-west2-docker.pkg.dev/gosst-scare-sandbox/quickstart-docker-repo/quickstart-image:v14" + } + ] + } + }, + "createTime": "2022-08-15T22:43:35.649016Z", + "envelope": { + "payload": "ewogICJfdHlwZSI6ICJodHRwczovL2luLXRvdG8uaW8vU3RhdGVtZW50L3YwLjEiLAogICJwcmVkaWNhdGUiOiB7CiAgICAiYnVpbGRlciI6IHsKICAgICAgImlkIjogImh0dHBzOi8vY2xvdWRidWlsZC5nb29nbGVhcGlzLmNvbS9Hb29nbGVIb3N0ZWRXb3JrZXJAdjAuMiIKICAgIH0sCiAgICAibWF0ZXJpYWxzIjogWwogICAgICB7CiAgICAgICAgInVyaSI6ICJodHRwczovL2dpdGh1Yi5jb20vbGF1cmVudHNpbW9uL2djYi10ZXN0cy9jb21taXQvZmJiYjk4NzY1ZTg1YWQ0NjQzMDJkYzU5Nzc5NjgxMDRkMzZlNDU1ZSIKICAgICAgfQogICAgXSwKICAgICJtZXRhZGF0YSI6IHsKICAgICAgImJ1aWxkRmluaXNoZWRPbiI6ICIyMDIyLTA4LTE1VDIyOjQzOjM0LjM2NjQ5OFoiLAogICAgICAiYnVpbGRJbnZvY2F0aW9uSWQiOiAiYjZlMDUyYTctNWFhNC00MWJmLWE1NmItOWJjNGU0ZjMwNThiIiwKICAgICAgImJ1aWxkU3RhcnRlZE9uIjogIjIwMjItMDgtMTVUMjI6NDM6MTguNzAwNjM4MTg3WiIKICAgIH0sCiAgICAicmVjaXBlIjogewogICAgICAiYXJndW1lbnRzIjogewogICAgICAgICJAdHlwZSI6ICJ0eXBlLmdvb2dsZWFwaXMuY29tL2dvb2dsZS5kZXZ0b29scy5jbG91ZGJ1aWxkLnYxLkJ1aWxkIiwKICAgICAgICAiaWQiOiAiYjZlMDUyYTctNWFhNC00MWJmLWE1NmItOWJjNGU0ZjMwNThiIiwKICAgICAgICAib3B0aW9ucyI6IHsKICAgICAgICAgICJkeW5hbWljU3Vic3RpdHV0aW9ucyI6IHRydWUsCiAgICAgICAgICAibG9nZ2luZyI6ICJMRUdBQ1kiLAogICAgICAgICAgInBvb2wiOiB7fSwKICAgICAgICAgICJzdWJzdGl0dXRpb25PcHRpb24iOiAiQUxMT1dfTE9PU0UiCiAgICAgICAgfSwKICAgICAgICAic291cmNlUHJvdmVuYW5jZSI6IHt9LAogICAgICAgICJzdGVwcyI6IFsKICAgICAgICAgIHsKICAgICAgICAgICAgImFyZ3MiOiBbCiAgICAgICAgICAgICAgImJ1aWxkIiwKICAgICAgICAgICAgICAiLXQiLAogICAgICAgICAgICAgICJ1cy13ZXN0Mi1kb2NrZXIucGtnLmRldi9nb3NzdC1zY2FyZS1zYW5kYm94L3F1aWNrc3RhcnQtZG9ja2VyLXJlcG8vcXVpY2tzdGFydC1pbWFnZTp2MTQiLAogICAgICAgICAgICAgICIuIgogICAgICAgICAgICBdLAogICAgICAgICAgICAibmFtZSI6ICJnY3IuaW8vY2xvdWQtYnVpbGRlcnMvZG9ja2VyIiwKICAgICAgICAgICAgInB1bGxUaW1pbmciOiB7CiAgICAgICAgICAgICAgImVuZFRpbWUiOiAiMjAyMi0wOC0xNVQyMjo0MzoyMS42NjIwMTY1MzNaIiwKICAgICAgICAgICAgICAic3RhcnRUaW1lIjogIjIwMjItMDgtMTVUMjI6NDM6MjEuNjU3MjYyNDkyWiIKICAgICAgICAgICAgfSwKICAgICAgICAgICAgInN0YXR1cyI6ICJTVUNDRVNTIiwKICAgICAgICAgICAgInRpbWluZyI6IHsKICAgICAgICAgICAgICAiZW5kVGltZSI6ICIyMDIyLTA4LTE1VDIyOjQzOjI3LjA1NjM3NzQ0MVoiLAogICAgICAgICAgICAgICJzdGFydFRpbWUiOiAiMjAyMi0wOC0xNVQyMjo0MzoyMS42NTcyNjI0OTJaIgogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgXQogICAgICB9LAogICAgICAiZW50cnlQb2ludCI6ICJjbG91ZGJ1aWxkLnlhbWwiLAogICAgICAidHlwZSI6ICJodHRwczovL2Nsb3VkYnVpbGQuZ29vZ2xlYXBpcy5jb20vR29vZ2xlSG9zdGVkV29ya2VyQHYwLjIiCiAgICB9CiAgfSwKICAicHJlZGljYXRlVHlwZSI6ICJodHRwczovL3Nsc2EuZGV2L3Byb3ZlbmFuY2UvdjAuMiIsCiAgInNsc2FQcm92ZW5hbmNlIjogewogICAgImJ1aWxkZXIiOiB7CiAgICAgICJpZCI6ICJodHRwczovL2Nsb3VkYnVpbGQuZ29vZ2xlYXBpcy5jb20vR29vZ2xlSG9zdGVkV29ya2VyQHYwLjIiCiAgICB9LAogICAgIm1hdGVyaWFscyI6IFsKICAgICAgewogICAgICAgICJ1cmkiOiAiaHR0cHM6Ly9naXRodWIuY29tL2xhdXJlbnRzaW1vbi9nY2ItdGVzdHMvY29tbWl0L2ZiYmI5ODc2NWU4NWFkNDY0MzAyZGM1OTc3OTY4MTA0ZDM2ZTQ1NWUiCiAgICAgIH0KICAgIF0sCiAgICAibWV0YWRhdGEiOiB7CiAgICAgICJidWlsZEZpbmlzaGVkT24iOiAiMjAyMi0wOC0xNVQyMjo0MzozNC4zNjY0OThaIiwKICAgICAgImJ1aWxkSW52b2NhdGlvbklkIjogImI2ZTA1MmE3LTVhYTQtNDFiZi1hNTZiLTliYzRlNGYzMDU4YiIsCiAgICAgICJidWlsZFN0YXJ0ZWRPbiI6ICIyMDIyLTA4LTE1VDIyOjQzOjE4LjcwMDYzODE4N1oiCiAgICB9LAogICAgInJlY2lwZSI6IHsKICAgICAgImFyZ3VtZW50cyI6IHsKICAgICAgICAiQHR5cGUiOiAidHlwZS5nb29nbGVhcGlzLmNvbS9nb29nbGUuZGV2dG9vbHMuY2xvdWRidWlsZC52MS5CdWlsZCIsCiAgICAgICAgImlkIjogImI2ZTA1MmE3LTVhYTQtNDFiZi1hNTZiLTliYzRlNGYzMDU4YiIsCiAgICAgICAgIm9wdGlvbnMiOiB7CiAgICAgICAgICAiZHluYW1pY1N1YnN0aXR1dGlvbnMiOiB0cnVlLAogICAgICAgICAgImxvZ2dpbmciOiAiTEVHQUNZIiwKICAgICAgICAgICJwb29sIjoge30sCiAgICAgICAgICAic3Vic3RpdHV0aW9uT3B0aW9uIjogIkFMTE9XX0xPT1NFIgogICAgICAgIH0sCiAgICAgICAgInNvdXJjZVByb3ZlbmFuY2UiOiB7fSwKICAgICAgICAic3RlcHMiOiBbCiAgICAgICAgICB7CiAgICAgICAgICAgICJhcmdzIjogWwogICAgICAgICAgICAgICJidWlsZCIsCiAgICAgICAgICAgICAgIi10IiwKICAgICAgICAgICAgICAidXMtd2VzdDItZG9ja2VyLnBrZy5kZXYvZ29zc3Qtc2NhcmUtc2FuZGJveC9xdWlja3N0YXJ0LWRvY2tlci1yZXBvL3F1aWNrc3RhcnQtaW1hZ2U6djE0IiwKICAgICAgICAgICAgICAiLiIKICAgICAgICAgICAgXSwKICAgICAgICAgICAgIm5hbWUiOiAiZ2NyLmlvL2Nsb3VkLWJ1aWxkZXJzL2RvY2tlciIsCiAgICAgICAgICAgICJwdWxsVGltaW5nIjogewogICAgICAgICAgICAgICJlbmRUaW1lIjogIjIwMjItMDgtMTVUMjI6NDM6MjEuNjYyMDE2NTMzWiIsCiAgICAgICAgICAgICAgInN0YXJ0VGltZSI6ICIyMDIyLTA4LTE1VDIyOjQzOjIxLjY1NzI2MjQ5MloiCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgICJzdGF0dXMiOiAiU1VDQ0VTUyIsCiAgICAgICAgICAgICJ0aW1pbmciOiB7CiAgICAgICAgICAgICAgImVuZFRpbWUiOiAiMjAyMi0wOC0xNVQyMjo0MzoyNy4wNTYzNzc0NDFaIiwKICAgICAgICAgICAgICAic3RhcnRUaW1lIjogIjIwMjItMDgtMTVUMjI6NDM6MjEuNjU3MjYyNDkyWiIKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgIF0KICAgICAgfSwKICAgICAgImVudHJ5UG9pbnQiOiAiY2xvdWRidWlsZC55YW1sIiwKICAgICAgInR5cGUiOiAiaHR0cHM6Ly9jbG91ZGJ1aWxkLmdvb2dsZWFwaXMuY29tL0dvb2dsZUhvc3RlZFdvcmtlckB2MC4yIgogICAgfQogIH0sCiAgInN1YmplY3QiOiBbCiAgICB7CiAgICAgICJkaWdlc3QiOiB7CiAgICAgICAgInNoYTI1NiI6ICIxYTAzM2IwMDJmODllZDJiOGVhNzMzMTYyNDk3ZmI3MGYxYTQwNDlhN2Y4NjAyZDZhMzM2ODJiNGFkOTkyMWZkIgogICAgICB9LAogICAgICAibmFtZSI6ICJodHRwczovL3VzLXdlc3QyLWRvY2tlci5wa2cuZGV2L2dvc3N0LXNjYXJlLXNhbmRib3gvcXVpY2tzdGFydC1kb2NrZXItcmVwby9xdWlja3N0YXJ0LWltYWdlOnYxNCIKICAgIH0KICBdCn0K", + "payloadType": "application/vnd.in-toto+json", + "signatures": [ + { + "keyid": "projects/verified-builder/locations/global/keyRings/attestor/cryptoKeys/builtByGCB/cryptoKeyVersions/1", + "sig": "MEYCIQD-0xUsdkYnsmKnQL_ndEvXknLfn82zsG-hGyYUd4aYsAIhAP4KSCxN2VPNc-dvfrQIGduMUNmAiHxLttdezqdrSf3F" + } + ] + }, + "kind": "BUILD", + "name": "projects/gosst-scare-sandbox/occurrences/8ce06798-f94d-4772-a224-04e473163790", + "noteName": "projects/verified-builder/notes/intoto_b6e052a7-5aa4-41bf-a56b-9bc4e4f3058b", + "resourceUri": "https://us-west2-docker.pkg.dev/gosst-scare-sandbox/quickstart-docker-repo/quickstart-image@sha256:1a033b002f89ed2b8ea733162497fb70f1a4049a7f8602d6a33682b4ad9921fd", + "updateTime": "2022-08-15T22:43:35.649016Z" + } + ] + } + } \ No newline at end of file diff --git a/verifiers/internal/gcb/verifier.go b/verifiers/internal/gcb/verifier.go index 8a353f77a..9ea8d4a4b 100644 --- a/verifiers/internal/gcb/verifier.go +++ b/verifiers/internal/gcb/verifier.go @@ -1,4 +1,4 @@ -package gha +package gcb import ( "context" @@ -7,6 +7,7 @@ import ( serrors "github.com/slsa-framework/slsa-verifier/errors" "github.com/slsa-framework/slsa-verifier/options" register "github.com/slsa-framework/slsa-verifier/register" + _ "github.com/slsa-framework/slsa-verifier/verifiers/internal/gcb/keys" ) const VerifierName = "GCB" @@ -40,9 +41,77 @@ func (v *GCBVerifier) VerifyArtifact(ctx context.Context, // VerifyImage verifies provenance for an OCI image. func (v *GCBVerifier) VerifyImage(ctx context.Context, - artifactImage string, + provenance []byte, artifactImage string, provenanceOpts *options.ProvenanceOpts, builderOpts *options.BuilderOpts, ) ([]byte, string, error) { - return nil, "todo", serrors.ErrorNotSupported + prov, err := ProvenanceFromBytes(provenance) + if err != nil { + return nil, "", err + } + + // Verify signature on the intoto attestation. + if err = prov.VerifySignature(); err != nil { + return nil, "", err + } + + // Verify intoto header. + if err = prov.VerifyIntotoHeaders(); err != nil { + return nil, "", err + } + + // Verify the builder. + builderID, err := prov.VerifyBuilder(builderOpts) + if err != nil { + return nil, "", err + } + + // Verify subject digest. + if err = prov.VerifySubjectDigest(provenanceOpts.ExpectedDigest); err != nil { + return nil, "", err + } + + // Verify source. + if err = prov.VerifySourceURI(provenanceOpts.ExpectedSourceURI); err != nil { + return nil, "", err + } + + // Verify metadata. + // This is metadata that GCB appends to the DSSE content. + if err = prov.VerifyMetadata(provenanceOpts); err != nil { + return nil, "", err + } + + // Verify the summary. + // This is an additional structure that GCB prepends to the provenance. + if err = prov.VerifySummary(provenanceOpts); err != nil { + return nil, "", err + } + + // Verify branch. + if provenanceOpts.ExpectedBranch != nil { + if err = prov.VerifyBranch(*provenanceOpts.ExpectedBranch); err != nil { + return nil, "", err + } + } + + // Verify the tag. + if provenanceOpts.ExpectedTag != nil { + if err := prov.VerifyTag(*provenanceOpts.ExpectedTag); err != nil { + return nil, "", err + } + } + + // Verify the versioned tag. + if provenanceOpts.ExpectedVersionedTag != nil { + if err := prov.VerifyVersionedTag(*provenanceOpts.ExpectedVersionedTag); err != nil { + return nil, "", err + } + } + + content, err := prov.GetVerifiedIntotoStatement() + if err != nil { + return nil, "", err + } + return content, builderID, nil } diff --git a/verifiers/internal/gha/builder.go b/verifiers/internal/gha/builder.go index fe2e97767..05223fb07 100644 --- a/verifiers/internal/gha/builder.go +++ b/verifiers/internal/gha/builder.go @@ -32,7 +32,8 @@ var defaultContainerTrustedReusableWorkflows = map[string]bool{ // builerOpts, or against the set of defaultBuilders provided. func VerifyWorkflowIdentity(id *WorkflowIdentity, builderOpts *options.BuilderOpts, source string, - defaultBuilders map[string]bool) (string, error) { + defaultBuilders map[string]bool, +) (string, error) { // cert URI path is /org/repo/path/to/workflow@ref workflowPath := strings.SplitN(id.JobWobWorkflowRef, "@", 2) if len(workflowPath) < 2 { diff --git a/verifiers/internal/gha/provenance.go b/verifiers/internal/gha/provenance.go index 53a682df5..1ab45a500 100644 --- a/verifiers/internal/gha/provenance.go +++ b/verifiers/internal/gha/provenance.go @@ -26,13 +26,17 @@ func EnvelopeFromBytes(payload []byte) (env *dsselib.Envelope, err error) { } func provenanceFromEnv(env *dsselib.Envelope) (prov *intoto.ProvenanceStatement, err error) { + if env.PayloadType != "application/vnd.in-toto+json" { + return nil, fmt.Errorf("%w: expected payload type 'application/vnd.in-toto+json', got '%s'", + serrors.ErrorInvalidDssePayload, env.PayloadType) + } pyld, err := base64.StdEncoding.DecodeString(env.Payload) if err != nil { - return nil, fmt.Errorf("%w: %s", serrors.ErrorInvalidDssePayload, "decoding payload") + return nil, fmt.Errorf("%w: %s:", serrors.ErrorInvalidDssePayload, err.Error()) } prov = &intoto.ProvenanceStatement{} if err := json.Unmarshal(pyld, prov); err != nil { - return nil, fmt.Errorf("%w: %s", serrors.ErrorInvalidDssePayload, "unmarshalling json") + return nil, fmt.Errorf("%w: %s", serrors.ErrorInvalidDssePayload, err.Error()) } return } diff --git a/verifiers/internal/gha/verifier.go b/verifiers/internal/gha/verifier.go index cf39ed672..e3a7896f8 100644 --- a/verifiers/internal/gha/verifier.go +++ b/verifiers/internal/gha/verifier.go @@ -97,7 +97,7 @@ func (v *GHAVerifier) VerifyArtifact(ctx context.Context, // VerifyImage verifies provenance for an OCI image. func (v *GHAVerifier) VerifyImage(ctx context.Context, - artifactImage string, + provenance []byte, artifactImage string, provenanceOpts *options.ProvenanceOpts, builderOpts *options.BuilderOpts, ) ([]byte, string, error) { diff --git a/verifiers/verifier.go b/verifiers/verifier.go index 934318d90..3af722d8c 100644 --- a/verifiers/verifier.go +++ b/verifiers/verifier.go @@ -38,7 +38,7 @@ func Verify(ctx context.Context, artifactImage string, // By default, try the GHA builders. if artifactImage != "" { - return verifier.VerifyImage(ctx, artifactImage, provenanceOpts, builderOpts) + return verifier.VerifyImage(ctx, provenance, artifactImage, provenanceOpts, builderOpts) } return verifier.VerifyArtifact(ctx, provenance, artifactHash, provenanceOpts, builderOpts)