utils/sql_drills/sql_drills/_secret.py
Krzysztof kuhy Rudnicki de7d5d17eb sql_drills: no root shell for learner SQL
Learner SQL piped into the mysql client could run `\! id` as container
root and read every DB. Now: --binary-mode (client commands error out),
a refused-backslash-line guard, learner exec as uid 65534, and a random
root password (0600 file, via env, adopted live on a legacy container).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WzxdWYGW5NZL5uVpnqmNKo
2026-11-02 16:05:59 +01:00

39 lines
1.2 KiB
Python

"""The MySQL root password: random, 0600, readable only by this engine.
The container's root used to be passwordless, so anything that reached a shell
in it (a backslash-bang meta-command) owned every database. Now root has this
password; learner SQL runs as a per-run user that never sees it.
"""
from __future__ import annotations
import contextlib
import os
import secrets
from sql_drills import _paths
_FILE = "root_password"
def root_password() -> str:
"""Read the password, creating it on first use.
The file appears complete or not at all: written to a private temp name,
then hard-linked into place (which fails if another process won the race).
"""
path = _paths.config_dir() / _FILE
if path.exists():
return path.read_text(encoding="utf-8").strip()
path.parent.mkdir(parents=True, exist_ok=True, mode=0o700)
tmp = path.with_name(f".{_FILE}.{secrets.token_hex(4)}")
fd = os.open(tmp, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600)
with os.fdopen(fd, "w", encoding="utf-8") as handle:
handle.write(secrets.token_urlsafe(24) + "\n")
try:
with contextlib.suppress(FileExistsError):
os.link(tmp, path)
finally:
tmp.unlink()
return path.read_text(encoding="utf-8").strip()