Skip to content

Feat/v3 verifier - #122

Open
lsd-cat wants to merge 11 commits into
mainfrom
feat/v3-verifier
Open

lsd-cat wants to merge 11 commits into
mainfrom
feat/v3-verifier

Conversation

@lsd-cat

@lsd-cat lsd-cat commented Aug 30, 2026

Copy link
Copy Markdown
Collaborator

v3 verifier generated using the conformance suite based on Go and JS.


Summary by cubic

Implements the v3 attestation verifier in Python and switches SecureClient.verify() from the v2 GitHub/sigstore/hardware-measurement flow to the v3 single-request flow, matching the Go and JS SDKs.

What's included

  • Adds tinfoil.v3 with strict envelope parsing, Sigstore provenance, and SEV-SNP (Genoa and Turin) and TDX quote verification.
  • Adds the tinfoil-conformance adapter; the shared v3 conformance suite passes.
  • Freshness now only trusts transparency-log time when a SET inclusion promise is verified.

Breaking changes

  • verify_from_bundle is removed; there is no v2 fallback.
  • Constructing SecureClient with a pinned measurement now raises instead of silently skipping code provenance.
  • v3 rejections surface as AttestationError, with the layer-carrying VerificationError attached as the cause.

Written for commit 1190ba0. Summary will update on new commits.

Review in cubic

lsd-cat added 11 commits August 28, 2026 18:15
PORTING.md pins the module map, snake_case interface contract, adapter wiring,
acceptance harness, and Python-specific pitfalls for the v3 port (per
tinfoil-conformance docs/PORTING_PLAYBOOK.md, referencing tinfoil-go feat/v3
Turin-era as primary source). embedded_roots.py carries the production trust
anchors byte-identical to Go's go:embed copies (Genoa + Turin + Intel SGX +
Sigstore trusted root). Implementation phases follow on this branch.
1:1 Python port of the v3 envelope (strict parse + check: nonce, endorsed
section hashes, report_data ladder, collateral accessors), the fail-closed
platform-endorsements artifact parser (Turin-era fields), Go-semantics strict
JSON (hand parser: decoded-name duplicate rejection with U+FFFD surrogate
coercion, raw-literal exact ints, canonical encodings), measurement types,
embedded production roots byte-identical to Go's, and the conformance adapter
skeleton (tinfoil-conformance script; envelope stage live, others exit 20).
Conformance: envelope 21/21 via the shared runner; 121 unit tests; existing
suite unaffected (599 passed).
authenticate_code / authenticate_platform_endorsements / authenticate_freshness
on the official sigstore-python (Verifier + verify_dsse works fully offline
against a supplied trusted root, matching sigstore-go's chain/SCT/tlog/
integrated-time semantics), with every tinfoil check it lacks implemented here:
media-type + legacy-layout + one-signature gates, duplicate-SCT-log rejection,
SAN-regex + issuer + runner_environment policy, protojson-strict statement
parse, subject digest enforcement, source ref/digest extraction (tag + 40-hex
commit), platform repo pin, freshness witness (earliest tlog time, 5min skew,
7d age; timedelta arithmetic, no floats). Adapter stages authenticate-provenance
+ assemble-policy wired. Conformance: provenance 33/33, policy 29/29, envelope
21/21; 201 unit tests green.
sev_authenticate: strict report ABI (all mbz ranges), CPUID-FMS product line
(Genoa+Turin), per-product pinned roots with injectable override, KDS chain +
extension validation (Turin TCB layouts, hwid variants, per-version spl rules),
RSA-PSS-SHA384 chain, fail-closed CRL (window + ASK/VCEK revocation), report
ECDSA-P384 LE signature over [0,0x2A0), VLEK/masked-CHIP_ID rejects.
sev_assemble/sev_validate: the forked go-sev-guest configured subset incl.
per-product iommu_write_safe/fmc_spl rules, Turin-aware TCB relations, and the
strict-equality companions. Deliberate fail-closed extensions beyond the fork
(VCEK-serial revocation, ARK self-signature) match the JS port. Conformance:
quote-sev 13/13, frozen-time 2/2, embedded-root SEV reject; 67 unit tests.
sev_authenticate: strict 1184-byte report ABI (all mbz/reserved rules),
per-product trusted roots (Genoa + Turin embedded chains, override seam),
product from CPUID FMS, VLEK/masked-CHIP_ID rejects, VCEK KDS extension
validation (TCB struct v0/v1, HWID 64/8, exclusivity rules), RSA-PSS-SHA384
chain with ARK self-signature, fail-closed CRL (window + ASK/VCEK serials),
ECDSA-P384 LE signature over [0,0x2A0). sev_assemble/sev_validate: the full
configured go-sev-guest subset incl. per-product iommu_write_safe/fmc_spl
rules, layout-tagged TCB floors and relations, mitigation-vector supersets,
Turin 8-byte PSN chip-id binding; report_id/_ma stay unenforced. Conformance:
quote-sev 13/13, embedded-root SEV reject, frozen-time 2/2; 67 unit tests on
real synthetic chains.
authenticate_code / authenticate_platform_endorsements / authenticate_freshness
on official sigstore-python 4.4 (offline verify_dsse against a caller-supplied
trusted root: chain, SCT, Merkle inclusion, checkpoint, SET, observer
timestamps, DSSE), with every tinfoil check it lacks ported locally:
media-type/legacy/one-signature gates, duplicate-SCT-log rejection, SAN-regex +
issuer + runner_environment policy, protojson-strict statement parsing,
artifact-digest semantics + DoS limits, source ref/tag/commit extraction,
freshness witness (earliest tlog time, 5min skew, 7d age). Adapter stages
authenticate-provenance + assemble-policy wired. provenance 33/33, policy
29/29, envelope 21/21.
Full DCAP quote-v4 verification: ABI parse, PCK SGX-extension tree, TCB Info
v3 + QE Identity with encoding/json semantics (exact ints, no floats), chain
to the pinned Intel root at the verification time incl. the header-root
byte-equality pin, root/PCK CRL windows + revocation, QE/AK signature chain
and report-data binding, versioned-module TCB status, PCS replay getter with
URL canonicalization and canonical-MIME headers, tcbEvaluationDataNumber
recorder, and tdx_assemble/tdx_validate policy comparison (fixed-bit xfam/
td_attributes rules, zero pins, component-wise TEE_TCB_SVN). Conformance:
quote-tdx 12/12 and byte-identical to the Go adapter on that directory;
real-crypto synthetic test material, no mocks; 390 v3 unit tests green.
… surface

