Skip to content

fix: validate agent_id before agent-runtime namespace concat (CLI + MCP)#491

Merged
memtomem merged 2 commits intomainfrom
feat/validate-agent-id-486
Apr 26, 2026
Merged

fix: validate agent_id before agent-runtime namespace concat (CLI + MCP)#491
memtomem merged 2 commits intomainfrom
feat/validate-agent-id-486

Conversation

@pandas-studio
Copy link
Copy Markdown
Collaborator

Summary

  • Add validate_agent_id in constants.py (thin wrapper around validate_name(value, kind="agent-id")).
  • Wire it into all three entry points that concatenate AGENT_NAMESPACE_PREFIX with caller input: mem_session_start (MCP), mm session start, and mm session wrap (CLI).
  • Pin the wiring + the regression contract in test_validate_agent_id: "agent-runtime:foo:bar" cannot reach storage from either surface.

Why

PR #485 review (item 2) flagged that f"{AGENT_NAMESPACE_PREFIX}{agent_id}" does no input validation. Hostile-shaped values (foo:bar, ../x, spaces, control chars) round-trip into storage as malformed namespace strings. The CLI mirrored the gap from the MCP path so a single-surface fix would leave the other open.

Single boundary, single charset, single error message: [A-Za-z0-9._-] (1–64 chars, no leading dash, not "." / ".."). MCP path raises an InvalidNameError (a ValueError subclass) which tool_handler formats as "Error: invalid agent-id 'foo:bar': ..."; CLI path converts the same exception to a ClickException with the identical core text.

mm session wrap validates before the wrapped subprocess runs so an invalid agent_id never leaves a half-set .current_session file or a rogue child.

Out of scope

  • Renaming or migrating any agent_ids users may have already stored — this is a forward gate only.
  • Tightening mem_agent_register / mem_agent_search (which still sanitize_namespace_segment rather than validate_*); the issue scopes this PR to the session-start surfaces, and changing the multi_agent tools' silently-mutating behavior is a separate UX call.

Test plan

  • uv run pytest -m "not ollama" — 2554 passed, 46 deselected (ollama).
  • uv run ruff check + ruff format --check on src/ and tests/ — clean.
  • New test_validate_agent_id:
    • charset acceptance + 13 hostile-input rejections at the validator
    • MCP boundary: mem_session_start(agent_id="foo:bar") returns "Error: invalid agent-id ..." and storage stays empty
    • CLI boundary: mm session start --agent-id "foo:bar" exits non-zero, storage mock confirms create_session was never called
    • mm session wrap rejects before the wrapped command can run
    • cross-surface parity: both surfaces produce the same "invalid agent-id 'foo:bar'" core text

Closes #486.

🤖 Generated with Claude Code

pandas-studio and others added 2 commits April 26, 2026 13:22
Without a gate, hostile-shaped values like ``foo:bar`` or ``../x``
concatenate into ``AGENT_NAMESPACE_PREFIX`` and round-trip into storage
as malformed namespace strings (``"agent-runtime:foo:bar"``). The CLI
side mirrored the gap from the MCP path so fixing only one surface
would leave the other open.

Add ``validate_agent_id`` in ``constants.py`` (a thin wrapper around
``validate_name`` from ``context/_names.py`` with ``kind="agent-id"``)
and apply it at the three entry points that build the namespace —
``mem_session_start`` (MCP), ``mm session start``, and
``mm session wrap`` (CLI). All three reject the same set (``:``, ``/``,
``..``, whitespace, control chars, and anything outside
``[A-Za-z0-9._-]``) with the same identifying error text; ``mm session
wrap`` fails before the wrapped subprocess runs so an invalid id never
leaves a half-set state file.

Charset coverage stays in ``test_context_names``; new
``test_validate_agent_id`` pins the wiring at both surfaces and the
regression contract: ``"agent-runtime:foo:bar"`` cannot reach storage
from either entry point.

Closes #486.

Co-Authored-By: Claude <[email protected]>
Three small follow-ups from the PR #491 review:

* ``validate_agent_id`` docstring previously claimed to gate "every
  boundary that concatenates AGENT_NAMESPACE_PREFIX". That overstated
  the scope — the LangGraph adapter's ``start_agent_session`` and
  ``MemtomemCheckpointer.namespace_for`` plus
  ``mem_agent_register`` / ``mem_agent_search`` still use the unvalidated
  / sanitize-instead-of-reject pattern. Narrow the docstring to the
  three surfaces actually wired in this PR and call out the deferred
  surfaces so future readers don't read the validator as load-bearing
  where it isn't. Follow-up parity work tracked separately.

* ``HOSTILE_AGENT_IDS`` had a literal U+200B in source. Switched to the
  ``​`` escape so the test reads as intentional rather than as an
  editor artifact a future grep might "fix".

* ``test_session_wrap_rejects_colon_before_subprocess`` only pinned the
  storage side of the contract — its docstring claims subprocess never
  runs, but it relied on storage_mock to catch the regression. Now
  patches ``subprocess.run`` directly with a MagicMock and asserts
  ``run_mock.assert_not_called()`` so the test matches its claim.

Co-Authored-By: Claude <[email protected]>
@pandas-studio
Copy link
Copy Markdown
Collaborator Author

Review fixes pushed in eaa9d3d:

  • Narrowed validate_agent_id docstring to the three surfaces actually wired in this PR + an explicit "Not yet applied at" list (LangGraph adapter, mem_agent_register / mem_agent_search).
  • Replaced literal U+200B in HOSTILE_AGENT_IDS with escape so the test reads as intentional.
  • test_session_wrap_rejects_colon_before_subprocess now patches subprocess.run directly and asserts run_mock.assert_not_called() — pins the contract its docstring claimed.

Concern 5 (_StubCtx consolidation into conftest.py) deferred per "fine for now."

Follow-up issues filed per the verdict:

@memtomem memtomem merged commit 6b1ec5c into main Apr 26, 2026
7 checks passed
@github-actions github-actions Bot locked and limited conversation to collaborators Apr 26, 2026
@memtomem memtomem deleted the feat/validate-agent-id-486 branch April 27, 2026 14:56
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Validate agent_id before agent-runtime namespace concatenation (CLI + MCP)

2 participants