Files
alighasami 3d5eaf9445
Security: Sync from Public / sync-from-public (push) Has been cancelled
Test: Benchmark Nightly / build (push) Has been cancelled
Test: Benchmark Nightly / Notify Cats on failure (push) Has been cancelled
CI: Python / Checks (push) Has been cancelled
Test: Evals Python / Workflow Comparison Python (push) Has been cancelled
Util: Check Docs URLs / check-docs-urls (push) Has been cancelled
Test: Visual Storybook / Cloudflare Pages (push) Has been cancelled
Test: E2E Performance / build-and-test-performance (push) Has been cancelled
Test: Workflows Nightly / Run Workflow Tests (push) Has been cancelled
Util: Cleanup CI Docker Images / Delete stale CI images (push) Has been cancelled
Test: Benchmark Destroy Env / build (push) Has been cancelled
Util: Update Node Popularity / update-popularity (push) Has been cancelled
Test: E2E Coverage Weekly / Coverage Tests (push) Has been cancelled
first commit
2026-03-17 16:22:57 +03:30

412 lines
11 KiB
TypeScript

/* eslint-disable n8n-nodes-base/node-filename-against-convention */
import { type INodeProperties } from 'n8n-workflow';
import { JAILBREAK_PROMPT } from './actions/checks/jailbreak';
import { NSFW_SYSTEM_PROMPT } from './actions/checks/nsfw';
import { PII_NAME_MAP, PIIEntity } from './actions/checks/pii';
import { TOPICAL_ALIGNMENT_SYSTEM_PROMPT } from './actions/checks/topicalAlignment';
import { LLM_SYSTEM_RULES } from './helpers/model';
const THRESHOLD_OPTION: INodeProperties = {
displayName: 'Threshold',
name: 'threshold',
type: 'number',
default: '',
description: 'Minimum confidence threshold to trigger the guardrail (0.0 to 1.0)',
hint: 'Inputs scoring less than this will be treated as violations',
};
const getPromptOption: (
defaultPrompt: string,
collapsible?: boolean,
hint?: string,
) => INodeProperties[] = (defaultPrompt, collapsible = true, hint) => {
const promptParameters: INodeProperties = {
displayName: 'Prompt',
name: 'prompt',
type: 'string',
default: defaultPrompt,
description:
'The system prompt used by the guardrail. Thresholds and JSON output are enforced by the node automatically.',
hint,
typeOptions: {
rows: 6,
},
};
if (collapsible) {
return [
{ displayName: 'Customize Prompt', name: 'customizePrompt', type: 'boolean', default: false },
{ ...promptParameters, displayOptions: { show: { customizePrompt: [true] } } },
];
}
return [promptParameters];
};
const wrapValue = (properties: INodeProperties[]) => ({
displayName: 'Value',
name: 'value',
values: properties,
});
export const propertiesDescription: INodeProperties[] = [
{
displayName:
'Use guardrails to validate text against a set of policies (e.g. NSFW, prompt injection) or to sanitize it (e.g. personal data, secret keys)',
name: 'guardrailsUsage',
type: 'notice',
default: '',
},
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
options: [
{
name: 'Check Text for Violations',
value: 'classify',
action: 'Check text for violations',
description: 'Validate text against a set of policies (e.g. NSFW, prompt injection)',
},
{
name: 'Sanitize Text',
value: 'sanitize',
action: 'Sanitize text',
// eslint-disable-next-line n8n-nodes-base/node-param-description-excess-final-period
description: 'Redact text to mask personal data, secret keys, URLs, etc.',
},
],
default: 'classify',
},
{
displayName: 'Text To Check',
name: 'text',
type: 'string',
required: true,
default: '',
typeOptions: {
rows: 1,
},
},
{
displayName: 'Guardrails',
name: 'guardrails',
placeholder: 'Add Guardrail',
type: 'collection',
default: {},
options: [
{
displayName: 'Keywords',
name: 'keywords',
type: 'string',
default: '',
description:
'This guardrail checks if specified keywords appear in the input text and can be configured to trigger tripwires based on keyword matches. Multiple keywords can be added separated by comma.',
displayOptions: {
show: {
'/operation': ['classify'],
},
},
},
{
displayName: 'Jailbreak',
name: 'jailbreak',
type: 'fixedCollection',
default: { value: { threshold: 0.7 } },
description: 'Detects attempts to jailbreak or bypass AI safety measures',
options: [wrapValue([THRESHOLD_OPTION, ...getPromptOption(JAILBREAK_PROMPT)])],
displayOptions: {
show: {
'/operation': ['classify'],
},
},
},
{
displayName: 'NSFW',
name: 'nsfw',
type: 'fixedCollection',
default: { value: { threshold: 0.7 } },
description: 'Detects attempts to generate NSFW content',
options: [wrapValue([THRESHOLD_OPTION, ...getPromptOption(NSFW_SYSTEM_PROMPT)])],
displayOptions: {
show: {
'/operation': ['classify'],
},
},
},
{
displayName: 'Personal Data (PII)',
name: 'pii',
type: 'fixedCollection',
default: { value: { type: 'all' } },
description: 'Detects attempts to use personal data content',
options: [
wrapValue([
{
displayName: 'Type',
name: 'type',
type: 'options',
default: '',
options: [
{ name: 'All', value: 'all' },
{ name: 'Selected', value: 'selected' },
],
},
{
displayName: 'Entities',
name: 'entities',
type: 'multiOptions',
default: [],
displayOptions: {
show: {
type: ['selected'],
},
},
options: Object.values(PIIEntity).map((entity) => ({
name: PII_NAME_MAP[entity],
value: entity,
})),
},
]),
],
},
{
displayName: 'Secret Keys',
name: 'secretKeys',
type: 'fixedCollection',
default: { value: { permissiveness: 'balanced' } },
description:
'Detects attempts to use secret keys in the input text. Scans text for common patterns, applies entropy analysis to detect random-looking strings.',
options: [
wrapValue([
{
displayName: 'Permissiveness',
name: 'permissiveness',
type: 'options',
default: '',
options: [
{
name: 'Strict',
value: 'strict',
description:
'Most sensitive, may have more false positives (commonly flag high entropy filenames or code)',
},
{
name: 'Balanced',
value: 'balanced',
description: 'Balanced between sensitivity and specificity',
},
{
name: 'Permissive',
value: 'permissive',
description:
'Least sensitive, may miss some secret keys (but also reduces false positives)',
},
],
},
]),
],
},
{
displayName: 'Topical Alignment',
name: 'topicalAlignment',
type: 'fixedCollection',
default: { value: { threshold: 0.7 } },
description: 'Detects attempts to stray from the business scope',
options: [
wrapValue([
THRESHOLD_OPTION,
...getPromptOption(
TOPICAL_ALIGNMENT_SYSTEM_PROMPT,
false,
'Make sure you replace the placeholder.',
),
]),
],
displayOptions: {
show: {
'/operation': ['classify'],
},
},
},
{
displayName: 'URLs',
name: 'urls',
type: 'fixedCollection',
default: { value: { allowedSchemes: ['https'], allowedUrls: '' } },
description: 'Blocks URLs that are not in the allowed list',
options: [
wrapValue([
{
displayName: 'Block All URLs Except',
name: 'allowedUrls',
type: 'string',
// keep placeholder to avoid limitation that removes collections with unchanged default values
default: 'PLACEHOLDER',
description:
'Multiple URLs can be added separated by comma. Leave empty to block all URLs.',
},
{
displayName: 'Allowed Schemes',
name: 'allowedSchemes',
type: 'multiOptions',
default: ['https'],
// eslint-disable-next-line n8n-nodes-base/node-param-multi-options-type-unsorted-items
options: [
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-miscased
{ name: 'https', value: 'https' },
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-miscased
{ name: 'http', value: 'http' },
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-miscased
{ name: 'ftp', value: 'ftp' },
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-miscased
{ name: 'data', value: 'data' },
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-miscased
{ name: 'javascript', value: 'javascript' },
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-miscased
{ name: 'vbscript', value: 'vbscript' },
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-miscased
{ name: 'mailto', value: 'mailto' },
],
},
{
displayName: 'Block Userinfo',
name: 'blockUserinfo',
type: 'boolean',
default: true,
description:
'Whether to block URLs with userinfo (user:pass@domain) to prevent credential injection',
displayOptions: {
show: {
'/operation': ['classify'],
},
},
},
{
displayName: 'Sanitize Userinfo',
name: 'blockUserinfo',
type: 'boolean',
default: true,
description:
'Whether to sanitize URLs with userinfo (user:pass@domain) to prevent credential injection',
displayOptions: {
show: {
'/operation': ['sanitize'],
},
},
},
{
displayName: 'Allow Subdomains',
name: 'allowSubdomains',
type: 'boolean',
default: true,
description:
'Whether to allow subdomains (e.g. sub.domain.com if domain.com is allowed)',
},
]),
],
},
{
displayName: 'Custom',
name: 'custom',
type: 'fixedCollection',
typeOptions: {
sortable: true,
multipleValues: true,
},
placeholder: 'Add Custom Guardrail',
default: {
guardrail: [{ name: 'Custom Guardrail' }],
},
options: [
{
displayName: 'Guardrail',
name: 'guardrail',
values: [
{
displayName: 'Name',
name: 'name',
type: 'string',
default: '',
description: 'Name of the custom guardrail',
},
THRESHOLD_OPTION,
...getPromptOption('', false),
],
},
],
displayOptions: {
show: {
'/operation': ['classify'],
},
},
},
{
displayName: 'Custom Regex',
name: 'customRegex',
type: 'fixedCollection',
typeOptions: {
sortable: true,
multipleValues: true,
},
placeholder: 'Add Custom Regex',
default: {},
options: [
{
displayName: 'Regex',
name: 'regex',
values: [
{
displayName: 'Name',
name: 'name',
type: 'string',
default: '',
description:
'Name of the custom regex. Will be used for replacement when sanitizing.',
},
{
displayName: 'Regex',
name: 'value',
type: 'string',
default: '',
description: 'Regex to match the input text',
placeholder: '/text/gi',
},
],
},
],
},
],
},
{
displayName: 'Customize System Message',
name: 'customizeSystemMessage',
description:
'Whether to customize the system message used by the guardrail to specify the output format',
type: 'boolean',
default: false,
displayOptions: {
show: {
'/operation': ['classify'],
},
},
},
{
displayName: 'System Message',
name: 'systemMessage',
type: 'string',
description:
'The system message used by the guardrail to enforce thresholds and JSON output according to schema',
hint: 'This message is appended after prompts defined by guardrails',
default: LLM_SYSTEM_RULES,
typeOptions: {
rows: 6,
},
displayOptions: {
show: {
'/customizeSystemMessage': [true],
},
},
},
];