Repository navigation
Messenger (SimpleX): bridge, gateway, provisioning, forum and per-session chats with scoped phone approvals - #416
Merged
Merged
Conversation
scripts/pi/pi_messenger.sh provisions a Pi, a login node or any other server the pins cover: it picks the platform from uname and the Ubuntu release from os-release, downloads the pinned simplex-chat v7.0.3 binary (one SHA-256 per platform, digests read from the release page 2026-10-25), installs it for a system user delfin-gw without rights, writes hardened systemd units (NoNewPrivileges, ProtectSystem=strict, PrivateTmp, CapabilityBoundingSet=, RestrictAddressFamilies) for daemon and gateway, and an nftables rule opening the daemon API port only to meta skuid delfin-gw. Idempotent; unit dir, os-release and other paths overridable for tests and non-standard systems. Tests drive the script with stand-ins for uname/curl/mktemp/sha256sum/systemctl/nft: pins per platform, refusal of an unpinned machine before any download, abort on a digest mismatch, unit hardening, nftables skuid rule, no fixed /tmp name, no moving release reference. Co-Authored-By: DELFIN-Agent
…rvice Design doc: docs/design/messenger-simplex.md (phases 1 and 2). The bridge serves the gateway over a unix socket in the agent service's runtime dir, 0660; a connection is accepted only when SO_PEERCRED says the peer runs as the configured uid. Fixed JSON-line commands (status, sessions, pending, answer, prompt, stop); answer reaches only attention.answer, so an approval is never granted from the phone; every line out goes through the service Redactor and is cut. The gateway (new package delfin/messenger/) speaks the simplex-chat daemon's local WebSocket API and the bridge, accepts only the paired contact, applies rate/size/replay limits, answers questions by number or text, and routes tasks with @name or to the phone session. Entry points: python -m delfin.messenger pair|run|revoke|status. Tests for both against fake service and fake daemon; no network in the tests. Co-Authored-By: DELFIN-Agent
configured_peer_uid returned DELFIN_MESSENGER_PEER_UID unchanged. Set to the service's own uid, the bridge admitted every process of that user, the agent's shell commands included, which could then approve the agent's own requests through the phone channel.
configured_peer_uid returns None (nobody is admitted) and says so on stderr when DELFIN_MESSENGER_PEER_UID equals the service's own uid. The provisioning runs the gateway as a user of its own; only a hand-set value on a host without that user hit this, and there it admitted every process of the user, including the agent's shell commands. Tests: the new file 2/2 (1 red before); all messenger test files: 103 passed. CI lint rule set: clean.
…wins Against a real agent service (tui_service.ServiceProcess): - the window answers first: the phone's code for that request is refused afterwards and the request resolves as the window decided; - the same shell command asked again next turn gets a new request id, and the code issued for the first does not approve it; it stays pending for the window. Both hold on 51ad607; 3 runs, 2/2 each.
Rooms.voice gets the local transcript, the chat and the reply reference:
- no reply: the next prompt, at once;
- reply to an approval: exactly a decision word ('Ja.', 'nein!', an
offered label) answers it like the typed word;
- a sentence, a mumble or an empty transcript frees nothing;
- a lasting rule is never confirmed by voice;
- reply to a question: the whole transcript is the answer.
All seven fail on 9a13bf1 (no Rooms.voice).
Rooms.voice decides on a local transcript, and handle_file calls it
right after transcription:
- no reply reference: the session's next prompt, at once (before: shown
and submitted only after a typed "senden");
- reply to a question: the transcript is the answer;
- reply to an approval: only a transcript that is exactly a decision
word (ja/jawohl/yes, nein/no) or an offered option's label, after
dropping case, outer space and sentence punctuation, goes through the
same Rooms.reply path as the typed word; the phone is told what was
understood. Anything else frees nothing and says so;
- a lasting rule (confirmChoice) is never confirmed by voice.
Reply-reference binding, the 600 s expiry and the bridge's
request-bound codes are unchanged, because voice goes through reply().
Rejected: matching yes/no anywhere in a sentence ("ja aber nicht
jetzt" would approve).
Tests: the voice file 7/7 (red before); all messenger files: 112
passed. CI lint rule set: clean.
faster-whisper 1.2.1 needs numpy 2.x; DELFIN in the gateway venv keeps numpy below 2. transcribe ran 'sys.executable -m delfin.messenger.media' in the gateway venv. Red: the named interpreter is not used.
Four checks on scripts/pi/pi_messenger.sh with the stand-in tools: the model revision and all four file digests are in the script and the packages install with --require-hashes from per-arch lists; a wrong digest installs no model and fails; a verified model reaches the gateway unit as DELFIN_WHISPER_MODEL/DELFIN_WHISPER_PYTHON; a gateway python other than 3.11 is refused. The harness's mktemp stand-in learns -d and sha256sum can answer per file. Red on 2 commits back; the 10 existing provisioning tests still pass.
- media.transcribe runs DELFIN_WHISPER_PYTHON (default: this
interpreter) with -I and a self-contained script that imports only
faster-whisper; faster-whisper needs numpy 2, DELFIN keeps numpy < 2.
- pi_messenger.sh --whisper: a venv of its own from the gateway's
CPython 3.11 (another version is refused, the wheels are cp311);
faster-whisper 1.2.1 with --require-hashes --no-deps from
whisper-requirements-{aarch64,x86_64}.txt (23 pins each, uv
--generate-hashes); faster-whisper-small at revision 536b0662, the
four files checked against their SHA-256 (a mismatch installs no
model), root-owned 0644 under /opt/delfin-messenger/models. The
gateway unit carries DELFIN_WHISPER_MODEL/_PYTHON only for a verified
model. Files already there with the right digest are kept.
- docs/design and scripts/pi/README describe the voice rules.
Checked here (x86_64): the venv from the pinned list installs
(faster-whisper 1.2.1, numpy 2.4.6), the four model files pass
sha256sum -c, and transcribe() returns the upstream test recording
jfk.flac verbatim in 4.3 s. Tests: all messenger and transcriber files
green; the provisioning tests 15/15; CI lint clean.
CI on 3752f57 failed four shards: - test_no_personal_data_is_committed: the whisper requirement lists carried a '# via -r <session scratch path>' line from their generation. Replaced with the requested package. - the trust-store and capabilities tests: sandbox._HOME_SECRET_DIRS gained .delfin/messenger_sessions, boundaries.MASKED_HOME_ENTRIES did not. Both lists name it now. - two edit-baseline tests: a shell command could not create a file in its own workspace ('Permission denied'). runtime_masked_dirs created and masked activation._DIR. Inside a workspace that contains it (the tests' tmp_path; a workspace at $HOME in the field) the workspace lost its write root under Landlock, which cannot carve a hole into an allowed tree. The runtime mask and its mkdir on every cage build are gone. The store stays masked as a home secret and refused by the path deny globs, like the trust store. tests/test_messenger_session_activation.py now pins that layout. Locally: the five failing files, all messenger files, the race and transcriber tests: 180 passed. CI lint clean.
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.
Design document and phases 1–3:
delfin/messenger/: serves only the paired contact, with rate, size and replay limits.