chore: mark the deliberate /tmp literals and shrink the lint baseline to one code block
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 — <why>` so the reason lives next to the line; the baseline keeps only a fenced tree listing where a marker would render.
This commit is contained in:
@@ -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])
|
||||
|
||||
|
||||
|
||||
@@ -364,7 +364,7 @@ def _query_codex_plugins(
|
||||
|
||||
|
||||
# pytest tempdir shapes: ``pytest-of-<user>/pytest-<n>/``, 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:
|
||||
|
||||
@@ -3117,7 +3117,7 @@ def _temp_home_in_service_definition(definition: str) -> str | None:
|
||||
candidates += re.findall(r"<key>HERMES_HOME</key>\s*<string>(.*?)</string>", 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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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.
|
||||
<!-- no-tmp: ok — documents the legacy scratch scope this plugin cleans up -->
|
||||
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
|
||||
|
||||
<!-- no-tmp: ok — documents the legacy scratch scope this plugin cleans up -->
|
||||
- `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
|
||||
|
||||
@@ -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.
|
||||
"""
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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"),
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)}")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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}/<task>` — avoid /tmp for "
|
||||
"clones that install node/python deps: /tmp is usually RAM-backed tmpfs and a few "
|
||||
f"`git clone --shared {root} {scratch}/<task>` — 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.")
|
||||
|
||||
@@ -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'(?<![-/])\b(dig|nslookup|host)\s+(?:[-+@]\S*(?:\s+[^\s$"\'-][^\s$]*)?\s+)*["\']?[^\s"\'$]*\$',
|
||||
"dns_exfil", "critical", "exfiltration", "DNS lookup with variable interpolation (possible DNS exfiltration)"),
|
||||
(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)"),
|
||||
|
||||
Reference in New Issue
Block a user