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

Allow injection of extra materials via files #72

Merged
merged 7 commits into from
Nov 9, 2021
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
5 changes: 5 additions & 0 deletions .github/workflows/example-local.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,16 @@ jobs:
- name: Download build artifact
uses: actions/download-artifact@v2

- name: Generate some extra materials (this usually happens as part of the build process)
run: |
echo '[{"uri": "pkg:deb/debian/stunnel4@5.50-3?arch=amd64", "digest": {"sha256": "e1731ae217fcbc64d4c00d707dcead45c828c5f762bcf8cc56d87de511e096fa"}}]' > extra-materials.json

- name: Generate provenance
# use action in the root directory
uses: ./
with:
artifact_path: artifact/
extra_materials: extra-materials.json

- name: Upload provenance
uses: actions/upload-artifact@v2
Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -173,10 +173,17 @@ The easiest way to use this action is to add the following into your workflow fi
with:
path: artifact/

- name: Download extra materials for provenance
uses: actions/download-artifact@v2
with:
name: extra-materials
path: extra-materials/

- name: Generate provenance
uses: philips-labs/SLSA-Provenance-Action@8c78a6b34703824b9561a26b1ae5893beea9a332
with:
artifact_path: artifact/
extra_materials: extra-materials/file1.json extra-materials/some-more.json

- name: Upload provenance
uses: actions/upload-artifact@v2
Expand Down Expand Up @@ -205,6 +212,7 @@ An action to generate SLSA build provenance for an artifact
| tag_name | The github release to generate provenance on.
(if set the artifacts will be downloaded from the release and the provenance will be added as an additional release asset.)
| `false` | |
| extra_materials | paths to files containing SLSA v0.1 formatted materials (JSON array) in to include in the provenance | `false` | |



