Skip to content

Commit 1898b38

Browse files
[7.9] Fix alerts unable to create / update when the name has trailing whitepace(s) (#76079) (#76172)
* Merge with master * Fix some references * Fix test failures Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
1 parent bbb51b5 commit 1898b38

File tree

4 files changed

+226
-7
lines changed

4 files changed

+226
-7
lines changed

x-pack/plugins/alerts/server/alerts_client.test.ts

Lines changed: 146 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,70 @@ describe('create()', () => {
508508
expect(taskManager.schedule).toHaveBeenCalledTimes(0);
509509
});
510510

511+
test('should trim alert name when creating API key', async () => {
512+
const data = getMockData({ name: ' my alert name ' });
513+
savedObjectsClient.bulkGet.mockResolvedValueOnce({
514+
saved_objects: [
515+
{
516+
id: '1',
517+
type: 'action',
518+
attributes: {
519+
actions: [],
520+
actionTypeId: 'test',
521+
},
522+
references: [],
523+
},
524+
],
525+
});
526+
savedObjectsClient.create.mockResolvedValueOnce({
527+
id: '1',
528+
type: 'alert',
529+
attributes: {
530+
enabled: false,
531+
name: ' my alert name ',
532+
alertTypeId: '123',
533+
schedule: { interval: 10000 },
534+
params: {
535+
bar: true,
536+
},
537+
createdAt: new Date().toISOString(),
538+
actions: [
539+
{
540+
group: 'default',
541+
actionRef: 'action_0',
542+
actionTypeId: 'test',
543+
params: {
544+
foo: true,
545+
},
546+
},
547+
],
548+
},
549+
references: [
550+
{
551+
name: 'action_0',
552+
type: 'action',
553+
id: '1',
554+
},
555+
],
556+
});
557+
taskManager.schedule.mockResolvedValueOnce({
558+
id: 'task-123',
559+
taskType: 'alerting:123',
560+
scheduledAt: new Date(),
561+
attempts: 1,
562+
status: TaskStatus.Idle,
563+
runAt: new Date(),
564+
startedAt: null,
565+
retryAt: null,
566+
state: {},
567+
params: {},
568+
ownerId: null,
569+
});
570+
571+
await alertsClient.create({ data });
572+
expect(alertsClientParams.createAPIKey).toHaveBeenCalledWith('Alerting: 123/my alert name');
573+
});
574+
511575
test('should validate params', async () => {
512576
const data = getMockData();
513577
alertTypeRegistry.get.mockReturnValue({
@@ -1864,8 +1928,24 @@ describe('update()', () => {
18641928
type: 'alert',
18651929
attributes: {
18661930
enabled: true,
1867-
alertTypeId: '123',
1931+
tags: ['foo'],
1932+
alertTypeId: 'myType',
1933+
schedule: { interval: '10s' },
1934+
consumer: 'myApp',
18681935
scheduledTaskId: 'task-123',
1936+
params: {},
1937+
throttle: null,
1938+
actions: [
1939+
{
1940+
group: 'default',
1941+
id: '1',
1942+
actionTypeId: '1',
1943+
actionRef: '1',
1944+
params: {
1945+
foo: true,
1946+
},
1947+
},
1948+
],
18691949
},
18701950
references: [],
18711951
version: '123',
@@ -1883,7 +1963,7 @@ describe('update()', () => {
18831963
savedObjectsClient.get.mockResolvedValue(existingAlert);
18841964
encryptedSavedObjects.getDecryptedAsInternalUser.mockResolvedValue(existingDecryptedAlert);
18851965
alertTypeRegistry.get.mockReturnValue({
1886-
id: '123',
1966+
id: 'myType',
18871967
name: 'Test',
18881968
actionGroups: [{ id: 'default', name: 'Default' }],
18891969
defaultActionGroupId: 'default',
@@ -2062,9 +2142,10 @@ describe('update()', () => {
20622142
},
20632143
},
20642144
],
2065-
"alertTypeId": "123",
2145+
"alertTypeId": "myType",
20662146
"apiKey": null,
20672147
"apiKeyOwner": null,
2148+
"consumer": "myApp",
20682149
"enabled": true,
20692150
"name": "abc",
20702151
"params": Object {
@@ -2217,9 +2298,10 @@ describe('update()', () => {
22172298
},
22182299
},
22192300
],
2220-
"alertTypeId": "123",
2301+
"alertTypeId": "myType",
22212302
"apiKey": "MTIzOmFiYw==",
22222303
"apiKeyOwner": "elastic",
2304+
"consumer": "myApp",
22232305
"enabled": true,
22242306
"name": "abc",
22252307
"params": Object {
@@ -2366,9 +2448,10 @@ describe('update()', () => {
23662448
},
23672449
},
23682450
],
2369-
"alertTypeId": "123",
2451+
"alertTypeId": "myType",
23702452
"apiKey": null,
23712453
"apiKeyOwner": null,
2454+
"consumer": "myApp",
23722455
"enabled": false,
23732456
"name": "abc",
23742457
"params": Object {
@@ -2440,6 +2523,64 @@ describe('update()', () => {
24402523
);
24412524
});
24422525

2526+
it('should trim alert name in the API key name', async () => {
2527+
savedObjectsClient.bulkGet.mockResolvedValueOnce({
2528+
saved_objects: [
2529+
{
2530+
id: '1',
2531+
type: 'action',
2532+
attributes: {
2533+
actions: [],
2534+
actionTypeId: 'test',
2535+
},
2536+
references: [],
2537+
},
2538+
],
2539+
});
2540+
savedObjectsClient.update.mockResolvedValueOnce({
2541+
id: '1',
2542+
type: 'alert',
2543+
attributes: {
2544+
enabled: false,
2545+
name: ' my alert name ',
2546+
schedule: { interval: '10s' },
2547+
params: {
2548+
bar: true,
2549+
},
2550+
createdAt: new Date().toISOString(),
2551+
actions: [
2552+
{
2553+
group: 'default',
2554+
actionRef: 'action_0',
2555+
actionTypeId: 'test',
2556+
params: {
2557+
foo: true,
2558+
},
2559+
},
2560+
],
2561+
scheduledTaskId: 'task-123',
2562+
apiKey: null,
2563+
},
2564+
updated_at: new Date().toISOString(),
2565+
references: [
2566+
{
2567+
name: 'action_0',
2568+
type: 'action',
2569+
id: '1',
2570+
},
2571+
],
2572+
});
2573+
await alertsClient.update({
2574+
id: '1',
2575+
data: {
2576+
...existingAlert.attributes,
2577+
name: ' my alert name ',
2578+
},
2579+
});
2580+
2581+
expect(alertsClientParams.createAPIKey).toHaveBeenCalledWith('Alerting: myType/my alert name');
2582+
});
2583+
24432584
it('swallows error when invalidate API key throws', async () => {
24442585
alertsClientParams.invalidateAPIKey.mockRejectedValueOnce(new Error('Fail'));
24452586
savedObjectsClient.bulkGet.mockResolvedValueOnce({

x-pack/plugins/alerts/server/alerts_client.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
*/
66

77
import Boom from 'boom';
8-
import { omit, isEqual, map, truncate } from 'lodash';
8+
import { omit, isEqual, map, truncate, trim } from 'lodash';
99
import { i18n } from '@kbn/i18n';
1010
import {
1111
Logger,
@@ -719,6 +719,6 @@ export class AlertsClient {
719719
}
720720

721721
private generateAPIKeyName(alertTypeId: string, alertName: string) {
722-
return truncate(`Alerting: ${alertTypeId}/${alertName}`, { length: 256 });
722+
return truncate(`Alerting: ${alertTypeId}/${trim(alertName)}`, { length: 256 });
723723
}
724724
}

x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/create.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,39 @@ export default function createAlertTests({ getService }: FtrProviderContext) {
153153
}
154154
});
155155

156+
it('should handle create alert request appropriately when alert name has leading and trailing whitespaces', async () => {
157+
const response = await supertestWithoutAuth
158+
.post(`${getUrlPrefix(space.id)}/api/alerts/alert`)
159+
.set('kbn-xsrf', 'foo')
160+
.auth(user.username, user.password)
161+
.send(
162+
getTestAlertData({
163+
name: ' leading and trailing whitespace ',
164+
})
165+
);
166+
167+
switch (scenario.id) {
168+
case 'no_kibana_privileges at space1':
169+
case 'global_read at space1':
170+
case 'space_1_all at space2':
171+
expect(response.statusCode).to.eql(404);
172+
expect(response.body).to.eql({
173+
statusCode: 404,
174+
error: 'Not Found',
175+
message: 'Not Found',
176+
});
177+
break;
178+
case 'superuser at space1':
179+
case 'space_1_all at space1':
180+
expect(response.statusCode).to.eql(200);
181+
expect(response.body.name).to.eql(' leading and trailing whitespace ');
182+
objectRemover.add(space.id, response.body.id, 'alert', 'alerts');
183+
break;
184+
default:
185+
throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`);
186+
}
187+
});
188+
156189
it('should handle create alert request appropriately when alert type is unregistered', async () => {
157190
const response = await supertestWithoutAuth
158191
.post(`${getUrlPrefix(space.id)}/api/alerts/alert`)

x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/update.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,51 @@ export default function createUpdateTests({ getService }: FtrProviderContext) {
191191
}
192192
});
193193

194+
it('should handle update alert request appropriately when alert name has leading and trailing whitespaces', async () => {
195+
const { body: createdAlert } = await supertest
196+
.post(`${getUrlPrefix(space.id)}/api/alerts/alert`)
197+
.set('kbn-xsrf', 'foo')
198+
.send(getTestAlertData())
199+
.expect(200);
200+
objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts');
201+
202+
const updatedData = {
203+
name: ' leading and trailing whitespace ',
204+
tags: ['bar'],
205+
params: {
206+
foo: true,
207+
},
208+
schedule: { interval: '12s' },
209+
actions: [],
210+
throttle: '1m',
211+
};
212+
const response = await supertestWithoutAuth
213+
.put(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}`)
214+
.set('kbn-xsrf', 'foo')
215+
.auth(user.username, user.password)
216+
.send(updatedData);
217+
218+
switch (scenario.id) {
219+
case 'no_kibana_privileges at space1':
220+
case 'space_1_all at space2':
221+
case 'global_read at space1':
222+
expect(response.statusCode).to.eql(404);
223+
expect(response.body).to.eql({
224+
statusCode: 404,
225+
error: 'Not Found',
226+
message: 'Not Found',
227+
});
228+
break;
229+
case 'superuser at space1':
230+
case 'space_1_all at space1':
231+
expect(response.statusCode).to.eql(200);
232+
expect(response.body.name).to.eql(' leading and trailing whitespace ');
233+
break;
234+
default:
235+
throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`);
236+
}
237+
});
238+
194239
it(`shouldn't update alert from another space`, async () => {
195240
const { body: createdAlert } = await supertest
196241
.post(`${getUrlPrefix(space.id)}/api/alerts/alert`)

0 commit comments

Comments
 (0)