Skip to main content
Diagram of a contract acting as the interface between CI/CD pipelines and compliance teams
A Chainloop contract becomes the interface between the developers who must instrument their CI/CD pipelines and Security and Compliance teams. A Workflow Contract defines the expectations of what content a workflow must send as part of their attestation. For example, a contract could explicitly state that the URI@digest of the generated container image, the container rootfs used during build, and the Software Bill of Materials of that container image must be present in the attestation. There are two additional properties of Workflow Contracts that aim to ease the management of workflows in your organization
  • A Workflow Contract is immutable and versioned, new revisions of the contract with new/different requirements can be added over time. This is especially useful for iterative integrations.
  • A Workflow Contract can belong to more than one Workflow. This means that a change in a single contract will be propagated to many workflows. This is especially useful for org-wide standardization and fleet management.
Example: three CI/CD pipelines associated with their respective Chainloop workflows. Two of those Workflows are sharing the same Contract (using the same or different revision).
Diagram of three workflows where two share the same contract

Managing Contracts

Contracts can be managed through the “Contracts” section in Chainloop platform:
The contracts list in the Chainloop UI showing scope and latest revision per contract
Contracts can also be managed declaratively as YAML files. See the Declarative Resource Management guide.
There is always a default, empty contract to speed up organization onboarding. A new contract can be added by clicking the “Create Contract” button, which opens a form where you can specify its scope and specification:
The Create Contract form with scope selector and YAML editor
A Workflow Contract can be provided in json or yaml (cue format is also supported through the Chainloop CLI).
When creating or updating a contract from a file, the CLI resolves the contract name from either the --name flag or the metadata.name field in the file. Provide at least one of them. You can also provide both as long as they have the same value — the command fails if they differ.

Contract Management Scope

Contracts in Chainloop operate at two different scopes with corresponding management permissions:
  • Organization-scope contracts: Managed by users with Organization Admin or Organization Owner roles. These contracts can be used across all projects within the organization.
  • Project-scope contracts: Managed by Project Admins. These contracts are specific to individual projects and can only be used within their respective project scope.

Restricting Contract Creation

Organizations can optionally enable the “Restrict Contract Creation to Organization Admins” setting to enforce stricter governance over contract management. When this setting is enabled:
  • Only users with Organization Admin or Organization Owner roles can create new contracts (regardless of the contract scope)
  • Project Admins that are not Organization Admins can no longer create their own contracts
  • Workflows created by non administrators must use existing contracts
This restriction helps organizations maintain tighter control over contract definitions and ensures consistency across projects by centralizing contract governance.

Enabling the setting

Organization owner and admins can enable this setting in the organization settings.
The Restrict Contract Creation to Organization Admins setting in the organization settings
or using the CLI:
For detailed information about roles and permissions, see our RBAC documentation.

Associating workflows to contracts

Once contracts are created, they can be attached to as many workflows as needed. Remember that workflows represent a unique source of data ingestion (attestations), usually representing a CI/CD pipeline.
In the workflows view, open the workflow’s actions menu, click “Edit” and associate the contract. Once the contract is associated, new attestations will automatically download and apply it, including required materials, policies, and so on.
The Update Workflow form where a contract is associated with the workflow

Writing contracts

Example

See below a contract schema example:
Note that the contract below is just an example crafted for educational purposes. In a real scenario, the contract will not contain such a disparate amount of materials or annotations.
Once they are created, contracts can be edited. Every change will be stored as a new version of the contract. Chainloop CLI will automatically retrieve the latest version of the contract when a new attestation is performed. The contract summary view will provide details about the contract, including a revision selector to inspect previous versions:
The contract detail view with revision selector, YAML source, and associated workflows tab

Schema

Materials

The contract can require one or more pieces of evidence (a.k.a material) to be attached during the attestation process.

”At Least One Of” Material Groups

