Skip to main content

Attestation Process, advanced features

The basics of the attestation process is described in our getting started guide. This guide, instead will focus in some advance features guide

Project and Versions

During the attestation process, you can provide the name of the project the workflow belongs to and optionally a version.

For example, the following line will perform an attestation associated with the project myproject and no version 1.0.0 (pre-release).

$ chainloop att init --workflow mywf --project myproject

Optionally you can provide a version either explicitly with the --version flag or using a .chainloop.yml file (more on that below).

$ chainloop att init --workflow mywf --project myproject --version 1.0.0

┌───────────────────┬──────────────────────────────────────┐
│ Initialized At │ 05 Nov 24 14:36 UTC │
├───────────────────┼──────────────────────────────────────┤
│ Attestation ID │ 0c6c780c-7a95-4e18-9f94-b27c5ae7de6f │
│ Organization │ miguel │
│ Name │ mywf │
│ Project │ myproject │
│ Version │ 1.0.0 (prerelease)
│ Contract Revision │ 1
└───────────────────┴──────────────────────────────────────┘

As you might have noticed in the table above, the version is 1.0.0 (prerelease), this is because, by default, Chainloop considers all versions pre-release until they are explicitly promoted with the --release flag.

$ chainloop att init --workflow mywf --project myproject --version 1.0.0 --release

Once the attestation is successfully crafted and pushed, the version will be promoted to 1.0.0.

$ chainloop att push
$ chainloop wf run ls
┌──────────────────────────────────────┬─────────────────────────────────┬───────────────────────┬─────────────┬─────────────────────┬─────────────────┬────────┐
│ ID │ WORKFLOW │ VERSION │ PRERELEASE │ STATE │ CREATED AT │ RUNNER │
├──────────────────────────────────────┼─────────────────────────────────┼───────────────────────┼─────────────┼─────────────────────┼─────────────────┼────────┤
│ e293221a-5e28-4ffa-af02-0a07be908866 │ myproject/mywf │ 1.0.0 │ success │ 05 Nov 24 14:38 UTC │ Unspecified │ │

This gives you control on the lifecycle of your project versions, deciding when a version is ready to be promoted to production.

Automatically load the version

An alternative to provide the --version flag in each attestation is to use a .chainloop.yml file in your repo.

# your-project/.chainloop.yml
projectVersion: v0.1.0 # example version

The CLI, during attestation init will traverse up the directory tree and load the version from the .chainloop.yml file automatically if it exists.

Contract-less pieces of evidence

A Workflow Contract specifies the necessary content that a workflow must include in its attestation. For instance, it might mandate the inclusion of the URI@digest of the generated container image, the container root filesystem used during the build, and the Software Bill of Materials for that container image. These pieces of evidence must be associated with a specific material type. Operators define what must be included in the contracts, and developers need to understand and comply with these requirements.

This has been the case up until now, with the introduction of contract-less pieces of evidences and auto-discovery, we ease the job of operators and developers when working with attestations.

Not all pieces of evidences need to to be registered as a material on the contract, you can add as many pieces of evidences as you like by adding its value and a new flag --kind, which determines that type of material you’re attesting, example:

$ chainloop attestation init --workflow wf-test --project core
INF Attestation initialized! now you can check its status or add materials to it
┌───────────────────┬──────────────────────────────────────┐
│ Initialized At │ 21 May 24 07:23 UTC │
├───────────────────┼──────────────────────────────────────┤
│ Attestation ID │ 6e9d2e76-fdc0-4493-a344-4cf44a2b7bf2 │
│ Name │ wf-test │
│ Team │ founding │
│ Project │ core │
│ Contract Revision │ 3
└───────────────────┴──────────────────────────────────────┘
┌────────────────────────┐
│ Materials │
├───────────┬────────────┤
│ Name │ one-file │
│ Type │ ARTIFACT │
│ Set │ No │
│ Required │ Yes │
│ Is output │ Yes │
├───────────┼────────────┤
│ Name │ other-file │
│ Type │ EVIDENCE │
│ Set │ No │
│ Required │ Yes │
│ Is output │ Yes │
└───────────┴────────────┘

There are two expected materials of kind ARTIFACT and EVIDENCE. With the changes we can perform the following:

$ chainloop attestation add --value controlplane.cyclonedx.json  --kind SBOM_CYCLONEDX_JSON
INF material added to attestation

We are explicitly saying which is the kind (SBOM_CYCLONEDX_JSON) we want to apply to material that is not found on the contract. After fulfilling the required materials, the ones stated on the contract, we can perform the attestation as usual:

$ chainloop attestation push
INF push completed
┌───────────────────┬──────────────────────────────────────┐
│ Initialized At │ 21 May 24 06:37 UTC │
├───────────────────┼──────────────────────────────────────┤
│ Attestation ID │ 57b8dc22-d84d-40c3-a04c-8948231b3134 │
│ Name │ wf-test │
│ Team │ founding │
│ Project │ core │
│ Contract Revision │ 3
└───────────────────┴──────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────────────┐
│ Materials │
├───────────┬─────────────────────────────────────────────────────────────────────────┤
│ Name │ one-file │
│ Type │ ARTIFACT │
│ Set │ Yes │
│ Required │ Yes │
│ Is output │ Yes │
│ Value │ go.mod │
│ Digest │ sha256:29773f085c46a33efcb6cdb185f6ec30ce1c4ca708b860708cd055b70488ef4d │
├───────────┼─────────────────────────────────────────────────────────────────────────┤
│ Name │ other-file │
│ Type │ EVIDENCE │
│ Set │ Yes │
│ Required │ Yes │
│ Is output │ Yes │
│ Value │ LICENSE.md │
│ Digest │ sha256:c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4 │
├───────────┼─────────────────────────────────────────────────────────────────────────┤
│ Name │ material-1716273574284654000 │
│ Type │ SBOM_CYCLONEDX_JSON │
│ Set │ Yes │
│ Required │ No │
│ Is output │ Yes │
│ Value │ controlplane.cyclonedx.json │
│ Digest │ sha256:a6bc29d7a2d8d9f6df12a86ee4c86c58189d77bb6ded9487330c39f46ee00d9a │
└───────────┴─────────────────────────────────────────────────────────────────────────┘
Attestation Digest: sha256:61832d846b870d01647a384c3df49e3c75fd87f45821c9295d97ab91d5bae198

