sql-guard 0.1.0 → 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/README.md +31 -15
- package/dist/cjs/index.cjs +59 -11
- package/dist/esm/index.js +41 -3
- package/dist/normalize/identifier.d.ts.map +1 -1
- package/dist/normalize/qualified-name.d.ts +14 -0
- package/dist/normalize/qualified-name.d.ts.map +1 -1
- package/dist/policy/compile-policy.d.ts +1 -0
- package/dist/policy/compile-policy.d.ts.map +1 -1
- package/dist/types/public.d.ts +13 -0
- package/dist/types/public.d.ts.map +1 -1
- package/package.json +32 -4
package/README.md
CHANGED
|
@@ -78,6 +78,7 @@ export interface Policy {
|
|
|
78
78
|
allowedFunctions?: string[];
|
|
79
79
|
tableIdentifierMatching?: 'strict' | 'caseInsensitive';
|
|
80
80
|
resolver?: (unqualified: string) => string | null;
|
|
81
|
+
defaultSchema?: string;
|
|
81
82
|
}
|
|
82
83
|
```
|
|
83
84
|
|
|
@@ -90,19 +91,47 @@ Defaults and behavior:
|
|
|
90
91
|
- `allowedFunctions` defaults to `[]`, which means any function call is denied unless allowlisted.
|
|
91
92
|
- `tableIdentifierMatching` defaults to `'strict'` (exact case-sensitive table matching).
|
|
92
93
|
- 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 table references in SQL are denied unless you provide `defaultSchema` or `resolver` to map them to `schema.table`.
|
|
95
|
+
- `defaultSchema`: when provided, unqualified `allowedTables` entries are auto-qualified with this schema, and unqualified SQL references resolve to it.
|
|
96
|
+
- `resolver`: optional function to map unqualified names to qualified names. Takes precedence over `defaultSchema`.
|
|
97
|
+
- Metadata schemas (`information_schema`, `pg_catalog`) are treated specially and must be explicitly allowlisted even when using `defaultSchema`. Setting `defaultSchema` to a metadata schema name does not grant automatic access.
|
|
94
98
|
- Unqualified function allowlist entries (for example, `lower`) match only unqualified calls (`lower(...)`).
|
|
95
99
|
- Schema-qualified function calls require schema-qualified allowlist entries (`pg_catalog.current_database`).
|
|
96
100
|
|
|
97
|
-
|
|
101
|
+
Policy examples:
|
|
98
102
|
|
|
99
103
|
```ts
|
|
104
|
+
// Explicit schema-qualified tables
|
|
100
105
|
const strictPolicy = {
|
|
101
106
|
allowedTables: ['public.users', 'analytics.events'],
|
|
102
107
|
allowedFunctions: ['lower', 'pg_catalog.current_database'],
|
|
103
108
|
resolver: (unqualified: string) =>
|
|
104
109
|
unqualified === 'users' ? 'public.users' : null,
|
|
105
110
|
};
|
|
111
|
+
|
|
112
|
+
// Using defaultSchema for simpler configuration
|
|
113
|
+
const defaultSchemaPolicy = {
|
|
114
|
+
defaultSchema: 'public',
|
|
115
|
+
allowedTables: ['users', 'orders', 'products'],
|
|
116
|
+
// Treated as ['public.users', 'public.orders', 'public.products']
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
// Mixed: defaultSchema + explicit qualified tables
|
|
120
|
+
const mixedPolicy = {
|
|
121
|
+
defaultSchema: 'public',
|
|
122
|
+
allowedTables: ['users', 'analytics.events'],
|
|
123
|
+
// Treated as ['public.users', 'analytics.events']
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
// Resolver takes precedence over defaultSchema
|
|
127
|
+
const resolverPolicy = {
|
|
128
|
+
defaultSchema: 'public',
|
|
129
|
+
allowedTables: ['public.users', 'archive.users'],
|
|
130
|
+
resolver: (name: string) =>
|
|
131
|
+
name === 'old_users' ? 'archive.users' : null,
|
|
132
|
+
// 'users' resolves to 'public.users' via defaultSchema
|
|
133
|
+
// 'old_users' resolves to 'archive.users' via resolver
|
|
134
|
+
};
|
|
106
135
|
```
|
|
107
136
|
|
|
108
137
|
## Security Model
|
|
@@ -151,19 +180,6 @@ This is a guardrail for LLM output. It helps enforce least privilege at the quer
|
|
|
151
180
|
- `table`
|
|
152
181
|
- `function`
|
|
153
182
|
|
|
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
183
|
## License
|
|
168
184
|
|
|
169
185
|
MIT
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -2,27 +2,37 @@ var __defProp = Object.defineProperty;
|
|
|
2
2
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
4
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
-
|
|
5
|
+
function __accessProp(key) {
|
|
6
|
+
return this[key];
|
|
7
|
+
}
|
|
6
8
|
var __toCommonJS = (from) => {
|
|
7
|
-
var entry = __moduleCache.get(from), desc;
|
|
9
|
+
var entry = (__moduleCache ??= new WeakMap).get(from), desc;
|
|
8
10
|
if (entry)
|
|
9
11
|
return entry;
|
|
10
12
|
entry = __defProp({}, "__esModule", { value: true });
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function")
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (var key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(entry, key))
|
|
16
|
+
__defProp(entry, key, {
|
|
17
|
+
get: __accessProp.bind(from, key),
|
|
18
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
19
|
+
});
|
|
20
|
+
}
|
|
16
21
|
__moduleCache.set(from, entry);
|
|
17
22
|
return entry;
|
|
18
23
|
};
|
|
24
|
+
var __moduleCache;
|
|
25
|
+
var __returnValue = (v) => v;
|
|
26
|
+
function __exportSetter(name, newValue) {
|
|
27
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
28
|
+
}
|
|
19
29
|
var __export = (target, all) => {
|
|
20
30
|
for (var name in all)
|
|
21
31
|
__defProp(target, name, {
|
|
22
32
|
get: all[name],
|
|
23
33
|
enumerable: true,
|
|
24
34
|
configurable: true,
|
|
25
|
-
set: (
|
|
35
|
+
set: __exportSetter.bind(all, name)
|
|
26
36
|
});
|
|
27
37
|
};
|
|
28
38
|
|
|
@@ -458,6 +468,13 @@ function parseIdentifierSegment(value) {
|
|
|
458
468
|
}
|
|
459
469
|
return { value: trimmed };
|
|
460
470
|
}
|
|
471
|
+
function isUnqualifiedName(value) {
|
|
472
|
+
if (typeof value !== "string") {
|
|
473
|
+
return false;
|
|
474
|
+
}
|
|
475
|
+
const segments = splitQualifiedNameSegments(value.trim());
|
|
476
|
+
return segments !== null && segments.length === 1;
|
|
477
|
+
}
|
|
461
478
|
function splitQualifiedNameSegments(value) {
|
|
462
479
|
if (!value) {
|
|
463
480
|
return null;
|
|
@@ -534,9 +551,21 @@ function normalizeTableReference(ref, policy, mode = policy.tableIdentifierMatch
|
|
|
534
551
|
};
|
|
535
552
|
}
|
|
536
553
|
}
|
|
554
|
+
if (policy.defaultSchema) {
|
|
555
|
+
const schema = normalizeIdentifier(policy.defaultSchema, mode);
|
|
556
|
+
const name = normalizeIdentifier(ref.name, mode);
|
|
557
|
+
return {
|
|
558
|
+
success: true,
|
|
559
|
+
table: {
|
|
560
|
+
schema,
|
|
561
|
+
name,
|
|
562
|
+
fullyQualified: `${schema}.${name}`
|
|
563
|
+
}
|
|
564
|
+
};
|
|
565
|
+
}
|
|
537
566
|
return {
|
|
538
567
|
success: false,
|
|
539
|
-
error: `Unqualified table reference '${ref.name}' not allowed
|
|
568
|
+
error: `Unqualified table reference '${ref.name}' not allowed. Provide 'defaultSchema' or 'resolver' in policy.`
|
|
540
569
|
};
|
|
541
570
|
}
|
|
542
571
|
function normalizeIdentifier(ident, mode) {
|
|
@@ -811,9 +840,27 @@ function compilePolicy(policy) {
|
|
|
811
840
|
if (tableIdentifierMatching !== "strict" && tableIdentifierMatching !== "caseInsensitive") {
|
|
812
841
|
return invalidPolicy("Policy 'tableIdentifierMatching' must be either 'strict' or 'caseInsensitive'");
|
|
813
842
|
}
|
|
843
|
+
const METADATA_SCHEMAS = new Set(["information_schema", "pg_catalog"]);
|
|
844
|
+
const defaultSchema = policy.defaultSchema?.trim();
|
|
845
|
+
if (defaultSchema !== undefined) {
|
|
846
|
+
if (defaultSchema.length === 0) {
|
|
847
|
+
return invalidPolicy("Policy 'defaultSchema' must be a non-empty string when provided");
|
|
848
|
+
}
|
|
849
|
+
if (defaultSchema.includes(".") || !/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(defaultSchema)) {
|
|
850
|
+
return invalidPolicy("Policy 'defaultSchema' must be a valid SQL identifier without dots");
|
|
851
|
+
}
|
|
852
|
+
if (METADATA_SCHEMAS.has(defaultSchema.toLowerCase())) {
|
|
853
|
+
return invalidPolicy("Policy 'defaultSchema' cannot be a metadata schema (information_schema, pg_catalog). Metadata tables must be explicitly allowlisted.");
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
const normalizedDefaultSchema = defaultSchema ? canonicalizeIdentifier(defaultSchema, tableIdentifierMatching) : undefined;
|
|
814
857
|
const allowedTables = new Set;
|
|
815
858
|
for (const table of policy.allowedTables) {
|
|
816
|
-
|
|
859
|
+
let tableToCanonicalize = table;
|
|
860
|
+
if (normalizedDefaultSchema && isUnqualifiedName(table)) {
|
|
861
|
+
tableToCanonicalize = `${normalizedDefaultSchema}.${table}`;
|
|
862
|
+
}
|
|
863
|
+
const canonical = canonicalizeQualifiedName(tableToCanonicalize, tableIdentifierMatching);
|
|
817
864
|
if (!canonical) {
|
|
818
865
|
return invalidPolicy(`Policy entry '${String(table)}' is invalid. allowedTables entries must be schema-qualified as 'schema.table'`);
|
|
819
866
|
}
|
|
@@ -844,7 +891,8 @@ function compilePolicy(policy) {
|
|
|
844
891
|
allowedTables,
|
|
845
892
|
allowedFunctionsUnqualified,
|
|
846
893
|
allowedFunctionsQualified,
|
|
847
|
-
tableIdentifierMatching
|
|
894
|
+
tableIdentifierMatching,
|
|
895
|
+
defaultSchema: normalizedDefaultSchema
|
|
848
896
|
}
|
|
849
897
|
};
|
|
850
898
|
}
|
package/dist/esm/index.js
CHANGED
|
@@ -411,6 +411,13 @@ function parseIdentifierSegment(value) {
|
|
|
411
411
|
}
|
|
412
412
|
return { value: trimmed };
|
|
413
413
|
}
|
|
414
|
+
function isUnqualifiedName(value) {
|
|
415
|
+
if (typeof value !== "string") {
|
|
416
|
+
return false;
|
|
417
|
+
}
|
|
418
|
+
const segments = splitQualifiedNameSegments(value.trim());
|
|
419
|
+
return segments !== null && segments.length === 1;
|
|
420
|
+
}
|
|
414
421
|
function splitQualifiedNameSegments(value) {
|
|
415
422
|
if (!value) {
|
|
416
423
|
return null;
|
|
@@ -487,9 +494,21 @@ function normalizeTableReference(ref, policy, mode = policy.tableIdentifierMatch
|
|
|
487
494
|
};
|
|
488
495
|
}
|
|
489
496
|
}
|
|
497
|
+
if (policy.defaultSchema) {
|
|
498
|
+
const schema = normalizeIdentifier(policy.defaultSchema, mode);
|
|
499
|
+
const name = normalizeIdentifier(ref.name, mode);
|
|
500
|
+
return {
|
|
501
|
+
success: true,
|
|
502
|
+
table: {
|
|
503
|
+
schema,
|
|
504
|
+
name,
|
|
505
|
+
fullyQualified: `${schema}.${name}`
|
|
506
|
+
}
|
|
507
|
+
};
|
|
508
|
+
}
|
|
490
509
|
return {
|
|
491
510
|
success: false,
|
|
492
|
-
error: `Unqualified table reference '${ref.name}' not allowed
|
|
511
|
+
error: `Unqualified table reference '${ref.name}' not allowed. Provide 'defaultSchema' or 'resolver' in policy.`
|
|
493
512
|
};
|
|
494
513
|
}
|
|
495
514
|
function normalizeIdentifier(ident, mode) {
|
|
@@ -764,9 +783,27 @@ function compilePolicy(policy) {
|
|
|
764
783
|
if (tableIdentifierMatching !== "strict" && tableIdentifierMatching !== "caseInsensitive") {
|
|
765
784
|
return invalidPolicy("Policy 'tableIdentifierMatching' must be either 'strict' or 'caseInsensitive'");
|
|
766
785
|
}
|
|
786
|
+
const METADATA_SCHEMAS = new Set(["information_schema", "pg_catalog"]);
|
|
787
|
+
const defaultSchema = policy.defaultSchema?.trim();
|
|
788
|
+
if (defaultSchema !== undefined) {
|
|
789
|
+
if (defaultSchema.length === 0) {
|
|
790
|
+
return invalidPolicy("Policy 'defaultSchema' must be a non-empty string when provided");
|
|
791
|
+
}
|
|
792
|
+
if (defaultSchema.includes(".") || !/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(defaultSchema)) {
|
|
793
|
+
return invalidPolicy("Policy 'defaultSchema' must be a valid SQL identifier without dots");
|
|
794
|
+
}
|
|
795
|
+
if (METADATA_SCHEMAS.has(defaultSchema.toLowerCase())) {
|
|
796
|
+
return invalidPolicy("Policy 'defaultSchema' cannot be a metadata schema (information_schema, pg_catalog). Metadata tables must be explicitly allowlisted.");
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
const normalizedDefaultSchema = defaultSchema ? canonicalizeIdentifier(defaultSchema, tableIdentifierMatching) : undefined;
|
|
767
800
|
const allowedTables = new Set;
|
|
768
801
|
for (const table of policy.allowedTables) {
|
|
769
|
-
|
|
802
|
+
let tableToCanonicalize = table;
|
|
803
|
+
if (normalizedDefaultSchema && isUnqualifiedName(table)) {
|
|
804
|
+
tableToCanonicalize = `${normalizedDefaultSchema}.${table}`;
|
|
805
|
+
}
|
|
806
|
+
const canonical = canonicalizeQualifiedName(tableToCanonicalize, tableIdentifierMatching);
|
|
770
807
|
if (!canonical) {
|
|
771
808
|
return invalidPolicy(`Policy entry '${String(table)}' is invalid. allowedTables entries must be schema-qualified as 'schema.table'`);
|
|
772
809
|
}
|
|
@@ -797,7 +834,8 @@ function compilePolicy(policy) {
|
|
|
797
834
|
allowedTables,
|
|
798
835
|
allowedFunctionsUnqualified,
|
|
799
836
|
allowedFunctionsQualified,
|
|
800
|
-
tableIdentifierMatching
|
|
837
|
+
tableIdentifierMatching,
|
|
838
|
+
defaultSchema: normalizedDefaultSchema
|
|
801
839
|
}
|
|
802
840
|
};
|
|
803
841
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"identifier.d.ts","sourceRoot":"","sources":["../../src/normalize/identifier.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AACvE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEtD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,mCAAmC;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,iBAAiB;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,mDAAmD;IACnD,cAAc,EAAE,MAAM,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,sCAAsC;IACtC,OAAO,EAAE,OAAO,CAAC;IACjB,6DAA6D;IAC7D,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB,uDAAuD;IACvD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CACrC,GAAG,EAAE,cAAc,EACnB,MAAM,EAAE,MAAM,EACd,IAAI,GAAE,uBAAoE,GACzE,mBAAmB,
|
|
1
|
+
{"version":3,"file":"identifier.d.ts","sourceRoot":"","sources":["../../src/normalize/identifier.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AACvE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEtD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,mCAAmC;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,iBAAiB;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,mDAAmD;IACnD,cAAc,EAAE,MAAM,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,sCAAsC;IACtC,OAAO,EAAE,OAAO,CAAC;IACjB,6DAA6D;IAC7D,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB,uDAAuD;IACvD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CACrC,GAAG,EAAE,cAAc,EACnB,MAAM,EAAE,MAAM,EACd,IAAI,GAAE,uBAAoE,GACzE,mBAAmB,CAiErB;AAcD;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAC5B,UAAU,EAAE,eAAe,EAC3B,aAAa,EAAE,QAAQ,CAAC,MAAM,CAAC,EAC/B,IAAI,GAAE,uBAAkC,GACvC,OAAO,CAcT"}
|
|
@@ -6,4 +6,18 @@ export interface QualifiedNameParts {
|
|
|
6
6
|
}
|
|
7
7
|
export declare function parseQualifiedName(value: unknown, mode?: TableIdentifierMatching): QualifiedNameParts | null;
|
|
8
8
|
export declare function canonicalizeIdentifier(value: string, mode: TableIdentifierMatching): string;
|
|
9
|
+
/**
|
|
10
|
+
* Check if a table name is unqualified (has no schema prefix).
|
|
11
|
+
* Uses quote-aware parsing to correctly handle quoted identifiers with dots.
|
|
12
|
+
*
|
|
13
|
+
* Examples:
|
|
14
|
+
* - `users` → true (unqualified)
|
|
15
|
+
* - `"audit.log"` → true (unqualified, dot is inside identifier)
|
|
16
|
+
* - `public.users` → false (qualified)
|
|
17
|
+
* - `"public"."users"` → false (qualified)
|
|
18
|
+
*
|
|
19
|
+
* @param value The table name to check
|
|
20
|
+
* @returns True if the name is unqualified (single segment)
|
|
21
|
+
*/
|
|
22
|
+
export declare function isUnqualifiedName(value: unknown): boolean;
|
|
9
23
|
//# sourceMappingURL=qualified-name.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"qualified-name.d.ts","sourceRoot":"","sources":["../../src/normalize/qualified-name.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAE/D,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,OAAO,EACd,IAAI,GAAE,uBAAkC,GACvC,kBAAkB,GAAG,IAAI,CA2B3B;AAED,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,uBAAuB,GAC5B,MAAM,CAGR"}
|
|
1
|
+
{"version":3,"file":"qualified-name.d.ts","sourceRoot":"","sources":["../../src/normalize/qualified-name.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAE/D,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,OAAO,EACd,IAAI,GAAE,uBAAkC,GACvC,kBAAkB,GAAG,IAAI,CA2B3B;AAED,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,uBAAuB,GAC5B,MAAM,CAGR;AA6BD;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAOzD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compile-policy.d.ts","sourceRoot":"","sources":["../../src/policy/compile-policy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,OAAO,KAAK,EAAE,MAAM,EAAE,uBAAuB,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAElF,MAAM,WAAW,cAAc;IAC7B,aAAa,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC3B,2BAA2B,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACzC,yBAAyB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACvC,uBAAuB,EAAE,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"compile-policy.d.ts","sourceRoot":"","sources":["../../src/policy/compile-policy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,OAAO,KAAK,EAAE,MAAM,EAAE,uBAAuB,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAElF,MAAM,WAAW,cAAc;IAC7B,aAAa,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC3B,2BAA2B,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACzC,yBAAyB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACvC,uBAAuB,EAAE,uBAAuB,CAAC;IACjD,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,KAAK,mBAAmB,GACpB;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,cAAc,CAAA;CAAE,GAC3C;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,SAAS,EAAE,SAAS,CAAC,cAAc,CAAC;IAAC,SAAS,EAAE,SAAS,CAAA;CAAE,CAAC;AAElF,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,mBAAmB,CAuFjE;AA2BD,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,OAAO,EACd,IAAI,GAAE,uBAAkC,GACvC,MAAM,GAAG,IAAI,CAGf"}
|
package/dist/types/public.d.ts
CHANGED
|
@@ -97,6 +97,19 @@ export interface Policy {
|
|
|
97
97
|
* ```
|
|
98
98
|
*/
|
|
99
99
|
resolver?: (unqualified: string) => string | null;
|
|
100
|
+
/**
|
|
101
|
+
* Default schema to use for unqualified table references.
|
|
102
|
+
* When provided, entries in `allowedTables` without a schema qualifier are
|
|
103
|
+
* automatically prefixed with this schema. Also used to resolve unqualified
|
|
104
|
+
* table references in SQL (unless a resolver is provided that returns non-null).
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* ```typescript
|
|
108
|
+
* defaultSchema: 'public',
|
|
109
|
+
* allowedTables: ['users', 'orders'] // treated as ['public.users', 'public.orders']
|
|
110
|
+
* ```
|
|
111
|
+
*/
|
|
112
|
+
defaultSchema?: string;
|
|
100
113
|
}
|
|
101
114
|
/**
|
|
102
115
|
* Result of validating a SQL query against a policy.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../src/types/public.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,oBAAY,SAAS;IACnB,0CAA0C;IAC1C,WAAW,gBAAgB;IAC3B,8EAA8E;IAC9E,uBAAuB,4BAA4B;IACnD,wDAAwD;IACxD,iBAAiB,sBAAsB;IACvC,yEAAyE;IACzE,qBAAqB,0BAA0B;IAC/C,qDAAqD;IACrD,oBAAoB,yBAAyB;IAC7C,+EAA+E;IAC/E,wBAAwB,6BAA6B;IACrD,sCAAsC;IACtC,cAAc,mBAAmB;CAClC;AAED;;;;;GAKG;AACH,MAAM,MAAM,uBAAuB,GAAG,QAAQ,GAAG,iBAAiB,CAAC;AAEnE;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,MAAM;IACrB;;;;OAIG;IACH,aAAa,EAAE,MAAM,EAAE,CAAC;IAExB;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,CAAC,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC,EAAE,CAAC;IAElE;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAE9B;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAE5B;;;;;OAKG;IACH,uBAAuB,CAAC,EAAE,uBAAuB,CAAC;IAElD;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../src/types/public.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,oBAAY,SAAS;IACnB,0CAA0C;IAC1C,WAAW,gBAAgB;IAC3B,8EAA8E;IAC9E,uBAAuB,4BAA4B;IACnD,wDAAwD;IACxD,iBAAiB,sBAAsB;IACvC,yEAAyE;IACzE,qBAAqB,0BAA0B;IAC/C,qDAAqD;IACrD,oBAAoB,yBAAyB;IAC7C,+EAA+E;IAC/E,wBAAwB,6BAA6B;IACrD,sCAAsC;IACtC,cAAc,mBAAmB;CAClC;AAED;;;;;GAKG;AACH,MAAM,MAAM,uBAAuB,GAAG,QAAQ,GAAG,iBAAiB,CAAC;AAEnE;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,MAAM;IACrB;;;;OAIG;IACH,aAAa,EAAE,MAAM,EAAE,CAAC;IAExB;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,CAAC,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC,EAAE,CAAC;IAElE;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAE9B;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAE5B;;;;;OAKG;IACH,uBAAuB,CAAC,EAAE,uBAAuB,CAAC;IAElD;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;IAElD;;;;;;;;;;;OAWG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,gBAAgB;IAC/B,+CAA+C;IAC/C,EAAE,EAAE,OAAO,CAAC;IACZ,uEAAuE;IACvE,UAAU,EAAE,SAAS,EAAE,CAAC;IACxB,8EAA8E;IAC9E,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB;AAED;;;GAGG;AACH,MAAM,WAAW,SAAS;IACxB,wBAAwB;IACxB,IAAI,EAAE,OAAO,GAAG,WAAW,GAAG,UAAU,GAAG,OAAO,GAAG,aAAa,GAAG,QAAQ,CAAC;IAC9E,kDAAkD;IAClD,OAAO,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,QAAQ,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC/C;AAED;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,kBAAmB,SAAQ,KAAK;IASzC,2DAA2D;aAC3C,IAAI,EAAE,SAAS;IAC/B,kDAAkD;aAClC,UAAU,EAAE,SAAS,EAAE;IAXzC;;;;;OAKG;gBAED,OAAO,EAAE,MAAM;IACf,2DAA2D;IAC3C,IAAI,EAAE,SAAS;IAC/B,kDAAkD;IAClC,UAAU,EAAE,SAAS,EAAE;CAK1C"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sql-guard",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Validate AI-generated PostgreSQL queries against explicit table allowlists",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -43,8 +43,36 @@
|
|
|
43
43
|
"security",
|
|
44
44
|
"llm",
|
|
45
45
|
"guard",
|
|
46
|
-
"allowlist"
|
|
46
|
+
"allowlist",
|
|
47
|
+
"validation",
|
|
48
|
+
"postgresql",
|
|
49
|
+
"postgres",
|
|
50
|
+
"ast",
|
|
51
|
+
"parser",
|
|
52
|
+
"sanitize",
|
|
53
|
+
"injection",
|
|
54
|
+
"prevent",
|
|
55
|
+
"ai",
|
|
56
|
+
"chatgpt",
|
|
57
|
+
"codegen",
|
|
58
|
+
"database",
|
|
59
|
+
"query",
|
|
60
|
+
"policy",
|
|
61
|
+
"whitelist",
|
|
62
|
+
"rbac",
|
|
63
|
+
"least-privilege"
|
|
47
64
|
],
|
|
48
|
-
"author": "",
|
|
49
|
-
"license": "MIT"
|
|
65
|
+
"author": "Nur Zaman",
|
|
66
|
+
"license": "MIT",
|
|
67
|
+
"repository": {
|
|
68
|
+
"type": "git",
|
|
69
|
+
"url": "git+https://github.com/nur-zaman/sql-guard.git"
|
|
70
|
+
},
|
|
71
|
+
"bugs": {
|
|
72
|
+
"url": "https://github.com/nur-zaman/sql-guard/issues"
|
|
73
|
+
},
|
|
74
|
+
"homepage": "https://github.com/nur-zaman/sql-guard#readme",
|
|
75
|
+
"engines": {
|
|
76
|
+
"node": ">=18"
|
|
77
|
+
}
|
|
50
78
|
}
|