replica-omnisciente/telminal/tests/test_config.py
Aurelio 56be25c1ed feat(telminal): add hardened Terminal-in-Telegram bot to aurelio
Port fristhon/telminal (MIT) into the aurelio monorepo as a self-hosted
Telegram shell bot for the fleet gateway (CT-217).

- telminal/ package: config (env + state file, refuses empty admins),
  core orchestrator (event handlers, router, watchers, interactive mode,
  file up/download, xterm.js image render), process (pexpect PTY + streaming
  + inline control buttons), telegram (Telethon wrapper, swappable for tests),
  cli (entry point reading TELEGRAM_* env), utils, values.
- aurelio hardening vs upstream: no first-run random token auth (explicit
  admin allowlist required); cd sandbox validated against working root;
  secrets from env mirroring the CT-217 gateway .env.
- 35 real tests (pty capture/control-char, router, watchers, perms, sandbox,
  fake-client orchestration) -- all green.
- deployment: systemd/telminal.service, .env.example entries, README, AGENTS.md.

Verified: pytest 35 passed; CLI refuses start with missing env / no admins.
2026-07-15 23:42:31 +01:00

108 lines
3.5 KiB
Python

"""Tests for configuration, utils, and routing/watcher regexes."""
from __future__ import annotations
import os
import pytest
from telminal.config import Config, ConfigError
from telminal.values import GET_PATTERN, WATCHER_PATTERN
from telminal import utils
def test_config_requires_env(monkeypatch):
for var in ("TELEGRAM_API_ID", "TELEGRAM_API_HASH", "TELEGRAM_TOKEN"):
monkeypatch.delenv(var, raising=False)
with pytest.raises(ConfigError):
Config.from_env()
def test_config_reads_env_admins(monkeypatch, tmp_path):
monkeypatch.setenv("TELEGRAM_API_ID", "123")
monkeypatch.setenv("TELEGRAM_API_HASH", "h")
monkeypatch.setenv("TELEGRAM_TOKEN", "t")
monkeypatch.setenv("TELEGRAM_ADMINS", "111, 222")
# from_env intentionally ignores TELEGRAM_ADMINS (that's the CLI's job);
# admins come only from the persisted state file, which is empty here.
cfg = Config.from_env(allow_empty_admins=True)
assert cfg.api_id == 123
assert cfg.admins == []
def test_cli_build_config_merges_env_admins(monkeypatch, tmp_path):
monkeypatch.setenv("TELEGRAM_API_ID", "123")
monkeypatch.setenv("TELEGRAM_API_HASH", "h")
monkeypatch.setenv("TELEGRAM_TOKEN", "t")
monkeypatch.setenv("TELEGRAM_ADMINS", "111, 222")
from telminal.cli import build_config
cfg = build_config()
assert cfg.admins == [111, 222]
def test_config_refuses_empty_admins(monkeypatch, tmp_path):
monkeypatch.setenv("TELEGRAM_API_ID", "123")
monkeypatch.setenv("TELEGRAM_API_HASH", "h")
monkeypatch.setenv("TELEGRAM_TOKEN", "t")
monkeypatch.delenv("TELEGRAM_ADMINS", raising=False)
with pytest.raises(ConfigError):
Config.from_env()
def test_config_bad_api_id(monkeypatch):
monkeypatch.setenv("TELEGRAM_API_ID", "not-an-int")
monkeypatch.setenv("TELEGRAM_API_HASH", "h")
monkeypatch.setenv("TELEGRAM_TOKEN", "t")
with pytest.raises(ConfigError):
Config.from_env(allow_empty_admins=True)
def test_config_persists_and_reloads(tmp_path):
state = tmp_path / "config.json"
cfg = Config(
api_id=1, api_hash="h", token="t", admins=[5],
working_dir=str(tmp_path), state_file=state,
)
cfg.save_state()
assert state.exists()
reloaded = Config(api_id=1, api_hash="h", token="t", state_file=state)
reloaded._load_state()
assert reloaded.admins == [5]
assert reloaded.working_dir == str(tmp_path)
def test_watcher_pattern():
m = __import__("re").match(WATCHER_PATTERN, "!watch 50s telminal.log")
assert m is not None
assert m.groups() == ("50", "s", "telminal.log")
m2 = __import__("re").match(WATCHER_PATTERN, "!watch 24h /backups/sql.dump")
assert m2.groups() == ("24", "h", "/backups/sql.dump")
assert __import__("re").match(WATCHER_PATTERN, "!watch bogus") is None
def test_get_pattern():
assert __import__("re").match(GET_PATTERN, "!get /etc/passwd")
assert not __import__("re").match(GET_PATTERN, "echo hi")
def test_html_template_render():
rendered = utils.HTML_TEMPLATE.format(title="t", data="hello world")
assert "hello world" in rendered
assert "<html" in rendered
def test_timestamp_and_seconds_readable():
assert utils.timestamp_to_readable(0).count(":") == 2
assert utils.seconds_to_readable(65) == "0:01:05"
def test_media_strip():
assert len(utils.HTML_TEMPLATE) # sanity import works
from telminal.telegram import Telegram
short = "hi"
assert Telegram.media_strip(short) == "hi"
long = "y" * 2000
stripped = Telegram.media_strip(long)
assert len(stripped) == 1024