diff --git a/x-pack/plugins/fleet/common/services/validate_package_policy.ts b/x-pack/plugins/fleet/common/services/validate_package_policy.ts index 2a8c187d71629..493d04a226ed8 100644 --- a/x-pack/plugins/fleet/common/services/validate_package_policy.ts +++ b/x-pack/plugins/fleet/common/services/validate_package_policy.ts @@ -260,29 +260,6 @@ export const validatePackagePolicyConfig = ( }) ); } - if (varDef.type === 'text' && parsedValue && Array.isArray(parsedValue)) { - const invalidStrings = parsedValue.filter((cand) => /^[*&]/.test(cand)); - // only show one error if multiple strings in array are invalid - if (invalidStrings.length > 0) { - errors.push( - i18n.translate('xpack.fleet.packagePolicyValidation.quoteStringErrorMessage', { - defaultMessage: - 'Strings starting with special YAML characters like * or & need to be enclosed in double quotes.', - }) - ); - } - } - } - - if (varDef.type === 'text' && parsedValue && !Array.isArray(parsedValue)) { - if (/^[*&]/.test(parsedValue)) { - errors.push( - i18n.translate('xpack.fleet.packagePolicyValidation.quoteStringErrorMessage', { - defaultMessage: - 'Strings starting with special YAML characters like * or & need to be enclosed in double quotes.', - }) - ); - } } if ( diff --git a/x-pack/plugins/fleet/common/types/models/epm.ts b/x-pack/plugins/fleet/common/types/models/epm.ts index 1c7e09a51c5da..95b22ff2446e8 100644 --- a/x-pack/plugins/fleet/common/types/models/epm.ts +++ b/x-pack/plugins/fleet/common/types/models/epm.ts @@ -330,7 +330,7 @@ export interface RegistryDataStreamPrivileges { indices?: string[]; } -export type RegistryVarType = 'integer' | 'bool' | 'password' | 'text' | 'yaml' | 'string'; +export type RegistryVarType = 'integer' | 'bool' | 'password' | 'text' | 'yaml'; export enum RegistryVarsEntryKeys { name = 'name', title = 'title', 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 df4800b241abb..76d3bb80525b7 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 @@ -273,4 +273,48 @@ paths: 'Error while compiling agent template: options.inverse is not a function' ); }); + + it('should escape string values when necessary', () => { + const stringTemplate = ` +my-package: + asterisk: {{asterisk}} + leadingasterisk: {{leadingasterisk}} + middleasterisk: {{middleasterisk}} + trailingasterisk: {{trailingasterisk}} + ampersand: {{ampersand}} + leadingampersand: {{leadingampersand}} + middleampersand: {{middleampersand}} + trailingampersand: {{trailingampersand}}`; + + // List of special chars that may lead to YAML parsing errors when not quoted. + // See YAML specification section 5.3 Indicator characters + // https://yaml.org/spec/1.2/spec.html#id2772075 + // Currently only escaping leading * and & + const vars = { + asterisk: { value: '*', type: 'text' }, + leadingasterisk: { value: '*blah', type: 'text' }, + middleasterisk: { value: 'blah*blah', type: 'text' }, + trailingasterisk: { value: 'blah*', type: 'text' }, + ampersand: { value: '&', type: 'text' }, + leadingampersand: { value: '&blah', type: 'text' }, + middleampersand: { value: 'blah&blah', type: 'text' }, + trailingampersand: { value: 'blah&', type: 'text' }, + }; + + const targetOutput = { + 'my-package': { + asterisk: '*', + leadingasterisk: '*blah', + middleasterisk: 'blah*blah', + trailingasterisk: 'blah*', + ampersand: '&', + leadingampersand: '&blah', + middleampersand: 'blah&blah', + trailingampersand: 'blah&', + }, + }; + + const output = compileTemplate(vars, stringTemplate); + expect(output).toEqual(targetOutput); + }); }); 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 762bc1ea624e1..c47aae15c302b 100644 --- a/x-pack/plugins/fleet/server/services/epm/agent/agent.ts +++ b/x-pack/plugins/fleet/server/services/epm/agent/agent.ts @@ -64,6 +64,14 @@ function replaceVariablesInYaml(yamlVariables: { [k: string]: any }, yaml: any) return yaml; } +const maybeEscapeString = (value: string) => { + // Quote strings that start with special characters + if (/^[*&]/.test(value)) { + return `"${value}"`; + } + return value; +}; + function buildTemplateVariables(variables: PackagePolicyConfigRecord, templateStr: string) { const yamlValues: { [k: string]: any } = {}; const vars = Object.entries(variables).reduce((acc, [key, recordEntry]) => { @@ -90,6 +98,12 @@ function buildTemplateVariables(variables: PackagePolicyConfigRecord, templateSt const yamlKeyPlaceholder = `##${key}##`; varPart[lastKeyPart] = recordEntry.value ? `"${yamlKeyPlaceholder}"` : null; yamlValues[yamlKeyPlaceholder] = recordEntry.value ? safeLoad(recordEntry.value) : null; + } else if (recordEntry.type && recordEntry.type === 'text' && recordEntry.value?.length) { + if (Array.isArray(recordEntry.value)) { + varPart[lastKeyPart] = recordEntry.value.map((value: string) => maybeEscapeString(value)); + } else { + varPart[lastKeyPart] = maybeEscapeString(recordEntry.value); + } } else { varPart[lastKeyPart] = recordEntry.value; }