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.
3.5 KiB
UmbraTrans remote credential broker
This is a standalone local MCP server for the UmbraTrans control plane. It is not imported by UmbraAudio and must be deployed separately on the trusted macOS/OpenCode host.
Security model
- Passwords are entered in a native macOS hidden-password dialog.
- Passwords are stored in the macOS login Keychain through the Security framework; they are never written to the repository, environment variables, command-line arguments, logs, or MCP responses.
- The MCP server exposes no
get_passwordoperation. - SSH host-key checking is strict. The server does not silently accept an unknown host key.
- Unprivileged SSH commands are bounded by a timeout and output limit.
- Sudo commands must exactly match an allowlist entry in the local config.
- The default configuration does not grant
sudoaccess to arbitrary commands. - The server is stdio-only and has no network listener.
The broker is intended to run on the Mac that owns the OpenCode session. The
remote umbra account receives an SSH connection; the password is supplied
only to the local SSH client/Keychain flow.
Files
broker.py— stdio MCP server and command-line popup setup.keychain.py— ctypes macOS Keychain backend.popup.py— native hidden-password prompt.askpass_helper.py— OpenSSHSSH_ASKPASShelper; it prints a secret only to the SSH process pipe.executor.py— bounded SSH/sudo execution and redaction.config.py— non-secret remote profile and sudo allowlist parser.config.example.json— oldbox/umbra example; copy to the user config path.tests/— dependency-free unit tests.
Local configuration
Copy the example to:
~/.config/umbra-trans/remote-broker.json
Review it. The known_hosts path must already contain the verified oldbox host
key. Do not use StrictHostKeyChecking=no or an empty known-hosts file.
The first credential profiles can be entered through the MCP tool
credential_set, which opens the popup, or directly from a terminal:
python3 -m remote_credential_broker.broker \
--credential-profile oldbox-umbra-ssh \
--purpose "SSH password for umbra@oldbox"
python3 -m remote_credential_broker.broker \
--credential-profile oldbox-umbra-sudo \
--purpose "sudo password for umbra@oldbox"
The command prints only whether the profile was stored. It never prints the secret.
OpenCode registration
Run the module from the directory containing the remote_credential_broker
package, or use an absolute Python path and package directory. A local server
entry has this shape:
{
"mcp": {
"servers": {
"remote-broker": {
"type": "local",
"command": [
"/absolute/path/to/python",
"-m",
"remote_credential_broker.broker"
],
"environment": {
"PYTHONPATH": "/absolute/path/to/package/parent"
}
}
}
}
}
The current OpenCode installation may use the older top-level mcp object;
use the format accepted by the installed version. Do not put a password in the
configuration file.
Tools
credential_set— opens the native popup and stores a profile.credential_status— reports existence only.credential_delete— removes a profile.remote_exec— runs a command as the configured SSH account.remote_sudo_exec— runs one exact allowlisted command through sudo.remote_status— runs fixed identity/hostname probes.
The model can request a popup or operation, but cannot read the secret entered in the popup.