Policy schema
A cilock policy is a signed DSSE document that declares which attestation collections must appear, which functionaries are trusted to sign each step, and which OPA Rego rules must pass against attestation contents.
This page mirrors the witness policy schema, since cilock and witness use the same policy format. Source of truth:
witness/docs/concepts/policy.md. Cilock-specific notes are called out where they exist.
DSSE wrapperโ
Policies are JSON documents wrapped in a DSSE envelope and signed with cilock sign. Cilock accepts two payloadType values for the same schema:
https://aflock.ai/policy/v0.1 # current canonical
https://witness.testifysec.com/policy/v0.1 # legacy (still accepted; default for `cilock sign --datatype`)
The default of cilock sign --datatype is the legacy witness type for backward compatibility; witness-signed policies verify under cilock unchanged. Both constants live at rookery/attestation/policy/policy.go (PolicyPredicate, LegacyPolicyPredicate); cilock's verifier accepts either in rookery/cilock/internal/policy/validate.go.
Top-level policy objectโ
| Key | Type | Description |
|---|---|---|
expires | string | ISO-8601 timestamp. Evaluation of expired policies always fails. |
roots | object | Trusted X.509 root certificates. Keys are the root certificate's Key ID (sha256 of the cert), values are a root object. Used for X.509 functionaries. |
publickeys | object | Trusted public keys. Keys are the public key's Key ID (sha256 of the key, or KMS reference URI), values are a publickey object. |
steps | object | Expected steps that must appear to satisfy the policy. Keys are step names (must match cilock run --step <name>), values are a step object. |
timestampauthorities | object | Trusted X.509 roots for RFC 3161 timestamp authorities. Same shape as roots. |
root objectโ
| Key | Type | Description |
|---|---|---|
certificate | string | Base64-encoded PEM block of the X.509 root certificate. |
intermediates | array<string> | Base64-encoded PEM blocks of intermediate certificates belonging to certificate. |
publickey objectโ
| Key | Type | Description |
|---|---|---|
keyid | string | sha256 of the public key, or a KMS reference URI like awskms:///arn:aws:kms:... or gcpkms://projects/.... |
key | string | Base64-encoded PEM-formatted public key. May be omitted when keyid is a KMS URI and online verification is acceptable. |
step objectโ
| Key | Type | Description |
|---|---|---|
name | string | Step name. Must match a cilock run --step <name> invocation that produced an attestation collection. |
functionaries | array<functionary> | Identities trusted to sign attestation collections for this step. |
attestations | array<attestation> | Attestation types that must appear in the collection to satisfy this step. |
artifactsFrom | array<string> | Names of upstream steps. The materials of this step must match the products of every step listed here, chain-of-custody verification across the supply chain. |
functionary objectโ
| Key | Type | Description |
|---|---|---|
type | string | "root" or "publickey". |
certConstraint | certConstraint object | Constraints on the signer's X.509 certificate. Only valid when type = "root". |
publickeyid | string | Key ID of a trusted public key (must appear in policy publickeys). Only valid when type = "publickey". |
certConstraint objectโ
Every attribute must match the certificate exactly. A certificate must satisfy at least one constraint to pass. * is allowed as a wildcard if it's the only element in the array.
| Key | Type | Description |
|---|---|---|
commonname | string | Required Common Name on the cert subject. |
dnsnames | array<string> | Required DNS SANs. |
emails | array<string> | Required email SANs. |
organizations | array<string> | Required Organization fields on the subject. |
uris | array<string> | Required URI SANs, including SPIFFE IDs. |
roots | array<string> | Trust roots (Key IDs from policy roots) the cert must chain to. |
Wildcard constraint (allow any cert from a trusted root)โ
{
"commonname": "*",
"dnsnames": ["*"],
"emails": ["*"],
"organizations": ["*"],
"uris": ["*"],
"roots": ["*"]
}
SPIFFE ID constraintโ
{
"commonname": "*",
"dnsnames": ["*"],
"emails": ["*"],
"organizations": ["*"],
"uris": ["spiffe://example.com/step1"],
"roots": ["*"]
}
attestation objectโ
| Key | Type | Description |
|---|---|---|
type | string | Attestation predicate type URL. Cilock-native types use https://aflock.ai/attestations/<name>/v0.1; legacy witness types https://witness.dev/attestations/<name>/v0.1 are also accepted via aliases. See attestor catalog. |
regopolicies | array<regopolicy> | OPA Rego policies that will be run against the attestation. All must pass. |
regopolicy objectโ
| Key | Type | Description |
|---|---|---|
name | string | Name of the rego policy. Reported on failure. |
module | string | Base64-encoded Rego module. |
The Rego module must export a deny rule. deny should be a string or array of strings, populated only when the policy fails. Anything else the module outputs is ignored.
package commandrun.exitcode
deny[msg] {
input.exitcode != 0
msg := "exitcode not 0"
}
Verification processโ
cilock verify runs five checks in order, all must pass:
- Verify signatures on each collection against
policy.publickeysandpolicy.roots. Anything failing signature verification is dropped. - Map signers to functionaries: each collection's signer must satisfy a functionary entry for the step.
- Verify timestamps (if present) against
policy.timestampauthorities. The signing certificate must have been valid at the timestamped time. - Verify materials/products consistency: the materials of each step must match the products of any step in
artifactsFrom. - Evaluate every embedded Rego policy against its target attestation. All
denyrules must be empty.
Exit code 0 on pass, non-zero on any failure.
Worked exampleโ
A two-step policy where clone produces source files, build produces a binary, and the build's command-run is constrained by a Rego rule that the build command must be exactly go build -o=testapp .:
{
"expires": "2030-12-17T23:57:40-05:00",
"steps": {
"clone": {
"name": "clone",
"attestations": [
{ "type": "https://aflock.ai/attestations/material/v0.1" },
{ "type": "https://aflock.ai/attestations/command-run/v0.1" },
{ "type": "https://aflock.ai/attestations/product/v0.1" }
],
"functionaries": [
{ "type": "publickey", "publickeyid": "ae2dcc..." }
]
},
"build": {
"name": "build",
"artifactsFrom": ["clone"],
"attestations": [
{ "type": "https://aflock.ai/attestations/material/v0.1" },
{
"type": "https://aflock.ai/attestations/command-run/v0.1",
"regopolicies": [
{
"name": "expected command",
"module": "cGFja2FnZSBjb21tYW5kcnVuLmNtZAoKZGVueVttc2ddIHsKCWlucHV0LmNtZCAhPSBbImdvIiwgImJ1aWxkIiwgIi1vPXRlc3RhcHAiLCAiLiJdCgltc2cgOj0gInVuZXhwZWN0ZWQgY21kIgp9Cg=="
}
]
},
{ "type": "https://aflock.ai/attestations/product/v0.1" }
],
"functionaries": [
{ "type": "publickey", "publickeyid": "ae2dcc..." }
]
}
},
"publickeys": {
"ae2dcc...": {
"keyid": "ae2dcc...",
"key": "<base64 PEM>"
}
}
}
The base64 module above decodes to:
package commandrun.cmd
deny[msg] {
input.cmd != ["go", "build", "-o=testapp", "."]
msg := "unexpected cmd"
}
Sign this policy with cilock sign before distribution:
cilock sign --signer-file-key-path policy-key.pem -f policy.json -o policy-signed.json
For the full witness reference (which cilock mirrors), see witness/docs/concepts/policy.md.