import os import subprocess import sys from dataclasses import replace import pytest from parser_lab.auth import Auth, Unauthorized from parser_lab.config import Settings from parser_lab.repository import Repository from parser_lab import cli def settings_from_env(monkeypatch, tmp_path): monkeypatch.setenv('LAB_ADMIN_USER', 'teacher') monkeypatch.setenv('LAB_ADMIN_PASSWORD', "мой пароль $ # ' \\ test") monkeypatch.setenv('LAB_SECRET', 'test-secret-at-least-32-characters') monkeypatch.setenv('LAB_DATA_DIR', str(tmp_path / 'data')) monkeypatch.delenv('LAB_ADMIN_HASH', raising=False) return Settings.from_env() def test_password_env_login_restart_and_change(monkeypatch, tmp_path): settings = settings_from_env(monkeypatch, tmp_path) password = os.environ['LAB_ADMIN_PASSWORD'] assert password not in repr(settings) repo = Repository(settings.data_dir) auth = Auth(settings, repo) token = auth.login('teacher', password, 'client') assert Auth(Settings.from_env(), repo).check(token) == token with pytest.raises(Unauthorized): auth.login('teacher', password + 'x', 'client') changed = Auth(replace(settings, password='replacement-password'), repo) with pytest.raises(Unauthorized): changed.check(token) with pytest.raises(Unauthorized): changed.login('teacher', password, 'client') assert changed.login('teacher', 'replacement-password', 'client') @pytest.mark.parametrize('password', ['', 'short']) def test_invalid_env_password(monkeypatch, tmp_path, password): settings_from_env(monkeypatch, tmp_path) monkeypatch.setenv('LAB_ADMIN_PASSWORD', password) with pytest.raises(ValueError, match='LAB_ADMIN_PASSWORD'): Settings.from_env() def test_init_env_plaintext_password_loads_with_uv(monkeypatch, tmp_path): path = tmp_path / '.env' password = "тест $HOME ${UNKNOWN} # ' \\ end" monkeypatch.setattr(sys, 'argv', ['cli', 'init-env', '--path', str(path)]) monkeypatch.setattr('builtins.input', lambda _: 'teacher') monkeypatch.setattr(cli.getpass, 'getpass', lambda _: password) cli.main() text = path.read_text(encoding='utf-8') assert 'LAB_ADMIN_PASSWORD=' in text and 'LAB_ADMIN_HASH=' not in text env = {k: v for k, v in os.environ.items() if not k.startswith('LAB_')} env['EXPECTED_PASSWORD'] = password result = subprocess.run( ['uv', 'run', '--no-project', '--env-file', str(path), sys.executable, '-c', 'import os; assert os.environ["LAB_ADMIN_PASSWORD"] == os.environ["EXPECTED_PASSWORD"]'], env=env, capture_output=True, text=True, ) assert result.returncode == 0, result.stderr with pytest.raises(SystemExit, match='уже существует'): cli.main()