[Fleet] Don't add extra quotes to YAML strings from manifest files (#93585)

* Add UI validation for string YAML values in policies.

* Do not quote YAML strings containing special characters.

* Add test case for wildcards in the middle of strings.

* Add multiline test case.

* Polish test case.

* Update API docs

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Sonja Krause-Harder 2021-03-05 15:00:31 +01:00 committed by GitHub
parent bf1dcb7679
commit 3cd0d455c6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 54 additions and 63 deletions

View file

@ -14114,7 +14114,7 @@
"link": "https://github.com/elastic/kibana/tree/masterx-pack/plugins/fleet/common/types/models/epm.ts#L234"
},
"signature": [
"\"text\" | \"password\" | \"integer\" | \"bool\" | \"yaml\""
"\"string\" | \"text\" | \"password\" | \"integer\" | \"bool\" | \"yaml\""
],
"initialIsOpen": false
},

View file

@ -231,7 +231,7 @@ export interface RegistryElasticsearch {
'index_template.mappings'?: object;
}
export type RegistryVarType = 'integer' | 'bool' | 'password' | 'text' | 'yaml';
export type RegistryVarType = 'integer' | 'bool' | 'password' | 'text' | 'yaml' | 'string';
// EPR types this as `[]map[string]interface{}`
// which means the official/possible type is Record<string, any>
// but we effectively only see this shape

View file

@ -229,6 +229,37 @@ export const validatePackagePolicyConfig = (
})
);
}
if (
(varDef.type === 'text' || varDef.type === 'string') &&
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' || varDef.type === 'string') &&
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.',
})
);
}
}
return errors.length ? errors : null;

View file

@ -183,71 +183,36 @@ input: logs
it('should escape string values when necessary', () => {
const stringTemplate = `
my-package:
opencurly: {{opencurly}}
closecurly: {{closecurly}}
opensquare: {{opensquare}}
closesquare: {{closesquare}}
ampersand: {{ampersand}}
asterisk: {{asterisk}}
question: {{question}}
pipe: {{pipe}}
hyphen: {{hyphen}}
openangle: {{openangle}}
closeangle: {{closeangle}}
equals: {{equals}}
exclamation: {{exclamation}}
percent: {{percent}}
at: {{at}}
colon: {{colon}}
asteriskOnly: {{asteriskOnly}}
startsWithAsterisk: {{startsWithAsterisk}}
numeric: {{numeric}}
mixed: {{mixed}}`;
mixed: {{mixed}}
concatenatedEnd: {{a}}{{b}}
concatenatedMiddle: {{c}}{{d}}
mixedMultiline: |-
{{{ search }}} | streamstats`;
// 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
// {,},[,],&,*,?,|,-,<,>,=,!,%,@,:
const vars = {
opencurly: { value: '{', type: 'string' },
closecurly: { value: '}', type: 'string' },
opensquare: { value: '[', type: 'string' },
closesquare: { value: ']', type: 'string' },
comma: { value: ',', type: 'string' },
ampersand: { value: '&', type: 'string' },
asterisk: { value: '*', type: 'string' },
question: { value: '?', type: 'string' },
pipe: { value: '|', type: 'string' },
hyphen: { value: '-', type: 'string' },
openangle: { value: '<', type: 'string' },
closeangle: { value: '>', type: 'string' },
equals: { value: '=', type: 'string' },
exclamation: { value: '!', type: 'string' },
percent: { value: '%', type: 'string' },
at: { value: '@', type: 'string' },
colon: { value: ':', type: 'string' },
asteriskOnly: { value: '"*"', type: 'string' },
startsWithAsterisk: { value: '"*lala"', type: 'string' },
numeric: { value: '100', type: 'string' },
mixed: { value: '1s', type: 'string' },
a: { value: '/opt/package/*', type: 'string' },
b: { value: '/logs/my.log*', type: 'string' },
c: { value: '/opt/*/package/', type: 'string' },
d: { value: 'logs/*my.log', type: 'string' },
search: { value: 'search sourcetype="access*"', type: 'text' },
};
const targetOutput = {
'my-package': {
opencurly: '{',
closecurly: '}',
opensquare: '[',
closesquare: ']',
ampersand: '&',
asterisk: '*',
question: '?',
pipe: '|',
hyphen: '-',
openangle: '<',
closeangle: '>',
equals: '=',
exclamation: '!',
percent: '%',
at: '@',
colon: ':',
asteriskOnly: '*',
startsWithAsterisk: '*lala',
numeric: '100',
mixed: '1s',
concatenatedEnd: '/opt/package/*/logs/my.log*',
concatenatedMiddle: '/opt/*/package/logs/*my.log',
mixedMultiline: 'search sourcetype="access*" | streamstats',
},
};

View file

@ -59,13 +59,8 @@ function replaceVariablesInYaml(yamlVariables: { [k: string]: any }, yaml: any)
}
const maybeEscapeString = (value: string) => {
// 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
const yamlSpecialCharsRegex = /[{}\[\],&*?|\-<>=!%@:]/;
// In addition, numeric strings need to be quoted to stay strings.
if ((value.length && !isNaN(+value)) || yamlSpecialCharsRegex.test(value)) {
// Numeric strings need to be quoted to stay strings.
if (value.length && !isNaN(+value)) {
return `"${value}"`;
}
return value;