""" Integration tests — Hypothesis #3: ROA_WEB grant-scoped access. Proves: - ROA_WEB cannot INSERT directly into MARIUSM_AUTO.NOM_LUCRARI → ORA-01031 or ORA-00942 - ROA_WEB cannot SELECT directly from MARIUSM_AUTO.NOM_LUCRARI → ORA-00942 - ROA_WEB CAN execute SP_CREEAZA_COMANDA_PROTOTIP via EXECUTE grant → no privilege error All tests skip gracefully when: - backend/secrets/roa_web.oracle_pass is absent (user not yet created) - ORA-01017 on connect (user doesn't exist / wrong password) Reference: docs/service-auto/grants-audit.md §3.1 """ import os import pytest import oracledb # --------------------------------------------------------------------------- # Oracle connection constants (MARIUSM_AUTO on central server) # --------------------------------------------------------------------------- _HOST = "10.0.20.121" _PORT = 1521 _SERVICE_NAME = "ROA" _ROA_WEB_USER = "ROA_WEB" _SECRETS_DIR = os.path.normpath( os.path.join(os.path.dirname(__file__), "..", "..", "..", "secrets") ) def _read_roa_web_password() -> str | None: """Return ROA_WEB password from secrets file, or None if not present.""" path = os.path.join(_SECRETS_DIR, "roa_web.oracle_pass") if not os.path.exists(path): return None with open(path) as f: return f.read().strip() or None # --------------------------------------------------------------------------- # Shared fixture — one connection per test module # --------------------------------------------------------------------------- @pytest.fixture(scope="module") def roa_web_connection(): """ Yields a sync oracledb.Connection as ROA_WEB. Skips the whole module if the user does not yet exist on the server. """ password = _read_roa_web_password() if not password: pytest.skip( "ROA_WEB password file not found in backend/secrets/ — " "user not yet created (Phase B deferred, see grants-audit.md §3)" ) try: conn = oracledb.connect( user=_ROA_WEB_USER, password=password, host=_HOST, port=_PORT, service_name=_SERVICE_NAME, ) except oracledb.DatabaseError as e: err = e.args[0] code = getattr(err, "code", 0) if code == 1017: pytest.skip( f"ROA_WEB login failed (ORA-01017: invalid username/password) — " "user not yet created on Oracle server" ) raise # unexpected error — let it surface yield conn conn.close() # --------------------------------------------------------------------------- # Negative tests — direct DML/SELECT must be rejected # --------------------------------------------------------------------------- @pytest.mark.integration def test_insert_direct_fails(roa_web_connection): """ ROA_WEB has no INSERT privilege on NOM_LUCRARI. Expected: ORA-01031 (insufficient privileges) or ORA-00942 (no table grant). """ conn = roa_web_connection with conn.cursor() as cur: with pytest.raises(oracledb.DatabaseError) as exc_info: cur.execute( "INSERT INTO MARIUSM_AUTO.NOM_LUCRARI (nrord, id_mod) " "VALUES ('TEST_GRANT_PROBE', 1200)" ) err = exc_info.value.args[0] assert err.code in (1031, 942), ( f"Expected ORA-01031 or ORA-00942, got ORA-{err.code}: {err.message}" ) @pytest.mark.integration @pytest.mark.skip( reason=( "Obsolete premise: ff_2026_04_13_01_AUTO.sql granted SELECT on " "NOM_LUCRARI to ROA_WEB (needed by /api/service-auto/operatii). " "Assertion ORA-00942 no longer holds. Rework or remove — see " "docs/service-auto/decision-log.md (2026-04-13)." ) ) def test_select_direct_fails(roa_web_connection): """ ROA_WEB has no SELECT privilege on NOM_LUCRARI. Expected: ORA-00942 (table or view does not exist). """ conn = roa_web_connection with conn.cursor() as cur: with pytest.raises(oracledb.DatabaseError) as exc_info: cur.execute( "SELECT COUNT(*) FROM MARIUSM_AUTO.NOM_LUCRARI WHERE ROWNUM < 2" ) cur.fetchone() err = exc_info.value.args[0] assert err.code == 942, ( f"Expected ORA-00942, got ORA-{err.code}: {err.message}" ) # --------------------------------------------------------------------------- # Positive test — SP execution must succeed (EXECUTE grant) # --------------------------------------------------------------------------- @pytest.mark.integration @pytest.mark.skip( reason=( "Obsolete target SP: commit 9cd7f35 migrated comanda creation to " "PACK_AUTO (+PACK_SERII_NUMERE). SP_CREEAZA_COMANDA_PROTOTIP is no " "longer invoked by production code; signature drift causes " "PLS-00306. Rewrite against PACK_AUTO.DEV_ADAUGA_LUCRARE or remove " "— see docs/service-auto/decision-log.md (2026-04-13)." ) ) def test_exec_sp_succeeds(roa_web_connection): """ ROA_WEB has EXECUTE on SP_CREEAZA_COMANDA_PROTOTIP. The SP call must not raise ORA-01031 (insufficient privileges). A FK violation (ORA-02291) is acceptable — it proves the SP was reached. Transaction is always rolled back — no test data left in prod. """ conn = roa_web_connection with conn.cursor() as cur: out_id_ordl = cur.var(oracledb.NUMBER) out_nrord = cur.var(oracledb.STRING) try: cur.callproc( "MARIUSM_AUTO.SP_CREEAZA_COMANDA_PROTOTIP", [ 1, # p_tip (FK DEV_TIP_DEVIZ) 1, # p_id_masiniclient (placeholder) "TEST GRANT PROBE", # p_solicitari 1, # p_id_firma out_id_ordl, out_nrord, ], ) except oracledb.DatabaseError as e: conn.rollback() err = e.args[0] # ORA-02291: FK violation — SP ran, data was bad → EXECUTE grant works if err.code == 2291: return # ORA-01031: execution was blocked → grant missing → test must fail raise conn.rollback() # ALWAYS rollback — never persist test data id_ordl = out_id_ordl.getvalue() nrord = out_nrord.getvalue() assert id_ordl is not None, "SP must return a non-null p_id_ordl" assert nrord, "SP must return a non-empty p_nrord"