Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Feat: redaction guardrails revamp #889

Merged
merged 23 commits into from
Jan 26, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
c1cdd1e
chore: update guardrail handler
b4s36t4 Jan 24, 2025
1f1991a
chore: remove redaction as a seaprate guardrail and merge them with e…
VisargD Jan 25, 2025
6c06047
chore: allow guardrail hook type to transform req and res
VisargD Jan 25, 2025
271b779
chore: merge redaction in existing guardrails as a parameter
VisargD Jan 25, 2025
d3a73a7
chore: update plugin test cases for redaction
VisargD Jan 25, 2025
ca24ef4
fix: handle string content in set content part plugin util
VisargD Jan 25, 2025
77acd8a
Merge branch 'feat/redaction-guardrails-revamp' into feat/bedrock-gua…
b4s36t4 Jan 25, 2025
86e272d
chore: rename file
b4s36t4 Jan 25, 2025
a2d29a0
Merge branch 'feat/bedrock-guardrails' of github.com:b4s36t4/Rubeus i…
b4s36t4 Jan 25, 2025
f8a4f6f
Merge pull request #890 from b4s36t4/feat/bedrock-guardrails
VisargD Jan 25, 2025
340b8cb
chore: refactor bedrock guardrails for redaction
VisargD Jan 25, 2025
e5063bb
chore: update promptfoo pii redaction verdict logic
VisargD Jan 25, 2025
312ad86
chore: update pangea pii redaction verdict logic
VisargD Jan 25, 2025
fd4cbd6
chore: update patronus pii and phi redaction verdict logic
VisargD Jan 25, 2025
759c81a
chore: add strict handling for different conditions in plugin utils f…
VisargD Jan 25, 2025
abdadf6
chore: add unit tests for get and set content part plugin util functions
VisargD Jan 25, 2025
bc892ef
chore: update set content part plugin util references
VisargD Jan 25, 2025
4b0a18c
chore: update portkey pii redaction explanation and test cases
VisargD Jan 25, 2025
bfce7bd
chore: add redact flag in manifest for all the required guardrails
VisargD Jan 26, 2025
260af68
chore: keep the boilerplate mutator hooks handler
VisargD Jan 26, 2025
7977779
chore: restrict pii redaction for embed requests
VisargD Jan 26, 2025
7edd398
chore: remove unnecessary comments
VisargD Jan 26, 2025
7e37c31
chore: minro cleanup
VisargD Jan 26, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
301 changes: 301 additions & 0 deletions plugins/bedrock/bedrock.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,301 @@
import { HookEventType, PluginContext, PluginParameters } from '../types';
import { pluginHandler } from './index';
import testCreds from './.creds.json';
import { BedrockParameters } from './type';

