gateia 0.1.2 → 0.1.4
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 +83 -13
- package/dist/engine/contract.d.ts +4 -0
- package/dist/engine/contract.js +7 -3
- package/dist/index.js +51 -29
- package/dist/policies/finance.d.ts +8 -0
- package/dist/policies/finance.js +35 -0
- package/dist/policies/index.d.ts +6 -0
- package/dist/policies/index.js +33 -0
- package/dist/policies/markup.d.ts +2 -0
- package/dist/policies/markup.js +34 -0
- package/dist/policies/pii.d.ts +2 -0
- package/dist/policies/pii.js +36 -0
- package/dist/policies/secrets.d.ts +2 -0
- package/dist/policies/secrets.js +33 -0
- package/dist/types.d.ts +38 -11
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -33,14 +33,14 @@ const result = await gate({
|
|
|
33
33
|
model: "gpt-4.1",
|
|
34
34
|
prompt: "Analyze this refund request against policy...",
|
|
35
35
|
contract: RefundSchema,
|
|
36
|
-
policies: ["support-safe"
|
|
36
|
+
policies: ["support-safe"]
|
|
37
37
|
});
|
|
38
38
|
|
|
39
39
|
console.log(result.safeOutput);
|
|
40
40
|
// { valid: true, reason: "Item damaged in transit", refund_amount: 49.99 }
|
|
41
41
|
|
|
42
42
|
console.log(result.enforcement.appliedPolicies);
|
|
43
|
-
// ['finance-safe', '
|
|
43
|
+
// [{ id: 'finance-safe', outcome: 'pass' }]
|
|
44
44
|
|
|
45
45
|
console.log(result.traceId);
|
|
46
46
|
// "uuid..."
|
|
@@ -69,22 +69,92 @@ GATEIA_MOCK_ADAPTERS=true
|
|
|
69
69
|
- `policies`: Array of policy IDs (strings) or Policy objects.
|
|
70
70
|
- `behavior`: Logic for repair, retries, and blocking.
|
|
71
71
|
|
|
72
|
+
**Returns:** `Promise<GateResult<T>>`
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
type GateResult<T> = {
|
|
76
|
+
safeOutput?: T; // Type-safe validated output
|
|
77
|
+
traceId: string; // Unique ID for this request
|
|
78
|
+
|
|
79
|
+
enforcement: {
|
|
80
|
+
appliedPolicies: Array<{
|
|
81
|
+
id: string;
|
|
82
|
+
mode: "enforce" | "audit";
|
|
83
|
+
outcome: "pass" | "warn" | "block";
|
|
84
|
+
reasons?: string[];
|
|
85
|
+
}>;
|
|
86
|
+
|
|
87
|
+
contract: {
|
|
88
|
+
outcome: "pass" | "fail" | "repaired";
|
|
89
|
+
errors?: Array<{ path: string; message: string }>;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
actions: Array<{ type: "rewrite" | "block"; policyId?: string; }>;
|
|
93
|
+
violations: Array<{
|
|
94
|
+
policyId: string;
|
|
95
|
+
code: string;
|
|
96
|
+
severity: "low"|"med"|"high";
|
|
97
|
+
message: string;
|
|
98
|
+
}>;
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
usage: {
|
|
102
|
+
model: string;
|
|
103
|
+
provider: string;
|
|
104
|
+
latencyMs: number;
|
|
105
|
+
tokens?: { prompt: number; completion: number; total: number };
|
|
106
|
+
costUsd?: number;
|
|
107
|
+
};
|
|
108
|
+
};
|
|
109
|
+
```
|
|
110
|
+
|
|
72
111
|
### Policies
|
|
73
112
|
|
|
74
|
-
|
|
75
|
-
- `finance-safe`: Blocks "guaranteed returns".
|
|
76
|
-
- `no-hallucinations`: (Audit only) Placeholder for hallucination checks.
|
|
113
|
+
## Policy Library
|
|
77
114
|
|
|
78
|
-
|
|
115
|
+
Gateia comes with a set of built-in policies you can use immediately.
|
|
116
|
+
|
|
117
|
+
| Policy ID | Function | Checks For | Outcome |
|
|
118
|
+
|-----------|----------|------------|---------|
|
|
119
|
+
| **`finance-safe`** | Financial Compliance | "Guaranteed returns", "No risk", "Guaranteed approval", "100% guaranteed" | `BLOCK` |
|
|
120
|
+
| **`support-safe`** | Support Safety (Alias) | Same as above. Useful for refund processing agents. | `BLOCK` |
|
|
121
|
+
| **`pii-safe`** | Data Privacy | Email addresses (`x@y.com`), Phone numbers (Format: `123-456-7890`) | `BLOCK` |
|
|
122
|
+
| **`secrets-safe`** | Security | API Keys (OpenAI, AWS, GitHub), Private Keys | `BLOCK` |
|
|
123
|
+
| **`markup-safe`** | XSS Prevention | `<script>`, `<iframe>`, `javascript:` URIs | `BLOCK` |
|
|
124
|
+
|
|
125
|
+
### Custom Policies
|
|
79
126
|
```typescript
|
|
80
|
-
{
|
|
81
|
-
|
|
82
|
-
|
|
127
|
+
import { gate, Policy } from 'gateia';
|
|
128
|
+
|
|
129
|
+
// 1. Define your custom policy
|
|
130
|
+
const noCompetitors: Policy = {
|
|
131
|
+
id: 'no-competitors',
|
|
132
|
+
mode: 'enforce', // 'audit' to just warn
|
|
83
133
|
check: (output) => {
|
|
84
|
-
|
|
85
|
-
|
|
134
|
+
// output is strict typed from your Contract (or string if simple)
|
|
135
|
+
const text = JSON.stringify(output).toLowerCase();
|
|
136
|
+
|
|
137
|
+
if (text.includes('acme corp')) {
|
|
138
|
+
return {
|
|
139
|
+
outcome: 'block',
|
|
140
|
+
violations: [{
|
|
141
|
+
policyId: 'no-competitors',
|
|
142
|
+
code: 'COMPETITOR_MENTION',
|
|
143
|
+
message: 'Mentioned competitor Acme Corp',
|
|
144
|
+
severity: 'high',
|
|
145
|
+
evidence: { snippet: 'acme corp' }
|
|
146
|
+
}]
|
|
147
|
+
};
|
|
86
148
|
}
|
|
87
|
-
return { outcome:
|
|
149
|
+
return { outcome: 'pass' };
|
|
88
150
|
}
|
|
89
|
-
}
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
// 2. Use it in the gate
|
|
154
|
+
await gate({
|
|
155
|
+
model: 'gpt-4',
|
|
156
|
+
prompt: 'Who is the best provider?',
|
|
157
|
+
contract: z.string(),
|
|
158
|
+
policies: ['finance-safe', noCompetitors] // Mix built-in ID strings and custom objects
|
|
159
|
+
});
|
|
90
160
|
```
|
package/dist/engine/contract.js
CHANGED
|
@@ -8,10 +8,14 @@ class ContractEngine {
|
|
|
8
8
|
return { success: true, data: result.data };
|
|
9
9
|
}
|
|
10
10
|
else {
|
|
11
|
-
const
|
|
12
|
-
|
|
11
|
+
const formattedErrors = result.error.errors.map(e => ({
|
|
12
|
+
path: e.path.join('.'),
|
|
13
|
+
message: e.message
|
|
14
|
+
}));
|
|
15
|
+
const errorMsg = formattedErrors
|
|
16
|
+
.map((e) => `${e.path}: ${e.message}`)
|
|
13
17
|
.join('; ');
|
|
14
|
-
return { success: false, error: errorMsg };
|
|
18
|
+
return { success: false, error: errorMsg, errors: formattedErrors };
|
|
15
19
|
}
|
|
16
20
|
}
|
|
17
21
|
// Helper to format error for the LLM repair prompt
|
package/dist/index.js
CHANGED
|
@@ -21,8 +21,8 @@ const uuid_1 = require("uuid");
|
|
|
21
21
|
const registry_1 = require("./adapters/registry");
|
|
22
22
|
const contract_1 = require("./engine/contract");
|
|
23
23
|
const policy_1 = require("./engine/policy");
|
|
24
|
-
const
|
|
25
|
-
// Global instances
|
|
24
|
+
const policies_1 = require("./policies");
|
|
25
|
+
// Global instances
|
|
26
26
|
const registry = new registry_1.ModelRegistry();
|
|
27
27
|
const contractEngine = new contract_1.ContractEngine();
|
|
28
28
|
const policyEngine = new policy_1.PolicyEngine();
|
|
@@ -35,7 +35,7 @@ async function gate(params) {
|
|
|
35
35
|
// 2. Resolve Policies
|
|
36
36
|
const activePolicies = policies.map(p => {
|
|
37
37
|
if (typeof p === 'string') {
|
|
38
|
-
const found =
|
|
38
|
+
const found = policies_1.policyLibrary[p];
|
|
39
39
|
if (!found)
|
|
40
40
|
throw new types_1.GateiaError(`Unknown policy: ${p}`, traceId);
|
|
41
41
|
return found;
|
|
@@ -126,15 +126,30 @@ async function gate(params) {
|
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
128
|
}
|
|
129
|
+
// Construct usage object
|
|
130
|
+
const finalUsage = {
|
|
131
|
+
provider: registry.getAdapter(model).constructor.name,
|
|
132
|
+
model: params.model,
|
|
133
|
+
latencyMs: finalLatency,
|
|
134
|
+
inputTokens: totalTokens.prompt,
|
|
135
|
+
outputTokens: totalTokens.completion,
|
|
136
|
+
totalTokens: totalTokens.total,
|
|
137
|
+
// costUsd: ... // TODO: Add cost calculation logic based on provider/model
|
|
138
|
+
};
|
|
129
139
|
if (!finalSafeOutput) {
|
|
130
140
|
// Block/Throw
|
|
131
141
|
// Construct report
|
|
132
142
|
const report = {
|
|
133
|
-
appliedPolicies:
|
|
134
|
-
|
|
143
|
+
appliedPolicies: [], // Policies not applied due to contract failure
|
|
144
|
+
contract: {
|
|
145
|
+
outcome: 'fail',
|
|
146
|
+
errors: contractEngine.validate(rawResult, contract).errors // re-running valid logic or grabbing from lastError
|
|
147
|
+
},
|
|
135
148
|
actions: [],
|
|
136
|
-
violations: [{ policyId: 'contract', message: lastError || "Contract Validation Failed", severity: '
|
|
149
|
+
violations: [{ policyId: 'contract', code: 'CONTRACT_FAIL', message: lastError || "Contract Validation Failed", severity: 'high' }]
|
|
137
150
|
};
|
|
151
|
+
// For accurate errors we might want to capture them better above instead of re-running or assuming lastError string
|
|
152
|
+
// But for now this matches structure.
|
|
138
153
|
throw new types_1.GateiaError("Contract Check Failed", traceId, report);
|
|
139
154
|
}
|
|
140
155
|
// 4. Apply Policies
|
|
@@ -144,47 +159,54 @@ async function gate(params) {
|
|
|
144
159
|
const policyResult = await policyEngine.evaluate(activePolicies, finalSafeOutput, policyCtx);
|
|
145
160
|
let finalViolations = policyResult.violations || [];
|
|
146
161
|
let enforcementActions = [];
|
|
162
|
+
// Detailed policy reporting
|
|
163
|
+
const appliedRecs = activePolicies.map(p => {
|
|
164
|
+
const policyViolations = finalViolations.filter(v => v.policyId === p.id);
|
|
165
|
+
let outcome = 'pass';
|
|
166
|
+
if (policyViolations.length > 0) {
|
|
167
|
+
const isBlock = policyViolations.some(v => v.severity === 'high');
|
|
168
|
+
outcome = isBlock ? 'block' : 'warn';
|
|
169
|
+
}
|
|
170
|
+
return {
|
|
171
|
+
id: p.id,
|
|
172
|
+
version: p.version,
|
|
173
|
+
mode: p.mode || 'enforce',
|
|
174
|
+
outcome,
|
|
175
|
+
reasons: policyViolations.map(v => v.message)
|
|
176
|
+
};
|
|
177
|
+
});
|
|
147
178
|
if (policyResult.rewrittenOutput) {
|
|
148
179
|
finalSafeOutput = policyResult.rewrittenOutput;
|
|
149
|
-
enforcementActions.push('rewritten');
|
|
180
|
+
enforcementActions.push({ type: 'rewrite', policyId: 'policy-engine', note: 'Content rewritten by policy' });
|
|
150
181
|
}
|
|
182
|
+
const report = {
|
|
183
|
+
appliedPolicies: appliedRecs,
|
|
184
|
+
contract: {
|
|
185
|
+
outcome: contractOutcome,
|
|
186
|
+
// If repaired, we could list repairs here if we tracked them detailly
|
|
187
|
+
},
|
|
188
|
+
actions: enforcementActions,
|
|
189
|
+
violations: finalViolations
|
|
190
|
+
};
|
|
151
191
|
if (policyResult.outcome === 'block') {
|
|
152
|
-
const report = {
|
|
153
|
-
appliedPolicies: activePolicies.map(p => p.id),
|
|
154
|
-
contractOutcome,
|
|
155
|
-
actions: enforcementActions,
|
|
156
|
-
violations: finalViolations
|
|
157
|
-
};
|
|
158
192
|
const onBlock = behavior?.onBlock || 'throw'; // Default throw?
|
|
159
193
|
if (onBlock === 'throw') {
|
|
160
194
|
throw new types_1.GateiaError("Policy Blocked Response", traceId, report);
|
|
161
195
|
}
|
|
162
196
|
// Return with no safeOutput? Or just raw?
|
|
163
|
-
// Result<T> safeOutput is optional.
|
|
164
197
|
return {
|
|
198
|
+
safeOutput: undefined,
|
|
165
199
|
traceId,
|
|
166
200
|
enforcement: report,
|
|
167
|
-
usage:
|
|
168
|
-
|
|
201
|
+
usage: finalUsage,
|
|
202
|
+
rawOutput: options?.includeRawOutput ? rawResult : undefined
|
|
169
203
|
};
|
|
170
204
|
}
|
|
171
|
-
// Success
|
|
172
|
-
const report = {
|
|
173
|
-
appliedPolicies: activePolicies.map(p => p.id),
|
|
174
|
-
contractOutcome,
|
|
175
|
-
actions: enforcementActions,
|
|
176
|
-
violations: finalViolations
|
|
177
|
-
};
|
|
178
205
|
return {
|
|
179
206
|
safeOutput: finalSafeOutput,
|
|
180
207
|
traceId,
|
|
181
208
|
enforcement: report,
|
|
182
|
-
usage:
|
|
183
|
-
provider: registry.getAdapter(model).constructor.name, // quick hack name
|
|
184
|
-
model: params.model,
|
|
185
|
-
tokens: totalTokens,
|
|
186
|
-
latencyMs: finalLatency
|
|
187
|
-
},
|
|
209
|
+
usage: finalUsage,
|
|
188
210
|
rawOutput: options?.includeRawOutput ? rawResult : undefined
|
|
189
211
|
};
|
|
190
212
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Policy } from '../types';
|
|
2
|
+
export declare const financeSafe: Policy;
|
|
3
|
+
export declare const supportSafe: {
|
|
4
|
+
id: string;
|
|
5
|
+
version?: string;
|
|
6
|
+
mode?: "enforce" | "audit";
|
|
7
|
+
check: (output: any, context: import("../types").PolicyContext) => import("../types").PolicyResult | Promise<import("../types").PolicyResult>;
|
|
8
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.supportSafe = exports.financeSafe = void 0;
|
|
4
|
+
exports.financeSafe = {
|
|
5
|
+
id: 'finance-safe',
|
|
6
|
+
mode: 'enforce',
|
|
7
|
+
check: (output) => {
|
|
8
|
+
const text = typeof output === 'string' ? output : JSON.stringify(output);
|
|
9
|
+
const lower = text.toLowerCase();
|
|
10
|
+
// Block guarantees
|
|
11
|
+
const forbidden = [
|
|
12
|
+
'guaranteed refund',
|
|
13
|
+
'guaranteed return',
|
|
14
|
+
'guaranteed approval',
|
|
15
|
+
'no risk',
|
|
16
|
+
'100% guaranteed'
|
|
17
|
+
];
|
|
18
|
+
const match = forbidden.find(phrase => lower.includes(phrase));
|
|
19
|
+
if (match) {
|
|
20
|
+
return {
|
|
21
|
+
outcome: 'block',
|
|
22
|
+
violations: [{
|
|
23
|
+
policyId: 'finance-safe',
|
|
24
|
+
code: 'FIN_GUARANTEE',
|
|
25
|
+
message: `Contains forbidden guarantee language: "${match}"`,
|
|
26
|
+
severity: 'high',
|
|
27
|
+
evidence: { snippet: match }
|
|
28
|
+
}]
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
return { outcome: 'pass' };
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
// Delegate alias
|
|
35
|
+
exports.supportSafe = { ...exports.financeSafe, id: 'support-safe' };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.policyLibrary = void 0;
|
|
18
|
+
const finance_1 = require("./finance");
|
|
19
|
+
const pii_1 = require("./pii");
|
|
20
|
+
const secrets_1 = require("./secrets");
|
|
21
|
+
const markup_1 = require("./markup");
|
|
22
|
+
// Registry of all built-in policies
|
|
23
|
+
exports.policyLibrary = {
|
|
24
|
+
'finance-safe': finance_1.financeSafe,
|
|
25
|
+
'support-safe': finance_1.supportSafe,
|
|
26
|
+
'pii-safe': pii_1.piiSafe,
|
|
27
|
+
'secrets-safe': secrets_1.secretsSafe,
|
|
28
|
+
'markup-safe': markup_1.markupSafe
|
|
29
|
+
};
|
|
30
|
+
__exportStar(require("./finance"), exports);
|
|
31
|
+
__exportStar(require("./pii"), exports);
|
|
32
|
+
__exportStar(require("./secrets"), exports);
|
|
33
|
+
__exportStar(require("./markup"), exports);
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.markupSafe = void 0;
|
|
4
|
+
exports.markupSafe = {
|
|
5
|
+
id: 'markup-safe',
|
|
6
|
+
mode: 'enforce',
|
|
7
|
+
check: (output) => {
|
|
8
|
+
const text = typeof output === 'string' ? output : JSON.stringify(output);
|
|
9
|
+
const lower = text.toLowerCase();
|
|
10
|
+
// Dangerous HTML/Script patterns
|
|
11
|
+
const patterns = [
|
|
12
|
+
{ name: 'Script Tag', regex: /<script[\s\S]*?>/i },
|
|
13
|
+
{ name: 'Iframe Tag', regex: /<iframe[\s\S]*?>/i },
|
|
14
|
+
{ name: 'Object Tag', regex: /<object[\s\S]*?>/i },
|
|
15
|
+
{ name: 'Javascript Protocol', regex: /javascript:/i }
|
|
16
|
+
];
|
|
17
|
+
const violations = [];
|
|
18
|
+
for (const pattern of patterns) {
|
|
19
|
+
if (pattern.regex.test(text)) {
|
|
20
|
+
violations.push({
|
|
21
|
+
policyId: 'markup-safe',
|
|
22
|
+
code: 'UNSAFE_MARKUP',
|
|
23
|
+
message: `Unsafe markup detected: ${pattern.name}`,
|
|
24
|
+
severity: 'high',
|
|
25
|
+
evidence: { snippet: pattern.regex.source }
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
if (violations.length > 0) {
|
|
30
|
+
return { outcome: 'block', violations };
|
|
31
|
+
}
|
|
32
|
+
return { outcome: 'pass' };
|
|
33
|
+
}
|
|
34
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.piiSafe = void 0;
|
|
4
|
+
exports.piiSafe = {
|
|
5
|
+
id: 'pii-safe',
|
|
6
|
+
mode: 'enforce',
|
|
7
|
+
check: (output) => {
|
|
8
|
+
const text = typeof output === 'string' ? output : JSON.stringify(output);
|
|
9
|
+
// Simple regex patterns (for MVP)
|
|
10
|
+
const emailRegex = /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/;
|
|
11
|
+
const phoneRegex = /\b\d{3}[-.]?\d{3}[-.]?\d{4}\b/; // US-centric simple
|
|
12
|
+
const violations = [];
|
|
13
|
+
if (emailRegex.test(text)) {
|
|
14
|
+
violations.push({
|
|
15
|
+
policyId: 'pii-safe',
|
|
16
|
+
code: 'PII_EMAIL',
|
|
17
|
+
message: 'Email address detected in output',
|
|
18
|
+
severity: 'high',
|
|
19
|
+
evidence: { snippet: 'email-detected-redacted' }
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
if (phoneRegex.test(text)) {
|
|
23
|
+
violations.push({
|
|
24
|
+
policyId: 'pii-safe',
|
|
25
|
+
code: 'PII_PHONE',
|
|
26
|
+
message: 'Phone number detected in output',
|
|
27
|
+
severity: 'high',
|
|
28
|
+
evidence: { snippet: 'phone-detected-redacted' }
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
if (violations.length > 0) {
|
|
32
|
+
return { outcome: 'block', violations };
|
|
33
|
+
}
|
|
34
|
+
return { outcome: 'pass' };
|
|
35
|
+
}
|
|
36
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.secretsSafe = void 0;
|
|
4
|
+
exports.secretsSafe = {
|
|
5
|
+
id: 'secrets-safe',
|
|
6
|
+
mode: 'enforce',
|
|
7
|
+
check: (output) => {
|
|
8
|
+
const text = typeof output === 'string' ? output : JSON.stringify(output);
|
|
9
|
+
// Common patterns for API keys and secrets
|
|
10
|
+
const patterns = [
|
|
11
|
+
{ name: 'OpenAI Key', regex: /sk-[a-zA-Z0-9]{20,}/ },
|
|
12
|
+
{ name: 'AWS Access Key', regex: /AKIA[0-9A-Z]{16}/ },
|
|
13
|
+
{ name: 'Generic Private Key', regex: /-----BEGIN PRIVATE KEY-----/ },
|
|
14
|
+
{ name: 'GitHub Token', regex: /ghp_[a-zA-Z0-9]{36}/ }
|
|
15
|
+
];
|
|
16
|
+
const violations = [];
|
|
17
|
+
for (const pattern of patterns) {
|
|
18
|
+
if (pattern.regex.test(text)) {
|
|
19
|
+
violations.push({
|
|
20
|
+
policyId: 'secrets-safe',
|
|
21
|
+
code: 'SECRET_DETECTED',
|
|
22
|
+
message: `Potential ${pattern.name} detected`,
|
|
23
|
+
severity: 'high',
|
|
24
|
+
evidence: { snippet: 'REDACTED_SECRET' } // Never show the secret
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
if (violations.length > 0) {
|
|
29
|
+
return { outcome: 'block', violations };
|
|
30
|
+
}
|
|
31
|
+
return { outcome: 'pass' };
|
|
32
|
+
}
|
|
33
|
+
};
|
package/dist/types.d.ts
CHANGED
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
export type GateOutcome = 'pass' | 'block' | 'warn' | 'rewrite';
|
|
3
|
-
export
|
|
3
|
+
export interface PolicyAction {
|
|
4
|
+
type: 'rewrite' | 'block' | 'log';
|
|
5
|
+
policyId: string;
|
|
6
|
+
note?: string;
|
|
7
|
+
}
|
|
4
8
|
export interface Violation {
|
|
5
9
|
policyId: string;
|
|
10
|
+
code: string;
|
|
6
11
|
message: string;
|
|
7
|
-
severity: '
|
|
12
|
+
severity: 'low' | 'med' | 'high';
|
|
13
|
+
evidence?: {
|
|
14
|
+
snippet: string;
|
|
15
|
+
};
|
|
8
16
|
}
|
|
9
17
|
export interface PolicyContext {
|
|
10
18
|
model: string;
|
|
@@ -48,21 +56,40 @@ export interface GateParams<T extends z.ZodTypeAny> {
|
|
|
48
56
|
behavior?: GateBehavior;
|
|
49
57
|
options?: GateOptions;
|
|
50
58
|
}
|
|
59
|
+
export interface AppliedPolicyRec {
|
|
60
|
+
id: string;
|
|
61
|
+
version?: string;
|
|
62
|
+
mode: 'enforce' | 'audit';
|
|
63
|
+
outcome: GateOutcome;
|
|
64
|
+
reasons?: string[];
|
|
65
|
+
}
|
|
66
|
+
export interface ContractEnforcement {
|
|
67
|
+
name?: string;
|
|
68
|
+
outcome: 'pass' | 'fail' | 'repaired';
|
|
69
|
+
errors?: {
|
|
70
|
+
path: string;
|
|
71
|
+
message: string;
|
|
72
|
+
}[];
|
|
73
|
+
repairs?: {
|
|
74
|
+
op: 'add' | 'remove' | 'replace';
|
|
75
|
+
path: string;
|
|
76
|
+
note?: string;
|
|
77
|
+
}[];
|
|
78
|
+
}
|
|
51
79
|
export interface GateEnforcementReport {
|
|
52
|
-
appliedPolicies:
|
|
53
|
-
|
|
54
|
-
actions:
|
|
80
|
+
appliedPolicies: AppliedPolicyRec[];
|
|
81
|
+
contract: ContractEnforcement;
|
|
82
|
+
actions: PolicyAction[];
|
|
55
83
|
violations: Violation[];
|
|
56
84
|
}
|
|
57
85
|
export interface GateUsage {
|
|
58
86
|
provider: string;
|
|
59
87
|
model: string;
|
|
60
|
-
latencyMs
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
};
|
|
88
|
+
latencyMs: number;
|
|
89
|
+
inputTokens?: number;
|
|
90
|
+
outputTokens?: number;
|
|
91
|
+
totalTokens?: number;
|
|
92
|
+
costUsd?: number;
|
|
66
93
|
}
|
|
67
94
|
export interface GateResult<T> {
|
|
68
95
|
safeOutput?: T;
|