Skip to content

Commit ef4a800

Browse files
test: add integration tests with real firmware and UKI fixtures
Bring test coverage from 61% to 92% by adding integration tests that exercise MRTD computation, PE/COFF parsing, full register computation, and CLI commands against real OVMF and UKI binaries.
1 parent a091299 commit ef4a800

29 files changed

Lines changed: 882 additions & 7 deletions

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ build/
99

1010
# Testing
1111
.pytest_cache/
12+
tests/fixtures/firmware/*.fd
13+
tests/fixtures/uki/*.efi
1214

1315
# IDE
1416
.vscode/

.pre-commit-config.yaml

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,13 @@
11
repos:
2+
- repo: https://github.com/pre-commit/pre-commit-hooks
3+
rev: v5.0.0
4+
hooks:
5+
- id: check-yaml
6+
- id: check-toml
7+
- id: check-merge-conflict
8+
- id: check-added-large-files
9+
args: ["--maxkb=512"]
10+
211
- repo: https://github.com/gitleaks/gitleaks
312
rev: v8.21.2
413
hooks:
@@ -21,3 +30,33 @@ repos:
2130
hooks:
2231
- id: bandit
2332
args: ["-r", "src/"]
33+
34+
- repo: https://github.com/lucas-c/pre-commit-hooks
35+
rev: v1.5.5
36+
hooks:
37+
- id: insert-license
38+
files: \.py$
39+
args:
40+
- --license-filepath=LICENSE-HEADER
41+
- --comment-style=#
42+
43+
- repo: https://github.com/pypa/pip-audit
44+
rev: v2.7.3
45+
hooks:
46+
- id: pip-audit
47+
48+
- repo: https://github.com/commitizen-tools/commitizen
49+
rev: v4.4.1
50+
hooks:
51+
- id: commitizen
52+
stages: [commit-msg]
53+
54+
- repo: local
55+
hooks:
56+
- id: pytest-cov
57+
name: pytest with coverage
58+
entry: python3 -m pytest tests/ --cov=cvm_measure --cov-fail-under=80 -q
59+
language: system
60+
types: [python]
61+
pass_filenames: false
62+
always_run: true

LICENSE-HEADER

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
Copyright 2026 Cohere, Inc.
2+
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
7+
http://www.apache.org/licenses/LICENSE-2.0
8+
9+
Unless required by applicable law or agreed to in writing, software
10+
distributed under the License is distributed on an "AS IS" BASIS,
11+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
See the License for the specific language governing permissions and
13+
limitations under the License.

README.md

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,16 @@
66
[![PyPI](https://img.shields.io/pypi/v/cvm-measure)](https://pypi.org/project/cvm-measure/)
77
![License](https://img.shields.io/github/license/cohere-ai/cvm-measure)
88

9-
Compute expected Intel TDX register values (MRTD + RTMR[0-3]) from published inputs, entirely offline.
10-
11-
`cvm-measure` is the TDX equivalent of [sev-snp-measure](https://github.com/virtee/sev-snp-measure) for AMD SEV-SNP. It takes firmware, UKI, baseline, and RAM topology as inputs and produces the hex register values that a correctly-launched CVM should report.
9+
Compute expected confidential VM register values from published inputs, entirely offline. `cvm-measure` takes firmware, UKI, baseline, and RAM topology as inputs and produces the hex register values that a correctly-launched CVM should report, letting you verify attestation without booting a VM.
1210

1311
**Zero dependencies.** Python 3.10+ standard library only.
1412

13+
### Supported Hardware
14+
15+
| Platform | Technology | Registers | Status |
16+
|----------|------------|-----------|--------|
17+
| Intel | [TDX](https://www.intel.com/content/www/us/en/developer/tools/trust-domain-extensions/overview.html) | MRTD, RTMR[0-3] | Supported |
18+
1519
## Install
1620

1721
```bash
@@ -48,6 +52,31 @@ rtmr2: 5e8f3a...
4852
rtmr3: 000000...
4953
```
5054

55+
### JSON output
56+
57+
Add `--output-format json` for machine-readable output, useful for CI pipelines and scripting:
58+
59+
```bash
60+
cvm-measure tdx \
61+
--firmware OVMF.fd \
62+
--uki BOOTX64.EFI \
63+
--baseline baseline.json \
64+
--ram 234 \
65+
--output-format json
66+
```
67+
68+
Output:
69+
70+
```json
71+
{
72+
"mrtd": "3a7b2c...",
73+
"rtmr0": "8f4e1d...",
74+
"rtmr1": "c2a9b7...",
75+
"rtmr2": "5e8f3a...",
76+
"rtmr3": "000000..."
77+
}
78+
```
79+
5180
### Multi-NUMA topology
5281

5382
```bash
@@ -129,7 +158,7 @@ A baseline file contains SHA-384 digests for events that **cannot be computed of
129158
- **Boot variables**: BootOrder, Boot0000-Boot0003
130159
- **GPT**: Disk partition table hash
131160

132-
Baselines are **not shipped with this tool**. They are data artifacts published alongside each CVM image release by the operator.
161+
Baselines are **not shipped with this tool**. Cohere publishes baselines in the [cohere-cc-baselines](https://github.com/cohere-ai/cohere-cc-baselines) repository, organized by provider, platform, and machine type.
133162

134163
### How baselines are created
135164

pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
55
[project]
66
name = "cvm-measure"
77
version = "0.1.0"
8-
description = "Compute expected TDX register values (MRTD + RTMR) from firmware, UKI, and baseline inputs"
8+
description = "Compute expected confidential VM register values from firmware, UKI, and baseline inputs"
99
requires-python = ">=3.10"
1010
license = {text = "Apache-2.0"}
1111
readme = "README.md"
@@ -14,6 +14,7 @@ dependencies = []
1414
[project.optional-dependencies]
1515
dev = [
1616
"pytest",
17+
"pytest-cov",
1718
"mypy",
1819
"ruff",
1920
]

src/cvm_measure/__init__.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
# Copyright 2026 Cohere, Inc.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
115
"""cvm-measure: compute expected TDX register values from published inputs."""
216

317
__version__ = "0.1.0"

src/cvm_measure/__main__.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
# Copyright 2026 Cohere, Inc.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
115
"""Allow running as: python -m cvm_measure"""
216

317
from .cli import main

src/cvm_measure/cli.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
# Copyright 2026 Cohere, Inc.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
115
"""CLI entry point for cvm-measure.
216
317
Usage:
@@ -95,6 +109,8 @@ def _resolve_rtmr3(args: argparse.Namespace, parser: argparse.ArgumentParser) ->
95109
parser.error("--initdata and --rtmr3 are mutually exclusive")
96110

97111
if args.initdata is not None:
112+
_require_file(args.initdata, "--initdata")
113+
98114
from .tdx.initdata import compute_digest
99115
from .tdx.rtmr import SHA384_SIZE, extend_rtmr
100116

@@ -105,12 +121,19 @@ def _resolve_rtmr3(args: argparse.Namespace, parser: argparse.ArgumentParser) ->
105121
return args.rtmr3
106122

107123

124+
def _require_file(path: Path, flag: str) -> None:
125+
if not path.exists():
126+
print(f"error: {flag} file not found: {path}", file=sys.stderr)
127+
sys.exit(1)
128+
129+
108130
def _cmd_compute(args: argparse.Namespace, parser: argparse.ArgumentParser) -> None:
109131
if args.firmware is None:
110132
parser.error("--firmware is required")
111133
if args.ram is None:
112134
parser.error("--ram is required")
113135

136+
_require_file(args.firmware, "--firmware")
114137
firmware = args.firmware.read_bytes()
115138

116139
if args.mode == "mrtd":
@@ -133,6 +156,9 @@ def _cmd_compute(args: argparse.Namespace, parser: argparse.ArgumentParser) -> N
133156

134157
from .tdx import compute_all_registers, load_baseline
135158

159+
_require_file(args.uki, "--uki")
160+
_require_file(args.baseline, "--baseline")
161+
136162
uki = args.uki.read_bytes()
137163
baseline = load_baseline(args.baseline)
138164

@@ -163,6 +189,7 @@ def _cmd_extract_baseline(args: argparse.Namespace) -> None:
163189

164190
from .tdx.baseline import extract_from_ccel, save
165191

192+
_require_file(args.ccel, "--ccel")
166193
ccel_data = args.ccel.read_bytes()
167194
baseline = extract_from_ccel(ccel_data, args.machine_type)
168195

@@ -194,6 +221,7 @@ def _cmd_replay(args: argparse.Namespace) -> None:
194221
from .tdx.ccel import parse_event_log
195222
from .tdx.rtmr import replay_event_log
196223

224+
_require_file(args.ccel, "--ccel")
197225
ccel_data = args.ccel.read_bytes()
198226
log = parse_event_log(ccel_data)
199227
rtmrs = replay_event_log(log)

src/cvm_measure/tdx/__init__.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
# Copyright 2026 Cohere, Inc.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
115
"""cvm_measure.tdx -- Intel TDX register computation.
216
317
Public API:

src/cvm_measure/tdx/baseline.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
# Copyright 2026 Cohere, Inc.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
115
"""Baseline management for non-computable event digests.
216
317
Stores event data that cannot be computed from firmware, UKI, or

0 commit comments

Comments
 (0)