Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gcb: add gcb compatibility for provenance formats and buckets #292

Merged
merged 1 commit into from
Oct 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion cli/slsa-verifier/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -821,6 +821,13 @@ func Test_runVerifyGCBArtifactImage(t *testing.T) {
provenance: "gcloud-container-github.json",
source: "github.com/laurentsimon/gcb-tests",
},
{
name: "valid main branch gcs",
artifact: "gcloud-container-gcs",
provenance: "gcloud-container-gcs.json",
minversion: "v0.3",
source: "gs://slsa-tooling_cloudbuild/source/1663616632.078353-fc7db143dcc64b5f9fe71d0497125ca1.tgz",
},
{
name: "mismatch input builder version",
artifact: "gcloud-container-github",
Expand Down Expand Up @@ -966,7 +973,7 @@ func Test_runVerifyGCBArtifactImage(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()

checkVersions := getBuildersAndVersions(t, "", nil, GCB_ARTIFACT_IMAGE_BUILDERS)
checkVersions := getBuildersAndVersions(t, tt.minversion, nil, GCB_ARTIFACT_IMAGE_BUILDERS)
if tt.noversion {
checkVersions = []string{""}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
{
"image_summary": {
"digest": "sha256:71efcbb3f03f5914dcde87e38d3813f63982b475f76887babf25f76fff760d3c",
"fully_qualified_digest": "us-west2-docker.pkg.dev/slsa-tooling/example-package-repo/e2e-gcb-workflow_dispatch-main-cloudbuild-slsa3@sha256:71efcbb3f03f5914dcde87e38d3813f63982b475f76887babf25f76fff760d3c",
"registry": "us-west2-docker.pkg.dev",
"repository": "example-package-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.3"
},
"materials": [
{
"digest": {
"md5": "7d4467b5b74959c39c08b3c8545ffac1",
"sha256": "9c4e7e28bef5c9ffabea170a40bfb6e286e170100c0eb02d7e06c7dd8c2238e4"
},
"uri": "gs://slsa-tooling_cloudbuild/source/1663616632.078353-fc7db143dcc64b5f9fe71d0497125ca1.tgz#1663616635134845"
}
],
"metadata": {
"buildFinishedOn": "2022-09-19T19:44:34.152421Z",
"buildInvocationId": "393794dc-82ec-495b-8f84-659dec87d381",
"buildStartedOn": "2022-09-19T19:43:56.076114651Z"
},
"recipe": {
"arguments": {
"@type": "type.googleapis.com/google.devtools.cloudbuild.v1.Build",
"id": "393794dc-82ec-495b-8f84-659dec87d381",
"name": "projects/819720953812/locations/us-west2/builds/393794dc-82ec-495b-8f84-659dec87d381",
"options": {
"logging": "CLOUD_LOGGING_ONLY",
"pool": {},
"requestedVerifyOption": "VERIFIED",
"sourceProvenanceHash": [
"SHA256"
]
},
"sourceProvenance": {
"fileHashes": {
"gs://slsa-tooling_cloudbuild/source/1663616632.078353-fc7db143dcc64b5f9fe71d0497125ca1.tgz#1663616635134845": {
"fileHash": [
{
"type": "SHA256",
"value": "nE5+KL71yf+r6hcKQL+24obhcBAMDrAtfgbH3YwiOOQ="
},
{
"type": "MD5",
"value": "fURntbdJWcOcCLPIVF/6wQ=="
}
]
}
},
"resolvedStorageSource": {
"bucket": "slsa-tooling_cloudbuild",
"generation": "1663616635134845",
"object": "source/1663616632.078353-fc7db143dcc64b5f9fe71d0497125ca1.tgz"
}
},
"steps": [
{
"args": [
"build",
"-t",
"us-west2-docker.pkg.dev/slsa-tooling/example-package-repo/e2e-gcb-workflow_dispatch-main-cloudbuild-slsa3",
"."
],
"name": "gcr.io/cloud-builders/docker",
"pullTiming": {
"endTime": "2022-09-19T19:44:02.300470459Z",
"startTime": "2022-09-19T19:44:02.296558439Z"
},
"status": "SUCCESS",
"timing": {
"endTime": "2022-09-19T19:44:32.329696525Z",
"startTime": "2022-09-19T19:44:02.296558439Z"
}
}
],
"substitutions": {
"_IMAGE_NAME": "slsa-tooling/example-package-repo/e2e-gcb-workflow_dispatch-main-cloudbuild-slsa3"
}
},
"definedInMaterial": "-1",
"type": "https://cloudbuild.googleapis.com/CloudBuildSteps@v0.1"
}
},
"subject": [
{
"digest": {
"sha256": "71efcbb3f03f5914dcde87e38d3813f63982b475f76887babf25f76fff760d3c"
},
"name": "https://us-west2-docker.pkg.dev/slsa-tooling/example-package-repo/e2e-gcb-workflow_dispatch-main-cloudbuild-slsa3"
},
{
"digest": {
"sha256": "71efcbb3f03f5914dcde87e38d3813f63982b475f76887babf25f76fff760d3c"
},
"name": "https://us-west2-docker.pkg.dev/slsa-tooling/example-package-repo/e2e-gcb-workflow_dispatch-main-cloudbuild-slsa3:latest"
}
]
}
},
"createTime": "2022-09-19T19:44:35.879537Z",
"envelope": {
"payload": "eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjAuMSIsInByZWRpY2F0ZSI6eyJidWlsZGVyIjp7ImlkIjoiaHR0cHM6Ly9jbG91ZGJ1aWxkLmdvb2dsZWFwaXMuY29tL0dvb2dsZUhvc3RlZFdvcmtlckB2MC4zIn0sIm1hdGVyaWFscyI6W3siZGlnZXN0Ijp7Im1kNSI6IjdkNDQ2N2I1Yjc0OTU5YzM5YzA4YjNjODU0NWZmYWMxIiwic2hhMjU2IjoiOWM0ZTdlMjhiZWY1YzlmZmFiZWExNzBhNDBiZmI2ZTI4NmUxNzAxMDBjMGViMDJkN2UwNmM3ZGQ4YzIyMzhlNCJ9LCJ1cmkiOiJnczovL3Nsc2EtdG9vbGluZ19jbG91ZGJ1aWxkL3NvdXJjZS8xNjYzNjE2NjMyLjA3ODM1My1mYzdkYjE0M2RjYzY0YjVmOWZlNzFkMDQ5NzEyNWNhMS50Z3ojMTY2MzYxNjYzNTEzNDg0NSJ9XSwibWV0YWRhdGEiOnsiYnVpbGRGaW5pc2hlZE9uIjoiMjAyMi0wOS0xOVQxOTo0NDozNC4xNTI0MjFaIiwiYnVpbGRJbnZvY2F0aW9uSWQiOiIzOTM3OTRkYy04MmVjLTQ5NWItOGY4NC02NTlkZWM4N2QzODEiLCJidWlsZFN0YXJ0ZWRPbiI6IjIwMjItMDktMTlUMTk6NDM6NTYuMDc2MTE0NjUxWiJ9LCJyZWNpcGUiOnsiYXJndW1lbnRzIjp7IkB0eXBlIjoidHlwZS5nb29nbGVhcGlzLmNvbS9nb29nbGUuZGV2dG9vbHMuY2xvdWRidWlsZC52MS5CdWlsZCIsImlkIjoiMzkzNzk0ZGMtODJlYy00OTViLThmODQtNjU5ZGVjODdkMzgxIiwibmFtZSI6InByb2plY3RzLzgxOTcyMDk1MzgxMi9sb2NhdGlvbnMvdXMtd2VzdDIvYnVpbGRzLzM5Mzc5NGRjLTgyZWMtNDk1Yi04Zjg0LTY1OWRlYzg3ZDM4MSIsIm9wdGlvbnMiOnsibG9nZ2luZyI6IkNMT1VEX0xPR0dJTkdfT05MWSIsInBvb2wiOnt9LCJyZXF1ZXN0ZWRWZXJpZnlPcHRpb24iOiJWRVJJRklFRCIsInNvdXJjZVByb3ZlbmFuY2VIYXNoIjpbIlNIQTI1NiJdfSwic291cmNlUHJvdmVuYW5jZSI6eyJmaWxlSGFzaGVzIjp7ImdzOi8vc2xzYS10b29saW5nX2Nsb3VkYnVpbGQvc291cmNlLzE2NjM2MTY2MzIuMDc4MzUzLWZjN2RiMTQzZGNjNjRiNWY5ZmU3MWQwNDk3MTI1Y2ExLnRneiMxNjYzNjE2NjM1MTM0ODQ1Ijp7ImZpbGVIYXNoIjpbeyJ0eXBlIjoiU0hBMjU2IiwidmFsdWUiOiJuRTUrS0w3MXlmK3I2aGNLUUwrMjRvYmhjQkFNRHJBdGZnYkgzWXdpT09RPSJ9LHsidHlwZSI6Ik1ENSIsInZhbHVlIjoiZlVSbnRiZEpXY09jQ0xQSVZGLzZ3UT09In1dfX0sInJlc29sdmVkU3RvcmFnZVNvdXJjZSI6eyJidWNrZXQiOiJzbHNhLXRvb2xpbmdfY2xvdWRidWlsZCIsImdlbmVyYXRpb24iOiIxNjYzNjE2NjM1MTM0ODQ1Iiwib2JqZWN0Ijoic291cmNlLzE2NjM2MTY2MzIuMDc4MzUzLWZjN2RiMTQzZGNjNjRiNWY5ZmU3MWQwNDk3MTI1Y2ExLnRneiJ9fSwic3RlcHMiOlt7ImFyZ3MiOlsiYnVpbGQiLCItdCIsInVzLXdlc3QyLWRvY2tlci5wa2cuZGV2L3Nsc2EtdG9vbGluZy9leGFtcGxlLXBhY2thZ2UtcmVwby9lMmUtZ2NiLXdvcmtmbG93X2Rpc3BhdGNoLW1haW4tY2xvdWRidWlsZC1zbHNhMyIsIi4iXSwibmFtZSI6Imdjci5pby9jbG91ZC1idWlsZGVycy9kb2NrZXIiLCJwdWxsVGltaW5nIjp7ImVuZFRpbWUiOiIyMDIyLTA5LTE5VDE5OjQ0OjAyLjMwMDQ3MDQ1OVoiLCJzdGFydFRpbWUiOiIyMDIyLTA5LTE5VDE5OjQ0OjAyLjI5NjU1ODQzOVoifSwic3RhdHVzIjoiU1VDQ0VTUyIsInRpbWluZyI6eyJlbmRUaW1lIjoiMjAyMi0wOS0xOVQxOTo0NDozMi4zMjk2OTY1MjVaIiwic3RhcnRUaW1lIjoiMjAyMi0wOS0xOVQxOTo0NDowMi4yOTY1NTg0MzlaIn19XSwic3Vic3RpdHV0aW9ucyI6eyJfSU1BR0VfTkFNRSI6InNsc2EtdG9vbGluZy9leGFtcGxlLXBhY2thZ2UtcmVwby9lMmUtZ2NiLXdvcmtmbG93X2Rpc3BhdGNoLW1haW4tY2xvdWRidWlsZC1zbHNhMyJ9fSwiZGVmaW5lZEluTWF0ZXJpYWwiOiItMSIsInR5cGUiOiJodHRwczovL2Nsb3VkYnVpbGQuZ29vZ2xlYXBpcy5jb20vQ2xvdWRCdWlsZFN0ZXBzQHYwLjEifX0sInByZWRpY2F0ZVR5cGUiOiJodHRwczovL3Nsc2EuZGV2L3Byb3ZlbmFuY2UvdjAuMSIsInNsc2FQcm92ZW5hbmNlIjp7ImJ1aWxkZXIiOnsiaWQiOiJodHRwczovL2Nsb3VkYnVpbGQuZ29vZ2xlYXBpcy5jb20vR29vZ2xlSG9zdGVkV29ya2VyQHYwLjMifSwibWF0ZXJpYWxzIjpbeyJkaWdlc3QiOnsibWQ1IjoiN2Q0NDY3YjViNzQ5NTljMzljMDhiM2M4NTQ1ZmZhYzEiLCJzaGEyNTYiOiI5YzRlN2UyOGJlZjVjOWZmYWJlYTE3MGE0MGJmYjZlMjg2ZTE3MDEwMGMwZWIwMmQ3ZTA2YzdkZDhjMjIzOGU0In0sInVyaSI6ImdzOi8vc2xzYS10b29saW5nX2Nsb3VkYnVpbGQvc291cmNlLzE2NjM2MTY2MzIuMDc4MzUzLWZjN2RiMTQzZGNjNjRiNWY5ZmU3MWQwNDk3MTI1Y2ExLnRneiMxNjYzNjE2NjM1MTM0ODQ1In1dLCJtZXRhZGF0YSI6eyJidWlsZEZpbmlzaGVkT24iOiIyMDIyLTA5LTE5VDE5OjQ0OjM0LjE1MjQyMVoiLCJidWlsZEludm9jYXRpb25JZCI6IjM5Mzc5NGRjLTgyZWMtNDk1Yi04Zjg0LTY1OWRlYzg3ZDM4MSIsImJ1aWxkU3RhcnRlZE9uIjoiMjAyMi0wOS0xOVQxOTo0Mzo1Ni4wNzYxMTQ2NTFaIn0sInJlY2lwZSI6eyJhcmd1bWVudHMiOnsiQHR5cGUiOiJ0eXBlLmdvb2dsZWFwaXMuY29tL2dvb2dsZS5kZXZ0b29scy5jbG91ZGJ1aWxkLnYxLkJ1aWxkIiwiaWQiOiIzOTM3OTRkYy04MmVjLTQ5NWItOGY4NC02NTlkZWM4N2QzODEiLCJuYW1lIjoicHJvamVjdHMvODE5NzIwOTUzODEyL2xvY2F0aW9ucy91cy13ZXN0Mi9idWlsZHMvMzkzNzk0ZGMtODJlYy00OTViLThmODQtNjU5ZGVjODdkMzgxIiwib3B0aW9ucyI6eyJsb2dnaW5nIjoiQ0xPVURfTE9HR0lOR19PTkxZIiwicG9vbCI6e30sInJlcXVlc3RlZFZlcmlmeU9wdGlvbiI6IlZFUklGSUVEIiwic291cmNlUHJvdmVuYW5jZUhhc2giOlsiU0hBMjU2Il19LCJzb3VyY2VQcm92ZW5hbmNlIjp7ImZpbGVIYXNoZXMiOnsiZ3M6Ly9zbHNhLXRvb2xpbmdfY2xvdWRidWlsZC9zb3VyY2UvMTY2MzYxNjYzMi4wNzgzNTMtZmM3ZGIxNDNkY2M2NGI1ZjlmZTcxZDA0OTcxMjVjYTEudGd6IzE2NjM2MTY2MzUxMzQ4NDUiOnsiZmlsZUhhc2giOlt7InR5cGUiOiJTSEEyNTYiLCJ2YWx1ZSI6Im5FNStLTDcxeWYrcjZoY0tRTCsyNG9iaGNCQU1EckF0ZmdiSDNZd2lPT1E9In0seyJ0eXBlIjoiTUQ1IiwidmFsdWUiOiJmVVJudGJkSldjT2NDTFBJVkYvNndRPT0ifV19fSwicmVzb2x2ZWRTdG9yYWdlU291cmNlIjp7ImJ1Y2tldCI6InNsc2EtdG9vbGluZ19jbG91ZGJ1aWxkIiwiZ2VuZXJhdGlvbiI6IjE2NjM2MTY2MzUxMzQ4NDUiLCJvYmplY3QiOiJzb3VyY2UvMTY2MzYxNjYzMi4wNzgzNTMtZmM3ZGIxNDNkY2M2NGI1ZjlmZTcxZDA0OTcxMjVjYTEudGd6In19LCJzdGVwcyI6W3siYXJncyI6WyJidWlsZCIsIi10IiwidXMtd2VzdDItZG9ja2VyLnBrZy5kZXYvc2xzYS10b29saW5nL2V4YW1wbGUtcGFja2FnZS1yZXBvL2UyZS1nY2Itd29ya2Zsb3dfZGlzcGF0Y2gtbWFpbi1jbG91ZGJ1aWxkLXNsc2EzIiwiLiJdLCJuYW1lIjoiZ2NyLmlvL2Nsb3VkLWJ1aWxkZXJzL2RvY2tlciIsInB1bGxUaW1pbmciOnsiZW5kVGltZSI6IjIwMjItMDktMTlUMTk6NDQ6MDIuMzAwNDcwNDU5WiIsInN0YXJ0VGltZSI6IjIwMjItMDktMTlUMTk6NDQ6MDIuMjk2NTU4NDM5WiJ9LCJzdGF0dXMiOiJTVUNDRVNTIiwidGltaW5nIjp7ImVuZFRpbWUiOiIyMDIyLTA5LTE5VDE5OjQ0OjMyLjMyOTY5NjUyNVoiLCJzdGFydFRpbWUiOiIyMDIyLTA5LTE5VDE5OjQ0OjAyLjI5NjU1ODQzOVoifX1dLCJzdWJzdGl0dXRpb25zIjp7Il9JTUFHRV9OQU1FIjoic2xzYS10b29saW5nL2V4YW1wbGUtcGFja2FnZS1yZXBvL2UyZS1nY2Itd29ya2Zsb3dfZGlzcGF0Y2gtbWFpbi1jbG91ZGJ1aWxkLXNsc2EzIn19LCJkZWZpbmVkSW5NYXRlcmlhbCI6Ii0xIiwidHlwZSI6Imh0dHBzOi8vY2xvdWRidWlsZC5nb29nbGVhcGlzLmNvbS9DbG91ZEJ1aWxkU3RlcHNAdjAuMSJ9fSwic3ViamVjdCI6W3siZGlnZXN0Ijp7InNoYTI1NiI6IjcxZWZjYmIzZjAzZjU5MTRkY2RlODdlMzhkMzgxM2Y2Mzk4MmI0NzVmNzY4ODdiYWJmMjVmNzZmZmY3NjBkM2MifSwibmFtZSI6Imh0dHBzOi8vdXMtd2VzdDItZG9ja2VyLnBrZy5kZXYvc2xzYS10b29saW5nL2V4YW1wbGUtcGFja2FnZS1yZXBvL2UyZS1nY2Itd29ya2Zsb3dfZGlzcGF0Y2gtbWFpbi1jbG91ZGJ1aWxkLXNsc2EzIn0seyJkaWdlc3QiOnsic2hhMjU2IjoiNzFlZmNiYjNmMDNmNTkxNGRjZGU4N2UzOGQzODEzZjYzOTgyYjQ3NWY3Njg4N2JhYmYyNWY3NmZmZjc2MGQzYyJ9LCJuYW1lIjoiaHR0cHM6Ly91cy13ZXN0Mi1kb2NrZXIucGtnLmRldi9zbHNhLXRvb2xpbmcvZXhhbXBsZS1wYWNrYWdlLXJlcG8vZTJlLWdjYi13b3JrZmxvd19kaXNwYXRjaC1tYWluLWNsb3VkYnVpbGQtc2xzYTM6bGF0ZXN0In1dfQ==",
"payloadType": "application/vnd.in-toto+json",
"signatures": [
{
"keyid": "projects/verified-builder/locations/us-west2/keyRings/attestor/cryptoKeys/builtByGCB/cryptoKeyVersions/1",
"sig": "MEYCIQDRCd9adBP6_ze18NxtlZ8yVqcETUGdpYQ8C1MKFEYNMAIhAMMFKpKDVbbUpxIcf_5vHUnuXEOMSybG9IS_43Glp6zH"
}
]
},
"kind": "BUILD",
"name": "projects/slsa-tooling/occurrences/970d284c-ab7a-4121-9a0e-52812595263b",
"noteName": "projects/verified-builder/notes/intoto_393794dc-82ec-495b-8f84-659dec87d381",
"resourceUri": "https://us-west2-docker.pkg.dev/slsa-tooling/example-package-repo/e2e-gcb-workflow_dispatch-main-cloudbuild-slsa3@sha256:71efcbb3f03f5914dcde87e38d3813f63982b475f76887babf25f76fff760d3c",
"updateTime": "2022-09-19T19:44:35.879537Z"
}
]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"schemaVersion": 2,
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"config": {
"mediaType": "application/vnd.docker.container.image.v1+json",
"size": 1748,
"digest": "sha256:40391da7d19c1900fc744f227bdcb229f9a14ce6390c1e76337361e2b7c7cc60"
},
"layers": [
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 804101,
"digest": "sha256:b9f88661235d25835ef747dab426861d51c4e9923b92623d422d7ac58eb123e9"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 608694,
"digest": "sha256:753a0c6a100dcd1b6ad628933020e3a9d388d7c05aa3f2dd8795196dd40f2a2e"
}
]
}
68 changes: 68 additions & 0 deletions verifiers/internal/gcb/intoto.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package gcb

