Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion schemas/trace-claim.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"type": "object",
"required": ["platform", "measurement"],
"properties": {
"platform": {"type": "string", "enum": ["intel-tdx", "amd-sev-snp", "nvidia-h100", "nvidia-blackwell", "aws-nitro", "arm-cca", "google-confidential-space", "tpm2"]},
"platform": {"type": "string", "enum": ["intel-tdx", "amd-sev-snp", "nvidia-h100", "nvidia-blackwell", "aws-nitro", "arm-cca", "google-confidential-space", "tpm2", "software-only"]},
"measurement": {"type": "string", "pattern": "^sha(256:[0-9a-f]{64}|384:[0-9a-f]{96})$"},
"rim_uri": {"type": "string", "format": "uri"},
"nonce": {"type": "string"},
Expand Down
23 changes: 20 additions & 3 deletions src/trace_tests/modules/tr_rte.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,36 @@
"arm-cca",
"google-confidential-space",
"tpm2",
"software-only",
})
# Platforms that provide no hardware attestation evidence. Valid only at Level 0.
_DEV_PLATFORMS = frozenset({"software-only"})


def check(trace: dict[str, Any]) -> list[Finding]:
"""Return TR-RTE findings for the runtime / TEE platform claim."""
def check(trace: dict[str, Any], level: int = 0) -> list[Finding]:
"""Return TR-RTE findings for the runtime / TEE platform claim.

*level* is the conformance level being checked. Development-mode platforms
(e.g. ``software-only``) are accepted at Level 0 but rejected at Level 1+
because they carry no hardware attestation evidence.
"""
findings: list[Finding] = []
runtime = trace.get("runtime")

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

platform = runtime.get("platform")
if platform in _VALID_PLATFORMS:
if platform in _DEV_PLATFORMS:
if level == 0:
findings.append(Finding("TR-RTE-001", Status.PASS, f"runtime.platform is registered ({platform!r})"))
else:
findings.append(Finding(
"TR-RTE-001", Status.FAIL,
f"TR-RTE-001: runtime.platform {platform!r} is development-mode and not acceptable for "
f"hardware-attested levels (Level {level} requires a hardware TEE platform)",
))
elif platform in _VALID_PLATFORMS:
findings.append(Finding("TR-RTE-001", Status.PASS, f"runtime.platform is registered ({platform!r})"))
else:
findings.append(Finding(
Expand Down
2 changes: 1 addition & 1 deletion src/trace_tests/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def run(
results["TR-POL"] = tr_pol.check(trace)

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

if "TR-SCA" in active:
results["TR-SCA"] = tr_sca.check(trace)
Expand Down
87 changes: 87 additions & 0 deletions tests/test_software_only_platform.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
"""Tests for software-only platform handling in TR-RTE.

Spec note: trace-spec added `software-only` as a valid `runtime.platform`
value for development and CI use. It carries no hardware attestation evidence
and is therefore only acceptable at Level 0. Level 1+ must reject it with a
clear message that names the reason (development-mode, not hardware-attested)
rather than the generic "unknown platform" error.

Covers:
- software-only at Level 0 passes TR-RTE-001
- software-only at Level 1 fails TR-RTE-001 with a message mentioning "development-mode"
- software-only at Level 2 fails TR-RTE-001 with a message mentioning "development-mode"
- software-only is accepted by the JSON Schema (schema enum coverage)
"""

from __future__ import annotations

import copy

import jsonschema
import pytest

from trace_tests.modules import tr_rte
from trace_tests.result import Status

_SOFTWARE_ONLY_TRACE = {
"runtime": {
"platform": "software-only",
"measurement": "sha256:" + "a" * 64,
}
}


@pytest.mark.parametrize("level", [1, 2])
def test_software_only_fails_at_level(level):
"""software-only must fail TR-RTE-001 at Level 1 and Level 2."""
findings = tr_rte.check(_SOFTWARE_ONLY_TRACE, level=level)
platform_findings = [f for f in findings if f.code == "TR-RTE-001"]
assert platform_findings, "TR-RTE-001 finding expected"
assert all(f.failed() for f in platform_findings), (
f"software-only must fail TR-RTE-001 at Level {level}; got {platform_findings}"
)


@pytest.mark.parametrize("level", [1, 2])
def test_software_only_failure_mentions_development_mode(level):
"""Failure message for software-only must mention 'development-mode', not 'unknown'."""
findings = tr_rte.check(_SOFTWARE_ONLY_TRACE, level=level)
fail_findings = [f for f in findings if f.code == "TR-RTE-001" and f.failed()]
assert fail_findings, f"Expected TR-RTE-001 FAIL at Level {level}"
messages = " ".join(f.message.lower() for f in fail_findings)
assert "development-mode" in messages, (
f"TR-RTE-001 failure at Level {level} must mention 'development-mode'; "
f"got: {[f.message for f in fail_findings]}"
)
assert "unknown" not in messages, (
f"TR-RTE-001 failure at Level {level} must not say 'unknown platform'; "
f"got: {[f.message for f in fail_findings]}"
)


def test_software_only_passes_at_level0():
"""software-only must pass TR-RTE-001 at Level 0."""
findings = tr_rte.check(_SOFTWARE_ONLY_TRACE, level=0)
platform_findings = [f for f in findings if f.code == "TR-RTE-001"]
assert platform_findings, "TR-RTE-001 finding expected"
assert all(f.passed() for f in platform_findings), (
f"software-only must pass TR-RTE-001 at Level 0; got {platform_findings}"
)


def test_software_only_default_level_passes():
"""check() with no level argument defaults to Level 0 and passes software-only."""
findings = tr_rte.check(_SOFTWARE_ONLY_TRACE)
platform_findings = [f for f in findings if f.code == "TR-RTE-001"]
assert platform_findings, "TR-RTE-001 finding expected"
assert all(f.passed() for f in platform_findings), (
f"software-only must pass TR-RTE-001 at default level; got {platform_findings}"
)


def test_software_only_accepted_by_schema(schema, valid_level0):
"""software-only must be a valid enum value in the JSON Schema."""
record = copy.deepcopy(valid_level0)
record["runtime"]["platform"] = "software-only"
# Must not raise
jsonschema.validate(record, schema)
Loading