sql-guard 0.1.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/LICENSE +21 -0
- package/README.md +169 -0
- package/dist/analysis/functions.d.ts +3 -0
- package/dist/analysis/functions.d.ts.map +1 -0
- package/dist/analysis/relations.d.ts +3 -0
- package/dist/analysis/relations.d.ts.map +1 -0
- package/dist/cjs/index.cjs +1033 -0
- package/dist/cjs/package.json +1 -0
- package/dist/esm/index.js +1001 -0
- package/dist/index.d.ts +97 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/normalize/identifier.d.ts +55 -0
- package/dist/normalize/identifier.d.ts.map +1 -0
- package/dist/normalize/qualified-name.d.ts +9 -0
- package/dist/normalize/qualified-name.d.ts.map +1 -0
- package/dist/parser/adapter.d.ts +30 -0
- package/dist/parser/adapter.d.ts.map +1 -0
- package/dist/parser/types.d.ts +73 -0
- package/dist/parser/types.d.ts.map +1 -0
- package/dist/policy/compile-policy.d.ts +20 -0
- package/dist/policy/compile-policy.d.ts.map +1 -0
- package/dist/policy/engine.d.ts +30 -0
- package/dist/policy/engine.d.ts.map +1 -0
- package/dist/policy/fail-closed.d.ts +8 -0
- package/dist/policy/fail-closed.d.ts.map +1 -0
- package/dist/policy/function.d.ts +44 -0
- package/dist/policy/function.d.ts.map +1 -0
- package/dist/policy/statement.d.ts +42 -0
- package/dist/policy/statement.d.ts.map +1 -0
- package/dist/types/public.d.ts +175 -0
- package/dist/types/public.d.ts.map +1 -0
- package/package.json +50 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# sql-guard
|
|
2
|
+
|
|
3
|
+
Validate AI generated PostgreSQL queries against explicit allowlists. This package parses SQL into an AST and denies anything outside your policy.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install sql-guard
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quickstart
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { validate, assertSafeSql, ErrorCode } from 'sql-guard';
|
|
15
|
+
|
|
16
|
+
const policy = {
|
|
17
|
+
allowedTables: ['public.users', 'public.orders'],
|
|
18
|
+
allowedFunctions: ['count', 'lower'],
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const result = validate('SELECT * FROM public.users', policy);
|
|
22
|
+
if (!result.ok) {
|
|
23
|
+
console.log('Denied:', result.errorCode);
|
|
24
|
+
console.log('Violations:', result.violations);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Or fail fast with an exception
|
|
28
|
+
assertSafeSql('SELECT lower(u.email) FROM public.users u', policy);
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## API Reference
|
|
32
|
+
|
|
33
|
+
### validate(sql, policy)
|
|
34
|
+
|
|
35
|
+
Validates SQL against a policy.
|
|
36
|
+
|
|
37
|
+
- Returns: `ValidationResult`
|
|
38
|
+
- On failure: `ok === false`, `violations` populated, and `errorCode` set
|
|
39
|
+
|
|
40
|
+
### assertSafeSql(sql, policy)
|
|
41
|
+
|
|
42
|
+
Validates SQL and throws when validation fails.
|
|
43
|
+
|
|
44
|
+
- Returns: `void`
|
|
45
|
+
- Throws: `SqlValidationError` with `code: ErrorCode` and `violations: Violation[]`
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
import { assertSafeSql, SqlValidationError, ErrorCode } from 'sql-guard';
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
assertSafeSql('SELECT pg_catalog.current_database() FROM public.users', {
|
|
52
|
+
allowedTables: ['public.users'],
|
|
53
|
+
allowedFunctions: ['lower'],
|
|
54
|
+
});
|
|
55
|
+
} catch (err) {
|
|
56
|
+
if (err instanceof SqlValidationError) {
|
|
57
|
+
if (err.code === ErrorCode.FUNCTION_NOT_ALLOWED) {
|
|
58
|
+
console.error('Blocked a function call:', err.violations);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
throw err;
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### ErrorCode
|
|
66
|
+
|
|
67
|
+
Enum of error codes returned by `validate()` and used by `SqlValidationError`.
|
|
68
|
+
|
|
69
|
+
### Policy
|
|
70
|
+
|
|
71
|
+
Policy settings that drive validation.
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
export interface Policy {
|
|
75
|
+
allowedTables: string[];
|
|
76
|
+
allowedStatements?: ('select' | 'insert' | 'update' | 'delete')[];
|
|
77
|
+
allowMultiStatement?: boolean;
|
|
78
|
+
allowedFunctions?: string[];
|
|
79
|
+
tableIdentifierMatching?: 'strict' | 'caseInsensitive';
|
|
80
|
+
resolver?: (unqualified: string) => string | null;
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Defaults and behavior:
|
|
85
|
+
|
|
86
|
+
- `allowedTables` is required.
|
|
87
|
+
- `allowedTables` entries must be schema-qualified (`schema.table`). Invalid entries return `INVALID_POLICY`.
|
|
88
|
+
- `allowedStatements` defaults to `['select']`.
|
|
89
|
+
- `allowMultiStatement` defaults to `false`.
|
|
90
|
+
- `allowedFunctions` defaults to `[]`, which means any function call is denied unless allowlisted.
|
|
91
|
+
- `tableIdentifierMatching` defaults to `'strict'` (exact case-sensitive table matching).
|
|
92
|
+
- Set `tableIdentifierMatching: 'caseInsensitive'` to preserve case-insensitive table matching.
|
|
93
|
+
- Unqualified table references in SQL are denied unless you provide `resolver` to map them to `schema.table`.
|
|
94
|
+
- Unqualified function allowlist entries (for example, `lower`) match only unqualified calls (`lower(...)`).
|
|
95
|
+
- Schema-qualified function calls require schema-qualified allowlist entries (`pg_catalog.current_database`).
|
|
96
|
+
|
|
97
|
+
Strict policy examples:
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
const strictPolicy = {
|
|
101
|
+
allowedTables: ['public.users', 'analytics.events'],
|
|
102
|
+
allowedFunctions: ['lower', 'pg_catalog.current_database'],
|
|
103
|
+
resolver: (unqualified: string) =>
|
|
104
|
+
unqualified === 'users' ? 'public.users' : null,
|
|
105
|
+
};
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Security Model
|
|
109
|
+
|
|
110
|
+
- AST based validation, not regex matching.
|
|
111
|
+
- Fail closed: unsupported or uncertain parser features are denied.
|
|
112
|
+
- Data-modifying CTE payloads (for example `WITH x AS (INSERT ...) SELECT ...`) are denied as unsupported.
|
|
113
|
+
- `SELECT INTO` is denied as unsupported.
|
|
114
|
+
- Table allowlists: every referenced table must be in `policy.allowedTables` by fully qualified name.
|
|
115
|
+
- Statement type restrictions: only `select` is allowed unless you opt in via `allowedStatements`.
|
|
116
|
+
- Multi statement restriction: `SELECT 1; SELECT 2` is denied unless `allowMultiStatement: true`.
|
|
117
|
+
- Function allowlists: schema-qualified calls are allowed only by exact schema-qualified entries.
|
|
118
|
+
- Metadata table protection: relations in `information_schema` and `pg_catalog` are denied unless explicitly allowlisted by fully qualified name.
|
|
119
|
+
|
|
120
|
+
This is a guardrail for LLM output. It helps enforce least privilege at the query shape level. Use it alongside parameterization, prepared statements, and database permissions.
|
|
121
|
+
|
|
122
|
+
## Limitations
|
|
123
|
+
|
|
124
|
+
- PostgreSQL focused (v1). Other dialects are not supported.
|
|
125
|
+
- No SQL rewriting or sanitization. This package validates, it doesn't transform queries.
|
|
126
|
+
- Not a complete SQL injection defense by itself. Treat it as defense in depth.
|
|
127
|
+
- No database context: it can't check column level permissions, RLS policies, or runtime schema changes.
|
|
128
|
+
|
|
129
|
+
## Error Codes
|
|
130
|
+
|
|
131
|
+
`validate()` returns a single `errorCode` plus a list of `violations`. Invalid policy configuration is reported before SQL parsing.
|
|
132
|
+
|
|
133
|
+
| Code | Description |
|
|
134
|
+
|------|-------------|
|
|
135
|
+
| `PARSE_ERROR` | SQL could not be parsed into an AST. |
|
|
136
|
+
| `UNSUPPORTED_SQL_FEATURE` | Parsed SQL contains features outside the supported subset (fail closed). |
|
|
137
|
+
| `TABLE_NOT_ALLOWED` | A referenced table is not in `policy.allowedTables`, or an unqualified table can't be resolved. |
|
|
138
|
+
| `STATEMENT_NOT_ALLOWED` | Statement type is not allowed (defaults to `select` only). |
|
|
139
|
+
| `FUNCTION_NOT_ALLOWED` | A function call is not in `policy.allowedFunctions`. |
|
|
140
|
+
| `MULTI_STATEMENT_DISABLED` | Query contains multiple statements while `allowMultiStatement` is disabled. |
|
|
141
|
+
| `INVALID_POLICY` | Policy configuration is invalid (for example non-qualified table allowlist entries). |
|
|
142
|
+
|
|
143
|
+
## Violation Types
|
|
144
|
+
|
|
145
|
+
`Violation.type` can be:
|
|
146
|
+
|
|
147
|
+
- `parse`
|
|
148
|
+
- `unsupported`
|
|
149
|
+
- `policy`
|
|
150
|
+
- `statement`
|
|
151
|
+
- `table`
|
|
152
|
+
- `function`
|
|
153
|
+
|
|
154
|
+
## Publishing
|
|
155
|
+
|
|
156
|
+
For first time npm publish:
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
npm login
|
|
160
|
+
npm publish --access public
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Notes:
|
|
164
|
+
|
|
165
|
+
- `prepublishOnly` runs typecheck, tests, and build, so publishing requires Bun in your environment.
|
|
166
|
+
|
|
167
|
+
## License
|
|
168
|
+
|
|
169
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"functions.d.ts","sourceRoot":"","sources":["../../src/analysis/functions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,GAAG,YAAY,EAAE,CAoChE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relations.d.ts","sourceRoot":"","sources":["../../src/analysis/relations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEjD,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,GAAG,cAAc,EAAE,CAyE/D"}
|