[8.18] [ResponseOps] mustache lambdas for EncodeURI and EncodeURIComponent, take 2 (#213859) (#215233)

# Backport

This will backport the following commits from `main` to `8.18`:
- [[ResponseOps] mustache lambdas for EncodeURI and EncodeURIComponent,
take 2 (#213859)](https://github.com/elastic/kibana/pull/213859)

<!--- Backport version: 9.6.6 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sorenlouv/backport)

<!--BACKPORT [{"author":{"name":"Patrick
Mueller","email":"patrick.mueller@elastic.co"},"sourceCommit":{"committedDate":"2025-03-19T18:54:03Z","message":"[ResponseOps]
mustache lambdas for EncodeURI and EncodeURIComponent, take 2
(#213859)\n\nresolves
https://github.com/elastic/kibana/issues/168728\n\n## Release
note\n\nAdds Mustache lambdas for alerting actions to encode URLs
with\n`{{#EncodeURI}}` and `{{#EncodeURIComponent}}` using `encodeURI()`
and\n`encodeURIComponent()`.\n\ndoc to update, in a separate
PR:\nhttps://github.com/elastic/docs-content/issues/735","sha":"a3aaa04eba457e8d1696275c1bf6942b8e1544dd","branchLabelMapping":{"^v9.1.0$":"main","^v8.19.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:enhancement","Team:ResponseOps","backport:version","v9.1.0","v8.19.0","v8.18.1","v9.0.1"],"title":"[ResponseOps]
mustache lambdas for EncodeURI and EncodeURIComponent, take
2","number":213859,"url":"https://github.com/elastic/kibana/pull/213859","mergeCommit":{"message":"[ResponseOps]
mustache lambdas for EncodeURI and EncodeURIComponent, take 2
(#213859)\n\nresolves
https://github.com/elastic/kibana/issues/168728\n\n## Release
note\n\nAdds Mustache lambdas for alerting actions to encode URLs
with\n`{{#EncodeURI}}` and `{{#EncodeURIComponent}}` using `encodeURI()`
and\n`encodeURIComponent()`.\n\ndoc to update, in a separate
PR:\nhttps://github.com/elastic/docs-content/issues/735","sha":"a3aaa04eba457e8d1696275c1bf6942b8e1544dd"}},"sourceBranch":"main","suggestedTargetBranches":["8.x","8.18","9.0"],"targetPullRequestStates":[{"branch":"main","label":"v9.1.0","branchLabelMappingKey":"^v9.1.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/213859","number":213859,"mergeCommit":{"message":"[ResponseOps]
mustache lambdas for EncodeURI and EncodeURIComponent, take 2
(#213859)\n\nresolves
https://github.com/elastic/kibana/issues/168728\n\n## Release
note\n\nAdds Mustache lambdas for alerting actions to encode URLs
with\n`{{#EncodeURI}}` and `{{#EncodeURIComponent}}` using `encodeURI()`
and\n`encodeURIComponent()`.\n\ndoc to update, in a separate
PR:\nhttps://github.com/elastic/docs-content/issues/735","sha":"a3aaa04eba457e8d1696275c1bf6942b8e1544dd"}},{"branch":"8.x","label":"v8.19.0","branchLabelMappingKey":"^v8.19.0$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"8.18","label":"v8.18.1","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"9.0","label":"v9.0.1","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"}]}]
BACKPORT-->

Co-authored-by: Patrick Mueller <patrick.mueller@elastic.co>
This commit is contained in:
Kibana Machine 2025-03-19 21:45:42 +01:00 committed by GitHub
parent 75fc4d5414
commit 856fb83a9e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 117 additions and 8 deletions

View file

@ -246,4 +246,52 @@ describe('mustache lambdas', () => {
expect(logger.warn).toHaveBeenCalledWith(`mustache render error: invalid number: 'nope'`);
});
});
describe('EncodeURI', () => {
it('valid string is successful', () => {
const uri = 'https://www.elastic.co?foo=bar&baz= qux'; // note the space
const template = dedent`
{{#EncodeURI}}{{uri}}{{/EncodeURI}}
`.trim();
expect(renderMustacheString(logger, template, { uri }, 'none')).toEqual(
'https://www.elastic.co?foo=bar&baz=%20qux'
);
});
it('logs an error message and returns the error message on errors', () => {
const uri = '\uDC00'; // invalid UTF-8
const template = dedent`
{{#EncodeURI}} {{uri}} {{/EncodeURI}}
`.trim();
const errMessage = `error evaluating encodeURI(\" ${uri} \"): URI malformed`;
expect(renderMustacheString(logger, template, { uri }, 'none')).toBe(errMessage);
expect(logger.warn).toHaveBeenCalledWith(`mustache render error: ${errMessage}`);
});
});
describe('EncodeURIComponent', () => {
it('valid string is successful', () => {
const uri = 'https://www.elastic.co?foo=bar&baz= qux'; // note the space
const template = dedent`
{{#EncodeURIComponent}}{{uri}} {{/EncodeURIComponent}}
`.trim();
expect(renderMustacheString(logger, template, { uri }, 'none')).toEqual(
'https%3A%2F%2Fwww.elastic.co%3Ffoo%3Dbar%26baz%3D%20qux%20'
);
});
it('logs an error message and returns the error message on errors', () => {
const uri = '\uDC00'; // invalid UTF-8
const template = dedent`
{{#EncodeURIComponent}} {{uri}} {{/EncodeURIComponent}}
`.trim();
const errMessage = `error evaluating encodeURIComponent(\" ${uri} \"): URI malformed`;
expect(renderMustacheString(logger, template, { uri }, 'none')).toBe(errMessage);
expect(logger.warn).toHaveBeenCalledWith(`mustache render error: ${errMessage}`);
});
});
});

View file

@ -46,9 +46,39 @@ function getLambdas(logger: Logger) {
const numberString = render(text.trim()).trim();
return formatNumber(logger, numberString);
},
EncodeURI: () =>
function (text: string, render: RenderFn) {
// specifically does not strip whitespace
const string = render(text);
return callEncodeURI(logger, string);
},
EncodeURIComponent: () =>
function (text: string, render: RenderFn) {
// specifically does not strip whitespace
const string = render(text);
return callEncodeURIComponent(logger, string);
},
};
}
function callEncodeURI(logger: Logger, string: string): string {
const s = `${string}`;
try {
return encodeURI(s);
} catch (err) {
return logAndReturnErr(logger, `error evaluating encodeURI("${s}"): ${err.message}`);
}
}
function callEncodeURIComponent(logger: Logger, string: string): string {
const s = `${string}`;
try {
return encodeURIComponent(s);
} catch (err) {
return logAndReturnErr(logger, `error evaluating encodeURIComponent("${s}"): ${err.message}`);
}
}
function evalMath(vars: Variables, o: unknown, logger: Logger): string {
const expr = `${o}`;
try {

View file

@ -48,6 +48,7 @@ export const DeepContextVariables = {
nullJ: null,
undefinedK: undefined,
dateL: '2023-04-20T04:13:17.858Z',
encodeableUrl: 'https://www.elastic.co?foo=bar&baz= qux',
};
function getAlwaysFiringRuleType() {

View file

@ -66,7 +66,7 @@ export default function executionStatusAlertTests({ getService }: FtrProviderCon
describe('escaping', () => {
it('should handle escapes in webhook', async () => {
// from x-pack/test/alerting_api_integration/common/plugins/alerts/server/alert_types.ts,
// from x-pack/test/alerting_api_integration/common/plugins/alerts/server/rule_types.ts
// const EscapableStrings
const template = '{{context.escapableDoubleQuote}} -- {{context.escapableLineFeed}}';
const rule = await createRule({
@ -81,7 +81,7 @@ export default function executionStatusAlertTests({ getService }: FtrProviderCon
});
it('should handle escapes in slack', async () => {
// from x-pack/test/alerting_api_integration/common/plugins/alerts/server/alert_types.ts,
// from x-pack/test/alerting_api_integration/common/plugins/alerts/server/rule_types.ts
// const EscapableStrings
const template =
'{{context.escapableBacktic}} -- {{context.escapableBold}} -- {{context.escapableBackticBold}} -- {{context.escapableHtml}} -- {{context.escapableLink}}';
@ -101,7 +101,7 @@ export default function executionStatusAlertTests({ getService }: FtrProviderCon
});
it('should handle context variable object expansion', async () => {
// from x-pack/test/alerting_api_integration/common/plugins/alerts/server/alert_types.ts,
// from x-pack/test/alerting_api_integration/common/plugins/alerts/server/rule_types.ts
// const DeepContextVariables
const template = '{{context.deep}}';
const rule = await createRule({
@ -113,7 +113,7 @@ export default function executionStatusAlertTests({ getService }: FtrProviderCon
});
const body = await retry.try(async () => waitForActionBody(slackSimulatorURL, rule.id));
expect(body).to.be(
'{"objectA":{"stringB":"B","arrayC":[{"stringD":"D1","numberE":42},{"stringD":"D2","numberE":43}],"objectF":{"stringG":"G","nullG":null}},"stringH":"H","arrayI":[44,45],"nullJ":null,"dateL":"2023-04-20T04:13:17.858Z"}'
'{"objectA":{"stringB":"B","arrayC":[{"stringD":"D1","numberE":42},{"stringD":"D2","numberE":43}],"objectF":{"stringG":"G","nullG":null}},"stringH":"H","arrayI":[44,45],"nullJ":null,"dateL":"2023-04-20T04:13:17.858Z","encodeableUrl":"https://www.elastic.co?foo=bar&amp;baz= qux"}'
);
});
@ -165,7 +165,7 @@ export default function executionStatusAlertTests({ getService }: FtrProviderCon
});
it('should handle asJSON', async () => {
// from x-pack/test/alerting_api_integration/common/plugins/alerts/server/alert_types.ts,
// from x-pack/test/alerting_api_integration/common/plugins/alerts/server/rule_types.ts
// const DeepContextVariables
const template = `{{#context.deep.objectA}}
{{{arrayC}}} {{{arrayC.asJSON}}}
@ -185,7 +185,7 @@ export default function executionStatusAlertTests({ getService }: FtrProviderCon
});
it('should handle EvalMath', async () => {
// from x-pack/test/alerting_api_integration/common/plugins/alerts/server/alert_types.ts,
// from x-pack/test/alerting_api_integration/common/plugins/alerts/server/rule_types.ts
// const DeepContextVariables
const template = `{{#context.deep}}avg({{arrayI.0}}, {{arrayI.1}})/100 => {{#EvalMath}}
round((arrayI[0] + arrayI[1]) / 2 / 100, 2)
@ -202,7 +202,7 @@ export default function executionStatusAlertTests({ getService }: FtrProviderCon
});
it('should handle FormatDate', async () => {
// from x-pack/test/alerting_api_integration/common/plugins/alerts/server/alert_types.ts,
// from x-pack/test/alerting_api_integration/common/plugins/alerts/server/rule_types.ts
// const DeepContextVariables
const template = `{{#context.deep}}{{#FormatDate}}
{{{dateL}}} ; America/New_York; dddd MMM Do YYYY HH:mm:ss
@ -220,7 +220,7 @@ export default function executionStatusAlertTests({ getService }: FtrProviderCon
});
it('should handle FormatNumber', async () => {
// from x-pack/test/alerting_api_integration/common/plugins/alerts/server/alert_types.ts,
// from x-pack/test/alerting_api_integration/common/plugins/alerts/server/rule_types.ts
// const DeepContextVariables
const template = `{{#context.deep}}{{#FormatNumber}}
{{{arrayI.1}}}; en-US; style: currency, currency: EUR
@ -236,6 +236,36 @@ export default function executionStatusAlertTests({ getService }: FtrProviderCon
expect(body.trim()).to.be('€45.00');
});
it('should handle EncodeURI', async () => {
// from x-pack/test/alerting_api_integration/common/plugins/alerts/server/rule_types.ts
// const DeepContextVariables
const template = `{{#context.deep}}{{#EncodeURI}}{{{encodeableUrl}}}{{/EncodeURI}}{{/context.deep}}`;
const rule = await createRule({
id: slackConnector.id,
group: 'default',
params: {
message: `message {{rule.id}} - ${template}`,
},
});
const body = await retry.try(async () => waitForActionBody(slackSimulatorURL, rule.id));
expect(body.trim()).to.be('https://www.elastic.co?foo=bar&baz=%20qux');
});
it('should handle EncodeURIComponent', async () => {
// from x-pack/test/alerting_api_integration/common/plugins/alerts/server/rule_types.ts
// const DeepContextVariables
const template = `{{#context.deep}}{{#EncodeURIComponent}}{{{encodeableUrl}}}{{/EncodeURIComponent}}{{/context.deep}}`;
const rule = await createRule({
id: slackConnector.id,
group: 'default',
params: {
message: `message {{rule.id}} - ${template}`,
},
});
const body = await retry.try(async () => waitForActionBody(slackSimulatorURL, rule.id));
expect(body.trim()).to.be('https%3A%2F%2Fwww.elastic.co%3Ffoo%3Dbar%26baz%3D%20qux');
});
async function createRule(action: any) {
const ruleResponse = await supertest
.post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`)