Expand Down
5 changes: 5 additions & 0 deletions action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ inputs:
The github release to generate provenance on.
(if set the artifacts will be downloaded from the release and the provenance will be added as an additional release asset.)
required: false
extra_materials:
description: 'paths to files containing SLSA v0.1 formatted materials (JSON array) in to include in the provenance'
required: false
runs:
using: 'docker'
image: 'docker://ghcr.io/philips-labs/slsa-provenance:v0.2.0'
Expand All @@ -39,3 +42,5 @@ runs:
- '${{ inputs.runner_context }}'
- "-tag_name"
- '${{ inputs.tag_name }}'
- "-extra_materials"
- '${{ inputs.extra_materials }}'
35 changes: 31 additions & 4 deletions cmd/slsa-provenance/cli/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import (
"flag"
"fmt"
"io"
"io/ioutil"
"os"
"strings"

"github.com/peterbourgon/ff/v3/ffcli"
"github.com/pkg/errors"
Expand All @@ -26,11 +28,16 @@ func Generate(w io.Writer) *ffcli.Command {
flagset = flag.NewFlagSet("slsa-provenance generate", flag.ExitOnError)
tagName = flagset.String("tag_name", "", `The github release to generate provenance on.
(if set the artifacts will be downloaded from the release and the provenance will be added as an additional release asset.)`)
artifactPath = flagset.String("artifact_path", "", "The file or dir path of the artifacts for which provenance should be generated.")
outputPath = flagset.String("output_path", "build.provenance", "The path to which the generated provenance should be written.")
githubContext = flagset.String("github_context", "", "The '${github}' context value.")
runnerContext = flagset.String("runner_context", "", "The '${runner}' context value.")
artifactPath = flagset.String("artifact_path", "", "The file or dir path of the artifacts for which provenance should be generated.")
outputPath = flagset.String("output_path", "build.provenance", "The path to which the generated provenance should be written.")
githubContext = flagset.String("github_context", "", "The '${github}' context value.")
runnerContext = flagset.String("runner_context", "", "The '${runner}' context value.")
extraMaterials = []string{}
)
flagset.Func("extra_materials", "paths to files containing SLSA v0.1 formatted materials (JSON array) in to include in the provenance", func(s string) error {
extraMaterials = append(extraMaterials, strings.Fields(s)...)
return nil
})

flagset.SetOutput(w)

Expand Down Expand Up @@ -80,6 +87,26 @@ func Generate(w io.Writer) *ffcli.Command {
return errors.Wrap(err, "failed to generate provenance")
}

for _, extra := range extraMaterials {
content, err := ioutil.ReadFile(extra)
if err != nil {
return errors.Wrapf(err, "Could not load extra materials from %s", extra)
}
var materials []intoto.Item
if err = json.Unmarshal(content, &materials); err != nil {
return errors.Wrapf(err, "Invalid JSON in extra materials file %s", extra)
}
for _, material := range materials {
if material.URI == "" {
return errors.Errorf("Empty or missing \"uri\" field in %s", extra)
}
if len(material.Digest) == 0 {
return errors.Errorf("Empty or missing \"digest\" in %s", extra)
}
}
stmt.Predicate.Materials = append(stmt.Predicate.Materials, materials...)
}

fmt.Fprintf(w, "Saving provenance to %s\n", *outputPath)

return env.PersistProvenanceStatement(ctx, stmt, *outputPath)
Expand Down
80 changes: 80 additions & 0 deletions cmd/slsa-provenance/cli/generate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,86 @@ func TestGenerateCliOptions(t *testing.T) {
runnerContext,
},
},
{
name: "With extra materials",
err: nil,
arguments: []string{
"-artifact_path",
path.Join(rootDir, "bin/slsa-provenance"),
"-github_context",
githubContext,
"-output_path",
provenanceFile,
"-runner_context",
runnerContext,
"-extra_materials",
path.Join(rootDir, "test-data/materials-valid.json"),
},
},
{
name: "With broken extra materials",
err: fmt.Errorf("Invalid JSON in extra materials file %s: unexpected end of JSON input", path.Join(rootDir, "test-data/materials-broken.not-json")),
arguments: []string{
"-artifact_path",
path.Join(rootDir, "bin/slsa-provenance"),
"-github_context",
githubContext,
"-output_path",
provenanceFile,
"-runner_context",
runnerContext,
"-extra_materials",
path.Join(rootDir, "test-data/materials-broken.not-json"),
},
},
{
name: "With non-existent extra materials",
err: fmt.Errorf("Could not load extra materials from non-existing-folder/unknown-file: open non-existing-folder/unknown-file: no such file or directory"),
arguments: []string{
"-artifact_path",
path.Join(rootDir, "bin/slsa-provenance"),
"-github_context",
githubContext,
"-output_path",
provenanceFile,
"-runner_context",
runnerContext,
"-extra_materials",
fmt.Sprintf("%s %s", path.Join(rootDir, "test-data/materials-valid.json"), "non-existing-folder/unknown-file"),
},
},
{
name: "With broken extra materials (no uri)",
err: fmt.Errorf("Empty or missing \"uri\" field in /home/lieter/src/SLSA/slsa-provenance-action/test-data/materials-no-uri.json"),
arguments: []string{
"-artifact_path",
path.Join(rootDir, "bin/slsa-provenance"),
"-github_context",
githubContext,
"-output_path",
provenanceFile,
"-runner_context",
runnerContext,
"-extra_materials",
path.Join(rootDir, "test-data/materials-no-uri.json"),
},
},
{
name: "With broken extra materials (no digest)",
err: fmt.Errorf("Empty or missing \"digest\" in /home/lieter/src/SLSA/slsa-provenance-action/test-data/materials-no-digest.json"),
arguments: []string{
"-artifact_path",
path.Join(rootDir, "bin/slsa-provenance"),
"-github_context",
githubContext,
"-output_path",
provenanceFile,
"-runner_context",
runnerContext,
"-extra_materials",
path.Join(rootDir, "test-data/materials-no-digest.json"),
},
},
}

for _, tc := range testCases {
Expand Down
7 changes: 7 additions & 0 deletions test-data/materials-broken.not-json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[
pieterlexis marked this conversation as resolved.
Show resolved Hide resolved
{
"uri": "pkg:deb/debian/stunnel4@5.50-3?arch=amd64",
"digest": {
"sha256": "e1731ae217fcbc64d4c00d707dcead45c828c5f762bcf8cc56d87de511e096fa"
}
}
8 changes: 8 additions & 0 deletions test-data/materials-no-digest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[
{
"uri": "pkg:deb/debian/stunnel4@5.50-3?arch=amd64",
"not-digest": {
"sha256": "e1731ae217fcbc64d4c00d707dcead45c828c5f762bcf8cc56d87de511e096fa"
}
}
]
8 changes: 8 additions & 0 deletions test-data/materials-no-uri.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[
{
"not-uri": "pkg:deb/debian/stunnel4@5.50-3?arch=amd64",
"digest": {
"sha256": "e1731ae217fcbc64d4c00d707dcead45c828c5f762bcf8cc56d87de511e096fa"
}
}
]
8 changes: 8 additions & 0 deletions test-data/materials-valid.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[
{
"uri": "pkg:deb/debian/stunnel4@5.50-3?arch=amd64",
"digest": {
"sha256": "e1731ae217fcbc64d4c00d707dcead45c828c5f762bcf8cc56d87de511e096fa"
}
}
]