diff --git a/cli/slsa-verifier/main_regression_test.go b/cli/slsa-verifier/main_regression_test.go index 005a2642d..780733c6b 100644 --- a/cli/slsa-verifier/main_regression_test.go +++ b/cli/slsa-verifier/main_regression_test.go @@ -1526,12 +1526,57 @@ func Test_runVerifyGithubAttestation(t *testing.T) { bcrPublisherBuilderID := "https://github.com/bazel-contrib/publish-to-bcr/.github/workflows/publish.yaml" tests := []struct { - name string - artifact string - source string - builderID string - err error + name string + artifact string + source string + sourceTag *string + sourceVersionTag *string + builderID string + err error }{ + { + name: "module.bazel using publishing builder", + artifact: "MODULE.bazel", + source: "github.com/aspect-build/rules_lint", + builderID: bcrPublisherBuilderID, + }, + { + name: "module.bazel using publishing builder and source tag", + artifact: "MODULE-on-tag.bazel", + source: "github.com/aspect-build/rules_lint", + sourceTag: pString("v1.3.4"), + builderID: bcrPublisherBuilderID, + }, + { + name: "module.bazel using publishing builder and incorrect source tag", + artifact: "MODULE-on-tag.bazel", + source: "github.com/aspect-build/rules_lint", + sourceTag: pString("v1.3.5"), + builderID: bcrPublisherBuilderID, + err: serrors.ErrorMismatchTag, + }, + { + name: "module.bazel using publishing builder and source versioned tag", + artifact: "MODULE-on-tag.bazel", + source: "github.com/aspect-build/rules_lint", + sourceVersionTag: pString("v1.3.4"), + builderID: bcrPublisherBuilderID, + }, + { + name: "module.bazel using publishing builder and partial source versioned tag", + artifact: "MODULE-on-tag.bazel", + source: "github.com/aspect-build/rules_lint", + sourceVersionTag: pString("v1.3"), + builderID: bcrPublisherBuilderID, + }, + { + name: "module.bazel using publishing builder and incorrect source versioned tag", + artifact: "MODULE-on-tag.bazel", + source: "github.com/aspect-build/rules_lint", + sourceVersionTag: pString("v1.3.5"), + builderID: bcrPublisherBuilderID, + err: serrors.ErrorMismatchVersionedTag, + }, { name: "module.bazel using publishing builder", artifact: "MODULE.bazel", @@ -1574,9 +1619,11 @@ func Test_runVerifyGithubAttestation(t *testing.T) { // we treat these single entry *.intoto.jsonl bundles as single attestations attestationPath := fmt.Sprintf("%s.intoto.jsonl", artifactPath) cmd := verify.VerifyGithubAttestationCommand{ - AttestationPath: attestationPath, - BuilderID: &tt.builderID, - SourceURI: tt.source, + AttestationPath: attestationPath, + BuilderID: &tt.builderID, + SourceTag: tt.sourceTag, + SourceVersionTag: tt.sourceVersionTag, + SourceURI: tt.source, } _, err := cmd.Exec(context.Background(), artifactPath) diff --git a/cli/slsa-verifier/testdata/bcr/MODULE-on-tag.bazel b/cli/slsa-verifier/testdata/bcr/MODULE-on-tag.bazel new file mode 100644 index 000000000..7b8533baf --- /dev/null +++ b/cli/slsa-verifier/testdata/bcr/MODULE-on-tag.bazel @@ -0,0 +1,31 @@ +"Bazel dependencies" + +module( + name = "aspect_rules_lint", + version = "1.3.4", + compatibility_level = 1, +) + +bazel_dep(name = "aspect_bazel_lib", version = "2.7.7") + +# Needed in the root because we use js_lib_helpers in our aspect impl +# Minimum version needs 'chore: bump bazel-lib to 2.0 by @alexeagle in #1311' +# to allow users on bazel-lib 2.0 +bazel_dep(name = "aspect_rules_js", version = "1.40.0") +bazel_dep(name = "bazel_features", version = "1.0.0") +bazel_dep(name = "bazel_skylib", version = "1.4.2") +bazel_dep(name = "platforms", version = "0.0.7") +bazel_dep(name = "rules_multirun", version = "0.9.0") +bazel_dep(name = "rules_multitool", version = "0.4.0") +bazel_dep(name = "rules_diff", version = "1.0.0") + +# Needed in the root because we dereference ProtoInfo in our aspect impl +bazel_dep(name = "rules_proto", version = "6.0.0") + +# Needed in the root because we dereference the toolchain in our aspect impl +bazel_dep(name = "rules_buf", version = "0.1.1") + +multitool = use_extension("@rules_multitool//multitool:extension.bzl", "multitool") +multitool.hub(lockfile = "//format:multitool.lock.json") +multitool.hub(lockfile = "//lint:multitool.lock.json") +use_repo(multitool, "multitool") diff --git a/cli/slsa-verifier/testdata/bcr/MODULE-on-tag.bazel.intoto.jsonl b/cli/slsa-verifier/testdata/bcr/MODULE-on-tag.bazel.intoto.jsonl new file mode 100644 index 000000000..bd762312d --- /dev/null +++ b/cli/slsa-verifier/testdata/bcr/MODULE-on-tag.bazel.intoto.jsonl @@ -0,0 +1 @@ +{"mediaType":"application/vnd.dev.sigstore.bundle.v0.3+json","verificationMaterial":{"certificate":{"rawBytes":"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"},"tlogEntries":[{"logIndex":"195660311","logId":{"keyId":"wNI9atQGlz+VWfO6LRygH4QUfY/8W4RFwiT5i5WRgB0="},"kindVersion":{"kind":"dsse","version":"0.0.1"},"integratedTime":"1744400792","inclusionPromise":{"signedEntryTimestamp":"MEYCIQD9O8mlJxO61Q2RA2TNqD/s/chcnyqV1ywFfXhYVfPzdgIhAJ4JohPCwI4w8dUczG0BOU0ecKwl3KXz7U5A/MouVb6Y"},"inclusionProof":{"logIndex":"73756049","rootHash":"qcjRmhfDT/ST4bUZKPwxdoNtWR3/96ycc3nIoTSELOs=","treeSize":"73756051","hashes":["7SDybmjPvVsgpSZO1KLhi1kBCrjeNv293CQVnRzwkA8=","7qUKLxQorgEM8Udd6RfAT6jTFEEzTbaA/mG63t3DdSw=","pMX3FNNY5Gw5HxkvCQI7gU4jnK0CUcd9jLMfop39mH0=","ecrDPMqwoYQa6Ub01gn4+OhP+mZcSplx/EXHRCSCMGw=","EyXgYjiKElD+8RAZMIeNlVYz6/uRFfhBsrUTT5Gz1r8=","PsyvDwhRew4z1mhH/NZkEh3V31yzDglbaCmZlSmOF1A=","e99hRDfz9PIv48S0TPJehSfNR/o7m6b8KInxd5XTqq0=","cOIIp4bX93gqYoR4rLsLwyevfYS9x3dFSJ7b21xUr9U=","f8/OvcM0ZwVTG2sfoN7/DJwD9BQNJjcJ3ZV9Mf1GAhI=","9WtmPzULWB/Z+vuB98kYTj1jHEM4mBRjRXP3F8z/dw8=","WDa2SJgceO7MYdLyxyaG9hj34lbB7NRR4+OiHScRXTs=","bUMWi9afi8M+WrpEiXczKOIZWruoe38aV/lXN5Z5o9E=","WEm5OgPzJpYROv+4CcrieexCYyQKrLUH3hbxmcQQ+DM=","7v8qPHNDLerpduaMx06eb/MwgoQwczTn/cYGKX/9wZ4="],"checkpoint":{"envelope":"rekor.sigstore.dev - 1193050959916656506\n73756051\nqcjRmhfDT/ST4bUZKPwxdoNtWR3/96ycc3nIoTSELOs=\n\n— rekor.sigstore.dev wNI9ajBEAiAuhsc5BOiok2v9btk8OvcvNX8wFBgrSTWhayCxEFaLbAIgAIuHT6PPASektFT3BTV5pYws3ju1JKyIZAhRuhoQvcQ=\n"}},"canonicalizedBody":"eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiZHNzZSIsInNwZWMiOnsiZW52ZWxvcGVIYXNoIjp7ImFsZ29yaXRobSI6InNoYTI1NiIsInZhbHVlIjoiM2NmMTA2OGY1MThjMDE5M2QyYWNjNTc2YWFmYzVmNzM4ZGUxMTQ2NDk3ZTU4N2FmMDlkOWJjYmUyMzAxMWYyMCJ9LCJwYXlsb2FkSGFzaCI6eyJhbGdvcml0aG0iOiJzaGEyNTYiLCJ2YWx1ZSI6IjdmNjk3M2YxZDA5YTEwYzE0MzhlMGUzODNkNzg3MmMxZWY5YThjZmYzOGU0YTMxNWY5Y2RhMzA3ZGVjYjdhMzAifSwic2lnbmF0dXJlcyI6W3sic2lnbmF0dXJlIjoiTUVVQ0lRRDBoRUdjNmw5Z3hLeE1GY1dtQVlWSGRXTFc0bWVLaHNTelNheWptN0lJY0FJZ1hpYUt1NFRzajNVRFpQR0NWbmNnd3orbVdva0wxVGI3bHdMd1BSNzdPcjg9IiwidmVyaWZpZXIiOiJMUzB0TFMxQ1JVZEpUaUJEUlZKVVNVWkpRMEZVUlMwdExTMHRDazFKU1VjemFrTkRRbTFUWjBGM1NVSkJaMGxWVEVSMlVESTFXbEJMWW04ckwyMVVMM2h1U0VocVIySnpiSGxOZDBObldVbExiMXBKZW1vd1JVRjNUWGNLVG5wRlZrMUNUVWRCTVZWRlEyaE5UV015Ykc1ak0xSjJZMjFWZFZwSFZqSk5ValIzU0VGWlJGWlJVVVJGZUZaNllWZGtlbVJIT1hsYVV6RndZbTVTYkFwamJURnNXa2RzYUdSSFZYZElhR05PVFdwVmQwNUVSWGhOVkdzd1RtcE5lVmRvWTA1TmFsVjNUa1JGZUUxVWF6Rk9hazE1VjJwQlFVMUdhM2RGZDFsSUNrdHZXa2w2YWpCRFFWRlpTVXR2V2tsNmFqQkVRVkZqUkZGblFVVXhNMFo1YUdSTVJVaHZabHBKUVVaQ2FVeG5SMnB6WWs4clkyUXdOazVOTkZSa1p6QUtWamh5VkdnMFNqWXlSSFJJS3psRGRqUmFVRkZTV0VGWmFqWktURGxvYURCYVJVaEtaRzFXU0dsRU5GbGpWVVl6UlRaUFEwSlpUWGRuWjFZdlRVRTBSd3BCTVZWa1JIZEZRaTkzVVVWQmQwbElaMFJCVkVKblRsWklVMVZGUkVSQlMwSm5aM0pDWjBWR1FsRmpSRUY2UVdSQ1owNVdTRkUwUlVablVWVklVR1Y0Q2pKbGIzRk1OREZPUnpSVFQzUTJlR3N2ZWt0Nk4zcG5kMGgzV1VSV1VqQnFRa0puZDBadlFWVXpPVkJ3ZWpGWmEwVmFZalZ4VG1wd1MwWlhhWGhwTkZrS1drUTRkMkpSV1VSV1VqQlNRVkZJTDBKSFRYZFpXVnBtWVVoU01HTklUVFpNZVRsdVlWaFNiMlJYU1hWWk1qbDBUREpLYUdWdFZuTk1WMDUyWW01U2VRcGhWMGwyWTBoV2FXSkhiSHBoUXpFd1lua3hhVmt6U1haTWJXUndaRWRvTVZscE9UTmlNMHB5V20xNGRtUXpUWFpqU0ZacFlrZHNlbUZETlRWWlZ6RnpDbEZJU214YWJrMTJaRWRHYm1ONU9USk5RelIzVEdwRmQwOVJXVXRMZDFsQ1FrRkhSSFo2UVVKQlVWRnlZVWhTTUdOSVRUWk1lVGt3WWpKMGJHSnBOV2dLV1ROU2NHSXlOWHBNYldSd1pFZG9NVmx1Vm5wYVdFcHFZakkxTUZwWE5UQk1iVTUyWWxSQlUwSm5iM0pDWjBWRlFWbFBMMDFCUlVOQ1FWSjNaRmhPYndwTlJGbEhRMmx6UjBGUlVVSm5OemgzUVZGTlJVdEVSbXhOVjBVMVRrUnJlRTVFWkd0T2FsRjRUa1JKTkZwSFJtcE5WR3hzVG5wa2JVMUVVVEJaYW1NMENrMXRXVEZQVkZGNFdtMVJkMFpSV1V0TGQxbENRa0ZIUkhaNlFVSkNRVkZJVlcxV2MxcFhSbnBhVkVGc1FtZHZja0puUlVWQldVOHZUVUZGUmtKQ1pHZ0tZek5DYkZrelVYUlpibFp3WWtkUmRtTnVWbk5hV0U1bVlrZHNkV1JFUVdWQ1oyOXlRbWRGUlVGWlR5OU5RVVZIUWtKQ2VWcFhXbnBNTTFKb1dqTk5kZ3BrYWtWMVRYazBNRTFFYzBkRGFYTkhRVkZSUW1jM09IZEJVV2RGVEZGM2NtRklVakJqU0UwMlRIazVNR0l5ZEd4aWFUVm9XVE5TY0dJeU5YcE1iV1J3Q21SSGFERlpibFo2V2xoS2FtSXlOVEJhVnpVd1RHMU9kbUpVUW5aQ1oyOXlRbWRGUlVGWlR5OU5RVVZLUWtkRlRWZ3lhREJrU0VKNlQyazRkbG95YkRBS1lVaFdhVXh0VG5aaVV6bHBXVmh3YkdKRE1XcGlNalV3WTIxc2FVd3pRakZaYlhod1l6Sm5kR1JIT0hSWmJVNTVUSGsxYm1GWVVtOWtWMGwyWkRJNWVRcGhNbHB6WWpOa2Vrd3pRakZaYlhod1l6Sm5kV1ZYUm5SaVJVSjVXbGRhZWt3elVtaGFNMDEyWkdwQmRVMUROSGhOUkdkSFEybHpSMEZSVVVKbk56aDNDa0ZSYjBWTFozZHZUbXBXYTA1SFdYZFpla0YzVFhwVk0xcEVWWGRaYlVWNFQxUkZNazVVYXpWTk1sa3lUbnBPYkU1VVdtaE9NbEpyV1dwVmQwMUVRV1FLUW1kdmNrSm5SVVZCV1U4dlRVRkZURUpCT0UxRVYyUndaRWRvTVZscE1XOWlNMDR3V2xkUmQwOW5XVXRMZDFsQ1FrRkhSSFo2UVVKRVFWRnpSRU53Yndwa1NGSjNZM3B2ZGt3eVpIQmtSMmd4V1drMWFtSXlNSFpaV0U1M1dsZE9NRXhYU2pGaFYzaHJURE5LTVdKSFZucFlNbmh3WW01UmQwOUJXVXRMZDFsQ0NrSkJSMFIyZWtGQ1JGRlJjVVJEWjNoYVZFWm9UMVJSTlUxVVVUTmFSRmt3VFZSUmVVOUhVbWhaZWtVMVdsUmpNMXBxUVRCT1Iwa3pUMFJLYlU1VWF6QUtUVmRhYTAxRFFVZERhWE5IUVZGUlFtYzNPSGRCVVRSRlJXZDNVV050Vm0xamVUa3dXVmRrZWt3eldYaE1hazExVGtSQldrSm5iM0pDWjBWRlFWbFBMd3BOUVVWUVFrRnpUVU5VV1hwTlZHTjRUVVJqTUUxVVFYWkNaMjl5UW1kRlJVRlpUeTlOUVVWUlFrTkZUVWd5YURCa1NFSjZUMms0ZGxveWJEQmhTRlpwQ2t4dFRuWmlVemxvWXpOQ2JGa3pVWFJaYmxad1lrZFJkMGRCV1V0TGQxbENRa0ZIUkhaNlFVSkZVVkZMUkVGbk1rMUVhekZOVkVFMVRVUkNjRUpuYjNJS1FtZEZSVUZaVHk5TlFVVlRRa1p6VFZkWGFEQmtTRUo2VDJrNGRsb3liREJoU0ZacFRHMU9kbUpUT1doak0wSnNXVE5SZEZsdVZuQmlSMUYyWTI1V2N3cGFXRTVtWWtkc2RXUkRPSFZhTW13d1lVaFdhVXd6WkhaamJYUnRZa2M1TTJONU9YbGFWM2hzV1ZoT2JFeHViSFJpUlVKNVdsZGFla3d6VW1oYU0wMTJDbVJxUlhWTmVUUXdUVVJuUjBOcGMwZEJVVkZDWnpjNGQwRlNUVVZMWjNkdlRWZFZlRmxVYXpCUFZFVXdUakpSTWs1RVJUQk5hbWhyV1ZkTmVFOVhWVE1LVGpKWmQwNUVVbWxPZW1kNVdtcFZOVTVFUm0xYVJFRlZRbWR2Y2tKblJVVkJXVTh2VFVGRlZVSkJXVTFDU0VJeFl6Sm5kMWhuV1V0TGQxbENRa0ZIUkFwMmVrRkNSbEZTVVVSRk5XOWtTRkozWTNwdmRrd3laSEJrUjJneFdXazFhbUl5TUhaWldFNTNXbGRPTUV4WFNqRmhWM2hyVEROS01XSkhWbnBZTW5od0NtSnVVWFpaVjA0d1lWYzVkV041T1hsa1Z6VjZUSHBGTUU1RVJYZFBSRmsxVG1wVmVVd3lSakJrUjFaMFkwaFNla3g2UlhkR1oxbExTM2RaUWtKQlIwUUtkbnBCUWtablVVbEVRVnAzWkZkS2MyRlhUWGRuV1hOSFEybHpSMEZSVVVJeGJtdERRa0ZKUldaUlVqZEJTR3RCWkhkRVpGQlVRbkY0YzJOU1RXMU5XZ3BJYUhsYVducGpRMjlyY0dWMVRqUTRjbVlyU0dsdVMwRk1lVzUxYW1kQlFVRmFXVzFaTjNGQ1FVRkJSVUYzUWtsTlJWbERTVkZEYmpGcldFOXlXVzlzQ21sSFJFTnBlV05VT0RacFZESXJZbGhtTmtSRVZDczFiRGhKSzA5b1NVUXpUa0ZKYUVGUE9FTjFaRlZUTkROblQxUTJZVXhsZFdwbFpWRjJSakJ3VldvS2VYTm9TelZqU0M5Mk0yRkxVSGhZWmsxQmIwZERRM0ZIVTAwME9VSkJUVVJCTW1kQlRVZFZRMDFSUkd3MEsyTXJPRzFpU1doUVowOHZXbmcwYTJ0NFl3cExhMVJOTm5WWUswWjJaUzlVUTJsc1YwMHpUbkZHVVZCSFFuWnhhME5FY25kYVQyWndNa1UwVW0xSlEwMUJaRTlJTVd4VFVIRTNWak51Y2xKa1F6VmFDbVZhV2psdUwxTlBOR0ZZTTFwUGVraHFjbUppYkZCRmVsWldhSGhxTkVZMFFqUkNjRU50ZFdsNGRsY3pNbmM5UFFvdExTMHRMVVZPUkNCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2c9PSJ9XX19"}],"timestampVerificationData":{}},"dsseEnvelope":{"payload":"eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjEiLCJzdWJqZWN0IjpbeyJuYW1lIjoiTU9EVUxFLmJhemVsIiwiZGlnZXN0Ijp7InNoYTI1NiI6ImUwNzU4ZjMyMzIzODg3Y2ZlMGI5ZDZlOWYwMWY4MDNmNTBhM2Y1ZWZiNmEyMjlmYzY3OTFlOTliZDkxZWEwMzgifX1dLCJwcmVkaWNhdGVUeXBlIjoiaHR0cHM6Ly9zbHNhLmRldi9wcm92ZW5hbmNlL3YxIiwicHJlZGljYXRlIjp7ImJ1aWxkRGVmaW5pdGlvbiI6eyJidWlsZFR5cGUiOiJodHRwczovL2FjdGlvbnMuZ2l0aHViLmlvL2J1aWxkdHlwZXMvd29ya2Zsb3cvdjEiLCJleHRlcm5hbFBhcmFtZXRlcnMiOnsid29ya2Zsb3ciOnsicmVmIjoicmVmcy90YWdzL3YxLjMuNCIsInJlcG9zaXRvcnkiOiJodHRwczovL2dpdGh1Yi5jb20vYXNwZWN0LWJ1aWxkL3J1bGVzX2xpbnQiLCJwYXRoIjoiLmdpdGh1Yi93b3JrZmxvd3MvcmVsZWFzZS55bWwifX0sImludGVybmFsUGFyYW1ldGVycyI6eyJnaXRodWIiOnsiZXZlbnRfbmFtZSI6InB1c2giLCJyZXBvc2l0b3J5X2lkIjoiNjMxNzEwNzQxIiwicmVwb3NpdG9yeV9vd25lcl9pZCI6IjYwOTUxMDkwIiwicnVubmVyX2Vudmlyb25tZW50IjoiZ2l0aHViLWhvc3RlZCJ9fSwicmVzb2x2ZWREZXBlbmRlbmNpZXMiOlt7InVyaSI6ImdpdCtodHRwczovL2dpdGh1Yi5jb20vYXNwZWN0LWJ1aWxkL3J1bGVzX2xpbnRAcmVmcy90YWdzL3YxLjMuNCIsImRpZ2VzdCI6eyJnaXRDb21taXQiOiIxZTFhOTQ5MTQ3ZDY0MTQyOGRhYzE5ZTc3ZjA0NGI3ODJmNTk0MWZkIn19XX0sInJ1bkRldGFpbHMiOnsiYnVpbGRlciI6eyJpZCI6Imh0dHBzOi8vZ2l0aHViLmNvbS9iYXplbC1jb250cmliL3B1Ymxpc2gtdG8tYmNyLy5naXRodWIvd29ya2Zsb3dzL3B1Ymxpc2gueWFtbEByZWZzL3RhZ3MvdjAuMC4xIn0sIm1ldGFkYXRhIjp7Imludm9jYXRpb25JZCI6Imh0dHBzOi8vZ2l0aHViLmNvbS9hc3BlY3QtYnVpbGQvcnVsZXNfbGludC9hY3Rpb25zL3J1bnMvMTQ0MTA4Njk2NTIvYXR0ZW1wdHMvMSJ9fX19","payloadType":"application/vnd.in-toto+json","signatures":[{"sig":"MEUCIQD0hEGc6l9gxKxMFcWmAYVHdWLW4meKhsSzSayjm7IIcAIgXiaKu4Tsj3UDZPGCVncgwz+mWokL1Tb7lwLwPR77Or8="}]}} \ No newline at end of file diff --git a/cli/slsa-verifier/verify.go b/cli/slsa-verifier/verify.go index 9542e2c14..54c43a171 100644 --- a/cli/slsa-verifier/verify.go +++ b/cli/slsa-verifier/verify.go @@ -189,10 +189,10 @@ func verifyGithubAttestation() *cobra.Command { o := &verify.VerifyGithubAttestationOptions{} cmd := &cobra.Command{ - Use: "verify-github-attestation [flags] module-file", + Use: "verify-github-attestation [flags] artifact", Args: func(cmd *cobra.Command, args []string) error { if len(args) != 1 { - return errors.New("expects a single path to an module file") + return errors.New("expects a single path to an artifact") } return nil }, @@ -204,6 +204,12 @@ func verifyGithubAttestation() *cobra.Command { PrintAttestation: o.PrintAttestation, BuilderID: &o.BuilderID, } + if cmd.Flags().Changed("source-tag") { + v.SourceTag = &o.SourceTag + } + if cmd.Flags().Changed("source-versioned-tag") { + v.SourceVersionTag = &o.SourceVersionTag + } if _, err := v.Exec(cmd.Context(), args[0]); err != nil { fmt.Fprintf(os.Stderr, "%s: %v\n", FAILURE, err) os.Exit(1) diff --git a/cli/slsa-verifier/verify/options.go b/cli/slsa-verifier/verify/options.go index aae633222..c41de6d6f 100644 --- a/cli/slsa-verifier/verify/options.go +++ b/cli/slsa-verifier/verify/options.go @@ -129,8 +129,10 @@ func (o *VerifyNpmOptions) AddFlags(cmd *cobra.Command) { // VerifyGithubAttestationOptions is the top-level options for the `verify-github-attestation` command. type VerifyGithubAttestationOptions struct { - SourceURI string BuilderID string + SourceURI string + SourceTag string + SourceVersionTag string AttestationPath string PrintAttestation bool } @@ -145,6 +147,11 @@ func (o *VerifyGithubAttestationOptions) AddFlags(cmd *cobra.Command) { cmd.Flags().StringVar(&o.SourceURI, "source-uri", "", "expected source repository that should have produced the binary, e.g. github.com/some/repo") + cmd.Flags().StringVar(&o.SourceTag, "source-tag", "", "[optional] expected tag the binary was compiled from") + + cmd.Flags().StringVar(&o.SourceVersionTag, "source-versioned-tag", "", + "[optional] expected version the binary was compiled from. Uses semantic version to match the tag") + /* Other options */ cmd.Flags().StringVar(&o.AttestationPath, "attestation-path", "", "path to an attestation file") diff --git a/cli/slsa-verifier/verify/verify_github_attestation.go b/cli/slsa-verifier/verify/verify_github_attestation.go index 16eda3bed..50cc4fdf0 100644 --- a/cli/slsa-verifier/verify/verify_github_attestation.go +++ b/cli/slsa-verifier/verify/verify_github_attestation.go @@ -29,6 +29,8 @@ type VerifyGithubAttestationCommand struct { AttestationPath string BuilderID *string SourceURI string + SourceTag *string + SourceVersionTag *string BuildWorkflowInputs map[string]string PrintAttestation bool } @@ -43,6 +45,8 @@ func (c *VerifyGithubAttestationCommand) Exec(ctx context.Context, artifact stri provenanceOpts := &options.ProvenanceOpts{ ExpectedSourceURI: c.SourceURI, ExpectedDigest: artifactHash, + ExpectedVersionedTag: c.SourceVersionTag, + ExpectedTag: c.SourceTag, ExpectedWorkflowInputs: c.BuildWorkflowInputs, } diff --git a/verifiers/internal/gha/slsaprovenance/v1.0/base.go b/verifiers/internal/gha/slsaprovenance/v1.0/base.go index 74774e8fe..790ceeb6c 100644 --- a/verifiers/internal/gha/slsaprovenance/v1.0/base.go +++ b/verifiers/internal/gha/slsaprovenance/v1.0/base.go @@ -17,6 +17,11 @@ type provenanceV1 struct { prov *Attestation } +const ( + refNameTags = "tags" + refNameHeads = "heads" +) + // Predicate implements ProvenanceV02.Predicate. func (p *provenanceV1) Predicate() slsa1.ProvenancePredicate { return p.prov.Predicate diff --git a/verifiers/internal/gha/slsaprovenance/v1.0/byob.go b/verifiers/internal/gha/slsaprovenance/v1.0/byob.go index d6dba5320..45a0039d9 100644 --- a/verifiers/internal/gha/slsaprovenance/v1.0/byob.go +++ b/verifiers/internal/gha/slsaprovenance/v1.0/byob.go @@ -37,10 +37,10 @@ func (p *BYOBProvenance) GetBranch() (string, error) { refType, _ := utils.ParseGitRef(ref) switch refType { - case "heads": // branch. + case refNameHeads: // branch. // NOTE: We return the full git ref. return ref, nil - case "tags": + case refNameTags: // NOTE: If the ref type is a tag we want to try to parse out the branch from the tag. sysParams, ok := p.prov.Predicate.BuildDefinition.InternalParameters.(map[string]interface{}) if !ok { @@ -73,9 +73,9 @@ func (p *BYOBProvenance) GetTag() (string, error) { refType, _ := utils.ParseGitRef(ref) switch refType { - case "heads": // branch. + case refNameHeads: // branch. return "", nil - case "tags": + case refNameTags: // NOTE: We return the full git ref. return ref, nil default: diff --git a/verifiers/internal/gha/slsaprovenance/v1.0/github_attest.go b/verifiers/internal/gha/slsaprovenance/v1.0/github_attest.go index ac24a5074..a7b3f4a18 100644 --- a/verifiers/internal/gha/slsaprovenance/v1.0/github_attest.go +++ b/verifiers/internal/gha/slsaprovenance/v1.0/github_attest.go @@ -4,6 +4,7 @@ import ( "fmt" serrors "github.com/slsa-framework/slsa-verifier/v2/errors" + "github.com/slsa-framework/slsa-verifier/v2/verifiers/utils" ) // GithubAttestBuildType is the build type for the github attest based builder. @@ -15,14 +16,10 @@ type GithubAttestProvenance struct { } func (p *GithubAttestProvenance) TriggerURI() (string, error) { - externalParams, err := p.getExternalParameters() + workflow, err := p.getWorkflow() if err != nil { return "", err } - workflow, ok := externalParams["workflow"].(map[string]interface{}) - if !ok { - return "", fmt.Errorf("%w: %s", serrors.ErrorInvalidFormat, "workflow parameters") - } repository, ok := workflow["repository"].(string) if !ok { return "", fmt.Errorf("%w: %s", serrors.ErrorInvalidFormat, "workflow parameters: repository") @@ -34,3 +31,36 @@ func (p *GithubAttestProvenance) TriggerURI() (string, error) { uri := fmt.Sprintf("git+%s@%s", repository, ref) return uri, nil } + +// GetTag returns the triggering event's tag. +func (p *GithubAttestProvenance) GetTag() (string, error) { + workflow, err := p.getWorkflow() + if err != nil { + return "", err + } + ref, ok := workflow["ref"].(string) + if !ok { + return "", fmt.Errorf("%w: %s", serrors.ErrorInvalidFormat, "workflow parameters: ref") + } + + refType, _ := utils.ParseGitRef(ref) + switch refType { + case refNameTags: + return ref, nil + default: + return "", fmt.Errorf("%w: non-tag ref type %q for ref %q", + serrors.ErrorInvalidDssePayload, refType, ref) + } +} + +func (p *GithubAttestProvenance) getWorkflow() (map[string]interface{}, error) { + externalParams, err := p.getExternalParameters() + if err != nil { + return nil, err + } + workflow, ok := externalParams["workflow"].(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("%w: %s", serrors.ErrorInvalidFormat, "workflow parameters") + } + return workflow, nil +}