quote_authenticate/assemble_and_validate (1:1 quote.go), verify_document_v3
(one appraisal time pins freshness and the quote clock; VerifiedDocumentV3
incl. code_tag; channel-key accessors with id/format pins), fetch_attestation/
random_nonce, the remaining adapter stages (both endorsed keys required on
full verify; layer attribution from VerificationError), live-verify through
the PUBLIC surface with TLS-SPKI channel binding, and the Tier-1 exports from
the package root per SDK_SURFACE_SPEC (adapter full-verify + live consume
them; block stages deep-import per the spec allowance).

Verified independently: 185/185; byte-identical wire outputs vs Go AND vs JS
(0 divergent both ways); live facts identical across all three adapters
against production (freshness witness re-signed upstream); 395 unit tests;
capabilities schema-valid.
…dening

Three-audit fix batch (fidelity/spec/duplication):
- Public verify_document_v3 is now the clean 3-arg surface-spec form; the
  root/clock injection seams move to a private _verify_document_v3 consumed
  only by the conformance adapter (spec §3 adapter-only seam).
- Real parity bug fixed: the SEV PEM decoder rejected CRLF chains Go accepts —
  found by diffing the sev/tdx duplicated x509 helpers, which are now one
  shared x509common.py (Go encoding/pem semantics; the two strict TLV readers
  stay separate with their deltas documented).
- Hardening: TDX option-length guards restored, report_data length checked at
  tdx_assemble, asserts on the trust path replaced with typed POLICY_REJECTED
  raises (survives python -O), dict-lookup KeyErrors replaced with typed errors,
  bare-IPv6 live-verify host parsing fixed.
- ~700 LOC of parallel-session scaffolding removed (superseded stage scripts,
  duplicate TDX/envelope test files + builders); PORTING.md moved out of the
  shipped wheel to repo root; four inaccurate comments corrected; README gains
  the conformance claim (adapter spec v1.1, surface spec v1.0 Tier-1).

