kibana/x-pack/plugins/actions/server/builtin_action_types/teams.test.ts
Mike Côté da8ce374cf
Make xpack.actions.rejectUnauthorized setting work (#88690)
* Remove ActionsConfigType due to being a duplicate

* Fix rejectUnauthorized not being configured

* Move proxySettings to configurationUtilities

* Fix isAxiosError check to code

* Add functional test

* Remove comment

* Close webhook server

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
2021-01-28 13:44:25 -05:00

278 lines
8.6 KiB
TypeScript

/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { Logger } from '../../../../../src/core/server';
import { Services } from '../types';
import { validateParams, validateSecrets } from '../lib';
import axios from 'axios';
import { ActionParamsType, ActionTypeSecretsType, getActionType, TeamsActionType } from './teams';
import { actionsConfigMock } from '../actions_config.mock';
import { actionsMock } from '../mocks';
import { createActionTypeRegistry } from './index.test';
import * as utils from './lib/axios_utils';
jest.mock('axios');
jest.mock('./lib/axios_utils', () => {
const originalUtils = jest.requireActual('./lib/axios_utils');
return {
...originalUtils,
request: jest.fn(),
patch: jest.fn(),
};
});
axios.create = jest.fn(() => axios);
const requestMock = utils.request as jest.Mock;
const ACTION_TYPE_ID = '.teams';
const services: Services = actionsMock.createServices();
let actionType: TeamsActionType;
let mockedLogger: jest.Mocked<Logger>;
beforeAll(() => {
const { logger, actionTypeRegistry } = createActionTypeRegistry();
actionType = actionTypeRegistry.get<{}, ActionTypeSecretsType, ActionParamsType>(ACTION_TYPE_ID);
mockedLogger = logger;
});
describe('action registration', () => {
test('returns action type', () => {
expect(actionType.id).toEqual(ACTION_TYPE_ID);
expect(actionType.name).toEqual('Microsoft Teams');
});
});
describe('validateParams()', () => {
test('should validate and pass when params is valid', () => {
expect(validateParams(actionType, { message: 'a message' })).toEqual({
message: 'a message',
});
});
test('should validate and throw error when params is invalid', () => {
expect(() => {
validateParams(actionType, {});
}).toThrowErrorMatchingInlineSnapshot(
`"error validating action params: [message]: expected value of type [string] but got [undefined]"`
);
expect(() => {
validateParams(actionType, { message: 1 });
}).toThrowErrorMatchingInlineSnapshot(
`"error validating action params: [message]: expected value of type [string] but got [number]"`
);
});
});
describe('validateActionTypeSecrets()', () => {
test('should validate and pass when config is valid', () => {
validateSecrets(actionType, {
webhookUrl: 'https://example.com',
});
});
test('should validate and throw error when config is invalid', () => {
expect(() => {
validateSecrets(actionType, {});
}).toThrowErrorMatchingInlineSnapshot(
`"error validating action type secrets: [webhookUrl]: expected value of type [string] but got [undefined]"`
);
expect(() => {
validateSecrets(actionType, { webhookUrl: 1 });
}).toThrowErrorMatchingInlineSnapshot(
`"error validating action type secrets: [webhookUrl]: expected value of type [string] but got [number]"`
);
expect(() => {
validateSecrets(actionType, { webhookUrl: 'fee-fi-fo-fum' });
}).toThrowErrorMatchingInlineSnapshot(
`"error validating action type secrets: error configuring teams action: unable to parse host name from webhookUrl"`
);
});
test('should validate and pass when the teams webhookUrl is added to allowedHosts', () => {
actionType = getActionType({
logger: mockedLogger,
configurationUtilities: {
...actionsConfigMock.create(),
ensureUriAllowed: (url) => {
expect(url).toEqual('https://outlook.office.com/');
},
},
});
expect(validateSecrets(actionType, { webhookUrl: 'https://outlook.office.com/' })).toEqual({
webhookUrl: 'https://outlook.office.com/',
});
});
test('config validation returns an error if the specified URL isnt added to allowedHosts', () => {
actionType = getActionType({
logger: mockedLogger,
configurationUtilities: {
...actionsConfigMock.create(),
ensureUriAllowed: () => {
throw new Error(`target hostname is not added to allowedHosts`);
},
},
});
expect(() => {
validateSecrets(actionType, { webhookUrl: 'https://outlook.office.com/' });
}).toThrowErrorMatchingInlineSnapshot(
`"error validating action type secrets: error configuring teams action: target hostname is not added to allowedHosts"`
);
});
});
describe('execute()', () => {
beforeAll(() => {
requestMock.mockReset();
actionType = getActionType({
logger: mockedLogger,
configurationUtilities: actionsConfigMock.create(),
});
});
beforeEach(() => {
requestMock.mockReset();
requestMock.mockResolvedValue({
status: 200,
statusText: '',
data: '',
headers: [],
config: {},
});
});
test('calls the mock executor with success', async () => {
const response = await actionType.executor({
actionId: 'some-id',
services,
config: {},
secrets: { webhookUrl: 'http://example.com' },
params: { message: 'this invocation should succeed' },
});
expect(requestMock.mock.calls[0][0]).toMatchInlineSnapshot(`
Object {
"axios": undefined,
"configurationUtilities": Object {
"ensureActionTypeEnabled": [MockFunction],
"ensureHostnameAllowed": [MockFunction],
"ensureUriAllowed": [MockFunction],
"getProxySettings": [MockFunction],
"isActionTypeEnabled": [MockFunction],
"isHostnameAllowed": [MockFunction],
"isRejectUnauthorizedCertificatesEnabled": [MockFunction],
"isUriAllowed": [MockFunction],
},
"data": Object {
"text": "this invocation should succeed",
},
"logger": Object {
"context": Array [],
"debug": [MockFunction] {
"calls": Array [
Array [
"response from teams action \\"some-id\\": [HTTP 200] ",
],
],
"results": Array [
Object {
"type": "return",
"value": undefined,
},
],
},
"error": [MockFunction],
"fatal": [MockFunction],
"get": [MockFunction],
"info": [MockFunction],
"log": [MockFunction],
"trace": [MockFunction],
"warn": [MockFunction],
},
"method": "post",
"url": "http://example.com",
}
`);
expect(response).toMatchInlineSnapshot(`
Object {
"actionId": "some-id",
"data": Object {
"text": "this invocation should succeed",
},
"status": "ok",
}
`);
});
test('calls the mock executor with success proxy', async () => {
const response = await actionType.executor({
actionId: 'some-id',
services,
config: {},
secrets: { webhookUrl: 'http://example.com' },
params: { message: 'this invocation should succeed' },
});
expect(requestMock.mock.calls[0][0]).toMatchInlineSnapshot(`
Object {
"axios": undefined,
"configurationUtilities": Object {
"ensureActionTypeEnabled": [MockFunction],
"ensureHostnameAllowed": [MockFunction],
"ensureUriAllowed": [MockFunction],
"getProxySettings": [MockFunction],
"isActionTypeEnabled": [MockFunction],
"isHostnameAllowed": [MockFunction],
"isRejectUnauthorizedCertificatesEnabled": [MockFunction],
"isUriAllowed": [MockFunction],
},
"data": Object {
"text": "this invocation should succeed",
},
"logger": Object {
"context": Array [],
"debug": [MockFunction] {
"calls": Array [
Array [
"response from teams action \\"some-id\\": [HTTP 200] ",
],
],
"results": Array [
Object {
"type": "return",
"value": undefined,
},
],
},
"error": [MockFunction],
"fatal": [MockFunction],
"get": [MockFunction],
"info": [MockFunction],
"log": [MockFunction],
"trace": [MockFunction],
"warn": [MockFunction],
},
"method": "post",
"url": "http://example.com",
}
`);
expect(response).toMatchInlineSnapshot(`
Object {
"actionId": "some-id",
"data": Object {
"text": "this invocation should succeed",
},
"status": "ok",
}
`);
});
});