From 161dd0a9a31e5ccf909241dcfd85f6b75e9c8842 Mon Sep 17 00:00:00 2001 From: Paulo Silva Date: Tue, 8 Oct 2024 11:56:08 -0700 Subject: [PATCH] [Fleet] add escapeMultilineString Handlebar helper (#195159) ## Summary Adding a handlebar helper to escape multiline strings. It has the same function as `escapeStringHelper`, but does not wrap strings in single quotes, allowing concatenation of escaped variables in the `hbs` template such as this example: ```hbs audit_rules: "{{escape_multiline_string audit_rules}} {{escape_multiline_string " # Session data audit rules -a always,exit -F arch=b64 -S execve,execveat -k exec -a always,exit -F arch=b64 -S exit_group -a always,exit -F arch=b64 -S setsid"}}" {{else}} {{#if audit_rules}} audit_rules: {{escape_string audit_rules}} {{/if}} {{/if}} ``` The above would not be possible using only `escape_string` as `audit_rules` would be wrapped in single quotes. ## Screenshots The example above illustrates how this option allows the Auditd manager integration to append Session data audit rules to the `audit_rules` field when Session data is enabled in the integration ([PR](https://github.com/elastic/integrations/pull/11336)). image image (cherry picked from commit 407137a6befb38f34cb11f6a3b6a741a27977031) --- .../server/services/epm/agent/agent.test.ts | 74 +++++++++++++++++++ .../fleet/server/services/epm/agent/agent.ts | 12 +++ 2 files changed, 86 insertions(+) diff --git a/x-pack/plugins/fleet/server/services/epm/agent/agent.test.ts b/x-pack/plugins/fleet/server/services/epm/agent/agent.test.ts index a3e5749384c0b..7a2a175c4697f 100644 --- a/x-pack/plugins/fleet/server/services/epm/agent/agent.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/agent/agent.test.ts @@ -261,6 +261,80 @@ New lines and \\n escaped values.`, }); }); + describe('escape_multiline_string helper', () => { + it('should escape new lines', () => { + const streamTemplate = ` + input: log + multiline_text: "{{escape_multiline_string multiline_text}}" + `; + + const vars = { + multiline_text: { + type: 'textarea', + value: `This is a text with +New lines and \n escaped values.`, + }, + }; + + const output = compileTemplate(vars, streamTemplate); + expect(output).toEqual({ + input: 'log', + multiline_text: `This is a text with +New lines and +escaped values.`, + }); + }); + + it('should escape single quotes', () => { + const streamTemplate = ` + input: log + multiline_text: "{{escape_multiline_string multiline_text}}" + `; + + const vars = { + multiline_text: { + type: 'textarea', + value: `This is a multiline text with +'escaped values.'`, + }, + }; + + const output = compileTemplate(vars, streamTemplate); + expect(output).toEqual({ + input: 'log', + multiline_text: `This is a multiline text with +''escaped values.''`, + }); + }); + + it('should allow concatenation of multiline strings', () => { + const streamTemplate = ` +input: log +multiline_text: "{{escape_multiline_string multiline_text}}{{escape_multiline_string " +This is a concatenated text +with new lines"}}" + `; + + const vars = { + multiline_text: { + type: 'textarea', + value: `This is a text with +New lines and\nescaped values.`, + }, + }; + + const output = compileTemplate(vars, streamTemplate); + expect(output).toEqual({ + input: 'log', + multiline_text: `This is a text with +New lines and +escaped values. +This is a concatenated text +with new lines`, + }); + }); + }); + describe('to_json helper', () => { const streamTemplate = ` input: log diff --git a/x-pack/plugins/fleet/server/services/epm/agent/agent.ts b/x-pack/plugins/fleet/server/services/epm/agent/agent.ts index f1187e3629c0b..c24f661cc3dc5 100644 --- a/x-pack/plugins/fleet/server/services/epm/agent/agent.ts +++ b/x-pack/plugins/fleet/server/services/epm/agent/agent.ts @@ -131,6 +131,18 @@ function escapeStringHelper(str: string) { } handlebars.registerHelper('escape_string', escapeStringHelper); +/** + * escapeMultilineStringHelper will escape a multiline string by doubling the newlines + * and escaping single quotes. + * This is useful when the string is multiline and needs to be escaped in a yaml file + * without wrapping it in single quotes. + */ +function escapeMultilineStringHelper(str: string) { + if (!str) return undefined; + return str.replace(/\'/g, "''").replace(/\n/g, '\n\n'); +} +handlebars.registerHelper('escape_multiline_string', escapeMultilineStringHelper); + // toJsonHelper will convert any object to a Json string. function toJsonHelper(value: any) { if (typeof value === 'string') {