Verified: 358 v3 tests + 836 total; 185/185 fixtures; byte-identical vs Go and
JS (185 each); live facts identical vs production; wheel free of PORTING.
Replace the v2 engine (GitHub release + Sigstore bundle fetch + hardware-
measurement repo fetch) with the v3 flow, mirroring Go SecureClient.verifyV3
and the JS Tier-2: random_nonce -> fetch_attestation -> the public
verify_document_v3 -> both endorsed channel keys hard-required at binding.
Transports unchanged and fed from the verified document: ehbp binds to the
endorsed HPKE key, tls pins the endorsed SPKI fingerprint per connection (no
eager dial, Go #118 parity). GroundTruth/VerificationDocument keep their
schema, populated from v3 facts incl. the TDX hardware-measurement fingerprint
rule; rejection layers map to the existing step states.

Release notes: v3-only, no v2 fallback (Go/JS parity); verify_from_bundle
removed (it was the v2 engine); the pinned-measurement constructor mode now
raises rather than silently skipping code provenance; v3 rejections surface as
AttestationError with the layered VerificationError as __cause__.

Verified: 848 unit tests (15 new v3-flow); live integration green against
inference.tinfoil.sh on the v3 engine (v0.0.142, document carries all v3
facts; remaining 401s reproduced on the unmodified tree = stale API key, not
code); conformance suite untouched at 185/185.
Security review finding: the freshness anchor read log_entry.integrated_time
unconditionally, but that time is only cryptographically bound when the
inclusion promise (SET) is present and verified — the same gate sigstore-python
uses to run _verify_set. The embedded trusted root carries a TSA, so a bundle
supplying its verified time via a timestamp authority (no inclusion promise)
could feed an unverified integrated_time into the 7-day freshness window,
weakening anti-replay. Now require the inclusion promise before trusting the
tlog time, matching Go's Type=="Tlog" VerifiedTimestamps filter. Real
freshness bundles carry inclusion promises, so fixtures are unaffected
(freshness 14/14, provenance 33/33).

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

40 issues found across 69 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/tinfoil/v3/tdx/expectations.py">

<violation number="1" location="src/tinfoil/v3/tdx/expectations.py:24">
P1: TDX debug quotes are accepted because `_TD_ATTRIBUTES_FIXED0` includes bit 0 and `_validate_bits` has no separate DEBUG check. Reject bit 0 unconditionally, since debug TD memory is visible to the host and breaks confidentiality.</violation>

<violation number="2" location="src/tinfoil/v3/tdx/expectations.py:106">
P3: Custom agent: **Nuke belt-and-suspenders**

`_options(p)` already rejects `minimum_tcb_evaluation_data_number is None` through `validate_tdx_policy(p)`, so this guard is unreachable after a successful call. Remove the duplicate check and keep policy validation centralized in `_options`.</violation>
</file>

<file name="src/tinfoil/v3/tdx/verify.py">

<violation number="1" location="src/tinfoil/v3/tdx/verify.py:502">
P1: When a quote's PCK leaf is issued by Intel SGX PCK Processor CA, this unconditional Platform CA check rejects the chain before verification. Select the expected intermediate phrase from `pck_cert.issuer_cn` so processor PCK quotes can authenticate.</violation>

<violation number="2" location="src/tinfoil/v3/tdx/verify.py:777">
P1: For a versioned TDX quote, this validates the top-level `TdxModule` instead of the selected `TdxModuleIdentity`, leaving the version-specific signer and SEAM attributes unbound. Compare `mr_signer_seam` and masked `seam_attributes` with the identity selected from `TEE_TCB_SVN[1]` before accepting its TCB status.</violation>
</file>

<file name="src/tinfoil/v3/sev/abi.py">

<violation number="1" location="src/tinfoil/v3/sev/abi.py:283">
P1: For report versions below 5, `0x1F8:0x208` is reserved and must be zero, but this check skips that range. Reject those bytes for versions below 5, while retaining `0x208` as the start for v5 reports where the mitigation vectors are defined.</violation>
</file>

<file name="src/tinfoil/v3/tdx/der.py">

<violation number="1" location="src/tinfoil/v3/tdx/der.py:161">
P2: Despite the P-256 contract, these helpers accept any elliptic-curve public key and verify it with SHA-256. Require `pub.curve` to be `SECP256R1` before verifying.</violation>

<violation number="2" location="src/tinfoil/v3/tdx/der.py:263">
P2: When a nested TLV extends beyond its parent, `tlv_children` accepts it if the bytes still fit the outer buffer and may parse sibling bytes as child content. Reject children whose `end` exceeds `t.end`.</violation>

<violation number="3" location="src/tinfoil/v3/tdx/der.py:272">
P2: When a future SGX OID uses first arc 2 with a second arc above 39, `decode_oid` computes the wrong arcs and fails to recognize it. Parse the first subidentifier as base-128 and reject unterminated or non-minimal components.</violation>
</file>

<file name="src/tinfoil/v3/tdx/quote.py">

<violation number="1" location="src/tinfoil/v3/tdx/quote.py:142">
P2: Quotes carrying a non-Intel QE vendor ID are accepted as long as their other signatures and collateral verify. Validate `qe_vendor_id` against Intel's vendor ID during header checking, matching the existing ABI parser, so authenticated quotes cannot claim an unsupported QE vendor.</violation>
</file>

<file name="src/tinfoil/v3/fetch.py">

<violation number="1" location="src/tinfoil/v3/fetch.py:24">
P2: When the attestation endpoint returns an oversized body, this fetch buffers it completely before verification and has no maximum response size. Stream the response and reject it after a bounded number of bytes to prevent a malicious or misbehaving router from exhausting client memory.</violation>

<violation number="2" location="src/tinfoil/v3/fetch.py:24">
P2: The 10-second `httpx` timeout does not cap total fetch duration. A slow peer can keep this call alive by sending data before each read timeout; enforce an overall deadline while streaming the bounded response.</violation>
</file>

<file name="src/tinfoil/v3/provenance/provenance.py">

<violation number="1" location="src/tinfoil/v3/provenance/provenance.py:241">
P2: Signed payloads with a missing or non-in-toto `_type` are accepted by the code and platform verifiers. Require `Statement.type` to equal `https://in-toto.io/Statement/v1`, matching the freshness verifier's check.</violation>

<violation number="2" location="src/tinfoil/v3/provenance/provenance.py:251">
P2: Malformed signed subjects can pass despite the documented protojson-style strict parsing because several recognized subject fields are never type-checked. Validate each allowed field's scalar/map type, or reject fields the verifier does not consume.</violation>
</file>

<file name="src/tinfoil/v3/strictjson.py">

<violation number="1" location="src/tinfoil/v3/strictjson.py:93">
P2: A deeply nested raw bundle or statement raises `RecursionError` instead of `ValueError`, escaping the caller's rejection path and potentially aborting verification. Catch this in `unmarshal()` or replace recursive walking with an iterative or depth-limited parser.</violation>
</file>

<file name="src/tinfoil/v3/client.py">

<violation number="1" location="src/tinfoil/v3/client.py:130">
P2: When `verification_time` is omitted, the freshness proofs and quote validity checks use different appraisal times. Pass the already sampled `appraisal` to `quote_authenticate` so boundary-sensitive verification remains consistent.</violation>
</file>

<file name="src/tinfoil/v3/__init__.py">

<violation number="1" location="src/tinfoil/v3/__init__.py:38">
P2: Custom agent: **Flag Security Vulnerabilities**

When an HTTPS attestation endpoint redirects to HTTP, `fetch_attestation` follows the redirect and sends the next request without TLS. Restrict redirects to HTTPS or disable redirect following before exposing this fetch API.</violation>
</file>

<file name="src/tinfoil/client.py">

<violation number="1" location="src/tinfoil/client.py:40">
P2: Custom agent: **Slop Comments**

Remove this import-narration comment: it repeats the v3 public-surface and single-network-request claims already documented in `verify()`, and the latter is inaccurate when `verify()` first performs router discovery via `get_router_address()`.</violation>

<violation number="2" location="src/tinfoil/client.py:885">
P2: Custom agent: **Detect Outdated or Unused State/Enum Definitions**

The `skipped` state is now obsolete: the v3 flow and remaining code never assign it after the pinned and bundle paths were removed. Remove `skipped` from `VerificationStepState.status` so the declared states match the application logic.</violation>

<violation number="3" location="src/tinfoil/client.py:897">
P2: When the existing ATC/bundle path is used for a deployment where the enclave is reachable only through a proxy, this call now dials the discovered enclave directly and ignores the configured proxy/ATC service. Preserve the bundle/proxy path or route the v3 attestation fetch through the configured proxy before replacing the old flow.</violation>

<violation number="4" location="src/tinfoil/client.py:1087">
P2: When callers use `get_router_address(atc_base_url=...)` directly, this accepts plaintext ATC URLs even though the client path requires HTTPS. Validate `atc_base_url` as an absolute HTTPS URL before constructing the routers endpoint.</violation>
</file>

<file name="src/tinfoil/v3/sev/authenticate.py">

<violation number="1" location="src/tinfoil/v3/sev/authenticate.py:155">
P2: Turin reports using an extended model 1 FMS are rejected before reaching the pinned Turin root, although `kds.product_line_from_fms` classifies them as Turin. Use the KDS product-line mapper here, or centralize the mapping, so supported Turin revisions follow the same product policy throughout verification.</violation>
</file>

<file name="src/tinfoil/v3/provenance/freshness.py">

<violation number="1" location="src/tinfoil/v3/provenance/freshness.py:108">
P2: Custom agent: **Check System Design and Architectural Patterns**

`verify_bundle_with_identity` already parses and verifies this bundle, including a parsed `VerifiedBundle.statement`, but `_parse_freshness_statement(bundle_json)` reparses and decodes the raw bundle. Apply the freshness-specific checks to the verified payload/statement or expose a shared parsed representation instead of parsing the bundle twice.</violation>

<violation number="2" location="src/tinfoil/v3/provenance/freshness.py:138">
P2: When a caller supplies an uppercase digest to `authenticate_code`, passing its returned `Code` to `authenticate_freshness` rejects the valid artifact as malformed. Preserve the existing case-insensitive digest contract by normalizing the expected digest for bundle, statement, and witness comparisons instead of imposing a lowercase-only invariant here.</violation>
</file>

<file name="src/tinfoil/v3/tdx/authenticate.py">

<violation number="1" location="src/tinfoil/v3/tdx/authenticate.py:61">
P2: When `tdx_authenticate(..., now=naive_datetime)` is used, `PCSReplayGetter.get` compares that naive value with timezone-aware CRL timestamps and raises `TypeError`. Normalize naive `now` to UTC before constructing the replay getter so this verification path returns `VerificationError` instead of escaping.</violation>
</file>

<file name="src/tinfoil/v3/provenance/bundle_format.py">

<violation number="1" location="src/tinfoil/v3/provenance/bundle_format.py:25">
P2: The dot-form media type is defined only for v0.3, but this regex also accepts unsupported `bundle.v0.1+json` and `bundle.v0.2+json` values. Restrict the dot-form check to v0.3 so unsupported bundle formats cannot pass `parse_bundle`.</violation>
</file>

<file name="src/tinfoil/v3/policy.py">

<violation number="1" location="src/tinfoil/v3/policy.py:492">
P2: When a signed artifact contains a very long decimal version component, `int()` raises before the parser assigns `PROVENANCE_REJECTED`, leaking an unexpected exception from policy authentication. Check the u8 range without converting unbounded input to an integer.</violation>

<violation number="2" location="src/tinfoil/v3/policy.py:612">
P2: When a platform artifact uses uppercase hex for `mrtd` or `rtmr0`, this comparison rejects the matching quote even though `decode_hex` accepts that encoding. Compare decoded bytes (or normalize both values) before matching.</violation>
</file>

<file name="src/tinfoil/conformance/run.py">

<violation number="1" location="src/tinfoil/conformance/run.py:114">
P2: When `verification_time_unix` is an out-of-range integer, `run` raises before stage handling and the CLI returns an internal-error exit code. Validate the timestamp’s supported range during input parsing and raise `MalformedInput` for conversion failures.</violation>

<violation number="2" location="src/tinfoil/conformance/run.py:317">
P2: When the injected Intel root has a non-`CERTIFICATE` PEM label, this precheck accepts it based only on the DER and the verifier later returns `QUOTE_REJECTED`, so malformed input gets exit 10 instead of exit 30. Require the PEM block type to be `CERTIFICATE` before parsing its DER.</violation>
</file>

<file name="src/tinfoil/v3/tdx/pcs.py">

<violation number="1" location="src/tinfoil/v3/tdx/pcs.py:580">
P2: When callers use `raw_top_level_member` directly, malformed JSON can be accepted as a signed member because the scanner does not validate primitive values or trailing bytes. Validate the complete JSON body before returning the extracted member.</violation>
</file>

<file name="src/tinfoil/v3/sev/x509.py">

<violation number="1" location="src/tinfoil/v3/sev/x509.py:130">
P2: When a configured CA has a finite `BasicConstraints.path_length`, `_verify_chain` accepts chains that exceed that limit. Track the number of intermediate CAs and reject the chain when the parent’s path-length constraint is exhausted.</violation>
</file>

<file name="tests/v3/test_tdx_authenticate.py">

<violation number="1" location="tests/v3/test_tdx_authenticate.py:464">
P2: test_expired_certificates_reject passes for the wrong reason: at now=NOT_AFTER+1 day the captured CRLs (default next_update=NOT_AFTER) are already out of window, so PCSReplayGetter rejects during collateral fetch and the certificate-expiry code path never runs. Build the CRLs with windows covering `now` (as test_now_pins_crl_window does) so only the certificates expire, otherwise this test gives false confidence in certificate-expiry rejection.</violation>
</file>

<file name="src/tinfoil/v3/x509common.py">

<violation number="1" location="src/tinfoil/v3/x509common.py:23">
P2: When a Go-compatible PEM block contains header fields, `pem_decode` returns `None` because the regex does not parse headers before the base64 payload. Parse and skip PEM headers before decoding the payload so the shared certificate loaders accept the same blocks as Go.</violation>
</file>

<file name="src/tinfoil/conformance/cli.py">

<violation number="1" location="src/tinfoil/conformance/cli.py:113">
P2: When `live-verify` receives a bare IPv6 literal, `fetch_attestation` constructs an invalid HTTPS URL and the verification fails before reaching the enclave. Bracket IPv6 hosts before passing them to the URL-based fetch, while retaining the original host for socket dialing.</violation>

<violation number="2" location="src/tinfoil/conformance/cli.py:150">
P2: The measurement dicts built inline in _run_live duplicate run.py's _to_measurement helper (both map Measurement.type plus list(registers) into the same "type"/"registers" shape). Keeping two copies forces any future change to the measurement wire format (e.g. adding a field) to be made in two places, which is exactly the kind of divergence the "simple but extendable" goal wants to avoid. Reuse _to_measurement here.</violation>
</file>

<file name="src/tinfoil/v3/measurement.py">

<violation number="1" location="src/tinfoil/v3/measurement.py:42">
P2: When a malformed `Measurement` reaches `fingerprint`, short register lists raise `IndexError` and oversized lists are silently accepted, despite the module’s all-`ValueError` contract. Validate the exact register count for each supported measurement type before dispatching.</violation>

<violation number="2" location="src/tinfoil/v3/measurement.py:42">
P3: Custom agent: **Slop Comments**

These inline labels merely restate the predicate-type branches and do not explain a non-obvious invariant or behavior. Remove `# Source` and `# Runtime` to keep the dispatch readable.</violation>
</file>

<file name="src/tinfoil/v3/sev/kds.py">

<violation number="1" location="src/tinfoil/v3/sev/kds.py:124">
P2: When `TCBParts` is constructed outside the current JSON path, negative components or `ucode_spl > 255` pass validation and produce an invalid packed TCB. Enforce lower bounds for the 0-127 fields and a complete 0-255 range for `ucode_spl` before packing.</violation>
</file>

<file name="tests/v3/test_tdx_expectations.py">

<violation number="1" location="tests/v3/test_tdx_expectations.py:151">
P2: test_td_attributes_fixed0_bits_reported does not test what its docstring claims. The fixed0/fixed1 bit check in expectations._validate_bits runs against the quote's td_attributes field, not the policy option. The module-scoped quote carries td_attributes 0x...40 (bit 30, allowed in _TD_ATTRIBUTES_FIXED0), so no unauthorized tdAttributes violation is produced. The test passes only on the byte-mismatch error from _exact_byte_match, making it an exact duplicate of test_bad_td_attributes_rejects. The fixed0/fixed1 bit-enforcement path is never exercised, and a regression that removed _validate_bits would go uncaught.</violation>
</file>

<file name="src/tinfoil/v3/embedded_roots.py">

<violation number="1" location="src/tinfoil/v3/embedded_roots.py:9">
P2: `SGX_ROOT_CA_PEM` is byte-identical to `INTEL_SGX_ROOT_CA_PEM` already embedded in `src/tinfoil/attestation/intel_root_ca.py`, so the Intel SGX trust anchor now exists in two places. Trust anchors rotate (Intel's SGX root CA is expiring in 2049 but can still be rotated), and keeping two embedded copies means a future rotation or correction must be made in both modules or the v2 and v3 verifiers will silently diverge. Reuse a single source of the cert (e.g. a lightweight shared constant module that both `attestation` and `v3` import) rather than embedding a second copy.</violation>
</file>

Tip: instead of fixing issues one by one fix them all with cubic

Re-trigger cubic

_TD_ATTRIBUTES_FIXED1 = 0x0
# Supported ATTRIBUTES bits: 0 (DEBUG), 28 (SEPT VE DISABLE), 30 (PKS),
# 63 (PERFMON). If bit X is 0 in tdAttributesFixed0, it must be 0.
_TD_ATTRIBUTES_FIXED0 = 0x1 | (1 << 28) | (1 << 30) | (1 << 63)

@cubic-dev-ai cubic-dev-ai Bot Aug 30, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: TDX debug quotes are accepted because _TD_ATTRIBUTES_FIXED0 includes bit 0 and _validate_bits has no separate DEBUG check. Reject bit 0 unconditionally, since debug TD memory is visible to the host and breaks confidentiality.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/tinfoil/v3/tdx/expectations.py, line 24:

<comment>TDX debug quotes are accepted because `_TD_ATTRIBUTES_FIXED0` includes bit 0 and `_validate_bits` has no separate DEBUG check. Reject bit 0 unconditionally, since debug TD memory is visible to the host and breaks confidentiality.</comment>

<file context>
@@ -0,0 +1,260 @@
+_TD_ATTRIBUTES_FIXED1 = 0x0
+# Supported ATTRIBUTES bits: 0 (DEBUG), 28 (SEPT VE DISABLE), 30 (PKS),
+# 63 (PERFMON). If bit X is 0 in tdAttributesFixed0, it must be 0.
+_TD_ATTRIBUTES_FIXED0 = 0x1 | (1 << 28) | (1 << 30) | (1 << 63)
+
+_UINT64_MASK = (1 << 64) - 1
</file context>
Suggested change
_TD_ATTRIBUTES_FIXED0 = 0x1 | (1 << 28) | (1 << 30) | (1 << 63)
_TD_ATTRIBUTES_FIXED0 = (1 << 28) | (1 << 30) | (1 << 63)
Fix with cubic

except ValueError as e:
raise ValueError(f"unable to validate root cert: {e}") from None
try:
_validate_certificate(intermediate_cert, root_cert, _INTERMEDIATE_CERT_PHRASE)

@cubic-dev-ai cubic-dev-ai Bot Aug 30, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: When a quote's PCK leaf is issued by Intel SGX PCK Processor CA, this unconditional Platform CA check rejects the chain before verification. Select the expected intermediate phrase from pck_cert.issuer_cn so processor PCK quotes can authenticate.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/tinfoil/v3/tdx/verify.py, line 502:

<comment>When a quote's PCK leaf is issued by Intel SGX PCK Processor CA, this unconditional Platform CA check rejects the chain before verification. Select the expected intermediate phrase from `pck_cert.issuer_cn` so processor PCK quotes can authenticate.</comment>

<file context>
@@ -0,0 +1,943 @@
+    except ValueError as e:
+        raise ValueError(f"unable to validate root cert: {e}") from None
+    try:
+        _validate_certificate(intermediate_cert, root_cert, _INTERMEDIATE_CERT_PHRASE)
+    except ValueError as e:
+        raise ValueError(f"unable to validate Intermediate CA certificate: {e}") from None
</file context>
Suggested change
_validate_certificate(intermediate_cert, root_cert, _INTERMEDIATE_CERT_PHRASE)
_validate_certificate(intermediate_cert, root_cert, _PROCESSOR_ISSUER if pck_cert.issuer_cn == _PROCESSOR_ISSUER else _PLATFORM_ISSUER)
Fix with cubic

Comment thread src/tinfoil/v3/sev/abi.py
_mbz(data, mbz_lo, 0x1A0)
_mbz(data, 0x1EB, 0x1EC)
_mbz(data, 0x1EF, 0x1F0)
_mbz(data, 0x208, SIGNATURE_OFFSET)

@cubic-dev-ai cubic-dev-ai Bot Aug 30, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: For report versions below 5, 0x1F8:0x208 is reserved and must be zero, but this check skips that range. Reject those bytes for versions below 5, while retaining 0x208 as the start for v5 reports where the mitigation vectors are defined.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/tinfoil/v3/sev/abi.py, line 283:

<comment>For report versions below 5, `0x1F8:0x208` is reserved and must be zero, but this check skips that range. Reject those bytes for versions below 5, while retaining `0x208` as the start for v5 reports where the mitigation vectors are defined.</comment>

<file context>
@@ -0,0 +1,368 @@
+    _mbz(data, mbz_lo, 0x1A0)
+    _mbz(data, 0x1EB, 0x1EC)
+    _mbz(data, 0x1EF, 0x1F0)
+    _mbz(data, 0x208, SIGNATURE_OFFSET)
+    if signature_algo == SIGN_ECDSA_P384_SHA384:
+        _mbz(data, SIGNATURE_OFFSET + 2 * _ECDSA_RS_SIZE, REPORT_SIZE)
</file context>
Suggested change
_mbz(data, 0x208, SIGNATURE_OFFSET)
_mbz(data, 0x208 if version >= 5 else 0x1F8, SIGNATURE_OFFSET)
Fix with cubic

"equal to PCEID value from Intel PCS's reported TDX TCB "
f"info({json.dumps(tcb_info.pce_id)})"
)
if tcb_info.tdx_module.mrsigner != td_quote_body.mr_signer_seam:

@cubic-dev-ai cubic-dev-ai Bot Aug 30, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: For a versioned TDX quote, this validates the top-level TdxModule instead of the selected TdxModuleIdentity, leaving the version-specific signer and SEAM attributes unbound. Compare mr_signer_seam and masked seam_attributes with the identity selected from TEE_TCB_SVN[1] before accepting its TCB status.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/tinfoil/v3/tdx/verify.py, line 777:

<comment>For a versioned TDX quote, this validates the top-level `TdxModule` instead of the selected `TdxModuleIdentity`, leaving the version-specific signer and SEAM attributes unbound. Compare `mr_signer_seam` and masked `seam_attributes` with the identity selected from `TEE_TCB_SVN[1]` before accepting its TCB status.</comment>

<file context>
@@ -0,0 +1,943 @@
+            "equal to PCEID value from Intel PCS's reported TDX TCB "
+            f"info({json.dumps(tcb_info.pce_id)})"
+        )
+    if tcb_info.tdx_module.mrsigner != td_quote_body.mr_signer_seam:
+        raise ValueError(
+            "MRSIGNERSEAM value from TD Quote Body is not equal to "
</file context>
Fix with cubic

Comment thread src/tinfoil/v3/tdx/der.py
out: list[TLV] = []
off = t.content_start
while off < t.end:
c = read_tlv(b, off)

@cubic-dev-ai cubic-dev-ai Bot Aug 30, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: When a nested TLV extends beyond its parent, tlv_children accepts it if the bytes still fit the outer buffer and may parse sibling bytes as child content. Reject children whose end exceeds t.end.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/tinfoil/v3/tdx/der.py, line 263:

<comment>When a nested TLV extends beyond its parent, `tlv_children` accepts it if the bytes still fit the outer buffer and may parse sibling bytes as child content. Reject children whose `end` exceeds `t.end`.</comment>

<file context>
@@ -0,0 +1,297 @@
+    out: list[TLV] = []
+    off = t.content_start
+    while off < t.end:
+        c = read_tlv(b, off)
+        out.append(c)
+        off = c.end
</file context>
Fix with cubic

tdx_validate(e, quote)


def test_td_attributes_fixed0_bits_reported(quote, code, report_data):

@cubic-dev-ai cubic-dev-ai Bot Aug 30, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: test_td_attributes_fixed0_bits_reported does not test what its docstring claims. The fixed0/fixed1 bit check in expectations._validate_bits runs against the quote's td_attributes field, not the policy option. The module-scoped quote carries td_attributes 0x...40 (bit 30, allowed in _TD_ATTRIBUTES_FIXED0), so no unauthorized tdAttributes violation is produced. The test passes only on the byte-mismatch error from _exact_byte_match, making it an exact duplicate of test_bad_td_attributes_rejects. The fixed0/fixed1 bit-enforcement path is never exercised, and a regression that removed _validate_bits would go uncaught.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At tests/v3/test_tdx_expectations.py, line 151:

<comment>test_td_attributes_fixed0_bits_reported does not test what its docstring claims. The fixed0/fixed1 bit check in expectations._validate_bits runs against the quote's td_attributes field, not the policy option. The module-scoped quote carries td_attributes 0x...40 (bit 30, allowed in _TD_ATTRIBUTES_FIXED0), so no unauthorized tdAttributes violation is produced. The test passes only on the byte-mismatch error from _exact_byte_match, making it an exact duplicate of test_bad_td_attributes_rejects. The fixed0/fixed1 bit-enforcement path is never exercised, and a regression that removed _validate_bits would go uncaught.</comment>

<file context>
@@ -0,0 +1,192 @@
+        tdx_validate(e, quote)
+
+
+def test_td_attributes_fixed0_bits_reported(quote, code, report_data):
+    # 0x4242... sets bits outside tdAttributesFixed0; both the byte mismatch
+    # and the fixed-bit violation are reported (multierr.Combine).
</file context>
Fix with cubic

"code_digest": verified.code_digest,
"code_measurement": {
"type": verified.code_measurement.type,
"registers": list(verified.code_measurement.registers),

@cubic-dev-ai cubic-dev-ai Bot Aug 30, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: The measurement dicts built inline in _run_live duplicate run.py's _to_measurement helper (both map Measurement.type plus list(registers) into the same "type"/"registers" shape). Keeping two copies forces any future change to the measurement wire format (e.g. adding a field) to be made in two places, which is exactly the kind of divergence the "simple but extendable" goal wants to avoid. Reuse _to_measurement here.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/tinfoil/conformance/cli.py, line 150:

<comment>The measurement dicts built inline in _run_live duplicate run.py's _to_measurement helper (both map Measurement.type plus list(registers) into the same "type"/"registers" shape). Keeping two copies forces any future change to the measurement wire format (e.g. adding a field) to be made in two places, which is exactly the kind of divergence the "simple but extendable" goal wants to avoid. Reuse _to_measurement here.</comment>

<file context>
@@ -0,0 +1,205 @@
+                "code_digest": verified.code_digest,
+                "code_measurement": {
+                    "type": verified.code_measurement.type,
+                    "registers": list(verified.code_measurement.registers),
+                },
+                "enclave_measurement": {
</file context>
Fix with cubic

@@ -0,0 +1,9 @@
"""Embedded production trust anchors, semantically identical to tinfoil-go's

@cubic-dev-ai cubic-dev-ai Bot Aug 30, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: SGX_ROOT_CA_PEM is byte-identical to INTEL_SGX_ROOT_CA_PEM already embedded in src/tinfoil/attestation/intel_root_ca.py, so the Intel SGX trust anchor now exists in two places. Trust anchors rotate (Intel's SGX root CA is expiring in 2049 but can still be rotated), and keeping two embedded copies means a future rotation or correction must be made in both modules or the v2 and v3 verifiers will silently diverge. Reuse a single source of the cert (e.g. a lightweight shared constant module that both attestation and v3 import) rather than embedding a second copy.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/tinfoil/v3/embedded_roots.py, line 9:

<comment>`SGX_ROOT_CA_PEM` is byte-identical to `INTEL_SGX_ROOT_CA_PEM` already embedded in `src/tinfoil/attestation/intel_root_ca.py`, so the Intel SGX trust anchor now exists in two places. Trust anchors rotate (Intel's SGX root CA is expiring in 2049 but can still be rotated), and keeping two embedded copies means a future rotation or correction must be made in both modules or the v2 and v3 verifiers will silently diverge. Reuse a single source of the cert (e.g. a lightweight shared constant module that both `attestation` and `v3` import) rather than embedding a second copy.</comment>

<file context>
@@ -0,0 +1,9 @@
+TRUSTED_ROOT_JSON = "{\n  \"mediaType\": \"application/vnd.dev.sigstore.trustedroot+json;version=0.1\",\n  \"tlogs\": [\n    {\n      \"baseUrl\": \"https://rekor.sigstore.dev\",\n      \"hashAlgorithm\": \"SHA2_256\",\n      \"publicKey\": {\n        \"rawBytes\": \"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE2G2Y+2tabdTV5BcGiBIx0a9fAFwrkBbmLSGtks4L3qX6yYY0zufBnhC8Ur/iy55GhWP/9A/bY2LhC30M9+RYtw==\",\n        \"keyDetails\": \"PKIX_ECDSA_P256_SHA_256\",\n        \"validFor\": {\n          \"start\": \"2021-01-12T11:53:27Z\"\n        }\n      },\n      \"logId\": {\n        \"keyId\": \"wNI9atQGlz+VWfO6LRygH4QUfY/8W4RFwiT5i5WRgB0=\"\n      }\n    },\n    {\n      \"baseUrl\": \"https://log2025-1.rekor.sigstore.dev\",\n      \"hashAlgorithm\": \"SHA2_256\",\n      \"publicKey\": {\n        \"rawBytes\": \"MCowBQYDK2VwAyEAt8rlp1knGwjfbcXAYPYAkn0XiLz1x8O4t0YkEhie244=\",\n        \"keyDetails\": \"PKIX_ED25519\",\n        \"validFor\": {\n          \"start\": \"2025-09-23T00:00:00Z\"\n        }\n      },\n      \"logId\": {\n        \"keyId\": \"zxGZFVvd0FEmjR8WrFwMdcAJ9vtaY/QXf44Y1wUeP6A=\"\n      }\n    }\n  ],\n  \"certificateAuthorities\": [\n    {\n      \"subject\": {\n        \"organization\": \"sigstore.dev\",\n        \"commonName\": \"sigstore\"\n      },\n      \"uri\": \"https://fulcio.sigstore.dev\",\n      \"certChain\": {\n        \"certificates\": [\n          {\n            \"rawBytes\": \"MIIB+DCCAX6gAwIBAgITNVkDZoCiofPDsy7dfm6geLbuhzAKBggqhkjOPQQDAzAqMRUwEwYDVQQKEwxzaWdzdG9yZS5kZXYxETAPBgNVBAMTCHNpZ3N0b3JlMB4XDTIxMDMwNzAzMjAyOVoXDTMxMDIyMzAzMjAyOVowKjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTB2MBAGByqGSM49AgEGBSuBBAAiA2IABLSyA7Ii5k+pNO8ZEWY0ylemWDowOkNa3kL+GZE5Z5GWehL9/A9bRNA3RbrsZ5i0JcastaRL7Sp5fp/jD5dxqc/UdTVnlvS16an+2Yfswe/QuLolRUCrcOE2+2iA5+tzd6NmMGQwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYEFMjFHQBBmiQpMlEk6w2uSu1KBtPsMB8GA1UdIwQYMBaAFMjFHQBBmiQpMlEk6w2uSu1KBtPsMAoGCCqGSM49BAMDA2gAMGUCMH8liWJfMui6vXXBhjDgY4MwslmN/TJxVe/83WrFomwmNf056y1X48F9c4m3a3ozXAIxAKjRay5/aj/jsKKGIkmQatjI8uupHr/+CxFvaJWmpYqNkLDGRU+9orzh5hI2RrcuaQ==\"\n          }\n        ]\n      },\n      \"validFor\": {\n        \"start\": \"2021-03-07T03:20:29Z\",\n        \"end\": \"2022-12-31T23:59:59.999Z\"\n      }\n    },\n    {\n      \"subject\": {\n        \"organization\": \"sigstore.dev\",\n        \"commonName\": \"sigstore\"\n      },\n      \"uri\": \"https://fulcio.sigstore.dev\",\n      \"certChain\": {\n        \"certificates\": [\n          {\n            \"rawBytes\": \"MIICGjCCAaGgAwIBAgIUALnViVfnU0brJasmRkHrn/UnfaQwCgYIKoZIzj0EAwMwKjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTAeFw0yMjA0MTMyMDA2MTVaFw0zMTEwMDUxMzU2NThaMDcxFTATBgNVBAoTDHNpZ3N0b3JlLmRldjEeMBwGA1UEAxMVc2lnc3RvcmUtaW50ZXJtZWRpYXRlMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE8RVS/ysH+NOvuDZyPIZtilgUF9NlarYpAd9HP1vBBH1U5CV77LSS7s0ZiH4nE7Hv7ptS6LvvR/STk798LVgMzLlJ4HeIfF3tHSaexLcYpSASr1kS0N/RgBJz/9jWCiXno3sweTAOBgNVHQ8BAf8EBAMCAQYwEwYDVR0lBAwwCgYIKwYBBQUHAwMwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU39Ppz1YkEZb5qNjpKFWixi4YZD8wHwYDVR0jBBgwFoAUWMAeX5FFpWapesyQoZMi0CrFxfowCgYIKoZIzj0EAwMDZwAwZAIwPCsQK4DYiZYDPIaDi5HFKnfxXx6ASSVmERfsynYBiX2X6SJRnZU84/9DZdnFvvxmAjBOt6QpBlc4J/0DxvkTCqpclvziL6BCCPnjdlIB3Pu3BxsPmygUY7Ii2zbdCdliiow=\"\n          },\n          {\n            \"rawBytes\": \"MIIB9zCCAXygAwIBAgIUALZNAPFdxHPwjeDloDwyYChAO/4wCgYIKoZIzj0EAwMwKjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTAeFw0yMTEwMDcxMzU2NTlaFw0zMTEwMDUxMzU2NThaMCoxFTATBgNVBAoTDHNpZ3N0b3JlLmRldjERMA8GA1UEAxMIc2lnc3RvcmUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAT7XeFT4rb3PQGwS4IajtLk3/OlnpgangaBclYpsYBr5i+4ynB07ceb3LP0OIOZdxexX69c5iVuyJRQ+Hz05yi+UF3uBWAlHpiS5sh0+H2GHE7SXrk1EC5m1Tr19L9gg92jYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRYwB5fkUWlZql6zJChkyLQKsXF+jAfBgNVHSMEGDAWgBRYwB5fkUWlZql6zJChkyLQKsXF+jAKBggqhkjOPQQDAwNpADBmAjEAj1nHeXZp+13NWBNa+EDsDP8G1WWg1tCMWP/WHPqpaVo0jhsweNFZgSs0eE7wYI4qAjEA2WB9ot98sIkoF3vZYdd3/VtWB5b9TNMea7Ix/stJ5TfcLLeABLE4BNJOsQ4vnBHJ\"\n          }\n        ]\n      },\n      \"validFor\": {\n        \"start\": \"2022-04-13T20:06:15Z\"\n      }\n    }\n  ],\n  \"ctlogs\": [\n    {\n      \"baseUrl\": \"https://ctfe.sigstore.dev/test\",\n      \"hashAlgorithm\": \"SHA2_256\",\n      \"publicKey\": {\n        \"rawBytes\": \"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEbfwR+RJudXscgRBRpKX1XFDy3PyudDxz/SfnRi1fT8ekpfBd2O1uoz7jr3Z8nKzxA69EUQ+eFCFI3zeubPWU7w==\",\n        \"keyDetails\": \"PKIX_ECDSA_P256_SHA_256\",\n        \"validFor\": {\n          \"start\": \"2021-03-14T00:00:00Z\",\n          \"end\": \"2022-10-31T23:59:59.999Z\"\n        }\n      },\n      \"logId\": {\n        \"keyId\": \"CGCS8ChS/2hF0dFrJ4ScRWcYrBY9wzjSbea8IgY2b3I=\"\n      }\n    },\n    {\n      \"baseUrl\": \"https://ctfe.sigstore.dev/2022\",\n      \"hashAlgorithm\": \"SHA2_256\",\n      \"publicKey\": {\n        \"rawBytes\": \"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEiPSlFi0CmFTfEjCUqF9HuCEcYXNKAaYalIJmBZ8yyezPjTqhxrKBpMnaocVtLJBI1eM3uXnQzQGAJdJ4gs9Fyw==\",\n        \"keyDetails\": \"PKIX_ECDSA_P256_SHA_256\",\n        \"validFor\": {\n          \"start\": \"2022-10-20T00:00:00Z\"\n        }\n      },\n      \"logId\": {\n        \"keyId\": \"3T0wasbHETJjGR4cmWc3AqJKXrjePK3/h4pygC8p7o4=\"\n      }\n    }\n  ],\n  \"timestampAuthorities\": [\n    {\n      \"subject\": {\n        \"organization\": \"sigstore.dev\",\n        \"commonName\": \"sigstore-tsa-selfsigned\"\n      },\n      \"uri\": \"https://timestamp.sigstore.dev/api/v1/timestamp\",\n      \"certChain\": {\n        \"certificates\": [\n          {\n            \"rawBytes\": \"MIICEDCCAZagAwIBAgIUOhNULwyQYe68wUMvy4qOiyojiwwwCgYIKoZIzj0EAwMwOTEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MSAwHgYDVQQDExdzaWdzdG9yZS10c2Etc2VsZnNpZ25lZDAeFw0yNTA0MDgwNjU5NDNaFw0zNTA0MDYwNjU5NDNaMC4xFTATBgNVBAoTDHNpZ3N0b3JlLmRldjEVMBMGA1UEAxMMc2lnc3RvcmUtdHNhMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE4ra2Z8hKNig2T9kFjCAToGG30jky+WQv3BzL+mKvh1SKNR/UwuwsfNCg4sryoYAd8E6isovVA3M4aoNdm9QDi50Z8nTEyvqgfDPtTIwXItfiW/AFf1V7uwkbkAoj0xxco2owaDAOBgNVHQ8BAf8EBAMCB4AwHQYDVR0OBBYEFIn9eUOHz9BlRsMCRscsc1t9tOsDMB8GA1UdIwQYMBaAFJjsAe9/u1H/1JUeb4qImFMHic6/MBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMIMAoGCCqGSM49BAMDA2gAMGUCMDtpsV/6KaO0qyF/UMsX2aSUXKQFdoGTptQGc0ftq1csulHPGG6dsmyMNd3JB+G3EQIxAOajvBcjpJmKb4Nv+2Taoj8Uc5+b6ih6FXCCKraSqupe07zqswMcXJTe1cExvHvvlw==\"\n          },\n          {\n            \"rawBytes\": \"MIIB9zCCAXygAwIBAgIUV7f0GLDOoEzIh8LXSW80OJiUp14wCgYIKoZIzj0EAwMwOTEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MSAwHgYDVQQDExdzaWdzdG9yZS10c2Etc2VsZnNpZ25lZDAeFw0yNTA0MDgwNjU5NDNaFw0zNTA0MDYwNjU5NDNaMDkxFTATBgNVBAoTDHNpZ3N0b3JlLmRldjEgMB4GA1UEAxMXc2lnc3RvcmUtdHNhLXNlbGZzaWduZWQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQUQNtfRT/ou3YATa6wB/kKTe70cfJwyRIBovMnt8RcJph/COE82uyS6FmppLLL1VBPGcPfpQPYJNXzWwi8icwhKQ6W/Qe2h3oebBb2FHpwNJDqo+TMaC/tdfkv/ElJB72jRTBDMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBSY7AHvf7tR/9SVHm+KiJhTB4nOvzAKBggqhkjOPQQDAwNpADBmAjEAwGEGrfGZR1cen1R8/DTVMI943LssZmJRtDp/i7SfGHmGRP6gRbuj9vOK3b67Z0QQAjEAuT2H673LQEaHTcyQSZrkp4mX7WwkmF+sVbkYY5mXN+RMH13KUEHHOqASaemYWK/E\"\n          }\n        ]\n      },\n      \"validFor\": {\n        \"start\": \"2025-07-04T00:00:00Z\"\n      }\n    }\n  ]\n}\n"
+GENOA_CERT_CHAIN_PEM = "-----BEGIN CERTIFICATE-----\n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\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\n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\n/wMz1R1BHg==\n-----END CERTIFICATE-----\n"
+TURIN_CERT_CHAIN_PEM = "-----BEGIN CERTIFICATE-----\n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\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\n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\nzpacMwFusA==\n-----END CERTIFICATE-----\n"
+SGX_ROOT_CA_PEM = "-----BEGIN CERTIFICATE-----\nMIICjzCCAjSgAwIBAgIUImUM1lqdNInzg7SVUr9QGzknBqwwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTE4MDUyMTEwNDUxMFoXDTQ5MTIzMTIzNTk1OVowaDEaMBgG\nA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0\naW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJBgNVBAYT\nAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC6nEwMDIYZOj/iPWsCzaEKi7\n1OiOSLRFhWGjbnBVJfVnkY4u3IjkDYYL0MxO4mqsyYjlBalTVYxFP2sJBK5zlKOB\nuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBSBgNVHR8ESzBJ\nMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2VydmljZXMuaW50\nZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUImUM1lqdNInzg7SV\nUr9QGzknBqwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwCgYI\nKoZIzj0EAwIDSQAwRgIhAOW/5QkR+S9CiSDcNoowLuPRLsWGf/Yi7GSX94BgwTwg\nAiEA4J0lrHoMs+Xo5o/sX6O9QWxHRAvZUGOdRQ7cvqRXaqI=\n-----END CERTIFICATE-----\n"
</file context>
Fix with cubic

opts.rtmrs = [rtmr0, code.rtmr1, code.rtmr2, code.rtmr3]
opts.report_data = report_data

if p.minimum_tcb_evaluation_data_number is None: # _options validated already

@cubic-dev-ai cubic-dev-ai Bot Aug 30, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: Custom agent: Nuke belt-and-suspenders

_options(p) already rejects minimum_tcb_evaluation_data_number is None through validate_tdx_policy(p), so this guard is unreachable after a successful call. Remove the duplicate check and keep policy validation centralized in _options.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/tinfoil/v3/tdx/expectations.py, line 106:

<comment>`_options(p)` already rejects `minimum_tcb_evaluation_data_number is None` through `validate_tdx_policy(p)`, so this guard is unreachable after a successful call. Remove the duplicate check and keep policy validation centralized in `_options`.</comment>

<file context>
@@ -0,0 +1,260 @@
+    opts.rtmrs = [rtmr0, code.rtmr1, code.rtmr2, code.rtmr3]
+    opts.report_data = report_data
+
+    if p.minimum_tcb_evaluation_data_number is None:  # _options validated already
+        raise _policy_error("policy minimum_tcb_evaluation_data_number is missing")
+    return (
</file context>
Fix with cubic

"""Compute a fingerprint for a measurement. Single-register measurements
return the register value directly; multi-register measurements hash the
type URL concatenated with all register values (no separator)."""
if m.type == SNP_TDX_MULTI_PLATFORM_V1: # Source

@cubic-dev-ai cubic-dev-ai Bot Aug 30, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: Custom agent: Slop Comments

These inline labels merely restate the predicate-type branches and do not explain a non-obvious invariant or behavior. Remove # Source and # Runtime to keep the dispatch readable.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/tinfoil/v3/measurement.py, line 42:

<comment>These inline labels merely restate the predicate-type branches and do not explain a non-obvious invariant or behavior. Remove `# Source` and `# Runtime` to keep the dispatch readable.</comment>

<file context>
@@ -0,0 +1,62 @@
+    """Compute a fingerprint for a measurement. Single-register measurements
+    return the register value directly; multi-register measurements hash the
+    type URL concatenated with all register values (no separator)."""
+    if m.type == SNP_TDX_MULTI_PLATFORM_V1:  # Source
+        if target_type == SEV_GUEST_V2:
+            registers = [m.registers[0]]
</file context>
Fix with cubic

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant