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 ed5d6473760ff..536ac21e1be12 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 @@ -199,6 +199,95 @@ pcap: false }); }); + describe('escape_string helper', () => { + const streamTemplate = ` +input: log +password: {{escape_string password}} + `; + + const streamTemplateWithNewlinesAndEscapes = ` +input: log +text_var: {{escape_string text_var}} + `; + + it('should wrap in single quotes and escape any single quotes in the string', () => { + const vars = { + password: { type: 'password', value: "ab'c'" }, + }; + + const output = compileTemplate(vars, streamTemplate); + expect(output).toEqual({ + input: 'log', + password: "ab'c'", + }); + }); + + it('should respect new lines and literal escapes', () => { + const vars = { + text_var: { + type: 'text', + value: `This is a text with +New lines and \\n escaped values.`, + }, + }; + + const output = compileTemplate(vars, streamTemplateWithNewlinesAndEscapes); + expect(output).toEqual({ + input: 'log', + text_var: `This is a text with +New lines and \\n escaped values.`, + }); + }); + }); + + describe('to_json helper', () => { + const streamTemplate = ` +input: log +json_var: {{to_json json_var}} + `; + + const streamTemplateWithNewYaml = ` +input: log +yaml_var: {{to_json yaml_var}} + `; + + it('should parse a json string into a json object', () => { + const vars = { + json_var: { type: 'text', value: `{"foo":["bar","bazz"]}` }, + }; + + const output = compileTemplate(vars, streamTemplate); + expect(output).toEqual({ + input: 'log', + json_var: { + foo: ['bar', 'bazz'], + }, + }); + }); + + it('should parse a yaml string into a json object', () => { + const vars = { + yaml_var: { + type: 'yaml', + value: `foo: + bar: + - a + - b`, + }, + }; + + const output = compileTemplate(vars, streamTemplateWithNewYaml); + expect(output).toEqual({ + input: 'log', + yaml_var: { + foo: { + bar: ['a', 'b'], + }, + }, + }); + }); + }); + it('should support optional yaml values at root level', () => { const streamTemplate = ` input: logs 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 a01643b22cf9d..31f82bc8dca13 100644 --- a/x-pack/plugins/fleet/server/services/epm/agent/agent.ts +++ b/x-pack/plugins/fleet/server/services/epm/agent/agent.ts @@ -104,6 +104,25 @@ function containsHelper(this: any, item: string, check: string | string[], optio } handlebars.registerHelper('contains', containsHelper); +// escapeStringHelper will wrap the provided string with single quotes. +// Single quoted strings in yaml need to escape single quotes by doubling them +// and to respect any incoming newline we also need to double them, otherwise +// they will be replaced with a space. +function escapeStringHelper(str: string) { + return "'" + str.replace(/\'/g, "''").replace(/\n/g, '\n\n') + "'"; +} +handlebars.registerHelper('escape_string', escapeStringHelper); + +// toJsonHelper will convert any object to a Json string. +function toJsonHelper(value: any) { + if (typeof value === 'string') { + // if we get a string we assume is an already serialized json + return value; + } + return JSON.stringify(value); +} +handlebars.registerHelper('to_json', toJsonHelper); + function replaceRootLevelYamlVariables(yamlVariables: { [k: string]: any }, yamlTemplate: string) { if (Object.keys(yamlVariables).length === 0 || !yamlTemplate) { return yamlTemplate;