From 4586cde64d5480a02f3be2ce8b484a3d7903c9ba Mon Sep 17 00:00:00 2001 From: teknium1 <127238744+teknium1@users.noreply.github.com> Date: Sat, 19 Sep 2026 01:45:46 -0700 Subject: [PATCH] chore: mark the deliberate /tmp literals and shrink the lint baseline to one code block MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The seventeen remaining literals are container-side paths, AF_UNIX socket-path-limit candidates on darwin, detection needles, guard regexes and guidance text that tells the model to avoid /tmp. Each carries an inline `no-tmp: ok — ` so the reason lives next to the line; the baseline keeps only a fenced tree listing where a marker would render. --- gateway/control_socket.py | 2 +- hermes_cli/codex_runtime_plugin_migration.py | 2 +- hermes_cli/gateway.py | 2 +- mini_swe_runner.py | 2 +- plugins/disk-cleanup/README.md | 2 + plugins/disk-cleanup/__init__.py | 2 +- plugins/platforms/line/adapter.py | 2 +- scripts/check_no_tmp_literals.py | 89 +------------------- scripts/generate_conformance_vectors.py | 2 +- tools/browser_tool.py | 2 +- tools/code_kernel.py | 2 +- tools/environments/base.py | 2 +- tools/environments/daytona.py | 2 +- tools/environments/docker.py | 2 +- tools/environments/vercel_sandbox.py | 2 +- tools/self_repo_guard.py | 4 +- tools/skills_guard.py | 4 +- 17 files changed, 21 insertions(+), 104 deletions(-) diff --git a/gateway/control_socket.py b/gateway/control_socket.py index 9a14f8c2e2..30348e492c 100644 --- a/gateway/control_socket.py +++ b/gateway/control_socket.py @@ -54,7 +54,7 @@ def _fallback_socket_path(home: Path) -> Path: then ``/tmp`` (POSIX); if nothing fits the tempdir candidate is returned anyway — bind fails non-fatally and consumers use the scan layer.""" name = f"hermes-gw-{_home_hash(home)}.sock" - candidates = [Path(tempfile.gettempdir()) / name] + ([] if _IS_WINDOWS else [Path("/tmp") / name]) + candidates = [Path(tempfile.gettempdir()) / name] + ([] if _IS_WINDOWS else [Path("/tmp") / name]) # no-tmp: ok — AF_UNIX 104-byte path limit needs the short /tmp candidate return next((c for c in candidates if _fits_sun_path(c)), candidates[0]) diff --git a/hermes_cli/codex_runtime_plugin_migration.py b/hermes_cli/codex_runtime_plugin_migration.py index cc47a49a70..8305a37129 100644 --- a/hermes_cli/codex_runtime_plugin_migration.py +++ b/hermes_cli/codex_runtime_plugin_migration.py @@ -364,7 +364,7 @@ def _query_codex_plugins( # pytest tempdir shapes: ``pytest-of-/pytest-/``, macOS ``/private/var/folders/…/T``. -_TEST_TEMPDIR_NEEDLES = ("pytest-of-", "/pytest-", "/tmp/pytest", "/private/var/folders/") +_TEST_TEMPDIR_NEEDLES = ("pytest-of-", "/pytest-", "/tmp/pytest", "/private/var/folders/") # no-tmp: ok — detection needle for pytest temp homes def _looks_like_test_tempdir(path: str) -> bool: diff --git a/hermes_cli/gateway.py b/hermes_cli/gateway.py index 7bf1506270..7e3b20ada2 100644 --- a/hermes_cli/gateway.py +++ b/hermes_cli/gateway.py @@ -3117,7 +3117,7 @@ def _temp_home_in_service_definition(definition: str) -> str | None: candidates += re.findall(r"HERMES_HOME\s*(.*?)", definition, flags=re.S) temp_roots = { Path(tempfile.gettempdir()).resolve(), - Path("/tmp"), Path("/var/tmp"), Path("/private/tmp"), Path("/private/var/tmp"), + Path("/tmp"), Path("/var/tmp"), Path("/private/tmp"), Path("/private/var/tmp"), # no-tmp: ok — detects a temp HERMES_HOME in service definitions } for raw in candidates: try: diff --git a/mini_swe_runner.py b/mini_swe_runner.py index 62410d8e33..696f50144a 100644 --- a/mini_swe_runner.py +++ b/mini_swe_runner.py @@ -107,7 +107,7 @@ def create_environment(env_type: str = "local", image: str = "python:3.11-slim", return LocalEnvironment(cwd=cwd or tempfile.gettempdir(), timeout=timeout) if env_type not in ("docker", "modal"): raise ValueError(f"Unknown environment type: {env_type}. Use 'local', 'docker', or 'modal'") - cwd = cwd or "/tmp" # container-side path, not the host temp dir + cwd = cwd or "/tmp" # container-side path, not the host temp dir # no-tmp: ok — container-side path, not the host temp dir module = importlib.import_module(f"tools.environments.{env_type}") return getattr(module, f"{env_type.capitalize()}Environment")(image=image, cwd=cwd, timeout=timeout, **kwargs) diff --git a/plugins/disk-cleanup/README.md b/plugins/disk-cleanup/README.md index d9410f2eb8..bf4c88f269 100644 --- a/plugins/disk-cleanup/README.md +++ b/plugins/disk-cleanup/README.md @@ -2,6 +2,7 @@ Auto-tracks and cleans up ephemeral files created during Hermes Agent sessions — test scripts, temp outputs, cron logs, stale chrome profiles. + Scoped strictly to `$HERMES_HOME` and `/tmp/hermes-*`. Originally contributed by [@LVT382009](https://github.com/LVT382009) as a @@ -41,6 +42,7 @@ Deletion rules (same as the original PR): ## Safety + - `is_safe_path()` rejects anything outside `HERMES_HOME` or `/tmp/hermes-*` - Windows mounts (`/mnt/c` etc.) are rejected - The state directory `$HERMES_HOME/disk-cleanup/` is itself excluded diff --git a/plugins/disk-cleanup/__init__.py b/plugins/disk-cleanup/__init__.py index 6320d8bccb..539415e732 100644 --- a/plugins/disk-cleanup/__init__.py +++ b/plugins/disk-cleanup/__init__.py @@ -102,7 +102,7 @@ Subcommands: Categories: temp | test | research | download | chrome-profile | cron-output | other -All operations are scoped to HERMES_HOME and /tmp/hermes-*. +All operations are scoped to HERMES_HOME and /tmp/hermes-*. # no-tmp: ok — legacy scratch scope this plugin cleans up Test files are auto-tracked on write_file / terminal and auto-cleaned at session end. """ diff --git a/plugins/platforms/line/adapter.py b/plugins/platforms/line/adapter.py index 2ac12d4ed0..6a5ee0d5cd 100644 --- a/plugins/platforms/line/adapter.py +++ b/plugins/platforms/line/adapter.py @@ -799,7 +799,7 @@ class LineAdapter(BasePlatformAdapter): except Exception: hermes_home = Path.home().joinpath(".hermes").resolve() resolved = path.resolve() - if not any(resolved.is_relative_to(r) for r in (Path(tempfile.gettempdir()).resolve(), Path("/tmp").resolve(), hermes_home)): + if not any(resolved.is_relative_to(r) for r in (Path(tempfile.gettempdir()).resolve(), Path("/tmp").resolve(), hermes_home)): # no-tmp: ok — macOS /private/tmp alias in the allowed-roots check, not a write target logger.warning("LINE: refusing to serve outside allowed roots: %s", resolved) return web.Response(status=403, text="forbidden") content_type = mimetypes.guess_type(str(path))[0] or "application/octet-stream" diff --git a/scripts/check_no_tmp_literals.py b/scripts/check_no_tmp_literals.py index b214153443..1f1bb1a10b 100644 --- a/scripts/check_no_tmp_literals.py +++ b/scripts/check_no_tmp_literals.py @@ -204,93 +204,8 @@ def scan(paths=None, root: Path | None = None) -> dict[str, list[tuple[int, str] # Files that carried literal /tmp paths when this check landed, with their hit counts. # Burn-down list: fix or mark, then delete the entry. Regenerate with --print-baseline. _BASELINE: dict[str, int] = { - "CONTRIBUTING.md": 1, - "apps/desktop/README.md": 1, - "apps/desktop/scripts/perf/README.md": 2, - "apps/desktop/scripts/profile-typing-lag.md": 4, - "gateway/control_socket.py": 1, - "hermes_cli/codex_runtime_plugin_migration.py": 1, - "hermes_cli/gateway.py": 1, - "hermes_constants.py": 1, - "mini_swe_runner.py": 1, - "plugins/disk-cleanup/README.md": 2, - "plugins/disk-cleanup/__init__.py": 1, - "plugins/platforms/line/adapter.py": 1, - "scripts/generate_conformance_vectors.py": 1, - "tools/browser_tool.py": 1, - "tools/code_kernel.py": 1, - "tools/environments/base.py": 1, - "tools/environments/daytona.py": 1, - "tools/environments/docker.py": 1, - "tools/environments/local.py": 3, - "tools/environments/vercel_sandbox.py": 1, - "tools/self_repo_guard.py": 2, - "tools/skills_guard.py": 2, - "website/docs/developer-guide/egress-internals.md": 2, - "website/docs/developer-guide/gateway-monitoring.md": 3, - "website/docs/developer-guide/image-gen-provider-plugin.md": 1, - "website/docs/developer-guide/middleware.md": 2, - "website/docs/developer-guide/model-provider-plugin.md": 1, - "website/docs/developer-guide/session-storage.md": 1, - "website/docs/getting-started/nix-setup.md": 2, - "website/docs/guides/delegation-patterns.md": 2, - "website/docs/guides/local-ollama-setup.md": 2, - "website/docs/guides/pipe-script-output.md": 1, - "website/docs/reference/cli-commands.md": 9, - "website/docs/reference/faq.md": 1, - "website/docs/user-guide/bot-mode.md": 3, - "website/docs/user-guide/configuration.md": 3, - "website/docs/user-guide/desktop.md": 1, - "website/docs/user-guide/docker.md": 2, - "website/docs/user-guide/features/built-in-plugins.md": 2, - "website/docs/user-guide/features/codex-app-server-runtime.md": 1, - "website/docs/user-guide/features/context-files.md": 1, - "website/docs/user-guide/features/cron.md": 2, - "website/docs/user-guide/features/deliverable-mode.md": 4, - "website/docs/user-guide/features/document-extraction.md": 1, - "website/docs/user-guide/features/goals.md": 11, - "website/docs/user-guide/features/mcp.md": 1, - "website/docs/user-guide/features/skills.md": 1, - "website/docs/user-guide/messaging/slack.md": 1, - "website/docs/user-guide/security.md": 2, - "website/docs/user-guide/skills/bundled/apple/apple-findmy.md": 6, - "website/docs/user-guide/skills/bundled/autonomous-ai-agents/autonomous-ai-agents-claude-code.md": 3, - "website/docs/user-guide/skills/bundled/autonomous-ai-agents/autonomous-ai-agents-codex.md": 6, - "website/docs/user-guide/skills/bundled/autonomous-ai-agents/autonomous-ai-agents-opencode.md": 2, - "website/docs/user-guide/skills/bundled/creative/creative-ascii-art.md": 2, - "website/docs/user-guide/skills/bundled/creative/creative-pretext.md": 1, - "website/docs/user-guide/skills/bundled/github/github-github-pr-workflow.md": 2, - "website/docs/user-guide/skills/bundled/github/github-github-repo-management.md": 2, - "website/docs/user-guide/skills/bundled/productivity/productivity-ocr-and-documents.md": 1, - "website/docs/user-guide/skills/bundled/research/research-blocked-page-recovery.md": 1, - "website/docs/user-guide/skills/bundled/smart-home/smart-home-openhue.md": 2, - "website/docs/user-guide/skills/bundled/software-development/software-development-hermes-agent-skill-authoring.md": 1, - "website/docs/user-guide/skills/bundled/software-development/software-development-inspecting-hermes-desktop-dom.md": 2, - "website/docs/user-guide/skills/bundled/software-development/software-development-node-inspect-debugger.md": 7, - "website/docs/user-guide/skills/bundled/software-development/software-development-python-debugpy.md": 1, - "website/docs/user-guide/skills/bundled/web/web-blocked-page-recovery.md": 1, - "website/docs/user-guide/skills/optional/autonomous-ai-agents/autonomous-ai-agents-blackbox.md": 2, - "website/docs/user-guide/skills/optional/autonomous-ai-agents/autonomous-ai-agents-dynamic-workflow.md": 2, - "website/docs/user-guide/skills/optional/autonomous-ai-agents/autonomous-ai-agents-grok.md": 7, - "website/docs/user-guide/skills/optional/autonomous-ai-agents/autonomous-ai-agents-openhands.md": 1, - "website/docs/user-guide/skills/optional/creative/creative-ascii-art.md": 2, - "website/docs/user-guide/skills/optional/creative/creative-meme-generation.md": 9, - "website/docs/user-guide/skills/optional/creative/creative-pixel-art.md": 3, - "website/docs/user-guide/skills/optional/creative/creative-pretext.md": 1, - "website/docs/user-guide/skills/optional/data-science/data-science-jupyter-notebook.md": 1, - "website/docs/user-guide/skills/optional/devops/devops-pinggy-tunnel.md": 25, - "website/docs/user-guide/skills/optional/gaming/gaming-pokemon-player.md": 1, - "website/docs/user-guide/skills/optional/mcp/mcp-mcp-oauth-remote-gateway.md": 2, - "website/docs/user-guide/skills/optional/payments/payments-stripe-link-cli.md": 2, - "website/docs/user-guide/skills/optional/research/research-bioinformatics.md": 4, - "website/docs/user-guide/skills/optional/research/research-darwinian-evolver.md": 5, - "website/docs/user-guide/skills/optional/research/research-parallel-cli.md": 2, - "website/docs/user-guide/skills/optional/research/research-qmd.md": 2, - "website/docs/user-guide/skills/optional/smart-home/smart-home-openhue.md": 2, - "website/docs/user-guide/skills/optional/software-development/software-development-pr-lens.md": 1, - "website/docs/user-guide/skills/optional/web-development/web-development-har-derived-api-client.md": 2, - "website/docs/user-guide/skills/optional/yuanbao/yuanbao-yuanbao.md": 1, - "website/docs/user-guide/windows-wsl-quickstart.md": 1, + # a tree listing inside a fenced code block; an inline marker would render on the page + "website/docs/getting-started/nix-setup.md": 1, } diff --git a/scripts/generate_conformance_vectors.py b/scripts/generate_conformance_vectors.py index 97228e8333..d1d6fc2830 100644 --- a/scripts/generate_conformance_vectors.py +++ b/scripts/generate_conformance_vectors.py @@ -111,7 +111,7 @@ SCAR: List[tuple] = [ ] ADVERSARIAL: List[tuple] = [ - ("media-tag", "Here you go\nMEDIA:/tmp/output.png\ndone"), + ("media-tag", "Here you go\nMEDIA:/tmp/output.png\ndone"), # no-tmp: ok — fixture string parsed by MEDIA-tag conformance vectors ("unclosed-fence", "```python\nprint('never closed')"), ("pathological-nesting", "**bold *italic ~~struck `code` struck~~ italic* bold**"), ("placeholder-injection", "sneaky \x00PH0\x00 token and \x00SL1\x00 too"), diff --git a/tools/browser_tool.py b/tools/browser_tool.py index 8badf1d927..0dc127717b 100644 --- a/tools/browser_tool.py +++ b/tools/browser_tool.py @@ -354,7 +354,7 @@ def _last_session_key(task_id: str) -> str: def _socket_safe_tmpdir() -> str: """Short temp dir for Unix sockets: macOS ``TMPDIR`` + ``agent-browser-hermes_…`` exceeds the 104-byte AF_UNIX limit (silent screenshot failures), so use /tmp there.""" - return "/tmp" if sys.platform == "darwin" else tempfile.gettempdir() + return "/tmp" if sys.platform == "darwin" else tempfile.gettempdir() # no-tmp: ok — AF_UNIX 104-byte socket path limit on darwin # Active sessions keyed by "session key": the bare task_id, or f"{task_id}::local" diff --git a/tools/code_kernel.py b/tools/code_kernel.py index 2f05a1d07d..5e5008a7be 100644 --- a/tools/code_kernel.py +++ b/tools/code_kernel.py @@ -565,7 +565,7 @@ def _bind_rpc_socket(kernel: SessionKernel) -> str: host, port = server_sock.getsockname()[:2] rpc_endpoint = f"tcp://{host}:{port}" else: - sock_tmpdir = "/tmp" if sys.platform == "darwin" else tempfile.gettempdir() + sock_tmpdir = "/tmp" if sys.platform == "darwin" else tempfile.gettempdir() # no-tmp: ok — AF_UNIX 104-byte socket path limit on darwin rpc_endpoint = kernel.sock_path = os.path.join(sock_tmpdir, f"hermes_rpc_{uuid.uuid4().hex}.sock") server_sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) server_sock.bind(kernel.sock_path) diff --git a/tools/environments/base.py b/tools/environments/base.py index b212ca7c13..f3e3627c6a 100644 --- a/tools/environments/base.py +++ b/tools/environments/base.py @@ -166,7 +166,7 @@ class BaseEnvironment(ABC): def get_temp_dir(self) -> str: """Backend temp directory for session artifacts (``/tmp`` in sandboxes; LocalEnvironment overrides for Termux where only ``TMPDIR`` is writable).""" - return "/tmp" + return "/tmp" # no-tmp: ok — sandbox-side (remote container) temp dir, not the host def __init__(self, cwd: str, timeout: int, env: dict = None): self.cwd = cwd diff --git a/tools/environments/daytona.py b/tools/environments/daytona.py index 06dda008e0..e9c3123f49 100644 --- a/tools/environments/daytona.py +++ b/tools/environments/daytona.py @@ -110,7 +110,7 @@ class DaytonaEnvironment(BaseEnvironment): """Download remote .hermes/ as a tar archive.""" rel_base = f"{self._remote_home}/.hermes".lstrip("/") # PID-suffixed remote temp path avoids collisions if sync_back runs concurrently. - remote_tar = f"/tmp/.hermes_sync.{os.getpid()}.tar" + remote_tar = f"/tmp/.hermes_sync.{os.getpid()}.tar" # no-tmp: ok — remote sandbox path # --exclude: live sockets cannot be archived ("socket ignored") and must not fail the download. self._sandbox.process.exec( f"tar cf {shlex.quote(remote_tar)} --exclude='*.sock' -C / {shlex.quote(rel_base)}") diff --git a/tools/environments/docker.py b/tools/environments/docker.py index 204088ed27..2d53f3e3d9 100644 --- a/tools/environments/docker.py +++ b/tools/environments/docker.py @@ -254,7 +254,7 @@ _BASE_SECURITY_ARGS = [ "--cap-add", "DAC_OVERRIDE", "--cap-add", "CHOWN", "--cap-add", "FOWNER", - "--tmpfs", "/tmp:rw,nosuid,size=512m", + "--tmpfs", "/tmp:rw,nosuid,size=512m", # no-tmp: ok — container tmpfs mount spec "--tmpfs", "/var/tmp:rw,noexec,nosuid,size=256m"] _DEFAULT_PIDS_LIMIT = "256" # applied only when the pids cgroup controller is available diff --git a/tools/environments/vercel_sandbox.py b/tools/environments/vercel_sandbox.py index 06353a186f..4fb361952a 100644 --- a/tools/environments/vercel_sandbox.py +++ b/tools/environments/vercel_sandbox.py @@ -288,7 +288,7 @@ class VercelSandboxEnvironment(BaseEnvironment): def _vercel_bulk_download(self, dest_tar_path: Path) -> None: archive_member = self._remote_hermes_dir().lstrip("/") - remote_tar = f"/tmp/.hermes_sync.{os.getpid()}.tar" + remote_tar = f"/tmp/.hermes_sync.{os.getpid()}.tar" # no-tmp: ok — remote sandbox path sandbox = self._require_sandbox() try: # --exclude: live sockets cannot be archived ("socket ignored") and must not fail the download. diff --git a/tools/self_repo_guard.py b/tools/self_repo_guard.py index 69132d18d5..0b03fe80f2 100644 --- a/tools/self_repo_guard.py +++ b/tools/self_repo_guard.py @@ -560,8 +560,8 @@ def _block_message(operation: str, root: Path) -> str: f"Blocked: `{operation}` would rewrite Hermes's live source checkout " f"({root}) and can mix module versions in this running process. " f"Use a separate worktree or a shared clone on real disk, e.g. " - f"`git clone --shared {root} {scratch}/` — avoid /tmp for " - "clones that install node/python deps: /tmp is usually RAM-backed tmpfs and a few " + f"`git clone --shared {root} {scratch}/` — avoid /tmp for " # no-tmp: ok — guidance telling the model to AVOID /tmp + "clones that install node/python deps: /tmp is usually RAM-backed tmpfs and a few " # no-tmp: ok — guidance telling the model to AVOID /tmp "dependency installs can fill it and ENOSPC other work. Delete the clone when the branch " "is pushed. To change this checkout, stop Hermes, run the command externally, then restart " "Hermes.") diff --git a/tools/skills_guard.py b/tools/skills_guard.py index e83a8f0838..f9ea6a627d 100644 --- a/tools/skills_guard.py +++ b/tools/skills_guard.py @@ -164,8 +164,8 @@ THREAT_PATTERNS = [ # `${SKILL_DIR}/x`") and on flag names such as llama.cpp `--host 127.0.0.1 --port $PORT`. (r'(?\s*/tmp/[^\s]*\s*&&\s*(curl|wget|nc|python)', - "tmp_staging", "critical", "exfiltration", "writes to /tmp then exfiltrates"), + (r'>\s*/tmp/[^\s]*\s*&&\s*(curl|wget|nc|python)', # no-tmp: ok — malicious-pattern regex + "tmp_staging", "critical", "exfiltration", "writes to /tmp then exfiltrates"), # no-tmp: ok — malicious-pattern label # ── Exfiltration: markdown/link based ── (r'!\[.*\]\(https?://[^\)]*\$\{?', "md_image_exfil", "high", "exfiltration", "markdown image URL with variable interpolation (image-based exfil)"),