Two groups of changes, committed together as the follow-up to the initial push: 1. .gitmodules — submodule Qwen3-TTS now points at the internal Gitea fork (ssh://git@mini-eq:2222/umbragit/Qwen3-TTS.git) instead of upstream GitHub, so a clone actually gets the UmbraAudio branding/integration commit 012e452 rather than vanilla upstream. 2. New infra/ tooling for the cross-machine work in spec 21: agent_bridge, remote_credential_broker (Keychain-backed, secrets read at runtime and generated via read_secret/random_secret — no hardcoded credentials), the enterprise bootstrap scripts, and the oldbox SSH/auth prompts. Plus backup/ restore scripts, two specs (18 UmbraTrans, 19 enterprise control plane), umbraaudio/voices/lmstudio_gate.py, and in-flight edits to the discovery/attribution/profiling modules, config, chapter_builder, emotion, pronunciation, qwen_tts and routes. Also adds *.db to .gitignore: SQLite project databases are runtime state and no .db file was tracked before. Verified before staging: .env's only change is UMBRA_TTS__QWEN_TTS_HELPER_URL and the committed copy has zero secret-looking values; the broker ships only config.example.json.
51 lines
2.0 KiB
Python
51 lines
2.0 KiB
Python
from __future__ import annotations
|
|
|
|
import json
|
|
import sys
|
|
import tempfile
|
|
import unittest
|
|
from pathlib import Path
|
|
|
|
sys.path.insert(0, str(Path(__file__).resolve().parents[2]))
|
|
|
|
from agent_bridge.server import BridgeError, BridgeState, MessageStore
|
|
|
|
|
|
class BridgeTests(unittest.TestCase):
|
|
def test_password_hashing_and_pairing(self) -> None:
|
|
state = BridgeState("correct-value", ttl_seconds=60)
|
|
self.assertTrue(state.check_password("192.0.2.1", "correct-value"))
|
|
self.assertFalse(state.check_password("192.0.2.1", "wrong-value"))
|
|
session, csrf = state.new_session()
|
|
self.assertIsNotNone(state.session(session))
|
|
self.assertTrue(csrf)
|
|
self.assertIsNone(state.session("missing"))
|
|
|
|
def test_message_queue_is_atomic_and_bounded(self) -> None:
|
|
with tempfile.TemporaryDirectory() as directory:
|
|
store = MessageStore(Path(directory))
|
|
message = store.send_to_mac("hello", "test")
|
|
self.assertEqual(store.status()["inbox"], 1)
|
|
self.assertEqual(store.poll_for_mac()[0]["body"], "hello")
|
|
self.assertEqual(store.status()["processed"], 1)
|
|
reply = store.send_to_browser("reply", "test")
|
|
self.assertEqual(store.read_for_browser()[0]["id"], reply["id"])
|
|
self.assertEqual(store.acknowledge([reply["id"]]), 1)
|
|
self.assertEqual(store.status()["delivered"], 1)
|
|
|
|
def test_message_size_is_limited(self) -> None:
|
|
with tempfile.TemporaryDirectory() as directory:
|
|
store = MessageStore(Path(directory))
|
|
with self.assertRaises(BridgeError):
|
|
store.send_to_mac("x" * (64 * 1024 + 1))
|
|
|
|
def test_invalid_message_file_is_ignored(self) -> None:
|
|
with tempfile.TemporaryDirectory() as directory:
|
|
store = MessageStore(Path(directory))
|
|
(store.inbox / "bad.json").write_text(json.dumps({"not": "a message"}))
|
|
self.assertEqual(store.poll_for_mac(), [])
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|