UNPKG

@unito/integration-sdk

Version:

Integration SDK

68 lines (67 loc) 2.64 kB
import { walkMemberChain, getCatchClauseParam, LOGGER_NAME_BROAD_RE } from '../utils.js'; const LOGGER_METHOD_RE = /^(error|warn|info|debug)$/; const ERROR_IDENTIFIER_RE = /^(e|err|error|ex|exception|cause)$/i; const SCRIPTS_FILE_RE = /\/scripts?\//; function isLoggerCall(node) { const callee = node.callee; if (!callee || callee.type !== 'MemberExpression') { return false; } const methodProp = callee.property; if (!methodProp || methodProp.type !== 'Identifier') { return false; } if (!LOGGER_METHOD_RE.test(methodProp.name)) { return false; } const { root, props } = walkMemberChain(callee.object); return [root, ...props].some(p => p !== null && LOGGER_NAME_BROAD_RE.test(p)); } const rule = { meta: { type: 'problem', docs: { description: 'Disallow passing full error objects to logger methods; extract specific fields like error.message instead', recommended: true, }, schema: [], messages: { fullErrorObjectLogged: "Do not pass the full error object to {{method}}(). Full error objects contain stack traces, provider response bodies, and potentially credentials. Extract specific fields instead: {{method}}('description', { message: {{identifier}}.message })", }, }, create(context) { const filename = context.filename ?? ''; if (SCRIPTS_FILE_RE.test(filename)) { return {}; } return { CallExpression(node) { if (!isLoggerCall(node)) { return; } const callee = node.callee; const methodProp = callee.property; const method = methodProp.name; const hasIdentifierArg = node.arguments.some(arg => arg.type === 'Identifier'); if (!hasIdentifierArg) { return; } const catchParam = getCatchClauseParam(node); for (const arg of node.arguments) { if (arg.type !== 'Identifier') { continue; } if ((catchParam && arg.name === catchParam) || ERROR_IDENTIFIER_RE.test(arg.name)) { context.report({ node, messageId: 'fullErrorObjectLogged', data: { method, identifier: arg.name }, }); return; } } }, }; }, }; export default rule;