// Copy of github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.1
Copy link
Member

Choose a reason for hiding this comment

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

nit: add a "NOTE: " prefix to the comment.

// This holds an internal copy of in-toto-golang's structs for
// SLSA predicates to handle GCB's incompatibility with the
// published specification. Specifically, GCB provenance currently
// produces a string for ProvenancePredicate.Recipe.DefinedInMaterial
// rather than the compliant signed integer.

import "time"

const (
// PredicateSLSAProvenance represents a build provenance for an artifact.
PredicateSLSAProvenance = "https://slsa.dev/provenance/v0.1"
)

// ProvenancePredicate is the provenance predicate definition.
type ProvenancePredicate struct {
Builder ProvenanceBuilder `json:"builder"`
Recipe ProvenanceRecipe `json:"recipe"`
Metadata *ProvenanceMetadata `json:"metadata,omitempty"`
Materials []ProvenanceMaterial `json:"materials,omitempty"`
}

// ProvenanceBuilder idenfifies the entity that executed the build steps.
type ProvenanceBuilder struct {
ID string `json:"id"`
}

// ProvenanceRecipe describes the actions performed by the builder.
type ProvenanceRecipe struct {
Type string `json:"type"`
// DefinedInMaterial can be sent as the null pointer to indicate that
// the value is not present.
// DefinedInMaterial *int `json:"definedInMaterial,omitempty"`
Copy link
Member

Choose a reason for hiding this comment

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

nit: add a short local comment as to why this is commented out. Maybe point to comment at top of file.

EntryPoint string `json:"entryPoint"`
Arguments interface{} `json:"arguments,omitempty"`
Environment interface{} `json:"environment,omitempty"`
}

