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:
Mihai Maruseac
2022-12-29 09:56:57 -08:00
committed by GitHub
parent 19030f3b12
commit e20f3cc7a3
4 changed files with 225 additions and 142 deletions
+26 -3
View File
@@ -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.
+150 -100
View File
@@ -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)
}
+2 -8
View File
@@ -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,
+47 -31
View File
@@ -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) {