OCI as attestations storage for your packages
Marco Franssen

Loading...
Marco Franssen

In my previous blog you can read about securing the software supply chain for Docker images using GitHub actions and Sigstore. We have seen how we can sign our Docker images, as well how to generate an SBOM and build provenance. Using Sigstore/cosign we attached both the signature, SBOM and build provenance to the Docker image. Using Sigstore we get a real nice integration and developer experience to add these security features to our build pipelines for Docker images.
In this blog I want to show an approach to store SBOMs and Provenance in an OCI registry for other software release assets (e.g. npm, maven, nuget, …). To do so we will also utilize cosign to interact with the registry. The developer experience will not be that nice and integrated as we have with Docker images, but at least this can be an approach to move into a more ideal situation untill there is some more integrated solution with package managers.
Using OCI as a blob storage we can leverage this to distribute and discover attestations for software assets that are not OCI/Docker images. The idea is to come up with some naming convention that can relate for example our npm package to a Blob in the OCI registry. Using this convention we can document and make it transparent for consumers of your assets where they can find the SBOM as well the 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 this SBOM and provenance generated we can use an OCI registry to distribute and store the SBOM and provenance. See in the next part an example on 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 any other package we can do similar by applying the same tagging convention («oci-registry»:«pkg-name»-«version».«attestation-type») like we applied in previous example.
With these attestations stored in the OCI registry, consumers of our assets can now easily download the attestations and verify its signature that guarantees its authenticity. We can do this using sget. Once downloaded we can write it to a file or pipe it to other shell tools to inspect/transform and use it for our usecases. More on consuming the stored attesations later in this blog, first lets have a look at a tool called fatt, which is a proof of concept (POC) to make the process of publishing and discoverability easier, by automating above steps.
To automate the steps of uploading and signing the SBOMs and provenance further we build fatt as a POC. (⚠️ NOTE the signing is not yet implemented in fatt and still a manual step, see fatt#20).
Fatt requires a few command line arguments to apply the convention we did manually using cosign. To identify the attestation type fatt requires to define a URL Scheme format in front of the attestations that will 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 as described earlier in this blog with the manual cosign steps. We also added an additional blob, attestations.txt, that we store in the OCI registry. In this attestations.txt, fatt stores the location of SBOM and provenane in purl format. Purls are commonly used in SBOMs to link to other resources. This attestations.txt is used by fatt filter capabilities to allow some advanced consumption usecases.
$ 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 our attestations published, either via cosign or using fatt as a convenience. As we used a convention it should be more recognizable for consumers of your packages where to find the attestations. This enables consumers to automate the consumption of the attestations. E.g.:
We can utilize 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 signature of this artifact to proof the authenticity.
COSIGN_EXPERIMENTAL=1 sget ghcr.io/marcofranssen/slsa-workflow-examples/attestations:awesome-node-cli-v0.1.5.discoveryIn my case I used the ephemeral keys from sigstore (COSIGN_EXPERIMENTAL=1). If you used selfsigned keys you will have to use the --key flag to provide your public key.
Fetching by tag requires signature verification. In this case you will receive 2 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"
}
]In case you fetch the asset by digest you can omit the signature verification. However the digest is less userfriendly to remember and type. Small advantage is you will not receive the signature in the output of the command.
$ 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"
}
]See here an example of getting 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"
}
}
]
}Similarly like the SBOM you could also fetch the provenance by digest, which does not require signature checks and slightly changes how you apply jq in further processing.
We have seen fatt was also adding the attestations.txt as an addition to the cosign steps (upload and sign). fatt list is similar to sget when it comes to fetching the ….discovery tag. It will download the blob, verify the signature and adds some additional capabilities to make more advanced commandline usecases possible. e.g.:
attestations.txt filesSee here 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:68f1d97c61e62228195aedfdfdce74b52123764c0c3b5f71d03b713bc63eb897Specifically this last example is usefull to further automate things to automatically fetch all SBOMs for projects on your local file system (all projects do need to have an attestations.txt in their workspace and have to share the same root path to allow scanning this filepath recursively).
e.g. if you would use fatt or sget to download the attestations.txt and store them on your local disc you might end up with a folder structure like this example.
$ 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"
}
]To see a full end to end example of a CI pipeline you can see following workflow.
Loading https://raw.githubusercontent.com/marcofranssen/slsa-workflow-examples/v0.1.5/.github/workflows/release-npm.yaml…
In this workflow we make a release for our software using npm pack. Then we utilize syft to generate an SBOM and we use the slsa-provenance-action to generate the provenance for our build. Last but not least we utilize fatt to publish the sbom and provenance to an OCI registry.
The second job in the workflow showcases some ways to consume the attestations. This gives you an impression on the possibilities of using these attestations in your workflows. E.g. you could check your dependencies in npm, try to fetch the SBOMs based on a convention, and if the SBOM is provided by the dependency you can perform some license checks in your CI pipeline.
Using crane you can easily query the OCI registry to see how the attestations are stored for your software assets.
$ 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 here, we have a signature for each released tag. You can also see that we didn't use the fatt commandline option --tag-prefix in an earlier release (v0.1.4-rc2). This commandline option allows you to choose between 2 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 blog we have stored attestations (SBOM, build provenance) in an OCI registry. We also have seen how we could automate those steps a little further using fatt. Aside from the publishing part we also looked at the consumption usecases. The examples where based on an NPM package, however we can apply the same for other package managers like Maven, Nuget, Go modules etc. Also take some time to explore the GitHub actions workflow to incorporate this in your own projects.
What do you think about this approach and the proof of concept using fatt? Do you see any other usecases to be applied or do you have any suggestions on taking this idea next-level? Feel free to reach out at the fatt repository, discuss at Twitter, Reddit or any other Social platform. Looking forward to your feedback.
Marco Franssen
Securing the software supply chain has been a hot topic these days. Many projects have emerged with the focus on bringing additional security to the software supply chain as well adding zero-trust capabilities to the infrastructure you are running the software on. In this blogpost I want to introduce you to a small commandline utility (spiffe-vault) that enables a whole bunch of usecases like: Secretless deployments Keyless codesigning Keyless encryption Spiffe-vault utilizes two projects t…
Marco Franssen
With the rise of software supply chain attacks it becomes more important to secure our software supply chains. Many others have been writing about software supply chain attacks already, so I won't repeat that over here in this article. Assuming you found my article, because you want to know how to prevent them. In this blogpost I want to show you how to secure the software supply chain by applying some SLSA requirements in the GitHub actions workflow. We will utilize Sigstore to sign and attest…
Marco Franssen
Have you ever been struggling to commit with the right email address on different repositories? It happened to me many times in the past, but for a couple of years I'm now using an approach that prevents me from making that mistake. E.g. when working on your work related machine, I'm pretty often also working on Opensource in my spare time, to build my own skills, and simply because I believe in the cause of Opensource. Also during work time I'm also sometimes contributing fixes back to Opensour…
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."