From 9092f032e088094153fc51dab5cdf88b96501e90 Mon Sep 17 00:00:00 2001 From: mrwulf Date: Mon, 6 Jul 2026 16:16:10 +0200 Subject: [PATCH] Public-exposure self-audit: genericize DEPLOY.md, scrub provider paths Socratic pass over everything this public repo reveals, adversary-first: - DEPLOY.md no longer names the hosting provider or the server's other software inventory (that sentence was NEW public information - the site's front page does not advertise it). It now states its own redaction policy up front, leads with a Caddy proxy config (matching what the target site actually fronts with), adds rate-limiting and proxy timeouts for the stdlib backend, generalizes the second-mirror section, and gains an explicit key-hygiene section (the signing key never touches the public server; a compromised box has nothing to rotate). - Future attestations stop leaking provider-machine paths: the machine_protection guard path is recorded repo-relative and the Lean project dir is recorded in its configured env-var form, never machine-resolved. (The 12 already-published leaves containing local home paths are immutable by design - severity assessed low: a local username on a non-addressable dev box, no credentials - and an append-only log does not rewrite its history.) Audited clean: no keys, tokens, or credential-named files anywhere in git history; no public IPs; loopback-only binds; commit identity is the owner's long-standing public one. 54/54 tests. Co-Authored-By: Claude Fable 5 --- DEPLOY.md | 61 +++++++++++++++++--------- provider/src/pacta_provider/service.py | 8 +++- 2 files changed, 47 insertions(+), 22 deletions(-) diff --git a/DEPLOY.md b/DEPLOY.md index 1c636bf..b2b27ae 100644 --- a/DEPLOY.md +++ b/DEPLOY.md @@ -1,8 +1,9 @@ # Deploying the online log at zkdefi.org/lean-transparency-log -Everything below is prepared to run on the DigitalOcean host (the one -running Forgejo). Nothing here needs to run on the development machine — -this file is the checklist for the server session. +Checklist for the server session. Deliberately generic about the host: +this file is public, so it names only what customers must know anyway +(the service URL) and standard software layouts - no provider inventory, +no credentials, nothing an attacker couldn't already get from public DNS. ## What gets deployed @@ -72,31 +73,51 @@ curl -s http://127.0.0.1:8461/lean-transparency-log/healthz ## 3. Reverse proxy on zkdefi.org -nginx (add inside the existing zkdefi.org server block, alongside Forgejo): +Caddy (inside the existing `zkdefi.org` site block): -```nginx -location /lean-transparency-log/ { - proxy_pass http://127.0.0.1:8461/lean-transparency-log/; - proxy_set_header Host $host; -} -location = /lean-transparency-log { - return 301 /lean-transparency-log/docs; +```caddy +redir /lean-transparency-log /lean-transparency-log/docs +route /lean-transparency-log/* { + reverse_proxy 127.0.0.1:8461 { + transport http { + response_header_timeout 15s + } + } } ``` -(Caddy equivalent: `handle_path` not needed — `reverse_proxy 127.0.0.1:8461` -under `route /lean-transparency-log*`.) +nginx equivalent, with basic rate limiting (the backend is a stdlib +threading server - let the proxy absorb abuse): + +```nginx +limit_req_zone $binary_remote_addr zone=pactalog:1m rate=20r/s; +location /lean-transparency-log/ { + limit_req zone=pactalog burst=40 nodelay; + proxy_read_timeout 15s; + proxy_pass http://127.0.0.1:8461/lean-transparency-log/; + proxy_set_header Host $host; +} +location = /lean-transparency-log { return 301 /lean-transparency-log/docs; } +``` Check: `https://zkdefi.org/lean-transparency-log/docs` renders the customer documentation; `/v1/sth` returns the dogfood-signed head. -## 4. Forgejo mirror +## 4. Second mirror (any Forgejo/Gitea/GitLab you operate) -In Forgejo: create migration/mirror of -`https://github.com/saymrwulf/lean-transparency-log` (and optionally the -pacta repo) with periodic sync. The published repo is the witness channel; -having it on BOTH GitHub and Forgejo means witnesses on two independent -hosts — exactly the point. +Create a periodic pull-mirror of +`https://github.com/saymrwulf/lean-transparency-log` on a second, +independently-operated git host. The published repo is the witness +channel; two independent mirrors mean split-view lies must fool two +infrastructures at once — exactly the point. + +## 4b. Key hygiene (non-negotiable) + +The provider SIGNING key never touches this server. The service is +read-only by construction and the systemd unit mounts the tree read-only; +keep it that way. If the box is ever compromised, rotate nothing — +there is nothing to rotate here; verify the published mirror with +`verify.py --all` and redeploy. ## 5. Update cycle (provider machine → world) @@ -106,7 +127,7 @@ After each new proof-check run on the provider machine: pacta_provider log-append ... # signs new head (offline, dogfood) pacta_provider log-publish --log-dir ... --git-dir \ --public-key provider/state/local-provider/provider.ed25519.pub -cd && git add -A && git commit -m "log update" && git push # GitHub + Forgejo sync +cd && git add -A && git commit -m "log update" && git push # mirrors sync from here # on the server: cd /srv/pacta/published && git pull && re-run step 1's reconstruction sudo systemctl restart pacta-log ``` diff --git a/provider/src/pacta_provider/service.py b/provider/src/pacta_provider/service.py index e940d51..03474e0 100644 --- a/provider/src/pacta_provider/service.py +++ b/provider/src/pacta_provider/service.py @@ -76,7 +76,9 @@ def build_attestation( "provider": provider, "issued_at": datetime.now(timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z"), "machine_protection": { - "lean_guard": lean_guard or "UNGUARDED", + # privacy: record the guard REPO-RELATIVE - attestations are + # published leaves and must not leak provider-machine paths. + "lean_guard": (str(Path(lean_guard).relative_to(path.resolve())) if lean_guard and Path(lean_guard).is_relative_to(path.resolve()) else ("configured" if lean_guard else "UNGUARDED")), "note": "All Lean compiles route through the repo's lean-guard (memory cap, core pinning, timeout, single-flight lock) when configured.", }, "subject": { @@ -91,7 +93,9 @@ def build_attestation( "lean_version": lean_version, "lake_version": lake_version, "env_script": str(env_script or repo.env_script or ""), - "lean_project_dir": str(project_dir or lean_project_dir or repo.lean_project_dir or ""), + # privacy: record the CONFIGURED value (env-var form), never the + # machine-resolved absolute path - attestations are published. + "lean_project_dir": str(lean_project_dir or repo.lean_project_dir or ""), }, "replay": { "check_attempted": check.attempted,