Auto-discovery of pieces of evidence

In top of contract-less pieces of evidences, we have introduced auto-discovery. Auto-discovery it’s a way of inspecting the incoming piece of evidence and try to match it with at least of of the available type of materials of Chainloop. Please note this is a best effort and the prediction might fail and matching it with the wrong type of material, defaulting in ARTIFACT.

In order to let the auto-discovery work, don’t set --name nor --kind, let the CLI work it our for you.

Example of usage. Given the following contract:

$ chainloop attestation init --workflow wf-test --project core
INF Attestation initialized! now you can check its status or add materials to it
┌───────────────────┬──────────────────────────────────────┐
│ Initialized At │ 22 May 24 13:38 UTC │
├───────────────────┼──────────────────────────────────────┤
│ Attestation ID │ 583553ef-d051-4c41-aec4-a4cdd725bf89 │
│ Name │ wf-test │
│ Team │ founding │
│ Project │ core │
│ Contract Revision │ 3
└───────────────────┴──────────────────────────────────────┘
┌────────────────────────┐
│ Materials │
├───────────┬────────────┤
│ Name │ one-file │
│ Type │ ARTIFACT │
│ Set │ No │
│ Required │ Yes │
│ Is output │ Yes │
├───────────┼────────────┤
│ Name │ other-file │
│ Type │ EVIDENCE │
│ Set │ No │
│ Required │ Yes │
│ Is output │ Yes │
└───────────┴────────────┘

Let's add the required materials:

$ chainloop attestation add --value go.mod --name one-file
INF material added to attestation

$ chainloop attestation add --value LICENSE.md --name other-file
INF material added to attestation

And finally let's try to discover one material without specifying its type:

$ chainloop attestation add --value controlplane.cyclonedx.json
INF material kind detected kind=SBOM_CYCLONEDX_JSON
INF material added to attestation

As a result we can see how it's added to the result:

$ chainloop attestation push
INF push completed
┌───────────────────┬──────────────────────────────────────┐
│ Initialized At │ 22 May 24 13:38 UTC │
├───────────────────┼──────────────────────────────────────┤
│ Attestation ID │ 583553ef-d051-4c41-aec4-a4cdd725bf89 │
│ Name │ wf-test │
│ Team │ founding │
│ Project │ core │
│ Contract Revision │ 3
└───────────────────┴──────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────────────┐
│ Materials │
├───────────┬─────────────────────────────────────────────────────────────────────────┤
│ Name │ one-file │
│ Type │ ARTIFACT │
│ Set │ Yes │
│ Required │ Yes │
│ Is output │ Yes │
│ Value │ go.mod │
│ Digest │ sha256:29773f085c46a33efcb6cdb185f6ec30ce1c4ca708b860708cd055b70488ef4d │
├───────────┼─────────────────────────────────────────────────────────────────────────┤
│ Name │ other-file │
│ Type │ EVIDENCE │
│ Set │ Yes │
│ Required │ Yes │
│ Is output │ Yes │
│ Value │ LICENSE.md │
│ Digest │ sha256:c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4 │
├───────────┼─────────────────────────────────────────────────────────────────────────┤
│ Name │ material-1716385111238449000 │
│ Type │ SBOM_CYCLONEDX_JSON │
│ Set │ Yes │
│ Required │ No │
│ Value │ controlplane.cyclonedx.json │
│ Digest │ sha256:a6bc29d7a2d8d9f6df12a86ee4c86c58189d77bb6ded9487330c39f46ee00d9a │
└───────────┴─────────────────────────────────────────────────────────────────────────┘
Attestation Digest: sha256:8a0b3a9db0372fdf571dbe85c8a9b5202f473ca97e9dbcdf77c3f9b423ea3b9c

Contract-less and auto-discovery and two features that walk hand by hand. They compose a new way of adding pieces of evidences to an existing contract in a frictionless way. You can see it in action in our quickstart guide.

Remote State

By default, the attestation process state is stored locally. But this setup is not suitable when running a multi-step attestation process in a stateless environment, like our Dagger module, or when you want to leverage CI multi-job parallelism or similar.

For that, we implemented attestation remote state. Simply put, instead of the attestation CLI being in charge of maintaining the state during the attestation, this can be delegated to the server and retrieved at any time by providing an “attestation-id.”

# You can enable the feature by providing the --remote-state flag
# and it will return an attestation-id
$ chainloop attestation init --name my-workflow --project my-project --remote-state

# Then you can add any piece of evidence by providing the attestation-id
$ chainloop attestation add --value cyberdyne.cyclonedx.sbom --attestation-id deadbeef

# And finally craft the attestation, sign-it and push it
$ chainloop attestation push --attestation-id deadbeef

With this optional feature, as long as you have the attestation-id, you can add any piece of evidence to the attestation from anywhere.