Files
ss-tools/scripts/dashboard_testing_lab_reset_archive.py

231 lines
11 KiB
Python

# #region Tooling.LabReset.Archive [C:4] [TYPE Module] [SEMANTICS maintenance,archive,private,typed]
# @BRIEF Private reversible selected-state archives and safe phase receipts for the two reviewed laboratories.
# @INVARIANT Protected row bodies never enter an archive; unsupported values refuse rather than stringify.
# @RATIONALE Separate reviewed phase digests prevent inventory from authorizing deletion or automatic recovery.
# @REJECTED Pickle, whole database dumps, public exception strings and implicit archive overwrite.
import base64
from datetime import date, datetime, time, timedelta
from decimal import Decimal
from hashlib import sha256
import json
import math
import os
from pathlib import Path
import stat
import traceback
from uuid import UUID, uuid4
# #region Tooling.LabReset.Archive.Stop [C:1] [TYPE Class]
class Stop(RuntimeError):
"""Fixed public cause; the original exception is retained only privately."""
# #endregion Tooling.LabReset.Archive.Stop
# #region Tooling.LabReset.Archive.Require [C:1] [TYPE Function]
def require(condition, code):
if not condition:
raise Stop(code)
# #endregion Tooling.LabReset.Archive.Require
# #region Tooling.LabReset.Archive.Json [C:1] [TYPE Function]
def json_bytes(value):
return json.dumps(value, sort_keys=True, separators=(",", ":"), ensure_ascii=False,
allow_nan=False).encode("utf-8")
# #endregion Tooling.LabReset.Archive.Json
# #region Tooling.LabReset.Archive.Digest [C:1] [TYPE Function]
def digest(value):
return sha256(json_bytes(value)).hexdigest()
# #endregion Tooling.LabReset.Archive.Digest
# #region Tooling.LabReset.Archive.EncodeScalar [C:2] [TYPE Function]
def scalar(value):
converters = {bytes: lambda v: base64.b64encode(v).decode("ascii"),
UUID: str, Decimal: str, datetime: lambda v: v.isoformat(),
date: lambda v: v.isoformat(), time: lambda v: v.isoformat(),
timedelta: lambda v: [v.days, v.seconds, v.microseconds]}
converter = converters.get(type(value))
require(converter is not None, "LAB_RESET_CODEC_UNSUPPORTED")
if isinstance(value, Decimal):
require(value.is_finite(), "LAB_RESET_CODEC_UNSUPPORTED")
return [type(value).__name__, converter(value)]
# #endregion Tooling.LabReset.Archive.EncodeScalar
# #region Tooling.LabReset.Archive.Encode [C:3] [TYPE Function]
# @POST Every supported SQL value has a reversible tagged representation; dict keys remain exact strings.
def encode(value):
if value is None or type(value) in (str, bool, int):
return [type(value).__name__, value]
if type(value) is float:
require(math.isfinite(value), "LAB_RESET_CODEC_UNSUPPORTED")
return ["float", value.hex()]
if type(value) in (list, tuple):
return [type(value).__name__, [encode(item) for item in value]]
if type(value) is dict:
require(all(type(key) is str for key in value), "LAB_RESET_CODEC_UNSUPPORTED")
return ["dict", [[key, encode(value[key])] for key in sorted(value)]]
return scalar(value)
# #endregion Tooling.LabReset.Archive.Encode
# #region Tooling.LabReset.Archive.Decode [C:3] [TYPE Function]
def decode(value):
require(isinstance(value, list) and len(value) == 2, "LAB_RESET_ARCHIVE_INVALID")
tag, body = value
converters = {"NoneType": lambda v: None, "str": str, "bool": bool, "int": int,
"float": float.fromhex, "bytes": lambda v: base64.b64decode(v, validate=True),
"UUID": UUID, "Decimal": Decimal, "datetime": datetime.fromisoformat,
"date": date.fromisoformat, "time": time.fromisoformat,
"timedelta": lambda v: timedelta(days=v[0], seconds=v[1], microseconds=v[2]),
"list": lambda v: [decode(item) for item in v],
"tuple": lambda v: tuple(decode(item) for item in v),
"dict": lambda v: {key: decode(item) for key, item in v}}
require(tag in converters, "LAB_RESET_ARCHIVE_INVALID")
result = converters[tag](body)
require(encode(result) == value, "LAB_RESET_ARCHIVE_INVALID")
return result
# #endregion Tooling.LabReset.Archive.Decode
# #region Tooling.LabReset.Archive.SafePath [C:3] [TYPE Function]
# @POST Every existing ancestor is a real directory; no symlink or lexical traversal is adopted.
def safe_path(root, relative):
root, relative = Path(root), Path(relative)
require(root.is_absolute() and not relative.is_absolute() and relative.parts
and all(part not in (".", "..") for part in relative.parts), "LAB_RESET_PATH_INVALID")
for current in [root, *root.parents]:
require(not current.is_symlink(), "LAB_RESET_SYMLINK_REFUSED")
current = root
for part in relative.parts:
current = current / part
require(not current.is_symlink(), "LAB_RESET_SYMLINK_REFUSED")
return current
# #endregion Tooling.LabReset.Archive.SafePath
# #region Tooling.LabReset.Archive.Read [C:3] [TYPE Function]
def read_bytes(path, private=False, owner_uid=None):
path = safe_path(Path(path).parent, Path(path).name)
fd = os.open(path, os.O_RDONLY | os.O_NOFOLLOW)
with os.fdopen(fd, "rb") as stream:
info = os.fstat(stream.fileno())
require(stat.S_ISREG(info.st_mode), "LAB_RESET_FILE_INVALID")
if private:
expected = os.geteuid() if owner_uid is None else owner_uid
require(stat.S_IMODE(info.st_mode) == 0o600 and info.st_uid == expected,
"LAB_RESET_PRIVATE_MODE_INVALID")
return stream.read()
# #endregion Tooling.LabReset.Archive.Read
# #region Tooling.LabReset.Archive.ReadJson [C:2] [TYPE Function]
def read_json(path, expected_sha, private=False, owner_uid=None):
raw = read_bytes(path, private, owner_uid)
require(len(expected_sha) == 64 and sha256(raw).hexdigest() == expected_sha,
"LAB_RESET_DIGEST_CONFLICT")
return json.loads(raw)
# #endregion Tooling.LabReset.Archive.ReadJson
# #region Tooling.LabReset.Archive.PrivateDirectory [C:2] [TYPE Function]
def private_directory(path, owner_uid=None):
path = Path(path)
require(path.is_absolute() and path.is_dir() and not path.is_symlink(),
"LAB_RESET_PRIVATE_MODE_INVALID")
require(stat.S_IMODE(path.stat().st_mode) == 0o700, "LAB_RESET_PRIVATE_MODE_INVALID")
if owner_uid is not None:
require(path.stat().st_uid == owner_uid, "LAB_RESET_PRIVATE_MODE_INVALID")
for ancestor in path.parents:
require(not ancestor.is_symlink(), "LAB_RESET_SYMLINK_REFUSED")
return path
# #endregion Tooling.LabReset.Archive.PrivateDirectory
# #region Tooling.LabReset.Archive.Sync [C:1] [TYPE Function]
def sync_directory(path):
fd = os.open(path, os.O_RDONLY | os.O_DIRECTORY | os.O_NOFOLLOW)
try:
os.fsync(fd)
finally:
os.close(fd)
# #endregion Tooling.LabReset.Archive.Sync
# #region Tooling.LabReset.Archive.Write [C:2] [TYPE Function]
# @POST Exclusive private durable member is reread byte-for-byte before its digest is returned.
def write_bytes(root, name, raw):
root = private_directory(root)
target = safe_path(root, name)
fd = os.open(target, os.O_WRONLY | os.O_CREAT | os.O_EXCL | os.O_NOFOLLOW, 0o600)
with os.fdopen(fd, "wb") as stream:
stream.write(raw)
stream.flush()
os.fsync(stream.fileno())
sync_directory(root)
require(read_bytes(target, private=True) == raw, "LAB_RESET_ARCHIVE_READBACK_FAILED")
return sha256(raw).hexdigest()
# #endregion Tooling.LabReset.Archive.Write
# #region Tooling.LabReset.Archive.Journal [C:4] [TYPE Class]
# @RELATION DEPENDS_ON -> [Std.Semantics.MolecularCoTLogging]
# @INVARIANT Public events contain only fixed causes, phase/count/hash facts; original causes stay in a separate 0600 file.
class Journal:
# #region Tooling.LabReset.Archive.Journal.Init [C:1] [TYPE Function]
def __init__(self, root, phase):
self.root, self.phase, self.trace = private_directory(root), phase, uuid4().hex
self.database_commit_status = "not_requested"
self.name = f"journal-{self.trace}.jsonl"
self.fd = os.open(self.root / self.name, os.O_WRONLY | os.O_CREAT | os.O_EXCL | os.O_NOFOLLOW, 0o600)
# #endregion Tooling.LabReset.Archive.Journal.Init
# #region Tooling.LabReset.Archive.Journal.Event [C:2] [TYPE Function]
def event(self, marker, intent, *, code=None, loc=None, **facts):
from src.core.cot_logger import build_cot_event
record = build_cot_event(src="Tooling.LabReset", marker=marker, intent=intent,
trace_id=self.trace, claim="PRE: exact reviewed laboratory state",
error_code=code, loc=loc, payload={"phase": self.phase, **facts})
raw = json_bytes(record) + b"\n"
require(os.write(self.fd, raw) == len(raw), "LAB_RESET_JOURNAL_WRITE_FAILED")
os.fsync(self.fd)
print(raw.decode("utf-8"), end="", flush=True)
# #endregion Tooling.LabReset.Archive.Journal.Event
# #region Tooling.LabReset.Archive.Journal.Failure [C:2] [TYPE Function]
def failure(self, exc):
cause = exc.__cause__
details = f"database_commit_status={self.database_commit_status}\n" + "".join(traceback.format_exception(exc))
if cause is not None and hasattr(cause, "stderr"):
details += f"\nstdout:\n{cause.stdout}\nstderr:\n{cause.stderr}"
write_bytes(self.root, f"cause-{self.trace}.txt",
details.encode("utf-8"))
code = str(exc) if isinstance(exc, Stop) else "LAB_RESET_PRIVATE_CAUSE"
frames = traceback.extract_tb(exc.__traceback__)
loc = f"{Path(frames[-1].filename).name}:{frames[-1].lineno}" if frames else None
try:
self.event("EXPLORE", "Laboratory phase stopped; reviewed recovery required",
code=code, loc=loc, failure_type=type(exc).__name__,
database_commit_status=self.database_commit_status)
except (OSError, Stop) as journal_error:
if isinstance(journal_error, Stop) and str(journal_error) != "LAB_RESET_JOURNAL_WRITE_FAILED":
raise
from src.core.cot_logger import build_cot_event
print(json_bytes(build_cot_event(src="Tooling.LabReset", marker="EXPLORE",
intent="Private cause retained; phase journal unavailable", trace_id=self.trace,
error_code="LAB_RESET_JOURNAL_WRITE_FAILED", payload={"phase": self.phase,
"database_commit_status": self.database_commit_status})).decode(), flush=True)
# #endregion Tooling.LabReset.Archive.Journal.Failure
# #region Tooling.LabReset.Archive.Journal.Close [C:1] [TYPE Function]
def close(self):
os.close(self.fd)
sync_directory(self.root)
# #endregion Tooling.LabReset.Archive.Journal.Close
# #endregion Tooling.LabReset.Archive.Journal
# #endregion Tooling.LabReset.Archive