feat(molecule_agent): add strip_a2a_boundary() for OFFSEC-003 trust-boundary markers
Some checks failed
Test / test (3.11) (pull_request) Failing after 2s
Test / test (3.12) (pull_request) Failing after 1s
Test / test (3.13) (pull_request) Failing after 1s

Platform now wraps peer A2A responses in [A2A_RESULT_FROM_PEER]...
[/A2A_RESULT_FROM_PEER] markers (OFFSEC-003) to mark them as untrusted
third-party content. This change adds:

- strip_a2a_boundary(text): strips the wrapper and returns the interior
  content. Safe on pre-OFFSEC-003 responses (returns input unchanged when
  markers absent or malformed) and on None/empty.

Exported from molecule_agent/__init__.py and added to __all__.

README updated with a dedicated OFFSEC-003 section and call_peer() table
note pointing to strip_a2a_boundary().

8 new tests: basic, whitespace edges, no-markers passthrough, only-start,
only-end, empty/None, end-before-start edge case, multiline content.
305 total tests pass.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Molecule AI · sdk-dev 2026-05-10 16:17:21 +00:00
parent 00ad231320
commit 99bb64ddf3
4 changed files with 111 additions and 2 deletions

View File

@ -72,7 +72,7 @@ A runnable demo with full setup walkthrough lives at
| `poll_state()` | 30.4 | Lightweight `{status, paused, deleted}` poll |
| `heartbeat(...)` | 30.1 | Single bearer-authed heartbeat |
| `get_peers()` / `discover_peer()` | 30.6 | Sibling URL discovery with TTL cache |
| `call_peer(target, message)` | 30.6 | Direct A2A with proxy fallback |
| `call_peer(target, message)` | 30.6 | Direct A2A with proxy fallback; response may be wrapped in OFFSEC-003 boundary markers — use ``strip_a2a_boundary()`` to remove them |
| `fetch_inbound(since_id=…)` | 30.8c | One-shot poll of `/workspaces/:id/activity` for inbound A2A |
| `reply(msg, text)` | 30.8c | Smart-routes reply to `/notify` (canvas user) or `/a2a` (peer) |
| `run_heartbeat_loop()` | combo | Drives heartbeat + state-poll on a timer; exits on pause/delete |
@ -165,6 +165,27 @@ silent acks. On non-2xx the underlying `requests.HTTPError` propagates so the
handler can decide whether to retry, surface to its observability, or fail
loudly.
### OFFSEC-003 — A2A peer response trust boundary
As of the OFFSEC-003 platform rollout, peer A2A responses are wrapped in
trust-boundary markers before being returned to callers::
[A2A_RESULT_FROM_PEER]<peer response text>[/A2A_RESULT_FROM_PEER]
The markers signal that the enclosed content is untrusted third-party output.
Use ``strip_a2a_boundary()`` to remove them before passing the response to
your agent context::
from molecule_agent import RemoteAgentClient, strip_a2a_boundary
result = client.call_peer(target_id, "do the thing")
raw_text = result.get("result", {}).get("text", "")
trusted_text = strip_a2a_boundary(raw_text)
The function returns the input unchanged if the markers are absent (platform
versions older than the OFFSEC-003 rollout), so it is safe to call on any
response.
## CLI: `molecule_agent connect`
One command bootstraps the full poll-mode loop. No code beyond your handler:

View File

