mirror of
https://github.com/elastic/kibana.git
synced 2025-04-25 02:09:32 -04:00
[Synthetics] Ensure port or url is never undefined, to prevent project monitor decryption errors (#134867)
This commit is contained in:
parent
8039218bf3
commit
fabe146739
14 changed files with 87 additions and 30 deletions
|
@ -72,7 +72,7 @@ export const DEFAULT_BROWSER_SIMPLE_FIELDS: BrowserSimpleFields = {
|
||||||
},
|
},
|
||||||
[ConfigKey.MONITOR_TYPE]: DataStream.BROWSER,
|
[ConfigKey.MONITOR_TYPE]: DataStream.BROWSER,
|
||||||
[ConfigKey.PARAMS]: '',
|
[ConfigKey.PARAMS]: '',
|
||||||
[ConfigKey.PORT]: undefined,
|
[ConfigKey.PORT]: null,
|
||||||
[ConfigKey.SCHEDULE]: {
|
[ConfigKey.SCHEDULE]: {
|
||||||
unit: ScheduleUnit.MINUTES,
|
unit: ScheduleUnit.MINUTES,
|
||||||
number: '10',
|
number: '10',
|
||||||
|
|
|
@ -229,8 +229,8 @@ export const BrowserSensitiveSimpleFieldsCodec = t.intersection([
|
||||||
[ConfigKey.SOURCE_ZIP_USERNAME]: t.string,
|
[ConfigKey.SOURCE_ZIP_USERNAME]: t.string,
|
||||||
[ConfigKey.SOURCE_ZIP_PASSWORD]: t.string,
|
[ConfigKey.SOURCE_ZIP_PASSWORD]: t.string,
|
||||||
[ConfigKey.PARAMS]: t.string,
|
[ConfigKey.PARAMS]: t.string,
|
||||||
[ConfigKey.URLS]: t.union([t.string, t.undefined]),
|
[ConfigKey.URLS]: t.union([t.string, t.null]),
|
||||||
[ConfigKey.PORT]: t.union([t.number, t.undefined]),
|
[ConfigKey.PORT]: t.union([t.number, t.null]),
|
||||||
}),
|
}),
|
||||||
ZipUrlTLSFieldsCodec,
|
ZipUrlTLSFieldsCodec,
|
||||||
CommonFieldsCodec,
|
CommonFieldsCodec,
|
||||||
|
|
|
@ -9,7 +9,7 @@ import React, { memo, useMemo, useCallback } from 'react';
|
||||||
import { FormattedMessage } from '@kbn/i18n-react';
|
import { FormattedMessage } from '@kbn/i18n-react';
|
||||||
import { EuiFormRow } from '@elastic/eui';
|
import { EuiFormRow } from '@elastic/eui';
|
||||||
import { Validation } from '../types';
|
import { Validation } from '../types';
|
||||||
import { ConfigKey } from '../types';
|
import { ConfigKey, MonitorFields } from '../types';
|
||||||
import { useBrowserSimpleFieldsContext } from '../contexts';
|
import { useBrowserSimpleFieldsContext } from '../contexts';
|
||||||
import { ScheduleField } from '../schedule_field';
|
import { ScheduleField } from '../schedule_field';
|
||||||
import { SourceField } from './source_field';
|
import { SourceField } from './source_field';
|
||||||
|
@ -76,7 +76,7 @@ export const BrowserSimpleFields = memo<Props>(({ validate, onFieldBlur }) => {
|
||||||
defaultMessage="Frequency"
|
defaultMessage="Frequency"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
isInvalid={!!validate[ConfigKey.SCHEDULE]?.(fields)}
|
isInvalid={!!validate[ConfigKey.SCHEDULE]?.(fields as Partial<MonitorFields>)}
|
||||||
error={
|
error={
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id="xpack.synthetics.createPackagePolicy.stepConfigure.monitorIntegrationSettingsSection.monitorInterval.error"
|
id="xpack.synthetics.createPackagePolicy.stepConfigure.monitorIntegrationSettingsSection.monitorInterval.error"
|
||||||
|
|
|
@ -10,6 +10,7 @@ import { NewPackagePolicy } from '@kbn/fleet-plugin/public';
|
||||||
import { validate } from '../validation';
|
import { validate } from '../validation';
|
||||||
import {
|
import {
|
||||||
ConfigKey,
|
ConfigKey,
|
||||||
|
MonitorFields,
|
||||||
DataStream,
|
DataStream,
|
||||||
TLSVersion,
|
TLSVersion,
|
||||||
CommonFields,
|
CommonFields,
|
||||||
|
@ -602,8 +603,8 @@ describe('useBarChartsHooks', () => {
|
||||||
it('handles browser data stream', async () => {
|
it('handles browser data stream', async () => {
|
||||||
const onChange = jest.fn();
|
const onChange = jest.fn();
|
||||||
const initialProps = {
|
const initialProps = {
|
||||||
defaultConfig: defaultConfig[DataStream.BROWSER],
|
defaultConfig: defaultConfig[DataStream.BROWSER] as Partial<MonitorFields>,
|
||||||
config: defaultConfig[DataStream.BROWSER],
|
config: defaultConfig[DataStream.BROWSER] as Partial<MonitorFields>,
|
||||||
newPolicy,
|
newPolicy,
|
||||||
onChange,
|
onChange,
|
||||||
validate,
|
validate,
|
||||||
|
@ -637,7 +638,7 @@ describe('useBarChartsHooks', () => {
|
||||||
|
|
||||||
rerender({
|
rerender({
|
||||||
...initialProps,
|
...initialProps,
|
||||||
config,
|
config: config as Partial<MonitorFields>,
|
||||||
});
|
});
|
||||||
|
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
|
|
|
@ -8,8 +8,7 @@
|
||||||
import React, { memo, useEffect, useMemo } from 'react';
|
import React, { memo, useEffect, useMemo } from 'react';
|
||||||
import { PackagePolicyCreateExtensionComponentProps } from '@kbn/fleet-plugin/public';
|
import { PackagePolicyCreateExtensionComponentProps } from '@kbn/fleet-plugin/public';
|
||||||
import { useTrackPageview } from '@kbn/observability-plugin/public';
|
import { useTrackPageview } from '@kbn/observability-plugin/public';
|
||||||
import { DataStream } from './types';
|
import { DataStream, PolicyConfig, MonitorFields } from './types';
|
||||||
import { PolicyConfig } from './types';
|
|
||||||
import { usePolicyConfigContext } from './contexts';
|
import { usePolicyConfigContext } from './contexts';
|
||||||
import { DEFAULT_FIELDS } from '../../../../common/constants/monitor_defaults';
|
import { DEFAULT_FIELDS } from '../../../../common/constants/monitor_defaults';
|
||||||
import { CustomFields } from './custom_fields';
|
import { CustomFields } from './custom_fields';
|
||||||
|
@ -39,8 +38,8 @@ export const SyntheticsPolicyCreateExtension = memo<PackagePolicyCreateExtension
|
||||||
|
|
||||||
useUpdatePolicy({
|
useUpdatePolicy({
|
||||||
monitorType,
|
monitorType,
|
||||||
defaultConfig: defaultConfig[monitorType],
|
defaultConfig: defaultConfig[monitorType] as Partial<MonitorFields>,
|
||||||
config: policyConfig[monitorType],
|
config: policyConfig[monitorType] as Partial<MonitorFields>,
|
||||||
newPolicy,
|
newPolicy,
|
||||||
onChange,
|
onChange,
|
||||||
validate,
|
validate,
|
||||||
|
|
|
@ -35,7 +35,7 @@ export const SyntheticsPolicyEditExtension = memo<SyntheticsPolicyEditExtensionP
|
||||||
|
|
||||||
useUpdatePolicy({
|
useUpdatePolicy({
|
||||||
defaultConfig,
|
defaultConfig,
|
||||||
config: policyConfig[monitorType],
|
config: policyConfig[monitorType] as Partial<MonitorFields>,
|
||||||
newPolicy,
|
newPolicy,
|
||||||
onChange,
|
onChange,
|
||||||
validate,
|
validate,
|
||||||
|
|
|
@ -9,9 +9,9 @@ import {
|
||||||
ConfigKey,
|
ConfigKey,
|
||||||
DataStream,
|
DataStream,
|
||||||
HTTPFields,
|
HTTPFields,
|
||||||
BrowserFields,
|
|
||||||
MonitorFields,
|
MonitorFields,
|
||||||
ScheduleUnit,
|
ScheduleUnit,
|
||||||
|
SyntheticsMonitor,
|
||||||
} from '../../../../common/runtime_types';
|
} from '../../../../common/runtime_types';
|
||||||
import { validate } from './validation';
|
import { validate } from './validation';
|
||||||
|
|
||||||
|
@ -53,18 +53,20 @@ describe('[Monitor Management] validation', () => {
|
||||||
[ConfigKey.SOURCE_INLINE, 'step(() => {});'],
|
[ConfigKey.SOURCE_INLINE, 'step(() => {});'],
|
||||||
[ConfigKey.SOURCE_ZIP_URL, 'https://test.zip'],
|
[ConfigKey.SOURCE_ZIP_URL, 'https://test.zip'],
|
||||||
])('Browser', (configKey, value) => {
|
])('Browser', (configKey, value) => {
|
||||||
const browserProps: Partial<BrowserFields> = {
|
const browserProps = {
|
||||||
...commonPropsValid,
|
...commonPropsValid,
|
||||||
[ConfigKey.MONITOR_TYPE]: DataStream.BROWSER,
|
[ConfigKey.MONITOR_TYPE]: DataStream.BROWSER,
|
||||||
[ConfigKey.TIMEOUT]: null,
|
[ConfigKey.TIMEOUT]: null,
|
||||||
|
[ConfigKey.URLS]: null,
|
||||||
|
[ConfigKey.PORT]: null,
|
||||||
[configKey]: value,
|
[configKey]: value,
|
||||||
};
|
} as SyntheticsMonitor;
|
||||||
|
|
||||||
it('should return false for all valid props', () => {
|
it('should return false for all valid props', () => {
|
||||||
const validators = validate[DataStream.BROWSER];
|
const validators = validate[DataStream.BROWSER];
|
||||||
const keysToValidate = [ConfigKey.SCHEDULE, ConfigKey.TIMEOUT, configKey];
|
const keysToValidate = [ConfigKey.SCHEDULE, ConfigKey.TIMEOUT, configKey];
|
||||||
const validatorFns = keysToValidate.map((key) => validators[key]);
|
const validatorFns = keysToValidate.map((key) => validators[key]);
|
||||||
const result = validatorFns.map((fn) => fn?.(browserProps) ?? true);
|
const result = validatorFns.map((fn) => fn?.(browserProps as Partial<MonitorFields>) ?? true);
|
||||||
|
|
||||||
expect(result).not.toEqual(expect.arrayContaining([true]));
|
expect(result).not.toEqual(expect.arrayContaining([true]));
|
||||||
});
|
});
|
||||||
|
|
|
@ -41,8 +41,8 @@ export const MonitorConfig = ({ isEdit = false }: { isEdit: boolean }) => {
|
||||||
const { isValid, config } = useFormatMonitor({
|
const { isValid, config } = useFormatMonitor({
|
||||||
monitorType,
|
monitorType,
|
||||||
validate,
|
validate,
|
||||||
config: policyConfig[monitorType],
|
config: policyConfig[monitorType] as Partial<MonitorFieldsType>,
|
||||||
defaultConfig: DEFAULT_FIELDS[monitorType],
|
defaultConfig: DEFAULT_FIELDS[monitorType] as Partial<MonitorFieldsType>,
|
||||||
});
|
});
|
||||||
|
|
||||||
const [hasBeenSubmitted, setHasBeenSubmitted] = useState(false);
|
const [hasBeenSubmitted, setHasBeenSubmitted] = useState(false);
|
||||||
|
|
|
@ -9,10 +9,10 @@ import {
|
||||||
ConfigKey,
|
ConfigKey,
|
||||||
DataStream,
|
DataStream,
|
||||||
HTTPFields,
|
HTTPFields,
|
||||||
BrowserFields,
|
|
||||||
MonitorFields,
|
MonitorFields,
|
||||||
ScheduleUnit,
|
ScheduleUnit,
|
||||||
ServiceLocations,
|
ServiceLocations,
|
||||||
|
SyntheticsMonitor,
|
||||||
} from '../../../../common/runtime_types';
|
} from '../../../../common/runtime_types';
|
||||||
import { validate, validateCommon } from './validation';
|
import { validate, validateCommon } from './validation';
|
||||||
|
|
||||||
|
@ -96,18 +96,18 @@ describe('[Monitor Management] validation', () => {
|
||||||
[ConfigKey.SOURCE_INLINE, 'step(() => {});'],
|
[ConfigKey.SOURCE_INLINE, 'step(() => {});'],
|
||||||
[ConfigKey.SOURCE_ZIP_URL, 'https://test.zip'],
|
[ConfigKey.SOURCE_ZIP_URL, 'https://test.zip'],
|
||||||
])('Browser', (configKey, value) => {
|
])('Browser', (configKey, value) => {
|
||||||
const browserProps: Partial<BrowserFields> = {
|
const browserProps = {
|
||||||
...commonPropsValid,
|
...commonPropsValid,
|
||||||
[ConfigKey.MONITOR_TYPE]: DataStream.BROWSER,
|
[ConfigKey.MONITOR_TYPE]: DataStream.BROWSER,
|
||||||
[ConfigKey.TIMEOUT]: undefined,
|
[ConfigKey.TIMEOUT]: undefined,
|
||||||
[configKey]: value,
|
[configKey]: value,
|
||||||
};
|
} as SyntheticsMonitor;
|
||||||
|
|
||||||
it('should return false for all valid props', () => {
|
it('should return false for all valid props', () => {
|
||||||
const validators = validate[DataStream.BROWSER];
|
const validators = validate[DataStream.BROWSER];
|
||||||
const keysToValidate = [ConfigKey.SCHEDULE, ConfigKey.TIMEOUT, configKey];
|
const keysToValidate = [ConfigKey.SCHEDULE, ConfigKey.TIMEOUT, configKey];
|
||||||
const validatorFns = keysToValidate.map((key) => validators[key]);
|
const validatorFns = keysToValidate.map((key) => validators[key]);
|
||||||
const result = validatorFns.map((fn) => fn?.(browserProps) ?? true);
|
const result = validatorFns.map((fn) => fn?.(browserProps as Partial<MonitorFields>) ?? true);
|
||||||
|
|
||||||
expect(result).not.toEqual(expect.arrayContaining([true]));
|
expect(result).not.toEqual(expect.arrayContaining([true]));
|
||||||
});
|
});
|
||||||
|
|
|
@ -173,8 +173,8 @@ describe('validateMonitor', () => {
|
||||||
[ConfigKey.SOURCE_ZIP_PASSWORD]: 'password',
|
[ConfigKey.SOURCE_ZIP_PASSWORD]: 'password',
|
||||||
[ConfigKey.SOURCE_ZIP_PROXY_URL]: 'http://proxy-url.com',
|
[ConfigKey.SOURCE_ZIP_PROXY_URL]: 'http://proxy-url.com',
|
||||||
[ConfigKey.PARAMS]: '',
|
[ConfigKey.PARAMS]: '',
|
||||||
[ConfigKey.URLS]: undefined,
|
[ConfigKey.URLS]: null,
|
||||||
[ConfigKey.PORT]: undefined,
|
[ConfigKey.PORT]: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
testBrowserAdvancedFields = {
|
testBrowserAdvancedFields = {
|
||||||
|
@ -309,7 +309,7 @@ describe('validateMonitor', () => {
|
||||||
const testMonitor = {
|
const testMonitor = {
|
||||||
...testHTTPFields,
|
...testHTTPFields,
|
||||||
...({
|
...({
|
||||||
[ConfigKey.URLS]: undefined,
|
[ConfigKey.URLS]: null,
|
||||||
} as unknown as Partial<HTTPFields>),
|
} as unknown as Partial<HTTPFields>),
|
||||||
} as MonitorFields;
|
} as MonitorFields;
|
||||||
|
|
||||||
|
|
|
@ -70,7 +70,7 @@ export const hydrateSavedObjects = async ({
|
||||||
monitors
|
monitors
|
||||||
.filter((monitor) => missingInfoIds.includes(monitor.id))
|
.filter((monitor) => missingInfoIds.includes(monitor.id))
|
||||||
.forEach((monitor) => {
|
.forEach((monitor) => {
|
||||||
let resultAttributes: Partial<SyntheticsMonitor> = monitor.attributes;
|
let resultAttributes: SyntheticsMonitor = monitor.attributes;
|
||||||
|
|
||||||
let isUpdated = false;
|
let isUpdated = false;
|
||||||
|
|
||||||
|
|
|
@ -439,8 +439,8 @@ export class SyntheticsService {
|
||||||
}
|
}
|
||||||
|
|
||||||
formatConfigs(configs: SyntheticsMonitorWithId[]) {
|
formatConfigs(configs: SyntheticsMonitorWithId[]) {
|
||||||
return configs.map((config: Partial<MonitorFields>) =>
|
return configs.map((config: SyntheticsMonitor) =>
|
||||||
formatMonitorConfig(Object.keys(config) as ConfigKey[], config)
|
formatMonitorConfig(Object.keys(config) as ConfigKey[], config as Partial<MonitorFields>)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -576,5 +576,58 @@ export default function ({ getService }: FtrProviderContext) {
|
||||||
await security.role.delete(roleName);
|
await security.role.delete(roleName);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('project monitors - is able to decrypt monitor when updated after hydration', async () => {
|
||||||
|
try {
|
||||||
|
await supertest
|
||||||
|
.put(API_URLS.SYNTHETICS_MONITORS_PROJECT)
|
||||||
|
.set('kbn-xsrf', 'true')
|
||||||
|
.send(projectMonitors);
|
||||||
|
|
||||||
|
const response = await supertest
|
||||||
|
.get(API_URLS.SYNTHETICS_MONITORS)
|
||||||
|
.query({
|
||||||
|
filter: `${syntheticsMonitorType}.attributes.journey_id: ${projectMonitors.monitors[0].id}`,
|
||||||
|
})
|
||||||
|
.set('kbn-xsrf', 'true')
|
||||||
|
.expect(200);
|
||||||
|
|
||||||
|
const { monitors } = response.body;
|
||||||
|
|
||||||
|
// add urls and ports to mimic hydration
|
||||||
|
const updates = {
|
||||||
|
[ConfigKey.URLS]: 'https://modified-host.com',
|
||||||
|
[ConfigKey.PORT]: 443,
|
||||||
|
};
|
||||||
|
|
||||||
|
const modifiedMonitor = { ...monitors[0]?.attributes, ...updates };
|
||||||
|
|
||||||
|
await supertest
|
||||||
|
.put(API_URLS.SYNTHETICS_MONITORS + '/' + monitors[0]?.id)
|
||||||
|
.set('kbn-xsrf', 'true')
|
||||||
|
.send(modifiedMonitor)
|
||||||
|
.expect(200);
|
||||||
|
|
||||||
|
// update project monitor via push api
|
||||||
|
const apiResponse = await supertest
|
||||||
|
.put(API_URLS.SYNTHETICS_MONITORS_PROJECT)
|
||||||
|
.set('kbn-xsrf', 'true')
|
||||||
|
.send(projectMonitors)
|
||||||
|
.expect(200);
|
||||||
|
expect(apiResponse.body.updatedMonitors).eql([projectMonitors.monitors[0].id]);
|
||||||
|
|
||||||
|
// ensure that monitor can still be decrypted
|
||||||
|
await supertest
|
||||||
|
.get(API_URLS.SYNTHETICS_MONITORS + '/' + monitors[0]?.id)
|
||||||
|
.set('kbn-xsrf', 'true')
|
||||||
|
.expect(200);
|
||||||
|
} finally {
|
||||||
|
await Promise.all([
|
||||||
|
projectMonitors.monitors.map((monitor) => {
|
||||||
|
return deleteMonitor(monitor.id, projectMonitors.project);
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,5 +43,7 @@
|
||||||
"locations": [],
|
"locations": [],
|
||||||
"name": "Test HTTP Monitor 03",
|
"name": "Test HTTP Monitor 03",
|
||||||
"namespace": "testnamespace",
|
"namespace": "testnamespace",
|
||||||
"origin": "ui"
|
"origin": "ui",
|
||||||
|
"urls": null,
|
||||||
|
"url.port": null
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue