@rigour-labs/core 4.1.0 → 4.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/dist/hooks/checker.js +89 -0
- package/dist/hooks/dlp-templates.d.ts +26 -0
- package/dist/hooks/dlp-templates.js +281 -0
- package/dist/hooks/index.d.ts +5 -0
- package/dist/hooks/index.js +4 -0
- package/dist/hooks/input-validator.d.ts +70 -0
- package/dist/hooks/input-validator.js +461 -0
- package/dist/hooks/input-validator.test.d.ts +1 -0
- package/dist/hooks/input-validator.test.js +272 -0
- package/dist/hooks/standalone-dlp-checker.d.ts +18 -0
- package/dist/hooks/standalone-dlp-checker.js +91 -0
- package/dist/templates/universal-config.js +33 -0
- package/dist/types/index.d.ts +230 -12
- package/dist/types/index.js +59 -0
- package/package.json +6 -6
package/dist/hooks/checker.js
CHANGED
|
@@ -12,6 +12,7 @@ import fs from 'fs-extra';
|
|
|
12
12
|
import path from 'path';
|
|
13
13
|
import yaml from 'yaml';
|
|
14
14
|
import { ConfigSchema } from '../types/index.js';
|
|
15
|
+
import { scanInputForCredentials } from './input-validator.js';
|
|
15
16
|
const JS_TS_PATTERN = /\.(ts|tsx|js|jsx|mts|mjs)$/;
|
|
16
17
|
/**
|
|
17
18
|
* Load rigour config from cwd, falling back to defaults.
|
|
@@ -42,6 +43,8 @@ async function resolveFile(filePath, cwd) {
|
|
|
42
43
|
function checkFile(content, relPath, cwd, config) {
|
|
43
44
|
const failures = [];
|
|
44
45
|
const lines = content.split('\n');
|
|
46
|
+
// Gate 0: Memory & Skills Governance — block writes to agent-native memory paths
|
|
47
|
+
checkGovernance(content, relPath, config, failures);
|
|
45
48
|
// Gate 1: File size
|
|
46
49
|
const maxLines = config.gates.max_file_lines ?? 500;
|
|
47
50
|
if (lines.length > maxLines) {
|
|
@@ -220,3 +223,89 @@ function checkCommandInjection(line, i, relPath, failures) {
|
|
|
220
223
|
});
|
|
221
224
|
}
|
|
222
225
|
}
|
|
226
|
+
// ── Memory & Skills Governance (v4.2+) ────────────────────────────
|
|
227
|
+
/**
|
|
228
|
+
* Simple glob matcher — handles exact paths, `*` (single segment),
|
|
229
|
+
* and `**` (any depth). No external dependencies.
|
|
230
|
+
*/
|
|
231
|
+
function simpleGlob(filePath, pattern) {
|
|
232
|
+
// Exact match
|
|
233
|
+
if (filePath === pattern)
|
|
234
|
+
return true;
|
|
235
|
+
// Convert glob to regex: ** → any path, * → single segment
|
|
236
|
+
const regexStr = pattern
|
|
237
|
+
.replace(/[.+^${}()|[\]\\]/g, '\\$&') // escape regex specials (except * and ?)
|
|
238
|
+
.replace(/\*\*/g, '<<<DOUBLESTAR>>>')
|
|
239
|
+
.replace(/\*/g, '[^/]*')
|
|
240
|
+
.replace(/<<<DOUBLESTAR>>>/g, '.*');
|
|
241
|
+
return new RegExp(`^${regexStr}$`).test(filePath);
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Intercept writes to agent-native memory AND skills files.
|
|
245
|
+
*
|
|
246
|
+
* Two separate enforcement layers:
|
|
247
|
+
* 1. enforce_memory — blocks writes to CLAUDE.md, .clinerules, .windsurf/memories/
|
|
248
|
+
* → tells agent: "use rigour_remember instead"
|
|
249
|
+
* 2. enforce_skills — blocks writes to .claude/skills/, .cursor/rules/, etc.
|
|
250
|
+
* → tells agent: "use rigour skills system instead"
|
|
251
|
+
*
|
|
252
|
+
* Both layers DLP-scan content for credentials regardless of blocking.
|
|
253
|
+
*
|
|
254
|
+
* Users can disable via rigour.yml:
|
|
255
|
+
* gates:
|
|
256
|
+
* governance:
|
|
257
|
+
* enabled: false # disable everything
|
|
258
|
+
* enforce_memory: false # allow native memory, still enforce skills
|
|
259
|
+
* enforce_skills: false # allow native skills, still enforce memory
|
|
260
|
+
*
|
|
261
|
+
* @since v4.2.0
|
|
262
|
+
*/
|
|
263
|
+
function checkGovernance(content, relPath, config, failures) {
|
|
264
|
+
const gov = config.gates.governance;
|
|
265
|
+
if (!gov?.enabled)
|
|
266
|
+
return;
|
|
267
|
+
const exemptPaths = gov.exempt_paths ?? [];
|
|
268
|
+
const normalizedPath = relPath.replace(/\\/g, '/');
|
|
269
|
+
// Check exemptions first (Rigour's own hook configs)
|
|
270
|
+
const isExempt = exemptPaths.some(pattern => simpleGlob(normalizedPath, pattern));
|
|
271
|
+
if (isExempt)
|
|
272
|
+
return;
|
|
273
|
+
// ── Check memory paths ──
|
|
274
|
+
const memoryPaths = gov.protected_memory_paths ?? [];
|
|
275
|
+
const isMemoryPath = memoryPaths.some(pattern => simpleGlob(normalizedPath, pattern));
|
|
276
|
+
// ── Check skills paths ──
|
|
277
|
+
const skillsPaths = gov.protected_skills_paths ?? [];
|
|
278
|
+
const isSkillsPath = skillsPaths.some((pattern) => simpleGlob(normalizedPath, pattern));
|
|
279
|
+
if (!isMemoryPath && !isSkillsPath)
|
|
280
|
+
return;
|
|
281
|
+
// ── Enforcement: block memory writes ──
|
|
282
|
+
if (isMemoryPath && gov.enforce_memory && gov.block_native_memory) {
|
|
283
|
+
failures.push({
|
|
284
|
+
gate: 'governance',
|
|
285
|
+
file: relPath,
|
|
286
|
+
message: `BLOCKED: Agent writing to native memory path "${relPath}". Use rigour_remember instead — it DLP-scans and persists safely to .rigour/memory.json`,
|
|
287
|
+
severity: 'critical',
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
// ── Enforcement: block skills writes ──
|
|
291
|
+
if (isSkillsPath && gov.enforce_skills) {
|
|
292
|
+
failures.push({
|
|
293
|
+
gate: 'governance-skills',
|
|
294
|
+
file: relPath,
|
|
295
|
+
message: `BLOCKED: Agent writing to native skills/rules path "${relPath}". Use Rigour skills system instead — governed, DLP-scanned, and auditable`,
|
|
296
|
+
severity: 'critical',
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
// ── DLP scan the content being written (always, regardless of block settings) ──
|
|
300
|
+
const dlpResult = scanInputForCredentials(content);
|
|
301
|
+
if (dlpResult.status !== 'clean') {
|
|
302
|
+
for (const detection of dlpResult.detections) {
|
|
303
|
+
failures.push({
|
|
304
|
+
gate: 'governance-dlp',
|
|
305
|
+
file: relPath,
|
|
306
|
+
message: `${detection.description} found in agent ${isMemoryPath ? 'memory' : 'skills'} file. ${detection.recommendation}`,
|
|
307
|
+
severity: detection.severity === 'critical' ? 'critical' : 'high',
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DLP Hook Templates — Pre-Input Credential Interception
|
|
3
|
+
*
|
|
4
|
+
* Generates tool-native hook configs that intercept user input
|
|
5
|
+
* BEFORE it reaches the AI agent. Complements the existing
|
|
6
|
+
* post-output templates in templates.ts.
|
|
7
|
+
*
|
|
8
|
+
* Hook events:
|
|
9
|
+
* - Claude Code: PreToolUse matcher (all tools)
|
|
10
|
+
* - Cursor: beforeFileEdit event
|
|
11
|
+
* - Cline: PreToolUse executable script
|
|
12
|
+
* - Windsurf: pre_write_code event
|
|
13
|
+
*
|
|
14
|
+
* @since v4.2.0 — AI Agent DLP layer
|
|
15
|
+
*/
|
|
16
|
+
import type { HookTool } from './types.js';
|
|
17
|
+
export interface GeneratedDLPHookFile {
|
|
18
|
+
path: string;
|
|
19
|
+
content: string;
|
|
20
|
+
executable?: boolean;
|
|
21
|
+
description: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Generate DLP (pre-input) hook config files for a specific tool.
|
|
25
|
+
*/
|
|
26
|
+
export declare function generateDLPHookFiles(tool: HookTool, checkerCommand: string): GeneratedDLPHookFile[];
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DLP Hook Templates — Pre-Input Credential Interception
|
|
3
|
+
*
|
|
4
|
+
* Generates tool-native hook configs that intercept user input
|
|
5
|
+
* BEFORE it reaches the AI agent. Complements the existing
|
|
6
|
+
* post-output templates in templates.ts.
|
|
7
|
+
*
|
|
8
|
+
* Hook events:
|
|
9
|
+
* - Claude Code: PreToolUse matcher (all tools)
|
|
10
|
+
* - Cursor: beforeFileEdit event
|
|
11
|
+
* - Cline: PreToolUse executable script
|
|
12
|
+
* - Windsurf: pre_write_code event
|
|
13
|
+
*
|
|
14
|
+
* @since v4.2.0 — AI Agent DLP layer
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Generate DLP (pre-input) hook config files for a specific tool.
|
|
18
|
+
*/
|
|
19
|
+
export function generateDLPHookFiles(tool, checkerCommand) {
|
|
20
|
+
switch (tool) {
|
|
21
|
+
case 'claude':
|
|
22
|
+
return generateClaudeDLPHooks(checkerCommand);
|
|
23
|
+
case 'cursor':
|
|
24
|
+
return generateCursorDLPHooks(checkerCommand);
|
|
25
|
+
case 'cline':
|
|
26
|
+
return generateClineDLPHooks(checkerCommand);
|
|
27
|
+
case 'windsurf':
|
|
28
|
+
return generateWindsurfDLPHooks(checkerCommand);
|
|
29
|
+
default:
|
|
30
|
+
return [];
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
// ── Claude Code DLP Hook ──────────────────────────────────────────
|
|
34
|
+
function generateClaudeDLPHooks(checkerCommand) {
|
|
35
|
+
// Claude Code supports PreToolUse hooks that fire BEFORE tool execution.
|
|
36
|
+
// We intercept all tool uses to scan user input for credentials.
|
|
37
|
+
const settings = {
|
|
38
|
+
hooks: {
|
|
39
|
+
PreToolUse: [
|
|
40
|
+
{
|
|
41
|
+
matcher: ".*",
|
|
42
|
+
hooks: [
|
|
43
|
+
{
|
|
44
|
+
type: "command",
|
|
45
|
+
command: `${checkerCommand} --mode dlp --stdin`,
|
|
46
|
+
}
|
|
47
|
+
]
|
|
48
|
+
}
|
|
49
|
+
]
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
return [
|
|
53
|
+
{
|
|
54
|
+
path: '.claude/dlp-settings.json',
|
|
55
|
+
content: JSON.stringify(settings, null, 4),
|
|
56
|
+
description: 'Claude Code PreToolUse DLP hook — scans input for credentials before agent processing',
|
|
57
|
+
},
|
|
58
|
+
];
|
|
59
|
+
}
|
|
60
|
+
// ── Cursor DLP Hook ───────────────────────────────────────────────
|
|
61
|
+
function generateCursorDLPHooks(checkerCommand) {
|
|
62
|
+
const hooks = {
|
|
63
|
+
version: 1,
|
|
64
|
+
hooks: {
|
|
65
|
+
beforeFileEdit: [
|
|
66
|
+
{
|
|
67
|
+
command: `${checkerCommand} --mode dlp --stdin`,
|
|
68
|
+
}
|
|
69
|
+
]
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
const wrapper = `#!/usr/bin/env node
|
|
73
|
+
/**
|
|
74
|
+
* Cursor DLP hook — scans input for credentials before agent processing.
|
|
75
|
+
* Receives { file_path, new_content } on stdin.
|
|
76
|
+
* Runs Rigour credential scanner on the content.
|
|
77
|
+
*
|
|
78
|
+
* @since v4.2.0 — AI Agent DLP
|
|
79
|
+
*/
|
|
80
|
+
|
|
81
|
+
let data = '';
|
|
82
|
+
process.stdin.on('data', chunk => { data += chunk; });
|
|
83
|
+
process.stdin.on('end', async () => {
|
|
84
|
+
try {
|
|
85
|
+
const payload = JSON.parse(data);
|
|
86
|
+
const textToScan = payload.new_content || payload.content || '';
|
|
87
|
+
|
|
88
|
+
if (!textToScan) {
|
|
89
|
+
process.stdout.write(JSON.stringify({ status: 'ok' }));
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const { spawnSync } = require('child_process');
|
|
94
|
+
const proc = spawnSync(
|
|
95
|
+
'node',
|
|
96
|
+
[require.resolve('@rigour-labs/core/dist/hooks/standalone-dlp-checker.js')],
|
|
97
|
+
{
|
|
98
|
+
input: textToScan,
|
|
99
|
+
encoding: 'utf-8',
|
|
100
|
+
timeout: 3000,
|
|
101
|
+
}
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
if (proc.error) throw proc.error;
|
|
105
|
+
|
|
106
|
+
const result = JSON.parse((proc.stdout || '').trim());
|
|
107
|
+
if (result.status === 'blocked') {
|
|
108
|
+
process.stderr.write('[rigour/dlp] ' + result.detections.length + ' credential(s) BLOCKED\\n');
|
|
109
|
+
for (const d of result.detections) {
|
|
110
|
+
process.stderr.write(' [' + d.severity.toUpperCase() + '] ' + d.description + '\\n');
|
|
111
|
+
process.stderr.write(' → ' + d.recommendation + '\\n');
|
|
112
|
+
}
|
|
113
|
+
process.exit(2); // Block the operation
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
process.stdout.write(JSON.stringify({ status: 'ok' }));
|
|
117
|
+
} catch (err) {
|
|
118
|
+
process.stderr.write('Rigour DLP hook error: ' + err.message + '\\n');
|
|
119
|
+
process.stdout.write(JSON.stringify({ status: 'ok' }));
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
`;
|
|
123
|
+
return [
|
|
124
|
+
{
|
|
125
|
+
path: '.cursor/dlp-hooks.json',
|
|
126
|
+
content: JSON.stringify(hooks, null, 4),
|
|
127
|
+
description: 'Cursor DLP hook config — pre-input credential scanning',
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
path: '.cursor/rigour-dlp-hook.js',
|
|
131
|
+
content: wrapper,
|
|
132
|
+
executable: true,
|
|
133
|
+
description: 'Cursor DLP hook wrapper — credential interception',
|
|
134
|
+
},
|
|
135
|
+
];
|
|
136
|
+
}
|
|
137
|
+
// ── Cline DLP Hook ────────────────────────────────────────────────
|
|
138
|
+
function generateClineDLPHooks(checkerCommand) {
|
|
139
|
+
const script = `#!/usr/bin/env node
|
|
140
|
+
/**
|
|
141
|
+
* Cline PreToolUse DLP hook for Rigour.
|
|
142
|
+
* Receives JSON on stdin with { toolName, toolInput }.
|
|
143
|
+
* Scans tool input for credentials BEFORE execution.
|
|
144
|
+
*
|
|
145
|
+
* @since v4.2.0 — AI Agent DLP
|
|
146
|
+
*/
|
|
147
|
+
|
|
148
|
+
let data = '';
|
|
149
|
+
process.stdin.on('data', chunk => { data += chunk; });
|
|
150
|
+
process.stdin.on('end', async () => {
|
|
151
|
+
try {
|
|
152
|
+
const payload = JSON.parse(data);
|
|
153
|
+
|
|
154
|
+
// Extract all string values from toolInput to scan
|
|
155
|
+
const textsToScan = [];
|
|
156
|
+
if (payload.toolInput) {
|
|
157
|
+
for (const [key, value] of Object.entries(payload.toolInput)) {
|
|
158
|
+
if (typeof value === 'string' && value.length > 5) {
|
|
159
|
+
textsToScan.push(value);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (textsToScan.length === 0) {
|
|
165
|
+
process.stdout.write(JSON.stringify({}));
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const combined = textsToScan.join('\\n');
|
|
170
|
+
const { spawnSync } = require('child_process');
|
|
171
|
+
const proc = spawnSync(
|
|
172
|
+
'node',
|
|
173
|
+
[require.resolve('@rigour-labs/core/dist/hooks/standalone-dlp-checker.js')],
|
|
174
|
+
{
|
|
175
|
+
input: combined,
|
|
176
|
+
encoding: 'utf-8',
|
|
177
|
+
timeout: 3000,
|
|
178
|
+
}
|
|
179
|
+
);
|
|
180
|
+
|
|
181
|
+
if (proc.error) throw proc.error;
|
|
182
|
+
|
|
183
|
+
const result = JSON.parse((proc.stdout || '').trim());
|
|
184
|
+
if (result.status === 'blocked') {
|
|
185
|
+
const msgs = result.detections
|
|
186
|
+
.map(d => '[rigour/dlp/' + d.type + '] ' + d.description + ' → ' + d.recommendation)
|
|
187
|
+
.join('\\n');
|
|
188
|
+
|
|
189
|
+
process.stdout.write(JSON.stringify({
|
|
190
|
+
contextModification: '\\n🛑 [Rigour DLP] ' + result.detections.length + ' credential(s) BLOCKED before agent processing:\\n' + msgs + '\\nReplace with environment variable references.',
|
|
191
|
+
}));
|
|
192
|
+
process.exit(2);
|
|
193
|
+
} else {
|
|
194
|
+
process.stdout.write(JSON.stringify({}));
|
|
195
|
+
}
|
|
196
|
+
} catch (err) {
|
|
197
|
+
process.stderr.write('Rigour DLP hook error: ' + err.message + '\\n');
|
|
198
|
+
process.stdout.write(JSON.stringify({}));
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
`;
|
|
202
|
+
return [
|
|
203
|
+
{
|
|
204
|
+
path: '.clinerules/hooks/PreToolUse',
|
|
205
|
+
content: script,
|
|
206
|
+
executable: true,
|
|
207
|
+
description: 'Cline PreToolUse DLP hook — credential interception before agent execution',
|
|
208
|
+
},
|
|
209
|
+
];
|
|
210
|
+
}
|
|
211
|
+
// ── Windsurf DLP Hook ─────────────────────────────────────────────
|
|
212
|
+
function generateWindsurfDLPHooks(checkerCommand) {
|
|
213
|
+
const hooks = {
|
|
214
|
+
version: 1,
|
|
215
|
+
hooks: {
|
|
216
|
+
pre_write_code: [
|
|
217
|
+
{
|
|
218
|
+
command: `${checkerCommand} --mode dlp --stdin`,
|
|
219
|
+
}
|
|
220
|
+
]
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
const wrapper = `#!/usr/bin/env node
|
|
224
|
+
/**
|
|
225
|
+
* Windsurf DLP hook — scans input for credentials before Cascade agent processing.
|
|
226
|
+
* Receives { file_path, content } on stdin.
|
|
227
|
+
*
|
|
228
|
+
* @since v4.2.0 — AI Agent DLP
|
|
229
|
+
*/
|
|
230
|
+
|
|
231
|
+
let data = '';
|
|
232
|
+
process.stdin.on('data', chunk => { data += chunk; });
|
|
233
|
+
process.stdin.on('end', async () => {
|
|
234
|
+
try {
|
|
235
|
+
const payload = JSON.parse(data);
|
|
236
|
+
const textToScan = payload.content || '';
|
|
237
|
+
|
|
238
|
+
if (!textToScan) {
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const { spawnSync } = require('child_process');
|
|
243
|
+
const proc = spawnSync(
|
|
244
|
+
'node',
|
|
245
|
+
[require.resolve('@rigour-labs/core/dist/hooks/standalone-dlp-checker.js')],
|
|
246
|
+
{
|
|
247
|
+
input: textToScan,
|
|
248
|
+
encoding: 'utf-8',
|
|
249
|
+
timeout: 3000,
|
|
250
|
+
}
|
|
251
|
+
);
|
|
252
|
+
|
|
253
|
+
if (proc.error) throw proc.error;
|
|
254
|
+
|
|
255
|
+
const result = JSON.parse((proc.stdout || '').trim());
|
|
256
|
+
if (result.status === 'blocked') {
|
|
257
|
+
for (const d of result.detections) {
|
|
258
|
+
process.stderr.write('[rigour/dlp] 🛑 ' + d.severity.toUpperCase() + ': ' + d.description + '\\n');
|
|
259
|
+
process.stderr.write(' → ' + d.recommendation + '\\n');
|
|
260
|
+
}
|
|
261
|
+
process.exit(2); // Block
|
|
262
|
+
}
|
|
263
|
+
} catch (err) {
|
|
264
|
+
process.stderr.write('Rigour DLP hook error: ' + err.message + '\\n');
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
`;
|
|
268
|
+
return [
|
|
269
|
+
{
|
|
270
|
+
path: '.windsurf/dlp-hooks.json',
|
|
271
|
+
content: JSON.stringify(hooks, null, 4),
|
|
272
|
+
description: 'Windsurf DLP hook config — pre-input credential scanning',
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
path: '.windsurf/rigour-dlp-hook.js',
|
|
276
|
+
content: wrapper,
|
|
277
|
+
executable: true,
|
|
278
|
+
description: 'Windsurf DLP hook wrapper — credential interception before Cascade',
|
|
279
|
+
},
|
|
280
|
+
];
|
|
281
|
+
}
|
package/dist/hooks/index.d.ts
CHANGED
|
@@ -2,8 +2,13 @@
|
|
|
2
2
|
* Hooks module — multi-tool hook integration for Rigour.
|
|
3
3
|
*
|
|
4
4
|
* @since v3.0.0
|
|
5
|
+
* @since v4.2.0 — AI Agent DLP (Data Loss Prevention)
|
|
5
6
|
*/
|
|
6
7
|
export { runHookChecker } from './checker.js';
|
|
7
8
|
export { generateHookFiles } from './templates.js';
|
|
8
9
|
export type { HookTool, HookConfig, HookCheckerResult } from './types.js';
|
|
9
10
|
export { DEFAULT_HOOK_CONFIG, FAST_GATE_IDS } from './types.js';
|
|
11
|
+
export { scanInputForCredentials, formatDLPAlert, createDLPAuditEntry } from './input-validator.js';
|
|
12
|
+
export type { CredentialDetection, InputValidationResult, InputValidationConfig } from './input-validator.js';
|
|
13
|
+
export { generateDLPHookFiles } from './dlp-templates.js';
|
|
14
|
+
export type { GeneratedDLPHookFile } from './dlp-templates.js';
|
package/dist/hooks/index.js
CHANGED
|
@@ -2,7 +2,11 @@
|
|
|
2
2
|
* Hooks module — multi-tool hook integration for Rigour.
|
|
3
3
|
*
|
|
4
4
|
* @since v3.0.0
|
|
5
|
+
* @since v4.2.0 — AI Agent DLP (Data Loss Prevention)
|
|
5
6
|
*/
|
|
6
7
|
export { runHookChecker } from './checker.js';
|
|
7
8
|
export { generateHookFiles } from './templates.js';
|
|
8
9
|
export { DEFAULT_HOOK_CONFIG, FAST_GATE_IDS } from './types.js';
|
|
10
|
+
// DLP (Data Loss Prevention) — v4.2.0
|
|
11
|
+
export { scanInputForCredentials, formatDLPAlert, createDLPAuditEntry } from './input-validator.js';
|
|
12
|
+
export { generateDLPHookFiles } from './dlp-templates.js';
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Input Validation Gate — AI Agent DLP (Data Loss Prevention)
|
|
3
|
+
*
|
|
4
|
+
* Scans user input text for credentials, secrets, and sensitive data
|
|
5
|
+
* BEFORE it reaches any AI agent. This is the pre-input counterpart
|
|
6
|
+
* to the existing post-output security patterns in checker.ts.
|
|
7
|
+
*
|
|
8
|
+
* Supported credential types:
|
|
9
|
+
* - AWS Access Keys (AKIA...)
|
|
10
|
+
* - OpenAI / Anthropic / GitHub API keys (sk-*, ghp_*, etc.)
|
|
11
|
+
* - Private keys (PEM format)
|
|
12
|
+
* - Database connection strings (postgresql://, mongodb://, mysql://, redis://)
|
|
13
|
+
* - Bearer tokens and JWTs
|
|
14
|
+
* - Generic password/secret assignments
|
|
15
|
+
* - .env format strings (KEY=value)
|
|
16
|
+
* - Azure / GCP / Stripe / Twilio keys
|
|
17
|
+
*
|
|
18
|
+
* @since v4.2.0 — AI Agent DLP layer
|
|
19
|
+
*/
|
|
20
|
+
export interface CredentialDetection {
|
|
21
|
+
type: string;
|
|
22
|
+
severity: 'critical' | 'high' | 'medium';
|
|
23
|
+
match: string;
|
|
24
|
+
redacted: string;
|
|
25
|
+
description: string;
|
|
26
|
+
recommendation: string;
|
|
27
|
+
compliance: string[];
|
|
28
|
+
position?: {
|
|
29
|
+
start: number;
|
|
30
|
+
end: number;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
export interface InputValidationResult {
|
|
34
|
+
status: 'clean' | 'blocked' | 'warning';
|
|
35
|
+
detections: CredentialDetection[];
|
|
36
|
+
duration_ms: number;
|
|
37
|
+
scanned_length: number;
|
|
38
|
+
}
|
|
39
|
+
export interface InputValidationConfig {
|
|
40
|
+
enabled?: boolean;
|
|
41
|
+
block_on_detection?: boolean;
|
|
42
|
+
/** Minimum length for generic secret values to avoid false positives */
|
|
43
|
+
min_secret_length?: number;
|
|
44
|
+
/** Custom patterns to add (regex strings) */
|
|
45
|
+
custom_patterns?: string[];
|
|
46
|
+
/** Patterns to ignore (regex strings for whitelisting) */
|
|
47
|
+
ignore_patterns?: string[];
|
|
48
|
+
/** Log blocked inputs to audit trail */
|
|
49
|
+
audit_log?: boolean;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Scan input text for credential patterns.
|
|
53
|
+
* Returns all detections with type, severity, and recommendations.
|
|
54
|
+
*
|
|
55
|
+
* Designed to complete in <50ms for real-time pre-input hooks.
|
|
56
|
+
*/
|
|
57
|
+
export declare function scanInputForCredentials(input: string, config?: InputValidationConfig): InputValidationResult;
|
|
58
|
+
/**
|
|
59
|
+
* Format a blocked input result for display in IDE/terminal.
|
|
60
|
+
* Used by hooks and CLI for human-readable output.
|
|
61
|
+
*/
|
|
62
|
+
export declare function formatDLPAlert(result: InputValidationResult): string;
|
|
63
|
+
/**
|
|
64
|
+
* Generate a structured audit log entry for a DLP event.
|
|
65
|
+
*/
|
|
66
|
+
export declare function createDLPAuditEntry(result: InputValidationResult, metadata: {
|
|
67
|
+
agent: string;
|
|
68
|
+
timestamp?: string;
|
|
69
|
+
userId?: string;
|
|
70
|
+
}): Record<string, unknown>;
|