Release Pipeline
Mero TEE ships two coupled artifact families from one monorepo: the
mero-kms-phala container (a Phala Cloud KMS) and the mero-tee GCP node image.
Each has its own release workflow, but they share a version number and a
measurement contract. This page traces the real pipeline: bump → build →
attest/measure → sign → publish → catalog.
Version coupling
Section titled “Version coupling”The KMS version and the node-image version move together. The release version
sync guard (release-version-sync-guard.yaml → scripts/policy/check_release_version_sync.sh)
fails a PR unless all three agree:
mero-kms/Cargo.tomlpackage.versionmero-tee/versions.jsonimageVersion- the
mero-kms-phalaentry inCargo.lock
versions.json merodVersion is decoupled — it pins the calimero-network/core
merod tag baked into the node image.
KMS release — release-kms-phala.yaml
Section titled “KMS release — release-kms-phala.yaml”Workflow name Release mero-kms. Triggers: push to master touching
mero-kms/**, Cargo.toml, Cargo.lock, or the KMS scripts/workflows; plus PR
(dry-run) and workflow_dispatch.
-
prepare— resolve the version and release tags (get-version-info.sh), validate the merod attestation-config helper scripts. -
build-binaries— compile themero-kms-phalabinary forx86_64and (on non-PR runs)aarch64, upload as artifacts. -
release-container— build and push a multi-arch image toghcr.io/calimero-network/mero-kms-phala, one tag set per profile (debug,debug-read-only,locked-read-only), and attest each image’s build provenance (actions/attest-build-provenance). -
probe— for each profile, dispatch the staging probe (kms-phala-staging-probe.yaml) against a real Phala CVM and wait. The probe returnskms-policy-candidates.json(measured MRTD/RTMR/TCB values) andkms-app-identity.json(the dstackcompose_hash). -
release-metadata— the assembly step:- Wait for and fetch the counterpart node release’s
published-mrtds.json. - Generate the SBOMs with Syft (
syftover the container and the binaries). - Build the per-profile attestation policy JSON from the probe candidates and the node MRTDs, plus a compatibility map and container-metadata file.
- Write
kms-phala-checksums.txt(SHA-256 of all assets). - Sign every asset with cosign keyless (Sigstore / Fulcio / Rekor),
producing
<asset>.bundle.jsonsidecars, then verify the signatures. - Publish the GitHub release
mero-kms-v<version>with all assets.
- Wait for and fetch the counterpart node release’s
KMS release assets
Section titled “KMS release assets”Uploaded to the mero-kms-v<version> release (each with a .bundle.json
Sigstore sidecar):
kms-phala-attestation-policy.<profile>.json(one per profile) and the legacy profile-lesskms-phala-attestation-policy.jsonkms-phala-checksums.txtkms-phala-container-sbom.spdx.json,kms-phala-binaries-sbom.spdx.jsonkms-phala-release-manifest.json,kms-phala-container-metadata.jsonkms-phala-compatibility-map.json,kms-phala-rekor-index.json
Node-image release — release-node-image-gcp.yaml
Section titled “Node-image release — release-node-image-gcp.yaml”Workflow name Release mero-tee. Triggers: push to master touching
mero-tee/versions.json; plus workflow_dispatch.
-
preflight— a release gate that resolves the target merod version and verifies thecalimero-network/corerelease tag (and its required tarball assets) actually exists, so the image build is blocked until core ships. ReadsimageVersionfromversions.json. -
profile_pipeline(matrix over the three profiles) — the measurement step, which unlike the KMS path must boot a real TDX VM:- Run
build-and-release.sh <profile>(Packer + Ansible) to build the GCP image. - Create an ephemeral firewall rule and a
c3-standard-4Intel TDX VM from the new image. - Collect TEE info and a TDX quote from the node’s admin API, then verify the quote externally against Intel Trust Authority.
- Emit
mrtd-<profile>.json(MRTD + RTMR0–3), a provenance record, and the attestation artifacts.
- Run
-
cleanup_attestation_resources— tear down the ephemeral VM and firewall rule. -
publish_mrtds— assemblepublished-mrtds.json(per-profile measurements) withassemble-published-mrtd-payload.sh, generate the SBOM, cosign-sign the assets (.sig+.pem), and publish the GitHub releasemero-tee-v<version>.
Node-image release assets
Section titled “Node-image release assets”Uploaded to mero-tee-v<version> (each with .sig and .pem sidecars):
published-mrtds.json— expected MRTD/RTMR0–3 for each profilerelease-provenance.jsonnode-image-gcp-release-sbom.spdx.jsonnode-image-gcp-checksums.txt
Compatibility catalog
Section titled “Compatibility catalog”compatibility-catalog.json is the source of truth for which KMS and node-image
versions pair. It is rebuilt by update-compatibility-catalog.yaml on every
release: published event (and on demand), by enumerating published
mero-kms-v* tags and pairing each with the identically-versioned node tag:
{ "schema_version": 1, "releases": [ { "version": "2.3.13", "kms_tag": "mero-kms-v2.3.13", "node_image_tag": "mero-tee-v2.3.13", "kms_policy_url": "https://github.com/calimero-network/mero-tee/releases/download/mero-kms-v2.3.13/kms-phala-attestation-policy.json", "node_policy_url": "https://github.com/calimero-network/mero-tee/releases/download/mero-tee-v2.3.13/published-mrtds.json" } ]}Guards and audits
Section titled “Guards and audits”| Workflow | Trigger | What it enforces |
|---|---|---|
release-version-sync-guard.yaml |
PR / push to master | KMS Cargo.toml, versions.json, and Cargo.lock versions agree. |
docs-update-guard.yaml |
PR | Changes under .github/workflows/, scripts/, or mero-tee/** ship with a docs/** / README.md / CHANGELOG.md update. |
ci-kms-phala.yaml |
PR / push (KMS paths) | cargo fmt + clippy -D warnings + tests on mero-kms-phala. |
security-audit.yaml |
Weekly (Mon 04:00) / PR | cargo audit against the advisory database. |
release-auditor.yaml |
Weekly (Mon 03:30) / dispatch | Re-verifies recent releases’ assets and cosign signatures. |
post-release-kms-node-e2e.yaml |
workflow_run after Release mero-tee |
KMS↔node compatibility e2e on the released artifacts. |
post-release-mero-tee-node-e2e.yaml |
workflow_run after Release mero-tee |
Boots fresh TDX VMs and checks their measurement candidates are covered by published-mrtds.json — without waiting on the KMS. |
Degraded policy state (policy_not_ready)
Section titled “Degraded policy state (policy_not_ready)”When the KMS has no usable policy (e.g. MERO_KMS_VERSION unset, or the release
policy fetch failed), it starts in a fail-closed degraded mode: /attest
still answers, but /get-key returns 503 policy_not_ready.
Next steps
Section titled “Next steps”- Configuration reference — the versions and env vars this pipeline consumes.
- Runbooks — deploying and probing a published release.
- Policy management — how the attestation policy governs key release.