wedge(T034): snapshot commits to registry audit/ via Forgejo contents API
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
5d651705ff
commit
2b84874515
2 changed files with 50 additions and 3 deletions
|
|
@ -143,6 +143,11 @@ def snapshot(conn=Depends(get_conn), _key: str = Depends(require_admin)):
|
|||
date = datetime.now(timezone.utc).strftime("%Y-%m-%d")
|
||||
path = f"audit/{date}.json"
|
||||
content = json.dumps(balances, sort_keys=True, indent=2)
|
||||
# TODO(T034): commit `content` to `path` in m2/market-registry via Forgejo API
|
||||
# (REGISTRY_REPO_URL + FORGEJO_TOKEN); this endpoint only produces the JSON.
|
||||
return {"path": path, "content": content}
|
||||
from m2_ledger.snapshot import SnapshotError, commit_snapshot
|
||||
|
||||
try:
|
||||
result = commit_snapshot(path, content)
|
||||
except SnapshotError as exc:
|
||||
# Snapshot content is still returned so an operator can commit by hand.
|
||||
return {"path": path, "content": content, "committed": False, "error": str(exc)}
|
||||
return {"path": path, "content": content, "committed": True, "commit": result["commit"]}
|
||||
|
|
|
|||
42
ledger/src/m2_ledger/snapshot.py
Normal file
42
ledger/src/m2_ledger/snapshot.py
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
"""Daily balance snapshot → committed to the registry's audit/ (constitution V, T034).
|
||||
|
||||
The commit uses the Forgejo contents API: create the file, or update it (same-day
|
||||
re-runs) with the current blob sha. Config via env: FORGEJO_URL, FORGEJO_TOKEN,
|
||||
REGISTRY_REPO (default m2/market-registry), FORGEJO_USER (default m2).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import base64
|
||||
import os
|
||||
|
||||
import httpx
|
||||
|
||||
|
||||
class SnapshotError(RuntimeError):
|
||||
pass
|
||||
|
||||
|
||||
def commit_snapshot(path: str, content: str) -> dict:
|
||||
forgejo_url = os.environ.get("FORGEJO_URL", "https://git.machinemachine.ai").rstrip("/")
|
||||
token = os.environ.get("FORGEJO_TOKEN", "")
|
||||
repo = os.environ.get("REGISTRY_REPO", "m2/market-registry")
|
||||
user = os.environ.get("FORGEJO_USER", "m2")
|
||||
if not token:
|
||||
raise SnapshotError("FORGEJO_TOKEN not set — snapshot produced but not committed")
|
||||
|
||||
api = f"{forgejo_url}/api/v1/repos/{repo}/contents/{path}"
|
||||
b64 = base64.b64encode(content.encode()).decode()
|
||||
message = f"audit: ledger balance snapshot {path.rsplit('/', 1)[-1]}"
|
||||
|
||||
with httpx.Client(auth=(user, token), timeout=15.0) as client:
|
||||
existing = client.get(api)
|
||||
if existing.status_code == 200:
|
||||
sha = existing.json().get("sha")
|
||||
resp = client.put(api, json={"content": b64, "message": message, "sha": sha})
|
||||
else:
|
||||
resp = client.post(api, json={"content": b64, "message": message})
|
||||
if resp.status_code not in (200, 201):
|
||||
raise SnapshotError(f"registry commit failed: {resp.status_code} {resp.text[:200]}")
|
||||
data = resp.json()
|
||||
return {"path": path, "commit": (data.get("commit") or {}).get("sha")}
|
||||
Loading…
Reference in a new issue