"""D7: read-only enforcement lives in the execute layer, not only in CLI callers. assert_read_only is the shared structural guard both codepaths (direct + REST) call, so reusing the execute API (e.g. from the backend) cannot bypass single-statement + SELECT-only. Pins that writes/multi-statement are rejected with ExecutionError. """ import pytest from tht.execute import ExecutionError, assert_read_only @pytest.mark.parametrize( "sql", [ "DELETE FROM pazienti", "UPDATE pazienti SET x = 1", "INSERT INTO pazienti VALUES (1)", "DROP TABLE pazienti", "SELECT 1; DROP TABLE pazienti", # multi-statement "TRUNCATE pazienti", ], ) def test_write_or_multistatement_rejected(sql): with pytest.raises(ExecutionError): assert_read_only(sql) @pytest.mark.parametrize( "sql", [ "SELECT 1", "WITH x AS (SELECT 1) SELECT * FROM x", "SELECT a FROM t UNION SELECT b FROM u", ], ) def test_select_allowed(sql): assert_read_only(sql) # no raise