Skip to content

[codex] Align INTERCOM with HiveMind-core#106

Closed
goldyfruit wants to merge 1 commit into
devfrom
codex/align-intercom-with-core
Closed

[codex] Align INTERCOM with HiveMind-core#106
goldyfruit wants to merge 1 commit into
devfrom
codex/align-intercom-with-core

Conversation

@goldyfruit
Copy link
Copy Markdown
Contributor

@goldyfruit goldyfruit commented Mar 30, 2026

What changed

This PR aligns websocket INTERCOM send and receive behavior with current HiveMind-core.

Why

HiveMind-core currently expects an RSA ciphertext/signature envelope for INTERCOM, while the websocket client had drifted to a different envelope shape and also routed wrapped INTERCOM frames incorrectly in BROADCAST, PROPAGATE, and QUERY handlers.

Impact

Direct encrypted messages use the same envelope shape as HiveMind-core and the client now dispatches decrypted inner hive messages consistently. The receive path remains backward-compatible with the older hybrid envelope format.

Validation

  • python -m unittest test.unittests.test_protocol_intercom
  • python -m unittest test.unittests.test_client

Summary by CodeRabbit

Release Notes

  • New Features

    • Updated INTERCOM message encryption to use RSA-based envelope format with improved compatibility.
    • Added support for both legacy and new encryption formats to ensure backward compatibility.
  • Tests

    • Added comprehensive test coverage for INTERCOM message encryption and decryption workflows.
    • Added regression tests for message routing through broadcast, propagate, and query handlers.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Mar 30, 2026

The automated sentinels have completed their watch. 💂‍♂️

I've aggregated the results of the automated checks for this PR below.

📋 Repo Health

I've checked the repo's hydration (aka documentation density). 💧

⚠️ Some required files are missing.

Latest Version: 0.6.0a1

hivemind_bus_client/version.py — Version file
README.md — README
LICENSE — License file
pyproject.toml — pyproject.toml
setup.py — setup.py
CHANGELOG.md — Changelog
requirements.txt — Requirements
hivemind_bus_client/version.py has valid version block markers

🔍 Lint

Analysis complete! Check out the details below. 📊

ruff: issues found — see job log

🏷️ Release Preview

I've checked the 'Platform Support' matrix. 💻

Current: 0.6.0a1Next: 0.6.0a2

Signal Value
Label (none)
PR title [codex] Align INTERCOM with HiveMind-core
Bump alpha

⚠️ No conventional commit prefix — alpha-only bump.
Suggested: fix: update the thing or feat: update the thing


🚀 Release Channel Compatibility

Predicted next version: 0.6.0a2

Channel Status Note Current Constraint
Stable Not in channel -
Testing Compatible hivemind-bus-client>=0.4.4,<1.0.0
Alpha Compatible hivemind-bus-client>=0.6.0a1

🔒 Security (pip-audit)

I've checked the security of our API endpoints. 🌐

✅ No known vulnerabilities found (61 packages scanned).

⚖️ License Check

Ensuring no unlicensed code has snuck in. 🕵️

✅ No license violations found (43 packages).

License distribution: 12× MIT License, 6× Apache Software License, 6× MIT, 4× Apache-2.0, 3× BSD-3-Clause, 2× ISC License (ISCL), 2× PSF-2.0, 1× Apache Software License; BSD License, +7 more

