Standards guidance
A ceiling is the highest level this evidence could support. It is not a verified level: a SLSA Build level needs an assessment of the build platform, and an ALPS level needs an independent verifier.
cilock run and cilock verify print a standards block and, under --json / --format json, a typed standards object (schema cilock.standards-guidance/v1) with slsa_build.ceiling, alps.ceiling, verified_level: null and an ordered next_steps[]. When a coding agent drives cilock, the steps are phrased as imperative actions for the agent.
SLSA Build
Specification: SLSA v1.2 Build track
| Level | Status | Requires | How cilock observes it |
|---|---|---|---|
| L1 | available | Provenance exists for the build. | The run selected the slsa attestor (-a slsa) and signed the collection. |
| L2 | available | Provenance is generated and signed by a hosted build platform and timestamped. | The signing leaf is a keyless CI workload identity (GitHub Actions, gitlab.com, Buildkite, CircleCI or a Kubernetes service account, recognized by its OIDC issuer) and its runner-environment names a provider-hosted runner, and the envelope carries an RFC 3161 timestamp. On a self-hosted runner, CircleCI or Kubernetes the level depends on whether you treat your runner operator as the build platform (formal/slsa-tracks interpretation I2), so cilock reports those as not provider-hosted. |
| L3 | planned | Provenance is unforgeable by the tenant's build steps: it is signed under a builder identity no build step can obtain, on an isolated, ephemeral runner. | The signing leaf's Build Signer URI names the isolated provenance workflow (builder_identity on the slsa-provenance-workflow step), not the tenant workflow. GitHub Actions only: other CI signer identities are pipeline-wide. |
Not reachable on some CI platforms
- L3 on gitlab, buildkite, circleci, kubernetes: not reachable on this CI today: its signer identity is pipeline-wide, so a build step can mint it. The only paths are the GitHub Actions provenance workflow (coming) and cilockd on a runner you operate (not yet available).
Next steps
slsa-provenance-attestor (to L1, available)
SLSA Build L1 needs provenance, and this run produced none.
Action: Add the slsa attestor to the cilock run invocation.
cilock run --step build -a slsa -- <your build command>slsa-hosted-runner (to L2, available)
SLSA Build L2 needs a hosted build platform. A laptop is never one. On a self-hosted runner, CircleCI or Kubernetes it depends on whether you treat your runner operator as the build platform; a provider-hosted runner (GitHub-hosted, gitlab.com SaaS, Buildkite hosted) removes that question.
Action: Run the build on a provider-hosted runner (GitHub-hosted, gitlab.com SaaS, or Buildkite hosted), or decide that your runner operator counts as the build platform and record why.
jobs:
build:
runs-on: ubuntu-latestslsa-workflow-identity (to L2, available)
SLSA Build L2 needs provenance signed by the platform's workload identity, not a key or a person's session.
Action: Sign keyless with your CI's workload OIDC identity. GitHub Actions works with the platform Fulcio or public Sigstore (grant id-token: write and use cilock-action). gitlab.com, Buildkite hosted and CircleCI cloud work with the platform Fulcio from the CI/lock release after 4.5.0, which fetches their job token itself (on gitlab.com declare an id_tokens entry with audience sigstore); with CI/lock 4.5.0 or earlier, and on Kubernetes, sign through public Sigstore Fulcio.
permissions:
id-token: write
contents: read
steps:
- uses: aflock-ai/[email protected] # pin to a 40-character commit SHA
with:
step: build
command: "<your build command>"
attestations: environment git github slsaDocs: https://cilock.dev/getting-started/quickstart-ci
slsa-hosted-runner-gitlab (to L2, available)
SLSA Build L2 needs a hosted build platform. On gitlab.com that is a GitLab-hosted runner. A self-managed GitLab has no provider-hosted runner, so it depends on whether you treat your runner operator as the build platform.
Action: On gitlab.com, run the job on a GitLab-hosted runner. On a self-managed GitLab, decide whether your runner operator counts as the build platform and record why.
build:
tags: [saas-linux-small-amd64]slsa-workflow-identity-gitlab (to L2, available)
SLSA Build L2 needs provenance signed by the platform's workload identity, not a key or a person's session.
Action: Sign keyless with the GitLab job's own ID token: declare an id_tokens entry with audience sigstore and run cilock with no signing key. This works on gitlab.com and on a self-managed GitLab whose issuer the platform Fulcio trusts.
build:
id_tokens:
SIGSTORE_ID_TOKEN:
aud: sigstore
script:
- cilock run --step build -a slsa -- <your build command>Docs: https://cilock.dev/tutorials/gitlab-ci-pipeline
slsa-timestamp (to L2, available)
The envelope carries no trusted timestamp, so a short-lived keyless leaf cannot be verified later.
Action: Sign with a timestamp authority.
cilock run --step build -a slsa --timestamp-servers <tsa-url> -- <your build command>slsa-provenance-workflow (to L3, planned)
Inline provenance is signed by the same workflow identity the build steps can mint, so a build step can forge it (issue #9822). L3 needs a separate builder identity, which only GitHub Actions' reusable-workflow identity provides.
Action: Coming: the isolated cilock provenance workflow. When it ships, add a provenance job that needs the build job and signs the build's subjects under its own identity.
Not yet published. Run and verify output withhold this snippet until it ships:
provenance:
needs: build
permissions:
id-token: write
uses: aflock-ai/cilock-action/.github/workflows/provenance.yml@{{pin}}
with:
subjects: ${{ needs.build.outputs.subjects }}ALPS
Specification: ALPS 0.1
| Level | Status | Requires | How cilock observes it |
|---|---|---|---|
| ALPS-0 | available | The statement is signed and bound to the commit. | The run signed the collection. |
| ALPS-1 | available | The signing leaf chains to the platform root and names a non-human agent or workload principal, and the envelope is timestamped. | Not reported by cilock yet. A leaf that names an agent or a CI workflow does not show the platform issued it (the same name appears under public Sigstore or a BYO CA), and authenticating the platform root is a separate design, so run and verify report ALPS-0 at most. A verifier policy that pins the platform root can still require it. |
| ALPS-2 | planned | The run happened inside an enforced sandbox, and a non-agent observer signed the boundary it ran in. | Nothing yet: the alps-evidence predicate has no boundary field. See docs/design/alps-2-boundary-attestation.md. |
| ALPS-3 | future | requires cilockd (not yet available) | Nothing yet. |
Next steps
alps-agent-identity (to ALPS-1, available)
ALPS 1 needs a non-human principal the platform issued. This run signed with a local key or a human session, so the evidence cannot say an agent signed it.
Action: Enroll an agent identity for this machine and approve it in the browser.
cilock enroll agentalps-workflow-identity (to ALPS-1, available)
ALPS 1 needs a non-human principal the platform issued. In CI that is the job's workload OIDC identity, which this job did not sign with.
Action: Sign with the job's workload identity against the platform Fulcio. On GitHub Actions grant the job id-token: write. On gitlab.com, Buildkite or CircleCI use a CI/lock newer than 4.5.0, which fetches the job token itself (on gitlab.com declare an id_tokens entry with audience sigstore). Other CI has no platform-issued identity yet.
alps-workflow-identity-gitlab (to ALPS-1, available)
ALPS 1 needs a non-human principal the platform issued. In GitLab CI that is the job's own ID token, which this job did not sign with.
Action: Declare an id_tokens entry with audience sigstore and sign keyless against the platform Fulcio (no signing key). This works on gitlab.com and on a self-managed GitLab whose issuer the platform Fulcio trusts.
alps-timestamp (to ALPS-1, available)
The envelope carries no trusted timestamp, so a short-lived identity cannot be verified later.
Action: Sign with a timestamp authority.
cilock run --step <step> --timestamp-servers <tsa-url> -- <command>alps-boundary-attestation (to ALPS-2, planned)
ALPS 2 needs an enforced sandbox and a non-agent observer that signs the boundary. cilock records no boundary today, so no run can present ALPS 2 evidence yet.
Action: Coming: boundary attestation in alps-evidence. Until it ships, run the agent inside the recommended sandbox so the run already has the boundary the attestation will record.
Reference generated from the product documentation. Match commands and support details to your installed release.