mirror of
https://github.com/saymrwulf/proof-aware-crypto-tooling-agent.git
synced 2026-09-03 19:53:43 +00:00
Move the log service to ltl.zkdefi.org (root path); keep path-mount support
- serve/webdocs/cli default to base_path='' (own subdomain, root serving) - webdocs link builder handles the empty base like web.py already did - all docs, paper, notebook 06b, and published-mirror README point at https://ltl.zkdefi.org; DEPLOY.md rewritten for subdomain + redirect - tests: root mount is the production shape; one test keeps exercising the path-mounted variant Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
aa16f6d530
commit
47dfb61a7f
12 changed files with 54 additions and 32 deletions
50
DEPLOY.md
50
DEPLOY.md
|
|
@ -1,4 +1,4 @@
|
||||||
# Deploying the online log at zkdefi.org/lean-transparency-log
|
# Deploying the online log at ltl.zkdefi.org
|
||||||
|
|
||||||
STATUS: DEPLOYED (2026-07-06) and serving. This file is now the as-built
|
STATUS: DEPLOYED (2026-07-06) and serving. This file is now the as-built
|
||||||
record plus the update runbook. Deliberately generic about the host: it
|
record plus the update runbook. Deliberately generic about the host: it
|
||||||
|
|
@ -101,7 +101,7 @@ After=network.target
|
||||||
User=pacta
|
User=pacta
|
||||||
WorkingDirectory=/srv/pacta/app
|
WorkingDirectory=/srv/pacta/app
|
||||||
Environment=PYTHONPATH=/srv/pacta/app/src:/srv/pacta/app/provider/src
|
Environment=PYTHONPATH=/srv/pacta/app/src:/srv/pacta/app/provider/src
|
||||||
ExecStart=/usr/bin/python3 -m pacta_provider serve --log-dir /srv/pacta/log --base-path lean-transparency-log --host 127.0.0.1 --port 8461
|
ExecStart=/usr/bin/python3 -m pacta_provider serve --log-dir /srv/pacta/log --host 127.0.0.1 --port 8461
|
||||||
Restart=on-failure
|
Restart=on-failure
|
||||||
# hardening: read-only service, no key material anywhere near it
|
# hardening: read-only service, no key material anywhere near it
|
||||||
ProtectSystem=strict
|
ProtectSystem=strict
|
||||||
|
|
@ -115,16 +115,21 @@ WantedBy=multi-user.target
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo systemctl daemon-reload && sudo systemctl enable --now pacta-log
|
sudo systemctl daemon-reload && sudo systemctl enable --now pacta-log
|
||||||
curl -s http://127.0.0.1:8461/lean-transparency-log/healthz
|
curl -s http://127.0.0.1:8461/healthz
|
||||||
```
|
```
|
||||||
|
|
||||||
## 3. Reverse proxy on zkdefi.org
|
The service serves from the root path by default (it lives on its own
|
||||||
|
subdomain); pass `--base-path <prefix>` only if you must mount it under
|
||||||
|
a path instead.
|
||||||
|
|
||||||
Caddy (inside the existing `zkdefi.org` site block):
|
## 3. Reverse proxy: ltl.zkdefi.org
|
||||||
|
|
||||||
|
DNS: an `A` record for `ltl` pointing at the same host (or a `CNAME` to
|
||||||
|
the apex). Caddy then gets its own site block and handles the
|
||||||
|
certificate automatically:
|
||||||
|
|
||||||
```caddy
|
```caddy
|
||||||
redir /lean-transparency-log /lean-transparency-log/docs
|
ltl.zkdefi.org {
|
||||||
route /lean-transparency-log/* {
|
|
||||||
reverse_proxy 127.0.0.1:8461 {
|
reverse_proxy 127.0.0.1:8461 {
|
||||||
transport http {
|
transport http {
|
||||||
response_header_timeout 15s
|
response_header_timeout 15s
|
||||||
|
|
@ -133,21 +138,34 @@ route /lean-transparency-log/* {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
If the log was ever served under a path (the original deployment used
|
||||||
|
`zkdefi.org/lean-transparency-log`), keep a permanent redirect in the
|
||||||
|
old site block so published links stay alive:
|
||||||
|
|
||||||
|
```caddy
|
||||||
|
redir /lean-transparency-log https://ltl.zkdefi.org/ permanent
|
||||||
|
handle_path /lean-transparency-log/* {
|
||||||
|
redir https://ltl.zkdefi.org{uri} permanent
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
nginx equivalent, with basic rate limiting (the backend is a stdlib
|
nginx equivalent, with basic rate limiting (the backend is a stdlib
|
||||||
threading server - let the proxy absorb abuse):
|
threading server - let the proxy absorb abuse):
|
||||||
|
|
||||||
```nginx
|
```nginx
|
||||||
limit_req_zone $binary_remote_addr zone=pactalog:1m rate=20r/s;
|
limit_req_zone $binary_remote_addr zone=pactalog:1m rate=20r/s;
|
||||||
location /lean-transparency-log/ {
|
server {
|
||||||
limit_req zone=pactalog burst=40 nodelay;
|
server_name ltl.zkdefi.org;
|
||||||
proxy_read_timeout 15s;
|
location / {
|
||||||
proxy_pass http://127.0.0.1:8461/lean-transparency-log/;
|
limit_req zone=pactalog burst=40 nodelay;
|
||||||
proxy_set_header Host $host;
|
proxy_read_timeout 15s;
|
||||||
|
proxy_pass http://127.0.0.1:8461/;
|
||||||
|
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
|
Check: `https://ltl.zkdefi.org/docs` renders the customer
|
||||||
documentation; `/v1/sth` returns the dogfood-signed head.
|
documentation; `/v1/sth` returns the dogfood-signed head.
|
||||||
|
|
||||||
## 4. Second mirror (any Forgejo/Gitea/GitLab you operate)
|
## 4. Second mirror (any Forgejo/Gitea/GitLab you operate)
|
||||||
|
|
@ -182,12 +200,12 @@ sudo systemctl restart pacta-log
|
||||||
## 6. Smoke tests from anywhere
|
## 6. Smoke tests from anywhere
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pacta log-fetch --url https://zkdefi.org/lean-transparency-log --component dalek-ed25519-verified --out-dir /tmp/e
|
pacta log-fetch --url https://ltl.zkdefi.org --component dalek-ed25519-verified --out-dir /tmp/e
|
||||||
pacta receipt-verify --attestation /tmp/e/dalek-ed25519-verified.attestation.json \
|
pacta receipt-verify --attestation /tmp/e/dalek-ed25519-verified.attestation.json \
|
||||||
--receipt /tmp/e/dalek-ed25519-verified.receipt.json \
|
--receipt /tmp/e/dalek-ed25519-verified.receipt.json \
|
||||||
--log-public-key <provider.ed25519.pub from the published repo> \
|
--log-public-key <provider.ed25519.pub from the published repo> \
|
||||||
--sth-store ~/.pacta-pins.json
|
--sth-store ~/.pacta-pins.json
|
||||||
pacta sth-refresh --url https://zkdefi.org/lean-transparency-log \
|
pacta sth-refresh --url https://ltl.zkdefi.org \
|
||||||
--sth-store ~/.pacta-pins.json --log-public-key <pubkey>
|
--sth-store ~/.pacta-pins.json --log-public-key <pubkey>
|
||||||
git clone https://github.com/saymrwulf/lean-transparency-log && cd lean-transparency-log && python3 verify.py --all
|
git clone https://github.com/saymrwulf/lean-transparency-log && cd lean-transparency-log && python3 verify.py --all
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -238,7 +238,7 @@ The log has three synchronized faces, transport being orthogonal to trust:
|
||||||
every leaf, every signed tree head (the WITNESS CHANNEL - all cloners
|
every leaf, every signed tree head (the WITNESS CHANNEL - all cloners
|
||||||
see the same heads), per-component receipts, the provider public key,
|
see the same heads), per-component receipts, the provider public key,
|
||||||
and a standalone stdlib-only `verify.py`. Anyone: `python3 verify.py --all`.
|
and a standalone stdlib-only `verify.py`. Anyone: `python3 verify.py --all`.
|
||||||
3. **HTTP service** (deployed at `zkdefi.org/lean-transparency-log`, see
|
3. **HTTP service** (deployed at `ltl.zkdefi.org`, see
|
||||||
`DEPLOY.md`): read-only CT-style endpoints + customer docs. The web
|
`DEPLOY.md`): read-only CT-style endpoints + customer docs. The web
|
||||||
process never touches private keys - heads are signed offline; a
|
process never touches private keys - heads are signed offline; a
|
||||||
compromised server can withhold or replay (pinning + freshness detect
|
compromised server can withhold or replay (pinning + freshness detect
|
||||||
|
|
@ -247,8 +247,8 @@ The log has three synchronized faces, transport being orthogonal to trust:
|
||||||
```bash
|
```bash
|
||||||
PYTHONPATH=src:provider/src python -m pacta_provider serve --log-dir ... --base-path lean-transparency-log
|
PYTHONPATH=src:provider/src python -m pacta_provider serve --log-dir ... --base-path lean-transparency-log
|
||||||
PYTHONPATH=src:provider/src python -m pacta_provider log-publish --log-dir ... --git-dir <mirror clone> --public-key <pub>
|
PYTHONPATH=src:provider/src python -m pacta_provider log-publish --log-dir ... --git-dir <mirror clone> --public-key <pub>
|
||||||
pacta log-fetch --url https://zkdefi.org/lean-transparency-log --component dalek-ed25519-verified --out-dir fetched
|
pacta log-fetch --url https://ltl.zkdefi.org --component dalek-ed25519-verified --out-dir fetched
|
||||||
pacta sth-refresh --url https://zkdefi.org/lean-transparency-log --sth-store pins.json --log-public-key <pub>
|
pacta sth-refresh --url https://ltl.zkdefi.org --sth-store pins.json --log-public-key <pub>
|
||||||
pacta witness-audit --published-dir <clone of lean-transparency-log> --log-public-key <pub>
|
pacta witness-audit --published-dir <clone of lean-transparency-log> --log-public-key <pub>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -220,7 +220,7 @@
|
||||||
"(`pacta witness-audit` recomputes every prefix root from the\n",
|
"(`pacta witness-audit` recomputes every prefix root from the\n",
|
||||||
"published leaves; run `python3 verify.py --all` in a clone for the\n",
|
"published leaves; run `python3 verify.py --all` in a clone for the\n",
|
||||||
"no-install version). The ONLINE SERVICE\n",
|
"no-install version). The ONLINE SERVICE\n",
|
||||||
"(`zkdefi.org/lean-transparency-log`) adds live endpoints: fetch\n",
|
"(`ltl.zkdefi.org`) adds live endpoints: fetch\n",
|
||||||
"fresh evidence (`pacta log-fetch`), advance your pin with an\n",
|
"fresh evidence (`pacta log-fetch`), advance your pin with an\n",
|
||||||
"online consistency proof (`pacta sth-refresh`). The verification\n",
|
"online consistency proof (`pacta sth-refresh`). The verification\n",
|
||||||
"you do afterwards is IDENTICAL in all three transports - this\n",
|
"you do afterwards is IDENTICAL in all three transports - this\n",
|
||||||
|
|
|
||||||
BIN
paper/ltl.pdf
BIN
paper/ltl.pdf
Binary file not shown.
|
|
@ -18,7 +18,7 @@
|
||||||
\title{\textbf{LTL: the Lean Transparency Log}\\[2pt]
|
\title{\textbf{LTL: the Lean Transparency Log}\\[2pt]
|
||||||
\large Distributing Machine-Checked Proof Evidence via an Authenticated
|
\large Distributing Machine-Checked Proof Evidence via an Authenticated
|
||||||
Data Structure Signed by Its Own Certified Artifact}
|
Data Structure Signed by Its Own Certified Artifact}
|
||||||
\author{saymrwulf\\ \small zkdefi.org --- \url{https://zkdefi.org/lean-transparency-log}}
|
\author{saymrwulf\\ \small zkdefi.org --- \url{https://ltl.zkdefi.org}}
|
||||||
\date{July 2026}
|
\date{July 2026}
|
||||||
|
|
||||||
\begin{document}
|
\begin{document}
|
||||||
|
|
@ -281,7 +281,7 @@ signing library's attestation enters the log record
|
||||||
\label{sec:deploy}
|
\label{sec:deploy}
|
||||||
|
|
||||||
The LTL is deployed\footnote{Service:
|
The LTL is deployed\footnote{Service:
|
||||||
\url{https://zkdefi.org/lean-transparency-log} (read-only HTTP API and
|
\url{https://ltl.zkdefi.org} (read-only HTTP API and
|
||||||
documentation). Mirror: \url{https://github.com/saymrwulf/lean-transparency-log}.
|
documentation). Mirror: \url{https://github.com/saymrwulf/lean-transparency-log}.
|
||||||
Operator/consumer tooling and a twelve-lecture course:
|
Operator/consumer tooling and a twelve-lecture course:
|
||||||
\url{https://github.com/saymrwulf/proof-aware-crypto-tooling-agent}. The
|
\url{https://github.com/saymrwulf/proof-aware-crypto-tooling-agent}. The
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@ def build_parser() -> argparse.ArgumentParser:
|
||||||
|
|
||||||
serve = sub.add_parser("serve", help="Serve the log read-only over HTTP (CT-style endpoints + customer docs). Never touches private keys.")
|
serve = sub.add_parser("serve", help="Serve the log read-only over HTTP (CT-style endpoints + customer docs). Never touches private keys.")
|
||||||
serve.add_argument("--log-dir", required=True)
|
serve.add_argument("--log-dir", required=True)
|
||||||
serve.add_argument("--base-path", default="lean-transparency-log")
|
serve.add_argument("--base-path", default="")
|
||||||
serve.add_argument("--host", default="127.0.0.1")
|
serve.add_argument("--host", default="127.0.0.1")
|
||||||
serve.add_argument("--port", type=int, default=8461)
|
serve.add_argument("--port", type=int, default=8461)
|
||||||
serve.set_defaults(func=cmd_serve)
|
serve.set_defaults(func=cmd_serve)
|
||||||
|
|
@ -166,7 +166,9 @@ def cmd_serve(args) -> int:
|
||||||
from .web import serve as make_server
|
from .web import serve as make_server
|
||||||
|
|
||||||
server = make_server(args.log_dir, base_path=args.base_path, host=args.host, port=args.port)
|
server = make_server(args.log_dir, base_path=args.base_path, host=args.host, port=args.port)
|
||||||
print(f"serving read-only log on http://{args.host}:{args.port}/{args.base_path.strip('/')}/docs")
|
base = args.base_path.strip("/")
|
||||||
|
prefix = f"/{base}" if base else ""
|
||||||
|
print(f"serving read-only log on http://{args.host}:{args.port}{prefix}/docs")
|
||||||
try:
|
try:
|
||||||
server.serve_forever()
|
server.serve_forever()
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
|
|
|
||||||
|
|
@ -184,7 +184,7 @@ python3 verify.py --receipt receipts/dalek-ed25519-verified.receipt.json
|
||||||
```
|
```
|
||||||
|
|
||||||
The online service (same data, live endpoints + customer documentation):
|
The online service (same data, live endpoints + customer documentation):
|
||||||
**https://zkdefi.org/lean-transparency-log**
|
**https://ltl.zkdefi.org**
|
||||||
|
|
||||||
The provider tooling, agent tooling, and course materials:
|
The provider tooling, agent tooling, and course materials:
|
||||||
**https://github.com/saymrwulf/proof-aware-crypto-tooling-agent**
|
**https://github.com/saymrwulf/proof-aware-crypto-tooling-agent**
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
"""The online face of the transparency log: a READ-ONLY, zero-dependency
|
"""The online face of the transparency log: a READ-ONLY, zero-dependency
|
||||||
HTTP service exposing CT-style endpoints under a base path (deployed at
|
HTTP service exposing CT-style endpoints under a base path (deployed at
|
||||||
zkdefi.org/lean-transparency-log behind a reverse proxy).
|
ltl.zkdefi.org behind a reverse proxy).
|
||||||
|
|
||||||
Security posture: this process never loads a private key. Tree heads are
|
Security posture: this process never loads a private key. Tree heads are
|
||||||
signed OFFLINE by the provider CLI (log-append / log-sth); the service
|
signed OFFLINE by the provider CLI (log-append / log-sth); the service
|
||||||
|
|
@ -150,7 +150,7 @@ def make_handler(log: TransparencyLog, base_path: str, docs_html: str):
|
||||||
|
|
||||||
def serve(
|
def serve(
|
||||||
log_dir: str,
|
log_dir: str,
|
||||||
base_path: str = "lean-transparency-log",
|
base_path: str = "",
|
||||||
host: str = "127.0.0.1",
|
host: str = "127.0.0.1",
|
||||||
port: int = 8461,
|
port: int = 8461,
|
||||||
docs_html: str | None = None,
|
docs_html: str | None = None,
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,7 @@ def _svg_tree(entries: list[LogEntry], root_hex: str, signing_backend: str) -> s
|
||||||
|
|
||||||
|
|
||||||
def render_docs(log: TransparencyLog, base_path: str) -> str:
|
def render_docs(log: TransparencyLog, base_path: str) -> str:
|
||||||
base = "/" + base_path.strip("/")
|
base = "/" + base_path.strip("/") if base_path.strip("/") else ""
|
||||||
metadata = log.metadata()
|
metadata = log.metadata()
|
||||||
history = log.sth_history()
|
history = log.sth_history()
|
||||||
latest: dict[str, Any] = history[-1] if history else {}
|
latest: dict[str, Any] = history[-1] if history else {}
|
||||||
|
|
|
||||||
|
|
@ -1549,7 +1549,7 @@ COURSE = {
|
||||||
(`pacta witness-audit` recomputes every prefix root from the
|
(`pacta witness-audit` recomputes every prefix root from the
|
||||||
published leaves; run `python3 verify.py --all` in a clone for the
|
published leaves; run `python3 verify.py --all` in a clone for the
|
||||||
no-install version). The ONLINE SERVICE
|
no-install version). The ONLINE SERVICE
|
||||||
(`zkdefi.org/lean-transparency-log`) adds live endpoints: fetch
|
(`ltl.zkdefi.org`) adds live endpoints: fetch
|
||||||
fresh evidence (`pacta log-fetch`), advance your pin with an
|
fresh evidence (`pacta log-fetch`), advance your pin with an
|
||||||
online consistency proof (`pacta sth-refresh`). The verification
|
online consistency proof (`pacta sth-refresh`). The verification
|
||||||
you do afterwards is IDENTICAL in all three transports - this
|
you do afterwards is IDENTICAL in all three transports - this
|
||||||
|
|
|
||||||
|
|
@ -143,7 +143,7 @@ def build_parser() -> argparse.ArgumentParser:
|
||||||
receipt_verify.set_defaults(func=cmd_receipt_verify)
|
receipt_verify.set_defaults(func=cmd_receipt_verify)
|
||||||
|
|
||||||
log_fetch = sub.add_parser("log-fetch", help="Fetch attestation + inclusion proof for a component from an ONLINE log; verify locally afterwards.")
|
log_fetch = sub.add_parser("log-fetch", help="Fetch attestation + inclusion proof for a component from an ONLINE log; verify locally afterwards.")
|
||||||
log_fetch.add_argument("--url", required=True, help="Base URL, e.g. https://zkdefi.org/lean-transparency-log")
|
log_fetch.add_argument("--url", required=True, help="Base URL, e.g. https://ltl.zkdefi.org")
|
||||||
log_fetch.add_argument("--component", required=True)
|
log_fetch.add_argument("--component", required=True)
|
||||||
log_fetch.add_argument("--out-dir", default="fetched-evidence")
|
log_fetch.add_argument("--out-dir", default="fetched-evidence")
|
||||||
log_fetch.set_defaults(func=cmd_log_fetch)
|
log_fetch.set_defaults(func=cmd_log_fetch)
|
||||||
|
|
|
||||||
|
|
@ -30,11 +30,12 @@ def _make_log(tmp_path, n=3):
|
||||||
|
|
||||||
|
|
||||||
def test_web_endpoints_and_online_proof_roundtrip(tmp_path):
|
def test_web_endpoints_and_online_proof_roundtrip(tmp_path):
|
||||||
|
# root mount: the production shape (ltl.zkdefi.org serves from /)
|
||||||
_make_log(tmp_path)
|
_make_log(tmp_path)
|
||||||
server = serve(str(tmp_path / "log"), port=0)
|
server = serve(str(tmp_path / "log"), port=0)
|
||||||
port = server.server_address[1]
|
port = server.server_address[1]
|
||||||
threading.Thread(target=server.serve_forever, daemon=True).start()
|
threading.Thread(target=server.serve_forever, daemon=True).start()
|
||||||
base = f"http://127.0.0.1:{port}/lean-transparency-log"
|
base = f"http://127.0.0.1:{port}"
|
||||||
try:
|
try:
|
||||||
def get(path):
|
def get(path):
|
||||||
with urllib.request.urlopen(base + path, timeout=10) as r:
|
with urllib.request.urlopen(base + path, timeout=10) as r:
|
||||||
|
|
@ -60,8 +61,9 @@ def test_web_endpoints_and_online_proof_roundtrip(tmp_path):
|
||||||
|
|
||||||
|
|
||||||
def test_logclient_fetch_and_refresh_pin(tmp_path):
|
def test_logclient_fetch_and_refresh_pin(tmp_path):
|
||||||
|
# path mount still supported for anyone proxying under a prefix
|
||||||
_make_log(tmp_path)
|
_make_log(tmp_path)
|
||||||
server = serve(str(tmp_path / "log"), port=0)
|
server = serve(str(tmp_path / "log"), base_path="lean-transparency-log", port=0)
|
||||||
port = server.server_address[1]
|
port = server.server_address[1]
|
||||||
threading.Thread(target=server.serve_forever, daemon=True).start()
|
threading.Thread(target=server.serve_forever, daemon=True).start()
|
||||||
base = f"http://127.0.0.1:{port}/lean-transparency-log"
|
base = f"http://127.0.0.1:{port}/lean-transparency-log"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue