UNPKG

@jupiterone/jupiterone-mcp

Version:

Model Context Protocol server for JupiterOne account rules and rule details

103 lines 3.41 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.redactJ1ql = redactJ1ql; exports.truncateReason = truncateReason; exports.summarizeInput = summarizeInput; exports.summarizeResult = summarizeResult; /** * Redacts string literals in a J1QL query, preserving structure (entity types, operators, * property names) so query *shape* is captured for usage analytics without literal values. * * Ported from query-engine's `redactCypher` (sdk-graph/src/cypher/redact.ts), adapted for J1QL * (single- and double-quoted literals). The patterns span escaped quotes (`\'` / `\"`) so a * literal is always replaced in full; imperfect boundaries only ever over-redact, never leak. */ function redactJ1ql(query) { return query .replace(/'(?:[^'\\]|\\.)*'/g, "'[REDACTED]'") .replace(/"(?:[^"\\]|\\.)*"/g, '"[REDACTED]"'); } const REASON_MAX = 500; function truncateReason(reason) { return reason.length > REASON_MAX ? `${reason.slice(0, REASON_MAX)}…` : reason; } // Allowlist of scalar inputs safe to log verbatim. Everything not listed is dropped (default-deny), // which keeps sensitive payloads out: action headers/endpoints/recipients/body, integration config, // templates, J1QL variables/flags/scopeFilters, rule operations, and the raw widget input. const SAFE_INPUT_KEYS = [ 'ruleId', 'dashboardId', 'integrationJobId', 'integrationInstanceId', 'jobId', 'definitionId', 'rawDataKey', 'limit', 'size', 'pollingInterval', 'type', 'status', 'name', 'timestamp', 'beginTimestamp', 'endTimestamp', 'tag', 'includeConfig', 'includeDeleted', ]; /** Allowlisted, sanitized summary of tool inputs for usage telemetry. */ function summarizeInput(params) { const out = {}; for (const key of SAFE_INPUT_KEYS) { if (params[key] !== undefined) out[key] = params[key]; } if (typeof params.query === 'string') out.query = redactJ1ql(params.query); // The cursor is an opaque pagination token — record only that paging was requested. if (params.cursor !== undefined) out.hasCursor = true; return out; } const COLLECTION_KEYS = [ 'data', 'rules', 'instances', 'jobs', 'definitions', 'events', 'evaluations', 'activeAlerts', 'dashboards', ]; /** Result metadata (counts, pagination, status) derived from the structured payload. */ function summarizeResult(result) { const out = { isError: !!result.isError }; const sc = result.structuredContent; if (!sc || typeof sc !== 'object' || Array.isArray(sc)) return out; const obj = sc; if (typeof obj.status === 'string') out.status = obj.status; const explicit = obj.total ?? obj.returned ?? obj.totalCount; if (typeof explicit === 'number') { out.resultCount = explicit; } else { for (const key of COLLECTION_KEYS) { if (Array.isArray(obj[key])) { out.resultCount = obj[key].length; break; } } } const pageInfo = obj.pageInfo; if (pageInfo && typeof pageInfo === 'object' && 'hasNextPage' in pageInfo) { out.hasNextPage = !!pageInfo.hasNextPage; } else if (typeof obj.cursor === 'string') { out.hasNextPage = true; } return out; } //# sourceMappingURL=usage.js.map