Files
roa2web-service-auto/backend/modules/service_auto/tests/test_grants_integration.py
2026-06-05 15:00:42 +00:00

179 lines
6.5 KiB
Python

"""
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"