Check analysis tool
The CheckAnalysisTool, which an agent sees as CheckAnalysis, inspects analysis code before
something else runs it. Code in, plus the tables the caller is willing to expose; a verdict out.
It exists for the case where a model authors freeform Spark SQL, PySpark, Scala or SparkR and something downstream submits it against a live cluster. A prompt asking the model to behave, plus a denylist of dangerous tokens at the far end, is not a control — a denylist is incomplete by construction, and it is the thing being replaced here.
It executes nothing. No endpoint, no submission, no engine, and it returns no query results. That is deliberate twice over: the executor generally lives outside the cluster, and a tool that POSTs to a configured URL from inside the cluster would be an arbitrary-fetch primitive — an embarrassing thing to add while adding a safety check.
A question about the data itself belongs to a tool that searches, such as
SearchIndexTool.
Parameters
| Parameter | Required | Default | Description |
|---|---|---|---|
code | Yes | The analysis code to check. | |
language | No | sql | The language the code is written in: sql, python, scala or r. |
tables | No | (empty) | Comma-separated list of tables the caller is willing to have read. An empty list permits nothing. |
What it actually checks
For SQL the answer is close to sound:
- One statement. A benign read cannot carry a second thing after a semicolon.
- It must begin as a read —
SELECTorWITH. That is an allowlist: nothing is inferred from the absence of something bad. - Every table it touches must have been named in advance, in
tables. - Comments are stripped first, because a comment can hide a keyword from a naive scan while the engine still parses what surrounds it. The check has to see what the engine sees.
Names bound by a WITH clause are not tables anybody grants access to, so they are not required in
the allowlist. Naming one after a real table buys no reach — the tables inside its body are scanned
like any other.
The three verdicts
Collapsing the first two is the failure this tool exists to prevent, so they stay distinguishable in the answer.
| Verdict | Meaning |
|---|---|
CLEARED | Fully checked against the allowlist, and it passed. |
SQL_CLEARED_HOST_UNCHECKED | The embedded SQL passed. The host language around it was never examined. |
REFUSED | Something in it is not permitted. The answer says what. |
SQL_CLEARED_HOST_UNCHECKED is not a pass. Real notebooks are Scala, PySpark or R handing a SQL
string to spark.sql, sqlContext.sql or SparkR::sql. The string can be checked exactly. The code
around it cannot: it can compute the query, reach a filesystem, open a socket or call into the JVM,
and no pattern over source text closes that.
Treat this verdict as "the query is fine and the program is unknown", and decide what runs it accordingly.
An empty table list refuses everything
That is the intended default: a caller that did not say what it would expose has exposed nothing. A bare refusal on a well-formed query would read as a bug, so the answer says explicitly that the allowlist was empty rather than only that the code was refused.
Register a flow agent that runs the CheckAnalysisTool
POST /_plugins/_agent/agents/_register
{
"name": "Analysis_Check_Agent",
"type": "flow",
"description": "checks analysis code before anything runs it",
"tools": [
{
"type": "CheckAnalysisTool",
"name": "DemoCheckAnalysisTool",
"parameters": {
"tables": "orders,customers"
}
}
]
}
Execute it with the code to check:
POST /_plugins/_agent/agents/<agent_id>/_execute
{
"parameters": {
"code": "SELECT customer_id, SUM(total) FROM orders GROUP BY customer_id",
"language": "sql",
"tables": "orders,customers"
}
}
It is not a sandbox
Worth stating plainly, because a checker in front of a dangerous operation invites the assumption that the result is safe. It is not that. SQL gets close to a sound answer. A host language gets an explicit statement that it was not looked at. Everything else about how the code is executed — credentials, network reach, what the executing engine will accept — is outside this tool.