Some checks failed
Assistant: codex Assistant-Model: gpt-6.1-sol Assistant-Session: 01a1468b-63fa-7710-85dc-8f2e16b3ebfa
179 lines
9.2 KiB
Python
179 lines
9.2 KiB
Python
"""Bounded, owner-private recovery journal; never an authorization source.
|
|
|
|
An unresolved write intent is retained indefinitely and blocks further writes.
|
|
Only the directory owner may reconcile it using independently obtained evidence.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
from contextlib import contextmanager
|
|
import os
|
|
from pathlib import Path
|
|
import sqlite3
|
|
import stat
|
|
from typing import Any, Protocol
|
|
from urllib.parse import quote
|
|
|
|
|
|
class GroupJournalStore(Protocol):
|
|
"""Owner-injected persistence only; grants no caller or native authority."""
|
|
def check(self) -> None: ...
|
|
def reserve(self, key: str, binding: str) -> tuple[dict[str, Any], bool]: ...
|
|
def get(self, key: str, binding: str) -> dict[str, Any]: ...
|
|
def claim_revoke(self, key: str, binding: str, delete_if_empty: bool) -> dict[str, Any]: ...
|
|
def save(self, receipt: dict[str, Any]) -> None: ...
|
|
|
|
|
|
class GroupProvenanceUnavailable(RuntimeError):
|
|
def __init__(self):
|
|
super().__init__("group_provenance_unavailable")
|
|
|
|
|
|
class GroupProvenance:
|
|
def __init__(self, path: str, *, capacity: int = 256, initialize: bool = False) -> None:
|
|
target = Path(path)
|
|
if not target.is_absolute() or target.parent.resolve() != target.parent or capacity < 1 or capacity > 4096:
|
|
raise ValueError("private absolute provenance path and bounded capacity required")
|
|
parent = target.parent.lstat()
|
|
if not stat.S_ISDIR(parent.st_mode) or parent.st_uid != os.geteuid() or parent.st_mode & 0o077:
|
|
raise ValueError("provenance directory must be owner-private")
|
|
# Service startup never creates a replacement for missing durable state.
|
|
flags = os.O_RDWR | os.O_NOFOLLOW
|
|
if initialize:
|
|
flags |= os.O_CREAT | os.O_EXCL
|
|
fd = os.open(target, flags, 0o600)
|
|
try:
|
|
info = os.fstat(fd)
|
|
if not stat.S_ISREG(info.st_mode) or info.st_uid != os.geteuid() or info.st_mode & 0o077 or info.st_nlink != 1:
|
|
raise ValueError("provenance file must be owner-private and regular")
|
|
finally:
|
|
os.close(fd)
|
|
self.path = str(target)
|
|
self._device, self._inode = info.st_dev, info.st_ino
|
|
self.capacity = capacity
|
|
with self._db() as db:
|
|
if initialize:
|
|
db.execute("CREATE TABLE group_receipts (key TEXT PRIMARY KEY, binding TEXT NOT NULL, state TEXT NOT NULL, active INTEGER UNIQUE, body TEXT NOT NULL)")
|
|
db.execute("PRAGMA user_version=1")
|
|
if db.execute("PRAGMA user_version").fetchone()[0] != 1:
|
|
raise RuntimeError("unrecognized group provenance schema")
|
|
db.execute("SELECT key, binding, state, active, body FROM group_receipts LIMIT 0")
|
|
|
|
def _check_file(self):
|
|
try:
|
|
target = Path(self.path)
|
|
parent = target.parent.lstat()
|
|
info = target.lstat()
|
|
if target.parent.resolve() != target.parent or not stat.S_ISDIR(parent.st_mode) or parent.st_uid != os.geteuid() or parent.st_mode & 0o077:
|
|
raise GroupProvenanceUnavailable()
|
|
if not stat.S_ISREG(info.st_mode) or info.st_uid != os.geteuid() or info.st_mode & 0o077 or info.st_nlink != 1:
|
|
raise GroupProvenanceUnavailable()
|
|
if (info.st_dev, info.st_ino) != (self._device, self._inode):
|
|
raise GroupProvenanceUnavailable()
|
|
except OSError:
|
|
raise GroupProvenanceUnavailable() from None
|
|
|
|
def check(self):
|
|
with self._db() as db:
|
|
if db.execute("PRAGMA user_version").fetchone()[0] != 1:
|
|
raise GroupProvenanceUnavailable()
|
|
db.execute("SELECT key FROM group_receipts LIMIT 0")
|
|
|
|
@staticmethod
|
|
def _load(body, key, binding):
|
|
try:
|
|
if not isinstance(body, str) or len(body) > 1048576:
|
|
raise GroupProvenanceUnavailable()
|
|
value = json.loads(body)
|
|
if not isinstance(value, dict) or value.get("key") != key or value.get("binding") != binding:
|
|
raise GroupProvenanceUnavailable()
|
|
if value.get("state") not in {"pending", "ensured", "revoking", "revoked", "uncertain", "refused"}:
|
|
raise GroupProvenanceUnavailable()
|
|
if not isinstance(value.get("groups"), dict) or len(value["groups"]) > 16:
|
|
raise GroupProvenanceUnavailable()
|
|
for field, limit in (("created_groups", 16), ("created_memberships", 256)):
|
|
if not isinstance(value.get(field), list) or len(value[field]) > limit or any(not isinstance(item, dict) for item in value[field]):
|
|
raise GroupProvenanceUnavailable()
|
|
if "intent" not in value or value["intent"] is not None and not isinstance(value["intent"], dict):
|
|
raise GroupProvenanceUnavailable()
|
|
for group in value["groups"].values():
|
|
if not isinstance(group, dict) or "id" not in group or not all(isinstance(group.get(f), list) and all(isinstance(u, str) for u in group[f]) for f in ("before", "after")):
|
|
raise GroupProvenanceUnavailable()
|
|
if value["state"] in {"ensured", "revoking", "revoked"} and (
|
|
not isinstance(value.get("requested_groups"), list) or not isinstance(value.get("ensure_correlation_id"), str)
|
|
):
|
|
raise GroupProvenanceUnavailable()
|
|
return value
|
|
except (TypeError, ValueError):
|
|
raise GroupProvenanceUnavailable() from None
|
|
|
|
@contextmanager
|
|
def _db(self):
|
|
db = None
|
|
try:
|
|
self._check_file()
|
|
db = sqlite3.connect("file:" + quote(self.path, safe="/") + "?mode=rw", uri=True, timeout=5)
|
|
self._check_file()
|
|
db.execute("PRAGMA synchronous=FULL")
|
|
with db:
|
|
yield db
|
|
except sqlite3.Error:
|
|
raise GroupProvenanceUnavailable() from None
|
|
finally:
|
|
if db is not None:
|
|
db.close()
|
|
|
|
def reserve(self, key: str, binding: str) -> tuple[dict[str, Any], bool]:
|
|
with self._db() as db:
|
|
db.execute("BEGIN IMMEDIATE")
|
|
row = db.execute("SELECT binding, body FROM group_receipts WHERE key=?", (key,)).fetchone()
|
|
if row:
|
|
if row[0] != binding:
|
|
raise ValueError("ensure idempotency key is bound to another request")
|
|
return self._load(row[1], key, binding), False
|
|
if db.execute("SELECT COUNT(*) FROM group_receipts").fetchone()[0] >= self.capacity:
|
|
raise RuntimeError("provenance capacity reached; retained records require owner disposition")
|
|
receipt = {"key": key, "binding": binding, "state": "pending", "intent": None,
|
|
"groups": {}, "created_groups": [], "created_memberships": []}
|
|
try:
|
|
db.execute("INSERT INTO group_receipts VALUES (?, ?, ?, 1, ?)",
|
|
(key, binding, "pending", json.dumps(receipt, sort_keys=True)))
|
|
except sqlite3.IntegrityError:
|
|
raise RuntimeError("another group operation is unresolved") from None
|
|
return receipt, True
|
|
|
|
def get(self, key: str, binding: str) -> dict[str, Any]:
|
|
with self._db() as db:
|
|
row = db.execute("SELECT binding, body FROM group_receipts WHERE key=?", (key,)).fetchone()
|
|
if not row or row[0] != binding:
|
|
raise ValueError("unknown ensure receipt or request binding mismatch")
|
|
return self._load(row[1], key, binding)
|
|
|
|
def claim_revoke(self, key: str, binding: str, delete_if_empty: bool) -> dict[str, Any]:
|
|
with self._db() as db:
|
|
db.execute("BEGIN IMMEDIATE")
|
|
row = db.execute("SELECT binding, body FROM group_receipts WHERE key=?", (key,)).fetchone()
|
|
if not row or row[0] != binding:
|
|
raise ValueError("unknown ensure receipt or request binding mismatch")
|
|
receipt = self._load(row[1], key, binding)
|
|
if receipt["state"] == "revoked":
|
|
if receipt["delete_if_empty"] != delete_if_empty:
|
|
raise ValueError("completed rollback options cannot change")
|
|
return receipt
|
|
if receipt["state"] != "ensured":
|
|
raise RuntimeError("group provenance unresolved; independent owner recovery required")
|
|
receipt.update(state="revoking", delete_if_empty=delete_if_empty)
|
|
try:
|
|
db.execute("UPDATE group_receipts SET state='revoking', active=1, body=? WHERE key=?",
|
|
(json.dumps(receipt, sort_keys=True), key))
|
|
except sqlite3.IntegrityError:
|
|
raise RuntimeError("another group operation is unresolved") from None
|
|
return receipt
|
|
|
|
def save(self, receipt: dict[str, Any]) -> None:
|
|
active = 1 if receipt["state"] in {"pending", "revoking", "uncertain"} else None
|
|
with self._db() as db:
|
|
written = db.execute("UPDATE group_receipts SET state=?, active=?, body=? WHERE key=? AND binding=?",
|
|
(receipt["state"], active, json.dumps(receipt, sort_keys=True), receipt["key"], receipt["binding"]))
|
|
if written.rowcount != 1:
|
|
raise GroupProvenanceUnavailable()
|