diff --git a/x-pack/plugins/stack_connectors/common/torq/index.ts b/x-pack/plugins/stack_connectors/common/torq/index.ts
new file mode 100644
index 0000000000000..76c6dcd71db14
--- /dev/null
+++ b/x-pack/plugins/stack_connectors/common/torq/index.ts
@@ -0,0 +1,12 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+const hostNameRegExp = /^hooks\.(eu\.)?torq\.io$/;
+
+export const isValidTorqHostName = (hostName: string) => {
+ return hostNameRegExp.test(hostName);
+};
diff --git a/x-pack/plugins/stack_connectors/public/connector_types/torq/torq_connectors.test.tsx b/x-pack/plugins/stack_connectors/public/connector_types/torq/torq_connectors.test.tsx
index db11c00e03589..3929e0a0432b4 100644
--- a/x-pack/plugins/stack_connectors/public/connector_types/torq/torq_connectors.test.tsx
+++ b/x-pack/plugins/stack_connectors/public/connector_types/torq/torq_connectors.test.tsx
@@ -93,6 +93,41 @@ describe('TorqActionConnectorFields renders', () => {
});
});
+ it('connector validation succeeds when using a EU torq webhook URL', async () => {
+ const connector = {
+ ...actionConnector,
+ config: { webhookIntegrationUrl: 'https://hooks.eu.torq.io/v1/webhooks/fjdksla' },
+ };
+ const { getByTestId } = render(
+
+
+
+ );
+
+ await act(async () => {
+ await userEvent.click(getByTestId('form-test-provide-submit'));
+ });
+
+ expect(onSubmit).toBeCalledWith({
+ data: {
+ actionTypeId: '.torq',
+ name: 'torq',
+ config: {
+ webhookIntegrationUrl: 'https://hooks.eu.torq.io/v1/webhooks/fjdksla',
+ },
+ secrets: {
+ token: 'testtoken',
+ },
+ isDeprecated: false,
+ },
+ isValid: true,
+ });
+ });
+
it('connector validation fails when there is no token', async () => {
const connector = {
...actionConnector,
@@ -153,7 +188,7 @@ describe('TorqActionConnectorFields renders', () => {
const connector = {
...actionConnector,
config: {
- webhookIntegrationUrl: 'https://test.com',
+ webhookIntegrationUrl: 'https://hooks.not-torq.io/v1/webhooks/fjdksla',
},
};
diff --git a/x-pack/plugins/stack_connectors/public/connector_types/torq/torq_connectors.tsx b/x-pack/plugins/stack_connectors/public/connector_types/torq/torq_connectors.tsx
index e6edceb68b9a8..235a54d771246 100644
--- a/x-pack/plugins/stack_connectors/public/connector_types/torq/torq_connectors.tsx
+++ b/x-pack/plugins/stack_connectors/public/connector_types/torq/torq_connectors.tsx
@@ -17,6 +17,7 @@ import {
import { isUrl } from '@kbn/es-ui-shared-plugin/static/validators/string';
import { ActionConnectorFieldsProps } from '@kbn/triggers-actions-ui-plugin/public';
import React from 'react';
+import { isValidTorqHostName } from '../../../common/torq';
import * as i18n from './translations';
const { urlField, emptyField } = fieldValidators;
@@ -42,7 +43,7 @@ const torqWebhookEndpoint =
};
if (!isUrl(value)) return error;
const hostname = new URL(value).hostname;
- return hostname === 'hooks.torq.io' ? undefined : error;
+ return isValidTorqHostName(hostname) ? undefined : error;
};
const TorqActionConnectorFields: React.FunctionComponent = ({
diff --git a/x-pack/plugins/stack_connectors/server/connector_types/torq/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/torq/index.test.ts
index 39bbdd44a918d..9fad686414150 100644
--- a/x-pack/plugins/stack_connectors/server/connector_types/torq/index.test.ts
+++ b/x-pack/plugins/stack_connectors/server/connector_types/torq/index.test.ts
@@ -85,6 +85,15 @@ describe('config validation', () => {
...config,
});
});
+ test('config validation passes with the EU endpoint', () => {
+ const config: Record = {
+ webhookIntegrationUrl: 'https://hooks.eu.torq.io/v1/test',
+ };
+ expect(validateConfig(actionType, config, { configurationUtilities })).toEqual({
+ ...defaultValues,
+ ...config,
+ });
+ });
const errorCases: Array<{ name: string; url: string; errorMsg: string }> = [
{
@@ -100,7 +109,12 @@ describe('config validation', () => {
{
name: 'fails when URL is not a Torq webhook endpoint',
url: 'http://mylisteningserver:9200/endpoint',
- errorMsg: `"error validating action type config: error configuring send to Torq action: url must begin with https://hooks.torq.io"`,
+ errorMsg: `"error validating action type config: error configuring send to Torq action: url must begin with https://hooks.torq.io or https://hooks.eu.torq.io"`,
+ },
+ {
+ name: 'fails when URL is an unsupported Torq webhook subdomain',
+ url: 'https://hooks.anothersubdomain.torq.io/v1/test',
+ errorMsg: `"error validating action type config: error configuring send to Torq action: url must begin with https://hooks.torq.io or https://hooks.eu.torq.io"`,
},
];
errorCases.forEach(({ name, url, errorMsg }) => {
diff --git a/x-pack/plugins/stack_connectors/server/connector_types/torq/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/torq/index.ts
index b60237dd7991e..5488be1805b6a 100644
--- a/x-pack/plugins/stack_connectors/server/connector_types/torq/index.ts
+++ b/x-pack/plugins/stack_connectors/server/connector_types/torq/index.ts
@@ -22,6 +22,7 @@ import {
import { renderMustacheObject } from '@kbn/actions-plugin/server/lib/mustache_renderer';
import { request } from '@kbn/actions-plugin/server/lib/axios_utils';
import { ValidatorServices } from '@kbn/actions-plugin/server/types';
+import { isValidTorqHostName } from '../../../common/torq';
import { getRetryAfterIntervalFromHeaders } from '../lib/http_response_retry_header';
import { promiseResult, isOk, Result } from '../lib/result_type';
@@ -128,11 +129,11 @@ function validateActionTypeConfig(
);
}
- if (configureUrlObj.hostname !== 'hooks.torq.io' && configureUrlObj.hostname !== 'localhost') {
+ if (!isValidTorqHostName(configureUrlObj.hostname) && configureUrlObj.hostname !== 'localhost') {
throw new Error(
i18n.translate('xpack.stackConnectors.torq.torqConfigurationErrorInvalidHostname', {
defaultMessage:
- 'error configuring send to Torq action: url must begin with https://hooks.torq.io',
+ 'error configuring send to Torq action: url must begin with https://hooks.torq.io or https://hooks.eu.torq.io',
})
);
}