@ -39,6 +39,7 @@ from .client import (
PeerInfo,
RemoteAgentClient,
WorkspaceState,
strip_a2a_boundary,
verify_plugin_sha256,
)
from .inbound import (
@ -71,6 +72,7 @@ __all__ = [
"DEFAULT_POLL_INTERVAL",
"compute_plugin_sha256",
"verify_plugin_sha256",
"strip_a2a_boundary",
"__version__",
]
__version__ = "0.1.0"

View File

@ -90,6 +90,43 @@ def make_idempotency_key(task_text: str) -> str:
return hashlib.sha256(payload.encode("utf-8")).hexdigest()
# ── A2A boundary marker stripping (OFFSEC-003) ───────────────────────────────
_A2A_BOUNDARY_START = "[A2A_RESULT_FROM_PEER]"
_A2A_BOUNDARY_END = "[/A2A_RESULT_FROM_PEER]"
def strip_a2a_boundary(text: str) -> str:
"""Strip OFFSEC-003 trust-boundary markers from a peer A2A response.
The platform wraps peer A2A responses in::
[A2A_RESULT_FROM_PEER]<content>[/A2A_RESULT_FROM_PEER]
to mark them as untrusted third-party content. Call this helper to
remove the wrapper before passing the content to your agent context:
Usage::
result = client.call_peer(target_id, "do the thing")
text = result.get("result", {}).get("text", "")
content = strip_a2a_boundary(text)
Returns the interior content (everything between the two markers).
Returns the input unchanged if the boundary markers are absent (the caller
may be talking to a platform version older than the OFFSEC-003 rollout).
Returns ``""`` for ``None`` or empty input.
"""
if not text:
return ""
start = text.find(_A2A_BOUNDARY_START)
end = text.find(_A2A_BOUNDARY_END)
if start != -1 and end != -1 and end > start:
return text[start + len(_A2A_BOUNDARY_START):end].strip()
return text
def _safe_extract_tar(tf: tarfile.TarFile, dest: Path) -> None:
"""Extract a tarfile, refusing entries that would escape `dest`
and logging skipped symlinks/hardlinks.

View File

@ -709,7 +709,7 @@ def test_install_plugin_404_raises_with_useful_url(client: RemoteAgentClient):
import hashlib
from molecule_agent.client import make_idempotency_key
from molecule_agent.client import make_idempotency_key, strip_a2a_boundary
def test_delegate_posts_task_and_idempotency_key(client: RemoteAgentClient):
@ -883,6 +883,55 @@ def test_make_idempotency_key_deterministic():
assert a == b
# ---------------------------------------------------------------------------
# strip_a2a_boundary — OFFSEC-003 trust-boundary marker stripping
# ---------------------------------------------------------------------------
def test_strip_a2a_boundary_basic():
"""Interior text between the two markers is returned."""
wrapped = "[A2A_RESULT_FROM_PEER]hello world[/A2A_RESULT_FROM_PEER]"
assert strip_a2a_boundary(wrapped) == "hello world"
def test_strip_a2a_boundary_strips_whitespace_edges():
"""Trailing/leading whitespace inside the boundary is stripped."""
wrapped = "[A2A_RESULT_FROM_PEER] peer reply [/A2A_RESULT_FROM_PEER]"
assert strip_a2a_boundary(wrapped) == "peer reply"
def test_strip_a2a_boundary_no_markers_returns_unchanged():
"""Without both markers present the input passes through unchanged."""
assert strip_a2a_boundary("plain text with no markers") == "plain text with no markers"
def test_strip_a2a_boundary_only_start_returns_unchanged():
"""Only a start marker — no-op to stay safe during mid-rollout."""
assert strip_a2a_boundary("[A2A_RESULT_FROM_PEER]unclosed") == "[A2A_RESULT_FROM_PEER]unclosed"
def test_strip_a2a_boundary_only_end_returns_unchanged():
"""Only an end marker — no-op."""
assert strip_a2a_boundary("[/A2A_RESULT_FROM_PEER]no start") == "[/A2A_RESULT_FROM_PEER]no start"
def test_strip_a2a_boundary_empty_returns_empty():
assert strip_a2a_boundary("") == ""
assert strip_a2a_boundary(None) == "" # type: ignore[arg-type]
def test_strip_a2a_boundary_end_before_start_returns_unchanged():
"""If end marker appears before start, treat as no-op."""
text = "[/A2A_RESULT_FROM_PEER]X[A2A_RESULT_FROM_PEER]"
assert strip_a2a_boundary(text) == text
def test_strip_a2a_boundary_multiline_content():
"""Multiline interior content is preserved (stripped at edges only)."""
wrapped = "[A2A_RESULT_FROM_PEER]\n step one\n step two\n[/A2A_RESULT_FROM_PEER]"
assert strip_a2a_boundary(wrapped) == "step one\n step two"
# ---------------------------------------------------------------------------
# _safe_extract_tar
# ---------------------------------------------------------------------------