Skip to content

Commit f60e2d9

Browse files
feat/regex-replace-guardrail
1 parent 6150f06 commit f60e2d9

File tree

2 files changed

+94
-0
lines changed

2 files changed

+94
-0
lines changed

plugins/default/regexReplace.ts

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import {
2+
HookEventType,
3+
PluginContext,
4+
PluginHandler,
5+
PluginParameters,
6+
} from '../types';
7+
import { getCurrentContentPart, setCurrentContentPart } from '../utils';
8+
9+
export const handler: PluginHandler = async (
10+
context: PluginContext,
11+
parameters: PluginParameters,
12+
eventType: HookEventType
13+
) => {
14+
let error = null;
15+
let verdict = true;
16+
let data: any = null;
17+
const transformedData: Record<string, any> = {
18+
request: {
19+
json: null,
20+
},
21+
response: {
22+
json: null,
23+
},
24+
};
25+
let transformed = false;
26+
27+
try {
28+
const regexPattern = parameters.rule;
29+
const redactText = parameters.redactText || '[REDACTED]';
30+
const failOnDetection = parameters.failOnDetection || false;
31+
32+
const { content, textArray } = getCurrentContentPart(context, eventType);
33+
34+
if (!regexPattern) {
35+
throw new Error('Missing regex pattern');
36+
}
37+
if (!content) {
38+
throw new Error('Missing text to match');
39+
}
40+
41+
const regex = new RegExp(regexPattern, 'g');
42+
43+
// Process all text items in the array
44+
let hasMatches = false;
45+
const mappedTextArray: Array<string | null> = [];
46+
textArray.forEach((text) => {
47+
if (!text) {
48+
mappedTextArray.push(null);
49+
return;
50+
}
51+
52+
// Reset regex for each text when using global flag
53+
regex.lastIndex = 0;
54+
55+
const matches = text.match(regex);
56+
if (matches && matches.length > 0) {
57+
hasMatches = true;
58+
}
59+
const replacedText = text.replace(regex, redactText);
60+
mappedTextArray.push(replacedText);
61+
});
62+
63+
// Handle transformation
64+
if (hasMatches) {
65+
setCurrentContentPart(
66+
context,
67+
eventType,
68+
transformedData,
69+
mappedTextArray
70+
);
71+
transformed = true;
72+
}
73+
if (failOnDetection && hasMatches) {
74+
verdict = false;
75+
}
76+
data = {
77+
regexPattern,
78+
verdict,
79+
explanation: transformed
80+
? `Pattern '${regexPattern}' matched and was replaced with '${redactText}'`
81+
: `The regex pattern '${regexPattern}' did not match any text.`,
82+
};
83+
} catch (e: any) {
84+
error = e;
85+
data = {
86+
explanation: `An error occurred while processing the regex: ${e.message}`,
87+
regexPattern: parameters.rule,
88+
};
89+
}
90+
91+
return { error, verdict, data, transformedData, transformed };
92+
};

plugins/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ import { handler as panwPrismaAirsintercept } from './panw-prisma-airs/intercept
5050
import { handler as defaultjwt } from './default/jwt';
5151
import { handler as defaultrequiredMetadataKeys } from './default/requiredMetadataKeys';
5252
import { handler as walledaiguardrails } from './walledai/guardrails';
53+
import { handler as defaultregexReplace } from './default/regexReplace';
5354

5455
export const plugins = {
5556
default: {
@@ -70,6 +71,7 @@ export const plugins = {
7071
modelWhitelist: defaultmodelWhitelist,
7172
jwt: defaultjwt,
7273
requiredMetadataKeys: defaultrequiredMetadataKeys,
74+
regexReplace: defaultregexReplace,
7375
},
7476
portkey: {
7577
moderateContent: portkeymoderateContent,

0 commit comments

Comments
 (0)