Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 37 additions & 2 deletions satgate-landing/app/verify-evidence-pack/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,36 @@ export default function VerifyEvidencePackPage() {
<div className="mx-auto max-w-4xl">
<Link href="/" className="text-sm text-gray-400 hover:text-white">← Back to Home</Link>
<p className="mt-10 text-sm font-bold uppercase tracking-[0.24em] text-cyan-300">Independent verification</p>
<h1 className="mt-4 text-5xl font-black tracking-tight sm:text-6xl">Verify a SatGate Evidence Pack.</h1>
<h1 className="mt-4 text-5xl font-black tracking-tight sm:text-6xl">Don&apos;t trust us—verify it yourself.</h1>
<p className="mt-6 text-xl leading-8 text-gray-300">
SatGate Evidence Packs are designed to be checked without SatGate credentials. A verifier should fetch the pack, fetch issuer JWKS, canonicalize the signed receipt with RFC 8785 JCS, recompute the SHA-256 receipt hash, verify the Ed25519 signature, and compare unsigned pack mirrors against the signed receipt.
SatGate Evidence Packs are designed to be checked without SatGate credentials. Fetch the pack and issuer JWKS, canonicalize the signed receipt with RFC 8785 JCS, recompute its SHA-256 hash, verify the Ed25519 signature, and compare unsigned pack mirrors against the signed receipt.
</p>
<div className="mt-8 flex flex-col gap-3 sm:flex-row">
<a href="https://github.com/SatGate-io/satgate/tree/main/tools" className="rounded-lg bg-white px-5 py-3 text-center font-bold text-black hover:bg-gray-200">Get verifier tool</a>
<a href={livePackUrl} className="rounded-lg border border-cyan-300/40 px-5 py-3 text-center font-bold text-cyan-100 hover:border-cyan-200">Open sample production pack</a>
<a href="/evidence/policy-to-proof-closure-20260718.json" className="rounded-lg border border-white/20 px-5 py-3 text-center font-bold text-gray-100 hover:border-white/40">Download sanitized closure</a>
</div>
</div>
</section>

<section className="border-b border-white/10 px-6 py-16">
<div className="mx-auto max-w-5xl">
<h2 className="text-3xl font-black">Read the result correctly.</h2>
<div className="mt-6 grid gap-4 md:grid-cols-2">
<div className="rounded-2xl border border-amber-400/20 bg-amber-400/10 p-5 text-amber-50">
<h3 className="font-bold"><code>valid=true</code></h3>
<p className="mt-2 text-sm leading-6">With an embedded key, this proves only that the artifact is internally self-consistent. It does not establish who controls the issuer.</p>
</div>
<div className="rounded-2xl border border-emerald-400/20 bg-emerald-400/10 p-5 text-emerald-50">
<h3 className="font-bold"><code>trusted_issuer_valid=true</code></h3>
<p className="mt-2 text-sm leading-6">Buyer-verifiable proof requires the signature to validate against a separately fetched or pinned issuer JWKS, with trusted-issuer verification required.</p>
</div>
</div>
<div className="mt-6 rounded-2xl border border-cyan-300/20 bg-cyan-300/[0.06] p-5 text-gray-200">
<h3 className="font-bold text-white">Latest bounded closure record</h3>
<p className="mt-2 text-sm leading-6">The July 18 record is sanitized, staging-only evidence. It records strict verifier and trusted-issuer success, verifier-copy parity, restart parity, and containment of historical staging bearer links. It does not authorize production promotion.</p>
<p className="mt-3 break-all font-mono text-xs text-cyan-100">Source manifest SHA-256: 62d00ac4bff91e56fea8f5e8e42ceb0bb46461c46ba5d5a8c9645047baba4f5a</p>
<p className="mt-2 break-all font-mono text-xs text-cyan-100">Public record SHA-256: 162f523d054feb99c2d65fadad7ecb3aa2d5127f1748160ca97424b73215eb7c</p>
</div>
</div>
</section>
Expand Down Expand Up @@ -55,6 +78,18 @@ python tools/verify_evidence_pack.py pack.json \
</div>
</section>

<section className="border-t border-white/10 px-6 py-16">
<div className="mx-auto max-w-4xl">
<h2 className="text-3xl font-black">Current limits</h2>
<ul className="mt-6 space-y-3 text-gray-300">
<li>• Receipt signing keys are platform-secret-managed; this page does not claim KMS/HSM custody or external assessment.</li>
<li>• The evidence archive is durable platform storage, not externally anchored or WORM-assured.</li>
<li>• Evidence URLs are bearer-by-ID links. Anyone holding a URL can fetch that Pack until retention or targeted deletion removes it.</li>
<li>• Verifier success establishes artifact integrity and issuer anchoring—not upstream behavior, settlement, or regulatory compliance.</li>
</ul>
</div>
</section>

<section className="border-t border-white/10 px-6 py-16">
<div className="mx-auto max-w-4xl">
<h2 className="text-3xl font-black">What this proves — and what it does not.</h2>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{
"schema_version": "1.0",
"record_type": "policy_to_proof_sanitized_closure",
"generated_at": "2026-07-18T20:50:36Z",
"scope": "staging_only",
"source_fingerprints": {
"reviewed_candidate_commit": "f320ccf8a0f0248526c8cedea68ab14c9acb59d4",
"enterprise_merge_commit": "24bb146a2eb062959b86470bd819618d51f55505",
"sanitized_manifest_sha256": "62d00ac4bff91e56fea8f5e8e42ceb0bb46461c46ba5d5a8c9645047baba4f5a"
},
"verification": {
"manifest_entries_verified": true,
"manifest_entry_count": 10,
"sensitive_data_scan_passed": true,
"json_string_boundary_passed": true,
"claim_hygiene_passed": true,
"verifier_copies_byte_identical": true,
"strict_verifier_tests_passed": true,
"strict_verifier_test_count": 71,
"strict_verifier_valid": true,
"trusted_issuer_valid": true,
"restart_parity_verified": true
},
"historical_bearer_containment": {
"exposed_staging_evidence_urls_found": 2,
"retrievable_before_containment": true,
"targeted_archive_entries_removed": 2,
"process_cache_cleared_by_restart": true,
"all_urls_http_404_after_restart": true,
"not_found_responses_indistinguishable": true,
"git_history_rewritten": false,
"source_repository_private": true,
"residual_private_history_risk_accepted": true
},
"boundaries": {
"production_touched": false,
"production_promotion_authorized": false,
"contains_raw_pack_identifiers": false,
"contains_raw_receipt_identifiers": false,
"contains_evidence_access_identifiers": false,
"contains_bearer_urls": false,
"contains_payment_credentials": false,
"proves_runtime_truth_independently": false,
"proves_billing_settlement": false,
"proves_external_archive_anchoring": false,
"proves_hardware_key_custody": false
}
}
59 changes: 59 additions & 0 deletions satgate-landing/scripts/check_proof_spine.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,17 @@
"policy_version",
"decision_reason",
],
"app/verify-evidence-pack/page.tsx": [
"Don&apos;t trust us—verify it yourself.",
"valid=true",
"trusted_issuer_valid=true",
"--jwks-file jwks.json",
"--require-trusted-issuer",
"Current limits",
"/evidence/policy-to-proof-closure-20260718.json",
"62d00ac4bff91e56fea8f5e8e42ceb0bb46461c46ba5d5a8c9645047baba4f5a",
"162f523d054feb99c2d65fadad7ecb3aa2d5127f1748160ca97424b73215eb7c",
],
"app/openai-budget-policy-generator/page.tsx": [
"receipt_id",
"evidence_pack_id",
Expand Down Expand Up @@ -158,12 +169,60 @@ def check_mcp_templates() -> list[str]:
return errors


def check_sanitized_closure() -> list[str]:
errors: list[str] = []
path = ROOT / "public/evidence/policy-to-proof-closure-20260718.json"
if not path.exists():
return ["missing sanitized Policy-to-Proof closure record"]
record = json.loads(path.read_text())
if record.get("scope") != "staging_only":
errors.append("sanitized closure scope must remain staging_only")
verification = record.get("verification", {})
for key in [
"manifest_entries_verified",
"sensitive_data_scan_passed",
"verifier_copies_byte_identical",
"strict_verifier_valid",
"trusted_issuer_valid",
"restart_parity_verified",
]:
if verification.get(key) is not True:
errors.append(f"sanitized closure verification.{key} is not true")
boundaries = record.get("boundaries", {})
for key in [
"production_touched",
"production_promotion_authorized",
"contains_raw_pack_identifiers",
"contains_raw_receipt_identifiers",
"contains_evidence_access_identifiers",
"contains_bearer_urls",
"contains_payment_credentials",
"proves_runtime_truth_independently",
"proves_billing_settlement",
"proves_external_archive_anchoring",
"proves_hardware_key_custody",
]:
if boundaries.get(key) is not False:
errors.append(f"sanitized closure boundaries.{key} must remain false")
containment = record.get("historical_bearer_containment", {})
if containment.get("exposed_staging_evidence_urls_found") != 2:
errors.append("sanitized closure containment count drifted")
if containment.get("targeted_archive_entries_removed") != 2:
errors.append("sanitized closure removed count drifted")
if containment.get("all_urls_http_404_after_restart") is not True:
errors.append("sanitized closure must preserve post-restart 404 containment")
if containment.get("git_history_rewritten") is not False:
errors.append("sanitized closure must not imply Git history was rewritten")
return errors


def main() -> int:
errors = []
errors += check_phrases()
errors += check_evidence_pack_schema()
errors += check_evidence_pack_samples()
errors += check_mcp_templates()
errors += check_sanitized_closure()
if errors:
print("Proof-spine guard failed:")
for error in errors:
Expand Down
Loading