@n8n/n8n-nodes-langchain 1.122.46 → 1.122.48
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/nodes/Guardrails/actions/checks/keywords.js +2 -3
- package/dist/nodes/Guardrails/actions/checks/keywords.js.map +1 -1
- package/dist/nodes/Guardrails/actions/checks/pii.js +6 -5
- package/dist/nodes/Guardrails/actions/checks/pii.js.map +1 -1
- package/dist/nodes/Guardrails/actions/checks/secretKeys.js +2 -2
- package/dist/nodes/Guardrails/actions/checks/secretKeys.js.map +1 -1
- package/dist/nodes/Guardrails/helpers/common.js +2 -10
- package/dist/nodes/Guardrails/helpers/common.js.map +1 -1
- package/package.json +6 -6
|
@@ -21,6 +21,7 @@ __export(keywords_exports, {
|
|
|
21
21
|
createKeywordsCheckFn: () => createKeywordsCheckFn
|
|
22
22
|
});
|
|
23
23
|
module.exports = __toCommonJS(keywords_exports);
|
|
24
|
+
var import_n8n_workflow = require("n8n-workflow");
|
|
24
25
|
const keywordsCheck = (text, config) => {
|
|
25
26
|
const { keywords } = config;
|
|
26
27
|
const sanitizedKeywords = keywords.map((k) => k.replace(/[.,!?;:]+$/, ""));
|
|
@@ -38,11 +39,9 @@ const keywordsCheck = (text, config) => {
|
|
|
38
39
|
(k) => k.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")
|
|
39
40
|
);
|
|
40
41
|
const patternText = `\\b(?:${escapedKeywords.join("|")})\\b`;
|
|
41
|
-
const pattern = new RegExp(patternText, "gi");
|
|
42
42
|
const matches = [];
|
|
43
|
-
let match;
|
|
44
43
|
const seen = /* @__PURE__ */ new Set();
|
|
45
|
-
|
|
44
|
+
for (const match of import_n8n_workflow.safeRegex.matchAll(patternText, text, "gi")) {
|
|
46
45
|
const matchedText = match[0];
|
|
47
46
|
if (!seen.has(matchedText.toLowerCase())) {
|
|
48
47
|
matches.push(matchedText);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../nodes/Guardrails/actions/checks/keywords.ts"],"sourcesContent":["// Source: https://github.com/openai/openai-guardrails-js/blob/b9b99b4fb454f02a362c2836aec6285176ec40a8/src/checks/keywords.ts\nimport type { CreateCheckFn, GuardrailResult } from '../types';\n\ninterface KeywordsConfig {\n\tkeywords: string[];\n}\n\n/**\n * Keywords-based content filtering guardrail.\n *\n * Checks if any of the configured keywords appear in the input text.\n * Can be configured to trigger tripwires on matches or just report them.\n *\n * @param text Input text to check\n * @param config Configuration specifying keywords and behavior\n * @returns GuardrailResult indicating if tripwire was triggered\n */\nconst keywordsCheck = (text: string, config: KeywordsConfig): GuardrailResult => {\n\tconst { keywords } = config;\n\n\t// Sanitize keywords by stripping trailing punctuation\n\tconst sanitizedKeywords = keywords.map((k: string) => k.replace(/[.,!?;:]+$/, ''));\n\n\tconst validKeywords = sanitizedKeywords.filter((k: string) => k.length > 0);\n\n\tif (validKeywords.length === 0) {\n\t\treturn {\n\t\t\tguardrailName: 'keywords',\n\t\t\ttripwireTriggered: false,\n\t\t\tinfo: {\n\t\t\t\tmatchedKeywords: [],\n\t\t\t},\n\t\t};\n\t}\n\n\t// Create regex pattern with word boundaries\n\t// Escape special regex characters and join with word boundaries\n\tconst escapedKeywords = validKeywords.map((k: string) =>\n\t\tk.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'),\n\t);\n\tconst patternText = `\\\\b(?:${escapedKeywords.join('|')})\\\\b`;\n\
|
|
1
|
+
{"version":3,"sources":["../../../../../nodes/Guardrails/actions/checks/keywords.ts"],"sourcesContent":["// Source: https://github.com/openai/openai-guardrails-js/blob/b9b99b4fb454f02a362c2836aec6285176ec40a8/src/checks/keywords.ts\nimport { safeRegex } from 'n8n-workflow';\n\nimport type { CreateCheckFn, GuardrailResult } from '../types';\n\ninterface KeywordsConfig {\n\tkeywords: string[];\n}\n\n/**\n * Keywords-based content filtering guardrail.\n *\n * Checks if any of the configured keywords appear in the input text.\n * Can be configured to trigger tripwires on matches or just report them.\n *\n * @param text Input text to check\n * @param config Configuration specifying keywords and behavior\n * @returns GuardrailResult indicating if tripwire was triggered\n */\nconst keywordsCheck = (text: string, config: KeywordsConfig): GuardrailResult => {\n\tconst { keywords } = config;\n\n\t// Sanitize keywords by stripping trailing punctuation\n\tconst sanitizedKeywords = keywords.map((k: string) => k.replace(/[.,!?;:]+$/, ''));\n\n\tconst validKeywords = sanitizedKeywords.filter((k: string) => k.length > 0);\n\n\tif (validKeywords.length === 0) {\n\t\treturn {\n\t\t\tguardrailName: 'keywords',\n\t\t\ttripwireTriggered: false,\n\t\t\tinfo: {\n\t\t\t\tmatchedKeywords: [],\n\t\t\t},\n\t\t};\n\t}\n\n\t// Create regex pattern with word boundaries\n\t// Escape special regex characters and join with word boundaries\n\tconst escapedKeywords = validKeywords.map((k: string) =>\n\t\tk.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'),\n\t);\n\tconst patternText = `\\\\b(?:${escapedKeywords.join('|')})\\\\b`;\n\n\tconst matches: string[] = [];\n\tconst seen = new Set<string>();\n\n\t// Find all matches and collect unique ones (case-insensitive)\n\tfor (const match of safeRegex.matchAll(patternText, text, 'gi')) {\n\t\tconst matchedText = match[0];\n\t\tif (!seen.has(matchedText.toLowerCase())) {\n\t\t\tmatches.push(matchedText);\n\t\t\tseen.add(matchedText.toLowerCase());\n\t\t}\n\t}\n\n\tconst tripwireTriggered = matches.length > 0;\n\n\treturn {\n\t\tguardrailName: 'keywords',\n\t\ttripwireTriggered,\n\t\tinfo: {\n\t\t\tmatchedKeywords: matches,\n\t\t},\n\t};\n};\n\nexport const createKeywordsCheckFn: CreateCheckFn<KeywordsConfig> = (config) => (input: string) =>\n\tkeywordsCheck(input, config);\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,0BAA0B;AAkB1B,MAAM,gBAAgB,CAAC,MAAc,WAA4C;AAChF,QAAM,EAAE,SAAS,IAAI;AAGrB,QAAM,oBAAoB,SAAS,IAAI,CAAC,MAAc,EAAE,QAAQ,cAAc,EAAE,CAAC;AAEjF,QAAM,gBAAgB,kBAAkB,OAAO,CAAC,MAAc,EAAE,SAAS,CAAC;AAE1E,MAAI,cAAc,WAAW,GAAG;AAC/B,WAAO;AAAA,MACN,eAAe;AAAA,MACf,mBAAmB;AAAA,MACnB,MAAM;AAAA,QACL,iBAAiB,CAAC;AAAA,MACnB;AAAA,IACD;AAAA,EACD;AAIA,QAAM,kBAAkB,cAAc;AAAA,IAAI,CAAC,MAC1C,EAAE,QAAQ,uBAAuB,MAAM;AAAA,EACxC;AACA,QAAM,cAAc,SAAS,gBAAgB,KAAK,GAAG,CAAC;AAEtD,QAAM,UAAoB,CAAC;AAC3B,QAAM,OAAO,oBAAI,IAAY;AAG7B,aAAW,SAAS,8BAAU,SAAS,aAAa,MAAM,IAAI,GAAG;AAChE,UAAM,cAAc,MAAM,CAAC;AAC3B,QAAI,CAAC,KAAK,IAAI,YAAY,YAAY,CAAC,GAAG;AACzC,cAAQ,KAAK,WAAW;AACxB,WAAK,IAAI,YAAY,YAAY,CAAC;AAAA,IACnC;AAAA,EACD;AAEA,QAAM,oBAAoB,QAAQ,SAAS;AAE3C,SAAO;AAAA,IACN,eAAe;AAAA,IACf;AAAA,IACA,MAAM;AAAA,MACL,iBAAiB;AAAA,IAClB;AAAA,EACD;AACD;AAEO,MAAM,wBAAuD,CAAC,WAAW,CAAC,UAChF,cAAc,OAAO,MAAM;","names":[]}
|
|
@@ -24,6 +24,7 @@ __export(pii_exports, {
|
|
|
24
24
|
createPiiCheckFn: () => createPiiCheckFn
|
|
25
25
|
});
|
|
26
26
|
module.exports = __toCommonJS(pii_exports);
|
|
27
|
+
var import_n8n_workflow = require("n8n-workflow");
|
|
27
28
|
var import_common = require("../../helpers/common");
|
|
28
29
|
var PIIEntity = /* @__PURE__ */ ((PIIEntity2) => {
|
|
29
30
|
PIIEntity2["CREDIT_CARD"] = "CREDIT_CARD";
|
|
@@ -159,11 +160,11 @@ function detectPii(text, config) {
|
|
|
159
160
|
}
|
|
160
161
|
const grouped = {};
|
|
161
162
|
const analyzerResults = [];
|
|
162
|
-
const matchAgainstPattern = (name,
|
|
163
|
-
const flags =
|
|
164
|
-
const
|
|
165
|
-
|
|
166
|
-
|
|
163
|
+
const matchAgainstPattern = (name, literal) => {
|
|
164
|
+
const flags = literal.flags.includes("g") ? literal.flags : literal.flags + "g";
|
|
165
|
+
const matches = import_n8n_workflow.safeRegex.matchAll(literal.source, text, flags);
|
|
166
|
+
for (const match of matches) {
|
|
167
|
+
if (match.index === void 0) continue;
|
|
167
168
|
const entityType = name;
|
|
168
169
|
const start = match.index;
|
|
169
170
|
const end = match.index + match[0].length;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../nodes/Guardrails/actions/checks/pii.ts"],"sourcesContent":["// Source: https://github.com/openai/openai-guardrails-js/blob/b9b99b4fb454f02a362c2836aec6285176ec40a8/src/checks/pii.ts\n/**\n * PII detection guardrail for sensitive text content.\n *\n * This module implements a guardrail for detecting Personally Identifiable\n * Information (PII) in text using regex patterns. It defines the config\n * schema for entity selection, output/result structures, and the async guardrail\n * check_fn for runtime enforcement.\n */\n\nimport { parseRegex } from '../../helpers/common';\nimport type { CreateCheckFn, CustomRegex } from '../types';\n\n/**\n * Supported PII entity types for detection.\n *\n * Includes global and region-specific types (US, UK, Spain, Italy, etc.).\n * These map to regex patterns for detection.\n */\n// eslint-disable-next-line no-restricted-syntax\nexport enum PIIEntity {\n\t// Global\n\tCREDIT_CARD = 'CREDIT_CARD',\n\tCRYPTO = 'CRYPTO',\n\tDATE_TIME = 'DATE_TIME',\n\tEMAIL_ADDRESS = 'EMAIL_ADDRESS',\n\tIBAN_CODE = 'IBAN_CODE',\n\tIP_ADDRESS = 'IP_ADDRESS',\n\tLOCATION = 'LOCATION',\n\tPHONE_NUMBER = 'PHONE_NUMBER',\n\tMEDICAL_LICENSE = 'MEDICAL_LICENSE',\n\n\t// USA\n\tUS_BANK_NUMBER = 'US_BANK_NUMBER',\n\tUS_DRIVER_LICENSE = 'US_DRIVER_LICENSE',\n\tUS_ITIN = 'US_ITIN',\n\tUS_PASSPORT = 'US_PASSPORT',\n\tUS_SSN = 'US_SSN',\n\n\t// UK\n\tUK_NHS = 'UK_NHS',\n\tUK_NINO = 'UK_NINO',\n\n\t// Spain\n\tES_NIF = 'ES_NIF',\n\tES_NIE = 'ES_NIE',\n\n\t// Italy\n\tIT_FISCAL_CODE = 'IT_FISCAL_CODE',\n\tIT_DRIVER_LICENSE = 'IT_DRIVER_LICENSE',\n\tIT_VAT_CODE = 'IT_VAT_CODE',\n\tIT_PASSPORT = 'IT_PASSPORT',\n\tIT_IDENTITY_CARD = 'IT_IDENTITY_CARD',\n\n\t// Poland\n\tPL_PESEL = 'PL_PESEL',\n\n\t// Singapore\n\tSG_NRIC_FIN = 'SG_NRIC_FIN',\n\tSG_UEN = 'SG_UEN',\n\n\t// Australia\n\tAU_ABN = 'AU_ABN',\n\tAU_ACN = 'AU_ACN',\n\tAU_TFN = 'AU_TFN',\n\tAU_MEDICARE = 'AU_MEDICARE',\n\n\t// India\n\tIN_PAN = 'IN_PAN',\n\tIN_AADHAAR = 'IN_AADHAAR',\n\tIN_VEHICLE_REGISTRATION = 'IN_VEHICLE_REGISTRATION',\n\tIN_VOTER = 'IN_VOTER',\n\tIN_PASSPORT = 'IN_PASSPORT',\n\n\t// Finland\n\tFI_PERSONAL_IDENTITY_CODE = 'FI_PERSONAL_IDENTITY_CODE',\n}\n\nconst allEntities = Object.values(PIIEntity);\n\nexport type PIIConfig = {\n\tentities?: PIIEntity[];\n\tcustomRegex?: CustomRegex[];\n};\n\nexport type CustomRegexConfig = {\n\tcustomRegex: CustomRegex[];\n};\n\n/**\n * Internal result structure for PII detection.\n */\ninterface PiiDetectionResult {\n\tmapping: Record<string, string[]>;\n\tanalyzerResults: PiiAnalyzerResult[];\n}\n\n/**\n * PII analyzer result structure.\n */\ninterface PiiAnalyzerResult {\n\tentityType: string;\n\ttext: string;\n}\n\nexport const PII_NAME_MAP: Record<PIIEntity, string> = {\n\t[PIIEntity.CREDIT_CARD]: 'Credit Card',\n\t[PIIEntity.CRYPTO]: 'Crypto',\n\t[PIIEntity.DATE_TIME]: 'Date Time',\n\t[PIIEntity.EMAIL_ADDRESS]: 'Email Address',\n\t[PIIEntity.IBAN_CODE]: 'IBAN Code',\n\t[PIIEntity.IP_ADDRESS]: 'IP Address',\n\t[PIIEntity.LOCATION]: 'Location',\n\t[PIIEntity.PHONE_NUMBER]: 'Phone Number',\n\t[PIIEntity.MEDICAL_LICENSE]: 'Medical License',\n\t[PIIEntity.US_BANK_NUMBER]: 'US Bank Number',\n\t[PIIEntity.US_DRIVER_LICENSE]: 'US Driver License',\n\t[PIIEntity.US_ITIN]: 'US ITIN',\n\t[PIIEntity.US_PASSPORT]: 'US Passport',\n\t[PIIEntity.US_SSN]: 'US SSN',\n\t[PIIEntity.UK_NHS]: 'UK NHS',\n\t[PIIEntity.UK_NINO]: 'UK NINO',\n\t[PIIEntity.ES_NIF]: 'ES NIF',\n\t[PIIEntity.ES_NIE]: 'ES NIE',\n\t[PIIEntity.IT_FISCAL_CODE]: 'IT Fiscal Code',\n\t[PIIEntity.IT_DRIVER_LICENSE]: 'IT Driver License',\n\t[PIIEntity.IT_VAT_CODE]: 'IT VAT Code',\n\t[PIIEntity.IT_PASSPORT]: 'IT Passport',\n\t[PIIEntity.IT_IDENTITY_CARD]: 'IT Identity Card',\n\t[PIIEntity.PL_PESEL]: 'PL PESEL',\n\t[PIIEntity.SG_NRIC_FIN]: 'SG NRIC FIN',\n\t[PIIEntity.SG_UEN]: 'SG UEN',\n\t[PIIEntity.AU_ABN]: 'AU ABN',\n\t[PIIEntity.AU_ACN]: 'AU ACN',\n\t[PIIEntity.AU_TFN]: 'AU TFN',\n\t[PIIEntity.AU_MEDICARE]: 'AU Medicare',\n\t[PIIEntity.IN_PAN]: 'IN PAN',\n\t[PIIEntity.IN_AADHAAR]: 'IN AADHAAR',\n\t[PIIEntity.IN_VEHICLE_REGISTRATION]: 'IN Vehicle Registration',\n\t[PIIEntity.IN_VOTER]: 'IN Voter',\n\t[PIIEntity.IN_PASSPORT]: 'IN Passport',\n\t[PIIEntity.FI_PERSONAL_IDENTITY_CODE]: 'FI Personal Identity Code',\n};\n\n/**\n * Default regex patterns for PII entity types.\n */\nconst DEFAULT_PII_PATTERNS: Record<PIIEntity, RegExp> = {\n\t[PIIEntity.CREDIT_CARD]: /\\b\\d{4}[-\\s]?\\d{4}[-\\s]?\\d{4}[-\\s]?\\d{4}\\b/g,\n\t[PIIEntity.CRYPTO]: /\\b[13][a-km-zA-HJ-NP-Z1-9]{25,34}\\b/g,\n\t[PIIEntity.DATE_TIME]: /\\b(0[1-9]|1[0-2])[\\/\\-](0[1-9]|[12]\\d|3[01])[\\/\\-](19|20)\\d{2}\\b/g,\n\t[PIIEntity.EMAIL_ADDRESS]: /\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Z|a-z]{2,}\\b/g,\n\t[PIIEntity.IBAN_CODE]: /\\b[A-Z]{2}[0-9]{2}[A-Z0-9]{4}[0-9]{7}([A-Z0-9]?){0,16}\\b/g,\n\t[PIIEntity.IP_ADDRESS]: /\\b(?:[0-9]{1,3}\\.){3}[0-9]{1,3}\\b/g,\n\t[PIIEntity.LOCATION]:\n\t\t/\\b[A-Za-z\\s]+(?:Street|St|Avenue|Ave|Road|Rd|Boulevard|Blvd|Drive|Dr|Lane|Ln|Place|Pl|Court|Ct|Way|Highway|Hwy)\\b/g,\n\t[PIIEntity.PHONE_NUMBER]: /\\b[\\+]?[(]?[0-9]{3}[)]?[-\\s\\.]?[0-9]{3}[-\\s\\.]?[0-9]{4,6}\\b/g,\n\t[PIIEntity.MEDICAL_LICENSE]: /\\b[A-Z]{2}\\d{6}\\b/g,\n\n\t// USA\n\t[PIIEntity.US_BANK_NUMBER]: /\\b\\d{8,17}\\b/g,\n\t[PIIEntity.US_DRIVER_LICENSE]: /\\b[A-Z]\\d{7}\\b/g,\n\t[PIIEntity.US_ITIN]: /\\b9\\d{2}-\\d{2}-\\d{4}\\b/g,\n\t[PIIEntity.US_PASSPORT]: /\\b[A-Z]\\d{8}\\b/g,\n\t[PIIEntity.US_SSN]: /\\b\\d{3}-\\d{2}-\\d{4}\\b|\\b\\d{9}\\b/g,\n\n\t// UK\n\t[PIIEntity.UK_NHS]: /\\b\\d{3} \\d{3} \\d{4}\\b/g,\n\t[PIIEntity.UK_NINO]: /\\b[A-Z]{2}\\d{6}[A-Z]\\b/g,\n\n\t// Spain\n\t[PIIEntity.ES_NIF]: /\\b[A-Z]\\d{8}\\b/g,\n\t[PIIEntity.ES_NIE]: /\\b[A-Z]\\d{8}\\b/g,\n\n\t// Italy\n\t[PIIEntity.IT_FISCAL_CODE]: /\\b[A-Z]{6}\\d{2}[A-Z]\\d{2}[A-Z]\\d{3}[A-Z]\\b/g,\n\t[PIIEntity.IT_DRIVER_LICENSE]: /\\b[A-Z]{2}\\d{7}\\b/g,\n\t[PIIEntity.IT_VAT_CODE]: /\\bIT\\d{11}\\b/g,\n\t[PIIEntity.IT_PASSPORT]: /\\b[A-Z]{2}\\d{7}\\b/g,\n\t[PIIEntity.IT_IDENTITY_CARD]: /\\b[A-Z]{2}\\d{7}\\b/g,\n\n\t// Poland\n\t[PIIEntity.PL_PESEL]: /\\b\\d{11}\\b/g,\n\n\t// Singapore\n\t[PIIEntity.SG_NRIC_FIN]: /\\b[A-Z]\\d{7}[A-Z]\\b/g,\n\t[PIIEntity.SG_UEN]: /\\b\\d{8}[A-Z]\\b|\\b\\d{9}[A-Z]\\b/g,\n\n\t// Australia\n\t[PIIEntity.AU_ABN]: /\\b\\d{2} \\d{3} \\d{3} \\d{3}\\b/g,\n\t[PIIEntity.AU_ACN]: /\\b\\d{3} \\d{3} \\d{3}\\b/g,\n\t[PIIEntity.AU_TFN]: /\\b\\d{9}\\b/g,\n\t[PIIEntity.AU_MEDICARE]: /\\b\\d{4} \\d{5} \\d{1}\\b/g,\n\n\t// India\n\t[PIIEntity.IN_PAN]: /\\b[A-Z]{5}\\d{4}[A-Z]\\b/g,\n\t[PIIEntity.IN_AADHAAR]: /\\b\\d{4} \\d{4} \\d{4}\\b/g,\n\t[PIIEntity.IN_VEHICLE_REGISTRATION]: /\\b[A-Z]{2}\\d{2}[A-Z]{2}\\d{4}\\b/g,\n\t[PIIEntity.IN_VOTER]: /\\b[A-Z]{3}\\d{7}\\b/g,\n\t[PIIEntity.IN_PASSPORT]: /\\b[A-Z]\\d{7}\\b/g,\n\n\t// Finland\n\t[PIIEntity.FI_PERSONAL_IDENTITY_CODE]: /\\b\\d{6}[+-A]\\d{3}[A-Z0-9]\\b/g,\n};\n\n/**\n * Run regex analysis and collect findings by entity type.\n *\n * @param text The text to analyze for PII\n * @param config PII detection configuration\n * @returns Object containing mapping of entities to detected snippets\n * @throws Error if text is empty or null\n */\nfunction detectPii(text: string, config: PIIConfig): PiiDetectionResult {\n\tif (!text) {\n\t\treturn {\n\t\t\tmapping: {},\n\t\t\tanalyzerResults: [],\n\t\t};\n\t}\n\n\tconst grouped: Record<string, string[]> = {};\n\tconst analyzerResults: PiiAnalyzerResult[] = [];\n\n\tconst matchAgainstPattern = (name: string, pattern: RegExp) => {\n\t\t// make sure to add the global flag to the regex, otherwise while() will never end\n\t\tconst flags = pattern.flags.includes('g') ? pattern.flags : pattern.flags + 'g';\n\t\tconst regex = new RegExp(pattern.source, flags);\n\t\tlet match;\n\t\twhile ((match = regex.exec(text)) !== null) {\n\t\t\tconst entityType = name;\n\t\t\tconst start = match.index;\n\t\t\tconst end = match.index + match[0].length;\n\n\t\t\tif (!grouped[entityType]) {\n\t\t\t\tgrouped[entityType] = [];\n\t\t\t}\n\t\t\tgrouped[entityType].push(text.substring(start, end));\n\n\t\t\tanalyzerResults.push({\n\t\t\t\tentityType,\n\t\t\t\ttext: text.substring(start, end),\n\t\t\t});\n\t\t}\n\t};\n\n\t// Check each configured entity type\n\tconst entities = config.entities ?? allEntities;\n\tfor (const entity of entities) {\n\t\tconst pattern = DEFAULT_PII_PATTERNS[entity];\n\t\tif (pattern) {\n\t\t\tmatchAgainstPattern(entity, pattern);\n\t\t}\n\t}\n\tif (config.customRegex?.length) {\n\t\tfor (const regex of config.customRegex) {\n\t\t\tmatchAgainstPattern(regex.name, parseRegex(regex.value));\n\t\t}\n\t}\n\n\treturn {\n\t\tmapping: grouped,\n\t\tanalyzerResults,\n\t};\n}\n\nexport const createPiiCheckFn: CreateCheckFn<PIIConfig> = (config) => {\n\treturn (input: string) => {\n\t\tconst detection = detectPii(input, config);\n\t\tconst piiFound = detection.mapping && Object.keys(detection.mapping).length > 0;\n\t\treturn {\n\t\t\tguardrailName: 'personalData',\n\t\t\ttripwireTriggered: piiFound,\n\t\t\tinfo: {\n\t\t\t\tmaskEntities: detection.mapping,\n\t\t\t\tanalyzerResults: detection.analyzerResults,\n\t\t\t},\n\t\t};\n\t};\n};\n\nexport const createCustomRegexCheckFn: CreateCheckFn<CustomRegexConfig> = (config) => {\n\treturn (input: string) => {\n\t\tconst detection = detectPii(input, { customRegex: config.customRegex, entities: [] });\n\t\tconst customRegexFound = detection.mapping && Object.keys(detection.mapping).length > 0;\n\t\treturn {\n\t\t\tguardrailName: 'customRegex',\n\t\t\ttripwireTriggered: customRegexFound,\n\t\t\tinfo: {\n\t\t\t\tmaskEntities: detection.mapping,\n\t\t\t\tanalyzerResults: detection.analyzerResults,\n\t\t\t},\n\t\t};\n\t};\n};\n"],"mappings":"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","names":["PIIEntity"]}
|
|
1
|
+
{"version":3,"sources":["../../../../../nodes/Guardrails/actions/checks/pii.ts"],"sourcesContent":["// Source: https://github.com/openai/openai-guardrails-js/blob/b9b99b4fb454f02a362c2836aec6285176ec40a8/src/checks/pii.ts\n/**\n * PII detection guardrail for sensitive text content.\n *\n * This module implements a guardrail for detecting Personally Identifiable\n * Information (PII) in text using regex patterns. It defines the config\n * schema for entity selection, output/result structures, and the async guardrail\n * check_fn for runtime enforcement.\n */\nimport { safeRegex } from 'n8n-workflow';\n\nimport { parseRegex } from '../../helpers/common';\nimport type { CreateCheckFn, CustomRegex } from '../types';\n\n/**\n * Supported PII entity types for detection.\n *\n * Includes global and region-specific types (US, UK, Spain, Italy, etc.).\n * These map to regex patterns for detection.\n */\n// eslint-disable-next-line no-restricted-syntax\nexport enum PIIEntity {\n\t// Global\n\tCREDIT_CARD = 'CREDIT_CARD',\n\tCRYPTO = 'CRYPTO',\n\tDATE_TIME = 'DATE_TIME',\n\tEMAIL_ADDRESS = 'EMAIL_ADDRESS',\n\tIBAN_CODE = 'IBAN_CODE',\n\tIP_ADDRESS = 'IP_ADDRESS',\n\tLOCATION = 'LOCATION',\n\tPHONE_NUMBER = 'PHONE_NUMBER',\n\tMEDICAL_LICENSE = 'MEDICAL_LICENSE',\n\n\t// USA\n\tUS_BANK_NUMBER = 'US_BANK_NUMBER',\n\tUS_DRIVER_LICENSE = 'US_DRIVER_LICENSE',\n\tUS_ITIN = 'US_ITIN',\n\tUS_PASSPORT = 'US_PASSPORT',\n\tUS_SSN = 'US_SSN',\n\n\t// UK\n\tUK_NHS = 'UK_NHS',\n\tUK_NINO = 'UK_NINO',\n\n\t// Spain\n\tES_NIF = 'ES_NIF',\n\tES_NIE = 'ES_NIE',\n\n\t// Italy\n\tIT_FISCAL_CODE = 'IT_FISCAL_CODE',\n\tIT_DRIVER_LICENSE = 'IT_DRIVER_LICENSE',\n\tIT_VAT_CODE = 'IT_VAT_CODE',\n\tIT_PASSPORT = 'IT_PASSPORT',\n\tIT_IDENTITY_CARD = 'IT_IDENTITY_CARD',\n\n\t// Poland\n\tPL_PESEL = 'PL_PESEL',\n\n\t// Singapore\n\tSG_NRIC_FIN = 'SG_NRIC_FIN',\n\tSG_UEN = 'SG_UEN',\n\n\t// Australia\n\tAU_ABN = 'AU_ABN',\n\tAU_ACN = 'AU_ACN',\n\tAU_TFN = 'AU_TFN',\n\tAU_MEDICARE = 'AU_MEDICARE',\n\n\t// India\n\tIN_PAN = 'IN_PAN',\n\tIN_AADHAAR = 'IN_AADHAAR',\n\tIN_VEHICLE_REGISTRATION = 'IN_VEHICLE_REGISTRATION',\n\tIN_VOTER = 'IN_VOTER',\n\tIN_PASSPORT = 'IN_PASSPORT',\n\n\t// Finland\n\tFI_PERSONAL_IDENTITY_CODE = 'FI_PERSONAL_IDENTITY_CODE',\n}\n\nconst allEntities = Object.values(PIIEntity);\n\nexport type PIIConfig = {\n\tentities?: PIIEntity[];\n\tcustomRegex?: CustomRegex[];\n};\n\nexport type CustomRegexConfig = {\n\tcustomRegex: CustomRegex[];\n};\n\n/**\n * Internal result structure for PII detection.\n */\ninterface PiiDetectionResult {\n\tmapping: Record<string, string[]>;\n\tanalyzerResults: PiiAnalyzerResult[];\n}\n\n/**\n * PII analyzer result structure.\n */\ninterface PiiAnalyzerResult {\n\tentityType: string;\n\ttext: string;\n}\n\nexport const PII_NAME_MAP: Record<PIIEntity, string> = {\n\t[PIIEntity.CREDIT_CARD]: 'Credit Card',\n\t[PIIEntity.CRYPTO]: 'Crypto',\n\t[PIIEntity.DATE_TIME]: 'Date Time',\n\t[PIIEntity.EMAIL_ADDRESS]: 'Email Address',\n\t[PIIEntity.IBAN_CODE]: 'IBAN Code',\n\t[PIIEntity.IP_ADDRESS]: 'IP Address',\n\t[PIIEntity.LOCATION]: 'Location',\n\t[PIIEntity.PHONE_NUMBER]: 'Phone Number',\n\t[PIIEntity.MEDICAL_LICENSE]: 'Medical License',\n\t[PIIEntity.US_BANK_NUMBER]: 'US Bank Number',\n\t[PIIEntity.US_DRIVER_LICENSE]: 'US Driver License',\n\t[PIIEntity.US_ITIN]: 'US ITIN',\n\t[PIIEntity.US_PASSPORT]: 'US Passport',\n\t[PIIEntity.US_SSN]: 'US SSN',\n\t[PIIEntity.UK_NHS]: 'UK NHS',\n\t[PIIEntity.UK_NINO]: 'UK NINO',\n\t[PIIEntity.ES_NIF]: 'ES NIF',\n\t[PIIEntity.ES_NIE]: 'ES NIE',\n\t[PIIEntity.IT_FISCAL_CODE]: 'IT Fiscal Code',\n\t[PIIEntity.IT_DRIVER_LICENSE]: 'IT Driver License',\n\t[PIIEntity.IT_VAT_CODE]: 'IT VAT Code',\n\t[PIIEntity.IT_PASSPORT]: 'IT Passport',\n\t[PIIEntity.IT_IDENTITY_CARD]: 'IT Identity Card',\n\t[PIIEntity.PL_PESEL]: 'PL PESEL',\n\t[PIIEntity.SG_NRIC_FIN]: 'SG NRIC FIN',\n\t[PIIEntity.SG_UEN]: 'SG UEN',\n\t[PIIEntity.AU_ABN]: 'AU ABN',\n\t[PIIEntity.AU_ACN]: 'AU ACN',\n\t[PIIEntity.AU_TFN]: 'AU TFN',\n\t[PIIEntity.AU_MEDICARE]: 'AU Medicare',\n\t[PIIEntity.IN_PAN]: 'IN PAN',\n\t[PIIEntity.IN_AADHAAR]: 'IN AADHAAR',\n\t[PIIEntity.IN_VEHICLE_REGISTRATION]: 'IN Vehicle Registration',\n\t[PIIEntity.IN_VOTER]: 'IN Voter',\n\t[PIIEntity.IN_PASSPORT]: 'IN Passport',\n\t[PIIEntity.FI_PERSONAL_IDENTITY_CODE]: 'FI Personal Identity Code',\n};\n\n/**\n * Default regex patterns for PII entity types.\n */\nconst DEFAULT_PII_PATTERNS: Record<PIIEntity, RegExp> = {\n\t[PIIEntity.CREDIT_CARD]: /\\b\\d{4}[-\\s]?\\d{4}[-\\s]?\\d{4}[-\\s]?\\d{4}\\b/g,\n\t[PIIEntity.CRYPTO]: /\\b[13][a-km-zA-HJ-NP-Z1-9]{25,34}\\b/g,\n\t[PIIEntity.DATE_TIME]: /\\b(0[1-9]|1[0-2])[\\/\\-](0[1-9]|[12]\\d|3[01])[\\/\\-](19|20)\\d{2}\\b/g,\n\t[PIIEntity.EMAIL_ADDRESS]: /\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Z|a-z]{2,}\\b/g,\n\t[PIIEntity.IBAN_CODE]: /\\b[A-Z]{2}[0-9]{2}[A-Z0-9]{4}[0-9]{7}([A-Z0-9]?){0,16}\\b/g,\n\t[PIIEntity.IP_ADDRESS]: /\\b(?:[0-9]{1,3}\\.){3}[0-9]{1,3}\\b/g,\n\t[PIIEntity.LOCATION]:\n\t\t/\\b[A-Za-z\\s]+(?:Street|St|Avenue|Ave|Road|Rd|Boulevard|Blvd|Drive|Dr|Lane|Ln|Place|Pl|Court|Ct|Way|Highway|Hwy)\\b/g,\n\t[PIIEntity.PHONE_NUMBER]: /\\b[\\+]?[(]?[0-9]{3}[)]?[-\\s\\.]?[0-9]{3}[-\\s\\.]?[0-9]{4,6}\\b/g,\n\t[PIIEntity.MEDICAL_LICENSE]: /\\b[A-Z]{2}\\d{6}\\b/g,\n\n\t// USA\n\t[PIIEntity.US_BANK_NUMBER]: /\\b\\d{8,17}\\b/g,\n\t[PIIEntity.US_DRIVER_LICENSE]: /\\b[A-Z]\\d{7}\\b/g,\n\t[PIIEntity.US_ITIN]: /\\b9\\d{2}-\\d{2}-\\d{4}\\b/g,\n\t[PIIEntity.US_PASSPORT]: /\\b[A-Z]\\d{8}\\b/g,\n\t[PIIEntity.US_SSN]: /\\b\\d{3}-\\d{2}-\\d{4}\\b|\\b\\d{9}\\b/g,\n\n\t// UK\n\t[PIIEntity.UK_NHS]: /\\b\\d{3} \\d{3} \\d{4}\\b/g,\n\t[PIIEntity.UK_NINO]: /\\b[A-Z]{2}\\d{6}[A-Z]\\b/g,\n\n\t// Spain\n\t[PIIEntity.ES_NIF]: /\\b[A-Z]\\d{8}\\b/g,\n\t[PIIEntity.ES_NIE]: /\\b[A-Z]\\d{8}\\b/g,\n\n\t// Italy\n\t[PIIEntity.IT_FISCAL_CODE]: /\\b[A-Z]{6}\\d{2}[A-Z]\\d{2}[A-Z]\\d{3}[A-Z]\\b/g,\n\t[PIIEntity.IT_DRIVER_LICENSE]: /\\b[A-Z]{2}\\d{7}\\b/g,\n\t[PIIEntity.IT_VAT_CODE]: /\\bIT\\d{11}\\b/g,\n\t[PIIEntity.IT_PASSPORT]: /\\b[A-Z]{2}\\d{7}\\b/g,\n\t[PIIEntity.IT_IDENTITY_CARD]: /\\b[A-Z]{2}\\d{7}\\b/g,\n\n\t// Poland\n\t[PIIEntity.PL_PESEL]: /\\b\\d{11}\\b/g,\n\n\t// Singapore\n\t[PIIEntity.SG_NRIC_FIN]: /\\b[A-Z]\\d{7}[A-Z]\\b/g,\n\t[PIIEntity.SG_UEN]: /\\b\\d{8}[A-Z]\\b|\\b\\d{9}[A-Z]\\b/g,\n\n\t// Australia\n\t[PIIEntity.AU_ABN]: /\\b\\d{2} \\d{3} \\d{3} \\d{3}\\b/g,\n\t[PIIEntity.AU_ACN]: /\\b\\d{3} \\d{3} \\d{3}\\b/g,\n\t[PIIEntity.AU_TFN]: /\\b\\d{9}\\b/g,\n\t[PIIEntity.AU_MEDICARE]: /\\b\\d{4} \\d{5} \\d{1}\\b/g,\n\n\t// India\n\t[PIIEntity.IN_PAN]: /\\b[A-Z]{5}\\d{4}[A-Z]\\b/g,\n\t[PIIEntity.IN_AADHAAR]: /\\b\\d{4} \\d{4} \\d{4}\\b/g,\n\t[PIIEntity.IN_VEHICLE_REGISTRATION]: /\\b[A-Z]{2}\\d{2}[A-Z]{2}\\d{4}\\b/g,\n\t[PIIEntity.IN_VOTER]: /\\b[A-Z]{3}\\d{7}\\b/g,\n\t[PIIEntity.IN_PASSPORT]: /\\b[A-Z]\\d{7}\\b/g,\n\n\t// Finland\n\t[PIIEntity.FI_PERSONAL_IDENTITY_CODE]: /\\b\\d{6}[+-A]\\d{3}[A-Z0-9]\\b/g,\n};\n\n/**\n * Run regex analysis and collect findings by entity type.\n *\n * @param text The text to analyze for PII\n * @param config PII detection configuration\n * @returns Object containing mapping of entities to detected snippets\n * @throws Error if text is empty or null\n */\nfunction detectPii(text: string, config: PIIConfig): PiiDetectionResult {\n\tif (!text) {\n\t\treturn {\n\t\t\tmapping: {},\n\t\t\tanalyzerResults: [],\n\t\t};\n\t}\n\n\tconst grouped: Record<string, string[]> = {};\n\tconst analyzerResults: PiiAnalyzerResult[] = [];\n\n\tconst matchAgainstPattern = (name: string, literal: { source: string; flags: string }) => {\n\t\t// make sure to add the global flag to the regex, otherwise while() will never end\n\t\tconst flags = literal.flags.includes('g') ? literal.flags : literal.flags + 'g';\n\t\tconst matches = safeRegex.matchAll(literal.source, text, flags);\n\t\tfor (const match of matches) {\n\t\t\tif (match.index === undefined) continue;\n\n\t\t\tconst entityType = name;\n\t\t\tconst start = match.index;\n\t\t\tconst end = match.index + match[0].length;\n\n\t\t\tif (!grouped[entityType]) {\n\t\t\t\tgrouped[entityType] = [];\n\t\t\t}\n\t\t\tgrouped[entityType].push(text.substring(start, end));\n\n\t\t\tanalyzerResults.push({\n\t\t\t\tentityType,\n\t\t\t\ttext: text.substring(start, end),\n\t\t\t});\n\t\t}\n\t};\n\n\t// Check each configured entity type\n\tconst entities = config.entities ?? allEntities;\n\tfor (const entity of entities) {\n\t\tconst pattern = DEFAULT_PII_PATTERNS[entity];\n\t\tif (pattern) {\n\t\t\tmatchAgainstPattern(entity, pattern);\n\t\t}\n\t}\n\tif (config.customRegex?.length) {\n\t\tfor (const regex of config.customRegex) {\n\t\t\tmatchAgainstPattern(regex.name, parseRegex(regex.value));\n\t\t}\n\t}\n\n\treturn {\n\t\tmapping: grouped,\n\t\tanalyzerResults,\n\t};\n}\n\nexport const createPiiCheckFn: CreateCheckFn<PIIConfig> = (config) => {\n\treturn (input: string) => {\n\t\tconst detection = detectPii(input, config);\n\t\tconst piiFound = detection.mapping && Object.keys(detection.mapping).length > 0;\n\t\treturn {\n\t\t\tguardrailName: 'personalData',\n\t\t\ttripwireTriggered: piiFound,\n\t\t\tinfo: {\n\t\t\t\tmaskEntities: detection.mapping,\n\t\t\t\tanalyzerResults: detection.analyzerResults,\n\t\t\t},\n\t\t};\n\t};\n};\n\nexport const createCustomRegexCheckFn: CreateCheckFn<CustomRegexConfig> = (config) => {\n\treturn (input: string) => {\n\t\tconst detection = detectPii(input, { customRegex: config.customRegex, entities: [] });\n\t\tconst customRegexFound = detection.mapping && Object.keys(detection.mapping).length > 0;\n\t\treturn {\n\t\t\tguardrailName: 'customRegex',\n\t\t\ttripwireTriggered: customRegexFound,\n\t\t\tinfo: {\n\t\t\t\tmaskEntities: detection.mapping,\n\t\t\t\tanalyzerResults: detection.analyzerResults,\n\t\t\t},\n\t\t};\n\t};\n};\n"],"mappings":"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","names":["PIIEntity"]}
|
|
@@ -22,6 +22,7 @@ __export(secretKeys_exports, {
|
|
|
22
22
|
secretKeysCheck: () => secretKeysCheck
|
|
23
23
|
});
|
|
24
24
|
module.exports = __toCommonJS(secretKeys_exports);
|
|
25
|
+
var import_n8n_workflow = require("n8n-workflow");
|
|
25
26
|
const COMMON_KEY_PREFIXES = [
|
|
26
27
|
"key-",
|
|
27
28
|
"sk-",
|
|
@@ -154,8 +155,7 @@ function isSecretCandidate(s, cfg, customRegex) {
|
|
|
154
155
|
if (customRegex) {
|
|
155
156
|
for (const pattern of customRegex) {
|
|
156
157
|
try {
|
|
157
|
-
|
|
158
|
-
if (regex.test(s)) {
|
|
158
|
+
if (import_n8n_workflow.safeRegex.test(pattern, s)) {
|
|
159
159
|
return true;
|
|
160
160
|
}
|
|
161
161
|
} catch {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../nodes/Guardrails/actions/checks/secretKeys.ts"],"sourcesContent":["/**\n * Secret key detection guardrail module.\n *\n * This module provides functions and configuration for detecting potential API keys,\n * secrets, and credentials in text. It includes entropy and diversity checks, pattern\n * recognition, and a guardrail check_fn for runtime enforcement.\n */\n\nimport type { CreateCheckFn, GuardrailResult } from '../types';\n\nexport type SecretKeysConfig = {\n\tthreshold: 'strict' | 'balanced' | 'permissive';\n\tcustomRegex?: string[];\n};\n\n/**\n * Common key prefixes used in secret keys.\n */\nconst COMMON_KEY_PREFIXES = [\n\t'key-',\n\t'sk-',\n\t'sk_',\n\t'pk_',\n\t'pk-',\n\t'ghp_',\n\t'AKIA',\n\t'xox',\n\t'SG.',\n\t'hf_',\n\t'api-',\n\t'apikey-',\n\t'token-',\n\t'secret-',\n\t'SHA:',\n\t'Bearer ',\n];\n\n/**\n * File extensions to ignore when strict_mode is False.\n */\nconst ALLOWED_EXTENSIONS = [\n\t'.py',\n\t'.js',\n\t'.html',\n\t'.css',\n\t'.json',\n\t'.md',\n\t'.txt',\n\t'.csv',\n\t'.xml',\n\t'.yaml',\n\t'.yml',\n\t'.ini',\n\t'.conf',\n\t'.config',\n\t'.log',\n\t'.sql',\n\t'.sh',\n\t'.bat',\n\t'.dll',\n\t'.so',\n\t'.dylib',\n\t'.jar',\n\t'.war',\n\t'.php',\n\t'.rb',\n\t'.go',\n\t'.rs',\n\t'.ts',\n\t'.jsx',\n\t'.vue',\n\t'.cpp',\n\t'.c',\n\t'.h',\n\t'.cs',\n\t'.fs',\n\t'.vb',\n\t'.doc',\n\t'.docx',\n\t'.xls',\n\t'.xlsx',\n\t'.ppt',\n\t'.pptx',\n\t'.pdf',\n\t'.jpg',\n\t'.jpeg',\n\t'.png',\n];\n\n/**\n * Configuration presets for different sensitivity levels.\n */\nconst CONFIGS: Record<\n\tstring,\n\t{\n\t\tmin_length: number;\n\t\tmin_entropy: number;\n\t\tmin_diversity: number;\n\t\tstrict_mode: boolean;\n\t}\n> = {\n\tstrict: {\n\t\tmin_length: 10,\n\t\tmin_entropy: 3.0, // Lowered from 3.5 to be more reasonable\n\t\tmin_diversity: 2,\n\t\tstrict_mode: true,\n\t},\n\tbalanced: {\n\t\tmin_length: 10, // Lowered to catch more common keys\n\t\tmin_entropy: 3.8,\n\t\tmin_diversity: 3,\n\t\tstrict_mode: false,\n\t},\n\tpermissive: {\n\t\tmin_length: 30,\n\t\tmin_entropy: 4.0,\n\t\tmin_diversity: 2, // Lowered from 3 to be more reasonable\n\t\tstrict_mode: false,\n\t},\n};\n\n/**\n * Calculate the Shannon entropy of a string.\n */\nfunction entropy(s: string): number {\n\tif (s.length === 0) return 0;\n\n\tconst counts: Record<string, number> = {};\n\tfor (const c of s) {\n\t\tcounts[c] = (counts[c] || 0) + 1;\n\t}\n\n\tlet entropy = 0;\n\tfor (const count of Object.values(counts)) {\n\t\tconst probability = count / s.length;\n\t\tentropy -= probability * Math.log2(probability);\n\t}\n\n\treturn entropy;\n}\n\n/**\n * Count the number of character types present in a string.\n */\nfunction charDiversity(s: string): number {\n\treturn [\n\t\ts\n\t\t\t.split('')\n\t\t\t.some((c) => c === c.toLowerCase() && c !== c.toUpperCase()), // lowercase\n\t\ts\n\t\t\t.split('')\n\t\t\t.some((c) => c === c.toUpperCase() && c !== c.toLowerCase()), // uppercase\n\t\ts\n\t\t\t.split('')\n\t\t\t.some((c) => /\\d/.test(c)), // digits\n\t\ts\n\t\t\t.split('')\n\t\t\t.some((c) => !/\\w/.test(c)), // special characters\n\t].filter(Boolean).length;\n}\n\n/**\n * Check if text contains allowed URL or file extension patterns.\n */\nfunction containsAllowedPattern(text: string): boolean {\n\t// Check if it's a URL pattern\n\tconst urlPattern = /^https?:\\/\\/[a-zA-Z0-9.-]+\\/?[a-zA-Z0-9.\\/_-]*$/i;\n\tif (urlPattern.test(text)) {\n\t\t// If it's a URL, check if it contains any secret patterns\n\t\t// If it contains secrets, don't allow it\n\t\tif (COMMON_KEY_PREFIXES.some((prefix) => text.includes(prefix))) {\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\t// Regex for allowed file extensions - must end with the extension\n\tconst extPattern = new RegExp(\n\t\t`^[^\\\\s]*(${ALLOWED_EXTENSIONS.map((ext) => ext.replace('.', '\\\\.')).join('|')})$`,\n\t\t'i',\n\t);\n\treturn extPattern.test(text);\n}\n\n/**\n * Check if a string is a secret key using the specified criteria.\n */\nfunction isSecretCandidate(\n\ts: string,\n\tcfg: (typeof CONFIGS)[keyof typeof CONFIGS],\n\tcustomRegex?: string[],\n): boolean {\n\t// Check custom patterns first if provided\n\tif (customRegex) {\n\t\tfor (const pattern of customRegex) {\n\t\t\ttry {\n\t\t\t\
|
|
1
|
+
{"version":3,"sources":["../../../../../nodes/Guardrails/actions/checks/secretKeys.ts"],"sourcesContent":["/**\n * Secret key detection guardrail module.\n *\n * This module provides functions and configuration for detecting potential API keys,\n * secrets, and credentials in text. It includes entropy and diversity checks, pattern\n * recognition, and a guardrail check_fn for runtime enforcement.\n */\n\nimport { safeRegex } from 'n8n-workflow';\n\nimport type { CreateCheckFn, GuardrailResult } from '../types';\n\nexport type SecretKeysConfig = {\n\tthreshold: 'strict' | 'balanced' | 'permissive';\n\tcustomRegex?: string[];\n};\n\n/**\n * Common key prefixes used in secret keys.\n */\nconst COMMON_KEY_PREFIXES = [\n\t'key-',\n\t'sk-',\n\t'sk_',\n\t'pk_',\n\t'pk-',\n\t'ghp_',\n\t'AKIA',\n\t'xox',\n\t'SG.',\n\t'hf_',\n\t'api-',\n\t'apikey-',\n\t'token-',\n\t'secret-',\n\t'SHA:',\n\t'Bearer ',\n];\n\n/**\n * File extensions to ignore when strict_mode is False.\n */\nconst ALLOWED_EXTENSIONS = [\n\t'.py',\n\t'.js',\n\t'.html',\n\t'.css',\n\t'.json',\n\t'.md',\n\t'.txt',\n\t'.csv',\n\t'.xml',\n\t'.yaml',\n\t'.yml',\n\t'.ini',\n\t'.conf',\n\t'.config',\n\t'.log',\n\t'.sql',\n\t'.sh',\n\t'.bat',\n\t'.dll',\n\t'.so',\n\t'.dylib',\n\t'.jar',\n\t'.war',\n\t'.php',\n\t'.rb',\n\t'.go',\n\t'.rs',\n\t'.ts',\n\t'.jsx',\n\t'.vue',\n\t'.cpp',\n\t'.c',\n\t'.h',\n\t'.cs',\n\t'.fs',\n\t'.vb',\n\t'.doc',\n\t'.docx',\n\t'.xls',\n\t'.xlsx',\n\t'.ppt',\n\t'.pptx',\n\t'.pdf',\n\t'.jpg',\n\t'.jpeg',\n\t'.png',\n];\n\n/**\n * Configuration presets for different sensitivity levels.\n */\nconst CONFIGS: Record<\n\tstring,\n\t{\n\t\tmin_length: number;\n\t\tmin_entropy: number;\n\t\tmin_diversity: number;\n\t\tstrict_mode: boolean;\n\t}\n> = {\n\tstrict: {\n\t\tmin_length: 10,\n\t\tmin_entropy: 3.0, // Lowered from 3.5 to be more reasonable\n\t\tmin_diversity: 2,\n\t\tstrict_mode: true,\n\t},\n\tbalanced: {\n\t\tmin_length: 10, // Lowered to catch more common keys\n\t\tmin_entropy: 3.8,\n\t\tmin_diversity: 3,\n\t\tstrict_mode: false,\n\t},\n\tpermissive: {\n\t\tmin_length: 30,\n\t\tmin_entropy: 4.0,\n\t\tmin_diversity: 2, // Lowered from 3 to be more reasonable\n\t\tstrict_mode: false,\n\t},\n};\n\n/**\n * Calculate the Shannon entropy of a string.\n */\nfunction entropy(s: string): number {\n\tif (s.length === 0) return 0;\n\n\tconst counts: Record<string, number> = {};\n\tfor (const c of s) {\n\t\tcounts[c] = (counts[c] || 0) + 1;\n\t}\n\n\tlet entropy = 0;\n\tfor (const count of Object.values(counts)) {\n\t\tconst probability = count / s.length;\n\t\tentropy -= probability * Math.log2(probability);\n\t}\n\n\treturn entropy;\n}\n\n/**\n * Count the number of character types present in a string.\n */\nfunction charDiversity(s: string): number {\n\treturn [\n\t\ts\n\t\t\t.split('')\n\t\t\t.some((c) => c === c.toLowerCase() && c !== c.toUpperCase()), // lowercase\n\t\ts\n\t\t\t.split('')\n\t\t\t.some((c) => c === c.toUpperCase() && c !== c.toLowerCase()), // uppercase\n\t\ts\n\t\t\t.split('')\n\t\t\t.some((c) => /\\d/.test(c)), // digits\n\t\ts\n\t\t\t.split('')\n\t\t\t.some((c) => !/\\w/.test(c)), // special characters\n\t].filter(Boolean).length;\n}\n\n/**\n * Check if text contains allowed URL or file extension patterns.\n */\nfunction containsAllowedPattern(text: string): boolean {\n\t// Check if it's a URL pattern\n\tconst urlPattern = /^https?:\\/\\/[a-zA-Z0-9.-]+\\/?[a-zA-Z0-9.\\/_-]*$/i;\n\tif (urlPattern.test(text)) {\n\t\t// If it's a URL, check if it contains any secret patterns\n\t\t// If it contains secrets, don't allow it\n\t\tif (COMMON_KEY_PREFIXES.some((prefix) => text.includes(prefix))) {\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\t// Regex for allowed file extensions - must end with the extension\n\tconst extPattern = new RegExp(\n\t\t`^[^\\\\s]*(${ALLOWED_EXTENSIONS.map((ext) => ext.replace('.', '\\\\.')).join('|')})$`,\n\t\t'i',\n\t);\n\treturn extPattern.test(text);\n}\n\n/**\n * Check if a string is a secret key using the specified criteria.\n */\nfunction isSecretCandidate(\n\ts: string,\n\tcfg: (typeof CONFIGS)[keyof typeof CONFIGS],\n\tcustomRegex?: string[],\n): boolean {\n\t// Check custom patterns first if provided\n\tif (customRegex) {\n\t\tfor (const pattern of customRegex) {\n\t\t\ttry {\n\t\t\t\tif (safeRegex.test(pattern, s)) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// Invalid regex pattern, skip\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (!cfg.strict_mode && containsAllowedPattern(s)) {\n\t\treturn false;\n\t}\n\n\tconst longEnough = s.length >= cfg.min_length;\n\tconst diverse = charDiversity(s) >= cfg.min_diversity;\n\n\t// Check common prefixes first - these should always be detected\n\tif (COMMON_KEY_PREFIXES.some((prefix) => s.startsWith(prefix))) {\n\t\treturn true;\n\t}\n\n\t// For other candidates, check length and diversity\n\tif (!(longEnough && diverse)) {\n\t\treturn false;\n\t}\n\n\treturn entropy(s) >= cfg.min_entropy;\n}\n\n/**\n * Detect potential secret keys in text.\n */\nfunction detectSecretKeys(\n\ttext: string,\n\tcfg: (typeof CONFIGS)[keyof typeof CONFIGS],\n\tconfig: SecretKeysConfig,\n): GuardrailResult {\n\tconst words = text.split(/\\s+/).map((w) => w.replace(/[*#]/g, ''));\n\tconst secrets = words.filter((w) => isSecretCandidate(w, cfg, config.customRegex));\n\n\treturn {\n\t\tguardrailName: 'secretKeys',\n\t\ttripwireTriggered: secrets.length > 0,\n\t\tinfo: {\n\t\t\tmaskEntities: { SECRET: secrets },\n\t\t\tdetectedSecrets: secrets,\n\t\t},\n\t};\n}\n\n/**\n * Async guardrail function for secret key and credential detection.\n *\n * Scans the input for likely secrets or credentials (e.g., API keys, tokens)\n * using entropy, diversity, and pattern rules.\n *\n * @param data Input text to scan.\n * @param config Configuration for secret detection.\n * @returns GuardrailResult indicating if secrets were detected, with findings in info.\n */\nexport const secretKeysCheck = (data: string, config: SecretKeysConfig): GuardrailResult => {\n\tconst cfg = CONFIGS[config.threshold];\n\treturn detectSecretKeys(data, cfg, config);\n};\n\nexport const createSecretKeysCheckFn: CreateCheckFn<SecretKeysConfig> =\n\t(config) => (input: string) =>\n\t\tsecretKeysCheck(input, config);\n"],"mappings":"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","names":["entropy"]}
|
|
@@ -22,20 +22,12 @@ __export(common_exports, {
|
|
|
22
22
|
splitByComma: () => splitByComma
|
|
23
23
|
});
|
|
24
24
|
module.exports = __toCommonJS(common_exports);
|
|
25
|
+
var import_n8n_workflow = require("n8n-workflow");
|
|
25
26
|
const splitByComma = (str) => {
|
|
26
27
|
return str.split(",").map((s) => s.trim()).filter((s) => s);
|
|
27
28
|
};
|
|
28
29
|
const parseRegex = (input) => {
|
|
29
|
-
|
|
30
|
-
let regex;
|
|
31
|
-
if (!regexMatch) {
|
|
32
|
-
regex = new RegExp((input || "").toString());
|
|
33
|
-
} else if (regexMatch.length === 1) {
|
|
34
|
-
regex = new RegExp(regexMatch[1]);
|
|
35
|
-
} else {
|
|
36
|
-
regex = new RegExp(regexMatch[1], regexMatch[2]);
|
|
37
|
-
}
|
|
38
|
-
return regex;
|
|
30
|
+
return (0, import_n8n_workflow.parseRegexLiteral)((input || "").toString());
|
|
39
31
|
};
|
|
40
32
|
// Annotate the CommonJS export names for ESM import in node:
|
|
41
33
|
0 && (module.exports = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../nodes/Guardrails/helpers/common.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"sources":["../../../../nodes/Guardrails/helpers/common.ts"],"sourcesContent":["import { parseRegexLiteral } from 'n8n-workflow';\n\nexport const splitByComma = (str: string) => {\n\treturn str\n\t\t.split(',')\n\t\t.map((s) => s.trim())\n\t\t.filter((s) => s);\n};\n\nexport const parseRegex = (input: string) => {\n\treturn parseRegexLiteral((input || '').toString());\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,0BAAkC;AAE3B,MAAM,eAAe,CAAC,QAAgB;AAC5C,SAAO,IACL,MAAM,GAAG,EACT,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EACnB,OAAO,CAAC,MAAM,CAAC;AAClB;AAEO,MAAM,aAAa,CAAC,UAAkB;AAC5C,aAAO,wCAAmB,SAAS,IAAI,SAAS,CAAC;AAClD;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@n8n/n8n-nodes-langchain",
|
|
3
|
-
"version": "1.122.
|
|
3
|
+
"version": "1.122.48",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"files": [
|
|
@@ -159,7 +159,7 @@
|
|
|
159
159
|
"fast-glob": "3.2.12",
|
|
160
160
|
"jest-mock-extended": "^3.0.4",
|
|
161
161
|
"tsup": "^8.5.1",
|
|
162
|
-
"n8n-core": "1.122.
|
|
162
|
+
"n8n-core": "1.122.39",
|
|
163
163
|
"@n8n/eslint-plugin-community-nodes": "0.7.0"
|
|
164
164
|
},
|
|
165
165
|
"dependencies": {
|
|
@@ -232,11 +232,11 @@
|
|
|
232
232
|
"@n8n/client-oauth2": "0.33.6",
|
|
233
233
|
"@n8n/config": "1.65.6",
|
|
234
234
|
"@n8n/di": "0.10.0",
|
|
235
|
-
"@n8n/json-schema-to-zod": "1.6.0",
|
|
236
235
|
"@n8n/errors": "0.5.1",
|
|
237
|
-
"@n8n/
|
|
238
|
-
"n8n-nodes-base": "1.121.
|
|
239
|
-
"n8n-workflow": "1.120.
|
|
236
|
+
"@n8n/json-schema-to-zod": "1.6.0",
|
|
237
|
+
"n8n-nodes-base": "1.121.44",
|
|
238
|
+
"n8n-workflow": "1.120.23",
|
|
239
|
+
"@n8n/typescript-config": "1.3.1"
|
|
240
240
|
},
|
|
241
241
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
242
242
|
"homepage": "https://n8n.io",
|