input refactor and readme updates (#13)

Signed-off-by: Brian DeHamer <[email protected]>
This commit is contained in:
Brian DeHamer
2024-02-29 11:59:05 -08:00
committed by GitHub
parent 69180bebd9
commit 3eb264bd7e
5 changed files with 183 additions and 299 deletions
+2 -2
View File
@@ -84,11 +84,11 @@ jobs:
subject-digest: 'sha256:7d070f6b64d9bcc530fe99cc21eaaa4b3c364e0b2d367d7735671fa202a03b32' subject-digest: 'sha256:7d070f6b64d9bcc530fe99cc21eaaa4b3c364e0b2d367d7735671fa202a03b32'
subject-name: 'subject' subject-name: 'subject'
github-token: ${{ secrets.GITHUB_TOKEN }} github-token: ${{ secrets.GITHUB_TOKEN }}
format: 'spdx' sbom-format: 'spdx'
- name: Run attest-sbom with cyclonedx format - name: Run attest-sbom with cyclonedx format
uses: ./ uses: ./
with: with:
subject-digest: 'sha256:7d070f6b64d9bcc530fe99cc21eaaa4b3c364e0b2d367d7735671fa202a03b32' subject-digest: 'sha256:7d070f6b64d9bcc530fe99cc21eaaa4b3c364e0b2d367d7735671fa202a03b32'
subject-name: 'subject' subject-name: 'subject'
github-token: ${{ secrets.GITHUB_TOKEN }} github-token: ${{ secrets.GITHUB_TOKEN }}
format: 'cyclonedx' sbom-format: 'cyclonedx'
+118 -203
View File
@@ -1,185 +1,127 @@
# attest-sbom # `actions/attest-sbom`
GitHub Action to create, sign and upload a SBOM (Software Bill of Materials) Generate signed SBOM attestations for workflow artifacts. Internally powered by
attestation for artifacts built as part of a workflow. the [@actions/attest-sbom][1] package.
Attestations bind some subject (a named artifact along with its digest) to a a
Software Bill of Materials (SBOM) using the [in-toto][2] format. The action
accepts SBOMs which have been generated by external tools or can generate one
automatically by invoking the [anchore/sbom-action][3]. Externally generated
SBOMs must be in either the [SPDX][4] or [CycloneDX][5] JSON-serialized format.
A verifiable signature is generated for the attestation using a short-lived
[Sigstore][6]-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][7].
## Usage ## Usage
Within the GitHub Actions workflow which builds some artifact you would like to Within the GitHub Actions workflow which builds some artifact you would like to
attest, attest:
1. Ensure that the following permissions are set: 1. Ensure that the following permissions are set:
```yaml ```yaml
permissions: permissions:
id-token: write id-token: write
contents: write contents: write # TODO: Update this
``` ```
The `id-token` permission gives the action the ability to mint the OIDC token The `id-token` permission gives the action the ability to mint the OIDC token
necessary to request a Sigstore signing certificate. The `contents` necessary to request a Sigstore signing certificate. The `contents`
permission is necessary to persist the attestation. permission is necessary to persist the attestation.
> **NOTE**: The set of required permissions will be refined in a future 1. Add the following to your workflow after your artifact has been built:
> release.
1. After your artifact build step, add the following:
```yaml ```yaml
- uses: actions/attest-sbom@main - uses: actions/attest-sbom@v1
with: with:
path: subject-path: '<PATH TO ARTIFACT>'
subject-path: '${{ github.workspace }}/PATH_TO_FILE'
format: 'spdx'
``` ```
The `subject-path` parameter should identity the artifact for which you want The `subject-path` parameter should identity the artifact for which you want
to generate an attestation. to generate an SBOM attestation. When no other inputs are specified, the
action will automatically generate an SPDX SBOM by scanning the
### What is being attested? `github.workspace` directory.
The generated attestation is a Software Bill of Materials (SBOM), which is
essentially a detailed list of all the components in a software artifact.
```json
{
"_type": "https://in-toto.io/Statement/v1",
"subject": [
{
"name": "subject",
"digest": {
"sha256": "7d070f6b64d9bcc530fe99cc21eaaa4b3c364e0b2d367d7735671fa202a03b32"
}
}
],
"predicateType": "https://spdx.dev/Document/v2.3",
"predicate": {
"spdxVersion": "SPDX-2.3",
"dataLicense": "CC0-1.0",
"SPDXID": "SPDXRef-DOCUMENT",
"name": "./",
"documentNamespace": "https://anchore.com/syft/dir/80b363b6-87f4-4162-853f-60d402537d20",
"creationInfo": {
"licenseListVersion": "3.22",
"creators": [
"Organization: Anchore, Inc",
"Tool: syft-0.103.1"
],
"created": "2024-01-31T18:22:50Z"
},
"packages": [
{
"name": "@ampproject/remapping",
"SPDXID": "SPDXRef-Package-npm--ampproject-remapping-5266573ba4f24a42",
"versionInfo": "2.2.1",
"supplier": "NOASSERTION",
"downloadLocation": "NOASSERTION",
"filesAnalyzed": false,
"sourceInfo":
"acquired package info from installed node module manifest file: /yarn.lock",
"licenseConcluded": "NOASSERTION",
"licenseDeclared": "Apache-2.0",
"copyrightText": "NOASSERTION",
"externalRefs": [
{
"referenceCategory": "SECURITY",
"referenceType": "cpe23Type",
"referenceLocator":
"cpe:2.3:a:\\@ampproject\\/remapping:\\@ampproject\\/remapping:2.2.1:*:*:*:*:*:*:*"
},
{
"referenceCategory": "PACKAGE-MANAGER",
"referenceType": "purl",
"referenceLocator": "pkg:npm/%40ampproject/[email protected]"
}
]
}
]
}
}
```
The SBOM 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][2] extension for the
[GitHub CLI][3].
## Customization
See [action.yml](action.yml)
### Inputs ### Inputs
- `path` - A path to a directory on the filesystem to scan and generate SBOM. See [action.yml](action.yml)
If `sbom-path` is specified, the path will not be used to generate SBOM. ```yaml
- uses: actions/attest@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:
- `sbom-path` - A path to a directory on the filesystem which contains SBOM for signing # SHA256 digest of the subject for for the attestation. Must be in the form
and uploading. # "sha256:hex_digest" (e.g. "sha256:abc123..."). Must specify exactly one
# of "subject-path" or "subject-digest".
subject-digest:
If `sbom-path` is not specified, the default implementation will be used # Subject name as it should appear in the attestation. Required unless
`path` to generate SBOM for signing. # "subject-path" is specified, in which case it will be inferred from the
# path.
subject-name:
- `format` - The format of the SBOM. Either `spdx` or `cyclonedx` # Path to the JSON-formatted SBOM file to attest. When specified, the
# "scan-path" and "sbom-format" inputs are ignored.
sbom-path:
- `subject-path` - Path to the artifact for which the SBOM statement will be # Path on the filesystem to scan for SBOM generation. Ignored if "sbom-path"
generated. # is specified. Defaults to ${{ github.workspace }}
scan-path:
Must specify exactly one of `subject-path` or `subject-digest`. Wildcards can # Format to use for the generated SBOM output. Supported formats are
be used to identify more than one artifact. # "spdx" and "cyclonedx". Ignored if "sbom-path" is specified. Defaults to
# "spdx".
sbom-format:
- `subject-digest` - Digest of the subject for which the SBOM statement will be # Whether to push the attestation to the image registry. Requires that the
generated. # "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 # The GitHub token used to make authenticated API requests. Default is
"sha256:\<hex-encoded-digest\>". Must specify exactly one of `subject-path` or # ${{ github.token }}
`subject-digest`. github-token:
```
- `subject-name` - Subject name as it should appear in the SBOM 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.
### Outputs ### Outputs
- `bundle-path` - The file path of JSON-serialized [Sigstore bundle][4] containing <!-- markdownlint-disable MD013 -->
the attestation and related verification material.
## Sample Workflows | Name | Description | Example |
| ------------- | -------------------------------------------------------------- | ----------------------- |
| `bundle-path` | Absolute path to the file containing the generated attestation | `/tmp/attestaion.jsonl` |
### Identify Artifact by Path <!-- markdownlint-enable MD013 -->
For the basic use case, simply add the `attest-sbom` action to Attestations are saved in the JSON-serialized [Sigstore bundle][8] format.
your workflow and supply the path to the artifact for which you want to generate
SBOM. 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][9]
format).
## Examples
### Identify Subject and SBOM by Path
For the basic use case, simply add the `attest-sbom` action to your workflow and
supply the path to the artifact and SBOM for which you want to generate
attestation.
```yaml ```yaml
name: attest-sbom name: build-attest
on: on:
workflow_dispatch: workflow_dispatch:
@@ -194,61 +136,35 @@ jobs:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Build artifact - name: Build artifact
run: make some-app run: make my-app
- name: Attest SBOM - name: Generate SBOM
uses: actions/attest-sbom@main run: make sbom
- name: Attest
uses: actions/attest-sbom@v1
with: with:
subject-path: '${{ github.workspace }}/some-app' subject-path: '${{ github.workspace }}/my-app'
path: '.' sbom-path: '${{ github.workspace }}/my-app.sbom.spdx.json'
format: 'spdx'
``` ```
### Identify Artifacts by Wildcard ### Identify Subjects by Wildcard
If you are generating multiple artifacts, you can generate sbom for If you are generating multiple artifacts, you can generate an attestation for
each artifact by using a wildcard in the `subject-path` input. each by using a wildcard in the `subject-path` input.
```yaml ```yaml
name: build-wildcard-with-sbom - uses: actions/attest-sbom@v1
with:
on: subject-path: 'dist/**/my-bin-*'
workflow_dispatch: sbom-path: '${{ github.workspace }}/my-bin.sbom.spdx.json'
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-sbom@main
with:
subject-path: 'dist/**/my-bin-*'
path: '.'
format: 'spdx'
``` ```
For supported wildcards along with behavior and documentation, see For supported wildcards along with behavior and documentation, see
[@actions/glob][5] which is used internally to search for files. [@actions/glob][10] which is used internally to search for files.
### Container Image ### Container Image
When working with container images you may not have a `subject-path` value you When working with container images you can invoke the action with the
can supply. In this case you can invoke the action with the `subject-name` and `subject-name` and `subject-digest` inputs.
`subject-digest` inputs.
If you want to publish the attestation to the container registry with the 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 `push-to-registry` option, it is important that the `subject-name` specify the
@@ -260,7 +176,7 @@ the specific image being attested is identified by the supplied digest.
> registry portion of the image name. > registry portion of the image name.
```yaml ```yaml
name: build-image-with-sbom name: build-attested-image
on: on:
push: push:
@@ -293,27 +209,26 @@ jobs:
context: . context: .
push: true push: true
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
- name: Generate SBOM from Docker Image - name: Generate SBOM
id: sbom run: make sbom
uses: anchore/sbom-action@v0 - name: Attest
uses: actions/attest-sbom@v1
id: attest
with: with:
image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
registry-username: ${{ github.actor }}
registry-password: ${{ secrets.GITHUB_TOKEN }}
format: "spdx-json"
output-file: "sbom.json"
- name: Attest SBOM
uses: actions/attest-sbom@main
id: attest-sbom
with:
sbom-path: "sbom.json"
subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
subject-digest: ${{ steps.push.outputs.digest }} subject-digest: ${{ steps.push.outputs.digest }}
format: "spdx" sbom-path: 'sbom.cyclonedx.json'
push-to-registry: true
``` ```
[1]: https://www.sigstore.dev/ [1]: https://github.com/actions/toolkit/tree/main/packages/attest
[2]: https://github.com/github-early-access/gh-attestation [2]: https://github.com/in-toto/attestation/tree/main/spec/v1
[3]: https://cli.github.com/ [3]: https://github.com/anchore/sbom-action
[4]: https://github.com/sigstore/protobuf-specs/blob/main/protos/sigstore_bundle.proto [4]: https://spdx.dev/
[5]: https://github.com/actions/toolkit/tree/main/packages/glob#patterns [5]: https://cyclonedx.org/
[6]: https://www.sigstore.dev/
[7]: https://cli.github.com/
[8]:
https://github.com/sigstore/protobuf-specs/blob/main/protos/sigstore_bundle.proto
[9]: https://jsonlines.org/
[10]: https://github.com/actions/toolkit/tree/main/packages/glob#patterns
+43 -46
View File
@@ -3,37 +3,39 @@ description: 'Generate SBOM attestations for build artifacts'
author: 'GitHub' author: 'GitHub'
inputs: inputs:
path:
required: false
description: "A path to a directory on the filesystem to scan"
default: "."
format:
required: false
description: "The SBOM format to export"
default: "spdx-json"
github-token:
description: >
The GitHub token used to make authenticated API requests.
default: ${{ github.token }}
required: false
subject-path: subject-path:
description: > description: >
Path to the artifact for which provenance will be generated. Must specify Path to the artifact serving as the subject of the attestation. Must
exactly one of "subject-path" or "subject-digest". specify exactly one of "subject-path" or "subject-digest".
required: false required: false
subject-digest: subject-digest:
description: > description: >
Digest of the subject for which provenance will be generated. Must be in SHA256 digest of the subject for for the attestation. Must be in the form
the form "algorithm:hex_digest" (e.g. "sha256:abc123..."). Must specify "sha256:hex_digest" (e.g. "sha256:abc123..."). Must specify exactly one of
exactly one of "subject-path" or "subject-digest". "subject-path" or "subject-digest".
required: false required: false
subject-name: subject-name:
description: > description: >
Subject name as it should appear in the provenance statement. Required Subject name as it should appear in the attestation. Required unless
unless "subject-path" is specified, in which case it will be inferred from "subject-path" is specified, in which case it will be inferred from the
the path. path.
sbom-path:
description: >
Path to the JSON-formatted SBOM file to attest. When specified, the
"scan-path" and "sbom-format" inputs are ignored.
required: false
scan-path:
description: >
Path on the filesystem to scan for SBOM generation. Ignored if "sbom-path"
is specified.
default: ${{ github.workspace }}
required: false
sbom-format:
description: >
Format to use for the generated SBOM output. Supported formats are "spdx"
and "cyclonedx". Ignored if "sbom-path" is specified.
default: 'spdx'
required: false
push-to-registry: push-to-registry:
description: > description: >
Whether to push the provenance statement to the image registry. Requires Whether to push the provenance statement to the image registry. Requires
@@ -41,11 +43,11 @@ inputs:
and that the "subject-digest" parameter be specified. Defaults to false. and that the "subject-digest" parameter be specified. Defaults to false.
default: false default: false
required: false required: false
sbom-path: github-token:
description: > description: >
Path to the SBOM file to generate sbom statement. The GitHub token used to make authenticated API requests.
default: ${{ github.token }}
required: false required: false
default: ''
outputs: outputs:
bundle-path: bundle-path:
description: 'The path to the file containing the attestation bundle(s).' description: 'The path to the file containing the attestation bundle(s).'
@@ -56,46 +58,41 @@ runs:
steps: steps:
- name: Generate random SBOM output file name - name: Generate random SBOM output file name
if: ${{ inputs.sbom-path == '' }} if: ${{ inputs.sbom-path == '' }}
run: echo "SBOM_FILENAME=${{ runner.temp }}/sbom_$(openssl rand -hex 6).json" >> $GITHUB_ENV run:
echo "SBOM_FILENAME=${{ runner.temp }}/sbom_$(openssl rand -hex 6).json" >> $GITHUB_ENV
shell: bash shell: bash
- name: SBOM format check - name: SBOM format check
if: ${{ inputs.sbom-path == '' }} if: ${{ inputs.sbom-path == '' }}
run: | run: |
if [ "${{inputs.format}}" != "spdx-json" ] && [ "${{inputs.format}}" != "cyclonedx-json" ] && [ "${{inputs.format}}" != "spdx" ] && [ "${{inputs.format}}" != "cyclonedx" ] ]; then if [ "${{inputs.sbom-format}}" != "spdx" ] && [ "${{inputs.sbom-format}}" != "cyclonedx" ] ]; then
echo "Invalid SBOM format. Supported formats are spdx-json, cyclonedx-json, spdx, cyclonedx" echo "Invalid SBOM format. Supported formats are spdx and cyclonedx."
exit 1 exit 1
fi elif [ "${{inputs.sbom-format}}" == "spdx" ]; then
echo "SBOM_FORMAT=${{inputs.format}}" >> $GITHUB_ENV
if [ "${{inputs.format}}" == "spdx" ]; then
echo "SBOM_FORMAT=spdx-json" >> $GITHUB_ENV echo "SBOM_FORMAT=spdx-json" >> $GITHUB_ENV
elif [ "${{inputs.format}}" == "cyclonedx" ]; then elif [ "${{inputs.sbom-format}}" == "cyclonedx" ]; then
echo "SBOM_FORMAT=cyclonedx-json" >> $GITHUB_ENV echo "SBOM_FORMAT=cyclonedx-json" >> $GITHUB_ENV
fi fi
shell: bash shell: bash
- name: Generate SBOM - name: Generate SBOM
if: ${{ inputs.sbom-path == '' }} if: ${{ inputs.sbom-path == '' }}
uses: anchore/sbom-action@v0 uses: anchore/sbom-action@b6a39da80722a2cb0ef5d197531764a89b5d48c3 # v0.15.8
with: with:
path: ${{inputs.path}} path: ${{inputs.scan-path}}
output-file: ${{env.SBOM_FILENAME}} output-file: ${{env.SBOM_FILENAME}}
format: ${{env.SBOM_FORMAT}} format: ${{env.SBOM_FORMAT}}
config: ${{inputs.config}} - uses: actions/attest-sbom/generate-sbom-predicate@readme
- uses: actions/attest-sbom/generate-sbom-statement@main id: generate-sbom-predicate
id: generate-sbom-statement
with: with:
github-token: ${{ inputs.github-token }}
subject-path: ${{ inputs.subject-path }}
subject-digest: ${{ inputs.subject-digest }}
subject-name: ${{ inputs.subject-name }}
push-to-registry: ${{ inputs.push-to-registry }}
sbom-path: ${{ inputs.sbom-path || env.SBOM_FILENAME }} sbom-path: ${{ inputs.sbom-path || env.SBOM_FILENAME }}
- uses: actions/attest@main - uses: actions/attest@main
id: attest id: attest
with: with:
github-token: ${{ inputs.github-token }}
subject-path: ${{ inputs.subject-path }} subject-path: ${{ inputs.subject-path }}
subject-digest: ${{ inputs.subject-digest }} subject-digest: ${{ inputs.subject-digest }}
subject-name: ${{ inputs.subject-name }} subject-name: ${{ inputs.subject-name }}
push-to-registry: ${{ inputs.push-to-registry }} push-to-registry: ${{ inputs.push-to-registry }}
predicate-type: ${{ steps.generate-sbom-statement.outputs.predicate-type }} predicate-type:
predicate-path: ${{ steps.generate-sbom-statement.outputs.predicate-path }} ${{ steps.generate-sbom-predicate.outputs.predicate-type }}
predicate-path:
${{ steps.generate-sbom-predicate.outputs.predicate-path }}
github-token: ${{ inputs.github-token }}
+19
View File
@@ -0,0 +1,19 @@
name: 'Generate SBOM Predicate'
description: 'Generate SBOM predicate'
author: 'GitHub'
inputs:
sbom-path:
description: >
Path to the SBOM file to generate sbom statement
required: false
outputs:
predicate-path:
description: >
The path to the JSON-serialized of the attestation predicate
predicate-type:
description: >
URI identifying the type of the predicate.
runs:
using: node20
main: ../dist/index.js
-47
View File
@@ -1,47 +0,0 @@
name: 'Generate SBOM Statement'
description: 'Generate SBOM Statement 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
exactly one of "subject-path" or "subject-digest".
required: false
subject-digest:
description: >
Digest of the subject for which provenance will be generated. Must be in
the form "algorithm:hex_digest" (e.g. "sha256:abc123..."). Must specify
exactly one of "subject-path" or "subject-digest".
required: false
subject-name:
description: >
Subject name as it should appear in the provenance statement. Required
unless "subject-path" is specified, in which case it will be inferred from
the path.
push-to-registry:
description: >
Whether to push the provenance statement 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.
default: false
required: false
sbom-path:
description: >
Path to the SBOM file to generate sbom statement
required: false
outputs:
predicate-path:
description: >
The path to the JSON-serialized of the attestation predicate
predicate-type:
description: >
URI identifying the type of the predicate.
runs:
using: node20
main: ../dist/index.js