← Files LegalQuants TransactionalARCHIVED FILE

skills/definition-check/scripts/definition_check/workspace.py

7.33 KB · Oct 3, 2026 · 06:34 UTC

↓ Download file

"""Create and safely remove definition-check internal run workspaces."""

from __future__ import annotations

import json
import os
import shutil
import tempfile
import uuid
from datetime import UTC, datetime
from pathlib import Path
from typing import Any

from .prompts import prompt_inventory
from .term_identity import TERM_NORMALIZATION_VERSION

WORKSPACE_SCHEMA_VERSION = "definition-check-workspace-v3"
WORKSPACE_MARKER = ".definition-check-workspace.json"


class WorkspaceError(ValueError):
    """Raised when an internal run workspace cannot be trusted."""


def require_within_workspace(
    path: str | Path, workspace: str | Path, *, label: str
) -> Path:
    """Resolve one internal artifact path and require workspace containment."""

    resolved = Path(path).resolve()
    root = Path(workspace).resolve()
    if resolved == root or not resolved.is_relative_to(root):
        raise WorkspaceError(
            f"{label} is outside the definition-check workspace: {resolved}"
        )
    return resolved


def require_disjoint_paths(output_dir: str | Path, work_dir: str | Path) -> None:
    """Prevent public output and private workspace trees from overlapping."""

    output = Path(output_dir).resolve()
    workspace = Path(work_dir).resolve()
    if (
        output == workspace
        or output.is_relative_to(workspace)
        or workspace.is_relative_to(output)
    ):
        raise WorkspaceError(
            "--output-dir and --work-dir must be disjoint directory trees"
        )


def temporary_workspace_root(workspace_root: str | Path | None = None) -> Path:
    approved = (
        Path(tempfile.gettempdir()) if workspace_root is None else Path(workspace_root)
    )
    approved = approved.resolve()
    return (approved / "definition-check").resolve()


def _private_mkdir(path: Path) -> None:
    path.mkdir(mode=0o700, parents=True, exist_ok=True)
    if os.name != "nt":
        path.chmod(0o700)


def _atomic_json(path: Path, value: object) -> None:
    path.parent.mkdir(parents=True, exist_ok=True)
    fd, temporary = tempfile.mkstemp(prefix=f".{path.name}.", dir=path.parent)
    try:
        with os.fdopen(fd, "w", encoding="utf-8", newline="") as handle:
            json.dump(value, handle, ensure_ascii=False, indent=2, sort_keys=True)
            handle.write("\n")
            handle.flush()
            os.fsync(handle.fileno())
        os.replace(temporary, path)
    except BaseException:
        try:
            os.unlink(temporary)
        except FileNotFoundError:
            pass
        raise


def _read_marker(root: Path) -> dict[str, Any]:
    marker_path = root / WORKSPACE_MARKER
    try:
        marker = json.loads(marker_path.read_text(encoding="utf-8"))
    except (OSError, json.JSONDecodeError) as exc:
        raise WorkspaceError(
            f"invalid definition-check workspace marker: {marker_path}"
        ) from exc
    if not isinstance(marker, dict):
        raise WorkspaceError("definition-check workspace marker must be an object")
    if marker.get("schema_version") != WORKSPACE_SCHEMA_VERSION:
        raise WorkspaceError("unsupported definition-check workspace marker")
    if Path(str(marker.get("path", ""))).resolve() != root:
        raise WorkspaceError("definition-check workspace marker path does not match")
    if marker.get("run_id") != root.name:
        raise WorkspaceError("definition-check workspace run ID does not match")
    return marker


def ensure_workspace(
    path: str | Path,
    *,
    source_sha256: str | None = None,
    cleanup_base: str | Path | None = None,
) -> tuple[Path, dict[str, Any]]:
    """Create or validate a workspace and its fixed internal directory layout."""

    root = Path(path).resolve()
    if root == temporary_workspace_root():
        raise WorkspaceError(
            "the reserved definition-check temp root is not a run workspace"
        )
    existed = root.exists()
    _private_mkdir(root)
    marker_path = root / WORKSPACE_MARKER
    if marker_path.exists():
        marker = _read_marker(root)
        if marker.get("prompt_inventory") != prompt_inventory():
            raise WorkspaceError(
                "workspace packaged prompt inventory does not match; create a new "
                "workspace after updating the installed skill"
            )
        if marker.get("normalization_version") != TERM_NORMALIZATION_VERSION:
            raise WorkspaceError(
                "workspace term normalization version does not match; create a new workspace"
            )
        recorded_source = marker.get("source_sha256")
        if source_sha256 and recorded_source not in (None, source_sha256):
            raise WorkspaceError("workspace source fingerprint does not match")
        if source_sha256 and recorded_source is None:
            marker["source_sha256"] = source_sha256
            _atomic_json(marker_path, marker)
    else:
        if existed and any(root.iterdir()):
            raise WorkspaceError(
                "refusing to mark a non-empty directory as a definition-check workspace"
            )
        marker = {
            "schema_version": WORKSPACE_SCHEMA_VERSION,
            "run_id": root.name,
            "path": str(root),
            "created_at": datetime.now(UTC).isoformat(),
            "source_sha256": source_sha256,
            "prompt_inventory": prompt_inventory(),
            "normalization_version": TERM_NORMALIZATION_VERSION,
            "lifecycle_state": "active",
            "cleanup_base": str(Path(cleanup_base).resolve()) if cleanup_base else None,
        }
        _atomic_json(marker_path, marker)
    for relative in (
        "packets/discovery",
        "packets/semantic",
        "packets/occurrence",
        "packets/reference",
        "private",
        "responses/discovery",
        "responses/semantic",
        "responses/occurrence",
        "responses/reference",
        "bundles",
    ):
        _private_mkdir(root / relative)
    return root, marker


def create_workspace(
    *, source_sha256: str | None = None, workspace_root: str | Path | None = None
) -> tuple[Path, dict[str, Any]]:
    """Create a new marked child beneath temp or an explicitly approved root."""

    base = temporary_workspace_root(workspace_root)
    try:
        _private_mkdir(base)
    except OSError as exc:
        if workspace_root is None:
            raise WorkspaceError(f"temporary_workspace_unavailable: {base}") from exc
        raise WorkspaceError(f"approved_workspace_root_unavailable: {base}") from exc
    run_id = f"run-{uuid.uuid4().hex}"
    return ensure_workspace(
        base / run_id, source_sha256=source_sha256, cleanup_base=base
    )


def cleanup_workspace(path: str | Path) -> Path:
    """Delete one exact, marked workspace beneath the definition-check temp root."""

    root = Path(path).resolve()
    marker = _read_marker(root)
    raw_base = marker.get("cleanup_base")
    if not isinstance(raw_base, str) or not raw_base:
        raise WorkspaceError("workspace marker has no validated cleanup base")
    base = Path(raw_base).resolve()
    if base.name != "definition-check" or root == base or not root.is_relative_to(base):
        raise WorkspaceError(
            "cleanup is restricted to the marked definition-check root"
        )
    marker["lifecycle_state"] = "cleanup_started"
    marker["cleanup_started_at"] = datetime.now(UTC).isoformat()
    _atomic_json(root / WORKSPACE_MARKER, marker)
    shutil.rmtree(root)
    return root

SHA-256: f89b704ee31417766b1efbce4b28cfd9578fb06a8b88f34a51dffbde0f1e62e7