Sometimes a contract should accept any one of several alternatives rather than a specific material. Assign those materials to the same group and Chainloop treats them as an “at least one of” set: the attestation is satisfied as long as at least one member of the group is present. For example, to accept either a CycloneDX or an SPDX SBOM:
A few things to keep in mind:
  • Materials in a group are not individually required — the requirement is enforced at the group level. Providing any single member satisfies the whole group.
  • Materials without a group keep their individual optional/required behavior.
  • Group names must follow DNS-1123 label rules: lowercase letters, numbers, and hyphens (e.g. sbom, sast-report).
Running chainloop attestation status surfaces each group’s rule and whether it has been satisfied yet, so you can see at a glance which alternatives are still outstanding.

Policy attachments

When defining a contract, a new policies section can be specified. Policies can be applied to any material, but also to the attestation statement as a whole.
Read the docs for full details on policies.

Runner Context

New runner contexts will be added over time. If yours is not implemented yet, please contact us
An optional runner type can be provided in a workflow contract.
skynet.contract.yaml showLineNumbers
It has the following effect on the attestation process.
  • Require the attestation process to be executed in the target runner type unless the --dry-run flag is set during initialization.
  • A link to the workload (i.e Github Action Run link) will be recorded both in the attestation and in the control plane during initialization.
  • An additional set of environment variables will be resolved in addition to the ones defined in the contract envAllowList.
Currently, we support the following runner types

AZURE_PIPELINE

The following environment variables will be automatically added to the attestation. For more information on what they mean, refer to this link.
  • BUILD_REQUESTEDFOREMAIL
  • BUILD_REQUESTEDFOR
  • BUILD_REPOSITORY_URI
  • BUILD_REPOSITORY_NAME
  • BUILD_BUILDID
  • BUILD_BUILDNUMBER
  • BUILD_BUILDURI
  • BUILD_REASON
  • AGENT_VERSION
  • TF_BUILD
A link to the Azure Pipeline build will be recorded in the control plane too during initialization.

CIRCLECI_BUILD

The following environment variables will be automatically added to the attestation. For more information on their meaning, refer to the official CircleCI documentation.
  • CIRCLE_BUILD_URL
  • CIRCLE_JOB
  • CIRCLE_BRANCH (optional)
  • CIRCLE_NODE_TOTAL
  • CIRCLE_NODE_INDEX
A link to the CircleCI build will be recorded in the control plane too, during initialization.

DAGGER_PIPELINE

To use Chainloop With Dagger you can use this Dagger module Commit Signature Verification: Dagger pipelines can run in various CI environments. Chainloop automatically detects the underlying platform (GitHub Actions or GitLab CI) and verifies commit signatures through the appropriate API when GITHUB_TOKEN or CI_JOB_TOKEN is available. The verification status and signature algorithm are recorded in the attestation annotations.

GITHUB_ACTION

The following environment variables will be automatically added to the attestation. For more information on what they do refer to this link.
  • GITHUB_ACTOR
  • GITHUB_REF
  • GITHUB_REPOSITORY
  • GITHUB_REPOSITORY_OWNER
  • GITHUB_RUN_ID
  • GITHUB_SHA
  • RUNNER_NAME
  • RUNNER_OS
A link to the Github Action will be recorded in the control plane too during initialization. Commit Signature Verification: When GITHUB_TOKEN is available, Chainloop automatically verifies commit signatures through GitHub’s API and records the verification status (verified, unverified, unavailable, not_applicable) and signature algorithm (e.g., PGP, SSH, X509) in the attestation annotations. This provides auditable evidence that commits are cryptographically signed and verified by GitHub. The default GITHUB_TOKEN provided by GitHub Actions has sufficient permissions to query commit verification status. No additional configuration is required - the token is automatically available in the workflow environment.
To check the interpretation of the verification status, refer to GitHub’s official documentation.

GITLAB_PIPELINE

The following environment variables will be automatically added to the attestation. More information about what they mean in GitLab’s official documentation
  • GITLAB_USER_EMAIL
  • GITLAB_USER_LOGIN
  • CI_PROJECT_URL
  • CI_COMMIT_SHA
  • CI_JOB_URL
  • CI_PIPELINE_URL
  • CI_RUNNER_VERSION
  • CI_RUNNER_DESCRIPTION
  • CI_COMMIT_REF_NAME
