From 11593f0b75a3ba717270a8f01b2028d2016b2617 Mon Sep 17 00:00:00 2001 From: Ying Mao Date: Mon, 5 Feb 2024 09:29:33 -0500 Subject: [PATCH] [Response Ops][Actions] Logging errors from the mustache lambda format functions (#176014) Resolves https://github.com/elastic/kibana/issues/173972 ## Summary Changing to log and return error string instead of throwing error inside the mustache format lambda functions. When an error occurs, the lambda will return the error message. This allows the rest of the action message to be rendered, while giving the user some indication an error occurred and logging the error in a way that is discoverable in the logs. ## To verify Create a rule and add a message like: ``` {{alert.id}} - {{#FormatDate}} {{{context.nope}}} ; America/New_York ; dddd MMM Do YYYY HH:mm:ss.SSS {{/FormatDate}} ``` When the rule runs and triggers and alert, you should see the alert ID in the notification message along with a `date is empty` message and an error log indicating that the date formatting was unsuccessful due to empty date. --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .../server/lib/mustache_lambdas.test.ts | 82 +++++--- .../actions/server/lib/mustache_lambdas.ts | 50 +++-- .../server/lib/mustache_renderer.test.ts | 176 +++++++++++------- .../actions/server/lib/mustache_renderer.ts | 18 +- .../server/lib/number_formatter.test.ts | 86 ++++++--- .../actions/server/lib/number_formatter.ts | 20 +- x-pack/plugins/actions/server/mocks.ts | 9 +- x-pack/plugins/actions/server/plugin.ts | 7 +- .../sub_action_framework/register.test.ts | 4 +- x-pack/plugins/actions/server/types.ts | 1 + .../connector_types/bedrock/render.test.ts | 11 +- .../server/connector_types/bedrock/render.ts | 3 +- .../connector_types/d3security/render.test.ts | 12 +- .../connector_types/d3security/render.ts | 3 +- .../connector_types/email/index.test.ts | 12 +- .../server/connector_types/email/index.ts | 6 +- .../connector_types/es_index/index.test.ts | 5 + .../server/connector_types/es_index/index.ts | 7 +- .../connector_types/openai/render.test.ts | 8 +- .../server/connector_types/openai/render.ts | 3 +- .../render_template_variables.test.ts | 11 ++ .../opsgenie/render_template_variables.ts | 7 +- .../connector_types/sentinelone/render.ts | 2 + .../connector_types/slack/index.test.ts | 6 +- .../server/connector_types/slack/index.ts | 4 +- .../connector_types/slack_api/index.test.ts | 2 + .../server/connector_types/slack_api/index.ts | 11 +- .../connector_types/tines/render.test.ts | 12 +- .../server/connector_types/tines/render.ts | 1 + .../server/connector_types/torq/index.test.ts | 6 +- .../server/connector_types/torq/index.ts | 3 +- .../connector_types/webhook/index.test.ts | 6 +- .../server/connector_types/webhook/index.ts | 4 +- 33 files changed, 404 insertions(+), 194 deletions(-) diff --git a/x-pack/plugins/actions/server/lib/mustache_lambdas.test.ts b/x-pack/plugins/actions/server/lib/mustache_lambdas.test.ts index 1e33f8b220cff..bd5195423986f 100644 --- a/x-pack/plugins/actions/server/lib/mustache_lambdas.test.ts +++ b/x-pack/plugins/actions/server/lib/mustache_lambdas.test.ts @@ -6,10 +6,16 @@ */ import dedent from 'dedent'; - +import { loggingSystemMock } from '@kbn/core/server/mocks'; import { renderMustacheString } from './mustache_renderer'; +const logger = loggingSystemMock.create().get(); + describe('mustache lambdas', () => { + beforeEach(() => { + jest.resetAllMocks(); + }); + describe('FormatDate', () => { it('date with defaults is successful', () => { const timeStamp = '2022-11-29T15:52:44Z'; @@ -17,7 +23,9 @@ describe('mustache lambdas', () => { {{#FormatDate}} {{timeStamp}} {{/FormatDate}} `.trim(); - expect(renderMustacheString(template, { timeStamp }, 'none')).toEqual('2022-11-29 03:52pm'); + expect(renderMustacheString(logger, template, { timeStamp }, 'none')).toEqual( + '2022-11-29 03:52pm' + ); }); it('date with a time zone is successful', () => { @@ -26,7 +34,9 @@ describe('mustache lambdas', () => { {{#FormatDate}} {{timeStamp}} ; America/New_York {{/FormatDate}} `.trim(); - expect(renderMustacheString(template, { timeStamp }, 'none')).toEqual('2022-11-29 10:52am'); + expect(renderMustacheString(logger, template, { timeStamp }, 'none')).toEqual( + '2022-11-29 10:52am' + ); }); it('date with a format is successful', () => { @@ -35,7 +45,7 @@ describe('mustache lambdas', () => { {{#FormatDate}} {{timeStamp}} ;; dddd MMM Do YYYY HH:mm:ss.SSS {{/FormatDate}} `.trim(); - expect(renderMustacheString(template, { timeStamp }, 'none')).toEqual( + expect(renderMustacheString(logger, template, { timeStamp }, 'none')).toEqual( 'Tuesday Nov 29th 2022 15:52:44.000' ); }); @@ -46,41 +56,48 @@ describe('mustache lambdas', () => { {{#FormatDate}} {{timeStamp}};America/New_York;dddd MMM Do YYYY HH:mm:ss.SSS {{/FormatDate}} `.trim(); - expect(renderMustacheString(template, { timeStamp }, 'none').trim()).toEqual( + expect(renderMustacheString(logger, template, { timeStamp }, 'none').trim()).toEqual( 'Tuesday Nov 29th 2022 10:52:44.000' ); }); - it('empty date produces error', () => { + it('empty date logs and returns error string', () => { const timeStamp = ''; const template = dedent` {{#FormatDate}} {{/FormatDate}} `.trim(); - expect(renderMustacheString(template, { timeStamp }, 'none').trim()).toEqual( - 'error rendering mustache template "{{#FormatDate}} {{/FormatDate}}": date is empty' + expect(renderMustacheString(logger, template, { timeStamp }, 'none').trim()).toEqual( + 'date is empty' ); + expect(logger.warn).toHaveBeenCalledWith(`mustache render error: date is empty`); }); - it('invalid date produces error', () => { + it('invalid date logs and returns error string', () => { const timeStamp = 'this is not a d4t3'; const template = dedent` {{#FormatDate}}{{timeStamp}}{{/FormatDate}} `.trim(); - expect(renderMustacheString(template, { timeStamp }, 'none').trim()).toEqual( - 'error rendering mustache template "{{#FormatDate}}{{timeStamp}}{{/FormatDate}}": invalid date "this is not a d4t3"' + expect(renderMustacheString(logger, template, { timeStamp }, 'none').trim()).toEqual( + 'invalid date "this is not a d4t3"' + ); + expect(logger.warn).toHaveBeenCalledWith( + `mustache render error: invalid date "this is not a d4t3"` ); }); - it('invalid timezone produces error', () => { + it('invalid timezone logs and returns error string', () => { const timeStamp = '2023-04-10T23:52:39'; const template = dedent` {{#FormatDate}}{{timeStamp}};NotATime Zone!{{/FormatDate}} `.trim(); - expect(renderMustacheString(template, { timeStamp }, 'none').trim()).toEqual( - 'error rendering mustache template "{{#FormatDate}}{{timeStamp}};NotATime Zone!{{/FormatDate}}": unknown timeZone value "NotATime Zone!"' + expect(renderMustacheString(logger, template, { timeStamp }, 'none').trim()).toEqual( + 'unknown timeZone value "NotATime Zone!"' + ); + expect(logger.warn).toHaveBeenCalledWith( + `mustache render error: unknown timeZone value "NotATime Zone!"` ); }); @@ -92,7 +109,7 @@ describe('mustache lambdas', () => { // not clear how to force an error, it pretty much does something with // ANY string - expect(renderMustacheString(template, { timeStamp }, 'none').trim()).toEqual( + expect(renderMustacheString(logger, template, { timeStamp }, 'none').trim()).toEqual( 'gamrbamg2' // a => am/pm (so am here); e => day of week ); }); @@ -114,11 +131,11 @@ describe('mustache lambdas', () => { {{/context}} `.trim(); - const result = renderMustacheString(template, vars, 'none'); + const result = renderMustacheString(logger, template, vars, 'none'); expect(result).toEqual(`1\n2\n3\n`); }); - it('invalid expression produces error', () => { + it('invalid expression logs and returns error string', () => { const vars = { context: { a: { b: 1 }, @@ -129,9 +146,12 @@ describe('mustache lambdas', () => { {{#EvalMath}} ) 1 ++++ 0 ( {{/EvalMath}} `.trim(); - const result = renderMustacheString(template, vars, 'none'); + const result = renderMustacheString(logger, template, vars, 'none'); expect(result).toEqual( - `error rendering mustache template "{{#EvalMath}} ) 1 ++++ 0 ( {{/EvalMath}}": error evaluating tinymath expression ") 1 ++++ 0 (": Failed to parse expression. Expected "(", function, literal, or whitespace but ")" found.` + 'error evaluating tinymath expression ") 1 ++++ 0 (": Failed to parse expression. Expected "(", function, literal, or whitespace but ")" found.' + ); + expect(logger.warn).toHaveBeenCalledWith( + `mustache render error: error evaluating tinymath expression ") 1 ++++ 0 (": Failed to parse expression. Expected "(", function, literal, or whitespace but ")" found.` ); }); }); @@ -147,7 +167,7 @@ describe('mustache lambdas', () => { const hjson = ` { # specify rate in requests/second (because comments are helpful!) - rate: 1000 + rate: 1000 a: {{context.a}} a_b: {{context.a.b}} @@ -166,7 +186,7 @@ describe('mustache lambdas', () => { {{#ParseHjson}} ${hjson} {{/ParseHjson}} `.trim(); - const result = renderMustacheString(template, vars, 'none'); + const result = renderMustacheString(logger, template, vars, 'none'); expect(JSON.parse(result)).toMatchInlineSnapshot(` Object { "a": Object { @@ -189,13 +209,18 @@ describe('mustache lambdas', () => { `); }); - it('renders an error message on parse errors', () => { + it('logs an error message and returns error string on parse errors', () => { const template = dedent` {{#ParseHjson}} [1,2,3,,] {{/ParseHjson}} `.trim(); - const result = renderMustacheString(template, {}, 'none'); - expect(result).toMatch(/^error rendering mustache template .*/); + const result = renderMustacheString(logger, template, {}, 'none'); + expect(result).toEqual( + `error parsing Hjson \"[1,2,3,,]\": Found a punctuator character ',' when expecting a quoteless string (check your syntax) at line 1,7 >>>1,2,3,,] ...` + ); + expect(logger.warn).toHaveBeenCalledWith( + `mustache render error: error parsing Hjson \"[1,2,3,,]\": Found a punctuator character ',' when expecting a quoteless string (check your syntax) at line 1,7 >>>1,2,3,,] ...` + ); }); }); @@ -206,16 +231,19 @@ describe('mustache lambdas', () => { {{#FormatNumber}} {{num}}; en-US; style: currency, currency: EUR {{/FormatNumber}} `.trim(); - expect(renderMustacheString(template, { num }, 'none')).toEqual('€42.00'); + expect(renderMustacheString(logger, template, { num }, 'none')).toEqual('€42.00'); }); - it('renders an error message on errors', () => { + it('logs an error message and returns empty string on errors', () => { const num = 'nope;;'; const template = dedent` {{#FormatNumber}} {{num}} {{/FormatNumber}} `.trim(); - expect(renderMustacheString(template, { num }, 'none')).toEqual(`invalid number: 'nope'`); + expect(renderMustacheString(logger, template, { num }, 'none')).toEqual( + `invalid number: 'nope'` + ); + expect(logger.warn).toHaveBeenCalledWith(`mustache render error: invalid number: 'nope'`); }); }); }); diff --git a/x-pack/plugins/actions/server/lib/mustache_lambdas.ts b/x-pack/plugins/actions/server/lib/mustache_lambdas.ts index 02ea659785aad..8d4a87556b70f 100644 --- a/x-pack/plugins/actions/server/lib/mustache_lambdas.ts +++ b/x-pack/plugins/actions/server/lib/mustache_lambdas.ts @@ -8,6 +8,7 @@ import * as tinymath from '@kbn/tinymath'; import { parse as hjsonParse } from 'hjson'; import moment from 'moment-timezone'; +import { Logger } from '@kbn/core/server'; import { formatNumber } from './number_formatter'; @@ -16,96 +17,102 @@ type Variables = Record; const DefaultDateTimeZone = 'UTC'; const DefaultDateFormat = 'YYYY-MM-DD hh:mma'; -export function getMustacheLambdas(): Variables { - return getLambdas(); +export function getMustacheLambdas(logger: Logger): Variables { + return getLambdas(logger); } const TimeZoneSet = new Set(moment.tz.names()); type RenderFn = (text: string) => string; -function getLambdas() { +function getLambdas(logger: Logger) { return { EvalMath: () => // mustache invokes lamdas with `this` set to the current "view" (variables) function (this: Variables, text: string, render: RenderFn) { - return evalMath(this, render(text.trim())); + return evalMath(this, render(text.trim()), logger); }, ParseHjson: () => function (text: string, render: RenderFn) { - return parseHjson(render(text.trim())); + return parseHjson(render(text.trim()), logger); }, FormatDate: () => function (text: string, render: RenderFn) { const dateString = render(text.trim()).trim(); - return formatDate(dateString); + return formatDate(dateString, logger); }, FormatNumber: () => function (text: string, render: RenderFn) { const numberString = render(text.trim()).trim(); - return formatNumber(numberString); + return formatNumber(logger, numberString); }, }; } -function evalMath(vars: Variables, o: unknown): string { +function evalMath(vars: Variables, o: unknown, logger: Logger): string { const expr = `${o}`; try { const result = tinymath.evaluate(expr, vars); return `${result}`; } catch (err) { - throw new Error(`error evaluating tinymath expression "${expr}": ${err.message}`); + return logAndReturnErr( + logger, + `error evaluating tinymath expression "${expr}": ${err.message}` + ); } } -function parseHjson(o: unknown): string { +function parseHjson(o: unknown, logger: Logger): string { const hjsonObject = `${o}`; let object: unknown; try { object = hjsonParse(hjsonObject); } catch (err) { - throw new Error(`error parsing Hjson "${hjsonObject}": ${err.message}`); + return logAndReturnErr(logger, `error parsing Hjson "${hjsonObject}": ${err.message}`); } return JSON.stringify(object); } -function formatDate(dateString: unknown): string { +function formatDate(dateString: unknown, logger: Logger): string { const { date, timeZone, format } = splitDateString(`${dateString}`); if (date === '') { - throw new Error(`date is empty`); + return logAndReturnErr(logger, `date is empty`); } if (isNaN(new Date(date).valueOf())) { - throw new Error(`invalid date "${date}"`); + return logAndReturnErr(logger, `invalid date "${date}"`); } let mDate: moment.Moment; try { mDate = moment(date); if (!mDate.isValid()) { - throw new Error(`date is invalid`); + return logAndReturnErr(logger, `invalid date "${date}"`); } } catch (err) { - throw new Error(`error evaluating moment date "${date}": ${err.message}`); + return logAndReturnErr(logger, `error evaluating moment date "${date}": ${err.message}`); } if (!TimeZoneSet.has(timeZone)) { - throw new Error(`unknown timeZone value "${timeZone}"`); + return logAndReturnErr(logger, `unknown timeZone value "${timeZone}"`); } try { mDate.tz(timeZone); } catch (err) { - throw new Error(`error evaluating moment timeZone "${timeZone}": ${err.message}`); + return logAndReturnErr( + logger, + `error evaluating moment timeZone "${timeZone}": ${err.message}` + ); } try { return mDate.format(format); } catch (err) { - throw new Error(`error evaluating moment format "${format}": ${err.message}`); + return logAndReturnErr(logger, `error evaluating moment format "${format}": ${err.message}`); } } @@ -118,3 +125,8 @@ function splitDateString(dateString: string) { format: format || DefaultDateFormat, }; } + +function logAndReturnErr(logger: Logger, errMessage: string): string { + logger.warn(`mustache render error: ${errMessage}`); + return errMessage; +} diff --git a/x-pack/plugins/actions/server/lib/mustache_renderer.test.ts b/x-pack/plugins/actions/server/lib/mustache_renderer.test.ts index 14bd5f47507e7..ed07b6899a318 100644 --- a/x-pack/plugins/actions/server/lib/mustache_renderer.test.ts +++ b/x-pack/plugins/actions/server/lib/mustache_renderer.test.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { loggingSystemMock } from '@kbn/core/server/mocks'; import { renderMustacheString, renderMustacheStringNoEscape, @@ -12,6 +13,8 @@ import { Escape, } from './mustache_renderer'; +const logger = loggingSystemMock.create().get(); + const variables = { a: 1, b: '2', @@ -38,97 +41,121 @@ const variables = { }; describe('mustache_renderer', () => { + beforeEach(() => { + jest.resetAllMocks(); + }); + describe('renderMustacheString()', () => { for (const escapeVal of ['none', 'slack', 'markdown', 'json']) { const escape = escapeVal as Escape; it(`handles basic templating that does not need escaping for ${escape}`, () => { - expect(renderMustacheString('', variables, escape)).toBe(''); - expect(renderMustacheString('{{a}}', variables, escape)).toBe('1'); - expect(renderMustacheString('{{b}}', variables, escape)).toBe('2'); - expect(renderMustacheString('{{c}}', variables, escape)).toBe('false'); - expect(renderMustacheString('{{d}}', variables, escape)).toBe(''); - expect(renderMustacheString('{{e}}', variables, escape)).toBe(''); + expect(renderMustacheString(logger, '', variables, escape)).toBe(''); + expect(renderMustacheString(logger, '{{a}}', variables, escape)).toBe('1'); + expect(renderMustacheString(logger, '{{b}}', variables, escape)).toBe('2'); + expect(renderMustacheString(logger, '{{c}}', variables, escape)).toBe('false'); + expect(renderMustacheString(logger, '{{d}}', variables, escape)).toBe(''); + expect(renderMustacheString(logger, '{{e}}', variables, escape)).toBe(''); if (escape === 'json') { - expect(renderMustacheString('{{f}}', variables, escape)).toBe('{\\"g\\":3,\\"h\\":null}'); + expect(renderMustacheString(logger, '{{f}}', variables, escape)).toBe( + '{\\"g\\":3,\\"h\\":null}' + ); } else if (escape === 'markdown') { - expect(renderMustacheString('{{f}}', variables, escape)).toBe('\\{"g":3,"h":null\\}'); + expect(renderMustacheString(logger, '{{f}}', variables, escape)).toBe( + '\\{"g":3,"h":null\\}' + ); } else { - expect(renderMustacheString('{{f}}', variables, escape)).toBe('{"g":3,"h":null}'); + expect(renderMustacheString(logger, '{{f}}', variables, escape)).toBe('{"g":3,"h":null}'); } - expect(renderMustacheString('{{f.g}}', variables, escape)).toBe('3'); - expect(renderMustacheString('{{f.h}}', variables, escape)).toBe(''); - expect(renderMustacheString('{{i}}', variables, escape)).toBe('42,43,44'); + expect(renderMustacheString(logger, '{{f.g}}', variables, escape)).toBe('3'); + expect(renderMustacheString(logger, '{{f.h}}', variables, escape)).toBe(''); + expect(renderMustacheString(logger, '{{i}}', variables, escape)).toBe('42,43,44'); if (escape === 'markdown') { - expect(renderMustacheString('{{i.asJSON}}', variables, escape)).toBe('\\[42,43,44\\]'); + expect(renderMustacheString(logger, '{{i.asJSON}}', variables, escape)).toBe( + '\\[42,43,44\\]' + ); } else { - expect(renderMustacheString('{{i.asJSON}}', variables, escape)).toBe('[42,43,44]'); + expect(renderMustacheString(logger, '{{i.asJSON}}', variables, escape)).toBe( + '[42,43,44]' + ); } }); } it('handles escape:none with commonly escaped strings', () => { - expect(renderMustacheString('{{lt}}', variables, 'none')).toBe(variables.lt); - expect(renderMustacheString('{{gt}}', variables, 'none')).toBe(variables.gt); - expect(renderMustacheString('{{amp}}', variables, 'none')).toBe(variables.amp); - expect(renderMustacheString('{{nl}}', variables, 'none')).toBe(variables.nl); - expect(renderMustacheString('{{dq}}', variables, 'none')).toBe(variables.dq); - expect(renderMustacheString('{{bt}}', variables, 'none')).toBe(variables.bt); - expect(renderMustacheString('{{bs}}', variables, 'none')).toBe(variables.bs); - expect(renderMustacheString('{{st}}', variables, 'none')).toBe(variables.st); - expect(renderMustacheString('{{ul}}', variables, 'none')).toBe(variables.ul); + expect(renderMustacheString(logger, '{{lt}}', variables, 'none')).toBe(variables.lt); + expect(renderMustacheString(logger, '{{gt}}', variables, 'none')).toBe(variables.gt); + expect(renderMustacheString(logger, '{{amp}}', variables, 'none')).toBe(variables.amp); + expect(renderMustacheString(logger, '{{nl}}', variables, 'none')).toBe(variables.nl); + expect(renderMustacheString(logger, '{{dq}}', variables, 'none')).toBe(variables.dq); + expect(renderMustacheString(logger, '{{bt}}', variables, 'none')).toBe(variables.bt); + expect(renderMustacheString(logger, '{{bs}}', variables, 'none')).toBe(variables.bs); + expect(renderMustacheString(logger, '{{st}}', variables, 'none')).toBe(variables.st); + expect(renderMustacheString(logger, '{{ul}}', variables, 'none')).toBe(variables.ul); }); it('handles escape:markdown with commonly escaped strings', () => { - expect(renderMustacheString('{{lt}}', variables, 'markdown')).toBe(variables.lt); - expect(renderMustacheString('{{gt}}', variables, 'markdown')).toBe(variables.gt); - expect(renderMustacheString('{{amp}}', variables, 'markdown')).toBe(variables.amp); - expect(renderMustacheString('{{nl}}', variables, 'markdown')).toBe(variables.nl); - expect(renderMustacheString('{{dq}}', variables, 'markdown')).toBe(variables.dq); - expect(renderMustacheString('{{bt}}', variables, 'markdown')).toBe('\\' + variables.bt); - expect(renderMustacheString('{{bs}}', variables, 'markdown')).toBe('\\' + variables.bs); - expect(renderMustacheString('{{st}}', variables, 'markdown')).toBe('\\' + variables.st); - expect(renderMustacheString('{{ul}}', variables, 'markdown')).toBe('\\' + variables.ul); - expect(renderMustacheString('{{vl}}', variables, 'markdown')).toBe('\\' + variables.vl); + expect(renderMustacheString(logger, '{{lt}}', variables, 'markdown')).toBe(variables.lt); + expect(renderMustacheString(logger, '{{gt}}', variables, 'markdown')).toBe(variables.gt); + expect(renderMustacheString(logger, '{{amp}}', variables, 'markdown')).toBe(variables.amp); + expect(renderMustacheString(logger, '{{nl}}', variables, 'markdown')).toBe(variables.nl); + expect(renderMustacheString(logger, '{{dq}}', variables, 'markdown')).toBe(variables.dq); + expect(renderMustacheString(logger, '{{bt}}', variables, 'markdown')).toBe( + '\\' + variables.bt + ); + expect(renderMustacheString(logger, '{{bs}}', variables, 'markdown')).toBe( + '\\' + variables.bs + ); + expect(renderMustacheString(logger, '{{st}}', variables, 'markdown')).toBe( + '\\' + variables.st + ); + expect(renderMustacheString(logger, '{{ul}}', variables, 'markdown')).toBe( + '\\' + variables.ul + ); + expect(renderMustacheString(logger, '{{vl}}', variables, 'markdown')).toBe( + '\\' + variables.vl + ); }); it('handles triple escapes', () => { - expect(renderMustacheString('{{{bt}}}', variables, 'markdown')).toBe(variables.bt); - expect(renderMustacheString('{{{bs}}}', variables, 'markdown')).toBe(variables.bs); - expect(renderMustacheString('{{{st}}}', variables, 'markdown')).toBe(variables.st); - expect(renderMustacheString('{{{ul}}}', variables, 'markdown')).toBe(variables.ul); + expect(renderMustacheString(logger, '{{{bt}}}', variables, 'markdown')).toBe(variables.bt); + expect(renderMustacheString(logger, '{{{bs}}}', variables, 'markdown')).toBe(variables.bs); + expect(renderMustacheString(logger, '{{{st}}}', variables, 'markdown')).toBe(variables.st); + expect(renderMustacheString(logger, '{{{ul}}}', variables, 'markdown')).toBe(variables.ul); }); it('handles escape:slack with commonly escaped strings', () => { - expect(renderMustacheString('{{lt}}', variables, 'slack')).toBe('<'); - expect(renderMustacheString('{{gt}}', variables, 'slack')).toBe('>'); - expect(renderMustacheString('{{amp}}', variables, 'slack')).toBe('&'); - expect(renderMustacheString('{{nl}}', variables, 'slack')).toBe(variables.nl); - expect(renderMustacheString('{{dq}}', variables, 'slack')).toBe(variables.dq); - expect(renderMustacheString('{{bt}}', variables, 'slack')).toBe(`'`); - expect(renderMustacheString('{{bs}}', variables, 'slack')).toBe(variables.bs); - expect(renderMustacheString('{{st}}', variables, 'slack')).toBe('`*`'); - expect(renderMustacheString('{{ul}}', variables, 'slack')).toBe('`_`'); + expect(renderMustacheString(logger, '{{lt}}', variables, 'slack')).toBe('<'); + expect(renderMustacheString(logger, '{{gt}}', variables, 'slack')).toBe('>'); + expect(renderMustacheString(logger, '{{amp}}', variables, 'slack')).toBe('&'); + expect(renderMustacheString(logger, '{{nl}}', variables, 'slack')).toBe(variables.nl); + expect(renderMustacheString(logger, '{{dq}}', variables, 'slack')).toBe(variables.dq); + expect(renderMustacheString(logger, '{{bt}}', variables, 'slack')).toBe(`'`); + expect(renderMustacheString(logger, '{{bs}}', variables, 'slack')).toBe(variables.bs); + expect(renderMustacheString(logger, '{{st}}', variables, 'slack')).toBe('`*`'); + expect(renderMustacheString(logger, '{{ul}}', variables, 'slack')).toBe('`_`'); // html escapes not needed when using backtic escaping - expect(renderMustacheString('{{st_lt}}', variables, 'slack')).toBe('`*<`'); - expect(renderMustacheString('{{link}}', variables, 'slack')).toBe('https://te_st.com/'); + expect(renderMustacheString(logger, '{{st_lt}}', variables, 'slack')).toBe('`*<`'); + expect(renderMustacheString(logger, '{{link}}', variables, 'slack')).toBe( + 'https://te_st.com/' + ); }); it('handles escape:json with commonly escaped strings', () => { - expect(renderMustacheString('{{lt}}', variables, 'json')).toBe(variables.lt); - expect(renderMustacheString('{{gt}}', variables, 'json')).toBe(variables.gt); - expect(renderMustacheString('{{amp}}', variables, 'json')).toBe(variables.amp); - expect(renderMustacheString('{{nl}}', variables, 'json')).toBe('\\n'); - expect(renderMustacheString('{{dq}}', variables, 'json')).toBe('\\"'); - expect(renderMustacheString('{{bt}}', variables, 'json')).toBe(variables.bt); - expect(renderMustacheString('{{bs}}', variables, 'json')).toBe('\\\\'); - expect(renderMustacheString('{{st}}', variables, 'json')).toBe(variables.st); - expect(renderMustacheString('{{ul}}', variables, 'json')).toBe(variables.ul); + expect(renderMustacheString(logger, '{{lt}}', variables, 'json')).toBe(variables.lt); + expect(renderMustacheString(logger, '{{gt}}', variables, 'json')).toBe(variables.gt); + expect(renderMustacheString(logger, '{{amp}}', variables, 'json')).toBe(variables.amp); + expect(renderMustacheString(logger, '{{nl}}', variables, 'json')).toBe('\\n'); + expect(renderMustacheString(logger, '{{dq}}', variables, 'json')).toBe('\\"'); + expect(renderMustacheString(logger, '{{bt}}', variables, 'json')).toBe(variables.bt); + expect(renderMustacheString(logger, '{{bs}}', variables, 'json')).toBe('\\\\'); + expect(renderMustacheString(logger, '{{st}}', variables, 'json')).toBe(variables.st); + expect(renderMustacheString(logger, '{{ul}}', variables, 'json')).toBe(variables.ul); }); it('handles errors', () => { - expect(renderMustacheString('{{a}', variables, 'none')).toMatchInlineSnapshot( + expect(renderMustacheString(logger, '{{a}', variables, 'none')).toMatchInlineSnapshot( `"error rendering mustache template \\"{{a}\\": Unclosed tag at 4"` ); }); @@ -285,7 +312,7 @@ describe('mustache_renderer', () => { describe('renderMustacheObject()', () => { it('handles deep objects', () => { - expect(renderMustacheObject(object, variables)).toMatchInlineSnapshot(` + expect(renderMustacheObject(logger, object, variables)).toMatchInlineSnapshot(` Object { "list": Array [ "1", @@ -311,12 +338,12 @@ describe('mustache_renderer', () => { }); it('handles primitive objects', () => { - expect(renderMustacheObject(undefined, variables)).toMatchInlineSnapshot(`undefined`); - expect(renderMustacheObject(null, variables)).toMatchInlineSnapshot(`null`); - expect(renderMustacheObject(0, variables)).toMatchInlineSnapshot(`0`); - expect(renderMustacheObject(true, variables)).toMatchInlineSnapshot(`true`); - expect(renderMustacheObject('{{a}}', variables)).toMatchInlineSnapshot(`"1"`); - expect(renderMustacheObject(['{{a}}'], variables)).toMatchInlineSnapshot(` + expect(renderMustacheObject(logger, undefined, variables)).toMatchInlineSnapshot(`undefined`); + expect(renderMustacheObject(logger, null, variables)).toMatchInlineSnapshot(`null`); + expect(renderMustacheObject(logger, 0, variables)).toMatchInlineSnapshot(`0`); + expect(renderMustacheObject(logger, true, variables)).toMatchInlineSnapshot(`true`); + expect(renderMustacheObject(logger, '{{a}}', variables)).toMatchInlineSnapshot(`"1"`); + expect(renderMustacheObject(logger, ['{{a}}'], variables)).toMatchInlineSnapshot(` Array [ "1", ] @@ -324,7 +351,7 @@ describe('mustache_renderer', () => { }); it('handles errors', () => { - expect(renderMustacheObject({ a: '{{a}' }, variables)).toMatchInlineSnapshot(` + expect(renderMustacheObject(logger, { a: '{{a}' }, variables)).toMatchInlineSnapshot(` Object { "a": "error rendering mustache template \\"{{a}\\": Unclosed tag at 4", } @@ -338,7 +365,7 @@ describe('mustache_renderer', () => { b: { c: 2, d: [3, 4] }, e: [5, { f: 6, g: 7 }], }; - expect(renderMustacheObject({ x: '{{a}} - {{b}} -- {{e}} ' }, deepVariables)) + expect(renderMustacheObject(logger, { x: '{{a}} - {{b}} -- {{e}} ' }, deepVariables)) .toMatchInlineSnapshot(` Object { "x": "1 - {\\"c\\":2,\\"d\\":[3,4]} -- 5,{\\"f\\":6,\\"g\\":7} ", @@ -346,10 +373,12 @@ describe('mustache_renderer', () => { `); const expected = '1 - {"c":2,"d":[3,4]} -- 5,{"f":6,"g":7}'; - expect(renderMustacheString('{{a}} - {{b}} -- {{e}}', deepVariables, 'none')).toEqual(expected); + expect(renderMustacheString(logger, '{{a}} - {{b}} -- {{e}}', deepVariables, 'none')).toEqual( + expected + ); - expect(renderMustacheString('{{e}}', deepVariables, 'none')).toEqual('5,{"f":6,"g":7}'); - expect(renderMustacheString('{{e.asJSON}}', deepVariables, 'none')).toEqual( + expect(renderMustacheString(logger, '{{e}}', deepVariables, 'none')).toEqual('5,{"f":6,"g":7}'); + expect(renderMustacheString(logger, '{{e.asJSON}}', deepVariables, 'none')).toEqual( '[5,{"f":6,"g":7}]' ); }); @@ -395,6 +424,7 @@ describe('mustache_renderer', () => { expect( renderMustacheObject( + logger, { x: '{{context.0._source.kibana.alert.rule.category}} - {{context.0._score.test}} - {{context.0._source.kibana.alert.time_range.gte}}', }, @@ -408,6 +438,7 @@ describe('mustache_renderer', () => { expect( renderMustacheString( + logger, '{{context.0._source.kibana.alert.rule.category}} - {{context.0._score.test}} - {{context.0._source.kibana.alert.time_range.gte}}', dotVariables, 'none' @@ -416,12 +447,13 @@ describe('mustache_renderer', () => { }); it('should replace single value with the object', () => { - expect(renderMustacheObject({ x: '{{a}}' }, { a: 1, 'a.b': 2 })).toMatchInlineSnapshot(` + expect(renderMustacheObject(logger, { x: '{{a}}' }, { a: 1, 'a.b': 2 })) + .toMatchInlineSnapshot(` Object { "x": "{\\"b\\":2}", } `); - expect(renderMustacheString('{{a}}', { a: 1, 'a.b': 2 }, 'none')).toEqual('{"b":2}'); + expect(renderMustacheString(logger, '{{a}}', { a: 1, 'a.b': 2 }, 'none')).toEqual('{"b":2}'); }); }); }); diff --git a/x-pack/plugins/actions/server/lib/mustache_renderer.ts b/x-pack/plugins/actions/server/lib/mustache_renderer.ts index c478d7e9ea1c3..bd35e499fb426 100644 --- a/x-pack/plugins/actions/server/lib/mustache_renderer.ts +++ b/x-pack/plugins/actions/server/lib/mustache_renderer.ts @@ -7,6 +7,7 @@ import Mustache from 'mustache'; import { isString, isPlainObject, cloneDeepWith, merge } from 'lodash'; +import { Logger } from '@kbn/core/server'; import { getMustacheLambdas } from './mustache_lambdas'; export type Escape = 'markdown' | 'slack' | 'json' | 'none'; @@ -25,9 +26,14 @@ export function renderMustacheStringNoEscape(string: string, variables: Variable } // return a rendered mustache template given the specified variables and escape -export function renderMustacheString(string: string, variables: Variables, escape: Escape): string { +export function renderMustacheString( + logger: Logger, + string: string, + variables: Variables, + escape: Escape +): string { const augmentedVariables = augmentObjectVariables(variables); - const lambdas = getMustacheLambdas(); + const lambdas = getMustacheLambdas(logger); const previousMustacheEscape = Mustache.escape; Mustache.escape = getEscape(escape); @@ -43,13 +49,17 @@ export function renderMustacheString(string: string, variables: Variables, escap } // return a cloned object with all strings rendered as mustache templates -export function renderMustacheObject(params: Params, variables: Variables): Params { +export function renderMustacheObject( + logger: Logger, + params: Params, + variables: Variables +): Params { const augmentedVariables = augmentObjectVariables(variables); const result = cloneDeepWith(params, (value: unknown) => { if (!isString(value)) return; // since we're rendering a JS object, no escaping needed - return renderMustacheString(value, augmentedVariables, 'none'); + return renderMustacheString(logger, value, augmentedVariables, 'none'); }); // The return type signature for `cloneDeep()` ends up taking the return diff --git a/x-pack/plugins/actions/server/lib/number_formatter.test.ts b/x-pack/plugins/actions/server/lib/number_formatter.test.ts index e054b5a7e6ebe..c8ab55119a343 100644 --- a/x-pack/plugins/actions/server/lib/number_formatter.test.ts +++ b/x-pack/plugins/actions/server/lib/number_formatter.test.ts @@ -5,52 +5,76 @@ * 2.0. */ +import { loggingSystemMock } from '@kbn/core/server/mocks'; import { formatNumber } from './number_formatter'; +const logger = loggingSystemMock.create().get(); + describe('formatNumber()', () => { + beforeEach(() => { + jest.restoreAllMocks(); + }); + it('using defaults is successful', () => { - expect(formatNumber('1;;')).toMatchInlineSnapshot(`"1"`); + expect(formatNumber(logger, '1;;')).toMatchInlineSnapshot(`"1"`); }); it('error cases handled', () => { - expect(formatNumber('1')).toMatchInlineSnapshot(`"invalid format, missing semicolons: '1'"`); - expect(formatNumber('nope;;')).toMatchInlineSnapshot(`"invalid number: 'nope'"`); - expect(formatNumber('1;; nah')).toMatchInlineSnapshot( - `"invalid options: missing colon in option: 'nah'"` + expect(formatNumber(logger, '1')).toEqual(`invalid format, missing semicolons: '1'`); + expect(logger.warn).toHaveBeenCalledWith( + `mustache render error: invalid format, missing semicolons: '1'` + ); + + expect(formatNumber(logger, 'nope;;')).toEqual(`invalid number: 'nope'`); + expect(logger.warn).toHaveBeenCalledWith(`mustache render error: invalid number: 'nope'`); + + expect(formatNumber(logger, '1;; nah')).toEqual( + `invalid options: missing colon in option: 'nah'` ); - expect(formatNumber('1;; minimumIntegerDigits: N.O.')).toMatchInlineSnapshot( - `"error formatting number: minimumIntegerDigits value is out of range."` + expect(logger.warn).toHaveBeenCalledWith( + `mustache render error: invalid options: missing colon in option: 'nah'` + ); + + expect(formatNumber(logger, '1;; minimumIntegerDigits: N.O.')).toEqual( + 'error formatting number: minimumIntegerDigits value is out of range.' ); - expect(formatNumber('1;; compactDisplay: uhuh')).toMatchInlineSnapshot( - `"error formatting number: Value uhuh out of range for Intl.NumberFormat options property compactDisplay"` + expect(logger.warn).toHaveBeenCalledWith( + `mustache render error: error formatting number: minimumIntegerDigits value is out of range.` + ); + + expect(formatNumber(logger, '1;; compactDisplay: uhuh')).toEqual( + 'error formatting number: Value uhuh out of range for Intl.NumberFormat options property compactDisplay' + ); + expect(logger.warn).toHaveBeenCalledWith( + `mustache render error: error formatting number: Value uhuh out of range for Intl.NumberFormat options property compactDisplay` ); }); it('using locales is successful', () => { - expect(formatNumber('1000; de-DE;')).toMatchInlineSnapshot(`"1.000"`); + expect(formatNumber(logger, '1000; de-DE;')).toMatchInlineSnapshot(`"1.000"`); }); it('option compactDisplay is successful', () => { expect( - formatNumber(' 1000;; notation: compact, compactDisplay: short, ') + formatNumber(logger, ' 1000;; notation: compact, compactDisplay: short, ') ).toMatchInlineSnapshot(`"1K"`); }); it('option currency is successful', () => { - expect(formatNumber('1000;; currency: EUR, style: currency')).toMatchInlineSnapshot( + expect(formatNumber(logger, '1000;; currency: EUR, style: currency')).toMatchInlineSnapshot( `"€1,000.00"` ); }); it('option currencyDisplay is successful', () => { expect( - formatNumber('1000;; currency: EUR, style: currency, currencyDisplay: name') + formatNumber(logger, '1000;; currency: EUR, style: currency, currencyDisplay: name') ).toMatchInlineSnapshot(`"1,000.00 euros"`); }); it('option currencySign is successful', () => { expect( - formatNumber('-1;; currency: EUR, style: currency, currencySign: accounting') + formatNumber(logger, '-1;; currency: EUR, style: currency, currencySign: accounting') ).toMatchInlineSnapshot(`"(€1.00)"`); }); @@ -60,34 +84,36 @@ describe('formatNumber()', () => { it.skip('option localeMatcher is successful', () => {}); it('option notation is successful', () => { - expect(formatNumber('1000;; notation: engineering')).toMatchInlineSnapshot(`"1E3"`); + expect(formatNumber(logger, '1000;; notation: engineering')).toMatchInlineSnapshot(`"1E3"`); }); it('option numberingSystem is successful', () => { - expect(formatNumber('1;; numberingSystem: fullwide')).toMatchInlineSnapshot(`"1"`); + expect(formatNumber(logger, '1;; numberingSystem: fullwide')).toMatchInlineSnapshot(`"1"`); }); it('option signDisplay is successful', () => { - expect(formatNumber('1;; signDisplay: always')).toMatchInlineSnapshot(`"+1"`); + expect(formatNumber(logger, '1;; signDisplay: always')).toMatchInlineSnapshot(`"+1"`); }); it('option style is successful', () => { - expect(formatNumber('1;; style: percent')).toMatchInlineSnapshot(`"100%"`); + expect(formatNumber(logger, '1;; style: percent')).toMatchInlineSnapshot(`"100%"`); }); it('option unit is successful', () => { - expect(formatNumber('1;; style: unit, unit: acre-per-liter')).toMatchInlineSnapshot(`"1 ac/L"`); + expect(formatNumber(logger, '1;; style: unit, unit: acre-per-liter')).toMatchInlineSnapshot( + `"1 ac/L"` + ); }); it('option unitDisplay is successful', () => { expect( - formatNumber('1;; style: unit, unit: petabyte, unitDisplay: narrow') + formatNumber(logger, '1;; style: unit, unit: petabyte, unitDisplay: narrow') ).toMatchInlineSnapshot(`"1PB"`); }); it('option useGrouping is successful', () => { - expect(formatNumber('1000;; useGrouping: true ')).toMatchInlineSnapshot(`"1,000"`); - expect(formatNumber('1000;; useGrouping: false')).toMatchInlineSnapshot(`"1000"`); + expect(formatNumber(logger, '1000;; useGrouping: true ')).toMatchInlineSnapshot(`"1,000"`); + expect(formatNumber(logger, '1000;; useGrouping: false')).toMatchInlineSnapshot(`"1000"`); }); // not yet supported in node.js @@ -103,22 +129,28 @@ describe('formatNumber()', () => { it.skip('option trailingZeroDisplay is successful', () => {}); it('option minimumIntegerDigits is successful', () => { - expect(formatNumber('1;; minimumIntegerDigits: 7')).toMatchInlineSnapshot(`"0,000,001"`); + expect(formatNumber(logger, '1;; minimumIntegerDigits: 7')).toMatchInlineSnapshot( + `"0,000,001"` + ); }); it('option minimumFractionDigits is successful', () => { - expect(formatNumber('1;; minimumFractionDigits: 3')).toMatchInlineSnapshot(`"1.000"`); + expect(formatNumber(logger, '1;; minimumFractionDigits: 3')).toMatchInlineSnapshot(`"1.000"`); }); it('option maximumFractionDigits is successful', () => { - expect(formatNumber('1.234;; maximumFractionDigits: 2')).toMatchInlineSnapshot(`"1.23"`); + expect(formatNumber(logger, '1.234;; maximumFractionDigits: 2')).toMatchInlineSnapshot( + `"1.23"` + ); }); it('option minimumSignificantDigits is successful', () => { - expect(formatNumber('1;; minimumSignificantDigits: 3')).toMatchInlineSnapshot(`"1.00"`); + expect(formatNumber(logger, '1;; minimumSignificantDigits: 3')).toMatchInlineSnapshot(`"1.00"`); }); it('option maximumSignificantDigits is successful', () => { - expect(formatNumber('123456;; maximumSignificantDigits: 4')).toMatchInlineSnapshot(`"123,500"`); + expect(formatNumber(logger, '123456;; maximumSignificantDigits: 4')).toMatchInlineSnapshot( + `"123,500"` + ); }); }); diff --git a/x-pack/plugins/actions/server/lib/number_formatter.ts b/x-pack/plugins/actions/server/lib/number_formatter.ts index b8a13efa39828..f1a2b3367d52f 100644 --- a/x-pack/plugins/actions/server/lib/number_formatter.ts +++ b/x-pack/plugins/actions/server/lib/number_formatter.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { Logger } from '@kbn/core/server'; const DEFAULT_LOCALES = ['en-US']; @@ -30,24 +31,28 @@ const DEFAULT_LOCALES = ['en-US']; * @param numberAndFormat string containing a number and formatting options * @returns number formatted according to the options */ -export function formatNumber(numberLocalesOptions: string): string { +export function formatNumber(logger: Logger, numberLocalesOptions: string): string { const [numString, localesString, optionsString] = splitNumberLocalesOptions(numberLocalesOptions); if (localesString === undefined || optionsString === undefined) { - return `invalid format, missing semicolons: '${numberLocalesOptions}'`; + return logAndReturnErr(logger, `invalid format, missing semicolons: '${numberLocalesOptions}'`); } const num = parseFloat(numString); - if (isNaN(num)) return `invalid number: '${numString}'`; + if (isNaN(num)) { + return logAndReturnErr(logger, `invalid number: '${numString}'`); + } const locales = getLocales(localesString); const [options, optionsError] = getOptions(optionsString); - if (optionsError) return `invalid options: ${optionsError}`; + if (optionsError) { + return logAndReturnErr(logger, `invalid options: ${optionsError}`); + } try { return new Intl.NumberFormat(locales, options).format(num); } catch (err) { - return `error formatting number: ${err.message}`; + return logAndReturnErr(logger, `error formatting number: ${err.message}`); } } @@ -110,3 +115,8 @@ function splitNumberLocalesOptions( const [num, locales, options] = numberLocalesOptions.split(';', 3); return [num.trim(), locales?.trim(), options?.trim()]; } + +function logAndReturnErr(logger: Logger, errMessage: string): string { + logger.warn(`mustache render error: ${errMessage}`); + return errMessage; +} diff --git a/x-pack/plugins/actions/server/mocks.ts b/x-pack/plugins/actions/server/mocks.ts index 70a2cfd9f8e85..7655ad6de945d 100644 --- a/x-pack/plugins/actions/server/mocks.ts +++ b/x-pack/plugins/actions/server/mocks.ts @@ -59,7 +59,14 @@ export function renderActionParameterTemplatesDefault( params: Record, variables: Record ) { - return renderActionParameterTemplates(undefined, actionTypeId, actionId, params, variables); + return renderActionParameterTemplates( + logger, + undefined, + actionTypeId, + actionId, + params, + variables + ); } const createServicesMock = () => { diff --git a/x-pack/plugins/actions/server/plugin.ts b/x-pack/plugins/actions/server/plugin.ts index 60a27eb04e411..6479ed1b1d05a 100644 --- a/x-pack/plugins/actions/server/plugin.ts +++ b/x-pack/plugins/actions/server/plugin.ts @@ -585,7 +585,7 @@ export class ActionsPlugin implements Plugin - renderActionParameterTemplates(actionTypeRegistry, ...args), + renderActionParameterTemplates(this.logger, actionTypeRegistry, ...args), }; } @@ -743,6 +743,7 @@ export class ActionsPlugin implements Plugin( + logger: Logger, actionTypeRegistry: ActionTypeRegistry | undefined, actionTypeId: string, actionId: string, @@ -751,8 +752,8 @@ export function renderActionParameterTemplates { const actionId = 'action-id'; const { renderParameterTemplates } = actionTypeRegistry.register.mock.calls[0][0]; - const rendered = renderParameterTemplates?.(params, variables, actionId); + const rendered = renderParameterTemplates?.(logger, params, variables, actionId); - expect(mockRenderParameterTemplates).toHaveBeenCalledWith(params, variables, actionId); + expect(mockRenderParameterTemplates).toHaveBeenCalledWith(logger, params, variables, actionId); expect(rendered).toBe(renderedVariables); }); }); diff --git a/x-pack/plugins/actions/server/types.ts b/x-pack/plugins/actions/server/types.ts index 0d9cc99ac6186..343d9b3dde4f6 100644 --- a/x-pack/plugins/actions/server/types.ts +++ b/x-pack/plugins/actions/server/types.ts @@ -119,6 +119,7 @@ export interface ActionValidationService { } export type RenderParameterTemplates = ( + logger: Logger, params: Params, variables: Record, actionId?: string diff --git a/x-pack/plugins/stack_connectors/server/connector_types/bedrock/render.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/bedrock/render.test.ts index bdbe792115562..08b421b61a7b8 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/bedrock/render.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/bedrock/render.test.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { loggingSystemMock } from '@kbn/core/server/mocks'; import { renderParameterTemplates } from './render'; import Mustache from 'mustache'; @@ -16,16 +17,20 @@ const params = { }; const variables = { domain: 'm0zepcuuu2' }; +const logger = loggingSystemMock.createLogger(); describe('Bedrock - renderParameterTemplates', () => { + beforeEach(() => { + jest.resetAllMocks(); + }); it('should not render body on test action', () => { const testParams = { subAction: 'test', subActionParams: { body: 'test_json' } }; - const result = renderParameterTemplates(testParams, variables); + const result = renderParameterTemplates(logger, testParams, variables); expect(result).toEqual(testParams); }); it('should rendered body with variables', () => { - const result = renderParameterTemplates(params, variables); + const result = renderParameterTemplates(logger, params, variables); expect(result.subActionParams.body).toEqual( JSON.stringify({ @@ -39,7 +44,7 @@ describe('Bedrock - renderParameterTemplates', () => { jest.spyOn(Mustache, 'render').mockImplementation(() => { throw new Error(errorMessage); }); - const result = renderParameterTemplates(params, variables); + const result = renderParameterTemplates(logger, params, variables); expect(result.subActionParams.body).toEqual( 'error rendering mustache template "{"domain":"{{domain}}"}": test error' ); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/bedrock/render.ts b/x-pack/plugins/stack_connectors/server/connector_types/bedrock/render.ts index 34dd90ff2a862..21fd5290ba311 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/bedrock/render.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/bedrock/render.ts @@ -11,6 +11,7 @@ import { RenderParameterTemplates } from '@kbn/actions-plugin/server/types'; import { SUB_ACTION } from '../../../common/bedrock/constants'; export const renderParameterTemplates: RenderParameterTemplates = ( + logger, params, variables ) => { @@ -20,7 +21,7 @@ export const renderParameterTemplates: RenderParameterTemplates ...params, subActionParams: { ...params.subActionParams, - body: renderMustacheString(params.subActionParams.body as string, variables, 'json'), + body: renderMustacheString(logger, params.subActionParams.body as string, variables, 'json'), }, }; }; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/d3security/render.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/d3security/render.test.ts index afff25ddd9129..8eb1420af4a16 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/d3security/render.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/d3security/render.test.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { loggingSystemMock } from '@kbn/core/server/mocks'; import { renderParameterTemplates } from './render'; import Mustache from 'mustache'; @@ -17,20 +18,25 @@ const params = { }, }; +const logger = loggingSystemMock.createLogger(); const variables = { domain: 'm0zepcuuu2' }; describe('D3 Security - renderParameterTemplates', () => { + beforeEach(() => { + jest.resetAllMocks(); + }); + it('should not render body on test action', () => { const testParams = { subAction: 'test', subActionParams: { ...params.subActionParams, body: 'test_json' }, }; - const result = renderParameterTemplates(testParams, variables); + const result = renderParameterTemplates(logger, testParams, variables); expect(result).toEqual(testParams); }); it('should rendered body with variables', () => { - const result = renderParameterTemplates(params, variables); + const result = renderParameterTemplates(logger, params, variables); expect(result.subActionParams.body).toEqual( JSON.stringify({ @@ -44,7 +50,7 @@ describe('D3 Security - renderParameterTemplates', () => { jest.spyOn(Mustache, 'render').mockImplementation(() => { throw new Error(errorMessage); }); - const result = renderParameterTemplates(params, variables); + const result = renderParameterTemplates(logger, params, variables); expect(result.subActionParams.body).toEqual( 'error rendering mustache template "{"domain":"{{domain}}"}": test error' ); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/d3security/render.ts b/x-pack/plugins/stack_connectors/server/connector_types/d3security/render.ts index c5c6c5ef1daef..bd59118ac6bdf 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/d3security/render.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/d3security/render.ts @@ -11,6 +11,7 @@ import { RenderParameterTemplates } from '@kbn/actions-plugin/server/types'; import { SUB_ACTION } from '../../../common/d3security/constants'; export const renderParameterTemplates: RenderParameterTemplates = ( + logger, params, variables ) => { @@ -20,7 +21,7 @@ export const renderParameterTemplates: RenderParameterTemplates ...params, subActionParams: { ...params.subActionParams, - body: renderMustacheString(params.subActionParams.body as string, variables, 'json'), + body: renderMustacheString(logger, params.subActionParams.body as string, variables, 'json'), }, }; }; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/email/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/email/index.test.ts index 5262577a9a932..fe18cf956c0e4 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/email/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/email/index.test.ts @@ -845,7 +845,11 @@ describe('execute()', () => { const variables = { rogue: '*bold*', }; - const renderedParams = connectorType.renderParameterTemplates!(paramsWithTemplates, variables); + const renderedParams = connectorType.renderParameterTemplates!( + mockedLogger, + paramsWithTemplates, + variables + ); expect(renderedParams.message).toBe('\\*bold\\*'); expect(renderedParams).toMatchInlineSnapshot(` @@ -887,7 +891,11 @@ describe('execute()', () => { const variables = { rogue: '*bold*', }; - const renderedParams = connectorType.renderParameterTemplates!(paramsWithTemplates, variables); + const renderedParams = connectorType.renderParameterTemplates!( + mockedLogger, + paramsWithTemplates, + variables + ); // Yes, this is tested in the snapshot below, but it's double-escaped there, // so easier to see here that the escaping is correct. expect(renderedParams.message).toBe('\\*bold\\*'); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/email/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/email/index.ts index 30d635cb0ced7..f1e9ab23d9793 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/email/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/email/index.ts @@ -8,6 +8,7 @@ import { curry } from 'lodash'; import { i18n } from '@kbn/i18n'; import { schema, TypeOf } from '@kbn/config-schema'; +import { Logger } from '@kbn/core/server'; import nodemailerGetService from 'nodemailer/lib/well-known'; import SMTPConnection from 'nodemailer/lib/smtp-connection'; import type { @@ -250,14 +251,15 @@ export function getConnectorType(params: GetConnectorTypeParams): EmailConnector } function renderParameterTemplates( + logger: Logger, params: ActionParamsType, variables: Record ): ActionParamsType { return { // most of the params need no escaping - ...renderMustacheObject(params, variables), + ...renderMustacheObject(logger, params, variables), // message however, needs to escaped as markdown - message: renderMustacheString(params.message, variables, 'markdown'), + message: renderMustacheString(logger, params.message, variables, 'markdown'), }; } diff --git a/x-pack/plugins/stack_connectors/server/connector_types/es_index/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/es_index/index.test.ts index 900f7cd334241..2b3fab30432fa 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/es_index/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/es_index/index.test.ts @@ -371,6 +371,7 @@ describe('execute()', () => { who: 'world', }; const renderedParams = connectorType.renderParameterTemplates!( + mockedLogger, paramsWithTemplates, variables, 'action-type-id' @@ -397,6 +398,7 @@ describe('execute()', () => { who: 'world', }; const renderedParams = connectorType.renderParameterTemplates!( + mockedLogger, paramsWithTemplates, variables, 'action-type-id' @@ -446,6 +448,7 @@ describe('execute()', () => { }, }; const renderedParams = connectorType.renderParameterTemplates!( + mockedLogger, paramsWithTemplates, variables, AlertHistoryEsIndexConnectorId @@ -526,6 +529,7 @@ describe('execute()', () => { }, }; const renderedParams = connectorType.renderParameterTemplates!( + mockedLogger, paramsWithTemplates, variables, AlertHistoryEsIndexConnectorId @@ -583,6 +587,7 @@ describe('execute()', () => { expect(() => connectorType.renderParameterTemplates!( + mockedLogger, paramsWithTemplates, variables, AlertHistoryEsIndexConnectorId diff --git a/x-pack/plugins/stack_connectors/server/connector_types/es_index/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/es_index/index.ts index 5057fdb5d8312..915a66568c20e 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/es_index/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/es_index/index.ts @@ -160,11 +160,16 @@ async function executor( } function renderParameterTemplates( + logger: Logger, params: ActionParamsType, variables: Record, actionId?: string ): ActionParamsType { - const { documents, indexOverride } = renderMustacheObject(params, variables); + const { documents, indexOverride } = renderMustacheObject( + logger, + params, + variables + ); if (actionId === AlertHistoryEsIndexConnectorId) { const alertHistoryDoc = buildAlertHistoryDocument(variables); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/openai/render.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/openai/render.test.ts index b9fff0362913c..e76b8331c041b 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/openai/render.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/openai/render.test.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { loggingSystemMock } from '@kbn/core/server/mocks'; import { renderParameterTemplates } from './render'; import Mustache from 'mustache'; @@ -16,16 +17,17 @@ const params = { }; const variables = { domain: 'm0zepcuuu2' }; +const logger = loggingSystemMock.createLogger(); describe('OpenAI - renderParameterTemplates', () => { it('should not render body on test action', () => { const testParams = { subAction: 'test', subActionParams: { body: 'test_json' } }; - const result = renderParameterTemplates(testParams, variables); + const result = renderParameterTemplates(logger, testParams, variables); expect(result).toEqual(testParams); }); it('should rendered body with variables', () => { - const result = renderParameterTemplates(params, variables); + const result = renderParameterTemplates(logger, params, variables); expect(result.subActionParams.body).toEqual( JSON.stringify({ @@ -39,7 +41,7 @@ describe('OpenAI - renderParameterTemplates', () => { jest.spyOn(Mustache, 'render').mockImplementation(() => { throw new Error(errorMessage); }); - const result = renderParameterTemplates(params, variables); + const result = renderParameterTemplates(logger, params, variables); expect(result.subActionParams.body).toEqual( 'error rendering mustache template "{"domain":"{{domain}}"}": test error' ); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/openai/render.ts b/x-pack/plugins/stack_connectors/server/connector_types/openai/render.ts index bb2f97d7ca0db..da79c1d305d1c 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/openai/render.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/openai/render.ts @@ -11,6 +11,7 @@ import { RenderParameterTemplates } from '@kbn/actions-plugin/server/types'; import { SUB_ACTION } from '../../../common/openai/constants'; export const renderParameterTemplates: RenderParameterTemplates = ( + logger, params, variables ) => { @@ -20,7 +21,7 @@ export const renderParameterTemplates: RenderParameterTemplates ...params, subActionParams: { ...params.subActionParams, - body: renderMustacheString(params.subActionParams.body as string, variables, 'json'), + body: renderMustacheString(logger, params.subActionParams.body as string, variables, 'json'), }, }; }; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/render_template_variables.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/render_template_variables.test.ts index 69372cb19824c..530e4533592e5 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/render_template_variables.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/render_template_variables.test.ts @@ -5,10 +5,12 @@ * 2.0. */ +import { loggingSystemMock } from '@kbn/core/server/mocks'; import { OpsgenieSubActions } from '../../../common'; import { renderParameterTemplates } from './render_template_variables'; const ruleTagsTemplate = '{{rule.tags}}'; +const logger = loggingSystemMock.createLogger(); describe('renderParameterTemplates', () => { const variables = { @@ -20,6 +22,7 @@ describe('renderParameterTemplates', () => { it('renders the rule.tags as a single string if subAction is not set to CreateAlert', () => { expect( renderParameterTemplates( + logger, { subAction: '', subActionParams: { @@ -43,6 +46,7 @@ describe('renderParameterTemplates', () => { it('does not transform the tags if the rule.tags string is not found', () => { expect( renderParameterTemplates( + logger, { subAction: OpsgenieSubActions.CreateAlert, subActionParams: { @@ -66,6 +70,7 @@ describe('renderParameterTemplates', () => { it('transforms the rule.tags to an empty array when the field does not exist in the variable', () => { expect( renderParameterTemplates( + logger, { subAction: OpsgenieSubActions.CreateAlert, subActionParams: { @@ -87,6 +92,7 @@ describe('renderParameterTemplates', () => { it('does not transform the tags when the field does not exist in the params', () => { expect( renderParameterTemplates( + logger, { subAction: OpsgenieSubActions.CreateAlert, subActionParams: {}, @@ -104,6 +110,7 @@ describe('renderParameterTemplates', () => { it('replaces the rule.tags template with an array of strings', () => { expect( renderParameterTemplates( + logger, { subAction: OpsgenieSubActions.CreateAlert, subActionParams: { @@ -132,6 +139,7 @@ describe('renderParameterTemplates', () => { it('replaces the rule.tags template with only a single instance of the rule.tags even when the mustache template exists multiple times', () => { expect( renderParameterTemplates( + logger, { subAction: OpsgenieSubActions.CreateAlert, subActionParams: { @@ -161,6 +169,7 @@ describe('renderParameterTemplates', () => { it('replaces the rule.tags template with empty array and preserves the other values already in the array', () => { expect( renderParameterTemplates( + logger, { subAction: OpsgenieSubActions.CreateAlert, subActionParams: { @@ -186,6 +195,7 @@ describe('renderParameterTemplates', () => { it('replaces the rule.tags template with variable value when the path is a full string', () => { expect( renderParameterTemplates( + logger, { subAction: OpsgenieSubActions.CreateAlert, subActionParams: { @@ -212,6 +222,7 @@ describe('renderParameterTemplates', () => { it('replaces the rule.tags template and other templates', () => { expect( renderParameterTemplates( + logger, { subAction: OpsgenieSubActions.CreateAlert, subActionParams: { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/render_template_variables.ts b/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/render_template_variables.ts index 14670fe162ca6..42d4c42134efa 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/render_template_variables.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/render_template_variables.ts @@ -15,17 +15,18 @@ import { OpsgenieSubActions } from '../../../common'; import { CreateAlertSubActionParams } from './types'; export const renderParameterTemplates: RenderParameterTemplates = ( + logger, params, variables ) => { if (!isCreateAlertSubAction(params) || !params.subActionParams.tags) { - return renderMustacheObject(params, variables); + return renderMustacheObject(logger, params, variables); } const foundRuleTagsTemplate = params.subActionParams.tags.includes(RULE_TAGS_TEMPLATE); if (!foundRuleTagsTemplate) { - return renderMustacheObject(params, variables); + return renderMustacheObject(logger, params, variables); } const paramsCopy = cloneDeep(params); @@ -39,7 +40,7 @@ export const renderParameterTemplates: RenderParameterTemplates ...getRuleTags(variables), ]); - return renderMustacheObject(paramsCopy, variables); + return renderMustacheObject(logger, paramsCopy, variables); }; type CreateAlertParams = CreateAlertSubActionParams & Record; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/render.ts b/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/render.ts index 21f3bebdd8274..651fae8978141 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/render.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/render.ts @@ -9,6 +9,7 @@ import { map } from 'lodash'; import { set } from '@kbn/safer-lodash-set/fp'; import type { EcsSecurityExtension as Ecs } from '@kbn/securitysolution-ecs'; import { ExecutorParams } from '@kbn/actions-plugin/server/sub_action_framework/types'; +import { Logger } from '@kbn/core/server'; import { SUB_ACTION } from '../../../common/sentinelone/constants'; interface Context { @@ -16,6 +17,7 @@ interface Context { } export const renderParameterTemplates = ( + logger: Logger, params: ExecutorParams, variables: Record ) => { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/slack/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/slack/index.test.ts index f96cc176e467e..3f6203b725913 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/slack/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/slack/index.test.ts @@ -344,7 +344,11 @@ describe('execute()', () => { const variables = { rogue: '*bold*', }; - const params = connectorType.renderParameterTemplates!(paramsWithTemplates, variables); + const params = connectorType.renderParameterTemplates!( + mockedLogger, + paramsWithTemplates, + variables + ); expect(params.message).toBe('`*bold*`'); }); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/slack/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/slack/index.ts index d80a242bbc69b..ba1cf22b3ef98 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/slack/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/slack/index.ts @@ -9,6 +9,7 @@ import { URL } from 'url'; import HttpProxyAgent from 'http-proxy-agent'; import { HttpsProxyAgent } from 'https-proxy-agent'; import { i18n } from '@kbn/i18n'; +import { Logger } from '@kbn/core/server'; import { schema, TypeOf } from '@kbn/config-schema'; import { IncomingWebhook, IncomingWebhookResult } from '@slack/webhook'; import { pipe } from 'fp-ts/lib/pipeable'; @@ -94,11 +95,12 @@ export function getConnectorType({ } function renderParameterTemplates( + logger: Logger, params: ActionParamsType, variables: Record ): ActionParamsType { return { - message: renderMustacheString(params.message, variables, 'slack'), + message: renderMustacheString(logger, params.message, variables, 'slack'), }; } diff --git a/x-pack/plugins/stack_connectors/server/connector_types/slack_api/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/slack_api/index.test.ts index 9821680741eee..59030a71aaa05 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/slack_api/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/slack_api/index.test.ts @@ -240,6 +240,7 @@ describe('execute', () => { }; const variables = { injected: '*foo*' }; const params = connectorType.renderParameterTemplates!( + mockedLogger, paramsWithTemplates, variables ) as PostMessageParams; @@ -266,6 +267,7 @@ describe('execute', () => { }; const variables = { name: '"Dwight"' }; const params = connectorType.renderParameterTemplates!( + mockedLogger, paramsWithTemplates, variables ) as PostMessageParams; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/slack_api/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/slack_api/index.ts index 5b8ded2ebbf1f..62e377dd623e1 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/slack_api/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/slack_api/index.ts @@ -10,6 +10,7 @@ import { AlertingConnectorFeatureId, SecurityConnectorFeatureId, } from '@kbn/actions-plugin/common/types'; +import { Logger } from '@kbn/core/server'; import { renderMustacheString } from '@kbn/actions-plugin/server/lib/mustache_renderer'; import type { ValidatorServices } from '@kbn/actions-plugin/server/types'; import { i18n } from '@kbn/i18n'; @@ -69,13 +70,17 @@ const validateSlackUrl = (secretsObject: SlackApiSecrets, validatorServices: Val } }; -const renderParameterTemplates = (params: SlackApiParams, variables: Record) => { +const renderParameterTemplates = ( + logger: Logger, + params: SlackApiParams, + variables: Record +) => { if (params.subAction === 'postMessage') { return { subAction: params.subAction, subActionParams: { ...params.subActionParams, - text: renderMustacheString(params.subActionParams.text, variables, 'slack'), + text: renderMustacheString(logger, params.subActionParams.text, variables, 'slack'), }, }; } else if (params.subAction === 'postBlockkit') { @@ -83,7 +88,7 @@ const renderParameterTemplates = (params: SlackApiParams, variables: Record { describe('renderParameterTemplates', () => { it('should not render body on test action', () => { const testParams = { subAction: 'test', subActionParams: { body: 'test_json' } }; - const result = renderParameterTemplates(testParams, variables); + const result = renderParameterTemplates(logger, testParams, variables); expect(result).toEqual(testParams); }); it('should rendered body from variables with cleaned alerts on run action', () => { - const result = renderParameterTemplates(params, variables); + const result = renderParameterTemplates(logger, params, variables); expect(result.subActionParams.body).toEqual( JSON.stringify({ @@ -79,14 +81,14 @@ describe('Tines body render', () => { it('should rendered body from variables on run action without context.alerts', () => { const variablesWithoutAlerts = set('context.alerts', undefined, variables); - const result = renderParameterTemplates(params, variablesWithoutAlerts); + const result = renderParameterTemplates(logger, params, variablesWithoutAlerts); expect(result.subActionParams.body).toEqual(JSON.stringify(variablesWithoutAlerts)); }); it('should rendered body from variables on run action without context', () => { const variablesWithoutContext = set('context', undefined, variables); - const result = renderParameterTemplates(params, variablesWithoutContext); + const result = renderParameterTemplates(logger, params, variablesWithoutContext); expect(result.subActionParams.body).toEqual(JSON.stringify(variablesWithoutContext)); }); @@ -96,7 +98,7 @@ describe('Tines body render', () => { jest.spyOn(JSON, 'stringify').mockImplementationOnce(() => { throw new Error(errorMessage); }); - const result = renderParameterTemplates(params, variables); + const result = renderParameterTemplates(logger, params, variables); expect(result.subActionParams.body).toEqual( JSON.stringify({ error: { message: errorMessage } }) ); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/tines/render.ts b/x-pack/plugins/stack_connectors/server/connector_types/tines/render.ts index ca3fdf7de5b6c..360b430927f6a 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/tines/render.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/tines/render.ts @@ -15,6 +15,7 @@ interface Context { } export const renderParameterTemplates: RenderParameterTemplates = ( + logger, params, variables ) => { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/torq/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/torq/index.test.ts index e970e1f678bde..4bf60d10eb789 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/torq/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/torq/index.test.ts @@ -227,7 +227,11 @@ describe('execute Torq action', () => { scalar: '1970', scalar_with_json_chars: 'noinjection", "here": "', }; - const params = actionType.renderParameterTemplates!(paramsWithTemplates, variables); + const params = actionType.renderParameterTemplates!( + mockedLogger, + paramsWithTemplates, + variables + ); expect(params.body).toBe( `{"x": ${templatedObject}, "y": "${variables.scalar}", "z": "${variables.scalar_with_json_chars}"}` ); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/torq/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/torq/index.ts index 9d805291cf92c..b58ab1f8a1aa7 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/torq/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/torq/index.ts @@ -88,11 +88,12 @@ export function getActionType(): TorqActionType { } function renderParameterTemplates( + logger: Logger, params: ActionParamsType, variables: Record ): ActionParamsType { if (!params.body) return params; - return renderMustacheObject(params, variables); + return renderMustacheObject(logger, params, variables); } function validateActionTypeConfig( diff --git a/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.test.ts index 73b16a3748fd2..bd24314fa79b7 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.test.ts @@ -676,7 +676,11 @@ describe('execute()', () => { const variables = { rogue, }; - const params = connectorType.renderParameterTemplates!(paramsWithTemplates, variables); + const params = connectorType.renderParameterTemplates!( + mockedLogger, + paramsWithTemplates, + variables + ); // eslint-disable-next-line @typescript-eslint/no-explicit-any let paramsObject: any; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.ts index 2b17dcac9b913..62c0d6210b3d3 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.ts @@ -9,6 +9,7 @@ import { i18n } from '@kbn/i18n'; import { isString } from 'lodash'; import axios, { AxiosError, AxiosResponse } from 'axios'; import { schema, TypeOf } from '@kbn/config-schema'; +import { Logger } from '@kbn/core/server'; import { pipe } from 'fp-ts/lib/pipeable'; import { map, getOrElse } from 'fp-ts/lib/Option'; import type { @@ -139,12 +140,13 @@ export function getConnectorType(): WebhookConnectorType { } function renderParameterTemplates( + logger: Logger, params: ActionParamsType, variables: Record ): ActionParamsType { if (!params.body) return params; return { - body: renderMustacheString(params.body, variables, 'json'), + body: renderMustacheString(logger, params.body, variables, 'json'), }; }