diff --git a/.github/linters/tsconfig.json b/.github/linters/tsconfig.json index cc87883..a34cf90 100644 --- a/.github/linters/tsconfig.json +++ b/.github/linters/tsconfig.json @@ -5,8 +5,5 @@ "noEmit": true }, "include": ["../../__tests__/**/*", "../../src/**/*"], - "exclude": ["../../dist", "../../node_modules", "../../coverage", "*.json"], - "references": [ - { "path": "./packages/attest" } - ] + "exclude": ["../../dist", "../../node_modules", "../../coverage", "*.json"] } diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5d3a7a3..1ff0c9d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,9 +49,8 @@ jobs: name: Test attest-provenance action runs-on: ubuntu-latest permissions: - contents: read + contents: write id-token: write - packages: write steps: - name: Checkout diff --git a/README.md b/README.md index b928abc..f9ad5c8 100644 --- a/README.md +++ b/README.md @@ -1,164 +1,109 @@ -# attest-build-provenance +# `actions/attest-build-provenance` -GitHub Action to create, sign and upload a build provenance attestation for -artifacts built as part of a workflow. +Generate signed build provenace attestations for workflow artifacts. Internally +powered by the [@actions/attest][1] package. + +Attestations bind some subject (a named artifact along with its digest) to a +[SLSA build provenance][3] predicate using the [in-toto][2] format. + +A verifiable signature is generated for the attestation using a short-lived +[Sigstore][4]-issued signing certificate. If the repository initiating the +GitHub Actions workflow is public, the public-good instance of Sigstore will be +used to generate the attestation signature. If the repository is +private/internal, it will use the GitHub private Sigstore instance. + +Once the attestation has been created and signed, it will be uploaded to the GH +attestations API and associated with the repository from which the workflow was +initiated. + +Attestations can be verified using the `attestation` command in the [GitHub +CLI][5]. ## Usage Within the GitHub Actions workflow which builds some artifact you would like to -attest, +attest: 1. Ensure that the following permissions are set: ```yaml permissions: id-token: write - contents: write + contents: write # TODO: Update this ``` The `id-token` permission gives the action the ability to mint the OIDC token - necessary to request a Sigstore signing certificate. The `contents` - permission is necessary to persist the attestation. + permission is necessary to persist the attestation. The `contents` permission + is necessary to persist the attestation. - > **NOTE**: The set of required permissions will be refined in a future - > release. - -1. After your artifact build step, add the following: +1. Add the following to your workflow after your artifact has been built: ```yaml - - uses: actions/attest-build-provenance@main + - uses: actions/attest-build-provenance@v1 with: - subject-path: '${{ github.workspace }}/PATH_TO_FILE' + subject-path: '' ``` The `subject-path` parameter should identity the artifact for which you want to generate an attestation. -### What is being attested? - -The generated attestation is a [SLSA provenance][2] document which captures -non-falsifiable information about the GitHub Actions run in which the subject -artifact was created: - -```json -{ - "_type": "https://in-toto.io/Statement/v1", - "subject": [ - { - "name": "some-app", - "digest": { - "sha256": "7d070f6b64d9bcc530fe99cc21eaaa4b3c364e0b2d367d7735671fa202a03b32" - } - } - ], - "predicateType": "https://slsa.dev/provenance/v1", - "predicate": { - "buildDefinition": { - "buildType": "https://slsa-framework.github.io/github-actions-buildtypes/workflow/v1", - "externalParameters": { - "workflow": { - "ref": "refs/heads/main", - "repository": "https://github.com/user/app", - "path": ".github/workflows/build.yml" - } - }, - "internalParameters": { - "github": { - "event_name": "push", - "repository_id": "706279790", - "repository_owner_id": "19792534" - } - }, - "resolvedDependencies": [ - { - "uri": "git+https://github.com/user/app@refs/heads/main", - "digest": { - "gitCommit": "c607ef44660b66df4d10b0dd6b01f56ec98f293f" - } - } - ] - }, - "runDetails": { - "builder": { - "id": "https://github.com/actions/runner/github-hosted" - }, - "metadata": { - "invocationId": "https://github.com/user/app/actions/runs/1880241037/attempts/1" - } - } - } -} -``` - -The provenance statement is signed with a short-lived, [Sigstore][1]-issued -certificate. - -If the repository initiating the GitHub Actions workflow is public, the public -instance of Sigstore will be used to generate the attestation signature. If the -repository is private, it will use the GitHub private Sigstore instance. - -### Where does the attestation go? - -On the actions summary page for a repository you'll see an "Attestations" link -which will take you to a list of all the attestations generated by workflows in -that repository. - -![Actions summary view](./.github/attestations.png) - -### How are attestations verified? - -Attestations can be verified using the [gh-attestation][3] extension for the -[GitHub CLI][4]. - -## Customization +### Inputs See [action.yml](action.yml) -### Inputs +```yaml +- uses: actions/attest-build-provenance@v1 + with: + # Path to the artifact serving as the subject of the attestation. Must + # specify exactly one of "subject-path" or "subject-digest". + subject-path: -- `subject-path` - Path to the artifact for which the provenance will be - generated. + # SHA256 digest of the subject for for the attestation. Must be in the form + # "sha256:hex_digest" (e.g. "sha256:abc123..."). Must specify exactly one + # of "subject-path" or "subject-digest". + subject-digest: - Must specify exactly one of `subject-path` or `subject-digest`. Wildcards can - be used to identify more than one artifact. + # Subject name as it should appear in the attestation. Required unless + # "subject-path" is specified, in which case it will be inferred from the + # path. + subject-name: -- `subject-digest` - Digest of the subject for which the provenance will be - generated. + # Whether to push the attestation to the image registry. Requires that the + # "subject-name" parameter specify the fully-qualified image name and that + # the "subject-digest" parameter be specified. Defaults to false. + push-to-registry: - Only SHA-256 digests are accepted and the supplied value must be in the form - "sha256:\". Must specify exactly one of `subject-path` or - `subject-digest`. - -- `subject-name` - Subject name as it should appear in the provenance statement. - - Required when the subject is identified by the `subject-digest` parameter. - When attesting container images, the name should be the fully qualified image - name. - -- `push-to-registry` - If true, the signed attestation is pushed to the - container registry identified by the `subject-name`. Default: `false`. - -- `github-token` - Token used to make authenticated requests to the GitHub API. - Default: `${{ github.token }}`. - - The supplied token must have the permissions necessary to write attestations - to the repository. + # The GitHub token used to make authenticated API requests. Default is + # ${{ github.token }} + github-token: +``` ### Outputs -- `bundle-path` - The file path of JSON-serialized [Sigstore bundle][5] containing - the attestation and related verification material. + -## Sample Workflows +| Name | Description | Example | +| ------------- | -------------------------------------------------------------- | ------------------------ | +| `bundle-path` | Absolute path to the file containing the generated attestation | `/tmp/attestation.jsonl` | -### Identify Artifact by Path + -For the basic use case, simply add the `attest-build-provenance` action to -your workflow and supply the path to the artifact for which you want to generate -build provenance. +Attestations are saved in the JSON-serialized [Sigstore bundle][6] format. + +If multiple subjects are being attested at the same time, each attestation will +be written to the output file on a separate line (using the [JSON Lines][7] +format). + +## Examples + +### Identify Subject by Path + +For the basic use case, simply add the `attest-build-provenance` action to your +workflow and supply the path to the artifact for which you want to generate +attestation. ```yaml -name: build-with-provenance +name: build-attest on: workflow_dispatch: @@ -173,57 +118,31 @@ jobs: - name: Checkout uses: actions/checkout@v4 - name: Build artifact - run: make some-app - - name: Attest artifact - uses: actions/attest-build-provenance@main + run: make my-app + - name: Attest + uses: actions/attest-build-provenance@v1 with: - subject-path: '${{ github.workspace }}/some-app' + subject-path: '${{ github.workspace }}/my-app' ``` -### Identify Artifacts by Wildcard +### Identify Subjects by Wildcard -If you are generating multiple artifacts, you can generate build provenance for -each artifact by using a wildcard in the `subject-path` input. +If you are generating multiple artifacts, you can generate a provenance +attestation for each by using a wildcard in the `subject-path` input. ```yaml -name: build-wildcard-with-provenance - -on: - workflow_dispatch: - -jobs: - build: - permissions: - id-token: write - contents: write - - steps: - - name: Checkout - uses: actions/checkout@v4 - - name: Set up Go - uses: actions/setup-go@v4 - - name: Run GoReleaser - uses: goreleaser/goreleaser-action@v5 - with: - distribution: goreleaser - version: latest - args: release --clean - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Attest artifact - uses: actions/attest-build-provenance@main - with: - subject-path: 'dist/**/my-bin-*' +- uses: actions/attest-build-provenance@v1 + with: + subject-path: 'dist/**/my-bin-*' ``` For supported wildcards along with behavior and documentation, see -[@actions/glob][6] which is used internally to search for files. +[@actions/glob][8] which is used internally to search for files. ### Container Image -When working with container images you may not have a `subject-path` value you -can supply. In this case you can invoke the action with the `subject-name` and -`subject-digest` inputs. +When working with container images you can invoke the action with the +`subject-name` and `subject-digest` inputs. If you want to publish the attestation to the container registry with the `push-to-registry` option, it is important that the `subject-name` specify the @@ -235,7 +154,7 @@ the specific image being attested is identified by the supplied digest. > registry portion of the image name. ```yaml -name: build-image-with-provenance +name: build-attested-image on: push: @@ -268,18 +187,21 @@ jobs: context: . push: true tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest - - name: Attest image - uses: actions/attest-build-provenance@main + - name: Attest + uses: actions/attest-build-provenance@v1 + id: attest with: subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} subject-digest: ${{ steps.push.outputs.digest }} push-to-registry: true ``` -[1]: https://www.sigstore.dev/ -[2]: https://slsa.dev/spec/v1.0/provenance -[3]: https://github.com/github-early-access/gh-attestation -[4]: https://cli.github.com/ -[5]: +[1]: https://github.com/actions/toolkit/tree/main/packages/attest +[2]: https://github.com/in-toto/attestation/tree/main/spec/v1 +[3]: https://slsa.dev/spec/v1.0/provenance +[4]: https://www.sigstore.dev/ +[5]: https://cli.github.com/ +[6]: https://github.com/sigstore/protobuf-specs/blob/main/protos/sigstore_bundle.proto -[6]: https://github.com/actions/toolkit/tree/main/packages/glob#patterns +[7]: https://jsonlines.org/ +[8]: https://github.com/actions/toolkit/tree/main/packages/glob#patterns diff --git a/action.yml b/action.yml index 851c430..6e0bb6f 100644 --- a/action.yml +++ b/action.yml @@ -3,11 +3,6 @@ description: 'Generate provenance attestations for build artifacts' author: 'GitHub' inputs: - github-token: - description: > - The GitHub token used to make authenticated API requests. - default: ${{ github.token }} - required: false subject-path: description: > Path to the artifact for which provenance will be generated. Must specify @@ -31,6 +26,11 @@ inputs: and that the "subject-digest" parameter be specified. Defaults to false. default: false required: false + github-token: + description: > + The GitHub token used to make authenticated API requests. + default: ${{ github.token }} + required: false outputs: bundle-path: description: 'The path to the file containing the attestation bundle(s).'