joy7759's picture
Upload 4 files
4a7b4cf verified
Raw
History Blame Contribute Delete
8.09 kB
from __future__ import annotations
import json
import tempfile
from datetime import datetime, timezone
from pathlib import Path
from secrets import token_hex
from typing import Any
from uuid import uuid4
import gradio as gr
from verifiable_tool_invocation_flow.guarded_tool_call import guarded_tool_call
from verifiable_tool_invocation_flow.models import ExecutionRequest, PolicySnapshot, ToolManifest
from verifiable_tool_invocation_flow.resources import load_example_json
from verifiable_tool_invocation_flow.signer import ReceiptSigner
from verifiable_tool_invocation_flow.tools.demo_metadata_lookup_tool import demo_metadata_lookup_tool
from verifiable_tool_invocation_flow.validator import validate_receipt
DEFAULT_AUDIENCE = "demo-validator"
CHECK_FIELDS = [
"schema_valid",
"input_hash_match",
"policy_hash_match",
"tool_manifest_hash_match",
"tool_input_hash_match",
"tool_output_hash_match",
"result_hash_match",
"pre_execution_commitment_match",
"policy_decision_valid",
"signature_valid",
"time_window_valid",
"replay_check_performed",
"replay_detected",
"audience_match",
"request_binding_match",
]
def load_json_upload(file_path: str | None) -> dict[str, Any]:
if not file_path:
raise gr.Error("Missing JSON file upload.")
try:
payload = json.loads(Path(file_path).read_text(encoding="utf-8"))
except json.JSONDecodeError as exc:
raise gr.Error(f"Invalid JSON upload: {exc.msg}") from exc
if not isinstance(payload, dict):
raise gr.Error("Uploaded JSON must be an object.")
return payload
def load_text_upload(file_path: str | None) -> bytes:
if not file_path:
raise gr.Error("Missing text file upload.")
return Path(file_path).read_bytes()
def summarize_report(report: dict[str, Any]) -> list[list[str]]:
rows: list[list[str]] = []
for field in CHECK_FIELDS:
value = report.get(field)
if isinstance(value, bool):
status = "pass" if value else "fail"
else:
status = "n/a"
rows.append([field, status])
return rows
def validate_uploaded_receipt(
receipt_file: str | None,
evidence_file: str | None,
public_key_file: str | None,
audience: str | None,
) -> tuple[str, list[list[str]], list[str], list[str], dict[str, Any], str]:
receipt = load_json_upload(receipt_file)
evidence = load_json_upload(evidence_file)
public_key = load_text_upload(public_key_file)
report = validate_receipt(
receipt=receipt,
evidence_bundle=evidence,
public_key_pem=public_key,
audience=(audience or DEFAULT_AUDIENCE).strip() or DEFAULT_AUDIENCE,
replay_cache_path=None,
update_replay_cache=False,
)
report_path = _write_temp_json("verification_report.json", report)
return (
str(report["verdict"]),
summarize_report(report),
report.get("errors", []),
report.get("warnings", []),
report,
report_path,
)
def run_builtin_demo() -> tuple[str, list[list[str]], dict[str, Any], str, str, str, str]:
request = _build_demo_request()
policy = PolicySnapshot.model_validate(load_example_json("policy_snapshot.json"))
tool_manifest = ToolManifest.model_validate(load_example_json("tool_manifest.json"))
tool_input = load_example_json("tool_input.json")
signer = ReceiptSigner.generate_demo()
result = guarded_tool_call(
request,
policy,
tool_manifest,
tool_input,
demo_metadata_lookup_tool,
signer,
audience=DEFAULT_AUDIENCE,
replay_cache_path=None,
update_replay_cache=False,
)
receipt_path = _write_temp_json("execution_receipt.json", result.receipt)
evidence_path = _write_temp_json("evidence_bundle.json", result.evidence_bundle)
report_path = _write_temp_json("verification_report.json", result.verification_report)
public_key_path = _write_temp_bytes("demo_public_key.pem", signer.public_key_pem())
return (
str(result.verification_report["verdict"]),
summarize_report(result.verification_report),
result.verification_report,
receipt_path,
evidence_path,
public_key_path,
report_path,
)
def _build_demo_request() -> ExecutionRequest:
payload = load_example_json("input_request.json")
now = datetime.now(timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")
payload.update(
{
"request_id": f"req-{uuid4()}",
"execution_id": f"exec-{uuid4()}",
"nonce": token_hex(16),
"requested_at": now,
}
)
return ExecutionRequest.model_validate(payload)
def _write_temp_json(filename: str, payload: dict[str, Any]) -> str:
temp_dir = Path(tempfile.mkdtemp(prefix="agent-receipt-validator-"))
target = temp_dir / filename
target.write_text(json.dumps(payload, indent=2, sort_keys=True) + "\n", encoding="utf-8")
return str(target)
def _write_temp_bytes(filename: str, payload: bytes) -> str:
temp_dir = Path(tempfile.mkdtemp(prefix="agent-receipt-validator-"))
target = temp_dir / filename
target.write_bytes(payload)
return str(target)
with gr.Blocks() as demo:
gr.Markdown(
"""
# Agent Receipt Validator
Validate signed agent execution receipts against evidence bundles. This is a demo for verifiable execution
evidence, not a compliance certification system.
"""
)
with gr.Tab("Validate uploaded receipt"):
uploaded_receipt = gr.File(label="execution_receipt.json", type="filepath")
uploaded_evidence = gr.File(label="evidence_bundle.json", type="filepath")
uploaded_public_key = gr.File(label="public key PEM", type="filepath")
uploaded_audience = gr.Textbox(label="Expected audience", value=DEFAULT_AUDIENCE)
uploaded_button = gr.Button("Validate")
uploaded_verdict = gr.Label(label="Verdict")
uploaded_checks = gr.Dataframe(label="Validation checks", headers=["check", "status"], interactive=False)
uploaded_errors = gr.JSON(label="Errors")
uploaded_warnings = gr.JSON(label="Warnings")
uploaded_report = gr.JSON(label="Verification report")
uploaded_report_file = gr.File(label="Download verification_report.json")
uploaded_button.click(
validate_uploaded_receipt,
inputs=[uploaded_receipt, uploaded_evidence, uploaded_public_key, uploaded_audience],
outputs=[
uploaded_verdict,
uploaded_checks,
uploaded_errors,
uploaded_warnings,
uploaded_report,
uploaded_report_file,
],
)
with gr.Tab("Run built-in demo"):
demo_button = gr.Button("Generate and validate fresh demo artifacts")
demo_verdict = gr.Label(label="Verdict")
demo_checks = gr.Dataframe(label="Validation checks", headers=["check", "status"], interactive=False)
demo_report = gr.JSON(label="Verification report")
demo_receipt_file = gr.File(label="Download execution_receipt.json")
demo_evidence_file = gr.File(label="Download evidence_bundle.json")
demo_public_key_file = gr.File(label="Download demo_public_key.pem")
demo_report_file = gr.File(label="Download verification_report.json")
demo_button.click(
run_builtin_demo,
inputs=[],
outputs=[
demo_verdict,
demo_checks,
demo_report,
demo_receipt_file,
demo_evidence_file,
demo_public_key_file,
demo_report_file,
],
)
gr.Markdown(
"This Space does not store uploaded files permanently. Avoid uploading confidential production receipts, "
"private keys, API tokens, or sensitive evidence bundles."
)
if __name__ == "__main__":
demo.launch()