litzki-sovp-agentrust-bridge 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,11 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ .pytest_cache/
4
+ .venv/
5
+ dist/
6
+ build/
7
+ *.egg-info/
8
+
9
+ # Private signing keys — never commit (demo keys are generated locally, see README)
10
+ *-private.pem
11
+ *.key
@@ -0,0 +1,77 @@
1
+ Metadata-Version: 2.5
2
+ Name: litzki-sovp-agentrust-bridge
3
+ Version: 0.1.0
4
+ Summary: SOVP to AgenTrust TRACE bridge
5
+ License: Apache-2.0
6
+ Requires-Python: >=3.11
7
+ Requires-Dist: agent-manifest>=0.11.1
8
+ Requires-Dist: agentrust-trace-tests>=0.5.1
9
+ Requires-Dist: agentrust-trace>=0.9.0
10
+ Requires-Dist: cmcp-runtime>=0.4.0
11
+ Requires-Dist: cryptography<51,>=42
12
+ Description-Content-Type: text/markdown
13
+
14
+ # Litzki SOVP AgenTrust Integration
15
+
16
+ Exports SOVP attestation results as signed AgenTrust TRACE records.
17
+
18
+ ## What it does
19
+
20
+ This integration provides a Python adapter that:
21
+
22
+ - loads a SOVP attestation result from JSON;
23
+ - maps explicitly supplied SOVP and AgenTrust fields into a TRACE envelope;
24
+ - signs the TRACE envelope with Ed25519 over a canonical JSON pre-image that excludes only the `signature` field;
25
+ - writes the signed record as JSON for downstream validation with `agentrust-trace-tests`.
26
+
27
+ ## What it does not claim
28
+
29
+ - It does not certify SOVP or any SOVP deployment.
30
+ - It does not call non-attested data attested.
31
+ - It does not mark the integration as Verified until the generated records pass `agentrust-trace-tests` in CI or a reviewer reproduction environment.
32
+
33
+ ## Installation
34
+
35
+ ```bash
36
+ python -m pip install -e integrations/litzki-sovp
37
+ ```
38
+
39
+ The package declares runtime dependencies on released PyPI packages: `cmcp-runtime`, `agentrust-trace`, `agentrust-trace-tests`, and `agent-manifest`.
40
+
41
+ ## Input contract
42
+
43
+ The adapter expects a JSON object with an `agentrust` object containing the TRACE envelope fields and a `sovp` object containing the source attestation payload. The adapter only signs fields present in `agentrust`; it does not infer missing attestation claims.
44
+
45
+ See `examples/sovp-attestation.json` for the minimal local fixture shape.
46
+
47
+ ## Usage
48
+
49
+ First generate a local Ed25519 signing key. This is a throwaway demo key; it is
50
+ git-ignored and must not be committed. Use a persistent, protected key for any
51
+ record you intend to be re-verified later.
52
+
53
+ ```bash
54
+ openssl genpkey -algorithm Ed25519 \
55
+ -out integrations/litzki-sovp/examples/ed25519-private.pem
56
+ ```
57
+
58
+ Then produce a signed TRACE record:
59
+
60
+ ```bash
61
+ litzki-sovp-trace \
62
+ --input integrations/litzki-sovp/examples/sovp-attestation.json \
63
+ --private-key integrations/litzki-sovp/examples/ed25519-private.pem \
64
+ --output /tmp/sovp.trace.json
65
+ ```
66
+
67
+ ## Reproduction target
68
+
69
+ ```bash
70
+ python -m pytest integrations/litzki-sovp/tests
71
+ trace-tests verify --record /tmp/sovp.trace.json --level 0
72
+ ```
73
+
74
+ The generated record passes TRACE conformance at **Level 0** (`TR-ENV`, `TR-SIG`,
75
+ `TR-POL`). Level 0 is the honest ceiling for this bridge: it transcribes a SOVP
76
+ attestation rather than measuring a hardware TEE, so `runtime.platform` is
77
+ `software-only`, which the suite accepts only at Level 0.
@@ -0,0 +1,64 @@
1
+ # Litzki SOVP AgenTrust Integration
2
+
3
+ Exports SOVP attestation results as signed AgenTrust TRACE records.
4
+
5
+ ## What it does
6
+
7
+ This integration provides a Python adapter that:
8
+
9
+ - loads a SOVP attestation result from JSON;
10
+ - maps explicitly supplied SOVP and AgenTrust fields into a TRACE envelope;
11
+ - signs the TRACE envelope with Ed25519 over a canonical JSON pre-image that excludes only the `signature` field;
12
+ - writes the signed record as JSON for downstream validation with `agentrust-trace-tests`.
13
+
14
+ ## What it does not claim
15
+
16
+ - It does not certify SOVP or any SOVP deployment.
17
+ - It does not call non-attested data attested.
18
+ - It does not mark the integration as Verified until the generated records pass `agentrust-trace-tests` in CI or a reviewer reproduction environment.
19
+
20
+ ## Installation
21
+
22
+ ```bash
23
+ python -m pip install -e integrations/litzki-sovp
24
+ ```
25
+
26
+ The package declares runtime dependencies on released PyPI packages: `cmcp-runtime`, `agentrust-trace`, `agentrust-trace-tests`, and `agent-manifest`.
27
+
28
+ ## Input contract
29
+
30
+ The adapter expects a JSON object with an `agentrust` object containing the TRACE envelope fields and a `sovp` object containing the source attestation payload. The adapter only signs fields present in `agentrust`; it does not infer missing attestation claims.
31
+
32
+ See `examples/sovp-attestation.json` for the minimal local fixture shape.
33
+
34
+ ## Usage
35
+
36
+ First generate a local Ed25519 signing key. This is a throwaway demo key; it is
37
+ git-ignored and must not be committed. Use a persistent, protected key for any
38
+ record you intend to be re-verified later.
39
+
40
+ ```bash
41
+ openssl genpkey -algorithm Ed25519 \
42
+ -out integrations/litzki-sovp/examples/ed25519-private.pem
43
+ ```
44
+
45
+ Then produce a signed TRACE record:
46
+
47
+ ```bash
48
+ litzki-sovp-trace \
49
+ --input integrations/litzki-sovp/examples/sovp-attestation.json \
50
+ --private-key integrations/litzki-sovp/examples/ed25519-private.pem \
51
+ --output /tmp/sovp.trace.json
52
+ ```
53
+
54
+ ## Reproduction target
55
+
56
+ ```bash
57
+ python -m pytest integrations/litzki-sovp/tests
58
+ trace-tests verify --record /tmp/sovp.trace.json --level 0
59
+ ```
60
+
61
+ The generated record passes TRACE conformance at **Level 0** (`TR-ENV`, `TR-SIG`,
62
+ `TR-POL`). Level 0 is the honest ceiling for this bridge: it transcribes a SOVP
63
+ attestation rather than measuring a hardware TEE, so `runtime.platform` is
64
+ `software-only`, which the suite accepts only at Level 0.
@@ -0,0 +1,25 @@
1
+ {
2
+ "agentrust": {
3
+ "trace_id": "0192f3a0-0000-7000-8000-0000000000aa",
4
+ "agent_id": "spiffe://litzki.systems/agent/sovp-demo",
5
+ "agent_manifest_id": "0192f3a0-0000-7000-8000-000000000001",
6
+ "manifest_verification_result": "VALID",
7
+ "tool_id": "systems.litzki.sovp.attestation",
8
+ "policy_hash": "sha256:a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1",
9
+ "catalog_hash": "sha256:b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2",
10
+ "decision": "allow",
11
+ "decision_reason": "SOVP attestation result accepted by caller policy.",
12
+ "payload_classification": "internal",
13
+ "egress_destination": "trace.local",
14
+ "hitl_required": false,
15
+ "hitl_approval_id": null,
16
+ "timestamp": "2026-08-22T00:00:00Z",
17
+ "tee_measurement": "sha256:cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"
18
+ },
19
+ "sovp": {
20
+ "result": "passed",
21
+ "measurement": "sha256:cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd",
22
+ "nonce": "example-nonce",
23
+ "subject": "sovp-demo"
24
+ }
25
+ }
@@ -0,0 +1,34 @@
1
+ name: litzki-sovp
2
+ vendor: Litzki Systems
3
+ product: SOVP
4
+ version: 0.1.0
5
+ category: attestation
6
+ summary: Emits signed AgenTrust TRACE records from SOVP attestation results.
7
+ maintainer:
8
+ name: Litzki Systems
9
+ email: maintainers@litzki.systems
10
+ links:
11
+ homepage: https://github.com/litzki-systems/sovp-agentrust-bridge
12
+ repository: https://github.com/litzki-systems/sovp-agentrust-bridge
13
+ runtime:
14
+ language: python
15
+ package: litzki-sovp-agentrust-bridge
16
+ requires_python: '>=3.11'
17
+ dependencies:
18
+ - cmcp-runtime
19
+ - agentrust-trace
20
+ - agentrust-trace-tests
21
+ - agent-manifest
22
+ capabilities:
23
+ emits:
24
+ - trace-record
25
+ consumes:
26
+ - sovp-attestation-result
27
+ claims:
28
+ tier: community
29
+ trace_conformance: level-0
30
+ verified: false
31
+ notes:
32
+ - Generated records pass agentrust-trace-tests at Level 0 (TR-ENV, TR-SIG, TR-POL). Reproduce with `trace-tests verify --record <record> --level 0`; this repository's CI runs that reproduction on every push and pull request (.github/workflows/ci.yml, Python 3.11 and 3.12).
33
+ - Level 0 is the honest ceiling for this bridge. It transcribes a SOVP attestation rather than measuring a hardware TEE, so runtime.platform is software-only, which the suite accepts only at Level 0.
34
+ - The Verified tier is granted by the AgenTrust maintainers during marketplace review, never self-declared. This field stays false until then.
@@ -0,0 +1,28 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "litzki-sovp-agentrust-bridge"
7
+ version = "0.1.0"
8
+ description = "SOVP to AgenTrust TRACE bridge"
9
+ readme = "README.md"
10
+ requires-python = ">=3.11"
11
+ license = {text = "Apache-2.0"}
12
+ dependencies = [
13
+ "agent-manifest>=0.11.1",
14
+ "agentrust-trace>=0.9.0",
15
+ "agentrust-trace-tests>=0.5.1",
16
+ "cmcp-runtime>=0.4.0",
17
+ "cryptography>=42,<51",
18
+ ]
19
+
20
+ [project.scripts]
21
+ litzki-sovp-trace = "litzki_sovp.adapter:main"
22
+
23
+ [tool.hatch.build.targets.wheel]
24
+ packages = ["src/litzki_sovp"]
25
+
26
+ [tool.pytest.ini_options]
27
+ testpaths = ["tests"]
28
+ pythonpath = ["src"]
@@ -0,0 +1,5 @@
1
+ """Litzki SOVP to AgenTrust TRACE bridge."""
2
+
3
+ from litzki_sovp.trace import build_trace_record, sign_trace_record, trace_signing_pre_image
4
+
5
+ __all__ = ["build_trace_record", "sign_trace_record", "trace_signing_pre_image"]
@@ -0,0 +1,40 @@
1
+ """Command line adapter for SOVP attestation JSON to signed TRACE JSON."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import argparse
6
+ import json
7
+ from pathlib import Path
8
+
9
+ from cryptography.hazmat.primitives import serialization
10
+ from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
11
+
12
+ from litzki_sovp.trace import build_trace_record, sign_trace_record
13
+
14
+
15
+ def load_private_key(path: Path) -> Ed25519PrivateKey:
16
+ key = serialization.load_pem_private_key(path.read_bytes(), password=None)
17
+ if not isinstance(key, Ed25519PrivateKey):
18
+ raise ValueError("private key must be an Ed25519 PEM key")
19
+ return key
20
+
21
+
22
+ def convert_file(input_path: Path, private_key_path: Path, output_path: Path) -> None:
23
+ sovp_result = json.loads(input_path.read_text(encoding="utf-8"))
24
+ private_key = load_private_key(private_key_path)
25
+ record = build_trace_record(sovp_result)
26
+ signed = sign_trace_record(record, private_key)
27
+ output_path.write_text(json.dumps(signed, indent=2, sort_keys=True) + "\n", encoding="utf-8")
28
+
29
+
30
+ def main() -> None:
31
+ parser = argparse.ArgumentParser(description="Convert SOVP attestation JSON to a signed AgenTrust TRACE record")
32
+ parser.add_argument("--input", required=True, type=Path, help="SOVP attestation result JSON")
33
+ parser.add_argument("--private-key", required=True, type=Path, help="Ed25519 private key in PEM format")
34
+ parser.add_argument("--output", required=True, type=Path, help="Output TRACE JSON path")
35
+ args = parser.parse_args()
36
+ convert_file(args.input, args.private_key, args.output)
37
+
38
+
39
+ if __name__ == "__main__":
40
+ main()
@@ -0,0 +1,157 @@
1
+ """TRACE record construction for SOVP attestation results.
2
+
3
+ Builds an AgenTrust TRACE v0.2 Trust Record from a SOVP attestation document and
4
+ signs it with the released ``agentrust-trace`` signing implementation, so the
5
+ output verifies under ``agentrust-trace-tests`` (TR-ENV / TR-SIG / TR-POL) at
6
+ Level 0.
7
+
8
+ Design stance: this bridge only *transcribes* a SOVP attestation into TRACE
9
+ shape. It measures nothing itself, so every field that would otherwise assert a
10
+ strong guarantee is set to its weakest honest value:
11
+
12
+ - ``runtime.platform`` is ``software-only`` (no hardware TEE in the bridge);
13
+ - ``origin.kind`` is ``third-party-control-plane`` (the evidence is asserted by
14
+ SOVP, not measured by this runtime);
15
+ - ``appraisal.status`` is ``none`` (no verifier appraised the result);
16
+ - ``build_provenance.slsa_level`` is ``0`` (no build-provenance guarantee claimed).
17
+
18
+ This mirrors the project README's "What it does not claim" section: the record
19
+ never dresses transcribed evidence up as hardware-attested.
20
+ """
21
+
22
+ from __future__ import annotations
23
+
24
+ import time
25
+ from collections.abc import Mapping
26
+ from typing import Any
27
+
28
+ from agentrust_trace.sign import TRACE_PROFILE_V0_2, sign_record
29
+ from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
30
+
31
+ # Fields the caller must supply explicitly in the ``agentrust`` object. The bridge
32
+ # never infers an attestation claim it was not given.
33
+ TRACE_REQUIRED_FIELDS = (
34
+ "agent_id",
35
+ "policy_hash",
36
+ "catalog_hash",
37
+ "payload_classification",
38
+ "tee_measurement",
39
+ )
40
+
41
+ # TR-POL-002 accepts only these; the model's fourth value ``declared`` passes the
42
+ # schema but fails Level-0 conformance, so it is deliberately not offered here.
43
+ _VALID_ENFORCEMENT_MODES = frozenset({"enforce", "advisory", "silent"})
44
+
45
+
46
+ def _enforcement_mode(agentrust: Mapping[str, Any]) -> str:
47
+ """Return a conformance-valid ``policy.enforcement_mode`` for the record.
48
+
49
+ Honest mapping from the caller's own governance decision:
50
+
51
+ - an explicit ``policy_enforcement_mode`` wins, but must be one the TRACE
52
+ conformance suite accepts;
53
+ - otherwise, a caller ``decision`` that was acted on means the policy was
54
+ *enforced*; with no decision at all the honest value is ``advisory`` (a
55
+ policy is named but nothing is asserted to have acted on it).
56
+ """
57
+ mode = agentrust.get("policy_enforcement_mode")
58
+ if mode is not None:
59
+ if mode not in _VALID_ENFORCEMENT_MODES:
60
+ raise ValueError(
61
+ f"policy_enforcement_mode must be one of {sorted(_VALID_ENFORCEMENT_MODES)}, "
62
+ f"got {mode!r} (the schema also allows 'declared', but it fails TRACE "
63
+ "conformance TR-POL-002)"
64
+ )
65
+ return mode
66
+ return "enforce" if agentrust.get("decision") else "advisory"
67
+
68
+
69
+ def build_trace_record(sovp_result: Mapping[str, Any]) -> dict[str, Any]:
70
+ """Build an unsigned AgenTrust TRACE v0.2 Trust Record from a SOVP result.
71
+
72
+ ``sovp_result`` must contain an ``agentrust`` object with the fields named in
73
+ :data:`TRACE_REQUIRED_FIELDS` and may contain a ``sovp`` object with the source
74
+ attestation payload. Missing required fields raise ``ValueError``; nothing is
75
+ inferred.
76
+ """
77
+ agentrust = sovp_result.get("agentrust")
78
+ if not isinstance(agentrust, Mapping):
79
+ raise ValueError("SOVP result must contain an 'agentrust' object")
80
+
81
+ missing = [field for field in TRACE_REQUIRED_FIELDS if field not in agentrust]
82
+ if missing:
83
+ raise ValueError(f"missing TRACE fields: {', '.join(missing)}")
84
+
85
+ sovp = sovp_result.get("sovp", {})
86
+ if not isinstance(sovp, Mapping):
87
+ raise ValueError("'sovp' must be an object when present")
88
+
89
+ now = int(time.time())
90
+
91
+ return {
92
+ "eat_profile": TRACE_PROFILE_V0_2,
93
+ "iat": now,
94
+ "subject": agentrust["agent_id"],
95
+ "model": {
96
+ "provider": str(agentrust.get("model_provider", "litzki-systems")),
97
+ "model_id": str(agentrust.get("model_id", "sovp")),
98
+ "version": str(agentrust.get("model_version", "0.1.0")),
99
+ },
100
+ "runtime": {
101
+ # No hardware TEE in the bridge; the measurement is transcribed from
102
+ # SOVP and the software-only platform says so.
103
+ "platform": "software-only",
104
+ "measurement": agentrust["tee_measurement"],
105
+ "nonce": sovp.get("nonce"),
106
+ },
107
+ "policy": {
108
+ "bundle_hash": agentrust["policy_hash"],
109
+ "enforcement_mode": _enforcement_mode(agentrust),
110
+ },
111
+ "data_class": agentrust["payload_classification"],
112
+ "origin": {
113
+ # The evidence is asserted by SOVP, not measured here.
114
+ "kind": "third-party-control-plane",
115
+ "producer": "SOVP",
116
+ "source_event_id": str(
117
+ sovp.get("subject", agentrust.get("trace_id", "sovp-attestation"))
118
+ ),
119
+ "ingested_at": now,
120
+ },
121
+ "build_provenance": {
122
+ # slsa_level 0 == no build-provenance guarantee claimed. The catalog
123
+ # hash is the one contextual digest the caller supplies.
124
+ "slsa_level": 0,
125
+ "digest": agentrust["catalog_hash"],
126
+ },
127
+ "appraisal": {
128
+ "status": "none",
129
+ "verifier": "litzki-sovp-agentrust-bridge",
130
+ "timestamp": now,
131
+ },
132
+ }
133
+
134
+
135
+ def sign_trace_record(
136
+ record: Mapping[str, Any], private_key: Ed25519PrivateKey
137
+ ) -> dict[str, Any]:
138
+ """Return a signed TRACE record.
139
+
140
+ Delegates to ``agentrust_trace.sign.sign_record``, which populates ``cnf.jwk``
141
+ with the public key and adds an Ed25519 ``signature`` over the RFC 8785 (JCS)
142
+ canonical form of the record with only the ``signature`` field absent. This is
143
+ the exact convention ``agentrust-trace-tests`` TR-SIG verifies.
144
+ """
145
+ return sign_record(dict(record), private_key)
146
+
147
+
148
+ def trace_signing_pre_image(record: Mapping[str, Any]) -> bytes:
149
+ """Return the canonical signing pre-image for a TRACE record.
150
+
151
+ Kept for API stability (re-exported from the package root). Signing itself is
152
+ owned by ``agentrust-trace``; this delegates to the same canonicalization so a
153
+ caller inspecting the pre-image sees exactly the bytes that get signed.
154
+ """
155
+ from agentrust_trace.sign import _canonical_bytes
156
+
157
+ return _canonical_bytes({k: v for k, v in record.items() if k != "signature"})
@@ -0,0 +1,96 @@
1
+ import copy
2
+
3
+ import pytest
4
+ from agentrust_trace import verify_record
5
+ from agentrust_trace.models import TrustRecord
6
+ from agentrust_trace.sign import TRACE_PROFILE_V0_2
7
+ from cryptography.exceptions import InvalidSignature
8
+ from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
9
+ from trace_tests.result import Status
10
+ from trace_tests.runner import run
11
+
12
+ from litzki_sovp.trace import build_trace_record, sign_trace_record, trace_signing_pre_image
13
+
14
+
15
+ def _sovp_result():
16
+ return {
17
+ "agentrust": {
18
+ "trace_id": "0192f3a0-0000-7000-8000-0000000000aa",
19
+ "agent_id": "spiffe://litzki.systems/agent/sovp-demo",
20
+ "policy_hash": "sha256:" + "a1" * 32,
21
+ "catalog_hash": "sha256:" + "b2" * 32,
22
+ "decision": "allow",
23
+ "decision_reason": "SOVP attestation result accepted by caller policy.",
24
+ "payload_classification": "internal",
25
+ "tee_measurement": "sha256:" + "cd" * 32,
26
+ },
27
+ "sovp": {"result": "passed", "measurement": "sha256:" + "cd" * 32, "nonce": "example-nonce", "subject": "sovp-demo"},
28
+ }
29
+
30
+
31
+ def test_build_trace_record_requires_explicit_trace_fields():
32
+ source = _sovp_result()
33
+ del source["agentrust"]["policy_hash"]
34
+
35
+ with pytest.raises(ValueError, match="policy_hash"):
36
+ build_trace_record(source)
37
+
38
+
39
+ def test_build_trace_record_is_a_structurally_valid_v0_2_record():
40
+ record = build_trace_record(_sovp_result())
41
+
42
+ assert record["eat_profile"] == TRACE_PROFILE_V0_2
43
+ # The unsigned record is a valid TrustRecord except for the cnf/signature that
44
+ # signing adds, so validate the signed form.
45
+ signed = sign_trace_record(record, Ed25519PrivateKey.generate())
46
+ TrustRecord.model_validate(signed)
47
+
48
+
49
+ def test_enforcement_mode_rejects_non_conformant_override():
50
+ source = _sovp_result()
51
+ source["agentrust"]["policy_enforcement_mode"] = "declared"
52
+
53
+ with pytest.raises(ValueError, match="TR-POL-002"):
54
+ build_trace_record(source)
55
+
56
+
57
+ def test_signed_record_verifies_with_agentrust_trace():
58
+ private_key = Ed25519PrivateKey.generate()
59
+ signed = sign_trace_record(build_trace_record(_sovp_result()), private_key)
60
+
61
+ # Real verifier: profile, freshness, and Ed25519 signature over the JCS pre-image.
62
+ verify_record(signed, private_key.public_key())
63
+
64
+
65
+ def test_tampered_field_invalidates_signature():
66
+ private_key = Ed25519PrivateKey.generate()
67
+ signed = sign_trace_record(build_trace_record(_sovp_result()), private_key)
68
+
69
+ tampered = copy.deepcopy(signed)
70
+ tampered["data_class"] = "public"
71
+
72
+ with pytest.raises(InvalidSignature):
73
+ verify_record(tampered, private_key.public_key())
74
+
75
+
76
+ def test_pre_image_excludes_only_signature():
77
+ record = sign_trace_record(build_trace_record(_sovp_result()), Ed25519PrivateKey.generate())
78
+ record["signature"] = "one"
79
+ first = trace_signing_pre_image(record)
80
+ record["signature"] = "two"
81
+
82
+ assert trace_signing_pre_image(record) == first
83
+
84
+
85
+ def test_record_passes_trace_tests_level_0():
86
+ signed = sign_trace_record(build_trace_record(_sovp_result()), Ed25519PrivateKey.generate())
87
+
88
+ results = run(signed, "trace", level=0)
89
+ failures = [
90
+ finding
91
+ for findings in results.values()
92
+ for finding in findings
93
+ if finding.status is Status.FAIL
94
+ ]
95
+
96
+ assert not failures, [f.message for f in failures]