Files
gitea-agent/harness/agents/review/skills/gitea-code-review/scripts/publication_journal.py
T

381 lines
14 KiB
Python

"""Canonical native-review publication journal registry."""
from __future__ import annotations
import errno
import fcntl
import hashlib
import json
import math
import os
import stat
import tempfile
from pathlib import Path
SCHEMA = "gitea-agent.native-review-binding/v1"
INTENT_SCHEMA = "gitea-agent.native-review-intent/v1"
ROOT_NAME = "native-review-journals"
_ROOT_PRESENCE_SCHEMA = "gitea-agent.native-review-root/v1"
_ENTRY_PRESENCE_SCHEMA = "gitea-agent.native-review-entry/v1"
_MAX_JSON = 16 * 1024 * 1024
def _fail(message):
raise ValueError(message)
def _canonical(value):
try:
return json.dumps(value, sort_keys=True, ensure_ascii=False,
allow_nan=False, separators=(",", ":"))
except (TypeError, ValueError, OverflowError):
_fail("non-canonical JSON value")
def _strict_load(data):
def pairs(pairs):
out = {}
for key, value in pairs:
if key in out:
_fail("duplicate JSON key")
out[key] = value
return out
try:
return json.loads(data.decode("utf-8"), object_pairs_hook=pairs,
parse_constant=lambda value: _fail("non-finite JSON"),
parse_float=lambda value: float(value) if math.isfinite(float(value)) else _fail("non-finite JSON"))
except ValueError:
raise
except Exception:
_fail("malformed journal artifact")
def binding_for(plan, *, origin):
t = plan["target"]
return {"schema": SCHEMA, "origin": origin, "owner": t["owner"],
"repository": t["repository"], "issue": t["issue"],
"pull": t["pull"], "head": t["head"],
"contract_sha256": plan["contract_sha256"],
"reviewer_id": plan["reviewer"]["id"]}
def plan_fingerprint(plan):
return hashlib.sha256(_canonical(plan).encode("utf-8")).hexdigest()
def root_for(anchor_file):
harness = Path(anchor_file).resolve().parents[5]
return harness / ".runtime" / ROOT_NAME
def canonical_path(plan, *, anchor_file, origin, validate):
validate(plan)
binding = binding_for(plan, origin=origin)
key = hashlib.sha256(_canonical(binding).encode("utf-8")).hexdigest()
return root_for(anchor_file) / "v1" / key
def _raw_path_safe(value):
if isinstance(value, str):
if not value.startswith("/"):
_fail("unsafe journal path")
parts = value.split("/")
if any(part in ("", ".", "..") for part in parts[1:]):
_fail("unsafe journal path")
def _check_ancestor_chain(path, *, allow_missing_leaf=False):
path = Path(path)
if not path.is_absolute() or any(part in ("", ".", "..") for part in path.parts):
_fail("unsafe journal path")
current = Path(path.anchor)
for index, part in enumerate(path.parts[1:]):
current /= part
try:
st = current.lstat()
except FileNotFoundError:
if allow_missing_leaf and index == len(path.parts) - 2:
return
_fail("missing trusted journal ancestor")
if stat.S_ISLNK(st.st_mode) or not stat.S_ISDIR(st.st_mode):
_fail("unsafe journal ancestor")
def _fsync_dir(path):
fd = os.open(path, os.O_RDONLY | os.O_DIRECTORY | os.O_NOFOLLOW | os.O_CLOEXEC)
try:
os.fsync(fd)
finally:
os.close(fd)
def _check_private_file(fd, *, what):
st = os.fstat(fd)
if (not stat.S_ISREG(st.st_mode) or st.st_uid != os.getuid()
or stat.S_IMODE(st.st_mode) != 0o600 or st.st_nlink != 1):
_fail("unsafe journal " + what)
return st
def _open_bootstrap(parent):
path = Path(parent) / (ROOT_NAME + ".bootstrap.lock")
try:
fd = os.open(path, os.O_RDWR | os.O_CREAT | os.O_NOFOLLOW | os.O_CLOEXEC, 0o600)
except OSError:
_fail("unsafe journal bootstrap lock")
try:
_check_private_file(fd, what="bootstrap lock")
try:
fcntl.flock(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
except (BlockingIOError, OSError) as exc:
if getattr(exc, "errno", None) in (errno.EACCES, errno.EAGAIN):
_fail("journal bootstrap busy")
raise
return fd
except Exception:
os.close(fd)
raise
def _presence_read(path, cap=4096):
try:
return _strict_load(_secure_file(path, cap=cap))
except FileNotFoundError:
return None
def _atomic_bytes(directory, name, data, *, replace=False):
directory = Path(directory)
_check_ancestor_chain(directory)
target = directory / name
try:
st = target.lstat()
if stat.S_ISLNK(st.st_mode) or not stat.S_ISREG(st.st_mode) or st.st_nlink != 1:
_fail("unsafe journal artifact")
if not replace:
_fail("journal artifact already exists")
except FileNotFoundError:
pass
fd, temp = tempfile.mkstemp(dir=directory, prefix=".native-review-")
try:
os.fchmod(fd, 0o600)
with os.fdopen(fd, "wb") as out:
out.write(data); out.flush(); os.fsync(out.fileno())
if replace:
os.replace(temp, target)
else:
try:
os.link(temp, target)
except FileExistsError:
_fail("journal artifact already exists")
os.unlink(temp)
_fsync_dir(directory)
finally:
try:
os.unlink(temp)
except FileNotFoundError:
pass
def atomic_json(directory, name, value):
_atomic_bytes(directory, name, _canonical(value).encode("utf-8"))
def ensure_root(root, *, _lock_fd=None):
root = Path(root)
parent = root.parent
_check_ancestor_chain(parent)
lock_fd = _lock_fd if _lock_fd is not None else _open_bootstrap(parent)
try:
root_presence = parent / (root.name + ".presence")
rp = _presence_read(root_presence)
root_exists = False
try:
rst = root.lstat(); root_exists = True
except FileNotFoundError:
rst = None
if rp is None:
if root_exists:
_fail("journal root presence anchor missing")
root.mkdir(mode=0o700)
rst = root.lstat()
atomic_json(parent, root_presence.name, {"schema": _ROOT_PRESENCE_SCHEMA,
"root": root.name + "/v1", "devino": [rst.st_dev, rst.st_ino]})
else:
if set(rp) != {"schema", "root", "devino"} or rp["schema"] != _ROOT_PRESENCE_SCHEMA:
_fail("malformed journal root presence")
if not root_exists or stat.S_ISLNK(rst.st_mode) or not stat.S_ISDIR(rst.st_mode):
_fail("journal root was deleted")
if [rst.st_dev, rst.st_ino] != rp["devino"]:
_fail("journal root was replaced")
rst = root.lstat()
if (stat.S_ISLNK(rst.st_mode) or not stat.S_ISDIR(rst.st_mode)
or rst.st_uid != os.getuid() or stat.S_IMODE(rst.st_mode) != 0o700):
_fail("unsafe journal root")
version = root / "v1"
try: vst = version.lstat()
except FileNotFoundError:
version.mkdir(mode=0o700); _fsync_dir(root); vst = version.lstat()
if (stat.S_ISLNK(vst.st_mode) or not stat.S_ISDIR(vst.st_mode)
or vst.st_uid != os.getuid() or stat.S_IMODE(vst.st_mode) != 0o700):
_fail("unsafe journal registry")
return root
finally:
if _lock_fd is None:
os.close(lock_fd)
def _secure_file(path, *, cap=_MAX_JSON):
_raw_path_safe(os.fspath(path))
fd = os.open(path, os.O_RDONLY | os.O_NOFOLLOW | os.O_NONBLOCK | os.O_CLOEXEC)
try:
st = _check_private_file(fd, what="artifact")
if st.st_size > cap:
_fail("oversize journal artifact")
chunks = []; total = 0
while True:
chunk = os.read(fd, min(65536, cap + 1 - total))
if not chunk: break
chunks.append(chunk); total += len(chunk)
if total > cap: _fail("oversize journal artifact")
return b"".join(chunks)
finally:
os.close(fd)
def _entry_check(entry):
st = Path(entry).lstat()
if (stat.S_ISLNK(st.st_mode) or not stat.S_ISDIR(st.st_mode)
or st.st_uid != os.getuid() or stat.S_IMODE(st.st_mode) != 0o700):
_fail("unsafe journal binding")
return st
def _presence_path(entry):
entry = Path(entry)
return entry.parents[1].parent / (entry.name + ".presence")
def open_binding(path, plan, *, anchor_file, origin, validate, require_new=False):
_raw_path_safe(os.fspath(path))
validate(plan)
expected = canonical_path(plan, anchor_file=anchor_file, origin=origin, validate=validate)
if Path(path) != expected or (isinstance(path, str) and path != str(expected)):
_fail("non-canonical journal path")
root = expected.parents[1]
_check_ancestor_chain(root.parent, allow_missing_leaf=True)
try:
root.parent.mkdir(mode=0o700)
_fsync_dir(root.parent.parent)
except FileExistsError:
pass
_entry_check(root.parent)
bootstrap = _open_bootstrap(root.parent)
try:
ensure_root(root, _lock_fd=bootstrap)
entry = expected
presence = _presence_path(entry)
ep = _presence_read(presence)
exists = entry.exists()
if require_new and (exists or ep is not None):
_fail("canonical journal entry already exists")
if ep is not None:
if set(ep) != {"schema", "entry", "devino", "fingerprint", "state"} or ep["schema"] != _ENTRY_PRESENCE_SCHEMA:
_fail("malformed journal entry presence")
if ep["state"] != "complete" or not exists:
_fail("interrupted or deleted journal entry")
st = _entry_check(entry)
if [st.st_dev, st.st_ino] != ep["devino"]:
_fail("journal entry was replaced")
elif exists:
_fail("journal entry presence anchor missing")
else:
entry.mkdir(mode=0o700); _fsync_dir(root)
if require_new:
atomic_json(entry, "import.pending.json", {
"schema": "gitea-agent.native-review-import/v1",
"state": "pending"})
st = _entry_check(entry)
pending = entry / "import.pending.json"
if not require_new and pending.exists():
_fail("interrupted legacy registration")
binding = binding_for(plan, origin=origin)
expected_record = {"schema": SCHEMA, "binding": binding, "fingerprint": plan_fingerprint(plan)}
record_path = entry / "binding.json"
try:
existing = _strict_load(_secure_file(record_path, cap=1024 * 1024))
except FileNotFoundError:
existing = None
if existing is not None and _canonical(existing) != _canonical(expected_record):
_fail("binding record mismatch")
if existing is None:
if ep is not None:
_fail("known journal binding record missing")
if require_new is False and record_path.exists() and not record_path.is_file():
_fail("unsafe journal binding record")
atomic_json(entry, "binding.json", expected_record)
if ep is None:
_atomic_bytes(presence.parent, presence.name, _canonical({
"schema": _ENTRY_PRESENCE_SCHEMA, "entry": entry.name,
"devino": [st.st_dev, st.st_ino], "fingerprint": expected_record["fingerprint"],
"state": "complete"}).encode())
else:
if ep["fingerprint"] != expected_record["fingerprint"]:
_fail("entry binding fingerprint mismatch")
return entry
finally:
os.close(bootstrap)
def assert_bound(entry, plan, *, anchor_file, origin, validate):
validate(plan)
entry = Path(entry)
expected = canonical_path(plan, anchor_file=anchor_file, origin=origin, validate=validate)
if entry != expected:
_fail("non-canonical journal path")
root = expected.parents[1]
_check_ancestor_chain(entry)
_entry_check(root.parent); rst = _entry_check(root)
_entry_check(root / 'v1'); st = _entry_check(entry)
rp = _presence_read(root.parent / (root.name + ".presence"))
expected_rp = {"schema": _ROOT_PRESENCE_SCHEMA, "root": root.name + "/v1",
"devino": [rst.st_dev, rst.st_ino]}
if _canonical(rp) != _canonical(expected_rp):
_fail("journal root presence mismatch")
expected_record = {"schema": SCHEMA, "binding": binding_for(plan, origin=origin), "fingerprint": plan_fingerprint(plan)}
ep = _presence_read(_presence_path(entry))
expected_ep = {"schema": _ENTRY_PRESENCE_SCHEMA, "entry": entry.name,
"devino": [st.st_dev, st.st_ino], "fingerprint": expected_record["fingerprint"],
"state": "complete"}
if _canonical(ep) != _canonical(expected_ep):
_fail("journal entry presence mismatch")
record = _strict_load(_secure_file(entry / "binding.json", cap=1024 * 1024))
if _canonical(record) != _canonical(expected_record):
_fail("binding record mismatch")
return entry
def acquire_lock(entry):
path = Path(entry) / "publication.lock"
fd = None
try:
fd = os.open(path, os.O_RDWR | os.O_CREAT | os.O_NOFOLLOW | os.O_NONBLOCK | os.O_CLOEXEC, 0o600)
_check_private_file(fd, what="lock")
try:
fcntl.flock(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
except OSError as exc:
if exc.errno in (errno.EACCES, errno.EAGAIN):
_fail("journal lock busy")
raise
return fd
except BaseException:
if fd is not None:
os.close(fd)
raise
def read_json(entry, name, cap=_MAX_JSON):
try:
return _strict_load(_secure_file(Path(entry) / name, cap=cap))
except FileNotFoundError:
return None