Manage AWS, Hetzner, OVH, and custom servers from one TUI — with a built-in AI assistant and MCP server
Drift inferred · capture-to-capture
No drift recorded — single capability capture; advisories appear once its surface changes.
transport stdio · http counts 0 tools · 0 res
· 0 prompts
permission surface via code analysis
No tools enumerated yet for this server.
prompt-surface
shipped agent-instruction files + hidden-content / dangerous-code findings —
quoted from the analyzed source
analyzed commit 9aae544 · analyzer v33 · 3d ago
danger signals4
- dynamic code execution __import__() zb-ss-servonaut-9aae544/src/servonaut/screens/settings/registry.py :43
__import__( - suspicious endpoint 169.254.169.254 (cloud metadata) zb-ss-servonaut-9aae544/tests/test_object_storage_service.py :124
endpoint_url="https://169.254.169.254", - committed secret OpenAI key zb-ss-servonaut-9aae544/docs/configuration.md :339
sk-Lwh…(25 chars, redacted) - committed secret Stripe live key zb-ss-servonaut-9aae544/tests/test_redaction_known_secrets.py :97
sk_liv…(34 chars, redacted)
evidence-backed
findings quoted directly from the published source artifact — not inferred
code files: 601
filesystem 161
- fs (weak) zb-ss-servonaut-9aae544/.github/scripts/release-policy.py :9
from pathlib import Path - fs (weak) zb-ss-servonaut-9aae544/scripts/desktop_probe/check.py :14
from pathlib import Path - fs (weak) zb-ss-servonaut-9aae544/scripts/desktop_probe/child.py :11
from pathlib import Path - fs (weak) zb-ss-servonaut-9aae544/scripts/desktop_probe/config.py :5
from pathlib import Path - fs (weak) zb-ss-servonaut-9aae544/scripts/desktop_probe/diagnostics.py :9
from pathlib import Path - fs (weak) zb-ss-servonaut-9aae544/scripts/desktop_probe/host.py :14
from pathlib import Path - fs (weak) zb-ss-servonaut-9aae544/scripts/desktop_probe/renderer.py :3
# Upstream registers WebGL and then replaces it with Canvas during open(). - fs zb-ss-servonaut-9aae544/src/servonaut/cli/ai.py :51
from pathlib import Path - fs zb-ss-servonaut-9aae544/src/servonaut/cli/hetzner.py :43
from pathlib import Path - fs zb-ss-servonaut-9aae544/src/servonaut/cli/login.py :151
if webbrowser.open(open_target): - fs zb-ss-servonaut-9aae544/src/servonaut/cli/memory.py :12
from pathlib import Path - fs zb-ss-servonaut-9aae544/src/servonaut/cli/secrets.py :46
import shutil
show 28 more
- fs zb-ss-servonaut-9aae544/src/servonaut/config/manager.py :7
from pathlib import Path - fs zb-ss-servonaut-9aae544/src/servonaut/config/migration.py :7
from pathlib import Path - fs zb-ss-servonaut-9aae544/src/servonaut/config/paths.py :26
from pathlib import Path - fs zb-ss-servonaut-9aae544/src/servonaut/config/secrets.py :7
from pathlib import Path - fs zb-ss-servonaut-9aae544/src/servonaut/main.py :11
from pathlib import Path - fs zb-ss-servonaut-9aae544/src/servonaut/mcp/audit.py :20
from pathlib import Path - fs zb-ss-servonaut-9aae544/src/servonaut/mcp/installer.py :8
import shutil - fs zb-ss-servonaut-9aae544/src/servonaut/mcp/tools.py :3912
from pathlib import Path as _Path - fs zb-ss-servonaut-9aae544/src/servonaut/screens/ai_conversations_screen.py :22
from pathlib import Path - fs zb-ss-servonaut-9aae544/src/servonaut/screens/backup_restore.py :7
from pathlib import Path - fs zb-ss-servonaut-9aae544/src/servonaut/screens/bug_report.py :394
webbrowser.open(receipt.url) - fs zb-ss-servonaut-9aae544/src/servonaut/screens/bw_dir_picker.py :19
Dismisses the chosen :class:`~pathlib.Path`, or ``None`` on cancel. - fs zb-ss-servonaut-9aae544/src/servonaut/screens/bw_item_picker.py :293
webbrowser.open(_PRICING_URL) - fs zb-ss-servonaut-9aae544/src/servonaut/screens/bw_key_import.py :21
from pathlib import Path - fs zb-ss-servonaut-9aae544/src/servonaut/screens/bw_vault_manager.py :369
webbrowser.open(url) - fs zb-ss-servonaut-9aae544/src/servonaut/screens/findings.py :767
webbrowser.open(url) - fs zb-ss-servonaut-9aae544/src/servonaut/screens/fleet_memory.py :21
from pathlib import Path - fs zb-ss-servonaut-9aae544/src/servonaut/screens/hetzner_setup.py :381
import shutil - fs zb-ss-servonaut-9aae544/src/servonaut/screens/ip_ban.py :132
from pathlib import Path - fs zb-ss-servonaut-9aae544/src/servonaut/screens/key_management.py :219
from pathlib import Path - fs zb-ss-servonaut-9aae544/src/servonaut/screens/memory.py :16
from pathlib import Path - fs zb-ss-servonaut-9aae544/src/servonaut/screens/memory_sync_setup.py :523
webbrowser.open(url) - fs zb-ss-servonaut-9aae544/src/servonaut/screens/ovh_setup.py :392
import shutil - fs zb-ss-servonaut-9aae544/src/servonaut/screens/scp_transfer.py :105
from pathlib import Path - fs zb-ss-servonaut-9aae544/src/servonaut/screens/secrets.py :600
webbrowser.open(url) - fs zb-ss-servonaut-9aae544/src/servonaut/screens/server_actions.py :1341
os.unlink(tmp_key_path) - fs zb-ss-servonaut-9aae544/src/servonaut/services/ai_conversations.py :20
from pathlib import Path - fs zb-ss-servonaut-9aae544/src/servonaut/services/ai_providers/demo_replay.py :39
from pathlib import Path
121 more not shown — this panel samples each group; the count above is the real total.
shell / exec 40
- shell (weak) zb-ss-servonaut-9aae544/.github/scripts/release-policy.py :6
import subprocess - shell zb-ss-servonaut-9aae544/src/servonaut/cli/memory.py :10
import subprocess - shell zb-ss-servonaut-9aae544/src/servonaut/cli/secrets.py :47
import subprocess - shell zb-ss-servonaut-9aae544/src/servonaut/cli/servers.py :21
import subprocess - shell zb-ss-servonaut-9aae544/src/servonaut/cli/ssh.py :22
import subprocess - shell zb-ss-servonaut-9aae544/src/servonaut/main.py :412
import subprocess - shell zb-ss-servonaut-9aae544/src/servonaut/mcp/installer.py :9
import subprocess - shell zb-ss-servonaut-9aae544/src/servonaut/screens/command_overlay.py :5
import subprocess - shell zb-ss-servonaut-9aae544/src/servonaut/screens/hetzner_setup.py :382
import subprocess - shell zb-ss-servonaut-9aae544/src/servonaut/screens/key_management.py :4
import subprocess - shell zb-ss-servonaut-9aae544/src/servonaut/screens/log_viewer.py :8
import subprocess - shell zb-ss-servonaut-9aae544/src/servonaut/screens/memory.py :14
import subprocess
show 28 more
- shell zb-ss-servonaut-9aae544/src/servonaut/screens/ovh_setup.py :393
import subprocess - shell zb-ss-servonaut-9aae544/src/servonaut/screens/server_actions.py :6
import subprocess - shell zb-ss-servonaut-9aae544/src/servonaut/services/bw_resolver.py :22
import subprocess - shell zb-ss-servonaut-9aae544/src/servonaut/services/bw_session_service.py :32
import subprocess - shell zb-ss-servonaut-9aae544/src/servonaut/services/memory/service.py :1306
from subprocess import CalledProcessError - shell zb-ss-servonaut-9aae544/src/servonaut/services/scan_service.py :7
import subprocess - shell zb-ss-servonaut-9aae544/src/servonaut/services/scp_service.py :7
import subprocess - shell zb-ss-servonaut-9aae544/src/servonaut/services/ssh_service.py :6
import subprocess - shell zb-ss-servonaut-9aae544/src/servonaut/services/terminal_service.py :6
import subprocess - shell zb-ss-servonaut-9aae544/src/servonaut/services/update_service.py :8
import subprocess - shell zb-ss-servonaut-9aae544/src/servonaut/utils/platform_utils.py :6
import subprocess - shell zb-ss-servonaut-9aae544/src/servonaut/utils/ssh_utils.py :7
import subprocess - shell zb-ss-servonaut-9aae544/src/servonaut/widgets/remote_tree.py :5
import subprocess - shell (weak) zb-ss-servonaut-9aae544/tests/test_bw_key_import.py :14
import subprocess - shell (weak) zb-ss-servonaut-9aae544/tests/test_bw_resolver.py :6
from subprocess import CompletedProcess - shell (weak) zb-ss-servonaut-9aae544/tests/test_bw_session_service.py :13
from subprocess import CompletedProcess, TimeoutExpired - shell (weak) zb-ss-servonaut-9aae544/tests/test_cli_servers.py :15
import subprocess - shell (weak) zb-ss-servonaut-9aae544/tests/test_css_paths.py :17
import subprocess - shell (weak) zb-ss-servonaut-9aae544/tests/test_demo_mode_coverage.py :958
import subprocess - shell (weak) zb-ss-servonaut-9aae544/tests/test_desktop_probe_native.py :7
import subprocess - shell (weak) zb-ss-servonaut-9aae544/tests/test_docs_cli_commands.py :14
import subprocess - shell (weak) zb-ss-servonaut-9aae544/tests/test_mcp_headless_imports.py :11
import subprocess - shell (weak) zb-ss-servonaut-9aae544/tests/test_memory_cli.py :318
import subprocess as _subprocess - shell (weak) zb-ss-servonaut-9aae544/tests/test_relay_lock.py :72
import subprocess - shell (weak) zb-ss-servonaut-9aae544/tests/test_release_policy.py :6
import subprocess - shell (weak) zb-ss-servonaut-9aae544/tests/test_remediation_executor.py :345
import subprocess - shell (weak) zb-ss-servonaut-9aae544/tests/test_remote_tree_sudo_fallback.py :106
import subprocess as _sp - shell (weak) zb-ss-servonaut-9aae544/tests/test_ssh_utils.py :5
import subprocess
network 40
- net (weak) zb-ss-servonaut-9aae544/scripts/desktop_probe/__main__.py :14
import socket - net (weak) zb-ss-servonaut-9aae544/scripts/desktop_probe/host.py :10
import socket - net zb-ss-servonaut-9aae544/src/servonaut/app.py :2285
"Bug reporting requires httpx. Install with: pip install 'servonaut[pro]'", - net zb-ss-servonaut-9aae544/src/servonaut/main.py :548
if we simply don't have credentials or httpx. - net zb-ss-servonaut-9aae544/src/servonaut/mcp/remote_client.py :16
import httpx - net zb-ss-servonaut-9aae544/src/servonaut/mcp/tools.py :1077
import httpx - net zb-ss-servonaut-9aae544/src/servonaut/screens/cloudwatch_browser.py :652
import httpx - net zb-ss-servonaut-9aae544/src/servonaut/screens/snapshot_manager.py :388
import socket - net zb-ss-servonaut-9aae544/src/servonaut/services/ai_analysis_service.py :21
import httpx - net zb-ss-servonaut-9aae544/src/servonaut/services/ai_providers/demo_replay.py :42
import httpx - net zb-ss-servonaut-9aae544/src/servonaut/services/ai_sse.py :5
underlying :class:`httpx.AsyncClient` lifetime via ``async with`` so a - net zb-ss-servonaut-9aae544/src/servonaut/services/api_client.py :18
import httpx
show 28 more
- net zb-ss-servonaut-9aae544/src/servonaut/services/auth_service.py :18
import httpx - net zb-ss-servonaut-9aae544/src/servonaut/services/bug_report_service.py :14
import urllib.parse - net zb-ss-servonaut-9aae544/src/servonaut/services/config_sync_service.py :9
import socket - net zb-ss-servonaut-9aae544/src/servonaut/services/db_credential_scanner.py :25
from urllib.parse import urlparse, unquote - net zb-ss-servonaut-9aae544/src/servonaut/services/ip_enrichment_service.py :27
import urllib.request - net zb-ss-servonaut-9aae544/src/servonaut/services/object_storage_service.py :8
import socket - net zb-ss-servonaut-9aae544/src/servonaut/services/ovh_ip_service.py :9
from urllib.parse import quote - net zb-ss-servonaut-9aae544/src/servonaut/services/relay_listener.py :10
import socket - net zb-ss-servonaut-9aae544/src/servonaut/services/relay_manager.py :22
from urllib.parse import urlsplit, urlunsplit - net zb-ss-servonaut-9aae544/src/servonaut/services/update_service.py :10
import urllib.request - net zb-ss-servonaut-9aae544/src/servonaut/services/voice_setup_service.py :973
import httpx - net (weak) zb-ss-servonaut-9aae544/tests/sse_replay.py :3
Turns a ``.sse`` byte fixture into an :class:`httpx.MockTransport` that - net (weak) zb-ss-servonaut-9aae544/tests/test_api_client_errors.py :39
"""Build a minimal mock that looks like an httpx.Response.""" - net (weak) zb-ss-servonaut-9aae544/tests/test_auth_service.py :586
"""Bare-minimum httpx.Response stand-in for refresh_token unit tests.""" - net (weak) zb-ss-servonaut-9aae544/tests/test_demo_chat_replay.py :8
import httpx - net (weak) zb-ss-servonaut-9aae544/tests/test_desktop_probe.py :46
async with aiohttp.ClientSession() as client: - net (weak) zb-ss-servonaut-9aae544/tests/test_desktop_probe_browser.py :10
from urllib.parse import parse_qs, urlsplit - net (weak) zb-ss-servonaut-9aae544/tests/test_findings_service.py :22
import httpx - net (weak) zb-ss-servonaut-9aae544/tests/test_mcp_api_request.py :73
"""Collects the last httpx.Request observed by the mock transport.""" - net (weak) zb-ss-servonaut-9aae544/tests/test_mcp_relay_reconnect.py :66
real = httpx.AsyncClient - net (weak) zb-ss-servonaut-9aae544/tests/test_mcp_relay_status_and_tool_call.py :61
real = httpx.AsyncClient - net (weak) zb-ss-servonaut-9aae544/tests/test_relay_handshake.py :245
import httpx - net (weak) zb-ss-servonaut-9aae544/tests/test_secret_provider_resolver.py :307
# E.g. httpx.ConnectError / generic OSError — should not log - net (weak) zb-ss-servonaut-9aae544/tests/test_secrets_audit_fixes.py :108
"servonaut.services.api_client.httpx.AsyncClient", - net (weak) zb-ss-servonaut-9aae544/tests/test_secrets_config_api_client.py :6
against the live endpoint. Mocks at the httpx.AsyncClient layer - net (weak) zb-ss-servonaut-9aae544/tests/test_secrets_followups.py :175
"servonaut.services.auth_service.httpx.AsyncClient", - net (weak) zb-ss-servonaut-9aae544/tests/test_sse_stream.py :279
``async with httpx.AsyncClient`` in :func:`stream_sse` unwound. - net (weak) zb-ss-servonaut-9aae544/tests/test_user_secrets_config.py :95
"servonaut.services.api_client.httpx.AsyncClient",
secrets 7
- secrets zb-ss-servonaut-9aae544/src/servonaut/cli/memory.py :6
import getpass - secrets zb-ss-servonaut-9aae544/src/servonaut/main.py :221
auth_token = os.environ.get('SERVONAUT_RELAY_TOKEN', '') - secrets zb-ss-servonaut-9aae544/src/servonaut/screens/memory.py :9
import getpass - secrets zb-ss-servonaut-9aae544/src/servonaut/services/hetzner_service.py :164
from_env = os.environ.get('HCLOUD_TOKEN', '') - secrets zb-ss-servonaut-9aae544/src/servonaut/services/memory/passphrase_store.py :31
import keyring as _keyring # type: ignore[import-untyped] - secrets (weak) zb-ss-servonaut-9aae544/tests/test_e2e_secrets_staging.py :119
oauth = os.environ.get("SERVONAUT_E2E_OAUTH_TOKEN", "") - secrets (weak) zb-ss-servonaut-9aae544/tests/test_secrets.py :134
assert os.environ["GOOD_KEY"] == "good_val"
declared dependencies 20
- mcp@>=1.0.0,<2
- boto3@*
- tabulate@*
- textual@>=8.0.0
- cryptography@>=42.0
- bcrypt@>=3.2
- pynacl@>=1.5
- httpx@>=0.25.0
- httpx-sse@>=0.4
- keyring@>=24
- pytest@>=7.0
- pytest-cov@>=4.0
show 8 more
- pytest-asyncio@>=0.21
- pytest-timeout@>=2.3
- ovh@*
- hcloud@>=2.0
- faster-whisper@>=1.0
- sounddevice@>=0.4
- numpy@>=1.24
- sherpa-onnx@>=1.13.3
clipboard 1
- clipboard shell call zb-ss-servonaut-9aae544/src/servonaut/utils/platform_utils.py :94
subprocess.run(['pbcopy'], input=text.encode(), check=True)