gateia 0.2.0 → 0.2.2

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 CHANGED
@@ -14,18 +14,18 @@
14
14
 
15
15
  ---
16
16
 
17
- **Gateia** is the standard for implementing **Deterministic Guardrails** in AI applications. It acts as a final, immutable security layer between your AI models and your customers.
17
+ **Gateia** is a deterministic verification layer for AI applications. It acts as a final, immutable security gate between your models and your customers.
18
18
 
19
- Unlike "AI-judging-AI" solutions, Gateia enables you to enforce **strict, code-based contracts**, ensuring that your application never halluncinates, leaks PII, or violates business rules—regardless of the underlying model (OpenAI, Anthropic, or Llama).
19
+ Unlike "AI-judging-AI" solutions, Gateia enforces **strict, code-based contracts** and deterministic policies that block known unsafe patterns—regardless of the underlying model (OpenAI, Anthropic, or Llama).
20
20
 
21
21
  ## 🚀 Why Gateia?
22
22
 
23
23
  In production, **probability is a liability.** Gateia restores deterministic control.
24
24
 
25
- * **🛡️ Zero Hallucination Policy**: Gateia does not use LLMs to verify. It uses deterministic logic and regex engines. It is impossible for the verifier to hallucinate.
25
+ * **🛡️ Deterministic Verification**: Gateia does not use LLMs to verify. It uses deterministic logic and regex engines to validate outputs.
26
26
  * **🏗️ Contract-First Architecture**: Define your data requirements with Zod schemas. If the output doesn't match, it doesn't ship.
27
27
  * **📋 Audit-Ready Logging**: Every decision is traced, logged, and categorized by severity, making compliance (SOC2, HIPAA) audits straightforward.
28
- * **🔒 Fail-Closed Security**: If a policy returns a block signal (even with malformed data), Gateia defaults to blocking. Security is never compromised by runtime errors.
28
+ * **🔒 Fail-Closed Security**: If a policy returns a block signal (even with malformed data), Gateia defaults to blocking.
29
29
 
30
30
  ---
31
31
 
@@ -39,40 +39,24 @@ npm install gateia zod
39
39
 
40
40
  ## ⚡️ Quick Start
41
41
 
42
- Secure a loan processing agent in 30 seconds.
42
+ **Scenario:** You have an AI Customer Support Agent. You need to block refund guarantees and PII.
43
43
 
44
44
  ```typescript
45
- import { verify } from 'gateia';
46
- import { z } from 'zod';
47
-
48
- // 1. Define the Business Contract
49
- // The AI *must* return data in this shape.
50
- const LoanDecisionContract = z.object({
51
- approved: z.boolean(),
52
- rate: z.number().min(2.5).max(10.0), // Business Logic
53
- reason: z.string(),
54
- risk_level: z.enum(['low', 'medium', 'high'])
55
- });
45
+ import { verify } from "gateia";
46
+ import { z } from "zod";
56
47
 
57
- // 2. The Verification Step
58
- // Run this *after* your LLM generates content.
59
- const result = await verify({
60
- output: llmResponse,
61
- contract: LoanDecisionContract,
62
- policies: ['finance-safe', 'pii-safe', 'secrets-safe'],
63
- mode: 'enforce'
48
+ const Reply = z.object({ reply: z.string() });
49
+
50
+ const res = await verify({
51
+ output: { reply: "Refund guaranteed. Email me at test@example.com" }, // pretend this came from an LLM
52
+ contract: Reply,
53
+ policies: ["finance-safe", "pii-safe"]
64
54
  });
65
55
 
66
- // 3. Deterministic Decision
67
- if (!result.allowed) {
68
- // Blocked. Do not show to user.
69
- console.error("Security Violation:", result.enforcement.violations);
70
- } else {
71
- // Safe. Proceed to database/frontend.
72
- console.log("Verified Data:", result.safeOutput);
73
- }
56
+ console.log(res.allowed ? "ALLOWED" : "BLOCKED");
74
57
  ```
75
58
 
59
+
76
60
  ---
77
61
 
78
62
  ## 🛡️ Policy Library
