Add approval-gated SQL writes without exposing DATABASE_URL
Read-only gates protect production and create ticket traffic for routine INSERT / bounded UPDATE work. Deny-all-writes and allow-all-writes are both wrong. Prefer: reads execute, writes park for approval, schema changes deny.
Configure approval-gated writes
Keep sql.read allowed, park sql.write, deny sql.ddl. Expose limetry_sql_query and limetry_sql_list_pending. The agent still never sees DATABASE_URL.
import { SqlActionGate } from "@limetry/sql"
const gate = new SqlActionGate({
connectionString: process.env.DATABASE_URL!,
apiKey: process.env.LIMETRY_API_KEY!,
baseUrl: process.env.LIMETRY_BASE_URL,
policyId: process.env.LIMETRY_SQL_POLICY_ID!,
agentId: "sql_mcp",
resourceLabel: "postgres://analytics",
dryRun: false,
})
const result = await gate.evaluateAndMaybeExecute({
sql: "INSERT INTO experiment_results (experiment_id, variant, conversions) VALUES ('exp_42', 'B', 17)",
execute: true,
})
if (result.evaluation.decision === "approval_required") {
process.stdout.write(JSON.stringify(gate.listPending(), null, 2))
}
{
"allowed_action_types": ["sql.read", "sql.write"],
"denied_action_types": ["sql.ddl"],
"require_approval_action_types": ["sql.write"],
"audit_mode": "minimal"
}
A production DELETE still classifies as sql.write and parks — it does not auto-execute. DROP TABLE is sql.ddl and still deny. Approval-gated writes do not create approval-gated schema changes. Operators approve via the approval API.
Review pending INSERT before retry
First INSERT returns approval_required:
{
"sql_class": "write",
"decision": "approval_required",
"approval_id": "apr_01j7m2k8",
"executed": false,
"reasons": [
"action_type sql.write requires human approval"
]
}
Open limetry_sql_list_pending, review the truncated preview, approve, and retry. On retry, Limetry returns allow, the gate executes, and the decision receipt ties execution to the approved intent. Reject broad UPDATE / DELETE shapes; require a narrowed WHERE and a new park.
Measure the first enforced week
Example targets:
- 243 read queries allowed and executed.
- 47 write queries returned
approval_required. - 44 writes approved and retried successfully.
- 3 writes rejected for broad predicates.
- 0 DDL statements executed.
Ticket traffic moves from "run this SQL" to "approve this evaluated intent." Audit shows every write with the approver's identity. The agent gains write access without seeing DATABASE_URL.
Incident that made read-only the default: Deny sql.write before the database sees a mass DELETE. Origin: Gate SQL writes so agents never hold DATABASE_URL.
