1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2026-11-08 19:26:48 +00:00
webvirtcloud/console/test_socketiod_disabled.py
catborise 1547e58e55 fix(console): disable the unauthenticated serial console by default
socketiod does not validate the console token, keeps a single global PTY
and broadcasts its output to every connected client, so anyone who can
reach port 6081 can read and write a serial console that someone opened.
It is also broken for legitimate users, since console/views.py now writes
signed tokens that socketiod cannot parse.

Until it is rewritten, turn the serial console off by default:

- Add SERIAL_CONSOLE_ENABLED = False to the settings template; installs
  whose settings.py lacks it are treated as disabled.
- The console view shows an error instead of the xterm page for pty
  consoles while the setting is off.
- socketiod refuses to start unless SERIAL_CONSOLE_ENABLED is True.
- Supervisor: autostart=false for socketiod; drop -d (debug) from the
  supervisor and systemd definitions; fix the systemd unit description;
  conf/systemd/install.sh no longer suggests enabling socketiod.
- README: stop opening port 6081 and document how to enable the serial
  console on a trusted network.
2026-10-02 17:22:20 +03:00

57 lines
2.2 KiB
Python

import os
import signal
import subprocess
import sys
import unittest
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
SOCKETIOD = ROOT / "console" / "socketiod"
class SocketiodDisabledTestCase(unittest.TestCase):
"""ROADMAP S-01: socketiod must refuse to start unless explicitly enabled."""
def test_socketiod_exits_when_serial_console_disabled(self):
settings_dir = ROOT / "console" / "_test_settings"
settings_dir.mkdir(exist_ok=True)
try:
(settings_dir / "__init__.py").write_text("")
(settings_dir / "disabled.py").write_text(
"from webvirtcloud.settings import * # noqa\n"
"SERIAL_CONSOLE_ENABLED = False\n"
"SOCKETIO_HOST = '127.0.0.1'\n"
"SOCKETIO_PORT = 0\n"
)
env = dict(
os.environ,
DJANGO_SETTINGS_MODULE="console._test_settings.disabled",
PYTHONPATH=str(ROOT),
)
# Other test modules import novncd, which sets SIGCHLD to SIG_IGN in
# this process; with that, the child's exit status is lost (always 0).
previous_sigchld = signal.signal(signal.SIGCHLD, signal.SIG_DFL)
try:
result = subprocess.run(
[sys.executable, str(SOCKETIOD)],
cwd=ROOT,
env=env,
capture_output=True,
text=True,
timeout=20,
)
except subprocess.TimeoutExpired:
self.fail("socketiod kept running although SERIAL_CONSOLE_ENABLED=False")
finally:
signal.signal(signal.SIGCHLD, previous_sigchld)
self.assertNotEqual(result.returncode, 0, result.stdout + result.stderr)
self.assertIn("SERIAL_CONSOLE_ENABLED", result.stderr)
finally:
for f in settings_dir.glob("*"):
if f.is_file():
f.unlink()
for d in settings_dir.glob("__pycache__"):
for f in d.glob("*"):
f.unlink()
d.rmdir()
settings_dir.rmdir()