@@ -82,7 +66,7 @@ Gateia ships with battle-tested policies for common enterprise risks.
82
66
  | Policy ID | Risk Category | Description | Severity |
83
67
  |-----------|---------------|-------------|----------|
84
68
  | `finance-safe` | **Compliance** | Blocks non-compliant guarantee language (e.g., "100% no risk", "guaranteed return"). | High |
85
- | `pii-safe` | **Privacy** | Redacts or blocks Personally Identifiable Information (Emails, Phone Numbers). | High |
69
+ | `pii-safe` | **Privacy** | Blocks personally identifiable information (emails, phone numbers, etc.). | High |
86
70
  | `secrets-safe` | **Security** | Detects leaked API keys (AWS, Stripe, OpenAI, Slack) and private keys. | High |
87
71
  | `markup-safe` | **Security** | Prevents XSS by blocking `<script>`, `iframe`, and other HTML injection vectors. | High |
88
72
 
@@ -130,9 +114,12 @@ const result = await verify({
130
114
 
131
115
  Every call to `verify()` returns a comprehensive `EnforcementReport`. Use this for your internal dashboards and compliance logs.
132
116
 
117
+ **Note:** `safeOutput` is always included on the response, but it will be `undefined` when `allowed === false` (contract failure or policy block).
118
+
133
119
  ```json
134
120
  {
135
121
  "allowed": false,
122
+ "safeOutput": null,
136
123
  "traceId": "123e4567-e89b-12d3-a456-426614174000",
137
124
  "enforcement": {
138
125
  "contract": { "outcome": "pass" },
@@ -156,4 +143,4 @@ Every call to `verify()` returns a comprehensive `EnforcementReport`. Use this f
156
143
 
157
144
  ## License
158
145
 
159
- MIT
146
+ MIT
@@ -7,24 +7,46 @@ exports.financeSafe = {
7
7
  check: (output) => {
8
8
  const text = typeof output === 'string' ? output : JSON.stringify(output);
9
9
  const lower = text.toLowerCase();
10
- // Block guarantees
11
- const forbidden = [
10
+ // Block guarantees and absolute assurances (expanded patterns)
11
+ const forbiddenPhrases = [
12
12
  'guaranteed refund',
13
13
  'guaranteed return',
14
14
  'guaranteed approval',
15
+ 'guaranteed payout',
16
+ 'guaranteed profit',
17
+ 'guaranteed results',
18
+ 'risk free',
19
+ 'risk-free',
15
20
  'no risk',
16
- '100% guaranteed'
21
+ 'zero risk',
22
+ '100% guaranteed',
23
+ 'one hundred percent guaranteed',
24
+ 'we will always refund',
25
+ 'we always refund',
26
+ 'instant refund',
27
+ 'automatic refund',
28
+ 'refund assured',
29
+ 'money back guaranteed',
30
+ 'guaranteed money back'
17
31
  ];
18
- const match = forbidden.find(phrase => lower.includes(phrase));
19
- if (match) {
32
+ const forbiddenRegexes = [
33
+ /\bguarantee(?:d|s|ing)?\b.{0,24}\b(refund|return|approval|payout|profit|results)\b/i,
34
+ /\b(refund|return|approval|payout|profit|results)\b.{0,24}\bguarantee(?:d|s|ing)?\b/i,
35
+ /\b100\s*%|\b100\s*percent|\b100\s*per\s*cent/i,
36
+ /\bno\s+risk\b|\bzero\s+risk\b|\brisk[-\s]?free\b/i,
37
+ /\b(always|never)\b.{0,24}\brefund\b/i
38
+ ];
39
+ const phraseMatch = forbiddenPhrases.find(phrase => lower.includes(phrase));
40
+ const regexMatch = forbiddenRegexes.find(regex => regex.test(text));
41
+ if (phraseMatch || regexMatch) {
20
42
  return {
21
43
  outcome: 'block',
22
44
  violations: [{
23
45
  policyId: 'finance-safe',
24
46
  code: 'FIN_GUARANTEE',
25
- message: `Contains forbidden guarantee language: "${match}"`,
47
+ message: `Contains forbidden guarantee language: "${phraseMatch ?? 'regex-match'}"`,
26
48
  severity: 'high',
27
- evidence: { snippet: match }
49
+ evidence: { snippet: phraseMatch ?? 'regex-match' }
28
50
  }]
29
51
  };
30
52
  }
@@ -12,7 +12,12 @@ exports.markupSafe = {
12
12
  { name: 'Script Tag', regex: /<script[\s\S]*?>/i },
13
13
  { name: 'Iframe Tag', regex: /<iframe[\s\S]*?>/i },
14
14
  { name: 'Object Tag', regex: /<object[\s\S]*?>/i },
15
- { name: 'Javascript Protocol', regex: /javascript:/i }
15
+ { name: 'Javascript Protocol', regex: /javascript:/i },
16
+ { name: 'Data URL', regex: /data:text\/html/i },
17
+ { name: 'Event Handler', regex: /\son\w+\s*=/i },
18
+ { name: 'SVG Tag', regex: /<svg[\s\S]*?>/i },
19
+ { name: 'Meta Refresh', regex: /<meta[\s\S]*?http-equiv=["']?refresh["']?/i },
20
+ { name: 'Base Tag', regex: /<base[\s\S]*?>/i }
16
21
  ];
17
22
  const violations = [];
18
23
  for (const pattern of patterns) {
@@ -6,9 +6,15 @@ exports.piiSafe = {
6
6
  mode: 'enforce',
7
7
  check: (output) => {
8
8
  const text = typeof output === 'string' ? output : JSON.stringify(output);
9
- // Simple regex patterns (for MVP)
9
+ // Expanded regex patterns (still heuristic)
10
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
11
+ const phoneRegexUS = /\b(?:\+?1[\s.-]?)?(?:\(\d{3}\)|\d{3})[\s.-]?\d{3}[\s.-]?\d{4}\b/;
12
+ const phoneRegexIntl = /\b\+?\d{1,3}[\s.-]?(?:\d{1,4}[\s.-]?){2,4}\d\b/;
13
+ const ssnRegex = /\b(?!000|666|9\d\d)\d{3}[- ]?(?!00)\d{2}[- ]?(?!0000)\d{4}\b/;
14
+ const creditCardRegex = /\b(?:\d[ -]*?){13,19}\b/;
15
+ const ipV4Regex = /\b(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\b/;
16
+ const ipV6Regex = /\b(?:[a-fA-F0-9]{1,4}:){7}[a-fA-F0-9]{1,4}\b/;
17
+ const dobRegex = /\b(?:19|20)\d{2}[-\/](?:0?[1-9]|1[0-2])[-\/](?:0?[1-9]|[12]\d|3[01])\b/; // YYYY-MM-DD or YYYY/MM/DD
12
18
  const violations = [];
13
19
  if (emailRegex.test(text)) {
14
20
  violations.push({
@@ -19,7 +25,7 @@ exports.piiSafe = {
19
25
  evidence: { snippet: 'email-detected-redacted' }
20
26
  });
21
27
  }
22
- if (phoneRegex.test(text)) {
28
+ if (phoneRegexUS.test(text) || phoneRegexIntl.test(text)) {
23
29
  violations.push({
24
30
  policyId: 'pii-safe',
25
31
  code: 'PII_PHONE',
@@ -28,6 +34,42 @@ exports.piiSafe = {
28
34
  evidence: { snippet: 'phone-detected-redacted' }
29
35
  });
30
36
  }
37
+ if (ssnRegex.test(text)) {
38
+ violations.push({
39
+ policyId: 'pii-safe',
40
+ code: 'PII_SSN',
41
+ message: 'SSN detected in output',
42
+ severity: 'high',
43
+ evidence: { snippet: 'ssn-detected-redacted' }
44
+ });
45
+ }
46
+ if (creditCardRegex.test(text)) {
47
+ violations.push({
48
+ policyId: 'pii-safe',
49
+ code: 'PII_CREDIT_CARD',
50
+ message: 'Credit card number detected in output',
51
+ severity: 'high',
52
+ evidence: { snippet: 'cc-detected-redacted' }
53
+ });
54
+ }
55
+ if (ipV4Regex.test(text) || ipV6Regex.test(text)) {
56
+ violations.push({
57
+ policyId: 'pii-safe',
58
+ code: 'PII_IP',
59
+ message: 'IP address detected in output',
60
+ severity: 'med',
61
+ evidence: { snippet: 'ip-detected-redacted' }
62
+ });
63
+ }
64
+ if (dobRegex.test(text)) {
65
+ violations.push({
66
+ policyId: 'pii-safe',
67
+ code: 'PII_DOB',
68
+ message: 'Date of birth detected in output',
69
+ severity: 'high',
70
+ evidence: { snippet: 'dob-detected-redacted' }
71
+ });
72
+ }
31
73
  if (violations.length > 0) {
32
74
  return { outcome: 'block', violations };
33
75
  }
@@ -8,10 +8,19 @@ exports.secretsSafe = {
8
8
  const text = typeof output === 'string' ? output : JSON.stringify(output);
9
9
  // Common patterns for API keys and secrets
10
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}/ }
11
+ { name: 'OpenAI Key', regex: /\bsk-[a-zA-Z0-9]{20,}\b/ },
12
+ { name: 'AWS Access Key', regex: /\bAKIA[0-9A-Z]{16}\b/ },
13
+ { name: 'AWS Secret Key', regex: /\b(?:aws|amazon)?[_-]?secret[_-]?access[_-]?key\b.{0,20}[A-Za-z0-9\/+=]{40}\b/i },
14
+ { name: 'Generic Private Key', regex: /-----BEGIN (?:RSA|EC|DSA|PGP)? ?PRIVATE KEY-----/ },
15
+ { name: 'GitHub Token', regex: /\bghp_[a-zA-Z0-9]{36}\b/ },
16
+ { name: 'GitHub Fine-grained Token', regex: /\bgithub_pat_[a-zA-Z0-9_]{82}\b/ },
17
+ { name: 'Slack Token', regex: /\bxox[baprs]-[A-Za-z0-9-]{10,}\b/ },
18
+ { name: 'Stripe Secret Key', regex: /\bsk_live_[A-Za-z0-9]{24}\b/ },
19
+ { name: 'Stripe Restricted Key', regex: /\brk_live_[A-Za-z0-9]{24}\b/ },
20
+ { name: 'Twilio API Key', regex: /\bSK[0-9a-fA-F]{32}\b/ },
21
+ { name: 'Mailgun API Key', regex: /\bkey-[0-9a-fA-F]{32}\b/ },
22
+ { name: 'Google API Key', regex: /\bAIza[0-9A-Za-z\-_]{35}\b/ },
23
+ { name: 'JWT', regex: /\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/ }
15
24
  ];
16
25
  const violations = [];
17
26
  for (const pattern of patterns) {
package/dist/types.d.ts CHANGED
@@ -60,7 +60,7 @@ export interface EnforcementReport {
60
60
  }
61
61
  export interface VerifyResult<T> {
62
62
  allowed: boolean;
63
- safeOutput?: T;
63
+ safeOutput: T | undefined;
64
64
  traceId: string;
65
65
  enforcement: EnforcementReport;
66
66
  rawOutput?: any;
package/dist/verify.js CHANGED
@@ -12,6 +12,7 @@ const policyEngine = new policy_1.PolicyEngine();
12
12
  async function verify(params) {
13
13
  const traceId = (0, uuid_1.v4)();
14
14
  const { output, contract, policies = [], mode = 'enforce' } = params;
15
+ const includeRawOutput = params.options?.includeRawOutput ?? true;
15
16
  try {
16
17
  // --- 1. Contract Validation ---
17
18
  // (If output is string and contract is Object, we might want to try parsing it?
@@ -118,7 +119,7 @@ async function verify(params) {
118
119
  safeOutput: allowed ? safeOutput : undefined,
119
120
  traceId,
120
121
  enforcement: report,
121
- rawOutput: params.options?.includeRawOutput ? output : undefined
122
+ rawOutput: includeRawOutput ? output : undefined
122
123
  };
123
124
  }
124
125
  catch (error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gateia",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "The Deterministic Verification Layer for Enterprise AI.",
5
5
  "keywords": [
6
6
  "ai",