diff --git a/.github/actions/ci/action.yml b/.github/actions/ci/action.yml index dd2ed98..5ea01fb 100644 --- a/.github/actions/ci/action.yml +++ b/.github/actions/ci/action.yml @@ -13,9 +13,9 @@ inputs: description: 'GH token used to download SDK test harness.' required: true outputs: - package-hashes: - description: "base64-encoded sha256 hashes of distribution files" - value: ${{ steps.package-hashes.outputs.package-hashes }} + dist-dir: + description: "Path to the stack dist directory containing built artifacts" + value: ${{ steps.dist-dir.outputs.dist-dir }} runs: using: composite @@ -34,15 +34,12 @@ runs: run: stack --no-terminal --resolver=${{ inputs.resolver }} sdist - name: Setup dist directory + id: dist-dir shell: bash - run: echo "STACK_DIR=$(stack --no-terminal path --dist-dir --resolver=${{ inputs.resolver }})" >> $GITHUB_ENV - - - name: Hash build files for provenance - id: package-hashes - shell: bash - working-directory: ${{ env.STACK_DIR }} run: | - echo "package-hashes=$(sha256sum *tar.gz | base64 -w0)" >> "$GITHUB_OUTPUT" + STACK_DIR=$(stack --no-terminal path --dist-dir --resolver=${{ inputs.resolver }}) + echo "STACK_DIR=$STACK_DIR" >> $GITHUB_ENV + echo "dist-dir=$STACK_DIR" >> "$GITHUB_OUTPUT" - name: Run tests shell: bash diff --git a/.github/workflows/manual-publish.yml b/.github/workflows/manual-publish.yml index d0340da..b5a174c 100644 --- a/.github/workflows/manual-publish.yml +++ b/.github/workflows/manual-publish.yml @@ -14,8 +14,7 @@ jobs: permissions: id-token: write contents: read - outputs: - package-hashes: ${{ steps.ci.outputs.package-hashes }} + attestations: write steps: - uses: actions/checkout@v4 @@ -43,13 +42,8 @@ jobs: token: ${{ env.HACKAGE_TOKEN }} dry_run: ${{ inputs.dry_run }} - release-provenance: - needs: ["build-publish"] - permissions: - actions: read - id-token: write - contents: write - uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@5a775b367a56d5bd118a224a811bba288150a563 # v2.0.0 - with: - base64-subjects: "${{ needs.build-publish.outputs.package-hashes }}" - upload-assets: ${{ !inputs.dry_run }} + - name: Attest build provenance + if: ${{ format('{0}', inputs.dry_run) == 'false' }} + uses: actions/attest@v4 + with: + subject-path: '${{ steps.ci.outputs.dist-dir }}/*tar.gz' diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index 7756729..352d80a 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -13,10 +13,7 @@ jobs: id-token: write # Needed if using OIDC to get release secrets. contents: write # Contents and pull-requests are for release-please to make releases. pull-requests: write - outputs: - release-created: ${{ steps.release.outputs.release_created }} - upload-tag-name: ${{ steps.release.outputs.tag_name }} - package-hashes: ${{ steps.ci.outputs.package-hashes }} + attestations: write steps: - uses: googleapis/release-please-action@16a9c90856f42705d54a6fda1823352bdc62cf38 # v4 @@ -34,9 +31,6 @@ jobs: with: branch: ${{ fromJSON(steps.release.outputs.pr).headBranchName }} - # - # These remaining steps are ONLY run if a release was actually created - # - uses: launchdarkly/gh-actions/actions/release-secrets@release-secrets-v1.2.0 name: "Get Hackage token" if: ${{ steps.release.outputs.releases_created == 'true' }} @@ -73,15 +67,8 @@ jobs: # and another token, then add more tokens to the composite action. token: ${{secrets.GITHUB_TOKEN}} - release-provenance: - needs: ["release-package"] - if: ${{ needs.release-package.outputs.release-created == 'true' }} - permissions: - actions: read - id-token: write - contents: write - uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@5a775b367a56d5bd118a224a811bba288150a563 # v2.0.0 - with: - base64-subjects: "${{ needs.release-package.outputs.package-hashes }}" - upload-assets: true - upload-tag-name: ${{ needs.release-package.outputs.upload-tag-name }} + - name: Attest build provenance + if: ${{ steps.release.outputs.releases_created == 'true' }} + uses: actions/attest@v4 + with: + subject-path: '${{ steps.ci.outputs.dist-dir }}/*tar.gz' diff --git a/PROVENANCE.md b/PROVENANCE.md index e7c98ba..51b6e01 100644 --- a/PROVENANCE.md +++ b/PROVENANCE.md @@ -1,10 +1,10 @@ -## Verifying SDK build provenance with the SLSA framework +## Verifying SDK build provenance with GitHub artifact attestations -LaunchDarkly uses the [SLSA framework](https://slsa.dev/spec/v1.0/about) (Supply-chain Levels for Software Artifacts) to help developers make their supply chain more secure by ensuring the authenticity and build integrity of our published SDK packages. +LaunchDarkly uses [GitHub artifact attestations](https://docs.github.com/en/actions/security-for-github-actions/using-artifact-attestations/using-artifact-attestations-to-establish-provenance-for-builds) to help developers make their supply chain more secure by ensuring the authenticity and build integrity of our published SDK packages. -As part of [SLSA requirements for level 3 compliance](https://slsa.dev/spec/v1.0/requirements), LaunchDarkly publishes provenance about our SDK package builds using [GitHub's generic SLSA3 provenance generator](https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/generic/README.md#generation-of-slsa3-provenance-for-arbitrary-projects) for distribution alongside our packages. These attestations are available for download from the GitHub release page for the release version under Assets > `multiple.intoto.jsonl`. +LaunchDarkly publishes provenance about our SDK package builds using [GitHub's `actions/attest` action](https://github.com/actions/attest). These attestations are stored in GitHub's attestation API and can be verified using the [GitHub CLI](https://cli.github.com/). -To verify SLSA provenance attestations, we recommend using [slsa-verifier](https://github.com/slsa-framework/slsa-verifier). Example usage for verifying SDK packages is included below: +To verify build provenance attestations, we recommend using the [GitHub CLI `attestation verify` command](https://cli.github.com/manual/gh_attestation_verify). Example usage for verifying SDK packages is included below: ``` @@ -13,31 +13,37 @@ SDK_VERSION=4.5.1 ``` - ``` # Download package from Hackage $ curl -O https://hackage.haskell.org/package/launchdarkly-server-sdk-${SDK_VERSION}/launchdarkly-server-sdk-${SDK_VERSION}.tar.gz -# Download provenance from Github release into same directory -$ curl --location -O \ - https://github.com/launchdarkly/haskell-server-sdk/releases/download/${SDK_VERSION}/launchdarkly-server-sdk-${SDK_VERSION}.tar.gz.intoto.jsonl - -# Run slsa-verifier to verify provenance against package artifacts -$ slsa-verifier verify-artifact \ ---provenance-path launchdarkly-server-sdk-${SDK_VERSION}.tar.gz.intoto.jsonl \ ---source-uri github.com/launchdarkly/haskell-server-sdk \ -launchdarkly-server-sdk-${SDK_VERSION}.tar.gz +# Verify provenance using the GitHub CLI +$ gh attestation verify launchdarkly-server-sdk-${SDK_VERSION}.tar.gz --owner launchdarkly ``` Below is a sample of expected output. + ``` -Verified signature against tlog entry index 76419919 at URL: https://rekor.sigstore.dev/api/v1/log/entries/24296fb24b8ad77a56491ff79d66537ddc16157d7ba7f31d59f0929cc6ce75ed98a0efed7fd3272a -Verified build using builder "https://github.com/slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@refs/tags/v1.7.0" at commit dcf5e4be8e0c176c875919dcd5877193fac4f634 -Verifying artifact launchdarkly-server-sdk-4.0.4.tar.gz: PASSED +Loaded digest sha256:... for file://launchdarkly-server-sdk-4.5.1.tar.gz +Loaded 1 attestation from GitHub API + +The following policy criteria will be enforced: +- Predicate type must match:................ https://slsa.dev/provenance/v1 +- Source Repository Owner URI must match:... https://github.com/launchdarkly +- Subject Alternative Name must match regex: (?i)^https://github.com/launchdarkly/ +- OIDC Issuer must match:................... https://token.actions.githubusercontent.com + +✓ Verification succeeded! + +The following 1 attestation matched the policy criteria -PASSED: Verified SLSA provenance +- Attestation #1 + - Build repo:..... launchdarkly/haskell-server-sdk + - Build workflow:. .github/workflows/release-please.yml + - Signer repo:.... launchdarkly/haskell-server-sdk + - Signer workflow: .github/workflows/release-please.yml ``` -Alternatively, to verify the provenance manually, the SLSA framework specifies [recommendations for verifying build artifacts](https://slsa.dev/spec/v1.0/verifying-artifacts) in their documentation. +For more information, see [GitHub's documentation on verifying artifact attestations](https://docs.github.com/en/actions/security-for-github-actions/using-artifact-attestations/using-artifact-attestations-to-establish-provenance-for-builds#verifying-artifact-attestations-with-the-github-cli). **Note:** These instructions do not apply when building our SDKs from source.