Observed contract failure
At commit f3475cf000a379732d37cfb317754dec5ef2b4db, RhoConservativeSqlGuard accepts or rejects SQL from its first token plus a forbidden-keyword regular expression. That is not a statement parser and does not establish the package's read-only claim.
An executed local canary used a fresh in-memory DuckDB database and a temporary output directory:
sql <- sprintf(
"SELECT 1 AS accepted_prefix; EXPORT DATABASE '%s' (FORMAT PARQUET)",
outdir
)
decision <- rho_check_readonly_sql(sql)
result <- rho_await(rho_sql_all(conn, sql), timeout = 5000)
Observed:
decision=RhoSqlAccepted
output_dir=TRUE
files=canary.parquet,load.sql,schema.sql
The same lexical design omits other statement families such as SET, CALL, and broad PRAGMA behavior. A SELECT statement can also invoke table functions that read undeclared paths or remote resources. “Starts with SELECT” and “contains no listed write word” are therefore neither single-statement validation nor resource admission.
Required contract
Use DuckDB's parser/AST serialization (for example json_serialize_sql) as the semantic authority:
- Parse first and require exactly one statement.
- Admit explicit read-only statement and expression classes; reject unknown AST nodes fail-closed.
- Inspect relation references, table functions, extension operations, path/URI literals, secrets, and external-access functions against host-supplied capabilities.
- Execute the same admitted statement, not a separately reinterpreted string.
- Keep SQL syntax admission separate from relation/path/network authority.
- Return a typed rejection containing the rejected AST class and policy reason without echoing secrets.
This must land before rho.bio.agent exposes model-authored query execution.
Acceptance evidence
- comments and quoted keywords do not cause false decisions;
- a second statement is rejected regardless of its spelling;
EXPORT, IMPORT, COPY, ATTACH, INSTALL, LOAD, mutating PRAGMA, SET, and effectful CALL cases fail closed;
- CTEs and ordinary nested read-only queries remain accepted;
- undeclared relations and path/remote table functions are rejected by capability policy;
- parser failure and a newly encountered AST class produce typed rejection;
- an executed canary proves no filesystem artifact or session mutation occurs after rejection.
Prepared in Pi using GPT Sol 5.6 High; the canary above was executed locally and cleaned up before filing.
Observed contract failure
At commit
f3475cf000a379732d37cfb317754dec5ef2b4db,RhoConservativeSqlGuardaccepts or rejects SQL from its first token plus a forbidden-keyword regular expression. That is not a statement parser and does not establish the package's read-only claim.An executed local canary used a fresh in-memory DuckDB database and a temporary output directory:
Observed:
The same lexical design omits other statement families such as
SET,CALL, and broadPRAGMAbehavior. ASELECTstatement can also invoke table functions that read undeclared paths or remote resources. “Starts with SELECT” and “contains no listed write word” are therefore neither single-statement validation nor resource admission.Required contract
Use DuckDB's parser/AST serialization (for example
json_serialize_sql) as the semantic authority:This must land before
rho.bio.agentexposes model-authored query execution.Acceptance evidence
EXPORT,IMPORT,COPY,ATTACH,INSTALL,LOAD, mutatingPRAGMA,SET, and effectfulCALLcases fail closed;Prepared in Pi using GPT Sol 5.6 High; the canary above was executed locally and cleaned up before filing.