feat(a2a): expose inbound message metadata to sessions - #3
Open
RuniThomsen wants to merge 3 commits into
Open
RuniThomsen wants to merge 3 commits into
RuniThomsen wants to merge 3 commits into
Conversation
Reviewed once and verified 111/111. Makes the 900-second Hermes-seat reply deadline and matching orphan watchdog config-native.
Co-Authored-By: Claude <noreply@anthropic.com>
RuniThomsen
pushed a commit
that referenced
this pull request
Sep 24, 2026
… fingerprint never authorizes a signal NousResearch#111617 review (andrexibiza P1 #3/#4, kvnloo nit): - worker_started_at persisted only gateway.status.get_process_start_time(): on Linux that is /proc/<pid>/stat field 22, clock ticks since THIS boot. The threat is a row surviving a reboot, and that counter does not, so an unrelated process on a later boot with the same PID and the same tick value passed _start_times_agree(). The fingerprint is now "<gateway.drain_control.current_instantiation_epoch()>|<start>" (boot_id + PID-1 start, the witness the drain marker already uses); both halves must match. Integer values on rows written before this change keep the start-time-only comparison. - A failed capture persisted NULL, which _pid_recycled treats as the legacy pre-fingerprint row and falls back to bare PID existence - a new spawn silently recreated the NousResearch#89614/ NousResearch#99558 kill authority. A failed capture now persists UNVERIFIED_WORKER_FINGERPRINT: the claim is held while the PID is live (never released beside it, never SIGTERM/SIGKILLed by timeout, stale-claim, manual reclaim, archive or the terminal reaper) and reclaimed once it is gone. NULL stays legacy-only. - Every tasks UPDATE that nulls worker_pid nulls worker_started_at too (archive_task and the reclaim/timeout/reopen paths): the fingerprint is part of the kill-authority tuple and must not outlive its pid. Live (real sleeper child): reboot-shaped row (same pid, same tick, other boot id) -> reclaimed to ready, child untouched; matching fingerprint -> SIGTERM delivered, exit -15. tests/hermes_cli/test_kanban_worker_pid_fingerprint.py: +2 hostile tests, both red on base. Not changed: the check-then-act window between _pid_recycled and kill (kvnloo P2) is real but needs pidfd_open/pidfd_send_signal (Linux 5.3+) to close atomically; left as the documented residual of "never kills a DETECTED recycled PID".
RuniThomsen
pushed a commit
that referenced
this pull request
Sep 24, 2026
Adopts the DNS-rebinding-pinned transport hardening (repo issues #2/#3, PR #3) and the starter-feed/settings failure-surfacing + SSRF-gated icon proxy fix (issue #6, PR #8). Full range in tony-simons-aiowa/hermes-newswire deccdc4..e6b438e (13 commits): Security-relevant highlights: - All outbound fetches (feeds, redirects, icons) now go through a pinned transport: the SSRF gate's validated address set is bound to the actual connection — no second DNS lookup, so DNS rebinding/TOCTOU has no window; the plugin fails closed if the pin seam changes. - New GET /icon.json proxies favicons through the same gate and returns base64 data URLs — the renderer's <img> no longer performs unpinned DNS resolutions of feed-controlled hostnames. 64 KB cap enforced mid-transfer; image content-type allowlist; bounded, normalized TTL cache. - Renderer surfaces backend failures (settings/sources banners, starter-feed inline errors) instead of silent no-ops. Capabilities unchanged (all empty — dashboard plugin, no tools/hooks/ env). Verification at the new pin: 129 pytest, 33 renderer interaction checks, 26 ESM render smoke, hermes plugins validate clean.
RuniThomsen
pushed a commit
that referenced
this pull request
Sep 24, 2026
…rametrize
test_cmd_gc_negative_days_leaves_workspaces_untouched and
test_cmd_gc_retention_bounds[negative-refuses] killed the same mutant
(the _cmd_gc guard turned into `if False`) and differed only in which
fixture they asserted survived. Create the archived scratch workspace in
the parametrized body (small helper) and assert on it alongside the
event/log checks; drop the standalone test.
WHY: one invariant, one test. The ordering claim ("refuse before ANY
sweep" — the unconditional workspace sweep runs first in _cmd_gc) is
still proven by the negative case; the 0/positive cases now also confirm
that valid values let the workspace sweep run. The file goes from 6 to 5
test functions with no lost mutation coverage.
Finding: simplify/D.quality.md #3
(tests/hermes_cli/test_kanban_gc_retention.py:82-97).
Proof: with the _cmd_gc guard mutated to `if False`,
test_cmd_gc_retention_bounds[negative-refuses] fails (1 failed, 7
passed); head is green (8 passed).
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
https://runi.services/a2a/ext/task/v1extension in the A2A Agent CardMessage.metadatagenerically beside message Parts in the receiving Hermes sessionVerification
scripts/run_tests.sh tests/plugins/test_a2a_plugin.py tests/plugins/test_a2a_phase23.py— 154 passedpython -m pytest tests/plugins/test_a2a_plugin.py::TestInboundRoundTrip::test_live_server_passes_message_metadata_into_agent_session -m integration -q— 1 passedgit diff --check— passedScope
This does not interpret extension keys or add a Runi-specific adapter path. Any JSON-object
Message.metadatais serialized next to the Parts and passes through the same inbound safety frame. Outbound metadata remains covered separately by NousResearch#90396.