Skip to content

Commit 773e2ae

Browse files
fix: accept software-only platform at Level 0, reject with clear message at Level 1+ (#16) (#17)
- schemas/trace-claim.json: add "software-only" to the platform enum so the JSON Schema validator no longer rejects it outright. - tr_rte.py: introduce _DEV_PLATFORMS set; check() now accepts an optional level parameter (default 0, matching the TR-SIG pattern). software-only passes TR-RTE-001 at Level 0 and fails with a "development-mode" message at Level 1+, replacing the misleading "unknown platform" error. - runner.py: pass level to tr_rte.check() so the runner propagates the conformance level correctly. - tests/test_software_only_platform.py: 7 new tests covering Level 0 pass, Level 1 and 2 fail, message content, schema acceptance, and default-level behavior. Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent ee4b6dd commit 773e2ae

4 files changed

Lines changed: 109 additions & 5 deletions

File tree

‎schemas/trace-claim.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
"type": "object",
2929
"required": ["platform", "measurement"],
3030
"properties": {
31-
"platform": {"type": "string", "enum": ["intel-tdx", "amd-sev-snp", "nvidia-h100", "nvidia-blackwell", "aws-nitro", "arm-cca", "google-confidential-space", "tpm2"]},
31+
"platform": {"type": "string", "enum": ["intel-tdx", "amd-sev-snp", "nvidia-h100", "nvidia-blackwell", "aws-nitro", "arm-cca", "google-confidential-space", "tpm2", "software-only"]},
3232
"measurement": {"type": "string", "pattern": "^sha(256:[0-9a-f]{64}|384:[0-9a-f]{96})$"},
3333
"rim_uri": {"type": "string", "format": "uri"},
3434
"nonce": {"type": "string"},

‎src/trace_tests/modules/tr_rte.py‎

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,36 @@
1717
"arm-cca",
1818
"google-confidential-space",
1919
"tpm2",
20+
"software-only",
2021
})
22+
# Platforms that provide no hardware attestation evidence. Valid only at Level 0.
23+
_DEV_PLATFORMS = frozenset({"software-only"})
2124

2225

23-
def check(trace: dict[str, Any]) -> list[Finding]:
24-
"""Return TR-RTE findings for the runtime / TEE platform claim."""
26+
def check(trace: dict[str, Any], level: int = 0) -> list[Finding]:
27+
"""Return TR-RTE findings for the runtime / TEE platform claim.
28+
29+
*level* is the conformance level being checked. Development-mode platforms
30+
(e.g. ``software-only``) are accepted at Level 0 but rejected at Level 1+
31+
because they carry no hardware attestation evidence.
32+
"""
2533
findings: list[Finding] = []
2634
runtime = trace.get("runtime")
2735

2836
if not isinstance(runtime, dict):
2937
return [Finding("TR-RTE-001", Status.FAIL, "TR-RTE-001: runtime field is missing or not an object")]
3038

