mirror of
https://github.com/slsa-framework/slsa-verifier.git
synced 2026-08-18 19:18:16 +00:00
feat: Verify all artifacts passed in cmdline (#419)
* Remove limit of number of artifacts to verify Signed-off-by: Mihai Maruseac <mihaimaruseac@google.com> * Update short description Mention that we support multiple artifacts as long as they come from the same provenance. Signed-off-by: Mihai Maruseac <mihaimaruseac@google.com> * Verify all artifacts passed in cmdline Signed-off-by: Mihai Maruseac <mihaimaruseac@google.com> * Remove header of verify step output Signed-off-by: Mihai Maruseac <mihaimaruseac@google.com> * Format the `cobra.Command.Use` argument Signed-off-by: Mihai Maruseac <mihaimaruseac@google.com> * Don't return a slice of builderIDs. Since all images should come from the same provenance file, there's an invariant that we will always get exactly one builderID. So, no need to return a slice of them. Just to preempt the case when the invariant would be broken, add a specific check. Signed-off-by: Mihai Maruseac <mihaimaruseac@google.com> * Change existing tests to support multiple artifacts. No new tests added, just changing table test data type. Signed-off-by: Mihai Maruseac <mihaimaruseac@google.com> * [nfc] Format test file Signed-off-by: Mihai Maruseac <mihaimaruseac@google.com> * Change test to allow passing multiple artifacts. For now, just allow passing the entire array of artifacts to command line / arguments. The functionality should still be the same. Signed-off-by: Mihai Maruseac <mihaimaruseac@google.com> * Fix typo Signed-off-by: Mihai Maruseac <mihaimaruseac@google.com> * Fix path to test artifacts Signed-off-by: Mihai Maruseac <mihaimaruseac@google.com> * Allow different provenance path Signed-off-by: Mihai Maruseac <mihaimaruseac@google.com> * Try 2 artifacts from existing testdata Signed-off-by: Mihai Maruseac <mihaimaruseac@google.com> * Add more tests for multiple artifacts Signed-off-by: Mihai Maruseac <mihaimaruseac@google.com> * Add failing test Signed-off-by: Mihai Maruseac <mihaimaruseac@google.com> * Fix artifact and error Signed-off-by: Mihai Maruseac <mihaimaruseac@google.com> * Add final test: no artifact match Signed-off-by: Mihai Maruseac <mihaimaruseac@google.com> * Update README.md Signed-off-by: Mihai Maruseac <mihaimaruseac@google.com> Signed-off-by: Mihai Maruseac <mihaimaruseac@google.com>
This commit is contained in:
@@ -156,13 +156,13 @@ Below is a list of options currently supported for binary blobs and container im
|
||||
```bash
|
||||
$ git clone git@github.com:slsa-framework/slsa-verifier.git
|
||||
$ go run ./cli/slsa-verifier/ verify-artifact --help
|
||||
Verifies SLSA provenance on an artifact blob
|
||||
Verifies SLSA provenance on artifact blobs given as arguments (assuming same provenance)
|
||||
|
||||
Usage:
|
||||
slsa-verifier verify-artifact [flags]
|
||||
slsa-verifier verify-artifact [flags] artifact [artifact..]
|
||||
|
||||
Flags:
|
||||
--build-workflow-input map[] [optional] a workflow input provided by a user at trigger time in the format 'key=value'. (Only for 'workflow_dispatch' events). (default map[])
|
||||
--build-workflow-input map[] [optional] a workflow input provided by a user at trigger time in the format 'key=value'. (Only for 'workflow_dispatch' events on GitHub Actions). (default map[])
|
||||
--builder-id string [optional] the unique builder ID who created the provenance
|
||||
-h, --help help for verify-artifact
|
||||
--print-provenance [optional] print the verified provenance to stdout
|
||||
@@ -173,6 +173,8 @@ Flags:
|
||||
--source-versioned-tag string [optional] expected version the binary was compiled from. Uses semantic version to match the tag
|
||||
```
|
||||
|
||||
Multiple artifacts can be passed to `verify-artifact`. As long as they are all covered by the same provenance file, the verification will succeed.
|
||||
|
||||
### Option details
|
||||
|
||||
The following options are available:
|
||||
@@ -205,6 +207,27 @@ The verified in-toto statement may be written to stdout with the `--print-proven
|
||||
|
||||
Only GitHub URIs are supported with the `--source-uri` flag. A tag should not be specified, even if the provenance was built at some tag. If you intend to do source versioning validation, use `--print-provenance` and inspect the commit SHA of the config source or materials.
|
||||
|
||||
Multiple artifacts built from the same GitHub builder can be verified in the same command, by passing them in the same command line as arguments:
|
||||
|
||||
```bash
|
||||
$ slsa-verifier verify-artifact \
|
||||
--provenance-path /tmp/demo/multiple.intoto.jsonl \
|
||||
--source-uri github.com/mihaimaruseac/example \
|
||||
/tmp/demo/fib /tmp/demo/hello
|
||||
|
||||
Verified signature against tlog entry index 9712459 at URL: https://rekor.sigstore.dev/api/v1/log/entries/24296fb24b8ad77a1544828b67bb5a2335f7e0d01c504a32ceb6f3a8814ed12c8f1b222d308bd9e8
|
||||
Verified build using builder https://github.com/slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@refs/tags/v1.4.0 at commit 11fab87c5ee6f46c6f5e68f6c5378c62ce1ca77c
|
||||
Verifying artifact /tmp/demo/fib: PASSED
|
||||
|
||||
Verified signature against tlog entry index 9712459 at URL: https://rekor.sigstore.dev/api/v1/log/entries/24296fb24b8ad77a1544828b67bb5a2335f7e0d01c504a32ceb6f3a8814ed12c8f1b222d308bd9e8
|
||||
Verified build using builder https://github.com/slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@refs/tags/v1.4.0 at commit 11fab87c5ee6f46c6f5e68f6c5378c62ce1ca77c
|
||||
Verifying artifact /tmp/demo/hello: PASSED
|
||||
|
||||
PASSED: Verified SLSA provenance
|
||||
```
|
||||
|
||||
The only requirement is that the provenance file covers all artifacts passed as arguments in the command line (that is, they are a subset of `subject` field in the provenance file).
|
||||
|
||||
### Containers
|
||||
|
||||
This is WIP and currently not supported.
|
||||
|
||||
@@ -78,7 +78,7 @@ func Test_runVerifyGHAArtifactPath(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
artifact string
|
||||
artifacts []string
|
||||
source string
|
||||
pbranch *string
|
||||
ptag *string
|
||||
@@ -96,147 +96,151 @@ func Test_runVerifyGHAArtifactPath(t *testing.T) {
|
||||
minversion string
|
||||
// specifying builders will restrict builders to only the specified ones.
|
||||
builders []string
|
||||
// specify provenance path if not the same as artifacts[0]
|
||||
// useful for testing provenance with multiple artifacts,
|
||||
// without needing to duplicate provenance
|
||||
provenancePath string
|
||||
}{
|
||||
{
|
||||
name: "valid main branch default",
|
||||
artifact: "binary-linux-amd64-workflow_dispatch",
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
name: "valid main branch default",
|
||||
artifacts: []string{"binary-linux-amd64-workflow_dispatch"},
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
},
|
||||
{
|
||||
name: "valid main branch default - invalid builderID",
|
||||
artifact: "binary-linux-amd64-workflow_dispatch",
|
||||
artifacts: []string{"binary-linux-amd64-workflow_dispatch"},
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
pBuilderID: pString("https://github.com/slsa-framework/slsa-github-generator/.github/workflows/not-trusted.yml"),
|
||||
err: serrors.ErrorUntrustedReusableWorkflow,
|
||||
},
|
||||
{
|
||||
name: "valid main branch set",
|
||||
artifact: "binary-linux-amd64-workflow_dispatch",
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
pbranch: pString("main"),
|
||||
name: "valid main branch set",
|
||||
artifacts: []string{"binary-linux-amd64-workflow_dispatch"},
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
pbranch: pString("main"),
|
||||
},
|
||||
{
|
||||
name: "wrong branch master",
|
||||
artifact: "binary-linux-amd64-workflow_dispatch",
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
pbranch: pString("master"),
|
||||
err: serrors.ErrorMismatchBranch,
|
||||
name: "wrong branch master",
|
||||
artifacts: []string{"binary-linux-amd64-workflow_dispatch"},
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
pbranch: pString("master"),
|
||||
err: serrors.ErrorMismatchBranch,
|
||||
},
|
||||
{
|
||||
name: "branch master not verified",
|
||||
artifact: "binary-linux-amd64-workflow_dispatch",
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
name: "branch master not verified",
|
||||
artifacts: []string{"binary-linux-amd64-workflow_dispatch"},
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
},
|
||||
{
|
||||
name: "wrong source append A",
|
||||
artifact: "binary-linux-amd64-workflow_dispatch",
|
||||
source: "github.com/laurentsimon/slsa-verifier-test-genA",
|
||||
err: serrors.ErrorMismatchSource,
|
||||
name: "wrong source append A",
|
||||
artifacts: []string{"binary-linux-amd64-workflow_dispatch"},
|
||||
source: "github.com/laurentsimon/slsa-verifier-test-genA",
|
||||
err: serrors.ErrorMismatchSource,
|
||||
},
|
||||
{
|
||||
name: "wrong source prepend A",
|
||||
artifact: "binary-linux-amd64-workflow_dispatch",
|
||||
source: "github.com/laurentsimon/slsa-verifier-test-gen",
|
||||
err: serrors.ErrorMismatchSource,
|
||||
name: "wrong source prepend A",
|
||||
artifacts: []string{"binary-linux-amd64-workflow_dispatch"},
|
||||
source: "github.com/laurentsimon/slsa-verifier-test-gen",
|
||||
err: serrors.ErrorMismatchSource,
|
||||
},
|
||||
{
|
||||
name: "wrong source middle A",
|
||||
artifact: "binary-linux-amd64-workflow_dispatch",
|
||||
source: "github.com/Alaurentsimon/slsa-verifier-test-gen",
|
||||
err: serrors.ErrorMismatchSource,
|
||||
name: "wrong source middle A",
|
||||
artifacts: []string{"binary-linux-amd64-workflow_dispatch"},
|
||||
source: "github.com/Alaurentsimon/slsa-verifier-test-gen",
|
||||
err: serrors.ErrorMismatchSource,
|
||||
},
|
||||
{
|
||||
name: "tag no match empty tag workflow_dispatch",
|
||||
artifact: "binary-linux-amd64-workflow_dispatch",
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
ptag: pString("v1.2.3"),
|
||||
err: serrors.ErrorMismatchTag,
|
||||
name: "tag no match empty tag workflow_dispatch",
|
||||
artifacts: []string{"binary-linux-amd64-workflow_dispatch"},
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
ptag: pString("v1.2.3"),
|
||||
err: serrors.ErrorMismatchTag,
|
||||
},
|
||||
{
|
||||
name: "versioned tag no match empty tag workflow_dispatch",
|
||||
artifact: "binary-linux-amd64-workflow_dispatch",
|
||||
artifacts: []string{"binary-linux-amd64-workflow_dispatch"},
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
pversiontag: pString("v1"),
|
||||
err: serrors.ErrorInvalidSemver,
|
||||
},
|
||||
// Provenance contains tag = v13.0.30.
|
||||
{
|
||||
name: "tag v13.0.29 no match v13.0.30",
|
||||
artifact: "binary-linux-amd64-push-v13.0.30",
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
ptag: pString("v13.0.29"),
|
||||
err: serrors.ErrorMismatchTag,
|
||||
name: "tag v13.0.29 no match v13.0.30",
|
||||
artifacts: []string{"binary-linux-amd64-push-v13.0.30"},
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
ptag: pString("v13.0.29"),
|
||||
err: serrors.ErrorMismatchTag,
|
||||
},
|
||||
{
|
||||
name: "tag v13.0 no match v13.0.30",
|
||||
artifact: "binary-linux-amd64-push-v13.0.30",
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
ptag: pString("v13.0"),
|
||||
err: serrors.ErrorMismatchTag,
|
||||
name: "tag v13.0 no match v13.0.30",
|
||||
artifacts: []string{"binary-linux-amd64-push-v13.0.30"},
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
ptag: pString("v13.0"),
|
||||
err: serrors.ErrorMismatchTag,
|
||||
},
|
||||
{
|
||||
name: "tag v13 no match v13.0.30",
|
||||
artifact: "binary-linux-amd64-push-v13.0.30",
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
ptag: pString("v13"),
|
||||
err: serrors.ErrorMismatchTag,
|
||||
name: "tag v13 no match v13.0.30",
|
||||
artifacts: []string{"binary-linux-amd64-push-v13.0.30"},
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
ptag: pString("v13"),
|
||||
err: serrors.ErrorMismatchTag,
|
||||
},
|
||||
{
|
||||
name: "versioned v13.0.30 match push-v13.0.30",
|
||||
artifact: "binary-linux-amd64-push-v13.0.30",
|
||||
artifacts: []string{"binary-linux-amd64-push-v13.0.30"},
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
pversiontag: pString("v13.0.30"),
|
||||
},
|
||||
{
|
||||
name: "versioned v13.0 match push-v13.0.30",
|
||||
artifact: "binary-linux-amd64-push-v13.0.30",
|
||||
artifacts: []string{"binary-linux-amd64-push-v13.0.30"},
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
pversiontag: pString("v13.0"),
|
||||
},
|
||||
{
|
||||
name: "versioned v13 match push-v13.0.30",
|
||||
artifact: "binary-linux-amd64-push-v13.0.30",
|
||||
artifacts: []string{"binary-linux-amd64-push-v13.0.30"},
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
pversiontag: pString("v13"),
|
||||
},
|
||||
{
|
||||
name: "versioned v2 no match push-v13.0.30",
|
||||
artifact: "binary-linux-amd64-push-v13.0.30",
|
||||
artifacts: []string{"binary-linux-amd64-push-v13.0.30"},
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
pversiontag: pString("v2"),
|
||||
err: serrors.ErrorMismatchVersionedTag,
|
||||
},
|
||||
{
|
||||
name: "versioned v0 no match push-v13.0.30",
|
||||
artifact: "binary-linux-amd64-push-v13.0.30",
|
||||
artifacts: []string{"binary-linux-amd64-push-v13.0.30"},
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
pversiontag: pString("v0"),
|
||||
err: serrors.ErrorMismatchVersionedTag,
|
||||
},
|
||||
{
|
||||
name: "versioned v13.1 no match push-v13.0.30",
|
||||
artifact: "binary-linux-amd64-push-v13.0.30",
|
||||
artifacts: []string{"binary-linux-amd64-push-v13.0.30"},
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
pversiontag: pString("v13.1"),
|
||||
err: serrors.ErrorMismatchVersionedTag,
|
||||
},
|
||||
{
|
||||
name: "versioned v12.9 no match push-v13.0.30",
|
||||
artifact: "binary-linux-amd64-push-v13.0.30",
|
||||
artifacts: []string{"binary-linux-amd64-push-v13.0.30"},
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
pversiontag: pString("v12.9"),
|
||||
err: serrors.ErrorMismatchVersionedTag,
|
||||
},
|
||||
{
|
||||
name: "versioned v13.0.29 no match push-v13.0.30",
|
||||
artifact: "binary-linux-amd64-push-v13.0.30",
|
||||
artifacts: []string{"binary-linux-amd64-push-v13.0.30"},
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
pversiontag: pString("v13.0.29"),
|
||||
err: serrors.ErrorMismatchVersionedTag,
|
||||
},
|
||||
{
|
||||
name: "versioned v13.0.31 no match push-v13.0.30",
|
||||
artifact: "binary-linux-amd64-push-v13.0.30",
|
||||
artifacts: []string{"binary-linux-amd64-push-v13.0.30"},
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
pversiontag: pString("v13.0.31"),
|
||||
err: serrors.ErrorMismatchVersionedTag,
|
||||
@@ -244,54 +248,54 @@ func Test_runVerifyGHAArtifactPath(t *testing.T) {
|
||||
// Provenance contains tag = v14.
|
||||
{
|
||||
name: "versioned v14 match push-v14",
|
||||
artifact: "binary-linux-amd64-push-v14",
|
||||
artifacts: []string{"binary-linux-amd64-push-v14"},
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
pversiontag: pString("v14"),
|
||||
},
|
||||
{
|
||||
name: "versioned v14.0 match push-v14",
|
||||
artifact: "binary-linux-amd64-push-v14",
|
||||
artifacts: []string{"binary-linux-amd64-push-v14"},
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
pversiontag: pString("v14.0"),
|
||||
},
|
||||
{
|
||||
name: "versioned v14.1 no match push-v14",
|
||||
artifact: "binary-linux-amd64-push-v14",
|
||||
artifacts: []string{"binary-linux-amd64-push-v14"},
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
pversiontag: pString("v14.1"),
|
||||
err: serrors.ErrorMismatchVersionedTag,
|
||||
},
|
||||
{
|
||||
name: "versioned v13 no match push-v14",
|
||||
artifact: "binary-linux-amd64-push-v14",
|
||||
artifacts: []string{"binary-linux-amd64-push-v14"},
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
pversiontag: pString("v13"),
|
||||
err: serrors.ErrorMismatchVersionedTag,
|
||||
},
|
||||
{
|
||||
name: "versioned v15 no match push-v14",
|
||||
artifact: "binary-linux-amd64-push-v14",
|
||||
artifacts: []string{"binary-linux-amd64-push-v14"},
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
pversiontag: pString("v15"),
|
||||
err: serrors.ErrorMismatchVersionedTag,
|
||||
},
|
||||
{
|
||||
name: "versioned v13.2 no match push-v14",
|
||||
artifact: "binary-linux-amd64-push-v14",
|
||||
artifacts: []string{"binary-linux-amd64-push-v14"},
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
pversiontag: pString("v13.2"),
|
||||
err: serrors.ErrorMismatchVersionedTag,
|
||||
},
|
||||
{
|
||||
name: "versioned v15 no match push-v14",
|
||||
artifact: "binary-linux-amd64-push-v14",
|
||||
artifacts: []string{"binary-linux-amd64-push-v14"},
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
pversiontag: pString("v15"),
|
||||
err: serrors.ErrorMismatchVersionedTag,
|
||||
},
|
||||
{
|
||||
name: "versioned v0 no match push-v14",
|
||||
artifact: "binary-linux-amd64-push-v14",
|
||||
artifacts: []string{"binary-linux-amd64-push-v14"},
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
pversiontag: pString("v0"),
|
||||
err: serrors.ErrorMismatchVersionedTag,
|
||||
@@ -299,68 +303,68 @@ func Test_runVerifyGHAArtifactPath(t *testing.T) {
|
||||
// Provenance contains tag = v14.2
|
||||
{
|
||||
name: "versioned v14.2 match push-v14.2",
|
||||
artifact: "binary-linux-amd64-push-v14.2",
|
||||
artifacts: []string{"binary-linux-amd64-push-v14.2"},
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
pversiontag: pString("v14.2"),
|
||||
},
|
||||
{
|
||||
name: "versioned v14.2.1 match push-v14.2",
|
||||
artifact: "binary-linux-amd64-push-v14.2",
|
||||
artifacts: []string{"binary-linux-amd64-push-v14.2"},
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
pversiontag: pString("v14.2.1"),
|
||||
err: serrors.ErrorMismatchVersionedTag,
|
||||
},
|
||||
{
|
||||
name: "versioned v14.2.3 match push-v14.2",
|
||||
artifact: "binary-linux-amd64-push-v14.2",
|
||||
artifacts: []string{"binary-linux-amd64-push-v14.2"},
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
pversiontag: pString("v14.2.3"),
|
||||
err: serrors.ErrorMismatchVersionedTag,
|
||||
},
|
||||
{
|
||||
name: "versioned v14 match push-v14.2",
|
||||
artifact: "binary-linux-amd64-push-v14.2",
|
||||
artifacts: []string{"binary-linux-amd64-push-v14.2"},
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
pversiontag: pString("v14"),
|
||||
},
|
||||
{
|
||||
name: "versioned v14.1 no match push-v14.2",
|
||||
artifact: "binary-linux-amd64-push-v14.2",
|
||||
artifacts: []string{"binary-linux-amd64-push-v14.2"},
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
pversiontag: pString("v14.1"),
|
||||
err: serrors.ErrorMismatchVersionedTag,
|
||||
},
|
||||
{
|
||||
name: "versioned v14.1.1 no match push-v14.2",
|
||||
artifact: "binary-linux-amd64-push-v14.2",
|
||||
artifacts: []string{"binary-linux-amd64-push-v14.2"},
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
pversiontag: pString("v14.1.1"),
|
||||
err: serrors.ErrorMismatchVersionedTag,
|
||||
},
|
||||
{
|
||||
name: "versioned v14.3.1 no match push-v14.2",
|
||||
artifact: "binary-linux-amd64-push-v14.2",
|
||||
artifacts: []string{"binary-linux-amd64-push-v14.2"},
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
pversiontag: pString("v14.3.1"),
|
||||
err: serrors.ErrorMismatchVersionedTag,
|
||||
},
|
||||
{
|
||||
name: "versioned v13 no match push-v14.2",
|
||||
artifact: "binary-linux-amd64-push-v14.2",
|
||||
artifacts: []string{"binary-linux-amd64-push-v14.2"},
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
pversiontag: pString("v13"),
|
||||
err: serrors.ErrorMismatchVersionedTag,
|
||||
},
|
||||
{
|
||||
name: "versioned v15 no match push-v14.2",
|
||||
artifact: "binary-linux-amd64-push-v14.2",
|
||||
artifacts: []string{"binary-linux-amd64-push-v14.2"},
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
pversiontag: pString("v15"),
|
||||
err: serrors.ErrorMismatchVersionedTag,
|
||||
},
|
||||
{
|
||||
name: "versioned v15.1 no match push-v14.2",
|
||||
artifact: "binary-linux-amd64-push-v14.2",
|
||||
artifacts: []string{"binary-linux-amd64-push-v14.2"},
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
pversiontag: pString("v15.1"),
|
||||
err: serrors.ErrorMismatchVersionedTag,
|
||||
@@ -368,21 +372,57 @@ func Test_runVerifyGHAArtifactPath(t *testing.T) {
|
||||
// Multiple subjects in version v1.2.0+
|
||||
{
|
||||
name: "multiple subject first match",
|
||||
artifact: "binary-linux-amd64-multi-subject-first",
|
||||
artifacts: []string{"binary-linux-amd64-multi-subject-first"},
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
noversion: true,
|
||||
builders: []string{"gha_generic"},
|
||||
},
|
||||
{
|
||||
name: "multiple subject second match",
|
||||
artifact: "binary-linux-amd64-multi-subject-second",
|
||||
artifacts: []string{"binary-linux-amd64-multi-subject-second"},
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
noversion: true,
|
||||
builders: []string{"gha_generic"},
|
||||
},
|
||||
{
|
||||
name: "multiple subject first and second match",
|
||||
artifacts: []string{"binary-linux-amd64-multi-subject-first", "binary-linux-amd64-multi-subject-second"},
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
noversion: true,
|
||||
builders: []string{"gha_generic"},
|
||||
},
|
||||
{
|
||||
name: "multiple subject second and first match",
|
||||
artifacts: []string{"binary-linux-amd64-multi-subject-second", "binary-linux-amd64-multi-subject-first"},
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
noversion: true,
|
||||
builders: []string{"gha_generic"},
|
||||
},
|
||||
{
|
||||
name: "multiple subject repeated match",
|
||||
artifacts: []string{"binary-linux-amd64-multi-subject-first", "binary-linux-amd64-multi-subject-first"},
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
noversion: true,
|
||||
builders: []string{"gha_generic"},
|
||||
},
|
||||
{
|
||||
name: "multiple subject one mismatch",
|
||||
artifacts: []string{"binary-linux-amd64-multi-subject-first", "binary-linux-amd64-sharded"},
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
noversion: true,
|
||||
err: serrors.ErrorMismatchHash,
|
||||
},
|
||||
{
|
||||
name: "multiple subject no match",
|
||||
artifacts: []string{"binary-linux-amd64-sharded"},
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
noversion: true,
|
||||
err: serrors.ErrorMismatchHash,
|
||||
provenancePath: "binary-linux-amd64-multi-subject-first.intoto.jsonl",
|
||||
},
|
||||
{
|
||||
name: "multiple subject second match - builderID",
|
||||
artifact: "binary-linux-amd64-multi-subject-second",
|
||||
artifacts: []string{"binary-linux-amd64-multi-subject-second"},
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
noversion: true,
|
||||
builders: []string{"gha_generic"},
|
||||
@@ -392,7 +432,7 @@ func Test_runVerifyGHAArtifactPath(t *testing.T) {
|
||||
// Special case of the e2e test repository building builder from head.
|
||||
{
|
||||
name: "e2e test repository verified with builder at head",
|
||||
artifact: "binary-linux-amd64-e2e-builder-repo",
|
||||
artifacts: []string{"binary-linux-amd64-e2e-builder-repo"},
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
pbranch: pString("main"),
|
||||
noversion: true,
|
||||
@@ -402,21 +442,21 @@ func Test_runVerifyGHAArtifactPath(t *testing.T) {
|
||||
// Malicious builders and workflows.
|
||||
{
|
||||
name: "rekor upload bypassed",
|
||||
artifact: "binary-linux-amd64-no-tlog-upload",
|
||||
artifacts: []string{"binary-linux-amd64-no-tlog-upload"},
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
err: serrors.ErrorRekorSearch,
|
||||
noversion: true,
|
||||
},
|
||||
{
|
||||
name: "malicious: untrusted builder",
|
||||
artifact: "binary-linux-amd64-untrusted-builder",
|
||||
artifacts: []string{"binary-linux-amd64-untrusted-builder"},
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
err: serrors.ErrorUntrustedReusableWorkflow,
|
||||
noversion: true,
|
||||
},
|
||||
{
|
||||
name: "malicious: invalid signature expired certificate",
|
||||
artifact: "binary-linux-amd64-expired-cert",
|
||||
artifacts: []string{"binary-linux-amd64-expired-cert"},
|
||||
source: "github.com/slsa-framework/example-package",
|
||||
err: serrors.ErrorRekorSearch,
|
||||
noversion: true,
|
||||
@@ -424,14 +464,14 @@ func Test_runVerifyGHAArtifactPath(t *testing.T) {
|
||||
// Annotated tags.
|
||||
{
|
||||
name: "annotated tag",
|
||||
artifact: "annotated-tag",
|
||||
artifacts: []string{"annotated-tag"},
|
||||
source: "github.com/laurentsimon/slsa-on-github-test",
|
||||
pversiontag: pString("v5.0.1"),
|
||||
noversion: true,
|
||||
},
|
||||
{
|
||||
name: "no branch",
|
||||
artifact: "annotated-tag",
|
||||
artifacts: []string{"annotated-tag"},
|
||||
source: "github.com/laurentsimon/slsa-on-github-test",
|
||||
pversiontag: pString("v5.0.1"),
|
||||
pbranch: pString("main"),
|
||||
@@ -440,9 +480,9 @@ func Test_runVerifyGHAArtifactPath(t *testing.T) {
|
||||
},
|
||||
// Workflow inputs.
|
||||
{
|
||||
name: "workflow inputs match",
|
||||
artifact: "workflow-inputs",
|
||||
source: "github.com/laurentsimon/slsa-on-github-test",
|
||||
name: "workflow inputs match",
|
||||
artifacts: []string{"workflow-inputs"},
|
||||
source: "github.com/laurentsimon/slsa-on-github-test",
|
||||
inputs: map[string]string{
|
||||
"release_version": "v1.2.3",
|
||||
"some_bool": "true",
|
||||
@@ -451,9 +491,9 @@ func Test_runVerifyGHAArtifactPath(t *testing.T) {
|
||||
noversion: true,
|
||||
},
|
||||
{
|
||||
name: "workflow inputs missing field",
|
||||
artifact: "workflow-inputs",
|
||||
source: "github.com/laurentsimon/slsa-on-github-test",
|
||||
name: "workflow inputs missing field",
|
||||
artifacts: []string{"workflow-inputs"},
|
||||
source: "github.com/laurentsimon/slsa-on-github-test",
|
||||
inputs: map[string]string{
|
||||
"release_version": "v1.2.3",
|
||||
"some_bool": "true",
|
||||
@@ -463,9 +503,9 @@ func Test_runVerifyGHAArtifactPath(t *testing.T) {
|
||||
noversion: true,
|
||||
},
|
||||
{
|
||||
name: "workflow inputs mismatch",
|
||||
artifact: "workflow-inputs",
|
||||
source: "github.com/laurentsimon/slsa-on-github-test",
|
||||
name: "workflow inputs mismatch",
|
||||
artifacts: []string{"workflow-inputs"},
|
||||
source: "github.com/laurentsimon/slsa-on-github-test",
|
||||
inputs: map[string]string{
|
||||
"release_version": "v1.2.3",
|
||||
"some_bool": "true",
|
||||
@@ -477,7 +517,7 @@ func Test_runVerifyGHAArtifactPath(t *testing.T) {
|
||||
// Regression test of sharded UUID.
|
||||
{
|
||||
name: "regression: sharded uuids",
|
||||
artifact: "binary-linux-amd64-sharded",
|
||||
artifacts: []string{"binary-linux-amd64-sharded"},
|
||||
source: "github.com/slsa-framework/slsa-verifier",
|
||||
pbranch: pString("release/v1.0"),
|
||||
pBuilderID: pString("https://github.com/slsa-framework/slsa-github-generator/.github/workflows/builder_go_slsa3.yml"),
|
||||
@@ -496,8 +536,18 @@ func Test_runVerifyGHAArtifactPath(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, v := range checkVersions {
|
||||
artifactPath := filepath.Clean(filepath.Join(TEST_DIR, v, tt.artifact))
|
||||
provenancePath := fmt.Sprintf("%s.intoto.jsonl", artifactPath)
|
||||
var provenancePath string
|
||||
if tt.provenancePath == "" {
|
||||
testPath := filepath.Clean(filepath.Join(TEST_DIR, v, tt.artifacts[0]))
|
||||
provenancePath = fmt.Sprintf("%s.intoto.jsonl", testPath)
|
||||
} else {
|
||||
provenancePath = filepath.Clean(filepath.Join(TEST_DIR, v, tt.provenancePath))
|
||||
}
|
||||
|
||||
artifacts := make([]string, len(tt.artifacts))
|
||||
for i, artifact := range tt.artifacts {
|
||||
artifacts[i] = filepath.Clean(filepath.Join(TEST_DIR, v, artifact))
|
||||
}
|
||||
|
||||
// TODO(#258): invalid builder ref.
|
||||
sv := path.Base(v)
|
||||
@@ -555,7 +605,7 @@ func Test_runVerifyGHAArtifactPath(t *testing.T) {
|
||||
BuildWorkflowInputs: tt.inputs,
|
||||
}
|
||||
|
||||
outBuilderID, err := cmd.Exec(context.Background(), []string{artifactPath})
|
||||
outBuilderID, err := cmd.Exec(context.Background(), artifacts)
|
||||
if !errCmp(err, tt.err) {
|
||||
t.Errorf("%v: %v", v, cmp.Diff(err, tt.err, cmpopts.EquateErrors()))
|
||||
}
|
||||
@@ -583,10 +633,10 @@ func Test_runVerifyGHAArtifactPath(t *testing.T) {
|
||||
// Smoke test against the CLI command
|
||||
cliCmd := verifyArtifactCmd()
|
||||
args := []string{
|
||||
artifactPath,
|
||||
"--source-uri", tt.source,
|
||||
"--provenance-path", provenancePath,
|
||||
}
|
||||
args = append(args, artifacts...)
|
||||
if bid != nil {
|
||||
args = append(args, "--builder-id", *bid)
|
||||
}
|
||||
|
||||
@@ -32,14 +32,8 @@ func verifyArtifactCmd() *cobra.Command {
|
||||
o := &verify.VerifyOptions{}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "verify-artifact [flags] artifact",
|
||||
Args: func(cmd *cobra.Command, args []string) error {
|
||||
if len(args) != 1 {
|
||||
return errors.New("expects a single path to an artifact")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
Short: "Verifies SLSA provenance on an artifact blob",
|
||||
Use: "verify-artifact [flags] artifact [artifact..]",
|
||||
Short: "Verifies SLSA provenance on artifact blobs given as arguments (assuming same provenance)",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
v := verify.VerifyArtifactCommand{
|
||||
ProvenancePath: o.ProvenancePath,
|
||||
|
||||
@@ -40,39 +40,55 @@ type VerifyArtifactCommand struct {
|
||||
}
|
||||
|
||||
func (c *VerifyArtifactCommand) Exec(ctx context.Context, artifacts []string) (*utils.TrustedBuilderID, error) {
|
||||
artifactHash, err := getArtifactHash(artifacts[0])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
var builderId *utils.TrustedBuilderID
|
||||
|
||||
for _, artifact := range artifacts {
|
||||
artifactHash, err := getArtifactHash(artifact)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Verifying artifact %s: FAILED: %v\n\n", artifact, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
provenanceOpts := &options.ProvenanceOpts{
|
||||
ExpectedSourceURI: c.SourceURI,
|
||||
ExpectedBranch: c.SourceBranch,
|
||||
ExpectedDigest: artifactHash,
|
||||
ExpectedVersionedTag: c.SourceVersionTag,
|
||||
ExpectedTag: c.SourceTag,
|
||||
ExpectedWorkflowInputs: c.BuildWorkflowInputs,
|
||||
}
|
||||
|
||||
builderOpts := &options.BuilderOpts{
|
||||
ExpectedID: c.BuilderID,
|
||||
}
|
||||
|
||||
provenance, err := os.ReadFile(c.ProvenancePath)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Verifying artifact %s: FAILED: %v\n\n", artifact, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
verifiedProvenance, outBuilderID, err := verifiers.VerifyArtifact(ctx, provenance, artifactHash, provenanceOpts, builderOpts)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Verifying artifact %s: FAILED: %v\n\n", artifact, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if c.PrintProvenance {
|
||||
fmt.Fprintf(os.Stdout, "%s\n", string(verifiedProvenance))
|
||||
}
|
||||
|
||||
if builderId == nil {
|
||||
builderId = outBuilderID
|
||||
} else if *builderId != *outBuilderID {
|
||||
err := fmt.Errorf("Encountered different builderIDs %v %v\n", builderId, outBuilderID)
|
||||
fmt.Fprintf(os.Stderr, "Verifying artifact %s: FAILED: %v\n\n", artifact, err)
|
||||
return nil, err
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "Verifying artifact %s: PASSED\n\n", artifact)
|
||||
}
|
||||
|
||||
provenanceOpts := &options.ProvenanceOpts{
|
||||
ExpectedSourceURI: c.SourceURI,
|
||||
ExpectedBranch: c.SourceBranch,
|
||||
ExpectedDigest: artifactHash,
|
||||
ExpectedVersionedTag: c.SourceVersionTag,
|
||||
ExpectedTag: c.SourceTag,
|
||||
ExpectedWorkflowInputs: c.BuildWorkflowInputs,
|
||||
}
|
||||
|
||||
builderOpts := &options.BuilderOpts{
|
||||
ExpectedID: c.BuilderID,
|
||||
}
|
||||
|
||||
provenance, err := os.ReadFile(c.ProvenancePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
verifiedProvenance, outBuilderID, err := verifiers.VerifyArtifact(ctx, provenance, artifactHash, provenanceOpts, builderOpts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if c.PrintProvenance {
|
||||
fmt.Fprintf(os.Stdout, "%s\n", string(verifiedProvenance))
|
||||
}
|
||||
|
||||
return outBuilderID, nil
|
||||
return builderId, nil
|
||||
}
|
||||
|
||||
func getArtifactHash(artifactPath string) (string, error) {
|
||||
|
||||
Reference in New Issue
Block a user