Full breakdown — 43 packages
Package Version License URL
bitarray 3.8.0 PSF-2.0 link
bitstring 4.4.0 MIT License link
build 1.4.2 MIT link
certifi 2026.2.25 Mozilla Public License 2.0 (MPL 2.0) link
cffi 2.0.0 MIT link
charset-normalizer 3.4.6 MIT link
click 8.3.1 BSD-3-Clause link
combo_lock 0.3.0 Apache Software License link
cryptography 46.0.6 Apache-2.0 OR BSD-3-Clause link
filelock 3.25.2 MIT link
hivemind_bus_client 0.6.0a1 Apache Software License link
idna 3.11 BSD-3-Clause link
json-database 0.10.1 MIT link
kthread 0.2.3 MIT License link
markdown-it-py 4.0.0 MIT License link
mdurl 0.1.2 MIT License link
memory-tempfile 2.2.3 MIT License link
ovos-config 2.1.1 Apache-2.0 link
ovos-utils 0.8.5 Apache-2.0 link
ovos_bus_client 1.5.0 Apache Software License link
packaging 26.0 Apache-2.0 OR BSD-2-Clause link
pexpect 4.9.0 ISC License (ISCL) link
poorman-handshake 1.0.1 Apache-2.0 link
ptyprocess 0.7.0 ISC License (ISCL) link
py-cpuinfo 9.0.0 MIT License link
pybase64 1.4.3 BSD License link
pycparser 3.0 BSD-3-Clause link
pycryptodomex 3.23.0 BSD License; Public Domain link
pyee 12.1.1 MIT License link
Pygments 2.20.0 BSD-2-Clause link
pyproject_hooks 1.2.0 MIT License link
python-dateutil 2.9.0.post0 Apache Software License; BSD License link
PyYAML 6.0.3 MIT License link
requests 2.33.0 Apache Software License link
rich 13.9.4 MIT License link
rich-click 1.9.7 MIT License

Copyright (c) 2022 Phil Ewels

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
| link |
| six | 1.17.0 | MIT License | link |
| tibs | 0.5.7 | MIT License | link |
| typing_extensions | 4.15.0 | PSF-2.0 | link |
| urllib3 | 2.6.3 | MIT | link |
| watchdog | 6.0.0 | Apache Software License | link |
| websocket-client | 1.9.0 | Apache Software License | link |
| z85base91 | 0.0.5 | Apache-2.0 | link |

Policy: Apache 2.0 (universal donor). StrongCopyleft / NetworkCopyleft / WeakCopyleft / Other / Error categories fail. MPL allowed.

📊 Coverage

I've mapped out the test coverage for you! 🗺️

57.4% total coverage

⚠️ Some tests failed — coverage figures may be incomplete.

Files below 80% coverage (6 files)
File Coverage Missing lines
hivemind_bus_client/http_client.py 0.0% 308
hivemind_bus_client/scripts.py 0.0% 215
hivemind_bus_client/version.py 0.0% 5
hivemind_bus_client/protocol.py 50.0% 160
hivemind_bus_client/client.py 57.7% 124
hivemind_bus_client/serialization.py 70.4% 32

Full report: download the coverage-report artifact.

🔨 Build Tests

The build bots are giving this a thumbs up. 👍

Python Build Install Tests
3.10 ⚠️
3.11 ⚠️
3.12 ⚠️
3.13 ⚠️
3.14 ⚠️

❌ 3.10: Install OK, tests failed
❌ 3.11: Install OK, tests failed
❌ 3.12: Install OK, tests failed
❌ 3.13: Install OK, tests failed
❌ 3.14: Install OK, tests failed
Check job logs for details.


The automation never sleeps, but I might reboot. 💤

@goldyfruit goldyfruit self-assigned this Mar 30, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 30, 2026

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 331397d3-4530-4cd4-95df-9fbe4a57b2de

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • ✅ Review completed - (🔄 Check again to review again)
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/align-intercom-with-core

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@goldyfruit goldyfruit marked this pull request as ready for review March 30, 2026 14:18
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
test/unittests/test_protocol_intercom.py (1)

27-44: Consider adding test coverage for the legacy hybrid envelope path.

The test validates the new "ciphertext"-only envelope format, but the implementation also supports the legacy "encrypted_key" format for backward compatibility. A test for the legacy path would ensure it doesn't regress.

Additionally, consider adding negative tests for:

  • Decryption failure (wrong key)
  • Missing ciphertext field
  • Malformed base64