3139
platform = runtime.get("platform")
32-
if platform in _VALID_PLATFORMS:
40+
if platform in _DEV_PLATFORMS:
41+
if level == 0:
42+
findings.append(Finding("TR-RTE-001", Status.PASS, f"runtime.platform is registered ({platform!r})"))
43+
else:
44+
findings.append(Finding(
45+
"TR-RTE-001", Status.FAIL,
46+
f"TR-RTE-001: runtime.platform {platform!r} is development-mode and not acceptable for "
47+
f"hardware-attested levels (Level {level} requires a hardware TEE platform)",
48+
))
49+
elif platform in _VALID_PLATFORMS:
3350
findings.append(Finding("TR-RTE-001", Status.PASS, f"runtime.platform is registered ({platform!r})"))
3451
else:
3552
findings.append(Finding(

‎src/trace_tests/runner.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ def run(
4141
results["TR-POL"] = tr_pol.check(trace)
4242

4343
if "TR-RTE" in active:
44-
results["TR-RTE"] = tr_rte.check(trace)
44+
results["TR-RTE"] = tr_rte.check(trace, level)
4545

4646
if "TR-SCA" in active:
4747
results["TR-SCA"] = tr_sca.check(trace)
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
"""Tests for software-only platform handling in TR-RTE.
2+
3+
Spec note: trace-spec added `software-only` as a valid `runtime.platform`
4+
value for development and CI use. It carries no hardware attestation evidence
5+
and is therefore only acceptable at Level 0. Level 1+ must reject it with a
6+
clear message that names the reason (development-mode, not hardware-attested)
7+
rather than the generic "unknown platform" error.
8+
9+
Covers:
10+
- software-only at Level 0 passes TR-RTE-001
11+
- software-only at Level 1 fails TR-RTE-001 with a message mentioning "development-mode"
12+
- software-only at Level 2 fails TR-RTE-001 with a message mentioning "development-mode"
13+
- software-only is accepted by the JSON Schema (schema enum coverage)
14+
"""
15+
16+
from __future__ import annotations
17+
18+
import copy
19+
20+
import jsonschema
21+
import pytest
22+
23+
from trace_tests.modules import tr_rte
24+
from trace_tests.result import Status
25+
26+
_SOFTWARE_ONLY_TRACE = {
27+
"runtime": {
28+
"platform": "software-only",
29+
"measurement": "sha256:" + "a" * 64,
30+
}
31+
}
32+
33+
34+
@pytest.mark.parametrize("level", [1, 2])
35+
def test_software_only_fails_at_level(level):
36+
"""software-only must fail TR-RTE-001 at Level 1 and Level 2."""
37+
findings = tr_rte.check(_SOFTWARE_ONLY_TRACE, level=level)
38+
platform_findings = [f for f in findings if f.code == "TR-RTE-001"]
39+
assert platform_findings, "TR-RTE-001 finding expected"
40+
assert all(f.failed() for f in platform_findings), (
41+
f"software-only must fail TR-RTE-001 at Level {level}; got {platform_findings}"
42+
)
43+
44+
45+
@pytest.mark.parametrize("level", [1, 2])
46+
def test_software_only_failure_mentions_development_mode(level):
47+
"""Failure message for software-only must mention 'development-mode', not 'unknown'."""
48+
findings = tr_rte.check(_SOFTWARE_ONLY_TRACE, level=level)
49+
fail_findings = [f for f in findings if f.code == "TR-RTE-001" and f.failed()]
50+
assert fail_findings, f"Expected TR-RTE-001 FAIL at Level {level}"
51+
messages = " ".join(f.message.lower() for f in fail_findings)
52+
assert "development-mode" in messages, (
53+
f"TR-RTE-001 failure at Level {level} must mention 'development-mode'; "
54+
f"got: {[f.message for f in fail_findings]}"
55+
)
56+
assert "unknown" not in messages, (
57+
f"TR-RTE-001 failure at Level {level} must not say 'unknown platform'; "
58+
f"got: {[f.message for f in fail_findings]}"
59+
)
60+
61+
62+
def test_software_only_passes_at_level0():
63+
"""software-only must pass TR-RTE-001 at Level 0."""
64+
findings = tr_rte.check(_SOFTWARE_ONLY_TRACE, level=0)
65+
platform_findings = [f for f in findings if f.code == "TR-RTE-001"]
66+
assert platform_findings, "TR-RTE-001 finding expected"
67+
assert all(f.passed() for f in platform_findings), (
68+
f"software-only must pass TR-RTE-001 at Level 0; got {platform_findings}"
69+
)
70+
71+
72+
def test_software_only_default_level_passes():
73+
"""check() with no level argument defaults to Level 0 and passes software-only."""
74+
findings = tr_rte.check(_SOFTWARE_ONLY_TRACE)
75+
platform_findings = [f for f in findings if f.code == "TR-RTE-001"]
76+
assert platform_findings, "TR-RTE-001 finding expected"
77+
assert all(f.passed() for f in platform_findings), (
78+
f"software-only must pass TR-RTE-001 at default level; got {platform_findings}"
79+
)
80+
81+
82+
def test_software_only_accepted_by_schema(schema, valid_level0):
83+
"""software-only must be a valid enum value in the JSON Schema."""
84+
record = copy.deepcopy(valid_level0)
85+
record["runtime"]["platform"] = "software-only"
86+
# Must not raise
87+
jsonschema.validate(record, schema)

0 commit comments

Comments
 (0)