Loading...
Loading...
Marco Franssen

In my previous post, you can read about securing the software supply chain for Docker images using GitHub Actions and Sigstore. We saw how to sign our Docker images and generate an SBOM and build provenance. Using Sigstore/cosign, we attached the signature, SBOM, and build provenance to the Docker image. Sigstore gives us a really nice integration and developer experience for adding these security features to our Docker image build pipelines.
In this post, I want to show you an approach to storing SBOMs and provenance in an OCI registry for other software release assets (e.g. npm, Maven, NuGet, …). We will also use cosign to interact with the registry. The developer experience is not as nicely integrated as it is for Docker images, but this can be a step toward a better setup until a more integrated solution is available for package managers.
By using OCI as blob storage, we can distribute and discover attestations for software assets that are not OCI/Docker images. The idea is to establish a naming convention that relates, for example, our npm package to a blob in the OCI registry. We can document this convention to make it clear to consumers of our assets where they can find the SBOM and build provenance.
Assuming we already have build provenance (named provenance.att) and an SBOM (named sbom-spdx.json) for a fictitious npm package, our folder structure might look like this.
$ tree examples/awesome-node-cli
examples/awesome-node-cli
├── bin
│ └── awesome-node-cli.js
├── node_modules
│ └── commander
│ └── …
├── sbom-spdx.json
├── provenance.att
├── package.json
└── yarn.lock
5 directories, 18 filesWith the SBOM and provenance generated, we can use an OCI registry to store and distribute them. The next example shows how to do that using cosign.
$ cosign upload blob -f provenance.att ghcr.io/marcofranssen/slsa-workflow-examples/attestations:awesome-node-cli-v0.1.5.provenance
Uploading file from [provenance.att] to [ghcr.io/marcofranssen/slsa-workflow-examples/attestations:awesome-node-cli-v0.1.5.provenance] with media type [text/plain]
File [provenance.att] is available directly at [ghcr.io/v2/marcofranssen/slsa-workflow-examples/attestations/blobs/sha256:f21e2217b67da30183139b8db23db829cd8abb7c9a5a66068e57cde07e29a215]
$ cosign sign --key cosign.key ghcr.io/marcofranssen/slsa-workflow-examples/attestations:awesome-node-cli-v0.1.5.provenance
Pushing signature to: ghcr.io/marcofranssen/slsa-workflow-examples/attestations
$ cosign upload blob -f sbom-spdx.json ghcr.io/marcofranssen/slsa-workflow-examples/attestations:awesome-node-cli-v0.1.5.sbom
Uploading file from [examples/awesome-node-cli/sbom-spdx.json] to [ghcr.io/marcofranssen/slsa-workflow-examples/attestations:awesome-node-cli-v0.1.5.sbom] with media type [text/plain]
File [examples/awesome-node-cli/sbom-spdx.json] is available directly at [ghcr.io/v2/marcofranssen/slsa-workflow-examples/attestations/blobs/sha256:ebdbffa2affe75b8ed7ff2e53cb41943a5201b13ff1a22375270f1c46c754f8c]
$ cosign sign --key cosign.key ghcr.io/marcofranssen/slsa-workflow-examples/attestations:awesome-node-cli-v0.1.5.sbom
Pushing signature to: ghcr.io/marcofranssen/slsa-workflow-examples/attestationsFor other packages, we can do the same by applying the tagging convention («oci-registry»:«pkg-name»-«version».«attestation-type») used in the previous example.
With these attestations stored in the OCI registry, consumers of our assets can download them and verify their signatures to establish their authenticity. We can do this using sget. Once downloaded, we can write an attestation to a file or pipe it to other shell tools to inspect, transform, and use it. More on consuming the stored attestations later in this post. First, let's look at fatt, a proof of concept (POC) that makes publishing and discovery easier by automating the steps above.
To further automate uploading and signing SBOMs and provenance, we built fatt as a POC. (Note: signing is not yet implemented in fatt and remains a manual step; see fatt#20).
fatt requires a few command-line arguments to apply the convention we used manually with cosign. To identify the attestation type, fatt requires a URL Scheme prefix on each attestation to be uploaded (see the example below).
$ fatt publish --repository ghcr.io/marcofranssen/slsa-workflow-examples/attestations --tag-prefix awesome-node-cli --version v0.1.5 sbom://sbom-spdx.json provenance://provenance.att
Publishing attestations…
Uploading file from [examples/awesome-node-cli/sbom-spdx.json] to [ghcr.io/marcofranssen/slsa-workflow-examples/attestations:awesome-node-cli-v0.1.5.sbom] with media type [text/plain]
File [examples/awesome-node-cli/sbom-spdx.json] is available directly at [ghcr.io/v2/marcofranssen/slsa-workflow-examples/attestations/blobs/sha256:ebdbffa2affe75b8ed7ff2e53cb41943a5201b13ff1a22375270f1c46c754f8c]
Uploading file from [provenance.att] to [ghcr.io/marcofranssen/slsa-workflow-examples/attestations:awesome-node-cli-v0.1.5.provenance] with media type [text/plain]
File [provenance.att] is available directly at [ghcr.io/v2/marcofranssen/slsa-workflow-examples/attestations/blobs/sha256:f21e2217b67da30183139b8db23db829cd8abb7c9a5a66068e57cde07e29a215]
Generating attestations.txt based on uploaded attestations…
Uploading file from [attestations.txt] to [ghcr.io/marcofranssen/slsa-workflow-examples/attestations:awesome-node-cli-v0.1.5.discovery] with media type [text/plain]
File [attestations.txt] is available directly at [ghcr.io/v2/marcofranssen/slsa-workflow-examples/attestations/blobs/sha256:a978b71603dfe0e1c2f7b4915059d2aefc4bb051ea8710d200cdd927fe22138c]
# These 3 signing steps can be removed once https://github.com/philips-labs/fatt/issues/20 is implemented.
$ cosign sign --key cosign.key ghcr.io/marcofranssen/slsa-workflow-examples/attestations:awesome-npm-cli-v0.1.5.sbom
Pushing signature to: ghcr.io/marcofranssen/slsa-workflow-examples/attestations
$ cosign sign --key cosign.key ghcr.io/marcofranssen/slsa-workflow-examples/attestations:awesome-npm-cli-v0.1.5.provenance
Pushing signature to: ghcr.io/marcofranssen/slsa-workflow-examples/attestations
$ cosign sign --key cosign.key ghcr.io/marcofranssen/slsa-workflow-examples/attestations:awesome-npm-cli-v0.1.5.discovery
Pushing signature to: ghcr.io/marcofranssen/slsa-workflow-examples/attestationsfatt uses the tagging convention described earlier in this post for the manual cosign steps. We also added a blob, attestations.txt, which we store in the OCI registry. In this attestations.txt, fatt stores the locations of the SBOM and provenance in purl format. Purls are commonly used in SBOMs to link to other resources. This attestations.txt is used by the filtering capabilities of fatt to support more advanced consumption use cases.
$ fatt list --key cosign.pub ghcr.io/marcofranssen/slsa-workflow-examples/attestations:awesome-node-cli-v0.1.5.discovery
Fetching attestations from ghcr.io/marcofranssen/slsa-workflow-examples/attestations:awesome-node-cli-v0.1.5.discovery…
Verifying signature for ghcr.io/marcofranssen/slsa-workflow-examples/attestations@sha256:252783857d310d36a54086cd1e5035298c98c5db604edc7daa7ce4cdcc03deaf…
pkg:oci/marcofranssen/slsa-workflow-examples/attestations@sha256:68f1d97c61e62228195aedfdfdce74b52123764c0c3b5f71d03b713bc63eb897?repository_url=ghcr.io%2Fmarcofranssen%2Fslsa-workflow-examples%2Fattestations&tag=awesome-node-cli-v0.1.5.sbom
pkg:oci/marcofranssen/slsa-workflow-examples/attestations@sha256:cad11e9b6229631175321b6e35dfbf0124064ef82761e41800bc533ecc3e8f06?repository_url=ghcr.io%2Fmarcofranssen%2Fslsa-workflow-examples%2Fattestations&tag=awesome-node-cli-v0.1.5.provenanceAt this stage, we have published our attestations, either with cosign or with fatt as a convenience. By using a convention, we make it clearer to consumers of our packages where to find the attestations. This also enables consumers to automate how they use them. For example:
We can use sget to fetch a specific blob from an OCI registry. sget is part of the Sigstore tools. It downloads the given resource and automatically verifies the artifact's signature to establish its authenticity.
COSIGN_EXPERIMENTAL=1 sget ghcr.io/marcofranssen/slsa-workflow-examples/attestations:awesome-node-cli-v0.1.5.discoveryIn my case, I used ephemeral keys from Sigstore (COSIGN_EXPERIMENTAL=1). If you used your own signing keys, you will need the --key flag to provide your public key.
Fetching by tag requires signature verification. In this case, you receive two JSON objects: one containing the signature data and one containing your SBOM. To get the SBOM contents, we can use jq.
$ COSIGN_EXPERIMENTAL=1 sget ghcr.io/marcofranssen/slsa-workflow-examples/attestations:awesome-node-cli-v0.1.5.sbom | grep -v '^Certificate' | jq --slurp '.[1] | .packages'
Verification for ghcr.io/marcofranssen/slsa-workflow-examples/attestations:awesome-node-cli-v0.1.5.sbom --
The following checks were performed on each of these signatures:
- The cosign claims were validated
- Existence of the claims in the transparency log was verified offline
- Any certificates were verified against the Fulcio roots.
[
{
"SPDXID": "SPDXRef-8f4c75ddef2e1d03",
"name": "commander",
"licenseConcluded": "NONE",
"downloadLocation": "NOASSERTION",
"externalRefs": [
{
"referenceCategory": "SECURITY",
"referenceLocator": "cpe:2.3:a:commander:commander:9.0.0:*:*:*:*:*:*:*",
"referenceType": "cpe23Type"
},
{
"referenceCategory": "SECURITY",
"referenceLocator": "cpe:2.3:a:*:commander:9.0.0:*:*:*:*:*:*:*",
"referenceType": "cpe23Type"
},
{
"referenceCategory": "PACKAGE_MANAGER",
"referenceLocator": "pkg:npm/commander@9.0.0",
"referenceType": "purl"
}
],
"filesAnalyzed": false,
"licenseDeclared": "NONE",
"sourceInfo": "acquired package info from installed node module manifest file: yarn.lock",
"versionInfo": "9.0.0"
}
]If you fetch the asset by digest, you can omit signature verification. However, the digest is less convenient to remember and type. One small advantage is that the command output does not include the signature.
$ sget ghcr.io/marcofranssen/slsa-workflow-examples/attestations@sha256:68f1d97c61e62228195aedfdfdce74b52123764c0c3b5f71d03b713bc63eb897 | jq '.packages'
[
{
"SPDXID": "SPDXRef-8f4c75ddef2e1d03",
"name": "commander",
"licenseConcluded": "NONE",
"downloadLocation": "NOASSERTION",
"externalRefs": [
{
"referenceCategory": "SECURITY",
"referenceLocator": "cpe:2.3:a:commander:commander:9.0.0:*:*:*:*:*:*:*",
"referenceType": "cpe23Type"
},
{
"referenceCategory": "SECURITY",
"referenceLocator": "cpe:2.3:a:*:commander:9.0.0:*:*:*:*:*:*:*",
"referenceType": "cpe23Type"
},
{
"referenceCategory": "PACKAGE_MANAGER",
"referenceLocator": "pkg:npm/commander@9.0.0",
"referenceType": "purl"
}
],
"filesAnalyzed": false,
"licenseDeclared": "NONE",
"sourceInfo": "acquired package info from installed node module manifest file: yarn.lock",
"versionInfo": "9.0.0"
}
]Here is an example of fetching the provenance predicate that describes how the awesome-node-cli asset was produced.
$ COSIGN_EXPERIMENTAL=1 sget ghcr.io/marcofranssen/slsa-workflow-examples/attestations:awesome-node-cli-v0.1.5.provenance | grep -v '^Certificate' | jq --slurp '.[1] | .predicate'
Verification for ghcr.io/marcofranssen/slsa-workflow-examples/attestations:awesome-node-cli-v0.1.5.provenance --
The following checks were performed on each of these signatures:
- The cosign claims were validated
- Existence of the claims in the transparency log was verified offline
- Any certificates were verified against the Fulcio roots.
{
"builder": {
"id": "https://github.com/marcofranssen/slsa-workflow-examples/Attestations/GitHubHostedActions@v1"
},
"buildType": "https://github.com/Attestations/GitHubActionsWorkflow@v1",
"invocation": {
"configSource": {
"entryPoint": "Release NPM",
"uri": "git+https://github.com/marcofranssen/slsa-workflow-examples",
"digest": {
"sha1": "01e93c44cd41e7f6025c815af1f5075a4fcbec8b"
}
},
"parameters": null,
"environment": null
},
"metadata": {
"buildInvocationId": "https://github.com/marcofranssen/slsa-workflow-examples/actions/runs/2070200957",
"buildFinishedOn": "2022-03-31T09:40:17Z",
"completeness": {
"parameters": true,
"environment": false,
"materials": false
},
"reproducible": false
},
"materials": [
{
"uri": "git+https://github.com/marcofranssen/slsa-workflow-examples",
"digest": {
"sha1": "01e93c44cd41e7f6025c815af1f5075a4fcbec8b"
}
}
]
}As with the SBOM, you can also fetch the provenance by digest. This does not require signature checks and slightly changes how you use jq for further processing.
We saw that fatt also adds attestations.txt to the cosign steps (upload and sign). fatt list is similar to sget when fetching the ….discovery tag. It downloads the blob, verifies the signature, and adds capabilities for more advanced command-line use cases, such as:
attestations.txt filesHere are some examples:
$ export COSIGN_EXPERIMENTAL=1
$ fatt list ghcr.io/marcofranssen/slsa-workflow-examples/attestations:awesome-node-cli-v0.1.5.discovery > attestations.txt
Fetching attestations from ghcr.io/marcofranssen/slsa-workflow-examples/attestations:awesome-node-cli-v0.1.5.discovery…
Verifying signature for ghcr.io/marcofranssen/slsa-workflow-examples/attestations@sha256:252783857d310d36a54086cd1e5035298c98c5db604edc7daa7ce4cdcc03deaf…$ export COSIGN_EXPERIMENTAL=1
$ fatt list -f '{ .IsAttestationType("provenance") }'
Fetching attestations from /Users/marco/code/slsa-workflow-examples/examples/awesome-npm-cli…
pkg:oci/marcofranssen/slsa-workflow-examples/attestations@sha256:cad11e9b6229631175321b6e35dfbf0124064ef82761e41800bc533ecc3e8f06?repository_url=ghcr.io%2Fmarcofranssen%2Fslsa-workflow-examples%2Fattestations&tag=awesome-node-cli-v0.1.5.provenance$ export COSIGN_EXPERIMENTAL=1
$ fatt list -o oci -f '{ .IsAttestationType("sbom") }'
Fetching attestations from /Users/marco/code/slsa-workflow-examples/examples/awesome-npm-cli…
ghcr.io/marcofranssen/slsa-workflow-examples/attestations@sha256:68f1d97c61e62228195aedfdfdce74b52123764c0c3b5f71d03b713bc63eb897This last example is especially useful for automatically fetching all SBOMs for projects on your local file system. All projects need an attestations.txt in their workspace and must share a root directory so we can scan that path recursively.
For example, if you use fatt or sget to download the attestations.txt files and store them on your local disk, you might end up with a folder structure like this.
$ tree code
code
├── node-cli
│ ├── attestations.txt
│ └── …
├── another-node-cli
│ ├── attestations.txt
│ └── …
└── super-cool-go-cli
├── attestations.txt
└── …
55 directories, 299 files
$ while IFS= read -r line ; do sget "${line}" | grep -v '^Certificate'; done \
<<< "$(fatt list -f '{ .IsAttestationType("sbom") }' -o oci code)" \
| jq --slurp 'map(.packages) | flatten | map({ name: .name, version: .versionInfo, license: .licenseConcluded }) | unique'
Fetching attestations from /Users/marco/code…
[
{
"name": "commander",
"version": "9.0.0",
"license": "NONE"
},
{
"name": "commander",
"version": "8.0.1",
"license": "NONE"
},
{
"name": "github.com/sigstore/cosign",
"version": "1.6.0",
"license": "NONE"
}
]For a complete, end-to-end example of a CI pipeline, have a look at the following workflow.
Loading https://raw.githubusercontent.com/marcofranssen/slsa-workflow-examples/v0.1.5/.github/workflows/release-npm.yaml…
In this workflow, we create a release of our software using npm pack. Then we use syft to generate an SBOM and slsa-provenance-action to generate provenance for our build. Last but not least, we use fatt to publish the sbom and provenance to an OCI registry.
The second job in the workflow shows some ways to consume the attestations. This gives you an idea of how you can use them in your own workflows. For example, you could check your npm dependencies and try to fetch their SBOMs based on a convention. If a dependency provides an SBOM, you can perform license checks in your CI pipeline.
Using crane, you can easily query the OCI registry to see how the attestations for your software assets are stored.
$ crane ls ghcr.io/marcofranssen/slsa-workflow-examples/attestations
v0.1.4-rc2.sbom
v0.1.4-rc2.provenance
v0.1.4-rc2.discovery
sha256-2303915bddc4a07184bbead2c57cc157eae79529c381c54c3c731a4d37ee8c6c.sig
sha256-9b42b04bad23bedb88b72ece1e69d2548c45d6bf18a92eba205dab975136bed2.sig
sha256-6b4c73905e7065f821aa10f26a6a96fead849c31b928ef51ecc079a7d2eebc8d.sig
awesome-node-cli-v0.1.4-rc3.sbom
awesome-node-cli-v0.1.4-rc3.provenance
awesome-node-cli-v0.1.4-rc3.discovery
sha256-f7bb6199092fa87d26b9a8195842eb87f7f907e80f95db07d21b73616e271aec.sig
sha256-49a0dfce851be9d88d3b73d525b2e9b950d546f1d7d7046050ed1f058a7cefb1.sig
sha256-c6184be9cf4c8d35aa26e4f1975f1fbd9b91d756a5ea2262b258293f369bb49c.sig
awesome-node-cli-v0.1.4.sbom
awesome-node-cli-v0.1.4.provenance
awesome-node-cli-v0.1.4.discovery
sha256-d3f5585432c887e626717dc04df80f97775a4ff4a5f721b62c0466a63b865c60.sig
sha256-84a13d69302341f15b8fb7e8b645b12309956546136fa218adc7225e4f6b5aaf.sig
sha256-1cb77a219aeb2165463660e6fd908dca27e72c1481ff79d5fe49feced2bd7bca.sig
awesome-node-cli-v0.1.5-rc.sbom
awesome-node-cli-v0.1.5-rc.provenance
awesome-node-cli-v0.1.5-rc.discovery
sha256-ad3b62e3793d6354292e63dba82b455decd5c6bcdf93b94f631ea6cba56aeff5.sig
sha256-394cf9cd05af02d2352e5f528a84a0bbb55a9424db6173b968402587b6c67a36.sig
sha256-26be1c1d7d8985ec8f770c9463bc8558c9abbed8b5d8632b2084dbcb063e9808.sig
awesome-node-cli-v0.1.5.sbom
awesome-node-cli-v0.1.5.provenance
awesome-node-cli-v0.1.5.discovery
sha256-252783857d310d36a54086cd1e5035298c98c5db604edc7daa7ce4cdcc03deaf.sig
sha256-cad11e9b6229631175321b6e35dfbf0124064ef82761e41800bc533ecc3e8f06.sig
sha256-68f1d97c61e62228195aedfdfdce74b52123764c0c3b5f71d03b713bc63eb897.sigAs you can see, we have a signature for each released tag. You can also see that we didn't use the fatt command-line option --tag-prefix in an earlier release (v0.1.4-rc2). This option lets you choose between two publishing strategies:
ghcr.io/marcofranssen/attestations-awesome-node-cli:v0.1.5.sbomghcr.io/marcofranssen/attestations-another-node-cli:v0.1.5.sbomghcr.io/marcofranssen/attestations:awesome-node-cli-v0.1.5.sbomghcr.io/marcofranssen/attestations:another-node-cli-v0.1.5.sbomIn this post, we stored attestations (SBOMs and build provenance) in an OCI registry. We also saw how to automate those steps a little further using fatt. Besides publishing, we looked at ways to consume the attestations. The examples were based on an npm package, but we can apply the same approach to other package ecosystems, such as Maven, NuGet, and Go modules. Take some time to explore the GitHub Actions workflow and incorporate this approach into your own projects.
What do you think about this approach and the proof of concept using fatt? Do you see other use cases or have suggestions for taking this idea further? Feel free to reach out in the fatt repository, or discuss it on Twitter, Reddit, or another social platform. I'm looking forward to your feedback.
name: Release NPM
on:
push:
tags:
- v**
env:
COSIGN_EXPERIMENTAL: 1
ATT_IMAGE: ghcr.io/marcofranssen/slsa-workflow-examples/attestations
PKG_NAME: awesome-node-cli
SIGSTORE_VERSION: v1.6.0
jobs:
npm-package:
runs-on: ubuntu-20.04
permissions:
contents: read
packages: write
id-token: write
steps:
- name: Checkout
uses: actions/checkout@v3.0.0
- name: Setup Node
uses: actions/setup-node@v3.0.0
with:
node-version: '16'
cache: 'yarn'
cache-dependency-path: examples/awesome-node-cli
registry-url: 'https://npm.pkg.github.com/'
scope: "@marcofranssen"
- name: Install cosign
uses: sigstore/cosign-installer@v2.1.0
with:
cosign-release: ${{ env.SIGSTORE_VERSION }}
- name: Install Syft
uses: anchore/sbom-action/download-syft@v0.7.0
- name: Install fatt
uses: philips-labs/fatt/installer-action@v0.3.1
with:
fatt-release: v0.3.1
env:
COSIGN_EXPERIMENTAL: 0
# This workflow assumes that package.json version was updated prior to tagging
# and aligned with the tag you are about to give.
- name: Publish npm package
working-directory: examples/awesome-node-cli
run: |
pkg_json=examples/awesome-node-cli/package.json
version_error='You need to update package.json version to be aligned with your tag (prior to tagging).'
yarn pack
yarn publish marcofranssen-awesome-node-cli-${GITHUB_REF_NAME}.tgz || \
(echo "::error file=${pkg_json},line=3,endLine=3,col=14,title=Version issue::${version_error}" ; exit 1)
env:
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Generate SBOM
working-directory: examples/awesome-node-cli
run: syft . -o spdx-json=sbom-spdx.json
- name: Generate provenance
uses: philips-labs/slsa-provenance-action@v0.7.2
with:
command: generate
subcommand: files
arguments: --artifact-path examples/awesome-node-cli/marcofranssen-awesome-node-cli-${GITHUB_REF_NAME}.tgz --output-path provenance.att
env:
COSIGN_EXPERIMENTAL: 0
- name: Login to ghcr.io
uses: docker/login-action@dd4fa0671be5250ee6f50aedf4cb05514abda2c7 #v1.14.1
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Upload attestations
run: |
fatt publish \
--repository "${ATT_IMAGE}" \
--tag-prefix "${PKG_NAME}" \
--version "${GITHUB_REF_NAME}" \
sbom://examples/awesome-node-cli/sbom-spdx.json \
provenance://provenance.att
- name: Sign attestations and discovery
run: |
cosign sign "${ATT_IMAGE}:${PKG_NAME}-${GITHUB_REF_NAME}.discovery"
cosign sign "${ATT_IMAGE}:${PKG_NAME}-${GITHUB_REF_NAME}.provenance"
cosign sign "${ATT_IMAGE}:${PKG_NAME}-${GITHUB_REF_NAME}.sbom"
test-attestation-fetching:
runs-on: ubuntu-20.04
needs: [npm-package]
steps:
- name: Install cosign
uses: sigstore/cosign-installer@v2.1.0
with:
cosign-release: ${{ env.SIGSTORE_VERSION }}
- name: Install sget
run: |
os="${RUNNER_OS,,}"
arch="${RUNNER_ARCH,,}"
[ "$arch" == "x64" ] && arch=amd64
curl -sSLo sget https://github.com/sigstore/cosign/releases/download/${SIGSTORE_VERSION}/sget-${os}-amd64
curl -sSLo sget.sig https://github.com/sigstore/cosign/releases/download/${SIGSTORE_VERSION}/sget-${os}-amd64.sig
curl -sSLo sigstore.pub https://github.com/sigstore/cosign/releases/download/${SIGSTORE_VERSION}/release-cosign.pub
cosign verify-blob --key sigstore.pub --signature sget.sig sget
mkdir -p /tmp/sigstore/bin
mv sget /tmp/sigstore/bin
chmod +x /tmp/sigstore/bin/sget
echo '/tmp/sigstore/bin' >> "${GITHUB_PATH}"
env:
COSIGN_EXPERIMENTAL: 0
- name: Install fatt
uses: philips-labs/fatt/installer-action@v0.3.1
with:
fatt-release: v0.3.1
env:
COSIGN_EXPERIMENTAL: 0
- name: Fetch discovery file
run: |
fatt list "${ATT_IMAGE}:${PKG_NAME}-${GITHUB_REF_NAME}.discovery" > attestations.txt
cat attestations.txt
- uses: actions/upload-artifact@v3.0.0
with:
name: package-attestations
path: attestations.txt
- name: Fetch provenance
run: |
# grep is a workaround to fix sget bug in v1.6.0, bug is resolved in next releases
sget "${ATT_IMAGE}:${PKG_NAME}-${GITHUB_REF_NAME}-provenance" | grep -v '^Certificate' | jq '.' > provenance.att
- uses: actions/upload-artifact@v3.0.0
with:
name: awesome-node-cli-sbom-via-sget
path: provenance.att
- name: Fetch SBOM
run: |
# grep is a workaround to fix sget bug in v1.6.0, bug is resolved in next releases
sget "${ATT_IMAGE}:${PKG_NAME}-${GITHUB_REF_NAME}.sbom" | grep -v '^Certificate' | jq '.' > sbom-spdx.json
- uses: actions/upload-artifact@v3.0.0
with:
name: awesome-node-cli-provenance-via-sget
path: sbom-spdx.json
- name: Example sbom traversal to get license info
run: |
echo Imagine you would have saved all 'attestations.txt' files in all your projects you can easily get all Licenses.
# grep is a workaround to fix sget bug in v1.6.0, bug is resolved in next releases
while IFS= read -r line ; do sget "${line}" | grep -v '^Certificate'; done \
<<< "$(fatt list -f '{ .IsAttestationType("sbom") }' -o oci)" \
| jq --slurp 'map(.packages) | flatten | map({ name: .name, version: .versionInfo, license: .licenseConcluded }) | unique'
- name: Notice
run: echo "::notice title=Attestations::See ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID} on how to fetch attestations."Marco Franssen
Explore spiffe-vault for secretless Vault authentication, using SPIFFE workload identities and Vault-managed signing keys to sign container images with Cosign.
Marco Franssen
Sign Docker images and attest SBOMs and build provenance with Sigstore in GitHub Actions, applying SLSA requirements to your release workflow.
Marco Franssen
Automatically choose work or personal Git commit email addresses with conditional includes in your global Git configuration and a folder-based setup.