feat(telegram): add secure Hermes Telegram-to-Firstmate bridge#972
Closed
AngelDIvanov wants to merge 7 commits into
Closed
feat(telegram): add secure Hermes Telegram-to-Firstmate bridge#972AngelDIvanov wants to merge 7 commits into
AngelDIvanov wants to merge 7 commits into
Conversation
4 tasks
Owner
|
Automated reminder: thanks for the PR! This branch currently has a merge conflict with the base branch. When you get a chance, please rebase onto (or merge) the latest base branch, resolve the conflict, and push. After that, checks will re-run and the PR will get looked at again. Noted for firstmate#972 at |
Author
|
Closing this for now while I tighten the publication approval flow. Thanks for the review. |
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.
Intent
Implement, test, document, and commit a secure repo-owned Hermes Telegram-to-Firstmate bridge using explicit /firstmate text and voice commands, authenticated private intake, durable correlation and deduplication, normal Firstmate wake, spawn, and follow-up lifecycle, safe Telegram replies, idempotent lifecycle commands, and real lifecycle validation exclusively through the named-session fm-herdr-lab.sh helper without touching Herdr's default session. Push and open a PR, but do not merge.
What Changed
bin/fm-telegram-bridge.pyplusfm-telegram-*wrapper scripts and theintegrations/hermes/firstmate-telegramplugin) that authenticates private/firstmatetext and voice intake, enforces the command boundary and a 120s timestamp window, durably records inbox/context state undertelegram-inbox/telegram-outbox, and drives the normal Firstmate wake/spawn/follow-up lifecycle with idempotent lifecycle commands and credential-shaped reply guarding.ingestof the same signedrequest_idno longer unlinks the inbox record when the reply context already exists, preventing silent loss of an authenticated request; also fix dedup to allow re-signed replays and resolve the SC2181 lint in the test.tests/fm-telegram-bridge.test.sh) and a named-session Herdr end-to-end test (tests/fm-telegram-herdr-e2e.test.sh), plus thetelegram-respondskill and docs (docs/telegram-bridge.md, scripts/configuration references, README index, and the AGENTS.md state inventory).Risk Assessment
✅ Low: The only change since the prior review is a surgical, well-targeted fix for the previously-flagged concurrent-duplicate intake race, backed by a deterministic regression test that proves exactly one inbox and one context survive; no new issues were introduced and the rest of the additive, opt-in subsystem is unchanged.
Testing
Ran both bridge test suites and a manual end-user demonstration. The focused fake-transport suite (17 checks covering authenticated intake, dedup, fail-closed rejection, idempotent replies/lifecycle, and secret non-leakage) and the real Herdr lifecycle e2e (intake→normal spawn in a generated fm-lab-* session→correlated single final reply→guarded teardown that preserved the default session) both pass against real herdr/treehouse binaries. I additionally captured a reviewer-visible CLI transcript exercising the real bridge code that shows the actual Telegram chat experience: an authorized captain's /firstmate command returns "Firstmate accepted your request." and a correlated final result to the same chat/topic, while unauthorized and credential-shaped traffic fail closed with nothing delivered. No screenshot applies — this is a Telegram-transport/CLI feature with no rendered UI surface, so the delivered-message transcript is the end-user artifact. Working tree left clean with no leaked sessions or state.
Evidence: End-user Telegram chat experience (authorized ack+result, unauthorized fail-closed, credential refusal)
Evidence: Real Herdr lifecycle e2e transcript
Evidence: Delivered Telegram messages (excerpt from real bridge + fake transport)
Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
🔧 **Review** - 2 issues found → auto-fixed ✅
bin/fm-telegram-bridge.py:396- command_ingest can silently drop a valid signed request under concurrent duplicate intake. Sequence: ingest A writes the inbox record (exclusive) at line 390, then a concurrent ingest B of the same request_id passes the top-of-function context check (366) and the inbox-exists branch (373), and publishes the context (377). A then reaches line 394, its exclusive context write fails with FileExistsError -> _atomic_write returns False -> raises 'Telegram reply context already exists', and the except block at 396-401 unlinks the inbox. Net result: the context exists but the inbox record is gone, so command_poll (which iterates telegram-inbox) never offers the request and the authenticated request is lost with no error surfaced to the sender. The rest of the module is carefully hardened against exactly these interleavings, so this cleanup path is the one gap: it should not unlink the inbox when the context now exists and its replay material matches the same request (a benign concurrent duplicate), only when the context write genuinely failed.bin/fm-telegram-bridge.py:62- _now() honors the FM_TELEGRAM_NOW_OVERRIDE environment variable in the production code path (not gated to tests), so the 120s intake timestamp window and the 7-day retention window can be shifted by anyone able to set that env var on the ingest/reply process. This only matters to an actor who already controls the local process environment (already inside the trust boundary), and mirrors the repo's existing test-clock conventions, so it is a low-risk observation rather than an exploitable flaw.🔧 Fix: fix telegram bridge concurrent duplicate intake inbox loss
✅ Re-checked - no issues remain.
✅ **Test** - passed
✅ No issues found.
bash tests/fm-telegram-bridge.test.sh— 17 fake-transport contract checks, all passbash tests/fm-telegram-herdr-e2e.test.sh— real Herdr lifecycle (intake→spawn in fm-lab session→correlated final reply→guarded teardown), all pass with herdr 0.7.5 + treehouse presentManual end-user demonstration through realfm-telegram-bridge.pywith a fake Hermes transport rendering delivered Telegram messages: authorized /firstmate ack + correlated final reply, unauthorized-sender fail-closed, credential-shaped reply refusedVerified clean teardown: no fm-lab/herdr/default tmux sessions or /tmp/fm-lab-* sockets remained;git statusclean✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.