📝 Example test for legacy envelope
def test_handle_intercom_accepts_legacy_hybrid_envelope(self):
    proto = _make_protocol()
    proto.identity.public_key = "client-pubkey"
    inner = HiveMessage(HiveMessageType.BUS,
                        Message("speak", {"utterance": "hello"}, {}))
    # Legacy envelope includes encrypted_key
    msg = HiveMessage(HiveMessageType.INTERCOM,
                      {"ciphertext": "...", "encrypted_key": "...", "iv": "..."},
                      target_pubkey="client-pubkey")

    with patch("hivemind_bus_client.protocol.load_RSA_key", return_value=object()):
        with patch("hivemind_bus_client.protocol.hybrid_decrypt", 
                   return_value=inner.serialize().encode("utf-8")):
            with patch.object(proto, "handle_bus") as mock_handle_bus:
                self.assertTrue(proto.handle_intercom(msg))

    mock_handle_bus.assert_called_once()
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/unittests/test_protocol_intercom.py` around lines 27 - 44, Add a unit
test that covers the legacy hybrid envelope path: create a test named
test_handle_intercom_accepts_legacy_hybrid_envelope that mirrors
test_handle_intercom_accepts_core_rsa_envelope but constructs HiveMessage with
"ciphertext", "encrypted_key" and "iv" fields and proto.identity.public_key set;
patch hivemind_bus_client.protocol.load_RSA_key to return a key-like object and
patch hivemind_bus_client.protocol.hybrid_decrypt to return
inner.serialize().encode("utf-8"), then call proto.handle_intercom(msg) and
assert it returns True and that proto.handle_bus was called once with a
HiveMessageType.BUS payload; additionally add short negative tests that patch
decrypt_RSA or hybrid_decrypt to raise/return invalid data and assert
proto.handle_intercom returns False (or does not call handle_bus) for decryption
failure, missing "ciphertext", and malformed base64 cases.
hivemind_bus_client/protocol.py (1)

543-566: PING type not handled in _dispatch_intercom_payload.

The dispatcher handles most message types but omits PING. Looking at handle_propagate (line 391-392), PING messages are handled via _handle_ping. If a PING can be embedded in an INTERCOM payload, it would hit the "Unsupported INTERCOM payload type" warning.

If PING-over-INTERCOM is a valid use case, add the handler:

+        if message.msg_type == HiveMessageType.PING:
+            # Wrap in PROPAGATE for _handle_ping compatibility
+            wrapper = HiveMessage(HiveMessageType.PROPAGATE, payload=message)
+            self._handle_ping(wrapper)
+            return True

If intentionally unsupported, this is fine as-is.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@hivemind_bus_client/protocol.py` around lines 543 - 566, The dispatcher
_dispatch_intercom_payload currently omits handling HiveMessageType.PING and
will log it as unsupported if a PING appears inside an INTERCOM payload; add a
branch that checks for message.msg_type == HiveMessageType.PING and route it to
the existing ping handler (call self.hm._handle_ping(message) or the same path
used by handle_propagate) so PING messages are processed correctly; update the
conditional ordering in _dispatch_intercom_payload to include this new case and
ensure it returns True after handling.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@hivemind_bus_client/protocol.py`:
- Around line 508-523: The RSA envelope path currently decodes the signature but
never verifies it; before decrypting call verify_RSA using the sender's public
key and the raw ciphertext (or the hybrid envelope's encrypted_key/ciphertext as
appropriate), base64-decode pload["signature"] and pass it and the ciphertext to
verify_RSA, and if verification fails log and return False; only after
successful verify_RSA proceed to decrypt with decrypt_RSA or hybrid_decrypt and
then HiveMessage.deserialize. Locate this logic around load_RSA_key,
decrypt_RSA, hybrid_decrypt, and HiveMessage.deserialize and add the signature
check there (use verify_RSA to mirror sign_RSA used by the sender).

---

Nitpick comments:
In `@hivemind_bus_client/protocol.py`:
- Around line 543-566: The dispatcher _dispatch_intercom_payload currently omits
handling HiveMessageType.PING and will log it as unsupported if a PING appears
inside an INTERCOM payload; add a branch that checks for message.msg_type ==
HiveMessageType.PING and route it to the existing ping handler (call
self.hm._handle_ping(message) or the same path used by handle_propagate) so PING
messages are processed correctly; update the conditional ordering in
_dispatch_intercom_payload to include this new case and ensure it returns True
after handling.

In `@test/unittests/test_protocol_intercom.py`:
- Around line 27-44: Add a unit test that covers the legacy hybrid envelope
path: create a test named test_handle_intercom_accepts_legacy_hybrid_envelope
that mirrors test_handle_intercom_accepts_core_rsa_envelope but constructs
HiveMessage with "ciphertext", "encrypted_key" and "iv" fields and
proto.identity.public_key set; patch hivemind_bus_client.protocol.load_RSA_key
to return a key-like object and patch
hivemind_bus_client.protocol.hybrid_decrypt to return
inner.serialize().encode("utf-8"), then call proto.handle_intercom(msg) and
assert it returns True and that proto.handle_bus was called once with a
HiveMessageType.BUS payload; additionally add short negative tests that patch
decrypt_RSA or hybrid_decrypt to raise/return invalid data and assert
proto.handle_intercom returns False (or does not call handle_bus) for decryption
failure, missing "ciphertext", and malformed base64 cases.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0766d767-9920-4215-952c-7a56fd1c49d5

📥 Commits

Reviewing files that changed from the base of the PR and between 68f1e48 and ed5c0c5.

📒 Files selected for processing (4)
  • hivemind_bus_client/client.py
  • hivemind_bus_client/protocol.py
  • test/unittests/test_client.py
  • test/unittests/test_protocol_intercom.py

Comment on lines +508 to 523
if isinstance(pload, dict) and "ciphertext" in pload:
try:
private_key = load_RSA_key(self.identity.private_key)
decrypted = hybrid_decrypt(private_key, pload).decode("utf-8")
if "encrypted_key" in pload:
# Backward-compatible with older hybrid AES+RSA envelopes.
decrypted = hybrid_decrypt(private_key, pload).decode("utf-8")
else:
ciphertext = pybase64.b64decode(pload["ciphertext"])
decrypted = decrypt_RSA(private_key, ciphertext).decode("utf-8")
message._payload = HiveMessage.deserialize(decrypted)
except Exception as e:
except Exception:
if k:
LOG.error("failed to decrypt INTERCOM message!")
else:
LOG.debug("failed to decrypt INTERCOM, not for us")
return False
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Missing signature verification on the new RSA envelope path.

The sender signs the ciphertext with sign_RSA, but the receiver doesn't verify the signature before trusting the message. The signature field in the payload is decoded but never verified against the sender's public key.

Without signature verification:

  • An attacker could replay or modify INTERCOM messages
  • The signature field serves no purpose

Consider adding signature verification using verify_RSA before decryption, or document why signature verification is intentionally deferred (e.g., if handled at a different layer).

🔒 Proposed fix to add signature verification
             if "encrypted_key" in pload:
                 # Backward-compatible with older hybrid AES+RSA envelopes.
                 decrypted = hybrid_decrypt(private_key, pload).decode("utf-8")
             else:
                 ciphertext = pybase64.b64decode(pload["ciphertext"])
+                # Verify signature if sender's public key is available
+                if "signature" in pload and message.source_peer:
+                    # TODO: Retrieve sender's public key and verify
+                    # signature = pybase64.b64decode(pload["signature"])
+                    # verify_RSA(sender_pubkey, ciphertext, signature)
+                    pass
                 decrypted = decrypt_RSA(private_key, ciphertext).decode("utf-8")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@hivemind_bus_client/protocol.py` around lines 508 - 523, The RSA envelope
path currently decodes the signature but never verifies it; before decrypting
call verify_RSA using the sender's public key and the raw ciphertext (or the
hybrid envelope's encrypted_key/ciphertext as appropriate), base64-decode
pload["signature"] and pass it and the ciphertext to verify_RSA, and if
verification fails log and return False; only after successful verify_RSA
proceed to decrypt with decrypt_RSA or hybrid_decrypt and then
HiveMessage.deserialize. Locate this logic around load_RSA_key, decrypt_RSA,
hybrid_decrypt, and HiveMessage.deserialize and add the signature check there
(use verify_RSA to mirror sign_RSA used by the sender).

@goldyfruit goldyfruit closed this Mar 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant