Skip to main content

Validate statements, TLS and credentials

Building a connector, step 7 (SQL track, 3 of 3). Previous: Statements and Grant kinds.

Before you run a single statement against the application's data, ask the database whether it accepts them. Every SQL connector has a handler for that, connection.validateStatements, which checks every statement without executing any. This page also covers how the gateway connects: TLS, and the username and password.

Validate statements​

connection.validateStatements asks the database to plan or compile each statement the definition runs. It binds every placeholder to null, because it checks the statement, not values. Each dialect checks without executing:

DialectHow the database checks a statement
PostgresEXPLAIN (ANALYZE false, COSTS false) on the statement, inside a read-only transaction that is always rolled back.
MySQLPREPARE and then DEALLOCATE PREPARE: the statement is parsed and its names resolved, and nothing is evaluated.
SQL Serversp_describe_first_result_set with the statement passed as a parameter: it is compiled and analyzed, and not executed.
OracleEXPLAIN PLAN FOR the statement, with the plan it writes rolled back.

The result names each statement by where the definition defines it:

KeyStatement
validationQueryThe connection test query
entities.<key>.syncThe entity's source: its selectStatement, or the SELECT built from its table and where
entities.<key>.statements.<operation>A write statement: create, update, delete, enable or disable
entities.<key>.createdIdThe entity's createdId query
grants.<kind>.select, grants.<kind>.add, grants.<kind>.removeA Grant kind's statements
{
"statements": {
"validationQuery": { "ok": true },
"entities.user.sync": { "ok": true },
"entities.user.statements.create": { "ok": true },
"grants.has_role.remove": { "ok": false, "message": "SQL postgres error 42703: column \"role\" does not exist" }
}
}

The input { "keys": ["grants.has_role.add", "grants.has_role.remove"] } limits the check to those statements. With no input, every statement is checked.

Validation proves that each statement in the table above parses and names real tables and columns. It does not prove the statement does the right thing: an UPDATE with the wrong WHERE validates. That is what testing is for.

It also checks only those statements, never the queries the engine builds around them: the paged, incremental and single-record reads of each entity, and each Grant kind's reads by target. Column names that appear only in those queries are checked for their spelling as identifiers, not against the database: orderKey, updatedAt, sourceColumn, targetColumn and the entity's identifier. So a misspelled orderKey, or an ORDER BY inside a selectStatement on SQL Server, validates cleanly and then fails on the first Sync. Run fetchAll, fetchOne and each Grant kind's relationship read once in a draft test before you publish.

In the Connector Builder​

On the Statements tab, the Validate section has a button for the selected entity, such as Validate user's statements, and Validate every statement. The Grant kinds tab has Validate every statement too. Validation runs on your tenant's gateway with the Test panel's run config, and each statement's result appears below it.

In a draft test​

A draft test of a SQL connector, validation included, runs your unpublished statements on your tenant's gateway with the credentials you type. Owlie treats that like publishing, so it needs the custom_connector.publish permission (the owner and admin roles have it by default), not only the permission to edit connectors. Point draft tests at a test database.

Validation runs without your consent to writes. Every other handler of a SQL draft, the connection test and every read included, counts as a write: the gateway cannot prove that authored statement text only reads, so the builder asks Run followed by the handler key and against the real system? before it runs one, and runs it when you select Run it. Through the API, a draft test of any handler but connection.validateStatements and connection.validateConfig needs "allow_writes": true.

Through the API, send every install field the test needs; Owlie fills in no defaults. Include dialect, or the gateway connects with its Postgres driver whatever your definition says, and type the password itself. A gateway secret name in its place is refused. gateway_id chooses the gateway; without it the test runs on your tenant's one active gateway.

{
"procedure": "connectors.testArtifact",
"input": {
"connector_id": "<connector id>",
"version_id": "<draft version id>",
"artifact_key": "connection.validateStatements",
"test_input": {},
"gateway_id": "<gateway id>",
"integration_config": {
"config": {
"dialect": "postgres",
"host": "db-test.acmeledger.example",
"port": 5432,
"database": "ledger_test"
},
"auth": { "key": "password", "config": { "user": "owlie_test", "password": "<test password>" } }
}
}
}

The same body with "artifact_key": "user.fetchAll" and "allow_writes": true reads the first page of users, as many rows as the definition's pageSize. Install-editable values you leave out of config take their seeds. Build with the API and agents describes the endpoint and the response.

TLS​

The install's ssl field decides how the gateway encrypts the connection:

sslConnectionNeeds the operator's allowTlsOverrides
Absent, or trueTLS, with the server's certificate verifiedNo
{ "caCert": "<PEM>" }TLS, verified against the certificate authority you giveYes
{ "rejectUnauthorized": false }TLS, without verifying the server's certificateYes
falseNo TLS, for a database on your network that does not offer itYes

Without allowTlsOverrides for the connector, the gateway refuses a connection that asks for any of the last three, and says which setting the operator needs. It never falls back silently. The ssl object accepts only caCert and rejectUnauthorized. The operator sets allowTlsOverrides in the gateway's configuration (Private-network gateways).

The username and password​

A SQL connector has one way to sign in, Username and password, with the fields user and password.

  • Installs do not give the password to Owlie. For an install on a gateway, the password field takes the name of a gateway secret: the install form asks for the gateway environment variable name, and the gateway reads the value from OWLIE_SECRET_<NAME> or its secrets file. The operator must also grant that name to the connector.
  • Draft tests take typed credentials in the Test panel's run config. The gateway resolves none of its own secrets for a draft, and scrubs the typed values from its logs and error messages.

Give the database user only what the connector's statements need: read on the tables and views Sync reads, and write on the tables the write statements change.

Next: Test your connector