@vericto/sdk 0.0.0-stage → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,83 @@
1
+ # Changelog
2
+
3
+ All notable changes to this package are documented here. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project uses
5
+ [Semantic Versioning](https://semver.org/).
6
+
7
+ ## [Unreleased]
8
+
9
+ ## [0.2.0] - 2026-10-16
10
+
11
+ ### Changed
12
+
13
+ - The package is now **`@vericto/sdk`** (it was `@vericto/vericto`, never
14
+ published). Entry points: `@vericto/sdk`, `@vericto/sdk/snowflake`,
15
+ `@vericto/sdk/better-sqlite3`, `@vericto/sdk/langchain`.
16
+
17
+ - Documentation: the Vericto server now evaluates the `sqlite` dialect
18
+ (vericto-engine 4.1.0; `GET /api/v1/meta/config` lists it), so
19
+ `@vericto/sdk/better-sqlite3` and `@vericto/sdk/langchain` on SQLite work
20
+ against it. The 0.1.0 known limitation no longer applies to such servers.
21
+ Unchanged behaviour: `guardDatabase()` still asks `/meta/config` and rejects
22
+ with `VerictoUnsupportedDialectError`, before any SQL runs, against a server
23
+ that does not list `sqlite`.
24
+
25
+ ### Added
26
+
27
+ - `@vericto/sdk/langchain`, for LangChain.js 1.x (`@langchain/classic`):
28
+ - `VerictoSqlDatabase`, a `SqlDatabase` whose TypeORM data source checks every
29
+ `query()` (agent queries, `getTableInfo` sample rows, `SqlDatabaseChain`).
30
+ BLOCKED returns a message with the rule, reason and suggested fix for the
31
+ model (`onBlock: 'return'`, default) or throws `VerictoBlockedError`
32
+ (`onBlock: 'raise'`); masked queries run as the rewrite; Vericto
33
+ unavailable/config errors are thrown, never returned to the model. Dialect
34
+ from the TypeORM type, or `dialect`.
35
+ - `VerictoQuerySqlTool` and `VerictoSqlToolkit` (for `createSqlAgent`), which
36
+ let Vericto errors through instead of turning them into text.
37
+ - `VerictoCheckSqlTool`, a check-only tool that returns the verdict.
38
+ - `guardDataSource`, `dialectFromDataSource`, `blockedMessage`,
39
+ `describeVerdict` helpers.
40
+ - Optional peer dependencies `@langchain/classic`, `@langchain/core`, `typeorm`.
41
+ Tested with `@langchain/classic` 1.0.52, `@langchain/core` 1.2.17,
42
+ `typeorm` 1.1.2.
43
+
44
+ - `test/live/sqlite.live.test.ts`: an opt-in end-to-end test of
45
+ `@vericto/sdk/better-sqlite3` against a real Runtime API (allowed statements,
46
+ UPSERT, the SQLite rules VERICTO-098/099/100/101, DELETE without WHERE, scripts
47
+ with a blocked statement). Skipped unless `VERICTO_LIVE_SQLITE=1` and the
48
+ `VERICTO_*` variables are set; see "Live tests" in the README.
49
+
50
+ ## [0.1.0] - unreleased (never published)
51
+
52
+ First release: Vericto checks in front of Node.js database drivers, evaluated by
53
+ the Vericto Runtime API (`POST /api/v1/proxy/query`).
54
+
55
+ ### Added
56
+
57
+ - `Vericto` guard: rejects with `VerictoBlockedError` on BLOCKED, runs the masked
58
+ `rewrittenQuery` for sensitive columns, logs FLAGGED / MONITORED / allowed
59
+ PARSE_ERROR verdicts and passes every verdict to `onVerdict`.
60
+ - Fail mode per guard: `closed` (default) rejects with `VerictoUnavailableError`
61
+ when Vericto cannot answer; `open` runs the statement and emits a
62
+ `VerictoFailOpenWarning` process warning. Configuration errors are never failed
63
+ open.
64
+ - `RuntimeApiEvaluator` on the global `fetch`: `VERICTO_*` environment
65
+ configuration as in vericto-cli, HTTPS-only key handling, timeouts, retries with
66
+ backoff on 5xx / 429 rate limits, `VerictoQuotaExceededError` for the monthly
67
+ quota, and dialect discovery through `GET /api/v1/meta/config`.
68
+ - `Evaluator` interface, so an embedded evaluator can be added later.
69
+ - `@vericto/vericto/snowflake`: `guardConnection()` for snowflake-sdk
70
+ (`execute` with the driver's options, callback or promise style, and `query`).
71
+ - `@vericto/vericto/better-sqlite3`: `guardDatabase()` (`prepare`, `exec`, `run`,
72
+ `all`, `get`).
73
+ - ESM and CommonJS builds with type declarations; Node.js 18+.
74
+ - Optional verdict cache (off by default).
75
+
76
+ ### Known limitations
77
+
78
+ - The Vericto engine does not evaluate the `sqlite` dialect yet:
79
+ `guardDatabase()` rejects with `VerictoUnsupportedDialectError` until the server
80
+ lists it.
81
+
82
+ [0.2.0]: https://github.com/vericto/vericto-node/releases/tag/v0.2.0
83
+ [0.1.0]: https://github.com/vericto/vericto-node/releases/tag/v0.1.0
package/LICENSE ADDED
@@ -0,0 +1,93 @@
1
+ Elastic License 2.0
2
+
3
+ URL: https://www.elastic.co/licensing/elastic-license
4
+
5
+ ## Acceptance
6
+
7
+ By using the software, you agree to all of the terms and conditions below.
8
+
9
+ ## Copyright License
10
+
11
+ The licensor grants you a non-exclusive, royalty-free, worldwide,
12
+ non-sublicensable, non-transferable license to use, copy, distribute, make
13
+ available, and prepare derivative works of the software, in each case subject to
14
+ the limitations and conditions below.
15
+
16
+ ## Limitations
17
+
18
+ You may not provide the software to third parties as a hosted or managed
19
+ service, where the service provides users with access to any substantial set of
20
+ the features or functionality of the software.
21
+
22
+ You may not move, change, disable, or circumvent the license key functionality
23
+ in the software, and you may not remove or obscure any functionality in the
24
+ software that is protected by the license key.
25
+
26
+ You may not alter, remove, or obscure any licensing, copyright, or other notices
27
+ of the licensor in the software. Any use of the licensor's trademarks is subject
28
+ to applicable law.
29
+
30
+ ## Patents
31
+
32
+ The licensor grants you a license, under any patent claims the licensor can
33
+ license, or becomes able to license, to make, have made, use, sell, offer for
34
+ sale, import and have imported the software, in each case subject to the
35
+ limitations and conditions in this license. This license does not cover any
36
+ patent claims that you cause to be infringed by modifications or additions to
37
+ the software. If you or your company make any written claim that the software
38
+ infringes or contributes to infringement of any patent, your patent license for
39
+ the software granted under these terms ends immediately. If your company makes
40
+ such a claim, your patent license ends immediately for work on behalf of your
41
+ company.
42
+
43
+ ## Notices
44
+
45
+ You must ensure that anyone who gets a copy of any part of the software from you
46
+ also gets a copy of these terms.
47
+
48
+ If you modify the software, you must include in any modified copies of the
49
+ software prominent notices stating that you have modified the software.
50
+
51
+ ## No Other Rights
52
+
53
+ These terms do not imply any licenses other than those expressly granted in
54
+ these terms.
55
+
56
+ ## Termination
57
+
58
+ If you use the software in violation of these terms, such use is not licensed,
59
+ and your licenses will automatically terminate. If the licensor provides you
60
+ with a notice of your violation, and you cease all violation of this license no
61
+ later than 30 days after you receive that notice, your licenses will be
62
+ reinstated retroactively. However, if you violate these terms after such
63
+ reinstatement, any additional violation of these terms will cause your licenses
64
+ to terminate automatically and permanently.
65
+
66
+ ## No Liability
67
+
68
+ As far as the law allows, the software comes as is, without any warranty or
69
+ condition, and the licensor will not be liable to you for any damages arising
70
+ out of these terms or the use or nature of the software, under any kind of
71
+ legal claim.
72
+
73
+ ## Definitions
74
+
75
+ The "licensor" is the entity offering these terms, and the "software" is the
76
+ software the licensor makes available under these terms, including any portion
77
+ of it.
78
+
79
+ "you" refers to the individual or entity agreeing to these terms.
80
+
81
+ "your company" is any legal entity, sole proprietorship, or other kind of
82
+ organization that you work for, plus all organizations that have control over,
83
+ are under the control of, or are under common control with that organization.
84
+ "control" means ownership of substantially all the assets of an entity, or the
85
+ power to direct its management and policies by vote, contract, or otherwise.
86
+ Control can be direct or indirect.
87
+
88
+ "your licenses" are all the licenses granted to you for the software under these
89
+ terms.
90
+
91
+ "use" means anything you do with the software requiring one of your licenses.
92
+
93
+ "trademark" means trademarks, service marks, and similar rights.
package/README.md CHANGED
@@ -1,3 +1,378 @@
1
- # Temporary Holding Version
1
+ Official Vericto SDK for Node.js: check SQL before it runs (snowflake-sdk, better-sqlite3, LangChain.js SQL agents and chains, and any driver through the Runtime API client).
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ # @vericto/sdk
4
+
5
+ > Check every SQL statement with [Vericto](https://vericto.com) **before** it runs:
6
+ > thin wrappers for `snowflake-sdk` and `better-sqlite3`, a LangChain.js
7
+ > integration for SQL agents, and a client for the Vericto Runtime API you can put
8
+ > in front of any driver.
9
+
10
+ Vericto is a deterministic SQL firewall: it parses each statement into an AST and
11
+ evaluates it against your workspace's rules (destructive statements, missing
12
+ `WHERE`/`LIMIT`, risky DDL, data exposure, sensitive columns, agent allowlists).
13
+ This package checks SQL before your driver runs it: blocked statements reject
14
+ before they reach the database, flagged ones run and are reported, and statements
15
+ that read masked columns run as the masked rewrite Vericto returns.
16
+
17
+ It is a thin client of the **Vericto Runtime API** (`POST /api/v1/proxy/query`).
18
+ Evaluation happens in your Vericto workspace; nothing is evaluated locally in this
19
+ release (see [Evaluators](#evaluators)).
20
+
21
+ - TypeScript types, ESM and CommonJS builds, Node.js 18+ (uses the global `fetch`).
22
+ - No runtime dependencies. Drivers and LangChain are optional peer dependencies
23
+ and separate entry points: importing `@vericto/sdk` never loads them.
24
+
25
+ ## Integrations
26
+
27
+ | Integration | Entry point | Peer dependencies | Status |
28
+ |---|---|---|---|
29
+ | snowflake-sdk | `@vericto/sdk/snowflake` | `snowflake-sdk` >= 1.9 | 0.1.0 |
30
+ | better-sqlite3 | `@vericto/sdk/better-sqlite3` | `better-sqlite3` >= 9 | 0.1.0 (see [SQLite status](#sqlite-status)) |
31
+ | LangChain.js SQL agents, tools and chains | `@vericto/sdk/langchain` | `@langchain/classic` 1.x, `@langchain/core` 1.x, `typeorm` | 0.2.0 |
32
+ | Any other driver | `@vericto/sdk` (`Vericto.enforce` / `prepare`) | none | 0.1.0 |
33
+
34
+ Python (snowflake-connector-python, sqlite3, SQLAlchemy, LangChain, LlamaIndex,
35
+ dbt and Airflow) lives in [vericto-python](https://github.com/vericto/vericto-python).
36
+
37
+ ## Install
38
+
39
+ ```bash
40
+ npm install @vericto/sdk
41
+ ```
42
+
43
+ ## Configure
44
+
45
+ Create an API key with the **`proxy:evaluate`** scope in the Vericto dashboard
46
+ (API keys) and register the database you are protecting. Then:
47
+
48
+ | Variable | Option | Meaning | Default |
49
+ |---|---|---|---|
50
+ | `VERICTO_API_KEY` | `apiKey` | API key (`vtro_...`), scope `proxy:evaluate` | required |
51
+ | `VERICTO_DATABASE_ID` | `databaseId` | The registered database (UUID): its rules, sensitive-column tags and agent allowlists apply | required |
52
+ | `VERICTO_API_URL` | `apiUrl` | API base URL | `https://api.vericto.com` |
53
+ | `VERICTO_FAIL_MODE` | `failMode` | `closed` or `open` (see [Fail mode](#fail-mode)) | `closed` |
54
+ | `VERICTO_TIMEOUT` | `timeoutMs` | Per-attempt timeout (env in seconds, option in ms) | 5 s |
55
+
56
+ The key is sent only in the `X-API-Key` header, only over HTTPS (plain HTTP is
57
+ accepted for localhost alone), and never appears in messages, `toString()` or
58
+ `JSON.stringify()`. To trust an extra CA, use Node's `NODE_EXTRA_CA_CERTS`.
59
+
60
+ ## Quickstart
61
+
62
+ ### snowflake-sdk
63
+
64
+ ```ts
65
+ import snowflake from 'snowflake-sdk';
66
+ import { VerictoBlockedError } from '@vericto/sdk';
67
+ import { guardConnection } from '@vericto/sdk/snowflake';
68
+
69
+ const raw = snowflake.createConnection({ account, username, authenticator: 'SNOWFLAKE_JWT', privateKeyPath });
70
+ await raw.connectAsync();
71
+ const conn = await guardConnection(raw);
72
+
73
+ const rows = await conn.query('SELECT id, email FROM customers WHERE id = ?', [42]);
74
+
75
+ // Callback style, with the driver's own options:
76
+ await conn.execute({
77
+ sqlText: 'DELETE FROM customers',
78
+ complete: (err, stmt, rows) => {
79
+ // err is a VerictoBlockedError: the statement never reached Snowflake
80
+ },
81
+ });
82
+ ```
83
+
84
+ `connection.execute()` returns its statement synchronously, but a Vericto check is
85
+ a network call, so the guarded `execute()` resolves the statement. With
86
+ `complete`, a Vericto rejection is delivered to it as `err` (and the promise
87
+ resolves `undefined`); without it, the promise rejects. A multi-statement
88
+ `sqlText` (`MULTI_STATEMENT_COUNT`) is evaluated as one request: a block anywhere
89
+ means nothing runs.
90
+
91
+ ### better-sqlite3
92
+
93
+ ```ts
94
+ import Database from 'better-sqlite3';
95
+ import { guardDatabase } from '@vericto/sdk/better-sqlite3';
96
+
97
+ const db = await guardDatabase(new Database('app.db'));
98
+
99
+ const expire = await db.prepare('DELETE FROM sessions WHERE expires_at < ?'); // checked once
100
+ expire.run(Date.now()); // synchronous, as usual
101
+
102
+ await db.run('INSERT INTO audit (event) VALUES (?)', 'login');
103
+ const user = await db.get('SELECT * FROM users WHERE id = ?', 1);
104
+ await db.exec(migrationSql); // whole script checked first
105
+ ```
106
+
107
+ better-sqlite3 is synchronous, so the SQL-carrying entry points (`prepare`,
108
+ `exec`, and the `run`/`all`/`get` shortcuts) become async. A prepared statement's
109
+ SQL cannot change, so its `run`/`all`/`get`/`iterate` stay synchronous: prepare
110
+ statements before `db.raw.transaction(...)` and use them inside it. See
111
+ [SQLite status](#sqlite-status).
112
+
113
+ ### LangChain.js (SQL agents, tools and chains)
114
+
115
+ ```bash
116
+ npm install @vericto/sdk @langchain/classic @langchain/core typeorm
117
+ ```
118
+
119
+ ```ts
120
+ import { DataSource } from 'typeorm';
121
+ import { createSqlAgent } from '@langchain/classic/agents/toolkits/sql';
122
+ import { VerictoSqlDatabase, VerictoSqlToolkit, VerictoCheckSqlTool } from '@vericto/sdk/langchain';
123
+
124
+ const db = await VerictoSqlDatabase.fromDataSourceParams({
125
+ appDataSource: new DataSource({ type: 'postgres', url: process.env.DATABASE_URL }),
126
+ // vericto: new Vericto({ ... }), dialect: 'postgres', onBlock: 'return' | 'raise'
127
+ });
128
+
129
+ const agent = createSqlAgent(llm, new VerictoSqlToolkit(db, llm));
130
+ await agent.invoke({ input: 'How many orders shipped last week?' });
131
+
132
+ // Or give an agent a check-only tool (nothing is executed):
133
+ const check = new VerictoCheckSqlTool({ db });
134
+ ```
135
+
136
+ `VerictoSqlDatabase` is a LangChain `SqlDatabase` (`@langchain/classic/sql_db`;
137
+ `langchain/sql_db` no longer exists in LangChain.js 1.x), so it is accepted
138
+ wherever one is: `QuerySqlTool`, `SqlToolkit`/`createSqlAgent`,
139
+ `SqlDatabaseChain`. Its TypeORM data source is wrapped so that every `query()` is
140
+ checked: the agent's queries, the sample rows `getTableInfo` puts in the prompt,
141
+ and the SQL `SqlDatabaseChain` generates.
142
+
143
+ | Verdict | What the agent sees |
144
+ |---|---|
145
+ | `BLOCKED` | `onBlock: 'return'` (default): the tool returns a message with the rule, severity, reason and suggested fix, and the query does not run, so the model can correct itself. `onBlock: 'raise'`: `VerictoBlockedError`. |
146
+ | `FLAGGED` / `MONITORED` | The query runs; the verdict is logged and passed to `onVerdict`. |
147
+ | mask | The masked rewrite runs, never the original: the model only sees masked values (sample rows included). |
148
+ | no verdict, config error | Thrown (`VerictoUnavailableError`, `VerictoConfigError`), never returned to the model; the [fail mode](#fail-mode) applies. |
149
+
150
+ - The dialect comes from the TypeORM type (`postgres`/`aurora-postgres`,
151
+ `mysql`/`mariadb`/`aurora-mysql`, `mssql`, `oracle`, `sqlite`/`better-sqlite3`/
152
+ `sqljs`); other types need `dialect`. The factory fails fast when the server does
153
+ not evaluate it.
154
+ - `VerictoSqlToolkit` is `SqlToolkit` with `VerictoQuerySqlTool`: the stock
155
+ `QuerySqlTool` turns every error into text for the model, which would also
156
+ hand it "Vericto unavailable" (and the block under `onBlock: 'raise'`).
157
+ `VerictoQuerySqlTool` rethrows Vericto errors and still returns SQL errors as text.
158
+ - A blocked sample-rows query is left out of the table info (LangChain logs the
159
+ error and carries on).
160
+ - `SqlDatabaseChain` swallows query errors itself (it logs them and answers from
161
+ an empty result), so there a block shows up as "no result" rather than as the
162
+ message.
163
+ - LangChain's schema introspection in `fromDataSourceParams` (its catalogue read
164
+ of tables and columns) runs on the raw data source. `db.rawDataSource` is the
165
+ unguarded data source: SQL run through it is not checked.
166
+ - `VerictoCheckSqlTool` is a Runtime API evaluation like any other: it counts
167
+ against the runtime quota and is in the audit trail.
168
+
169
+ ### Any driver, by hand
170
+
171
+ ```ts
172
+ import { Vericto, sqlToExecute } from '@vericto/sdk';
173
+
174
+ const vericto = new Vericto(); // one per process
175
+ const verdict = await vericto.enforce(sql, 'postgres'); // rejects with VerictoBlockedError
176
+ await pool.query(sqlToExecute(verdict)); // the masked rewrite, if any
177
+ ```
178
+
179
+ `vericto.prepare(sql, dialect)` resolves the SQL text directly; `vericto.check()`
180
+ resolves the verdict without applying it.
181
+
182
+ ## What each decision does
183
+
184
+ | Verdict | What the wrapper does |
185
+ |---|---|
186
+ | `ALLOWED` | Runs the statement. |
187
+ | `FLAGGED` | Runs it, logs a warning, calls `onVerdict`. |
188
+ | `MONITORED` | Runs it, logs at info, calls `onVerdict`. |
189
+ | `PARSE_ERROR` (allowed) | The workspace's `parse_error_action` let it through: runs it and logs a warning. When the workspace blocks unparseable SQL, the server answers `BLOCKED`. |
190
+ | `BLOCKED` | Rejects with `VerictoBlockedError` (`verdict`, `findings`, `suggestedFix`) **before** the driver is called. |
191
+ | mask (`rewrittenQuery`) | Runs `rewrittenQuery` **instead of** your SQL: the sensitive columns come back masked. Never the original. |
192
+ | no verdict | The [fail mode](#fail-mode) decides. |
193
+
194
+ `onVerdict` receives every verdict, blocked and unevaluated ones included. The
195
+ default logger is `console` for warnings and errors (`logger: false` silences it,
196
+ or pass your own `{ info, warn, error }`). Log lines carry the rule code, severity
197
+ and Vericto event id, **never the SQL text**. Every evaluation is recorded in the
198
+ Vericto audit trail.
199
+
200
+ ## Fail mode
201
+
202
+ When Vericto cannot answer (network error, timeout, HTTP 5xx, rate limit after
203
+ retries, or the monthly quota `QUOTA_EXCEEDED`):
204
+
205
+ - `failMode: 'closed'` (default): reject with `VerictoUnavailableError`; the
206
+ statement does not run.
207
+ - `failMode: 'open'`: run the statement unevaluated, emit a process warning of type
208
+ `VerictoFailOpenWarning`, log it, and pass an `UNEVALUATED` verdict to `onVerdict`.
209
+
210
+ Configuration errors are **never** failed open: a missing or revoked key (401), a
211
+ key without the scope or for another database (403), a malformed request (400) or
212
+ an unsupported dialect reject with `VerictoConfigError` in both modes.
213
+
214
+ Retries: network errors, timeouts, 5xx and 429 `RATE_LIMIT_EXCEEDED` are retried
215
+ `maxRetries` times (default 2) with exponential backoff and jitter (capped at 2 s,
216
+ honouring `Retry-After`). `QUOTA_EXCEEDED` is not retried.
217
+
218
+ ## Parameters
219
+
220
+ Bind values are **never** sent to Vericto. The SQL text goes as written,
221
+ placeholders included (`?`, `:1` for Snowflake; `?`, `:name`, `@name`, `$name` for
222
+ SQLite), and the driver binds the values afterwards.
223
+
224
+ ## Caching
225
+
226
+ Off by default (`cacheTtlMs: 0`). With `cacheTtlMs: 30_000`, identical
227
+ `(sql, dialect)` pairs reuse a verdict for 30 seconds (LRU, `cacheSize: 1024`), and
228
+ the cache is dropped when a response reports a new `ruleset_version`. A cached hit
229
+ is not evaluated, so it is **not in the Vericto audit trail**, and rule changes
230
+ apply only when the entry expires (the Runtime API does not report the ruleset
231
+ version today). Enable it only for hot, repetitive statements, with a short TTL.
232
+
233
+ ## SQLite status
234
+
235
+ SQLite has no server, so there is no Vericto proxy for it: this wrapper is the
236
+ enforcement point. The **Vericto server evaluates the `sqlite` dialect**
237
+ (vericto-engine 4.1.0+; `GET /api/v1/meta/config` lists `postgres`, `mysql`,
238
+ `oracle`, `mssql`, `snowflake`, `sqlite`), including SQLite-specific rules such
239
+ as `ATTACH DATABASE` (VERICTO-098), `PRAGMA foreign_keys = OFF` (VERICTO-099),
240
+ `load_extension()` (VERICTO-100) and `VACUUM INTO` (VERICTO-101).
241
+
242
+ `guardDatabase()` still asks the server first and rejects with
243
+ `VerictoUnsupportedDialectError`, before any SQL runs, if it does not list
244
+ `sqlite` (for example an older self-hosted server). There is deliberately no
245
+ fallback to another dialect. See [Live tests](#live-tests) for an end-to-end
246
+ check against a real server.
247
+
248
+ ## Enforcement boundary
249
+
250
+ The wrapper protects the SQL that goes through it. `db.raw`, `conn.raw`, another
251
+ connection or another process with the same credentials are not checked. Pair the
252
+ wrapper with database-side least privilege (and, for Snowflake, a network policy)
253
+ when the guarantee matters.
254
+
255
+ ## Errors
256
+
257
+ All extend `VerictoError`.
258
+
259
+ | Error | When |
260
+ |---|---|
261
+ | `VerictoBlockedError` | Vericto blocked the statement. `.verdict`, `.findings`, `.suggestedFix`, `.sql`. |
262
+ | `VerictoUnavailableError` | No verdict and `failMode: 'closed'`. |
263
+ | `VerictoQuotaExceededError` | Extends `VerictoUnavailableError`: monthly quota used (`.resetsAt`). |
264
+ | `VerictoConfigError` | Key, scope, database id, URL or request problem. Thrown in both fail modes. |
265
+ | `VerictoUnsupportedDialectError` | Extends `VerictoConfigError`: the server does not evaluate that dialect. |
266
+
267
+ ## Evaluators
268
+
269
+ `Vericto` takes an `evaluator`: any object with `evaluate(sql, dialect)` and
270
+ `supportedDialects()`. This release ships `RuntimeApiEvaluator`. An embedded
271
+ evaluator (the Vericto engine in-process, for example WASM, with synced rules) can
272
+ be added later behind the same interface without changing the wrappers.
273
+
274
+ ## Integrations roadmap
275
+
276
+ Not implemented yet; each is meant to be a thin layer over `Vericto.enforce`:
277
+
278
+ - **LlamaIndex.TS** SQL tools.
279
+ - **`pg` and `mysql2`**: `pool.query` wrappers (the TCP proxy already covers
280
+ PostgreSQL and MySQL without code changes).
281
+ - **Cloudflare D1** Workers binding helper.
282
+ - **Embedded evaluator** (WASM).
283
+
284
+ ## Development
285
+
286
+ ```bash
287
+ npm ci
288
+ npm run lint && npm run typecheck
289
+ npm test # vitest: local Runtime API stand-in, real better-sqlite3, fake snowflake-sdk,
290
+ # real LangChain.js + TypeORM with a scripted LLM (no model calls)
291
+ npm run build # tsup → dist/ (ESM + CJS + .d.ts)
292
+ npm run smoke # the built package, ESM and CJS, on any Node >= 18
293
+ ```
294
+
295
+ Development needs Node 22+ (the tooling); the published package runs on Node 18+.
296
+ Nothing in the test suite connects to Snowflake.
297
+
298
+ ### Live tests
299
+
300
+ `test/live/sqlite.live.test.ts` is an opt-in end-to-end test of
301
+ `@vericto/sdk/better-sqlite3` against a **real Vericto Runtime API** and a real
302
+ SQLite file in a temporary directory. It is skipped unless the variables below
303
+ are set, and never runs in CI. Benign statements (`CREATE TABLE`, `INSERT` with
304
+ `?` binds, UPSERT `ON CONFLICT ... DO UPDATE`, `SELECT`, `DELETE ... WHERE`) must
305
+ run; `DELETE` without `WHERE` (VERICTO-001), `ATTACH DATABASE` (VERICTO-098),
306
+ `load_extension()` (VERICTO-100) and `VACUUM INTO` (VERICTO-101) must reject with
307
+ `VerictoBlockedError` before SQLite sees them (checked with better-sqlite3's
308
+ `verbose` trace, the file's SHA-256 and the absence of the attached/copy files);
309
+ `PRAGMA foreign_keys = OFF` (VERICTO-099) must run and log a FLAGGED warning; an
310
+ `exec` script with a blocked statement in the middle must run none of it. The
311
+ database's workspace must use the default rules; a run makes about 25
312
+ evaluations, counted against the workspace's monthly quota.
313
+
314
+ | Variable | Value |
315
+ |---|---|
316
+ | `VERICTO_LIVE_SQLITE` | `1` |
317
+ | `VERICTO_API_KEY` | a `vtro_...` key with the `proxy:evaluate` scope |
318
+ | `VERICTO_API_URL` | `https://api-staging.vericto.com` (or another server that lists `sqlite`) |
319
+ | `VERICTO_DATABASE_ID` | the id of a database of dialect `sqlite` in that workspace |
320
+
321
+ On the host (Node 22+):
322
+
323
+ ```bash
324
+ export VERICTO_LIVE_SQLITE=1 VERICTO_API_URL=https://api-staging.vericto.com
325
+ export VERICTO_API_KEY=vtro_... VERICTO_DATABASE_ID=...
326
+ npm ci && npx vitest run test/live
327
+ ```
328
+
329
+ Or in a throwaway `node:22-slim` container (the repository is mounted read-only
330
+ and copied; better-sqlite3 installs its prebuilt linux binary; the SQLite file
331
+ never leaves the container):
332
+
333
+ ```bash
334
+ docker run --rm -v "$PWD":/src:ro \
335
+ -e VERICTO_LIVE_SQLITE=1 -e VERICTO_API_KEY -e VERICTO_API_URL -e VERICTO_DATABASE_ID \
336
+ node:22-slim sh -c 'mkdir /work && cd /src && tar --exclude=node_modules --exclude=dist -cf - . | tar -xf - -C /work \
337
+ && cd /work && npm ci --no-audit --no-fund && npx vitest run test/live'
338
+ ```
339
+
340
+ A skipped run (`7 skipped`) means a variable is missing.
341
+
342
+ ## Security
343
+
344
+ See [SECURITY.md](SECURITY.md). Report vulnerabilities to security@vericto.com,
345
+ not in public issues.
346
+
347
+ ## License
348
+
349
+ [Elastic License 2.0](LICENSE).
350
+
351
+ ---
352
+
353
+ ## En español
354
+
355
+ `@vericto/sdk` (antes `@vericto/vericto`, nunca publicado) valida cada sentencia
356
+ SQL con Vericto **antes** de ejecutarla: wrappers para `snowflake-sdk` y
357
+ `better-sqlite3`, una integración con LangChain.js (`@vericto/sdk/langchain`) y un
358
+ cliente de la Runtime API para cualquier otro driver. En LangChain.js, una consulta
359
+ bloqueada devuelve al agente un mensaje con la regla y la corrección sugerida (o
360
+ lanza `VerictoBlockedError` con `onBlock: 'raise'`), y las consultas con columnas
361
+ enmascaradas se ejecutan reescritas.
362
+
363
+ - **BLOCKED**: rechaza con `VerictoBlockedError` (hallazgos y corrección sugerida) y
364
+ la sentencia no llega a la base de datos.
365
+ - **FLAGGED / MONITORED**: se ejecuta y se registra (`onVerdict`, logger).
366
+ - **Máscara de columnas sensibles**: se ejecuta `rewrittenQuery`, nunca la original.
367
+ - **Sin respuesta de Vericto**: `failMode: 'closed'` (por defecto) bloquea; `'open'`
368
+ ejecuta y emite el aviso `VerictoFailOpenWarning`. Los errores de configuración
369
+ nunca se dejan pasar.
370
+
371
+ Configuración: `VERICTO_API_KEY` (clave `vtro_...` con el scope `proxy:evaluate`),
372
+ `VERICTO_DATABASE_ID` y, opcionalmente, `VERICTO_API_URL`, `VERICTO_FAIL_MODE`,
373
+ `VERICTO_TIMEOUT`. Los valores de los parámetros nunca se envían a Vericto.
374
+
375
+ SQLite: el servidor de Vericto evalúa el dialecto `sqlite` (vericto-engine
376
+ 4.1.0+). `guardDatabase()` igual consulta `GET /api/v1/meta/config` y, si un
377
+ servidor no lo anuncia, rechaza con `VerictoUnsupportedDialectError` sin ejecutar
378
+ nada.
package/SECURITY.md ADDED
@@ -0,0 +1,58 @@
1
+ # Security Policy
2
+
3
+ Vericto is a security product. We take vulnerabilities seriously and
4
+ appreciate responsible disclosure.
5
+
6
+ ## Reporting a vulnerability
7
+
8
+ **Do not open a public GitHub issue for security vulnerabilities.**
9
+
10
+ Report it privately, by either channel:
11
+
12
+ - Email **security@vericto.com**.
13
+ - Open a private report on GitHub:
14
+ [Report a vulnerability](https://github.com/vericto/vericto-node/security/advisories/new)
15
+ (Security tab → "Report a vulnerability"). Only the maintainers can see it.
16
+
17
+ Include:
18
+
19
+ - A description of the vulnerability and its impact.
20
+ - Steps to reproduce.
21
+ - The affected version (`npm ls @vericto/sdk`)
22
+ and the driver involved.
23
+ - Any suggested remediation.
24
+
25
+ You will receive an acknowledgement within **48 hours** and a status update
26
+ within **5 business days**.
27
+
28
+ ## Scope
29
+
30
+ High-priority issues for this package include:
31
+
32
+ - **Credential exposure**: the API key written, logged or sent anywhere other
33
+ than the configured Vericto API over TLS.
34
+ - **Guard bypass**: a path through a wrapped connection that executes SQL Vericto
35
+ did not evaluate, or blocked, outside an explicit `failMode: 'open'`; or a masked
36
+ statement that runs the original SQL instead of `rewrittenQuery`.
37
+ - **Data leakage to Vericto**: bind values sent to the API.
38
+
39
+ - **Supply chain**: a published package that was not built by this repository's
40
+ release workflow (every release carries npm provenance).
41
+
42
+ Issues in the SQL evaluation itself belong to
43
+ [vericto-engine](https://github.com/vericto/vericto-engine/security).
44
+
45
+ ## Disclosure process
46
+
47
+ 1. Report received and acknowledged (within 48h).
48
+ 2. We confirm and assess severity.
49
+ 3. We develop and test a fix.
50
+ 4. We release the fix and credit you (unless you prefer to remain anonymous).
51
+ 5. Public disclosure after users have had reasonable time to update.
52
+
53
+ ## Supported versions
54
+
55
+ Security fixes are applied to the latest released version. Older versions are
56
+ patched at the maintainers' discretion.
57
+
58
+ Thank you for helping keep Vericto and its users safe.
@@ -0,0 +1,62 @@
1
+ 'use strict';
2
+
3
+ var chunkHFL7W4WC_cjs = require('./chunk-HFL7W4WC.cjs');
4
+
5
+ // src/better-sqlite3.ts
6
+ var DIALECT = "sqlite";
7
+ var GuardedDatabase = class {
8
+ /** The underlying database. SQL run through it directly is **not** checked. */
9
+ raw;
10
+ vericto;
11
+ constructor(db, vericto) {
12
+ this.raw = db;
13
+ this.vericto = vericto;
14
+ }
15
+ /** Check `sql`, then `db.prepare()` the SQL to run (the masked rewrite, if any). */
16
+ async prepare(sql) {
17
+ const final = await this.vericto.prepare(sql, DIALECT);
18
+ return this.raw.prepare(final);
19
+ }
20
+ /** Like `prepare`, also resolving the verdict (decision, rule, event id). */
21
+ async prepareWithVerdict(sql) {
22
+ const verdict = await this.vericto.enforce(sql, DIALECT);
23
+ return { statement: this.raw.prepare(chunkHFL7W4WC_cjs.sqlToExecute(verdict)), verdict };
24
+ }
25
+ /**
26
+ * Check a script, then `db.exec()` it. The script is evaluated as one request (the
27
+ * engine evaluates every statement in it); a block anywhere means nothing runs.
28
+ */
29
+ async exec(sql) {
30
+ const final = await this.vericto.prepare(sql, DIALECT);
31
+ this.raw.exec(final);
32
+ return this;
33
+ }
34
+ /** `prepare(sql)` then `statement.run(...params)`. */
35
+ async run(sql, ...params) {
36
+ return call(await this.prepare(sql), "run", params);
37
+ }
38
+ /** `prepare(sql)` then `statement.all(...params)`. */
39
+ async all(sql, ...params) {
40
+ return call(await this.prepare(sql), "all", params);
41
+ }
42
+ /** `prepare(sql)` then `statement.get(...params)`. */
43
+ async get(sql, ...params) {
44
+ return call(await this.prepare(sql), "get", params);
45
+ }
46
+ };
47
+ function call(statement, method, params) {
48
+ const fn = statement[method];
49
+ if (typeof fn !== "function") throw new TypeError(`vericto: the prepared statement has no ${method}()`);
50
+ return fn.apply(statement, params);
51
+ }
52
+ async function guardDatabase(db, options = {}) {
53
+ const vericto = options.vericto ?? new chunkHFL7W4WC_cjs.Vericto();
54
+ await vericto.requireDialect(DIALECT);
55
+ return new GuardedDatabase(db, vericto);
56
+ }
57
+
58
+ exports.DIALECT = DIALECT;
59
+ exports.GuardedDatabase = GuardedDatabase;
60
+ exports.guardDatabase = guardDatabase;
61
+ //# sourceMappingURL=better-sqlite3.cjs.map
62
+ //# sourceMappingURL=better-sqlite3.cjs.map