diff --git a/internal/builders/generic/README.md b/internal/builders/generic/README.md index cf9d3ea70..40d3d5734 100644 --- a/internal/builders/generic/README.md +++ b/internal/builders/generic/README.md @@ -29,6 +29,7 @@ project simply generates provenance as a separate step in an existing workflow. - [Provenance for Bazel](#provenance-for-bazel) - [Provenance for Java](#provenance-for-java) - [Provenance for Rust](#provenance-for-rust) + - [Provenance for Haskell](#provenance-for-haskell) --- @@ -403,7 +404,7 @@ jobs: run: | # Your normal build workflow targets here bazel build //path/to/target_binary //path/to_another/binary - + # Copy the binaries. cp bazel-bin/path/to/target_binary . cp bazel-bin/path/to/another/binary . @@ -425,7 +426,7 @@ jobs: ``` 4. Call the generic workflow to generate provenance by declaring the job below: - + ```yaml provenance: needs: [build] @@ -456,7 +457,7 @@ jobs: run: | # Your normal build workflow targets here bazel build //path/to/target_binary //path/to_another/binary - + # Copy the binaries. cp bazel-bin/path/to/target_binary . cp bazel-bin/path/to/another/binary . @@ -512,7 +513,7 @@ jobs: run: | # Your normal build workflow targets here mvn clean package - + # Save the location of the maven output files for easier reference ARTIFACT_PATTERN=./target/$(mvn help:evaluate -Dexpression=project.artifactId -q -DforceStdout)-$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)*.jar echo "::set-output name=artifact_pattern::$ARTIFACT_PATTERN" @@ -563,7 +564,7 @@ jobs: run: | # Your normal build workflow targets here mvn clean package - + # Save the location of the maven output files for easier reference ARTIFACT_PATTERN=./target/$(mvn help:evaluate -Dexpression=project.artifactId -q -DforceStdout)-$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)*.jar echo "::set-output name=artifact_pattern::$ARTIFACT_PATTERN" @@ -572,7 +573,7 @@ jobs: id: hash run: | echo "::set-output name=hashes::$(sha256sum ${{ steps.build.outputs.artifact_pattern }} | base64 -w0)" - + - name: Upload build artifacts uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 # tag=v3 with: @@ -606,7 +607,7 @@ jobs: ``` 2. Add an `id: build` field to your gradle build ste: - + ```yaml steps: [...] @@ -665,7 +666,7 @@ jobs: id: hash run: | echo "::set-output name=hashes::$(sha256sum ./build/libs/* | base64 -w0)" - + - name: Upload build artifacts uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 # tag=v3 with: @@ -778,4 +779,109 @@ jobs: base64-subjects: "${{ needs.build.outputs.hashes }}" upload-assets: true # Optional: Upload to a new release -``` \ No newline at end of file +``` + +### Provenance for Haskell + +If you use [Haskell](https://www.haskell.org/) (either via +[`cabal`](https://www.haskell.org/cabal/) or +[`stack`](https://docs.haskellstack.org/en/stable/README/)) to generate your +artifacts, you can easily generate SLSA3 provenance by updating your existing +workflow with the steps indicated in the workflow below. + +1. Declare an `outputs` for the hashes: + +```yaml +jobs: + build: + outputs: + hashes: ${{ steps.hash.outputs.hashes }} + +``` + +2. Build your binaries. Then add a step to generate the provenance subjects as shown below. Update the sha256 sum arguments to include all binaries that you generate provenance for: + +```yaml + steps: + [...] + - name: Build using Haskell + run: | + # Your normal build workflow targets here. + cabal build # or stack build + + # Copy the binary to the root directory for easier reference + # For Cabal, use the following command + cp $(cabal list-bin .) . + # For Stack, use the following command instead + # cp $(stack path --local-install-root)/bin/target_binary . + + # Generate the subject. + - name: Generate subject + id: hash + run: | + set -euo pipefail + + echo "::set-output name=hashes::$(sha256sum target_binary | base64 -w0)" + +``` + +3. Call the generic workflow to generate provenance by declaring the job below: + +```yaml + provenance: + needs: [build] + permissions: + actions: read # To read the workflow path. + id-token: write # To sign the provenance. + contents: write # To add assets to a release. + uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v1.2.0 + with: + base64-subjects: "${{ needs.build.outputs.hashes }}" + upload-assets: true # Optional: Upload to a new release + +``` + +All in all, it will look as the following: + +```yaml +jobs: + build: + outputs: + hashes: ${{ steps.hash.outputs.hashes }} + + steps: + - name: Checkout repository + uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # tag=v3 + - name: Setup Haskell + uses: haskell/actions/setup@745062a754c3c4b70b87cb93937ad443096cc94d # tag=v1 + + - name: Build using Haskell + run: | + # Your normal build workflow targets here. + cabal build # or stack build + + # Copy the binary to the root directory for easier reference + # For Cabal, use the following command + cp $(cabal list-bin .) . + # For Stack, use the following command instead + # cp $(stack path --local-install-root)/bin/target_binary . + + # Generate the subject. + - name: Generate subject + id: hash + run: | + set -euo pipefail + + echo "::set-output name=hashes::$(sha256sum target_binary | base64 -w0)" + + provenance: + needs: [build] + permissions: + actions: read # To read the workflow path. + id-token: write # To sign the provenance. + contents: write # To add assets to a release. + uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v1.2.0 + with: + base64-subjects: "${{ needs.build.outputs.hashes }}" + upload-assets: true # Optional: Upload to a new release +```