A link to the GitLab CI job will be recorded in the control plane too, during initialization. Commit Signature Verification: When CI_JOB_TOKEN is available, Chainloop automatically verifies commit signatures through GitLab’s API and records the verification status (verified, unverified, unavailable, not_applicable) and signature algorithm (e.g., PGP, SSH, X509) in the attestation annotations. This provides auditable evidence that commits are cryptographically signed and verified by GitLab. The CI_JOB_TOKEN is automatically available in GitLab CI pipelines and has the necessary permissions to query commit signature information.
To check the interpretation of the verification status, refer to GitLab’s official documentation.

JENKINS_JOB

The following environment variables will be automatically added to the attestation. For more information on how to use Jenkins environment variables, refer to the official Jenkins documentation.
  • JOB_NAME
  • BUILD_URL
  • GIT_BRANCH (optional)
  • GIT_COMMIT (optional)
  • AGENT_WORKDIR
  • NODE_NAME
A link to the build will be recorded in the control plane too, during initialization.

TEAMCITY_PIPELINE

The following environment variables will be automatically added to the attestation. For more information on TeamCity environment variables, refer to the official TeamCity documentation.
  • BUILD_URL
  • TEAMCITY_PROJECT_NAME
  • TEAMCITY_VERSION
  • BUILD_NUMBER
  • USER
  • TEAMCITY_GIT_VERSION
  • BUILD_VCS_NUMBER
  • HOME
A link to the TeamCity build will be recorded in the control plane too, during initialization.
Remember, if all the env variables that you need are not defined in the context, you can extend such list via the envAllowList option.

TEKTON_PIPELINE

The following variables are automatically discovered and added to the attestation. No environment variable wiring is needed in your Pipeline YAML — the runner discovers everything from Kubernetes pod labels and the ServiceAccount namespace file. A run link will be recorded in the control plane during initialization, using the format tekton://<namespace>/pipelineruns/<name>. If the TEKTON_DASHBOARD_URL environment variable is set, a Tekton Dashboard URL will be used instead.
RBAC requirement: The TaskRun ServiceAccount needs get permission on pods in its namespace for pod label discovery. If the permission is missing, the runner degrades gracefully and captures only the variables available without it.

Skip storing runner-discovered environment variables

As shown above, each runner automatically discovers a set of environment variables and stores them in the attestation as build metadata. If your organization prefers not to persist these auto-discovered variables, an organization owner or admin can opt out with the skip_runner_env_vars organization setting. When this setting is enabled, the environment variables that the runner injects automatically (the per-runner lists above) are no longer collected into the attestation. The following are not affected:
  • The contract’s envAllowList — these are an explicit, user-defined opt-in and are always resolved and injected.
  • Runner detection — Chainloop still detects the runner type and enforces the contract’s runner constraint.
  • The structured runner metadata, such as the recorded run link, which is unaffected.
This setting is disabled by default (false), preserving the current behavior. It applies to the whole organization, and only organization owners and admins can change it.
Navigate to the organization settings and enable the Skip Runner-Discovered Environment Variables toggle.
Skip Runner-Discovered Environment Variables toggle in organization settings

Gather Additional Runner Configuration

The Chainloop CLI Enterprise Edition provides a runner context that can be used to gather the runner context. When Chainloop CLI Enterprise Edition is used it enables automatic retrieval of the following data:
  • Branch protection rules
  • Pull request requirements
  • Commit policies
This information is retrieved directly from your CI/CD system settings without you having to manually enter anything. The gathered security information becomes part of your attestation, which helps:
  • Verifying that proper protections were in place during the build process
  • Understanding what security measures are protecting the code
  • Proving that security policies were followed during development
Essentially, Chainloop creates an automatic security audit trail that shows your code was properly protected throughout the development process.