from pathlib import Path def test_login_page_does_not_disclose_demo_passwords(client): response = client.get('/auth/login') assert response.status_code == 200 assert b'admin' not in response.data assert b'adminadmin' not in response.data def test_login_rejects_external_next_url(client, admin_user): response = client.post( '/auth/login?next=//example.net', data={'username': admin_user['username'], 'password': admin_user['password']}, ) assert response.status_code == 302 assert 'example.net' not in response.headers['Location'] def test_setup_requires_token(client, monkeypatch, tmp_path): from app_new.core.routes import setup_wizard monkeypatch.setattr(setup_wizard, 'DATA_DIR', str(tmp_path)) assert client.get('/setup-wizard/').status_code == 403 assert client.get('/setup-wizard/?token=invalid').status_code == 403 def test_setup_token_is_removed_from_url(client, monkeypatch, tmp_path): from app_new.core.routes import setup_wizard monkeypatch.setattr(setup_wizard, 'DATA_DIR', str(tmp_path)) token = 'test-setup-token-with-at-least-32-characters' response = client.get(f'/setup-wizard/?token={token}') assert response.status_code == 302 assert 'token=' not in response.headers['Location'] assert client.get('/setup-wizard/').status_code == 200 def test_completed_setup_rejects_mutation(client, monkeypatch, tmp_path): from app_new.core.routes import setup_wizard monkeypatch.setattr(setup_wizard, 'DATA_DIR', str(tmp_path)) Path(tmp_path, '.setup_complete').write_text('complete', encoding='utf-8') response = client.post('/setup-wizard/api/step/1', json={ 'username': 'new-admin', 'password': 'a-strong-password', }) assert response.status_code == 403