Skip to content

Commit 75e6066

Browse files
committed
docs: verification commands for signed images
Extend docs/docker-image-policy.md with a Verification section covering gh attestation verify, cosign verify-attestation, a build-age (soak) gate using SLSA finishedOn, and a note on digest-pinned deploys.
1 parent 3fb641b commit 75e6066

1 file changed

Lines changed: 54 additions & 0 deletions

File tree

docs/docker-image-policy.md

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,60 @@ Additional tags applied automatically:
3838
- **PR number** (e.g., `pr-123`)
3939
- **Git tag** (e.g., `v2.1.0`); agent releases use `agents-*` tags which also produce semver tags
4040

41+
## Verification
42+
43+
All images pushed by `rust-docker.yml`, `monorepo-docker.yml`, and `node-services-docker.yml` carry a SLSA v1 build-provenance attestation, signed keyless via GitHub Actions OIDC and attached to the image digest as an OCI referrer.
44+
45+
The attestation identifies:
46+
47+
- repository: `hyperlane-xyz/hyperlane-monorepo`
48+
- workflow: the producing `.github/workflows/*.yml`
49+
- commit SHA
50+
- runner / builder
51+
- `startedOn` / `finishedOn` build timestamps
52+
53+
### Verify with `gh`
54+
55+
```bash
56+
gh attestation verify \
57+
oci://ghcr.io/hyperlane-xyz/hyperlane-agent:<tag-or-digest> \
58+
--repo hyperlane-xyz/hyperlane-monorepo
59+
```
60+
61+
Add `--signer-workflow hyperlane-xyz/hyperlane-monorepo/.github/workflows/rust-docker.yml` to pin the producing workflow.
62+
63+
### Verify with `cosign`
64+
65+
```bash
66+
cosign verify-attestation \
67+
--type slsaprovenance1 \
68+
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
69+
--certificate-identity-regexp '^https://github.com/hyperlane-xyz/hyperlane-monorepo/\.github/workflows/rust-docker\.yml@' \
70+
ghcr.io/hyperlane-xyz/hyperlane-agent@<digest>
71+
```
72+
73+
### Minimum build age (soak time)
74+
75+
Provenance timestamps enable a "cool-off" gate in promotion pipelines. Extract `finishedOn` and compare against `now - soak`:
76+
77+
```bash
78+
FINISHED=$(cosign verify-attestation \
79+
--type slsaprovenance1 \
80+
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
81+
--certificate-identity-regexp '^https://github.com/hyperlane-xyz/hyperlane-monorepo/\.github/workflows/rust-docker\.yml@' \
82+
ghcr.io/hyperlane-xyz/hyperlane-agent@<digest> \
83+
| jq -r '.payload | @base64d | fromjson | .predicate.runDetails.metadata.finishedOn')
84+
85+
AGE=$(( $(date -u +%s) - $(date -u -d "$FINISHED" +%s) ))
86+
[ "$AGE" -ge 86400 ] || { echo "image younger than 24h"; exit 1; }
87+
```
88+
89+
Staging typically needs no soak; production can require ≥24h.
90+
91+
### Pin deploys by digest
92+
93+
Tags are mutable. For verification guarantees to hold end-to-end, promotion/deploy should resolve tag → digest once, verify the digest, then deploy the digest. See `typescript/infra/config/docker.ts` for the deployed-tag surface.
94+
4195
## Retention
4296

4397
| Image type | Retention | Notes |

0 commit comments

Comments
 (0)