# Make a recovery requirement executable

Source: https://www.testifysec.com/docs/cilock/recovery-policy

Evaluate successful and failed rehearsals against the same signed recovery policy.

Evaluate successful and failed rehearsals against the same signed recovery policy.

[Jump to the written guide ↓](https://www.testifysec.com/docs/cilock/recovery-policy#follow-along)

## Follow along

 

**Goal:** evaluate both recovery results against a signed policy, including the failed rehearsal. The command's success condition belongs in the policy; signing a result alone does not make it acceptable.

 

### Before you start

 

Complete [recording recovery evidence](https://www.testifysec.com/docs/cilock/recovery-rehearsal). You need `rehearsal.json`, `gap.json`, and the same source commit. Have an authorized policy signer prepare `policy/recovery.json` using the [policy schema](https://www.testifysec.com/docs/cilock/reference/policy-schema). It must require the `recovery-rehearsal` step, the relevant attestation types, and the permitted evidence producers.

 

The example policy attaches a Rego rule to the command-run attestation:

 

```rego
package commandrun
import rego.v1

deny contains msg if {
  input.exitcode != 0
  msg := "the restore did not recover every row"
}
```

 

This is the rule body, **not a complete policy file**. Add it through the policy schema's Rego configuration. It trusts your rehearsal to detect missing data; it does not independently query the database. Review [policy verification](https://www.testifysec.com/docs/cilock/concepts/policy-verification) before using your own test.

 

### 1. Inspect the intended policy

 

With `jq` installed:

 

```sh
jq . policy/recovery.json
cilock policy draft --help
cilock verify --help
```

 

**Expected:** the step names match the evidence, and your installed CI/lock supports the flags below. Confirm policy expiry, producer identities, the nonzero-exit rule, and subject requirements. Do not use an empty rule list for this exercise.

 

### 2. Bind the policy to your platform's trust configuration

 

Set `P` to your trusted platform origin. This example is for a local appliance running on loopback:

 

```sh
P=http://localhost:8080
cilock policy draft -f policy/recovery.json \
  --hydrate-local --platform-url "$P" \
  -o recovery.hydrated.json
```

 

**Expected:** a hydrated policy file. Inspect it before signing; do not blindly accept newly discovered roots. Hosted or remote environments require the verified HTTPS origin and trust configuration supplied by your administrator.

 

### 3. Sign the reviewed policy

 

Run as the authorized policy signer using that principal's supported approval flow:

 

```sh
cilock sign -f recovery.hydrated.json \
  -o recovery.signed.json \
  -t https://aflock.ai/policy/v0.1 --platform-url "$P"
```

 

**Expected:** a signed policy envelope. This does not publish the policy or activate it at a Pushgate repository. Those are separate operations with separate authorization.

 

### 4. Prepare offline verification inputs

 

Obtain `platform-trust.pem` from your administrator through a trusted channel. Set the expected policy signer email and issuer to the exact values your team authorized. Do not derive the expected identity from the untrusted evidence you are verifying.

 

```sh
POLICY_SIGNER_EMAIL=you@company.example
POLICY_ISSUER="$P/fulcio/oidc"
SUBJECT="sha1:$(git rev-parse HEAD)"
```

 

Replace the example email and confirm the issuer; do not assume every deployment uses this issuer path. The trust bundle must contain the required certificate and timestamp trust material for your release. Preserve the original recorded commit instead of using a later checkout's HEAD.

 

### 5. Verify the successful rehearsal

 

```sh
cilock verify --offline \
  -p recovery.signed.json -a rehearsal.json \
  --subjects "$SUBJECT" \
  --policy-ca-roots platform-trust.pem \
  --policy-timestamp-servers platform-trust.pem \
  --policy-emails "$POLICY_SIGNER_EMAIL" \
  --policy-fulcio-oidc-issuer "$POLICY_ISSUER" --format json
```

 

**Expected:** success for the required subject, producer, step, and rule. A missing root, issuer mismatch, or expired policy is a configuration failure, not a passing recovery check.

 

### 6. Verify the failed rehearsal

 

```sh
cilock verify --offline \
  -p recovery.signed.json -a gap.json \
  --subjects "$SUBJECT" \
  --policy-ca-roots platform-trust.pem \
  --policy-timestamp-servers platform-trust.pem \
  --policy-emails "$POLICY_SIGNER_EMAIL" \
  --policy-fulcio-oidc-issuer "$POLICY_ISSUER" --format json
```

 

**Expected:** a nonzero verification result identifying the recovery rule's denial. Keep stderr visible. A failure due to the wrong file or trust configuration does not demonstrate that this rule worked.

 

## Troubleshooting and next steps

 

If both results pass, inspect the actual signed policy and confirm the rule is attached to the command-run attestation. If both fail, first check identity, expiry, roots, step names, and subject binding. Keep the signed policy and both evidence records for review. Offline verification of these files does not establish that every appliance feature works without network access.

[Browse the other walkthroughs](https://www.testifysec.com/resources#walkthroughs)
