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
6 changes: 4 additions & 2 deletions src/agentrust_trace/platform_measurement.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,11 @@ def check_platform_measurement(
if appraiser is None:
return NOT_ATTEMPTED
runtime = record.get("runtime")
if not isinstance(runtime, dict) or runtime.get("measurement") is None:
if not isinstance(runtime, dict):
return PlatformMeasurementCheck(outcome="not_attempted", cause="field_absent")
measurement = runtime.get("measurement")
if not isinstance(measurement, str) or not measurement:
return PlatformMeasurementCheck(outcome="not_attempted", cause="field_absent")
measurement = runtime["measurement"]

try:
report = appraiser(copy.deepcopy(runtime))
Expand Down
15 changes: 13 additions & 2 deletions tests/test_platform_measurement.py
Original file line number Diff line number Diff line change
Expand Up @@ -308,8 +308,19 @@ def test_P9_a_non_callable_appraiser_is_refused_at_entry(junk: Any) -> None:
def test_P9_a_non_object_record_is_refused_and_a_missing_measurement_is_field_absent() -> None:
with pytest.raises(ValueError):
check_platform_measurement(["not", "a", "record"], None) # type: ignore[arg-type]
absent = check_platform_measurement({"runtime": {}}, lambda runtime: None)
assert (absent.outcome, absent.cause) == ("not_attempted", "field_absent")
for bad_runtime in (
{},
{"measurement": None},
{"measurement": ""},
{"measurement": 123},
{"measurement": True},
{"measurement": ["sha256:aa"]},
):
absent = check_platform_measurement(
{"runtime": bad_runtime},
lambda rt: {"measurement": rt.get("measurement"), "layers": {"pcr:0": "established"}},
)
assert (absent.outcome, absent.cause) == ("not_attempted", "field_absent")


def test_P10_a_record_that_fails_verification_never_reaches_the_appraiser() -> None:
Expand Down
24 changes: 24 additions & 0 deletions tests/test_trust_record_verify_citations_and_platform.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,22 @@ def ts_results() -> dict[str, Any]:
out.checks.badPlatformAppraiser = await codeOf(() =>
trace.verifyRecord({}, { platformAppraiser: 123 })
);
out.checks.nonStringMeasurements = [];
const badRuntimes = [
{},
{ measurement: null },
{ measurement: "" },
{ measurement: 123 },
{ measurement: true },
{ measurement: ["sha256:aa"] },
];
for (const badRuntime of badRuntimes) {
const pm = await trace.checkPlatformMeasurement(
{ runtime: badRuntime },
(rt) => ({ measurement: rt.measurement, layers: { "pcr:0": "established" } })
);
out.checks.nonStringMeasurements.push([pm.outcome, pm.cause]);
}

process.stdout.write(JSON.stringify(out));
"""
Expand Down Expand Up @@ -209,3 +225,11 @@ def test_ts_platform_measurement_vector(path: pathlib.Path, ts_results: dict[str
def test_ts_invalid_callback_options_rejected_at_entry(ts_results: dict[str, Any]) -> None:
assert ts_results["checks"]["badCitationResolver"] == "invalid_argument"
assert ts_results["checks"]["badPlatformAppraiser"] == "invalid_argument"


def test_ts_non_string_or_empty_runtime_measurement_is_field_absent(
ts_results: dict[str, Any],
) -> None:
assert ts_results["checks"]["nonStringMeasurements"] == [
["not_attempted", "field_absent"]
] * 6
2 changes: 1 addition & 1 deletion trust-record-verify/src/platform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ export async function checkPlatformMeasurement(
return FIELD_ABSENT;
}
const measurement = own(runtime, "measurement");
if (measurement === undefined || measurement === null) {
if (typeof measurement !== "string" || measurement === "") {
return FIELD_ABSENT;
}

Expand Down
Loading