chore(standards): all 17 branches to 100% — Windows-compat sweep + checker getattr fix
Windows-compat hardening across every branch to reach 100% on the seedgo standards audit: - UTF-8 stdout/stderr reconfigure guards (getattr form) on Rich/CLI entry points - platform-branched POSIX-only subprocess kwargs (start_new_session -> CREATE_NEW_PROCESS_GROUP on win32) - seedgo windows_compat checker: credit the getattr reconfigure form + locking test - commons: shared-init test-suite speedup - spawn: aipass_framework template — strip pytest.ini inline comments + add scaffold smoke test - includes in-progress cross-OS testing work (doctor/init_flow/cross_os handlers + tests) Verified: full audit 17/17 at 100%, pyright clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013uzDhtcZ6wT1T9e2AHPQig
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
8630cd90a3
commit
4105a7e8a7
@@ -19,6 +19,13 @@ import sys
|
||||
from pathlib import Path
|
||||
from typing import List
|
||||
|
||||
if sys.platform == "win32":
|
||||
os.environ.setdefault("PYTHONUTF8", "1")
|
||||
for _stream in (sys.stdout, sys.stderr):
|
||||
_reconfigure = getattr(_stream, "reconfigure", None)
|
||||
if _reconfigure is not None:
|
||||
_reconfigure(encoding="utf-8", errors="replace")
|
||||
|
||||
from rich.table import Table
|
||||
from rich.text import Text
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ import json
|
||||
import os
|
||||
import secrets
|
||||
import socket
|
||||
import tempfile
|
||||
import threading
|
||||
import time
|
||||
from pathlib import Path
|
||||
@@ -46,7 +47,7 @@ _SECRET_NAME = "broker_secret"
|
||||
|
||||
_DENYLIST_DIRS = frozenset((".git", ".trinity", ".aipass", ".codex", ".agents"))
|
||||
|
||||
_TMP_BASES = (Path("/tmp"), Path("/var/tmp"))
|
||||
_TMP_BASES = (Path(tempfile.gettempdir()),)
|
||||
|
||||
|
||||
def _find_project_root() -> Path | None:
|
||||
@@ -67,7 +68,7 @@ def _default_socket_path() -> Path:
|
||||
"""Return the default broker socket path under the repo root."""
|
||||
root = _find_project_root()
|
||||
if root is None:
|
||||
return Path("/tmp") / _SOCKET_NAME
|
||||
return Path(tempfile.gettempdir()) / _SOCKET_NAME
|
||||
return root / _DEFAULT_SOCKET_DIR / _SOCKET_NAME
|
||||
|
||||
|
||||
@@ -75,7 +76,7 @@ def _default_audit_path() -> Path:
|
||||
"""Return the default audit log path."""
|
||||
root = _find_project_root()
|
||||
if root is None:
|
||||
return Path("/tmp") / _AUDIT_LOG_NAME
|
||||
return Path(tempfile.gettempdir()) / _AUDIT_LOG_NAME
|
||||
return root / _DEFAULT_SOCKET_DIR / _AUDIT_LOG_NAME
|
||||
|
||||
|
||||
@@ -83,7 +84,7 @@ def _default_secret_path() -> Path:
|
||||
"""Return the default secret path."""
|
||||
root = _find_project_root()
|
||||
if root is None:
|
||||
return Path("/tmp") / _SECRET_NAME
|
||||
return Path(tempfile.gettempdir()) / _SECRET_NAME
|
||||
return root / _DEFAULT_SOCKET_DIR / _SECRET_NAME
|
||||
|
||||
|
||||
|
||||
@@ -17,11 +17,19 @@ from __future__ import annotations
|
||||
import inspect
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
if sys.platform == "win32":
|
||||
os.environ.setdefault("PYTHONUTF8", "1")
|
||||
for _stream in (sys.stdout, sys.stderr):
|
||||
_reconfigure = getattr(_stream, "reconfigure", None)
|
||||
if _reconfigure is not None:
|
||||
_reconfigure(encoding="utf-8", errors="replace")
|
||||
|
||||
from aipass.prax import logger
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@@ -21,6 +21,7 @@ from __future__ import annotations
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
|
||||
@@ -47,8 +48,8 @@ def _find_project_root() -> Path | None:
|
||||
def get_allowed_roots() -> list[Path]:
|
||||
"""Return resolved roots under which deletion is permitted.
|
||||
|
||||
Union of: project root, ``/tmp``, and ``tempfile.gettempdir()`` (which
|
||||
honors ``$TMPDIR``). Deduplicated by resolved path.
|
||||
Union of: project root, system temp dir, and (on POSIX) the canonical
|
||||
temp path. Deduplicated by resolved path.
|
||||
"""
|
||||
seen: set[Path] = set()
|
||||
roots: list[Path] = []
|
||||
@@ -58,7 +59,12 @@ def get_allowed_roots() -> list[Path]:
|
||||
seen.add(project_root)
|
||||
roots.append(project_root)
|
||||
|
||||
for tmp_candidate in (Path("/tmp"), Path(tempfile.gettempdir())):
|
||||
tmp_candidates: list[Path] = []
|
||||
if sys.platform != "win32":
|
||||
tmp_candidates.append(Path("/tmp"))
|
||||
tmp_candidates.append(Path(tempfile.gettempdir()))
|
||||
|
||||
for tmp_candidate in tmp_candidates:
|
||||
resolved = tmp_candidate.resolve()
|
||||
if resolved not in seen:
|
||||
seen.add(resolved)
|
||||
@@ -129,8 +135,8 @@ def check_containment(path: Path, roots: list[Path]) -> tuple[bool, str]:
|
||||
"""Check if *path* (already resolved) is a strict child of any allowed root.
|
||||
|
||||
Returns ``(allowed, reason)``. Refuses the root directories themselves.
|
||||
When multiple roots are nested (e.g. /tmp and /tmp/claude-1000), the path
|
||||
must not equal ANY root — checked upfront before containment.
|
||||
When multiple roots are nested (e.g. temp dir and a subdirectory of it),
|
||||
the path must not equal ANY root — checked upfront before containment.
|
||||
"""
|
||||
root_set = frozenset(roots)
|
||||
if path in root_set:
|
||||
|
||||
@@ -14,6 +14,8 @@ checks and deletion. Provider-agnostic alternative to shell ``rm``.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import tempfile
|
||||
|
||||
from aipass.prax import logger
|
||||
from aipass.cli.apps.modules import console
|
||||
from aipass.drone.apps.handlers.json import json_handler
|
||||
@@ -107,7 +109,8 @@ def print_help() -> None:
|
||||
console.print(" • Symlinks are resolved; refuses if target escapes allowed roots")
|
||||
console.print(" • Nonexistent paths produce a clean error")
|
||||
console.print()
|
||||
_tmp = tempfile.gettempdir()
|
||||
console.print("[bold]Examples:[/bold]")
|
||||
console.print(" [green]drone rm /tmp/scratch_dir[/green]")
|
||||
console.print(f" [green]drone rm {_tmp}/scratch_dir[/green]")
|
||||
console.print(" [green]drone rm build/ dist/[/green]")
|
||||
console.print(" [green]drone rm /tmp/aipass_test_abc123[/green]")
|
||||
console.print(f" [green]drone rm {_tmp}/aipass_test_abc123[/green]")
|
||||
|
||||
Reference in New Issue
Block a user