cilock CLI reference
Source of truth:
rookery/cilock/cmd/cilock/main.goandrookery/cilock/cli/. Defaults and flag names below track the releasedcilockand are completeness-gated against the binary in CI (scripts/check-cli-coverage.mjs) — every command has a section here.
cilock - Collect and verify attestations about your build environments
CI/lock attestation types use the https://aflock.ai/attestations/<name>/v0.1 namespace. Witness-style URLs (https://witness.dev/attestations/<name>/v0.1) are accepted via legacy aliases for interop with witness-produced evidence.
Top-level commands
| Command | Purpose |
|---|---|
cilock login | Sign in to the platform and store a session bound to a working tenant + product. |
cilock use | Switch the working tenant/product the stored session binds attestations to. |
cilock whoami | Show the current platform session (tenant, product, expiry). |
cilock logout | Remove the stored platform session credential. |
cilock enroll agent | Enroll this machine's agent principal in one ceremony: a human approves in the browser with a fresh passkey step-up, cilock stores and redeems the credential. |
cilock agent login / logout / status | Manage this machine's enrolled agent principal (signs in place of the human session when present). |
cilock trust [provider] [owner/repo] | Register an OIDC identity the platform trusts for keyless upload (CI). |
cilock doctor | Read-only preflight: is the environment sane to attest + upload against the platform? |
cilock git configure | Configure Git commit and tag signing through CI/lock's standard X.509 signing protocol. |
cilock pushgate status | Show whether the exact current ref and commit were accepted and delivered by Pushgate. |
cilock run [cmd] | Run a command and record signed attestations about its execution. |
cilock attest | Record attestations without wrapping a command (sugar for run -- true; for consultative/at-rest attestors). |
cilock attest vex | Author a signed OpenVEX document from a triage decision (validated against the spec before it is signed). |
cilock sign [file] | Sign an arbitrary file (typically a policy) with the configured signer. |
cilock verify | Verify an artifact (subject) against a signed policy using attestations as evidence. |
cilock policy from-bundles | Generate a starter Witness policy from one or more signed attestation bundles. |
cilock policy from-commit | Author a Witness policy from a commit's CI attestations already in the platform's Archivista. |
cilock policy push | Upload a signed policy DSSE to the platform and create a release. |
cilock policy bind | Bind a published policy definition/release to a product on the platform. |
cilock policy validate | Validate a Witness/cilock policy document (schema; signature only with -k or --require-signed). |
cilock policy draft | Hydrate a hand-authored policy with the tenant's platform trust roots. Returns it UNSIGNED. |
cilock keyid | Print the canonical keyid (hex(sha256(PEM(pub)))) derived from a public or private key. |
cilock bundle create / inspect | Build or inspect a portable attestation bundle (tar.gz of DSSE envelopes). |
cilock plan -- <cmd> | Show which attestors detection would fire for a command, without executing it. |
cilock attestors list | List every attestor compiled into the binary. |
cilock attestors schema <name> | Print the JSON schema of a specific attestor's predicate. |
cilock tools list / show / test-plan | List supported detectors, show one, or emit per-tool test plans. |
cilock get <tool> | Install a trusted tool only if its release artifact matches the SHA-256 pin embedded in this binary. |
cilock completion <shell> | Emit shell completion script (bash, zsh, fish, powershell). |
cilock version | Print the cilock version. |
Global flags
These persistent flags are accepted on every subcommand:
| Flag | Default | Notes |
|---|---|---|
--log-level, -l <level> | info | One of debug, info, warn, error. |
--debug-cpu-profile-file <path> | (none) | Write a CPU pprof profile to this path. Profiling enabled when non-empty. |
--debug-mem-profile-file <path> | (none) | Write a heap pprof profile to this path. Profiling enabled when non-empty. |
--policy-hardening <mode> | enforce | Policy-verification hardening: enforce rejects dangerous policy configurations; warn downgrades them to loud warnings. Also settable via CILOCK_POLICY_HARDENING. |
Platform session & CI trust
These commands establish and inspect the platform session that attestation upload (and keyless signing-token exchange) need. Signing itself is keyless and needs no login; uploading to Archivista binds the evidence to your tenant/product, which is what the session carries. The onboarding path is login → (use to switch scope) → trust to let CI upload → doctor to preflight.
The platform is derived from a single --platform-url (default https://platform.testifysec.com); it auto-resolves Fulcio, TSA, and Archivista from that host's discovery document. After login, the commands that consume a session — run, trust, bundle, policy …, pushgate status — default to the platform you logged into. The commands that manage sessions (use, whoami, logout, and agent login/logout/status) do not: with no flag they act on https://platform.testifysec.com, so against any other platform pass the same --platform-url you gave login to every one of them.
cilock login
Sign in and store a session credential. The browser approve page binds a working tenant AND product — creating a default tenant/product if you have none — so every subsequent attestation is scoped to one. Identity resolves by precedence: --token (explicit JWT, CI/headless; - reads stdin) → ambient CI workflow OIDC (GitHub Actions, auto-detected) → interactive browser (default for local use).
| Flag | Default | Description |
|---|---|---|
--platform-url <url> | https://platform.testifysec.com | Platform to sign in to. |
--token <jwt> | (none) | JWT for CI/headless login (skips the browser); - reads it from stdin. |
--workflow-identity | false | Use the ambient CI workflow OIDC identity (auto-detected on the default platform; required to send a workflow token to a non-default --platform-url). |
--interactive | false | Force the interactive browser login (skip ambient CI identity). |
--tenant <id|name> / --product <id|name> | (none) | Pre-select tenant/product on the approve page. |
--tenant-id <uuid> / --product-id <uuid> | (none) | Bind tenant/product directly for a headless --token login. |
--tenant-name / --product-name <str> | (none) | Label to record alongside --tenant-id / --product-id. |
--allow-trust | false | Also grant the narrow oidc:write scope so this session can run cilock trust. Off by default. |
# Interactive browser login (binds tenant+product on the approve page)
cilock login
# CI on GitHub Actions: ambient workflow identity (needs permissions: id-token: write)
cilock login --workflow-identity --platform-url "$PLATFORM_URL"
# CI/headless with an explicit JWT + the tenant+product to bind
cilock login --platform-url https://platform.example.com --token "$TESTIFYSEC_TOKEN" \
--tenant-id <uuid> --product-id <uuid>
cilock use
Switch the working tenant + product the stored session binds attestations to, so cilock run scopes evidence without re-prompting. Requires an existing session (cilock login first). The analog of kubectl config use-context for cilock.
| Flag | Default | Description |
|---|---|---|
--product-id <uuid> / --tenant-id <uuid> | (none) | Bind directly (no browser). |
--product-name / --tenant-name <str> | (none) | Label recorded alongside the id. |
--product <id|name> / --tenant <id|name> | (none) | Select by name on the approve page (re-opens the browser to resolve names → ids, auto-creating a default tenant/product if you have none). |
--platform-url <url> | https://platform.testifysec.com | Platform whose session to rebind. Must match the login. |
# Switch the working product by id (no browser)
cilock use --product-id 5664d4f5-9003-41e8-90e4-035c51d09b45 --product-name acme-web
# Pick or create tenant+product interactively
cilock use
# Pre-select by name on the approve page
cilock use --tenant acme --product acme-web
cilock whoami
Show the platform session — the logged-in tenant, bound product, and expiry — for one platform.
| Flag | Default | Description |
|---|---|---|
--platform-url <url> | https://platform.testifysec.com | Platform whose session to show. Must match the login. |
cilock whoami
cilock whoami --platform-url https://platform.example.com
cilock logout
Remove the stored platform session credential for one platform. It does not look up which platform you logged into: with no flag it removes the public-platform session, and a session on any other platform stays on disk while the command exits 0.
| Flag | Default | Description |
|---|---|---|
--platform-url <url> | https://platform.testifysec.com | Platform whose session to remove. Must match the login. |
cilock logout
cilock logout --platform-url https://platform.example.com
cilock enroll agent
Enroll an agent principal for this machine in one ceremony. A browser window opens on the platform's enrollment page; your human signs in, reviews what is being minted — name, organization, repository scope, lifetime — steps up with their passkey (required afresh for every ceremony — a session that stepped up this morning is not a person present now), and confirms. The passkey locks in exactly what was reviewed: the platform digests the review into the ceremony's challenge and refuses a mint that differs in any of those fields, so a browser an agent drives cannot take the gesture for one enrollment and submit another. The platform mints the principal inside that session and hands the one-time credential, sealed to this ceremony's ephemeral key, straight back to the command, which stores it 0600 and then redeems it. Only that first exchange activates the principal. The delivered credential is held pending beside whatever this machine already signs with, never over it: if the platform refuses it (its own structured verdict — a bare 401/403 from a proxy is not one), the command fails and discards only the pending credential, and the previously enrolled identity keeps signing; if the platform did not answer, both are kept and the next cilock run redeems the pending one first. A ceremony that did not complete leaves nothing that claims to be an identity, and costs nothing that was.
The identity is time-bound: it stops signing at the lifetime the human confirmed (eight hours by default, seven days at most) and cannot be extended. Run the command again for a new principal. An agent may run this command; it cannot complete it — nothing on the command line substitutes for the person in the browser.
| Flag | Default | Description |
|---|---|---|
--platform-url <url> | https://platform.testifysec.com | Platform to enroll with. |
--name <label> | (none) | Pre-fill the principal's display label on the approve page. |
--repo <owner/name> | (none) | Pre-select a repository scope on the approve page. |
--ttl <duration> | platform default (8h) | Pre-select the principal's lifetime on the approve page; 15m–168h. |
cilock enroll agent
cilock enroll agent --name claude-on-coles-mbp --repo testifysec/judge --ttl 4h
cilock agent enroll is a hidden alias of the same command.
cilock agent login
Store a refresh credential minted for this agent outside the enroll agent ceremony (for example by an administrator running the createAgentPrincipal mutation directly). The credential is read from STDIN by default so it never lands in shell history or a process listing; it is written 0600 to cilock's own agent store, kept apart from the cilock login session, and never printed again. Once stored, runs against that platform sign as the agent principal, taking precedence over any human cilock login session. The tenant and agent ids are not secret — they are the SPIFFE path segments (spiffe://<trust-domain>/tenant/<tenant-id>/agent/<agent-id>) every certificate this credential buys will carry.
| Flag | Default | Description |
|---|---|---|
--platform-url <url> | https://platform.testifysec.com | Platform the agent is enrolled with. |
--tenant-id <uuid> | (none) | Tenant UUID this agent is enrolled in (SPIFFE path segment). |
--agent-id <uuid> | (none) | Agent principal UUID minted at enrollment (SPIFFE path segment). |
# Read the credential from stdin (preferred)
cilock agent login --platform-url https://platform.example.com \
--tenant-id <uuid> --agent-id <uuid> < credential.txt
cilock agent logout
Remove this machine's copy of the agent credential. This is a local delete, not a revocation: the principal stays valid on the platform until a human revokes it there. The credential is keyed by platform, and logout does not look up which platform you enrolled with — it removes the credential for --platform-url, defaulting to the public platform. Pass the same --platform-url you gave cilock agent login, or a non-default enrollment stays on disk while the command prints No agent credential stored for … and exits 0.
| Flag | Default | Description |
|---|---|---|
--platform-url <url> | https://platform.testifysec.com | Platform whose agent credential to remove. Must match the login. |
cilock agent logout --platform-url https://platform.example.com
cilock agent status
Show the agent principal this machine would sign as against one platform: the full SPIFFE ID once the platform has redeemed the credential, or not yet redeemed while it has not (an unredeemed credential is kept across a transient refusal and the next cilock run retries), and when its authority expires. Like logout, it reads the credential for --platform-url only; with no flag it reports the public platform, so a non-default enrollment shows as absent unless you name it.
An expired credential prints EXPIRED and exits non-zero, so a script can gate on a dead identity without parsing the output. There are two ways out and cilock takes neither on its own: cilock enroll agent for a new ceremony, or cilock agent logout to sign as your own session. An enrolled agent credential pre-empts the human session machine-wide by design — falling back to it silently would put a human's name on an agent's work — so cilock run refuses the same way, before it executes the wrapped command, rather than spending the build on a refusal it could read locally.
| Flag | Default | Description |
|---|---|---|
--platform-url <url> | https://platform.testifysec.com | Platform to report the enrolled agent for. Must match the login. |
cilock agent status --platform-url https://platform.example.com
cilock agent login
Store the refresh credential a human minted for this agent at enrollment. The credential is read from STDIN by default so it never lands in shell history or a process listing; it is written 0600 to cilock's own agent store, kept apart from the cilock login session, and never printed again. Once stored, runs against that platform sign as the agent principal, taking precedence over any human cilock login session. The tenant and agent ids are not secret — they are the SPIFFE path segments (spiffe://<trust-domain>/tenant/<tenant-id>/agent/<agent-id>) every certificate this credential buys will carry.
| Flag | Default | Description |
|---|---|---|
--platform-url <url> | https://platform.testifysec.com | Platform the agent is enrolled with. |
--tenant-id <uuid> | (none) | Tenant UUID this agent is enrolled in (SPIFFE path segment). |
--agent-id <uuid> | (none) | Agent principal UUID minted at enrollment (SPIFFE path segment). |
# Read the credential from stdin (preferred)
cilock agent login --platform-url https://platform.example.com \
--tenant-id <uuid> --agent-id <uuid> < credential.txt
cilock agent logout
Remove this machine's copy of the agent credential. This is a local delete, not a revocation: the principal stays valid on the platform until a human revokes it there.
| Flag | Default | Description |
|---|---|---|
--platform-url <url> | https://platform.testifysec.com | Platform whose agent credential to remove. |
cilock agent logout
cilock agent status
Show the agent principal this machine would sign as.
| Flag | Default | Description |
|---|---|---|
--platform-url <url> | https://platform.testifysec.com | Platform to report the enrolled agent for. |
cilock agent status
cilock trust
Register an OIDC federated identity the platform will trust for keyless attestation upload — the CI complement to cilock run. It creates an OIDC credential only; cilock never mints a long-lived API-token secret. Run it as a tenant admin after cilock login --allow-trust (the oidc:write scope is opt-in). The audience defaults to the same ${platform}/archivista that cilock run uploads to, and the subject is templated from the provider's claim convention, so trust and run can't drift. Providers: github, gitlab (or --issuer + --subject for any other); on-prem GHES / self-hosted GitLab add --host.
| Flag | Default | Description |
|---|---|---|
[provider] [owner/repo] | auto-detect repo | Positional: e.g. github testifysec/judge. With no args (interactive), detects the current repo. |
--host <host> | (none) | On-prem instance host for the provider (e.g. github.acme.com). |
--issuer <url> / --subject <glob> | (none) | Generic provider escape hatch (use together). |
--audience <aud> | ${platform-url}/archivista | OIDC audience (matches cilock run). |
--scope <s> | attestation:upload | Repeatable. Only attestation:{upload,read,verify} allowed. |
--verify | false | Also grant attestation:read (for cilock verify --enable-archivista). |
--allowed-ip <cidr> | any | Source IP/CIDR allowlist (repeatable; e.g. the runner egress). |
--name / --description <str> | <provider>:<slug> | Credential name / description. |
--tag <t> | (none) | Categorization tag (repeatable). |
--tenant <id> | logged-in working tenant | Tenant to register the trust under. |
--dry-run | false | Print what would be created without calling the platform. |
--yes, -y | false | Skip the interactive confirmation. |
# Trust a GitHub repo's Actions to upload (most common)
cilock trust github testifysec/judge
# Interactive: auto-detect the current repo and confirm
cilock trust
# On-prem GitHub Enterprise Server
cilock trust github acme/app --host github.acme.com
# Any OIDC provider (generic escape hatch)
cilock trust --issuer https://oidc.corp/foo --subject sub:acme:prod
cilock doctor
Read-only preflight (no build, no upload) of a cilock attestation environment. Prints a green/red checklist: logged in? platform reachable (.well-known/judge-configuration discovery)? Fulcio / TSA / Archivista destinations (derived + discovered); upload authorization (login session origin matches Archivista origin). Run it before a multi-minute cilock run to confirm signing + upload will work. --json emits a machine-readable report an agent can gate on (report.ok).
| Flag | Default | Description |
|---|---|---|
--platform-url <url> | https://platform.testifysec.com | Platform to probe. |
--json | false | Emit the preflight report as a single JSON object (report.ok is the rollup to gate on). |
# Check the default hosted platform
cilock doctor
# Check a self-hosted / standalone platform, machine-readable
cilock doctor --platform-url https://judge.example.com --json
cilock git configure
Configure Git's standard X.509 signing protocol to use CI/lock for signed
commits and tags. By default the command changes only the current repository;
--global applies the same configuration to every repository for the current
user. CI/lock obtains a short-lived Fulcio certificate from the selected
TestifySec platform and requires its RFC 3161 timestamp authority, so no
long-lived signing key is written into the repository.
| Flag | Default | Description |
|---|---|---|
--global | false | Write the signing configuration to the current user's global Git configuration instead of this repository. |
# Configure this repository, then use ordinary Git signing commands
cilock git configure
git commit -S -m "feat: signed by CI/lock"
git verify-commit HEAD
# Configure all repositories for this user
cilock git configure --global
cilock pushgate status
Read the exact Pushgate delivery record for a Git ref and commit. With no flags,
CI/lock discovers the current branch, HEAD commit, selected platform, and the
configured Pushgate Git remote. The platform discovery document pins the trusted
Pushgate origin; the request uses the matched remote's repository-scoped
credential and refuses redirects rather than forwarding that credential.
Use --wait after git push to stay attached until delivery finishes. A
delivered push exits successfully; a refusal, conflict, terminal delivery
failure, or timeout exits non-zero with an actionable status. --json emits one
machine-readable object when the command finishes.
| Flag | Default | Description |
|---|---|---|
--remote <name> | inferred Pushgate remote | Select a Git remote explicitly when more than one matches the discovered Pushgate origin. |
--ref <ref> | current branch | Fully qualified refs/heads/* or refs/tags/* ref. Discovery reads git symbolic-ref HEAD, which resolves a branch only, so a checked-out tag — a detached HEAD — must pass --ref explicitly. |
--commit <sha> | HEAD | Exact lowercase 40-character commit to query. |
--wait | false | Poll until delivery succeeds or reaches a terminal failure. |
--timeout <duration> | 15m | Maximum time to wait for delivery. |
--json | false | Emit the final status or stable error as JSON. |
# Inspect the current commit without changing anything
cilock pushgate status
# Push, then remain attached through asynchronous Git-provider delivery
git push pushgate HEAD
cilock pushgate status --wait
# Agent-friendly output with an explicit wait budget
cilock pushgate status --wait --timeout 20m --json
cilock run [cmd]
Runs the provided command and records attestations about the execution.
Always-run attestors (cannot be omitted): material, product, and (when args are provided) command-run. Trying to pass command-run via --attestations is rejected.
Only one signer is supported per run invocation (enforced in cilock/cli/signer_error.go).
Common flags
| Flag | Short | Default | Description |
|---|---|---|---|
--step <name> | -s | inferred | Step category. Optional — when omitted, inferred from the wrapped command. Must be a value from the step lexicon. |
--attestations <list> | -a | environment,git,platform | Comma-separated attestors (product + material are always recorded). Passing -a disables auto-detection (set becomes exact) unless --workload auto. |
--workingdir <dir> | -d | current dir | Working directory for material/product capture. |
--outfile <path> | -o | stdout | Path for the signed DSSE envelope. |
--trace | -r | false | Enable syscall tracing (Linux). Backend is ptrace+seccomp or eBPF — see capture modes. No-op on non-Linux. |
--ignore-command-exit-code | (none) | false | Exit 0 from cilock even when the wrapped command exits non-zero. The exit code is recorded and signed in command-run/v0.2 either way (and the envelope is written and uploaded either way), so a policy rule on input.exitcode can deny the run; without the flag a non-zero exit also fails cilock run itself. Useful for tools that signal findings via exit code (e.g. oscap exits 2, scanners exit 1). |
--hashes <list> | (none) | sha256 | Hash algorithms used in digests (comma-separated). |
--max-attestation-bytes <size> | (none) | 4MiB | Largest in-toto statement CI/lock will sign, as plain bytes (4194304) or with a unit (4MiB, 512KiB, 4MB — binary units are 1024-based, KB/MB/GB are 1000-based). A statement over this is refused before it is signed, written or uploaded, and the error names the total, the limit and the five largest attestors with a remedy for each. Also settable via CILOCK_MAX_ATTESTATION_BYTES (the flag wins). 0 disables the limit and warns once on stderr. See why 4 MiB. |
--dirhash-glob <list> | (none) | (none) | Globs for which directories should be hashed as a single unit. |
--timestamp-servers <list> | -t | (none) | RFC 3161 TSA URLs (comma-separated; repeatable). |
--enable-archivista | (none) | false | Push the signed envelope to Archivista. |
--archivista-server <url> | (none) | https://platform.testifysec.com/archivista | Archivista server URL (derived from --platform-url if not explicitly set). |
--archivista-headers <h> | (none) | (none) | Repeatable Authorization: ... headers for Archivista. |
--archivista-oidc | (none) | false | Use GitHub Actions OIDC for Archivista auth (auto-enabled in GitHub Actions). |
--archivista-audience <aud> | (none) | Archivista server URL | OIDC audience claim. |
--platform-url <url> | (none) | https://platform.testifysec.com | TestifySec platform URL; archivista, fulcio, and TSA URLs are derived from it if unset. |
--env-filter-sensitive-vars | (none) | false | Remove sensitive env vars from output rather than obfuscating. |
--env-add-sensitive-key <key> | (none) | (none) | Add a name or glob (e.g. *TOKEN*) to the sensitive env list (repeatable). |
--env-allow-sensitive-key <key> | (none) | (none) | Whitelist a specific key from the sensitive list. |
--env-disable-default-sensitive-vars | (none) | false | Disable CI/lock's default sensitive-var list entirely. |
Capture, detection & hardening flags
| Flag | Default | Description |
|---|---|---|
--capture-mode <mode> | auto | Where material/product digests come from: auto (trace if --trace, else walk), walk, trace (requires --trace), ima. See capture modes. |
--hardening <profile> | standard | Integrity profile: off, standard (fanotify on, fs-verity opportunistic), strict (fanotify + fs-verity required, drops fail). |
--require-zero-drops | from --hardening | Fail the run if the trace dropped any event. strict ⇒ true. |
--workload <mode> | auto | Attestor selection. auto detects (only when -a absent, unless forced); manual uses -a/defaults exactly. See auto-detection. |
--validate-only | false | Run pre-flight workload + tool checks, print the planned attestor set, exit without running the command. |
--no-default-attestor <name> | (none) | Drop an always-on attestor (product, material). Repeatable. |
--material-manifest | false | Publish the material attestor's per-file leaves as a detached companion envelope (<outfile>-material-manifest.json), stored before the collection when Archivista upload is on. The predicate records manifestUploaded and the manifest's content digest either way. The Merkle root is signed regardless — this changes only where the proof material lives. |
--diagnose | false | Verbose internal logging (eBPF load, fanotify, ringbuf drops, fs-verity). Sets CILOCK_DIAGNOSE=1. |
--cache-add-pattern <glob> | (none) | Add a glob to the build-cache classification set (cache files aren't products). Repeatable. |
--cache-allow-pattern <glob> | (none) | Remove a glob from the cache set (treat as a product). Repeatable. |
--prewalk-skip-dir <name> | (none) | Add a basename to the pre-trace walk skip list (defaults: .git, node_modules, vendor, .cache). Repeatable. |
--prewalk-include-dir <name> | (none) | Force the pre-trace walk into a basename even if skipped. Most-specific wins. Repeatable. |
Capture backend selection within --trace is controlled by the --capture-mode suffix — trace:auto (eBPF, else ptrace), trace:ebpf (require eBPF), or trace:ptrace (skip the eBPF probe) — plus the CILOCK_FANOTIFY / CILOCK_FSVERITY feature toggles.
Plus the signer flags (see below) and attestor-specific flags prefixed --attestor-<name>-* (e.g. --attestor-secretscan-fail-on-detection, --attestor-product-include-glob).
Signer selection
CI/lock loads signers based on which --signer-*-* flags are set. The default binary registers two signer providers plus a KMS provider:
file:--signer-file-key-path,--signer-file-cert-path,--signer-file-intermediate-paths,--signer-file-key-passphrase,--signer-file-key-passphrase-pathfulcio:--signer-fulcio-url,--signer-fulcio-oidc-issuer,--signer-fulcio-oidc-client-id,--signer-fulcio-oidc-redirect-url,--signer-fulcio-token,--signer-fulcio-token-path,--signer-fulcio-use-http(defaulttrue)kms:--signer-kms-ref(key reference URI, e.g.awskms://,gcpkms://,azurekms://,hashivault://),--signer-kms-hashType(defaultsha256),--signer-kms-keyVersion
Additional providers (spiffe, vault, and per-cloud KMS broker clients with their extra sub-flags) are not compiled into the default release binary; add them via a custom build — see build a custom CI/lock. Run cilock run --help-advanced to see the exact signer flags your binary exposes.
For the full URI conventions, see signing & identity.
cilock plan
Dry-run of
cilock run's pre-gate detection: prints which attestors would fire for a hypothetical command, which would be skipped (with reasons), and any warnings — without executing the command. Take the names from thefirelist and pass them tocilock run -a <attestor>,...to run the planned set.
| Flag | Default | Description |
|---|---|---|
-- <command> [args...] | (required) | The command to plan for (after the -- separator). |
--format <fmt> | text | text or json (machine-readable, for an agent to consume). |
--verbose, -v | false | Include the full skip list (every detector considered) in text output. |
# Show which attestors would fire for a build, without running it
cilock plan -- go build ./...
# Machine-readable plan for an agent to consume
cilock plan --format json -- docker build -t app .
cilock sign [file]
Signs a file with the provided key source and outputs the signed file to the specified destination.
Wraps an arbitrary file in a DSSE envelope. Used most commonly to sign a policy document before distribution. Same signer-selection model as run. Only one signer per invocation.
| Flag | Short | Default | Description |
|---|---|---|---|
--infile <path> | -f | (required) | File to sign (typically the policy JSON). |
--outfile <path> | -o | stdout | Destination for the signed DSSE envelope. |
--datatype <uri> | -t | https://witness.testifysec.com/policy/v0.1 | DSSE payloadType. Default is the witness policy type for backward compatibility; CI/lock also accepts https://aflock.ai/policy/v0.1. |
--max-attestation-bytes <size> | (none) | 4MiB | Largest input sign will wrap, measured on the bytes read from --infile — for sign the input is the payload, so nothing is framed around it. Refused before a signer is loaded, so an oversized file fails even with no key configured. Same grammar, env var and 0 opt-out as run. |
--platform-url <url> | (none) | https://platform.testifysec.com | Platform whose session is exchanged for a keyless Fulcio certificate. Pass "" to sign with --signer-* only. |
--offline | (none) | false | Alias for --platform-url "", the same opt-out run and verify take: no session lookup, no keyless exchange, no platform TSA. Needs a local signer (-k or a --signer-kms-*/--signer-vault-*/--signer-spiffe-* provider); without one the command says so instead of failing with "no signers found". |
Why the attestation size limit is 4 MiB
The number comes from what the platform can afford to read, not from what a signer can produce.
On each push evaluation the platform downloads and JSON-parses every envelope matching the commit, three times, and caches nothing above 512 KiB. Measured 2026-09-15 on the evaluate-release path: about 0.4 s per MB. A commit with no large envelope evaluates in 0.95 s median; one 45 MB envelope takes 18.6 s; two take 32 s. A single evaluation is timed out at the edge after 25 s, under Envoy's 30 s route timeout — so a pair of oversized envelopes does not merely make a push slow, it makes the platform report itself unreachable.
That is not hypothetical. A command-run attestor that captured a whole go test -json
stream produced 45.6 MB and 47.1 MB envelopes and took pushes over the edge budget.
A 4 MiB ceiling keeps a commit carrying several envelopes inside roughly two seconds
of parse time. The edge has 4 MiB constants of its own, but they are not a per-envelope
read cap and this limit is not derived from them: that number is the git push prefix
cap (the ref-update section, push certificate and push-options), and the edge's
whole-body cap is 16 MiB. The agreement is a coincidence, and the parse-time
measurement above is the only thing this default rests on.
For scale on the other side: a real push-tests mint of this repository — -a git -a alps-evidence with the product exclude glob, compact evidence profile — measured
17,023 bytes of statement on 2026-09-15. The default leaves about 240x headroom
for ordinary evidence, so a run that trips it has a stdout-capture or a
material/product-scope problem, which is what the refusal's per-attestor breakdown
points at.
The margin is narrower on a legacy-profile build, where the material attestor's per-file leaves stay inline. The same repository measured a 4.95 MiB envelope — about 3.7 MiB of statement, 17,152 leaves — before compact inventories detached them, which is 88% of this limit rather than 0.4% of it. That is the intended behaviour: a legacy build really is producing the envelopes push evaluation struggles with. Raise the limit deliberately with the flag or the env var if you need it, or move to a compact build.
verify has no such flag, deliberately. The limit is a mint-time guardrail;
evidence already signed — including envelopes minted before the limit existed — must
stay verifiable forever.
Companion envelopes (--material-manifest, detached file inventories) are exempt.
They are keyed by tree root and unreachable from a commit-keyed lookup, so a push
evaluation never opens one, and each carries its own ceiling and its own upload
consent.
cilock verify
Verifies an artifact (subject) against a signed policy. You name the subject — an artifact file (
-f) or a digest such assha256:$DIGEST(-s) — and CI/lock uses the supplied attestations as the evidence that validates it. You verify the thing, not the attestation.
Because v0.3 product/material attestations inline their Merkle leaves by default, cilock verify <artifact> -p policy -a <attestations> resolves the artifact's digest to its signed tree with no separate inclusion-proof envelope — the inclusion-proof bridge maps the artifact's sha256 to the tree:products root directly from the signed attestation's inline leaves.
Policy-signer trust. A build can embed its policy trust anchors (policy CA root, TSA root, signer functionary) at compile time, so cilock verify <artifact> -p policy -a <attestations> needs no --policy-* flags; verify prints the trust anchors it uses. The canonical binary ships empty embedded trust ({}), so you supply trust per dimension via -k/--publickey (key) or --policy-ca-roots + the Fulcio constraint flags below. Flags override embedded trust; verify fails closed when neither a flag nor embedded trust is present for a required dimension.
| Flag | Short | Description |
|---|---|---|
--policy <path> | -p | Path to the signed DSSE policy envelope. |
--publickey <path> | -k | Path to the policy signer's public key (PEM). |
--attestations <list> | -a | Attestation envelope files (comma-separated; repeatable). |
--artifactfile <path> | -f | Path to the artifact subject to verify. |
--subjects <list> | -s | Additional subjects to use when looking up attestations (e.g. sha256:<hex>). Useful when the artifact file itself isn't available locally — verify by a known digest instead. Do not pass sha1:$COMMIT to anchor a match: sha1-commit anchoring was rejected (chosen-prefix collision, CVE-2026-22703) — --artifactfile (see above) already resolves the multi-stage-pipeline product/material mismatch that anchoring on the commit hash used to work around, via the inline-leaf inclusion-proof bridge. |
--directory-path <path> | (none) | Path to a directory subject (for material/product matching). |
--enable-archivista + --archivista-server | (none) | Pull collections from Archivista by subject digest instead of (or in addition to) file paths. |
--policy-ca-roots <list> | (none) | X.509 roots for verifying a policy signed via x.509 cert (replaces the deprecated --policy-ca). |
--policy-ca-intermediates <list> | (none) | Intermediate CAs for the policy cert chain. |
--policy-commonname, --policy-dns-names, --policy-emails, --policy-organizations, --policy-uris | (none) | Cert-constraint fields when the policy is signed with x.509. |
--policy-fulcio-oidc-issuer, --policy-fulcio-build-trigger, --policy-fulcio-build-config-uri, --policy-fulcio-runner-environment, --policy-fulcio-run-invocation-uri, --policy-fulcio-source-repository-{ref,identifier,digest} | (none) | Fulcio cert-constraint fields pinning a keyless policy signer — e.g. --policy-fulcio-build-config-uri https://github.com/org/repo/.github/workflows/release.yml@* pins which workflow may sign a trusted policy without pinning the ref; --policy-fulcio-runner-environment github-hosted. |
--policy-timestamp-servers <list> | (none) | Trusted TSA CA cert paths for verifying timestamped policies. |
--verifier-kms-* | (none) | Same shape as --signer-kms-*, used when the policy's public key is referenced by a KMS URI. |
--offline | (none) | Alias for --platform-url "": fully offline verify. |
--format <fmt> | (none) | text (default) or json, which also emits one machine-readable verdict object on stdout. An unknown value is an error. -o is a deprecated alias for --format on this command only (it prints a notice); on every other command -o is an output path. |
--vsa-outfile <path> | (none) | Write the Verification Summary Attestation to a file. This, not -o, is where verify writes a file. |
Full verifier flag list is in cilock/internal/options/verify.go.
Exit code 0 on policy pass, non-zero on any verification failure or error.
cilock bundle
Build or inspect a portable attestation bundle (a tar.gz of DSSE envelopes) — the offline-evidence companion to
cilock verify --bundle.createwalks Archivista's subject graph from a digest and packs everything reachable;inspectprints a bundle's manifest so you can see what's inside before verifying.
cilock bundle create
Pulls every DSSE envelope reachable from the given subject digest(s) via Archivista's subject graph and packs them into a tar.gz.
| Flag | Default | Description |
|---|---|---|
--subject, -s <digest> | (required) | Subject digest(s) to seed the graph walk (e.g. sha256:abc...). Repeatable. |
--output, -o <path> | stdout | Path to write the bundle (tar.gz). |
--max-depth <n> | 5 | Maximum subject-graph traversal depth. |
--max-envelopes <n> | 10000 | Maximum envelopes to fetch before aborting. |
cilock bundle create -s sha256:<digest> -o evidence.tar.gz
cilock bundle inspect
Print a bundle's manifest and a per-envelope summary.
| Flag | Default | Description |
|---|---|---|
<bundle.tar.gz> | (required) | Bundle to inspect. |
--json | false | Emit the manifest as JSON (suppresses the per-envelope summary). |
cilock bundle inspect evidence.tar.gz
# then verify offline against it:
cilock verify ./app -p policy.signed.json -k pub.pem --bundle evidence.tar.gz --platform-url ""
cilock attest
Records attestations against the current context without wrapping a command — sugar for
cilock run -- true. Everyrunflag works here. Use it for consultative / at-rest attestors that snapshot state (e.g.github-review,aws-iid) rather than observe a command.
cilock attest -a github-review -k key.pem -o review.bundle.json -s review-head
cilock attest vex
Authors an OpenVEX document from a triage decision, validates it against the spec's own rules, writes it to disk, and attests it with the same signer, timestamper, and Archivista destination every other command uses. Before this, cilock could only consume a VEX document, so producing one meant hand-written JSON that nothing checked.
Validation is fail-closed — a statement that suppresses a finding has to say why. Unknown statuses, unknown justifications, and malformed vulnerability IDs are rejected rather than recorded. Product digests are canonicalized to bare lowercase hex, which is how the platform stores an image digest at ingest, so a statement authored here joins to the image it is about.
| Flag | Default | Description |
|---|---|---|
--product <ref> | (required) | Product the statement is about. Repeatable. An OCI reference with a digest (ghcr.io/org/img@sha256:<hex>), a package URL (pkg:…), or a bare sha256 digest. |
--vuln <id> | (required) | Vulnerability the statement is about (CVE-YYYY-NNNN or GHSA-xxxx-xxxx-xxxx). Repeatable; each becomes its own statement carrying every --product. |
--status <status> | (required) | not_affected, affected, fixed, or under_investigation. |
--justification <j> | (none) | Why the product is not affected. Required with --status not_affected, rejected otherwise. One of component_not_present, vulnerable_code_not_present, vulnerable_code_not_in_execute_path, vulnerable_code_cannot_be_controlled_by_adversary, inline_mitigations_already_exist. |
--impact-statement <text> | (none) | Free-text elaboration on the justification — where a human (or an agent) explains the reasoning a reviewer will read. |
--action-statement <text> | (none) | What is being done about it. Required with --status affected: an affected statement with no remediation plan is a finding, not triage. |
--author <name> | cilock | Author recorded in the OpenVEX metadata. The cryptographic identity is the signer; this is the human-readable attribution. |
--author-role <role> | (none) | Optional role of the author (OpenVEX role). |
--vex-out <path> | vex.openvex.json | Where the OpenVEX document lands. The signed bundle still goes to --outfile. |
Every cilock run flag applies — signer selection, --outfile, --platform-url, Archivista upload.
# Triage a CVE as unreachable in a specific image, signed keyless
cilock attest vex \
--product ghcr.io/acme/api@sha256:2f3c50f223e2c4e30b100dbcbaa5ff5e2f4bffd09b57ff0a687e766e79a76d1f \
--vuln CVE-2024-12345 \
--status not_affected \
--justification vulnerable_code_not_in_execute_path \
--impact-statement "the vulnerable parser is never reached from the request path" \
-s vex-triage -o vex.bundle.json
# Accept a finding with a remediation plan, signed with a local key
cilock attest vex \
--product pkg:golang/github.com/example/mod@v1.2.3 \
--vuln CVE-2024-99999 \
--status affected \
--action-statement "upgrade to v1.2.4 in the next release train" \
-k cosign.key -s vex-triage -o vex.bundle.json
cilock policy draft
Turns a hand-authored policy source into a complete, verifiable policy document without you looking up a trust root. You write the part that expresses intent — the steps, the functionaries, the rego — and leave the trust material out; draft sends that source to the platform, which fills in the tenant's platform Fulcio roots and timestamp authorities, validates the result, and returns it. draft then verifies the returned digest against the bytes it actually received before writing to
--output.draft never signs. The hydrated document is inert until a human signs it, and that is deliberate: signing is what makes a policy authoritative, so it stays an explicit human act with a human identity. draft prints the exact
cilock signcommand rather than running it. Needs a logged-in session with thepolicy:validatescope — if the platform rejects the call for a missing scope, runcilock loginagain to pick it up.
| Flag | Default | Description |
|---|---|---|
--datatype, -t <uri> | https://aflock.ai/policy/v0.1 | Policy payload type sent for hydration. |
--file, -f <path> | (required) | Path to the hand-authored policy source. |
--force | false | Overwrite --output if it already exists. |
--output, -o <path> | the source path with a .hydrated.json suffix | Where to write the hydrated, UNSIGNED policy. |
--platform-url <url> | the logged-in platform | TestifySec platform URL. |
# Hydrate a hand-authored policy — writes policy.hydrated.json, UNSIGNED
cilock policy draft -f policy.json
# Then sign it yourself; cilock never signs a policy for you:
cilock sign -f policy.hydrated.json -o policy.hydrated.signed.json
cilock policy from-bundles
Reads one or more signed attestation bundles and emits a starter Witness policy — one step per bundle (step name = the bundle basename without the
.bundle.jsonsuffix), functionaries populated from each signing keyid, andattestations[]populated from the predicate types found. Edit, then sign withcilock sign. Use--step-prefixto prepend a prefix to every generated step name.
cilock policy from-bundles -k signer.pub build.bundle.json scan.bundle.json -o policy.json
cilock policy from-commit <commit-sha>
Authors a starter Witness policy from the CI attestations the platform already holds for a commit — no local bundle files needed. It resolves the commit, finds every DSSE whose subjects include it, groups them by witness collection name (one step per collection), populates functionaries from each collection's signers (raw keyid or Fulcio keyless cert with the leaf SAN email pinned), recovers TSA trust anchors so short-lived keyless leaves verify, and wires cross-step provenance edges. Author-only by default (write the policy, then
cilock sign→policy push→policy bind); pass both--productand--tagfor the one-shot derive → sign → push → bind flow. The Archivista query needs a logged-in session; publication needspolicy:publish, and the optional Product binding additionally needs legacypolicy:write.
| Flag | Default | Description |
|---|---|---|
--definition, -d <name> | the product name | PolicyDefinition name for the one-shot flow. |
--description <str> | (none) | Description used only when the one-shot flow creates a new PolicyDefinition. |
--expires <dur> | 8760h (1 year) | How far in the future the policy's expires field is set. Set short and re-issue after review. |
--output, -o <path> | - (stdout) | Write the authored policy here. Ignored in one-shot mode. |
--platform-url <url> | the logged-in platform | TestifySec platform URL. |
--product, -p <id|name> | (none) | Product id or exact name. With --tag, runs the one-shot sign→push→bind flow against this product. |
--step-prefix <str> | (none) | Optional prefix prepended to every generated step name (e.g. release-). |
--tag, -t <t> | (none) | Release tag for the one-shot flow (requires --product). |
# Author a policy from a commit's CI evidence, write it for review
cilock policy from-commit 1a2b3c4d... -o policy.json
# One-shot: derive, sign keyless, publish a release tagged v1, bind to a product
cilock policy from-commit 1a2b3c4d... --product my-service --tag v1
cilock policy draft --file
Turns a hand-authored policy source into a complete, verifiable policy document without you looking up a trust root. You write the part that expresses intent — the steps, the functionaries, the rego — and leave the trust material out;
draftsends that source to the platform, which fills in the tenant's platform Fulcio roots and timestamp authorities, validates the result, and returns it.draftthen verifies the returned digest against the bytes it actually received and writes the hydrated document to--output. It does not sign: the hydrated document is inert until a human signs it, sodraftnever invokescilock signfor you — it prints the exact command to run. Needs a logged-in session with thepolicy:validatescope; if the platform rejects the call for a missing scope, runcilock loginagain to pick it up.
| Flag | Default | Description |
|---|---|---|
--file, -f <path> | (required) | Path to the hand-authored policy source. |
--output, -o <path> | the source path with a .hydrated.json suffix | Where to write the hydrated, UNSIGNED policy. |
--force | false | Overwrite --output if it already exists. |
--datatype, -t <url> | https://aflock.ai/policy/v0.1 | Policy payload type sent for hydration. |
--platform-url <url> | the logged-in platform | TestifySec platform URL. |
# Hydrate a hand-authored policy — writes policy.hydrated.json, UNSIGNED
cilock policy draft -f policy.json
# Then sign it yourself; cilock never signs a policy for you:
cilock sign -f policy.hydrated.json -o policy.hydrated.signed.json
# Explicit output, overwriting a previous draft
cilock policy draft -f policy.json -o hydrated.json --force
cilock policy push --file --definition --tag
Publishes an author-signed Witness policy to the platform. It uploads the signed policy DSSE to the platform's Archivista (the same upload path as
cilock run --enable-archivista), ensures the named PolicyDefinition exists (creating it if absent), then creates a PolicyRelease that pins the definition to the uploaded policy under--tag. The policy file must already be DSSE-signed — produce it withcilock signagainst the platform's keyless Fulcio. The DSSE upload needsattestation:upload; creating the immutable definition and release needspolicy:publish. That scope cannot bind a Product or assign a Pushgate repository.
| Flag | Default | Description |
|---|---|---|
--file, -f <path> | (required) | Path to the DSSE-signed policy (from cilock sign). |
--definition, -d <name> | (required) | PolicyDefinition name; created if it doesn't exist. |
--tag, -t <t> | (required) | Release tag (e.g. a semver or string). |
--description <str> | (none) | Description used only when creating a new PolicyDefinition. |
--platform-url <url> | the logged-in platform | TestifySec platform URL. |
# Sign first, then publish a release tagged v1.0.0
cilock sign -f policy.json -o policy.signed.json
cilock policy push --file policy.signed.json --definition supply-chain --tag v1.0.0
cilock policy publish --file --definition --tag
draft+ sign +pushas a single ceremony, for a policy a human signs. It hydrates the hand-authored source against the platform (the same callcilock policy draftmakes), then starts a sign-in whose approval names that exact hydrated document. Your human opens the printed URL, reads what the policy requires, and approves with a passkey; the platform signs those exact bytes as them — never as you, and never at a lower assurance level than the session it observed — then creates the PolicyRelease.You never hold a key, and your human never runs a second command. Before asking for the approval, cilock re-computes the digest of the hydrated bytes it holds, checks it against the source it sent and against the tenant that answered, and sends those same bytes at signing time — the platform refuses the pair if they disagree, so what is signed cannot drift from what was shown. Use
cilock policy pushinstead when the policy is already DSSE-signed by an author key.The release is created Off. Turning it on for a repository stays a separate act on Pushgate.
| Flag | Default | Description |
|---|---|---|
--file, -f <path> | (required) | Path to the hand-authored (unsigned) policy source. |
--definition, -d <name> | (required) | PolicyDefinition name; created if it does not exist. |
--tag, -t <t> | (required) | Release tag, e.g. v1. |
--description <str> | (none) | Description used only when the ceremony creates a new PolicyDefinition. |
--platform-url <url> | the logged-in platform | TestifySec platform URL. |
--datatype <type> | https://aflock.ai/policy/v0.1 | Policy payload type. |
# Publish v1 of judge-gates from a hand-authored source
cilock policy publish -f deploy/pushgate/judge-gates.policy.json -d judge-gates -t v1
cilock policy bind --definition --product
Binds a published policy to a product on the platform. It resolves the named PolicyDefinition and the target product, then creates a PolicyBinding linking them. Pass
--release(a release id) or--tag(resolved to a release under the definition) to pin a specific release; omit both to bind the definition itself. Creating the binding needspolicy:write.
| Flag | Default | Description |
|---|---|---|
--definition, -d <name> | (required) | PolicyDefinition name. |
--product, -p <id|name> | (required) | Product id or exact name to bind to. |
--release <id> | (none) | PolicyRelease id to bind (overrides --tag). |
--tag, -t <t> | (none) | Release tag to resolve under the definition. |
--platform-url <url> | the logged-in platform | TestifySec platform URL. |
# Bind a definition's v1.0.0 release to a product (by exact name)
cilock policy bind --definition supply-chain --tag v1.0.0 --product my-service
cilock keyid show
Prints the canonical keyid —
hex(sha256(PEM(pubkey)))— derived from a public or private key. The same value that appears in policyfunctionaries[].publickeyidand in attestation signatures. Reads PEM public keys (PKIX) or private keys (PKCS#8/PKCS#1/SEC1; the public half is extracted). One line per input (<keyid> <path>, matchingsha256sum's shape). Keys come from positional args or-k/--key.
| Flag | Default | Description |
|---|---|---|
<key-file>... / --key, -k <path> | (required) | Public or private key(s). -k takes a single file; mixing -k with positional args is an error. |
--format <fmt> | text | text = sha256sum-style lines; json = JSON array (for jq). |
cilock keyid show signer.pub
cilock keyid show signer.key signer.pub other.pem
cilock keyid show --format=json signer.key | jq .
cilock attestors list
Prints a box-drawn table of every attestor compiled into the binary:
┌──────────────────────────┬─────────────────────────────────────────────────────┬─────────────┐
│ NAME │ TYPE │ RUN TYPE │
├──────────────────────────┼─────────────────────────────────────────────────────┼─────────────┤
│ git (default) │ https://aflock.ai/attestations/git/v0.1 │ prematerial │
│ environment (default) │ https://aflock.ai/attestations/environment/v0.1 │ prematerial │
│ material (always run) │ https://aflock.ai/attestations/material/v0.3 │ material │
│ command-run (always run) │ https://aflock.ai/attestations/command-run/v0.2 │ execute │
│ product (always run) │ https://aflock.ai/attestations/product/v0.3 │ product │
│ inclusion-proof │ https://aflock.ai/attestations/inclusion-proof/v0.1 │ postproduct │
│ material-v0.1 │ https://aflock.ai/attestations/material/v0.1 │ material │
│ product-v0.1 │ https://aflock.ai/attestations/product/v0.1 │ product │
│ product-v0.2 │ https://aflock.ai/attestations/product/v0.2 │ product │
│ ... │ ... │ ... │
└──────────────────────────┴─────────────────────────────────────────────────────┴─────────────┘
Run types are lowercase strings: prematerial, material, execute, product, postproduct, verify.
Markers: (always run) means the attestor runs on every cilock run; (default) means it's enabled by default and you don't need to pass it via --attestations. The full catalog is in the attestor catalog.
cilock attestors schema <name>
Prints the JSON Schema document for the named attestor's predicate. Useful for writing Rego policies against a specific schema.
cilock policy validate -p <path>
Validates a Witness/cilock policy document for schema correctness. An unsigned policy is the normal input (validate, then cilock sign) and produces no signature warning; a DSSE envelope that carries no signatures does.
| Flag | Short | Default | Description |
|---|---|---|---|
--policy <path> | -p | (required) | Policy to validate: raw JSON or a signed DSSE envelope. |
--publickey <path> | -k | (none) | Verify the envelope's signature against this key. Requires a DSSE envelope. |
--require-signed | (none) | false | Fail unless the policy is a DSSE envelope with at least one signature (presence only; add -k to verify it). |
--format <fmt> | (none) | text | text or json. --output/-o are deprecated aliases that print a notice. |
cilock tools
The catalog of detectors cilock knows how to auto-fire (the same source cilock.dev's tool pages render from).
listenumerates them,showprints one tool's full record,test-planemits a validation plan.
cilock tools list
List every detector cilock knows how to auto-fire.
| Flag | Default | Description |
|---|---|---|
--category <cat> | (all) | Filter by lexicon category (e.g. build, vulnerability-scan, ci-context, sbom-generate). |
--source <src> | (all) | Filter: attestor-backed | catalog-only. |
--format <fmt> | table | table or json. |
cilock tools list
cilock tools list --category vulnerability-scan --format json
cilock tools show <name>
Show full catalog detail for one tool/attestor — the same record the website generates from.
| Flag | Default | Description |
|---|---|---|
<name> | (required) | Tool/attestor to show (e.g. sarif). |
--section <slug> | (all) | Print only one documentation section, by slug (see the summary). |
--format <fmt> | text | text or json (the full machine-readable record). |
cilock tools show sarif
cilock tools show sarif --section policy-gotcha
cilock tools show sarif --format json
cilock tools test-plan
Emit a structured test plan describing how to validate each detector (what triggers it, the expected fire decision, and a negative case). Pipe --format=json into a runner that exercises each scenario against cilock plan.
| Flag | Default | Description |
|---|---|---|
--only <name> | (all) | Limit the plan to a single detector. |
--format <fmt> | markdown | markdown or json. |
cilock tools test-plan
cilock tools test-plan --only sarif --format json
cilock get <tool>
Install a supporting tool from a SHA-256 pin embedded in this cilock binary. The pinned URL, release-artifact digest, and (for archives) the extracted-executable digest all live in one reviewable manifest compiled into the binary, so "which build of syft did CI run?" is answered by the cilock version alone — not by whatever a package manager or curl | sh happened to resolve that day.
The command fails closed: an unknown tool, a missing or malformed pin, or a digest mismatch aborts before anything is installed. Archives (.tar.gz, .zip) are verified before extraction and the extracted executable is hashed again against its own pin.
| Flag | Default | Description |
|---|---|---|
<tool> | (required) | Tool to install. Passing an unknown name fails and prints the available tools (today: syft, zarf). |
--dest <dir> | $HOME/.cilock/bin | Installation directory. |
--verify | false | Hash the already-installed executable against its embedded pin and exit — no download, no write. |
# Install the pinned Syft release to $HOME/.cilock/bin
cilock get syft
# Install Zarf into a repo-local bin directory
cilock get zarf --dest ./bin
# Confirm an existing installation still matches its pin
cilock get syft --verify
The install path is printed on success, along with the export PATH=… line needed to use it (on Windows, the directory to add to PATH). An existing installation is replaced atomically; on Windows the previous binary is backed up and restored if the swap fails, so a failed upgrade never destroys a working tool.
Upgrading a pin is a deliberate, reviewable change to the manifest in the cilock source tree — there is no --version flag, because a version selected at runtime would defeat the point of pinning.
cilock completion <shell>
Standard cobra completion. Supported shells: bash, zsh, fish, powershell.
cilock version
Prints cilock <version>. The version string is injected at build time via -ldflags="-X 'github.com/aflock-ai/rookery/cilock/cli.Version=<version>'".
cilock license
Prints the license under which this binary is distributed, plus any branded-distribution metadata baked in at build time. The stock cilock CLI is Apache 2.0, so a stock binary shows the Apache 2.0 statement. Binaries produced by the rookery-builder link the same CLI and likewise print the Apache 2.0 statement (the builder's own distribution terms are covered under licensing). Custom binaries built with --customer X --tenant Y additionally show:
Built for: X
Tenant: Y
The CustomerID and TenantID are injected via -ldflags="-X 'github.com/aflock-ai/rookery/cilock/cli.CustomerID=...' -X 'github.com/aflock-ai/rookery/cilock/cli.TenantID=...'".
Configuration
CI/lock is args-only: there is no config file. CLI flags (highest precedence), a small set of CILOCK_* env vars, and built-in defaults are the entire configuration surface. See Configuration for the override hierarchy. (The legacy .witness.yaml config file inherited from the witness lineage was removed deliberately — a config file in a cloned repo could silently override security-critical flags.)