# Standards guidance

Source: https://www.testifysec.com/docs/cilock/reference/standards-guidance

How cilock reports an observed SLSA Build and ALPS ceiling for every run and verify, never a verified level, and the next steps that raise it.

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](https://slsa.dev/spec/v1.2/levels)

 

| 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.

 

```bash
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.

 

```yaml
jobs:
  build:
    runs-on: ubuntu-latest
```

 

#### `slsa-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.

 

```yaml
permissions:
  id-token: write
  contents: read
steps:
  - uses: aflock-ai/cilock-action@v1.0.4   # pin to a 40-character commit SHA
    with:
      step: build
      command: "<your build command>"
      attestations: environment git github slsa
```

 

Docs: [https://cilock.dev/getting-started/quickstart-ci](https://www.testifysec.com/docs/cilock/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.

 

```yaml
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.

 

```yaml
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](https://www.testifysec.com/docs/cilock/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.

 

```bash
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:

 

```yaml
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](https://www.testifysec.com/docs/pushgate/agent-sandbox)

 

| 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.

 

```bash
cilock enroll agent
```

 

#### `alps-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.

 

```bash
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.

 

Docs: [https://pushgate.dev/docs/agent-sandbox](https://www.testifysec.com/docs/pushgate/agent-sandbox)

Reference generated from the product documentation. Match commands and support details to your installed release.
