#!/usr/bin/env python3 """Canonical Atlas project and Git-ref policy for distributed execution.""" from __future__ import annotations import json import os import re import stat import subprocess from pathlib import Path from typing import Any DATA_ROOT = Path(os.environ.get("HERMES_HOME", "/opt/data")) PROJECT_ROOT = DATA_ROOT / "workspace/projects" BOARD_ROOT = DATA_ROOT / "kanban/boards" ATLAS_REPO = re.compile( r"https://scm\.bstein\.dev/titan/(?P[A-Za-z0-9][A-Za-z0-9_.-]{0,99})\.git\Z" ) SAFE_PREFIXES = frozenset( {"feature", "fix", "chore", "docs", "test", "refactor", "wt", "review", "hermes", "handoff"} ) IDENTIFIER = re.compile(r"[A-Za-z0-9][A-Za-z0-9_.-]{0,127}\Z") GIT = "/usr/bin/git" MAX_BOARD_BYTES = 64 * 1024 REPOSITORY_ALIASES = {"titan-iac": "atlas-iac"} class ProjectPolicyError(ValueError): """Canonical project metadata or a requested ref failed closed.""" def _task_value(task: Any, name: str, default: Any = None) -> Any: return getattr(task, name, default) def _run_git(workdir: Path, *arguments: str) -> str: completed = subprocess.run( [GIT, "-C", str(workdir), *arguments], check=False, stdin=subprocess.DEVNULL, capture_output=True, text=True, timeout=30, env={ "HOME": "/nonexistent", "PATH": "/usr/bin:/bin", "GIT_CONFIG_NOSYSTEM": "1", "GIT_TERMINAL_PROMPT": "0", }, ) if completed.returncode: raise ProjectPolicyError("canonical project Git metadata is unavailable") return completed.stdout.strip() def validate_branch(value: object, *, feature: bool) -> str: """Validate a complete local branch name with Git and a reviewed namespace.""" if not isinstance(value, str) or not value or len(value) > 200: raise ProjectPolicyError("branch name exceeds the safe limit") if not value.isascii() or value.startswith("-"): raise ProjectPolicyError("branch name must be canonical ASCII") prefix = value.split("/", 1)[0] if feature and ("/" not in value or prefix not in SAFE_PREFIXES): raise ProjectPolicyError("task branch is outside the reviewed namespace") completed = subprocess.run( [GIT, "check-ref-format", f"refs/heads/{value}"], check=False, stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, timeout=10, env={"PATH": "/usr/bin:/bin", "GIT_CONFIG_NOSYSTEM": "1"}, ) if completed.returncode: raise ProjectPolicyError("branch name is not a valid Git ref") return value def _read_board(board: str) -> dict[str, Any]: if not IDENTIFIER.fullmatch(board): raise ProjectPolicyError("board slug is invalid") path = BOARD_ROOT / board / "board.json" descriptor = os.open(path, os.O_RDONLY | getattr(os, "O_NOFOLLOW", 0)) try: info = os.fstat(descriptor) if not stat.S_ISREG(info.st_mode) or not 0 < info.st_size <= MAX_BOARD_BYTES: raise ProjectPolicyError("board registry entry is not a bounded regular file") raw = os.read(descriptor, MAX_BOARD_BYTES + 1) finally: os.close(descriptor) try: value = json.loads(raw) except (UnicodeError, json.JSONDecodeError) as error: raise ProjectPolicyError("board registry entry is malformed") from error if not isinstance(value, dict) or value.get("slug") != board or value.get("archived") is True: raise ProjectPolicyError("board registry identity is unavailable or archived") return value def resolve_project(board: str) -> tuple[str, str, Path]: """Resolve repo and base exclusively from the canonical board registry. A board may be created before its primary checkout. In that case the Atlas repository naming contract and ``main`` are the registry defaults; once a checkout exists, its credential-free origin and remote HEAD must agree with that identity. This keeps a missing checkout from silently routing work to some other project's repository. """ entry = _read_board(board) raw_workdir = entry.get("default_workdir") if not isinstance(raw_workdir, str) or not Path(raw_workdir).is_absolute(): raise ProjectPolicyError("board default_workdir is missing") workdir = Path(raw_workdir).resolve(strict=False) project_root = PROJECT_ROOT.resolve(strict=True) try: workdir.relative_to(project_root) except ValueError as error: raise ProjectPolicyError("board workdir is outside the Atlas project registry") from error repository = REPOSITORY_ALIASES.get(board, board) remote = f"https://scm.bstein.dev/titan/{repository}.git" if not ATLAS_REPO.fullmatch(remote): raise ProjectPolicyError("board repository identity is invalid") if not workdir.exists(): return remote, "main", workdir if not workdir.is_dir(): raise ProjectPolicyError("board checkout is not a directory") checkout_remote = _run_git(workdir, "remote", "get-url", "origin") if "@" in checkout_remote or checkout_remote != remote: raise ProjectPolicyError("board origin disagrees with the Atlas registry") try: base = _run_git(workdir, "symbolic-ref", "--short", "refs/remotes/origin/HEAD") if not base.startswith("origin/"): raise ProjectPolicyError("origin HEAD is not canonical") base = base.removeprefix("origin/") except ProjectPolicyError: base = "main" return remote, validate_branch(base, feature=False), workdir def resolve_assignment(board: str, task: Any) -> tuple[str, str, str]: """Resolve the exact repo/base and safe task branch for one board task.""" repo, base, _workdir = resolve_project(board) task_id = str(_task_value(task, "id", "") or "") if not IDENTIFIER.fullmatch(task_id): raise ProjectPolicyError("task identity is invalid") branch = str(_task_value(task, "branch_name", "") or f"wt/{task_id}") return repo, validate_branch(branch, feature=True), base def distributed_workspace_eligible(task: Any) -> bool: """Only pathless tasks migrate; an existing worktree stays with its local owner.""" return not str(_task_value(task, "workspace_path", "") or "").strip()