// ProvenanceMetadata contains metadata for the built artifact.
type ProvenanceMetadata struct {
// Use pointer to make sure that the abscense of a time is not
// encoded as the Epoch time.
BuildStartedOn *time.Time `json:"buildStartedOn,omitempty"`
BuildFinishedOn *time.Time `json:"buildFinishedOn,omitempty"`
Completeness ProvenanceComplete `json:"completeness"`
Reproducible bool `json:"reproducible"`
}

// ProvenanceMaterial defines the materials used to build an artifact.
type ProvenanceMaterial struct {
URI string `json:"uri"`
Digest DigestSet `json:"digest,omitempty"`
}

// ProvenanceComplete indicates wheter the claims in build/recipe are complete.
// For in depth information refer to the specifictaion:
// https://github.com/in-toto/attestation/blob/v0.1.0/spec/predicates/provenance.md
type ProvenanceComplete struct {
Arguments bool `json:"arguments"`
Environment bool `json:"environment"`
Materials bool `json:"materials"`
}

// DigestSet contains a set of digests. It is represented as a map from
// algorithm name to lowercase hex-encoded value.
type DigestSet map[string]string
24 changes: 14 additions & 10 deletions verifiers/internal/gcb/provenance.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import (
"github.com/google/go-cmp/cmp"

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"
Expand All @@ -29,7 +28,7 @@ var GCBBuilderIDs = []string{

type v01IntotoStatement struct {
intoto.StatementHeader
Predicate slsa01.ProvenancePredicate `json:"predicate"`
Predicate ProvenancePredicate `json:"predicate"`
}

// The GCB provenance contains a human-readable version of the intoto
Expand All @@ -38,7 +37,7 @@ type v01IntotoStatement struct {
// by the GCB team.
type v01GCBIntotoStatement struct {
intoto.StatementHeader
SlsaProvenance slsa01.ProvenancePredicate `json:"slsaProvenance"`
SlsaProvenance ProvenancePredicate `json:"slsaProvenance"`
}

type provenance struct {
Expand Down Expand Up @@ -72,7 +71,7 @@ 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 nil, fmt.Errorf("json.Unmarshal gcloud provenance: %w", err)
}

return &Provenance{
Expand Down Expand Up @@ -205,9 +204,9 @@ func (self *Provenance) VerifyIntotoHeaders() error {
}

// https://slsa.dev/provenance/v0.1
if statement.StatementHeader.PredicateType != slsa01.PredicateSLSAProvenance {
if statement.StatementHeader.PredicateType != PredicateSLSAProvenance {
return fmt.Errorf("%w: expected statement predicate type '%s', got '%s'",
serrors.ErrorInvalidDssePayload, slsa01.PredicateSLSAProvenance, statement.StatementHeader.PredicateType)
serrors.ErrorInvalidDssePayload, PredicateSLSAProvenance, statement.StatementHeader.PredicateType)
}

return nil
Expand Down Expand Up @@ -357,7 +356,9 @@ func (self *Provenance) VerifySourceURI(expectedSourceURI string, builderID util
return fmt.Errorf("%w: no materials", serrors.ErrorInvalidDssePayload)
}
uri := materials[0].URI
if !strings.HasPrefix(expectedSourceURI, "https://") {

// It is possible that GCS builds at level 2 use GCS sources, prefixed by gs://.
if strings.HasPrefix(uri, "https://") && !strings.HasPrefix(expectedSourceURI, "https://") {
Copy link
Member

Choose a reason for hiding this comment

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

nit: You might also leave a note as to why this is necessary in the first place. It's not necessarily obvious why "https://" might need to be prefixed at the beginning.

Copy link
Member

Choose a reason for hiding this comment

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

Also, consider checking for any URI scheme rather than "https://" specifically. So you don't end up with strange URIs like "https://http://example.com/..." if the user enters "--source http://example.com"

Suggested change
if strings.HasPrefix(uri, "https://") && !strings.HasPrefix(expectedSourceURI, "https://") {
if strings.HasPrefix(uri, "https://") && !strings.HasPrefix(expectedSourceURI, "://") {

expectedSourceURI = "https://" + expectedSourceURI
}

Expand All @@ -367,14 +368,17 @@ func (self *Provenance) VerifySourceURI(expectedSourceURI string, builderID util
case "v0.2":
// In v0.2, it uses format
// `https://github.com/laurentsimon/gcb-tests/commit/01ce393d04eb6df2a7b2b3e95d4126e687afb7ae`.
if !strings.HasPrefix(uri, expectedSourceURI+"/commit/") {
if !strings.HasPrefix(uri, expectedSourceURI+"/commit/") &&
!strings.HasPrefix(uri, expectedSourceURI+"#") {
return fmt.Errorf("%w: expected '%s', got '%s'",
serrors.ErrorMismatchSource, expectedSourceURI, uri)
}
// In v0.3, it uses the standard intoto and has the commit sha in its own
// `digest.sha1` field.
case "v0.3":
if uri != expectedSourceURI {
// The latter case is a versioned GCS source.
if uri != expectedSourceURI &&
!strings.HasPrefix(uri, expectedSourceURI+"#") {
return fmt.Errorf("%w: expected '%s', got '%s'",
serrors.ErrorMismatchSource, expectedSourceURI, uri)
}
Expand Down Expand Up @@ -418,7 +422,7 @@ func decodeSignature(s string) ([]byte, []error) {
}

// verifySignatures iterates over all the signatures in the DSSE and verifies them.
// It succeeds if one of them can ne verified.
// It succeeds if one of them can be verified.
func (self *Provenance) verifySignatures(prov *provenance) error {
// Verify the envelope type. It should be an intoto type.
if prov.Envelope.PayloadType != intoto.PayloadType {
Expand Down
Loading