feat: expand Reyna CLI integrations
This commit is contained in:
@@ -0,0 +1,176 @@
|
||||
from pathlib import Path
|
||||
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from reyna_cli.web import WebSettings, create_app, normalize_args, RunRequest, run_web_server
|
||||
from reyna_cli.tts import TTSError, _custom_tts
|
||||
|
||||
|
||||
def test_web_health_without_auth_config():
|
||||
app = create_app(
|
||||
WebSettings(
|
||||
auth_enabled=True,
|
||||
dev_auth=False,
|
||||
session_secret="",
|
||||
authentik_issuer="https://auth.reynafamily.com/application/o/reyna-cli-web/",
|
||||
client_id=None,
|
||||
client_secret=None,
|
||||
basic_user=None,
|
||||
basic_password=None,
|
||||
public_url=None,
|
||||
command_timeout=5,
|
||||
output_limit=1000,
|
||||
workdir=Path.cwd(),
|
||||
)
|
||||
)
|
||||
client = TestClient(app)
|
||||
response = client.get("/healthz")
|
||||
assert response.status_code == 200
|
||||
assert response.json()["auth_enabled"] is True
|
||||
assert response.json()["oidc_configured"] is False
|
||||
|
||||
|
||||
def test_web_index_renders_with_dev_auth():
|
||||
app = create_app(
|
||||
WebSettings(
|
||||
auth_enabled=True,
|
||||
dev_auth=True,
|
||||
session_secret="dev-secret",
|
||||
authentik_issuer="https://auth.reynafamily.com/application/o/reyna-cli-web/",
|
||||
client_id=None,
|
||||
client_secret=None,
|
||||
basic_user=None,
|
||||
basic_password=None,
|
||||
public_url=None,
|
||||
command_timeout=5,
|
||||
output_limit=1000,
|
||||
workdir=Path.cwd(),
|
||||
)
|
||||
)
|
||||
client = TestClient(app)
|
||||
response = client.get("/")
|
||||
assert response.status_code == 200
|
||||
assert "Reyna CLI Web" in response.text
|
||||
assert "doctor --json" in response.text
|
||||
|
||||
|
||||
def test_web_refuses_dev_auth_on_lan_bind(monkeypatch, tmp_path):
|
||||
monkeypatch.setenv("HERMES_ENV_PATH", str(tmp_path / "missing.env"))
|
||||
monkeypatch.setenv("REYNA_WEB_DEV_AUTH", "1")
|
||||
monkeypatch.delenv("REYNA_WEB_ALLOW_INSECURE_LAN", raising=False)
|
||||
try:
|
||||
run_web_server(host="0.0.0.0", port=8765)
|
||||
except SystemExit as exc:
|
||||
assert "Refusing to run" in str(exc)
|
||||
else:
|
||||
raise AssertionError("LAN dev-auth server was allowed")
|
||||
|
||||
|
||||
def test_web_refuses_lan_bind_without_oidc_config(monkeypatch, tmp_path):
|
||||
monkeypatch.setenv("HERMES_ENV_PATH", str(tmp_path / "missing.env"))
|
||||
monkeypatch.delenv("REYNA_WEB_DEV_AUTH", raising=False)
|
||||
monkeypatch.delenv("REYNA_WEB_AUTH_CLIENT_ID", raising=False)
|
||||
monkeypatch.delenv("REYNA_WEB_AUTH_CLIENT_SECRET", raising=False)
|
||||
monkeypatch.delenv("REYNA_WEB_BASIC_USER", raising=False)
|
||||
monkeypatch.delenv("REYNA_WEB_BASIC_PASSWORD", raising=False)
|
||||
monkeypatch.delenv("REYNA_WEB_SESSION_SECRET", raising=False)
|
||||
try:
|
||||
run_web_server(host="0.0.0.0", port=8765)
|
||||
except SystemExit as exc:
|
||||
assert "without configured authentication" in str(exc)
|
||||
else:
|
||||
raise AssertionError("LAN server without OIDC config was allowed")
|
||||
|
||||
|
||||
def test_web_basic_auth_protects_index():
|
||||
app = create_app(
|
||||
WebSettings(
|
||||
auth_enabled=True,
|
||||
dev_auth=False,
|
||||
session_secret="basic-secret",
|
||||
authentik_issuer="https://auth.reynafamily.com/application/o/reyna-cli-web/",
|
||||
client_id=None,
|
||||
client_secret=None,
|
||||
basic_user="adolfo",
|
||||
basic_password="correct-password",
|
||||
public_url=None,
|
||||
command_timeout=5,
|
||||
output_limit=1000,
|
||||
workdir=Path.cwd(),
|
||||
)
|
||||
)
|
||||
client = TestClient(app)
|
||||
unauthenticated = client.get("/")
|
||||
assert unauthenticated.status_code == 401
|
||||
assert unauthenticated.headers["www-authenticate"] == 'Basic realm="Reyna CLI Web"'
|
||||
|
||||
authenticated = client.get("/", auth=("adolfo", "correct-password"))
|
||||
assert authenticated.status_code == 200
|
||||
assert "HTTP Basic auth" in authenticated.text
|
||||
|
||||
|
||||
def test_web_allows_lan_bind_with_basic_auth(monkeypatch, tmp_path):
|
||||
monkeypatch.setenv("HERMES_ENV_PATH", str(tmp_path / "missing.env"))
|
||||
called = {}
|
||||
|
||||
def fake_run(app_path, host, port, reload):
|
||||
called.update({"app_path": app_path, "host": host, "port": port, "reload": reload})
|
||||
|
||||
monkeypatch.delenv("REYNA_WEB_DEV_AUTH", raising=False)
|
||||
monkeypatch.delenv("REYNA_WEB_AUTH_CLIENT_ID", raising=False)
|
||||
monkeypatch.delenv("REYNA_WEB_AUTH_CLIENT_SECRET", raising=False)
|
||||
monkeypatch.setenv("REYNA_WEB_BASIC_USER", "adolfo")
|
||||
monkeypatch.setenv("REYNA_WEB_BASIC_PASSWORD", "correct-password")
|
||||
monkeypatch.setattr("uvicorn.run", fake_run)
|
||||
|
||||
run_web_server(host="0.0.0.0", port=8765)
|
||||
assert called["host"] == "0.0.0.0"
|
||||
|
||||
|
||||
def test_web_api_run_uses_argument_vector(monkeypatch):
|
||||
app = create_app(
|
||||
WebSettings(
|
||||
auth_enabled=False,
|
||||
dev_auth=False,
|
||||
session_secret="dev-secret",
|
||||
authentik_issuer="https://auth.reynafamily.com/application/o/reyna-cli-web/",
|
||||
client_id=None,
|
||||
client_secret=None,
|
||||
basic_user=None,
|
||||
basic_password=None,
|
||||
public_url=None,
|
||||
command_timeout=5,
|
||||
output_limit=1000,
|
||||
workdir=Path.cwd(),
|
||||
)
|
||||
)
|
||||
|
||||
def fake_run(args, settings):
|
||||
return {"ok": True, "args": args, "exit_code": 0, "stdout": "done", "stderr": ""}
|
||||
|
||||
monkeypatch.setattr("reyna_cli.web.run_reyna_cli", fake_run)
|
||||
client = TestClient(app)
|
||||
response = client.post("/api/run", json={"command": "doctor --json"})
|
||||
assert response.status_code == 200
|
||||
payload = response.json()
|
||||
assert payload["ok"] is True
|
||||
assert payload["args"] == ["doctor", "--json"]
|
||||
assert payload["stdout"] == "done"
|
||||
|
||||
|
||||
def test_normalize_args_refuses_nested_server():
|
||||
try:
|
||||
normalize_args(RunRequest(command="--help web"))
|
||||
except Exception as exc:
|
||||
assert getattr(exc, "status_code", None) == 400
|
||||
else:
|
||||
raise AssertionError("nested web command was not rejected")
|
||||
|
||||
|
||||
def test_custom_tts_rejects_raw_text_placeholder(tmp_path):
|
||||
try:
|
||||
_custom_tts("hello", tmp_path / "audio", "printf {raw_text}", None)
|
||||
except TTSError as exc:
|
||||
assert "raw_text" in str(exc)
|
||||
else:
|
||||
raise AssertionError("raw_text placeholder was not rejected")
|
||||
Reference in New Issue
Block a user