"""Teil D.6 Schritt 7: vollstaendig neu geschrieben (Umsetzungsauftrag_ Sonnet5.md D.6 Schritt 7 nennt diese Datei ausdruecklich als Beispiel -- sie schrieb direkt in user_hostgroup_roles, das app/rbac.py seit Schritt 4 nicht mehr liest und das seit Migration 0019 (Schritt 5) nicht mehr unter diesem Namen existiert -- die Tabelle heisst jetzt user_hostgroup_roles_legacy). Rechte werden ausschliesslich noch ueber Benutzergruppen vergeben (group_hostgroup_roles), daher seeden alle Tests hier ueber eine Gruppe.""" import pytest import aiosqlite from app.db import MIGRATIONS_DIR from app.rbac import user_has_role, user_has_role_for_host async def _fresh_db() -> aiosqlite.Connection: conn = await aiosqlite.connect(":memory:") for migration_file in sorted(MIGRATIONS_DIR.glob("*.sql")): await conn.executescript(migration_file.read_text(encoding="utf-8")) return conn @pytest.mark.asyncio async def test_rbac_grants_and_expiry(): conn = await _fresh_db() await conn.execute("INSERT INTO users (id, username, password_hash) VALUES (1, 'alice', 'x')") await conn.execute("INSERT INTO host_groups (id, name) VALUES (1, 'linux-prod')") await conn.execute( "INSERT INTO hosts (id, host_group_id, hostname, address, protocol, port, os_type) " "VALUES (1, 1, 'db01', '10.0.0.1', 'ssh', 22, 'linux')" ) await conn.execute("INSERT INTO user_groups (id, name) VALUES (1, 'alice-team')") await conn.execute("INSERT INTO user_group_members (user_group_id, user_id) VALUES (1, 1)") await conn.commit() assert not await user_has_role(conn, user_id=1, host_group_id=1, role_name="ssh_connect") await conn.execute( "INSERT INTO group_hostgroup_roles (user_group_id, host_group_id, role_id) VALUES (1, 1, 1)" ) await conn.commit() assert await user_has_role(conn, user_id=1, host_group_id=1, role_name="ssh_connect") assert await user_has_role_for_host(conn, user_id=1, host_id=1, role_name="ssh_connect") assert not await user_has_role_for_host(conn, user_id=1, host_id=1, role_name="rdp_connect") # Abgelaufene Freigabe darf nicht mehr gelten. await conn.execute( "UPDATE group_hostgroup_roles SET expires_at = '2000-01-01T00:00:00.000000Z' " "WHERE user_group_id = 1 AND host_group_id = 1 AND role_id = 1" ) await conn.commit() assert not await user_has_role(conn, user_id=1, host_group_id=1, role_name="ssh_connect") await conn.close() @pytest.mark.asyncio async def test_rbac_role_survives_via_second_group_after_first_expires(): """S1 (Umsetzungsauftrag_Sonnet5.md Teil D.2): ein Benutzer kann dieselbe Rolle ueber MEHRERE Gruppen halten -- laeuft die Freigabe einer Gruppe ab, darf das Recht bestehen bleiben, solange eine andere Gruppe es weiterhin gewaehrt (genau das macht GET /admin/roles seit Teil D Schritt 5 ueber die Spalte via_group_name sichtbar).""" conn = await _fresh_db() await conn.execute("INSERT INTO users (id, username, password_hash) VALUES (1, 'bob', 'x')") await conn.execute("INSERT INTO host_groups (id, name) VALUES (1, 'linux-prod')") await conn.execute("INSERT INTO user_groups (id, name) VALUES (1, 'team-a'), (2, 'team-b')") await conn.execute( "INSERT INTO user_group_members (user_group_id, user_id) VALUES (1, 1), (2, 1)" ) await conn.execute( "INSERT INTO group_hostgroup_roles (user_group_id, host_group_id, role_id, expires_at) " "VALUES (1, 1, 1, '2000-01-01T00:00:00.000000Z'), (2, 1, 1, NULL)" ) await conn.commit() assert await user_has_role(conn, user_id=1, host_group_id=1, role_name="ssh_connect") await conn.close() @pytest.mark.asyncio async def test_rbac_role_does_not_leak_across_host_groups(): """Eine Rolle auf Hostgruppe 1 darf keinen Zugriff auf Hostgruppe 2 gewaehren.""" conn = await _fresh_db() await conn.execute("INSERT INTO users (id, username, password_hash) VALUES (1, 'carol', 'x')") await conn.execute( "INSERT INTO host_groups (id, name) VALUES (1, 'linux-prod'), (2, 'linux-test')" ) await conn.execute("INSERT INTO user_groups (id, name) VALUES (1, 'carol-team')") await conn.execute("INSERT INTO user_group_members (user_group_id, user_id) VALUES (1, 1)") await conn.execute( "INSERT INTO group_hostgroup_roles (user_group_id, host_group_id, role_id) VALUES (1, 1, 1)" ) await conn.commit() assert await user_has_role(conn, user_id=1, host_group_id=1, role_name="ssh_connect") assert not await user_has_role(conn, user_id=1, host_group_id=2, role_name="ssh_connect") await conn.close()