fix: make local Telegram verification preparation-only
This commit is contained in:
parent
8f87c540dc
commit
35c9531950
2 changed files with 164 additions and 83 deletions
|
|
@ -1,5 +1,5 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Verify retained authenticated-Chrome proof for Leo's unseen Telegram chain."""
|
||||
"""Validate local Telegram capture structure without authenticating live delivery."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
|
|
@ -24,12 +24,15 @@ except ImportError: # pragma: no cover - imported as scripts.* in tests
|
|||
from scripts import collect_telegram_visible_unseen_chain_state as state_collector
|
||||
from scripts import verify_leo_unseen_reasoning_chain as unseen
|
||||
|
||||
SCHEMA = "livingip.telegramVisibleUnseenChainReceipt.v2"
|
||||
SCHEMA = "livingip.telegramVisibleUnseenChainReceipt.v3"
|
||||
CAPTURE_SCHEMA = "livingip.telegramVisibleUnseenChainCapture.v1"
|
||||
BROWSER_PROVENANCE_SCHEMA = "livingip.authenticatedChromeTelegramCaptureProvenance.v1"
|
||||
SHA64_RE = re.compile(r"^[0-9a-f]{64}$")
|
||||
MIN_SCREENSHOT_WIDTH = 320
|
||||
MIN_SCREENSHOT_HEIGHT = 200
|
||||
PREPARATION_STATUS = "prepared_external_receipt_required"
|
||||
PREPARATION_TIER = "T0_local_preparation"
|
||||
FAILED_PREPARATION_TIER = "T0_failed_preparation"
|
||||
DEFAULT_CODEX_SESSIONS_ROOT = Path.home() / ".codex" / "sessions"
|
||||
REPORT_DIR = Path("docs/reports/leo-working-state-20260709")
|
||||
DEFAULT_PACKET = packet_builder.DEFAULT_OUT
|
||||
|
|
@ -57,6 +60,24 @@ def _present(value: Any) -> bool:
|
|||
return True
|
||||
|
||||
|
||||
def _preparation_only_fields(*, preparation_ready: bool) -> dict[str, Any]:
|
||||
return {
|
||||
"verification_scope": "caller_writable_preparation_structure",
|
||||
"preparation_ready": preparation_ready,
|
||||
"receipt_ready": False,
|
||||
"current_tier": PREPARATION_TIER if preparation_ready else FAILED_PREPARATION_TIER,
|
||||
"required_tier": "T3_live_readonly",
|
||||
"telegram_visible_messages_sent": False,
|
||||
"live_receipt_boundary": {
|
||||
"required": True,
|
||||
"verified": False,
|
||||
"accepted_by_this_api": False,
|
||||
"authority": "independently_authenticated_platform_browser_receipt",
|
||||
"local_inputs_are": "caller_writable_preparation_evidence",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def blank_capture_template(packet: dict[str, Any], preflight: dict[str, Any]) -> dict[str, Any]:
|
||||
target = packet.get("target") or {}
|
||||
return {
|
||||
|
|
@ -322,7 +343,7 @@ def _browser_provenance_checks(
|
|||
"browser_provenance_artifact_hashes_exact": provenance.get("artifacts") == artifact_hashes,
|
||||
"browser_provenance_capture_timestamp_bound": browser.get("captured_at_utc")
|
||||
== capture_source.get("captured_at_utc"),
|
||||
"authorization_provenance_is_independent_codex_user_message": authorization.get("source")
|
||||
"authorization_provenance_claim_has_codex_user_message_shape": authorization.get("source")
|
||||
== "codex_platform_user_message"
|
||||
and all(
|
||||
len(str(authorization.get(key) or "")) >= 8 for key in ("thread_id", "user_message_id", "source_receipt_id")
|
||||
|
|
@ -336,7 +357,7 @@ def _browser_provenance_checks(
|
|||
return checks, provenance
|
||||
|
||||
|
||||
def _codex_rollout_provenance_checks(
|
||||
def _local_codex_rollout_structure_checks(
|
||||
rollout_path: Path | None,
|
||||
*,
|
||||
sessions_root: Path,
|
||||
|
|
@ -348,6 +369,8 @@ def _codex_rollout_provenance_checks(
|
|||
artifact_hashes: dict[str, Any],
|
||||
messages: list[dict[str, Any]],
|
||||
) -> tuple[dict[str, bool], dict[str, Any]]:
|
||||
# Codex session JSONL is same-user writable. These checks establish internal
|
||||
# consistency for external review, never an independently authenticated receipt.
|
||||
root = sessions_root.resolve()
|
||||
resolved = rollout_path.resolve() if rollout_path is not None else Path()
|
||||
contained = bool(rollout_path) and resolved.is_file() and root in resolved.parents
|
||||
|
|
@ -513,9 +536,8 @@ def _codex_rollout_provenance_checks(
|
|||
authorization_event_at = _parse_aware_timestamp(user_event.get("timestamp")) if user_event else None
|
||||
capture_source = capture.get("capture_source") if isinstance(capture.get("capture_source"), dict) else {}
|
||||
checks = {
|
||||
"codex_rollout_log_is_trusted_external_file": contained
|
||||
and outside_evidence_root
|
||||
and thread_id in resolved.name,
|
||||
"codex_rollout_log_has_expected_local_sessions_shape": contained and thread_id in resolved.name,
|
||||
"codex_rollout_log_is_separate_from_evidence_root": outside_evidence_root,
|
||||
"codex_rollout_log_jsonl_valid": jsonl_valid and bool(events),
|
||||
"codex_rollout_session_meta_matches_thread": session_meta_ids == [thread_id],
|
||||
"codex_rollout_has_exact_single_authorization_event": len(matching_user_events) == 1,
|
||||
|
|
@ -726,7 +748,7 @@ def verify_capture(
|
|||
packet_path: Path,
|
||||
evidence_root: Path,
|
||||
codex_rollout_log: Path | None = None,
|
||||
codex_sessions_root: Path = DEFAULT_CODEX_SESSIONS_ROOT,
|
||||
codex_sessions_root: Path | None = None,
|
||||
) -> dict[str, Any]:
|
||||
if capture is None:
|
||||
packet_integrity = state_collector.packet_checks(packet)
|
||||
|
|
@ -740,12 +762,9 @@ def verify_capture(
|
|||
return {
|
||||
"schema": SCHEMA,
|
||||
"generated_at_utc": datetime.now(timezone.utc).isoformat(),
|
||||
"mode": "telegram_visible_unseen_chain_capture_verifier",
|
||||
"mode": "telegram_visible_unseen_chain_preparation_verifier",
|
||||
"status": "awaiting_action_time_authorization" if ready else "fail",
|
||||
"receipt_ready": False,
|
||||
"current_tier": "T0_packet_plus_T3_preflight" if ready else "T0_failed_preflight",
|
||||
"required_tier": "T3_live_readonly",
|
||||
"telegram_visible_messages_sent": False,
|
||||
**_preparation_only_fields(preparation_ready=ready),
|
||||
"mutates_db": False,
|
||||
"packet_path": str(packet_path),
|
||||
"preflight_path": str(DEFAULT_PREFLIGHT),
|
||||
|
|
@ -760,11 +779,12 @@ def verify_capture(
|
|||
},
|
||||
"claim_ceiling": {
|
||||
"proven": (
|
||||
"The exact packet and live zero-mutation preflight are ready."
|
||||
"The caller-supplied packet and preflight are structurally ready for external review."
|
||||
if ready
|
||||
else "No readiness claim; packet or preflight integrity validation failed."
|
||||
),
|
||||
"not_proven": [
|
||||
"independently authenticated platform or browser receipt",
|
||||
"Telegram-visible message delivery",
|
||||
"Telegram-visible Leo replies",
|
||||
"post-send fingerprint equality",
|
||||
|
|
@ -834,9 +854,9 @@ def verify_capture(
|
|||
messages=messages,
|
||||
artifact_hashes=artifact_hashes,
|
||||
)
|
||||
codex_rollout_checks, codex_rollout_evidence = _codex_rollout_provenance_checks(
|
||||
codex_rollout_checks, codex_rollout_evidence = _local_codex_rollout_structure_checks(
|
||||
codex_rollout_log,
|
||||
sessions_root=codex_sessions_root,
|
||||
sessions_root=codex_sessions_root or DEFAULT_CODEX_SESSIONS_ROOT,
|
||||
evidence_root=evidence_root,
|
||||
packet=packet,
|
||||
capture=capture,
|
||||
|
|
@ -971,8 +991,8 @@ def verify_capture(
|
|||
),
|
||||
**semantics,
|
||||
}
|
||||
outcomes = {
|
||||
"telegram_visible_three_turn_chain": all(
|
||||
preparation_outcomes = {
|
||||
"caller_bundle_three_turn_chain_structurally_consistent": all(
|
||||
checks[key]
|
||||
for key in (
|
||||
"authenticated_chrome_transport_declared",
|
||||
|
|
@ -999,7 +1019,7 @@ def verify_capture(
|
|||
"turn_accessibility_binds_exact_messages_and_replies",
|
||||
)
|
||||
),
|
||||
"visible_db_grounded_challenge": all(
|
||||
"caller_bundle_db_grounded_challenge_structurally_consistent": all(
|
||||
checks[key]
|
||||
for key in (
|
||||
"visible_db_object_selected_without_operator_id",
|
||||
|
|
@ -1009,7 +1029,7 @@ def verify_capture(
|
|||
"independent_db_object_matches_visible_subject",
|
||||
)
|
||||
),
|
||||
"visible_review_only_revision": all(
|
||||
"caller_bundle_review_only_revision_structurally_consistent": all(
|
||||
checks[key]
|
||||
for key in (
|
||||
"multiple_review_only_candidates_proposed",
|
||||
|
|
@ -1019,24 +1039,23 @@ def verify_capture(
|
|||
"reply_claimed_no_mutation",
|
||||
)
|
||||
),
|
||||
"canonical_state_unchanged": checks["canonical_fingerprint_unchanged_from_preflight"],
|
||||
"caller_bundle_canonical_state_claim_structurally_consistent": checks[
|
||||
"canonical_fingerprint_unchanged_from_preflight"
|
||||
],
|
||||
}
|
||||
passed = all(checks.values()) and all(outcomes.values())
|
||||
preparation_ready = all(checks.values()) and all(preparation_outcomes.values())
|
||||
return {
|
||||
"schema": SCHEMA,
|
||||
"generated_at_utc": datetime.now(timezone.utc).isoformat(),
|
||||
"mode": "telegram_visible_unseen_chain_capture_verifier",
|
||||
"status": "pass" if passed else "fail",
|
||||
"receipt_ready": passed,
|
||||
"current_tier": "T3_live_readonly" if passed else "T2_or_lower_incomplete_visible_proof",
|
||||
"required_tier": "T3_live_readonly",
|
||||
"telegram_visible_messages_sent": passed,
|
||||
"capture_claimed_messages_sent": True,
|
||||
"mode": "telegram_visible_unseen_chain_preparation_verifier",
|
||||
"status": PREPARATION_STATUS if preparation_ready else "fail",
|
||||
**_preparation_only_fields(preparation_ready=preparation_ready),
|
||||
"capture_bundle_present": True,
|
||||
"production_apply_executed": False,
|
||||
"mutates_db": False,
|
||||
"packet_path": str(packet_path),
|
||||
"checks": checks,
|
||||
"outcomes": outcomes,
|
||||
"preparation_outcomes": preparation_outcomes,
|
||||
"selected_subject": {
|
||||
"ref": subject_ref,
|
||||
"table": subject_match.get("table"),
|
||||
|
|
@ -1060,13 +1079,15 @@ def verify_capture(
|
|||
},
|
||||
"claim_ceiling": {
|
||||
"proven": (
|
||||
"One exact authenticated-Chrome Telegram chain visibly selected and challenged a DB object, "
|
||||
"proposed and revised review-only knowledge, preserved the approval/apply boundary, and left the "
|
||||
"canonical fingerprint unchanged."
|
||||
if passed
|
||||
else "No T3 claim; at least one visible, semantic, binding, or state check failed."
|
||||
"The caller-supplied capture bundle is structurally consistent, including its chronology, evidence, "
|
||||
"semantic, and unchanged-state claims. It is ready for an independently authenticated platform or "
|
||||
"browser receipt outside this verifier; no live activity is authenticated here."
|
||||
if preparation_ready
|
||||
else "No preparation claim; at least one structural, semantic, binding, or state check failed."
|
||||
),
|
||||
"not_proven": [
|
||||
"T3 live-readonly Telegram proof",
|
||||
"Telegram-visible message delivery or replies",
|
||||
"canonical proposal staging or apply",
|
||||
"agent-to-agent review",
|
||||
"GCP runtime parity for the Telegram-visible chain",
|
||||
|
|
@ -1086,10 +1107,12 @@ def write_markdown(path: Path, data: dict[str, Any]) -> None:
|
|||
"",
|
||||
f"Generated UTC: `{data['generated_at_utc']}`",
|
||||
f"Status: `{data['status']}`",
|
||||
f"Preparation ready: `{data['preparation_ready']}`",
|
||||
f"Receipt ready: `{data['receipt_ready']}`",
|
||||
f"Current tier: `{data['current_tier']}`",
|
||||
f"Required tier: `{data['required_tier']}`",
|
||||
f"Telegram-visible messages sent: `{data['telegram_visible_messages_sent']}`",
|
||||
f"Independent live receipt verified: `{data['live_receipt_boundary']['verified']}`",
|
||||
f"Mutates DB: `{data['mutates_db']}`",
|
||||
"",
|
||||
"## Checks",
|
||||
|
|
@ -1102,12 +1125,17 @@ def write_markdown(path: Path, data: dict[str, Any]) -> None:
|
|||
"",
|
||||
"## Awaiting Authorized Capture",
|
||||
"",
|
||||
"The packet and preflight are ready. No Telegram message has been sent by this verifier.",
|
||||
"A future T3 receipt also requires the exact platform authorization event and Chrome-backend capture receipts from the bound Codex rollout log.",
|
||||
"The packet and preflight are structurally ready. No Telegram message has been sent by this verifier.",
|
||||
"A future T3 receipt requires an independently authenticated platform/browser authority outside this verifier.",
|
||||
]
|
||||
)
|
||||
lines.extend(
|
||||
[
|
||||
"",
|
||||
"## Trust Boundary",
|
||||
"",
|
||||
"Local files, capture artifacts, and Codex rollout JSONL are caller-writable preparation evidence only. "
|
||||
"This verifier cannot accept or mint a live receipt.",
|
||||
"",
|
||||
"## Claim Ceiling",
|
||||
"",
|
||||
|
|
@ -1129,7 +1157,7 @@ def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
|
|||
parser.add_argument(
|
||||
"--codex-rollout-log",
|
||||
type=Path,
|
||||
help="Platform rollout JSONL containing the exact user authorization and Chrome capture tool receipts",
|
||||
help="Local Codex rollout JSONL for preparation-structure checks; this never authenticates a live receipt",
|
||||
)
|
||||
parser.add_argument("--out", type=Path, default=DEFAULT_OUT)
|
||||
parser.add_argument("--markdown-out", type=Path, default=DEFAULT_MARKDOWN_OUT)
|
||||
|
|
@ -1165,7 +1193,7 @@ def main(argv: list[str] | None = None) -> int:
|
|||
sort_keys=True,
|
||||
)
|
||||
)
|
||||
return 0 if receipt["status"] in {"pass", "awaiting_action_time_authorization"} else 2
|
||||
return 0 if receipt["status"] in {PREPARATION_STATUS, "awaiting_action_time_authorization"} else 2
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
|||
|
|
@ -383,9 +383,9 @@ def verified_fixture(tmp_path: Path) -> tuple[dict, Path, dict, dict, dict, Path
|
|||
packet, packet_path = packet_and_path(tmp_path)
|
||||
before = preflight(packet, packet_path)
|
||||
after = postflight(packet, packet_path, before)
|
||||
capture, trusted_sha256 = good_capture(packet, tmp_path)
|
||||
capture, rollout = good_capture(packet, tmp_path)
|
||||
capture["preflight_state_token_sha256"] = before["state_token_sha256"]
|
||||
return packet, packet_path, before, after, capture, trusted_sha256
|
||||
return packet, packet_path, before, after, capture, rollout
|
||||
|
||||
|
||||
def run_verifier(
|
||||
|
|
@ -425,22 +425,72 @@ def test_no_capture_returns_awaiting_authorization_template(tmp_path: Path) -> N
|
|||
)
|
||||
|
||||
assert receipt["status"] == "awaiting_action_time_authorization"
|
||||
assert receipt["preparation_ready"] is True
|
||||
assert receipt["receipt_ready"] is False
|
||||
assert receipt["current_tier"] == verifier.PREPARATION_TIER
|
||||
assert receipt["telegram_visible_messages_sent"] is False
|
||||
assert receipt["live_receipt_boundary"]["accepted_by_this_api"] is False
|
||||
assert receipt["live_receipt_boundary"]["verified"] is False
|
||||
assert receipt["capture_template"]["schema"] == verifier.CAPTURE_SCHEMA
|
||||
assert receipt["capture_template"]["messages"][0]["prompt_id"] == "OOS-CHAIN-01"
|
||||
|
||||
|
||||
def test_good_chrome_capture_and_unchanged_fingerprint_pass_t3(tmp_path: Path) -> None:
|
||||
packet, packet_path, before, after, capture, trusted = verified_fixture(tmp_path)
|
||||
def test_public_verifier_keeps_fully_well_formed_all_local_forgery_preparation_only(
|
||||
tmp_path: Path,
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
_packet, packet_path, before, after, capture, rollout = verified_fixture(tmp_path)
|
||||
preflight_path = tmp_path / "preflight.json"
|
||||
capture_path = tmp_path / "capture.json"
|
||||
postflight_path = tmp_path / "postflight.json"
|
||||
out_path = tmp_path / "receipt.json"
|
||||
markdown_path = tmp_path / "receipt.md"
|
||||
verifier.write_json(preflight_path, before)
|
||||
verifier.write_json(capture_path, capture)
|
||||
verifier.write_json(postflight_path, after)
|
||||
monkeypatch.setattr(verifier, "DEFAULT_CODEX_SESSIONS_ROOT", rollout.parents[3])
|
||||
|
||||
receipt = run_verifier(packet, packet_path, before, after, capture, trusted, tmp_path)
|
||||
exit_code = verifier.main(
|
||||
[
|
||||
"--packet",
|
||||
str(packet_path),
|
||||
"--preflight",
|
||||
str(preflight_path),
|
||||
"--capture-json",
|
||||
str(capture_path),
|
||||
"--postflight",
|
||||
str(postflight_path),
|
||||
"--evidence-root",
|
||||
str(tmp_path),
|
||||
"--codex-rollout-log",
|
||||
str(rollout),
|
||||
"--out",
|
||||
str(out_path),
|
||||
"--markdown-out",
|
||||
str(markdown_path),
|
||||
]
|
||||
)
|
||||
receipt = json.loads(out_path.read_text(encoding="utf-8"))
|
||||
|
||||
assert receipt["status"] == "pass"
|
||||
assert receipt["receipt_ready"] is True
|
||||
assert receipt["current_tier"] == "T3_live_readonly"
|
||||
assert exit_code == 0
|
||||
assert receipt["status"] == verifier.PREPARATION_STATUS
|
||||
assert receipt["verification_scope"] == "caller_writable_preparation_structure"
|
||||
assert receipt["preparation_ready"] is True
|
||||
assert receipt["receipt_ready"] is False
|
||||
assert receipt["current_tier"] == verifier.PREPARATION_TIER
|
||||
assert receipt["telegram_visible_messages_sent"] is False
|
||||
assert receipt["live_receipt_boundary"] == {
|
||||
"accepted_by_this_api": False,
|
||||
"authority": "independently_authenticated_platform_browser_receipt",
|
||||
"local_inputs_are": "caller_writable_preparation_evidence",
|
||||
"required": True,
|
||||
"verified": False,
|
||||
}
|
||||
assert all(receipt["checks"].values())
|
||||
assert all(receipt["outcomes"].values())
|
||||
assert all(receipt["preparation_outcomes"].values())
|
||||
assert receipt["selected_subject"]["row_id"] == SUBJECT_ID
|
||||
assert "T3_live_readonly" not in receipt["current_tier"]
|
||||
assert "caller-writable preparation evidence only" in markdown_path.read_text(encoding="utf-8")
|
||||
|
||||
|
||||
def test_self_declared_browser_provenance_without_codex_rollout_cannot_pass_t3(
|
||||
|
|
@ -452,7 +502,7 @@ def test_self_declared_browser_provenance_without_codex_rollout_cannot_pass_t3(
|
|||
|
||||
assert receipt["status"] == "fail"
|
||||
assert receipt["telegram_visible_messages_sent"] is False
|
||||
assert receipt["checks"]["codex_rollout_log_is_trusted_external_file"] is False
|
||||
assert receipt["checks"]["codex_rollout_log_has_expected_local_sessions_shape"] is False
|
||||
assert receipt["checks"]["codex_rollout_capture_events_are_chrome_backend"] is False
|
||||
|
||||
|
||||
|
|
@ -475,10 +525,10 @@ def test_non_chrome_rollout_capture_events_are_rejected(tmp_path: Path) -> None:
|
|||
|
||||
|
||||
def test_bot_api_capture_is_rejected(tmp_path: Path) -> None:
|
||||
packet, packet_path, before, after, capture, trusted = verified_fixture(tmp_path)
|
||||
packet, packet_path, before, after, capture, rollout = verified_fixture(tmp_path)
|
||||
capture["capture_source"]["transport"] = "telegram_bot_api"
|
||||
|
||||
receipt = run_verifier(packet, packet_path, before, after, capture, trusted, tmp_path)
|
||||
receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path)
|
||||
|
||||
assert receipt["status"] == "fail"
|
||||
assert receipt["checks"]["authenticated_chrome_transport_declared"] is False
|
||||
|
|
@ -486,10 +536,10 @@ def test_bot_api_capture_is_rejected(tmp_path: Path) -> None:
|
|||
|
||||
|
||||
def test_postflight_fingerprint_drift_is_rejected(tmp_path: Path) -> None:
|
||||
packet, packet_path, before, after, capture, trusted = verified_fixture(tmp_path)
|
||||
packet, packet_path, before, after, capture, rollout = verified_fixture(tmp_path)
|
||||
after["remote"]["fingerprint_after"]["fingerprint_sha256"] = "0" * 64
|
||||
|
||||
receipt = run_verifier(packet, packet_path, before, after, capture, trusted, tmp_path)
|
||||
receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path)
|
||||
|
||||
assert receipt["status"] == "fail"
|
||||
assert receipt["checks"]["postflight_state_token_derivation_valid"] is False
|
||||
|
|
@ -497,10 +547,10 @@ def test_postflight_fingerprint_drift_is_rejected(tmp_path: Path) -> None:
|
|||
|
||||
|
||||
def test_message_text_drift_is_rejected(tmp_path: Path) -> None:
|
||||
packet, packet_path, before, after, capture, trusted = verified_fixture(tmp_path)
|
||||
packet, packet_path, before, after, capture, rollout = verified_fixture(tmp_path)
|
||||
capture["messages"][1]["sent_text"] += " extra"
|
||||
|
||||
receipt = run_verifier(packet, packet_path, before, after, capture, trusted, tmp_path)
|
||||
receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path)
|
||||
|
||||
assert receipt["status"] == "fail"
|
||||
assert receipt["checks"]["sent_text_exact"] is False
|
||||
|
|
@ -518,31 +568,31 @@ def test_sent_and_reply_message_id_reuse_is_rejected(tmp_path: Path) -> None:
|
|||
|
||||
|
||||
def test_copied_reply_not_present_in_accessibility_is_rejected(tmp_path: Path) -> None:
|
||||
packet, packet_path, before, after, capture, trusted = verified_fixture(tmp_path)
|
||||
packet, packet_path, before, after, capture, rollout = verified_fixture(tmp_path)
|
||||
capture["messages"][0]["reply"] += " copied-only suffix"
|
||||
|
||||
receipt = run_verifier(packet, packet_path, before, after, capture, trusted, tmp_path)
|
||||
receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path)
|
||||
|
||||
assert receipt["status"] == "fail"
|
||||
assert receipt["checks"]["turn_accessibility_binds_exact_messages_and_replies"] is False
|
||||
|
||||
|
||||
def test_all_prompts_sent_before_replies_is_rejected(tmp_path: Path) -> None:
|
||||
packet, packet_path, before, after, capture, trusted = verified_fixture(tmp_path)
|
||||
packet, packet_path, before, after, capture, rollout = verified_fixture(tmp_path)
|
||||
capture["messages"][0]["reply_at_utc"] = "2026-07-15T00:02:30Z"
|
||||
|
||||
receipt = run_verifier(packet, packet_path, before, after, capture, trusted, tmp_path)
|
||||
receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path)
|
||||
|
||||
assert receipt["status"] == "fail"
|
||||
assert receipt["checks"]["strict_send_reply_turn_order"] is False
|
||||
|
||||
|
||||
def test_after_the_fact_authorization_is_rejected(tmp_path: Path) -> None:
|
||||
packet, packet_path, before, after, capture, _trusted = verified_fixture(tmp_path)
|
||||
packet, packet_path, before, after, capture, _rollout = verified_fixture(tmp_path)
|
||||
capture["operator_authorization_captured_at_utc"] = "2026-07-15T00:01:10Z"
|
||||
trusted = refresh_provenance_and_rollout(packet, capture, tmp_path)
|
||||
rollout = refresh_provenance_and_rollout(packet, capture, tmp_path)
|
||||
|
||||
receipt = run_verifier(packet, packet_path, before, after, capture, trusted, tmp_path)
|
||||
receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path)
|
||||
|
||||
assert receipt["status"] == "fail"
|
||||
assert receipt["checks"]["captured_authorization_before_first_send"] is False
|
||||
|
|
@ -550,22 +600,22 @@ def test_after_the_fact_authorization_is_rejected(tmp_path: Path) -> None:
|
|||
|
||||
@pytest.mark.parametrize("timestamp", ["2026-07-15T00:01:00", "not-a-timestamp"])
|
||||
def test_naive_or_malformed_timestamps_are_rejected(tmp_path: Path, timestamp: str) -> None:
|
||||
packet, packet_path, before, after, capture, trusted = verified_fixture(tmp_path)
|
||||
packet, packet_path, before, after, capture, rollout = verified_fixture(tmp_path)
|
||||
capture["messages"][0]["sent_at_utc"] = timestamp
|
||||
|
||||
receipt = run_verifier(packet, packet_path, before, after, capture, trusted, tmp_path)
|
||||
receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path)
|
||||
|
||||
assert receipt["status"] == "fail"
|
||||
assert receipt["checks"]["timestamps_valid_and_timezone_aware"] is False
|
||||
|
||||
|
||||
def test_reused_per_turn_evidence_is_rejected(tmp_path: Path) -> None:
|
||||
packet, packet_path, before, after, capture, _trusted = verified_fixture(tmp_path)
|
||||
packet, packet_path, before, after, capture, _rollout = verified_fixture(tmp_path)
|
||||
capture["messages"][1]["turn_screenshot"] = capture["messages"][0]["turn_screenshot"]
|
||||
capture["messages"][1]["turn_accessibility"] = capture["messages"][0]["turn_accessibility"]
|
||||
trusted = refresh_provenance_and_rollout(packet, capture, tmp_path)
|
||||
rollout = refresh_provenance_and_rollout(packet, capture, tmp_path)
|
||||
|
||||
receipt = run_verifier(packet, packet_path, before, after, capture, trusted, tmp_path)
|
||||
receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path)
|
||||
|
||||
assert receipt["status"] == "fail"
|
||||
assert receipt["checks"]["per_turn_screenshot_hashes_distinct_nonempty"] is False
|
||||
|
|
@ -573,56 +623,59 @@ def test_reused_per_turn_evidence_is_rejected(tmp_path: Path) -> None:
|
|||
|
||||
|
||||
def test_final_capture_may_reuse_turn_three_when_documented(tmp_path: Path) -> None:
|
||||
packet, packet_path, before, after, capture, _trusted = verified_fixture(tmp_path)
|
||||
packet, packet_path, before, after, capture, _rollout = verified_fixture(tmp_path)
|
||||
capture["capture_source"]["final_screenshot"] = capture["messages"][2]["turn_screenshot"]
|
||||
capture["capture_source"]["final_accessibility"] = capture["messages"][2]["turn_accessibility"]
|
||||
capture["capture_source"]["final_capture_reuses_turn_3"] = True
|
||||
capture["capture_source"]["final_capture_reuse_reason"] = (
|
||||
"The final Chrome capture is the retained third-turn response state."
|
||||
)
|
||||
trusted = refresh_provenance_and_rollout(packet, capture, tmp_path)
|
||||
rollout = refresh_provenance_and_rollout(packet, capture, tmp_path)
|
||||
|
||||
receipt = run_verifier(packet, packet_path, before, after, capture, trusted, tmp_path)
|
||||
receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path)
|
||||
|
||||
assert receipt["status"] == "pass"
|
||||
assert receipt["status"] == verifier.PREPARATION_STATUS
|
||||
assert receipt["preparation_ready"] is True
|
||||
assert receipt["receipt_ready"] is False
|
||||
assert receipt["telegram_visible_messages_sent"] is False
|
||||
assert receipt["checks"]["final_capture_reuse_policy_satisfied"] is True
|
||||
|
||||
|
||||
def test_undocumented_final_turn_three_reuse_is_rejected(tmp_path: Path) -> None:
|
||||
packet, packet_path, before, after, capture, _trusted = verified_fixture(tmp_path)
|
||||
packet, packet_path, before, after, capture, _rollout = verified_fixture(tmp_path)
|
||||
capture["capture_source"]["final_screenshot"] = capture["messages"][2]["turn_screenshot"]
|
||||
trusted = refresh_provenance_and_rollout(packet, capture, tmp_path)
|
||||
rollout = refresh_provenance_and_rollout(packet, capture, tmp_path)
|
||||
|
||||
receipt = run_verifier(packet, packet_path, before, after, capture, trusted, tmp_path)
|
||||
receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path)
|
||||
|
||||
assert receipt["status"] == "fail"
|
||||
assert receipt["checks"]["final_capture_reuse_policy_satisfied"] is False
|
||||
|
||||
|
||||
def test_evidence_path_escape_is_rejected(tmp_path: Path) -> None:
|
||||
packet, packet_path, before, after, capture, trusted = verified_fixture(tmp_path)
|
||||
packet, packet_path, before, after, capture, rollout = verified_fixture(tmp_path)
|
||||
outside = tmp_path.parent / "outside-turn.png"
|
||||
write_png(outside, (1, 2, 3, 255))
|
||||
capture["messages"][0]["turn_screenshot"] = str(outside)
|
||||
|
||||
receipt = run_verifier(packet, packet_path, before, after, capture, trusted, tmp_path)
|
||||
receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path)
|
||||
|
||||
assert receipt["status"] == "fail"
|
||||
assert receipt["checks"]["all_evidence_paths_contained_in_root"] is False
|
||||
|
||||
|
||||
def test_non_png_screenshot_is_rejected(tmp_path: Path) -> None:
|
||||
packet, packet_path, before, after, capture, _trusted = verified_fixture(tmp_path)
|
||||
packet, packet_path, before, after, capture, _rollout = verified_fixture(tmp_path)
|
||||
Path(capture["messages"][0]["turn_screenshot"]).write_bytes(b"not a png")
|
||||
trusted = refresh_provenance_and_rollout(packet, capture, tmp_path)
|
||||
rollout = refresh_provenance_and_rollout(packet, capture, tmp_path)
|
||||
|
||||
receipt = run_verifier(packet, packet_path, before, after, capture, trusted, tmp_path)
|
||||
receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path)
|
||||
|
||||
assert receipt["status"] == "fail"
|
||||
assert receipt["checks"]["screenshots_are_valid_png_with_metadata"] is False
|
||||
|
||||
|
||||
def test_fabricated_local_bundle_without_supported_state_or_trusted_chrome_provenance_fails(
|
||||
def test_malformed_local_bundle_without_supported_state_or_rollout_structure_fails(
|
||||
tmp_path: Path,
|
||||
) -> None:
|
||||
packet, packet_path = packet_and_path(tmp_path)
|
||||
|
|
@ -696,18 +749,18 @@ def test_fabricated_local_bundle_without_supported_state_or_trusted_chrome_prove
|
|||
assert receipt["checks"]["capture_schema_supported"] is False
|
||||
assert receipt["checks"]["preflight_schema_supported"] is False
|
||||
assert receipt["checks"]["preflight_state_token_derivation_valid"] is False
|
||||
assert receipt["checks"]["codex_rollout_log_is_trusted_external_file"] is False
|
||||
assert receipt["checks"]["codex_rollout_log_has_expected_local_sessions_shape"] is False
|
||||
assert receipt["checks"]["codex_rollout_has_exact_single_authorization_event"] is False
|
||||
assert receipt["checks"]["screenshots_are_valid_png_with_metadata"] is False
|
||||
assert receipt["checks"]["per_turn_screenshot_hashes_distinct_nonempty"] is False
|
||||
|
||||
|
||||
def test_state_token_tampering_is_rejected(tmp_path: Path) -> None:
|
||||
packet, packet_path, before, after, capture, trusted = verified_fixture(tmp_path)
|
||||
packet, packet_path, before, after, capture, rollout = verified_fixture(tmp_path)
|
||||
before = copy.deepcopy(before)
|
||||
before["generated_at_utc"] = "2026-07-14T23:58:00Z"
|
||||
|
||||
receipt = run_verifier(packet, packet_path, before, after, capture, trusted, tmp_path)
|
||||
receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path)
|
||||
|
||||
assert receipt["status"] == "fail"
|
||||
assert receipt["checks"]["preflight_state_token_derivation_valid"] is False
|
||||
|
|
|
|||
Loading…
Reference in a new issue