/**
* @example Parameters object
*
* {
"credentials": {
"accessKeyId": "keyId",
"accessKeySecret": "keysecret",
"region": "us-east-1"
},
"guardrailId": "xyxyxyx",
"guardrailVersion": "1"
* }
*/
describe('Credentials check', () => {
test('Should fail withuout accessKey or accessKeySecret', async () => {
const context = {
request: {
text: 'My email is abc@xyz.com and SSN is 123-45-6789',
json: {
messages: [
{
role: 'user',
content: 'My email is abc@xyz.com and SSN is 123-45-6789',
},
],
},
},
requestType: 'chatComplete',
};
const parameters: PluginParameters<BedrockParameters['credentials']> = {
credentials: {
accessKeyId: '',
accessKeySecret: '',
region: '',
},
guardrailId: '',
guardrailVersion: '',
};

const result = await pluginHandler(
context as unknown as PluginContext,
parameters,
'beforeRequestHook',
{ env: {} }
);

expect(result).toBeDefined();
expect(result.verdict).toBe(true);
expect(result.error).toBeDefined();
expect(result.data).toBeNull();
});

test('Should fail with wrong creds', async () => {
const context = {
request: {
text: 'My email is abc@xyz.com and SSN is 123-45-6789',
json: {
messages: [
{
role: 'user',
content: 'My email is abc@xyz.com and SSN is 123-45-6789',
},
],
},
},
requestType: 'chatComplete',
};
const parameters: PluginParameters<BedrockParameters['credentials']> = {
credentials: {
accessKeyId: 'accessKeyID',
region: 'us-east-1',
accessKeySecret: 'accessKeySecret',
},
guardrailId: 'guardrailID',
guardrailVersion: 'guardrailVersion',
};

const result = await pluginHandler(
context as unknown as PluginContext,
parameters,
'beforeRequestHook',
{ env: {} }
);

expect(result).toBeDefined();
expect(result.verdict).toBe(true);
expect(result.error).toBeDefined();
expect(result.data).toBeNull();
});

it('should only detect PII', async () => {
const eventType = 'beforeRequestHook' as HookEventType;
const context = {
request: {
text: 'My email is abc@xyz.com and SSN is 123-45-6789',
json: {
messages: [
{
role: 'user',
content: 'My email is abc@xyz.com and SSN is 123-45-6789',
},
],
},
},
requestType: 'chatComplete',
};
const parameters = {
credentials: testCreds,
guardrailId: testCreds.guardrailId,
guardrailVersion: testCreds.guardrailVersion,
};

const result = await pluginHandler(
context as PluginContext,
parameters,
eventType,
{
env: {},
}
);
expect(result).toBeDefined();
expect(result.verdict).toBe(false);
expect(result.error).toBeNull();
expect(result.data).toBeDefined();
expect(result.transformedData?.request?.json).toBeNull();
});

it('should detect and redact PII in request text', async () => {
const context = {
request: {
text: 'My SSN is 123-45-6789 and some random text',
json: {
messages: [
{
role: 'user',
content: 'My SSN is 123-45-6789 and some random text',
},
],
},
},
requestType: 'chatComplete',
};
const parameters = {
credentials: testCreds,
redact: true,
guardrailId: testCreds.guardrailId,
guardrailVersion: testCreds.guardrailVersion,
};

const result = await pluginHandler(
context as PluginContext,
parameters,
'beforeRequestHook',
{
env: {},
}
);
expect(result.error).toBeNull();
expect(result.verdict).toBe(true);
expect(result.data).toBeDefined();
expect(result.transformedData?.request?.json?.messages?.[0]?.content).toBe(
'My SSN is {US_SOCIAL_SECURITY_NUMBER} and some random text'
);
});

it('should detect and redact PII in request text with multiple content parts', async () => {
const context = {
request: {
text: 'My SSN is 123-45-6789 My SSN is 123-45-6789 and some random text',
json: {
messages: [
{
role: 'user',
content: [
{
type: 'text',
text: 'My SSN is 123-45-6789',
},
{
type: 'text',
text: 'My SSN is 123-45-6789 and some random text',
},
],
},
],
},
},
requestType: 'chatComplete',
};
const parameters = {
credentials: testCreds,
redact: true,
guardrailId: testCreds.guardrailId,
guardrailVersion: testCreds.guardrailVersion,
};

const result = await pluginHandler(
context as PluginContext,
parameters,
'beforeRequestHook',
{
env: {},
}
);

expect(result.error).toBeNull();
expect(result.verdict).toBe(true);
expect(result.data).toBeDefined;
expect(
result.transformedData?.request?.json?.messages?.[0]?.content?.[0]?.text
).toBe('My SSN is {US_SOCIAL_SECURITY_NUMBER}');
expect(
result.transformedData?.request?.json?.messages?.[0]?.content?.[1]?.text
).toBe('My SSN is {US_SOCIAL_SECURITY_NUMBER} and some random text');
});

it('should detect and redact PII in response text', async () => {
const context = {
response: {
text: 'My SSN is 123-45-6789 and some random text',
json: {
choices: [
{
message: {
role: 'assistant',
content: 'My SSN is 123-45-6789 and some random text',
},
},
],
},
},
requestType: 'chatComplete',
};
const parameters = {
credentials: testCreds,
redact: true,
guardrailId: testCreds.guardrailId,
guardrailVersion: testCreds.guardrailVersion,
};

const result = await pluginHandler(
context as PluginContext,
parameters,
'afterRequestHook',
{
env: {},
}
);

expect(result.error).toBeNull();
expect(result.verdict).toBe(true);
expect(result.data).toBeDefined();
expect(
result.transformedData?.response?.json?.choices?.[0]?.message?.content
).toBe('My SSN is {US_SOCIAL_SECURITY_NUMBER} and some random text');
});

it('should pass text without PII', async () => {
const eventType = 'afterRequestHook' as HookEventType;
const context = {
response: {
text: 'Hello world',
json: {
choices: [
{
message: {
role: 'assistant',
content: 'Hello world',
},
},
],
},
},
requestType: 'chatComplete',
};
const parameters = {
credentials: testCreds,
guardrailId: testCreds.guardrailId,
guardrailVersion: testCreds.guardrailVersion,
};

const result = await pluginHandler(
context as PluginContext,
parameters,
eventType,
{
env: {},
}
);
expect(result).toBeDefined();
expect(result.verdict).toBe(true);
expect(result.error).toBeNull();
expect(result.data).toBeDefined();
expect(result.transformedData?.response?.json).toBeNull();
});
});
Loading
Loading