mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-04 17:57:28 +08:00
fix(kanban): close the two v2-flagged issues in v1
Both items the atypical-scenarios pass flagged as "v2 follow-up"
actually belong in v1. Fixed now.
Fix 1: workspace path traversal
resolve_workspace now rejects non-absolute paths for all three
workspace_kinds (scratch-with-explicit-path, dir:, worktree). A
relative path like '../../../tmp/attacker' was being silently
resolved against the dispatcher's CWD — a confused-deputy escape.
Error message points users at the absolute-path requirement.
Storage remains verbatim (kernel doesn't rewrite user input);
the refusal happens at resolution time, so the dispatcher's
existing spawn-failure circuit breaker correctly categorizes it.
Threat model documented in website/docs/user-guide/features/kanban.md:
single-host, trusted-local-user. The absolute-path rule prevents
ambiguity-driven escape, not malicious access — kanban runs as you,
with your uid, on your filesystem.
Fix 2: build_worker_context unbounded
Added per-section caps so worker prompts stay bounded on pathological
boards:
_CTX_MAX_PRIOR_ATTEMPTS = 10 most-recent N runs shown; older
collapsed into "N earlier attempts
omitted" marker. Attempt numbering
preserved (shows "Attempt 16" not
renumbered).
_CTX_MAX_COMMENTS = 30 same pattern for comments.
_CTX_MAX_FIELD_BYTES = 4 KB per summary / error / metadata / result.
_CTX_MAX_BODY_BYTES = 8 KB per task.body (opening post).
_CTX_MAX_COMMENT_BYTES = 2 KB per comment.
Truncation uses a visible ellipsis + char-count so the worker knows
it's been truncated.
Effect on atypical-scenario runs:
huge_run_count_on_one_task (1000 runs): 63 KB → 820 chars
comment_storm (1000 comments): 50 KB → 1,671 chars
Tests (+6 in main suite)
test_resolve_workspace_rejects_relative_dir_path — relative dir:
path stored verbatim but refused at resolve.
test_resolve_workspace_accepts_absolute_dir_path — legitimate
absolute paths are created and returned.
test_resolve_workspace_rejects_relative_worktree_path — same guard
for worktree kind.
test_build_worker_context_caps_prior_attempts — 25 runs → exactly
_CTX_MAX_PRIOR_ATTEMPTS shown, omitted marker present,
attempt numbering preserves original index.
test_build_worker_context_caps_comments — 100 comments → 30 shown,
70 in the omitted marker.
test_build_worker_context_caps_huge_summary — 1 MB summary on a
prior run → context under 10 KB total, truncation marker visible.
189/189 kanban suite pass. Atypical-scenarios stress script still
passes all 28 scenarios with the new caps in effect.
This commit is contained in:
@@ -50,8 +50,8 @@ They coexist: a kanban worker may call `delegate_task` internally during its run
|
||||
- **Comment** — the inter-agent protocol. Agents and humans append comments; when a worker is (re-)spawned it reads the full comment thread as part of its context.
|
||||
- **Workspace** — the directory a worker operates in. Three kinds:
|
||||
- `scratch` (default) — fresh tmp dir under `~/.hermes/kanban/workspaces/<id>/`.
|
||||
- `dir:<path>` — an existing shared directory (Obsidian vault, mail ops dir, per-account folder).
|
||||
- `worktree` — a git worktree under `.worktrees/<id>/` for coding tasks.
|
||||
- `dir:<path>` — an existing shared directory (Obsidian vault, mail ops dir, per-account folder). **Must be an absolute path.** Relative paths like `dir:../tenants/foo/` are rejected at dispatch because they'd resolve against whatever CWD the dispatcher happens to be in, which is ambiguous and a confused-deputy escape vector. The path is otherwise trusted — it's your box, your filesystem, the worker runs with your uid. This is the trusted-local-user threat model; kanban is single-host by design.
|
||||
- `worktree` — a git worktree under `.worktrees/<id>/` for coding tasks. Worker-side `git worktree add` creates it.
|
||||
- **Dispatcher** — a long-lived loop that, every N seconds (default 60): reclaims stale claims, reclaims crashed workers (PID gone but TTL not yet expired), promotes ready tasks, atomically claims, spawns assigned profiles. Runs as `hermes kanban daemon` (foreground) or as a systemd user service. After ~5 consecutive spawn failures on the same task the dispatcher auto-blocks it with the last error as the reason — prevents thrashing on tasks whose profile doesn't exist, workspace can't mount, etc.
|
||||
- **Tenant** — optional string namespace. One specialist fleet can serve multiple businesses (`--tenant business-a`) with data isolation by workspace path and memory key prefix.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user