Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Synthetics] enable/disable - prevent incorrect keys from being added to the monitor saved object #140553

Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
72de9c3
synthetics - enable/disable - prevent incorrect keys from being added…
dominiqueclarke Sep 12, 2022
3520486
[CI] Auto-commit changed files from 'node scripts/precommit_hook.js -…
kibanamachine Sep 12, 2022
64a3337
Merge branch 'main' of github.com:elastic/kibana into fix/synthetics-…
dominiqueclarke Sep 24, 2022
8878b8c
adjust types
dominiqueclarke Sep 24, 2022
f9aa1df
Merge branch 'fix/synthetics-enable-disable-incorrect-keys' of https:…
dominiqueclarke Sep 24, 2022
8ecb794
add exact typing
dominiqueclarke Sep 24, 2022
6a39211
[CI] Auto-commit changed files from 'node scripts/precommit_hook.js -…
kibanamachine Sep 24, 2022
a614583
adjust test
dominiqueclarke Sep 24, 2022
aa42c58
use exact types
dominiqueclarke Sep 24, 2022
9da887a
Merge branch 'fix/synthetics-enable-disable-incorrect-keys' of https:…
dominiqueclarke Sep 24, 2022
7a9ff1b
use exact types for editing
dominiqueclarke Sep 24, 2022
a840eaa
adjust types
dominiqueclarke Sep 24, 2022
a3de6fc
adjust tests
dominiqueclarke Sep 25, 2022
bebde51
adjust types
dominiqueclarke Sep 25, 2022
5795c5e
Update x-pack/test/api_integration/apis/uptime/rest/add_monitor.ts
dominiqueclarke Sep 25, 2022
df617c6
adjust normalizers
dominiqueclarke Sep 25, 2022
3e84c89
Merge branch 'fix/synthetics-enable-disable-incorrect-keys' of https:…
dominiqueclarke Sep 25, 2022
929c451
Update x-pack/plugins/synthetics/common/runtime_types/monitor_managem…
dominiqueclarke Sep 25, 2022
ec265de
Update x-pack/plugins/synthetics/server/routes/monitor_cruds/add_moni…
dominiqueclarke Sep 25, 2022
0e68251
adjust types
dominiqueclarke Sep 26, 2022
694c390
Merge branch 'fix/synthetics-enable-disable-incorrect-keys' of https:…
dominiqueclarke Sep 26, 2022
1871790
[CI] Auto-commit changed files from 'node scripts/eslint --no-cache -…
kibanamachine Sep 26, 2022
9b3d683
adjust jest tests
dominiqueclarke Sep 26, 2022
63d613d
Merge branch 'fix/synthetics-enable-disable-incorrect-keys' of https:…
dominiqueclarke Sep 26, 2022
a5b2f03
adjust types
dominiqueclarke Sep 26, 2022
4d4ca60
adjust api_integration tests
dominiqueclarke Sep 26, 2022
3a7d244
merge main
dominiqueclarke Sep 29, 2022
5c43159
update tests
dominiqueclarke Sep 29, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
tlsValueToStringFormatter,
tlsArrayToYamlFormatter,
} from '../tls/formatters';
import { tlsFormatters } from '../tls/formatters';

export type BrowserFormatMap = Record<keyof BrowserFields, Formatter>;

Expand Down Expand Up @@ -72,10 +73,8 @@ export const browserFormatters: BrowserFormatMap = {
arrayToJsonFormatter(fields[ConfigKey.JOURNEY_FILTERS_TAGS]),
[ConfigKey.THROTTLING_CONFIG]: throttlingFormatter,
[ConfigKey.IGNORE_HTTPS_ERRORS]: null,
[ConfigKey.PROJECT_ID]: null,
[ConfigKey.PLAYWRIGHT_OPTIONS]: null,
[ConfigKey.CUSTOM_HEARTBEAT_ID]: null,
[ConfigKey.ORIGINAL_SPACE]: null,
[ConfigKey.TEXT_ASSERTION]: null,
...commonFormatters,
...tlsFormatters,
};
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ export const commonFormatters: CommonFormatMap = {
[ConfigKey.MONITOR_SOURCE_TYPE]: null,
[ConfigKey.FORM_MONITOR_TYPE]: null,
[ConfigKey.JOURNEY_ID]: null,
[ConfigKey.PROJECT_ID]: null,
[ConfigKey.CUSTOM_HEARTBEAT_ID]: null,
[ConfigKey.ORIGINAL_SPACE]: null,
};

export const arrayToJsonFormatter = (value: string[] = []) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ export const CommonFieldsCodec = t.intersection([
[ConfigKey.MONITOR_SOURCE_TYPE]: SourceTypeCodec,
[ConfigKey.CONFIG_ID]: t.string,
[ConfigKey.JOURNEY_ID]: t.string,
[ConfigKey.PROJECT_ID]: t.string,
[ConfigKey.ORIGINAL_SPACE]: t.string,
[ConfigKey.CUSTOM_HEARTBEAT_ID]: t.string,
}),
]);

Expand Down Expand Up @@ -216,9 +219,6 @@ export const EncryptedBrowserSimpleFieldsCodec = t.intersection([
}),
t.partial({
[ConfigKey.PLAYWRIGHT_OPTIONS]: t.string,
[ConfigKey.PROJECT_ID]: t.string,
[ConfigKey.ORIGINAL_SPACE]: t.string,
[ConfigKey.CUSTOM_HEARTBEAT_ID]: t.string,
[ConfigKey.TEXT_ASSERTION]: t.string,
}),
]),
Expand All @@ -241,7 +241,7 @@ export const BrowserSensitiveSimpleFieldsCodec = t.intersection([
CommonFieldsCodec,
]);

export const BrowserAdvancedFieldsCodec = t.interface({
export const EncryptedBrowserAdvancedFieldsCodec = t.interface({
[ConfigKey.SCREENSHOTS]: t.string,
[ConfigKey.JOURNEY_FILTERS_MATCH]: t.string,
[ConfigKey.JOURNEY_FILTERS_TAGS]: t.array(t.string),
Expand All @@ -263,25 +263,26 @@ export const BrowserSensitiveAdvancedFieldsCodec = t.interface({
[ConfigKey.SYNTHETICS_ARGS]: t.array(t.string),
});

export const BrowserAdvancedsCodec = t.intersection([
BrowserAdvancedFieldsCodec,
export const BrowserAdvancedFieldsCodec = t.intersection([
EncryptedBrowserAdvancedFieldsCodec,
BrowserSensitiveAdvancedFieldsCodec,
]);

export const EncryptedBrowserFieldsCodec = t.intersection([
EncryptedBrowserSimpleFieldsCodec,
BrowserAdvancedFieldsCodec,
EncryptedBrowserAdvancedFieldsCodec,
TLSFieldsCodec,
]);

export const BrowserFieldsCodec = t.intersection([
BrowserSimpleFieldsCodec,
BrowserAdvancedFieldsCodec,
BrowserSensitiveAdvancedFieldsCodec,
TLSCodec,
]);

export type BrowserFields = t.TypeOf<typeof BrowserFieldsCodec>;
export type BrowserSimpleFields = t.TypeOf<typeof BrowserSimpleFieldsCodec>;
export type BrowserAdvancedFields = t.TypeOf<typeof BrowserAdvancedsCodec>;
export type BrowserAdvancedFields = t.TypeOf<typeof BrowserAdvancedFieldsCodec>;

// MonitorFields, represents any possible monitor type
export const MonitorFieldsCodec = t.intersection([
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export const MonitorEnabled = ({

const handleEnabledChange = (event: EuiSwitchEvent) => {
const checked = event.target.checked;
updateMonitorEnabledState(monitor, checked);
updateMonitorEnabledState(checked);
};

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,15 +111,7 @@ describe('ActionsPopover', () => {
const enableButton = getByText('Disable monitor');
fireEvent.click(enableButton);
expect(updateMonitorEnabledState).toHaveBeenCalledTimes(1);
expect(updateMonitorEnabledState.mock.calls[0]).toEqual([
{
id: 'somelongstring',
isEnabled: true,
location: { id: 'us_central', isServiceManaged: true },
name: 'Monitor 1',
},
false,
]);
expect(updateMonitorEnabledState.mock.calls[0]).toEqual([false]);
});

it('sets enabled state to true', async () => {
Expand All @@ -139,14 +131,6 @@ describe('ActionsPopover', () => {
const enableButton = getByText('Enable monitor');
fireEvent.click(enableButton);
expect(updateMonitorEnabledState).toHaveBeenCalledTimes(1);
expect(updateMonitorEnabledState.mock.calls[0]).toEqual([
{
id: 'somelongstring',
isEnabled: false,
location: { id: 'us_central', isServiceManaged: true },
name: 'Monitor 1',
},
true,
]);
expect(updateMonitorEnabledState.mock.calls[0]).toEqual([true]);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ export function ActionsPopover({
icon: 'invert',
onClick: () => {
if (status !== FETCH_STATUS.LOADING)
updateMonitorEnabledState(monitor, !monitor.isEnabled);
updateMonitorEnabledState(!monitor.isEnabled);
},
},
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,7 @@ import { useKibana } from '@kbn/kibana-react-plugin/public';
import { FETCH_STATUS } from '@kbn/observability-plugin/public';
import React, { useCallback, useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import {
ConfigKey,
EncryptedSyntheticsMonitor,
MonitorOverviewItem,
} from '../components/monitors_page/overview/types';
import { ConfigKey } from '../components/monitors_page/overview/types';
import {
clearMonitorUpsertStatus,
fetchUpsertMonitorAction,
Expand Down Expand Up @@ -41,11 +37,11 @@ export function useMonitorEnableHandler({
const savedObjEnabledState = upsertStatuses[id]?.enabled;
const [isEnabled, setIsEnabled] = useState<boolean | null>(null);
const updateMonitorEnabledState = useCallback(
(monitor: EncryptedSyntheticsMonitor | MonitorOverviewItem, enabled: boolean) => {
(enabled: boolean) => {
dispatch(
fetchUpsertMonitorAction({
id,
monitor: { ...monitor, [ConfigKey.ENABLED]: enabled },
monitor: { [ConfigKey.ENABLED]: enabled },
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since edits are applied on top of the existing object, we can just pass the enabled key to be safe here.

})
);
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import { createAction } from '@reduxjs/toolkit';
import {
EncryptedSyntheticsMonitor,
MonitorManagementListResult,
MonitorOverviewItem,
} from '../../../../../common/runtime_types';
import { createAsyncAction } from '../utils/actions';

Expand All @@ -23,7 +22,7 @@ export const fetchMonitorListAction = createAsyncAction<

export interface UpsertMonitorRequest {
id: string;
monitor: EncryptedSyntheticsMonitor | MonitorOverviewItem;
monitor: Partial<EncryptedSyntheticsMonitor>;
}
export const fetchUpsertMonitorAction = createAction<UpsertMonitorRequest>('fetchUpsertMonitor');
export const fetchUpsertSuccessAction = createAction<{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import {
FetchMonitorManagementListQueryArgs,
MonitorManagementListResult,
MonitorManagementListResultCodec,
MonitorOverviewItem,
ServiceLocationErrors,
SyntheticsMonitor,
} from '../../../../../common/runtime_types';
Expand Down Expand Up @@ -55,7 +54,7 @@ export const fetchUpsertMonitor = async ({
monitor,
id,
}: {
monitor: SyntheticsMonitor | EncryptedSyntheticsMonitor | MonitorOverviewItem;
monitor: Partial<SyntheticsMonitor> | Partial<EncryptedSyntheticsMonitor>;
id?: string;
}): Promise<{ attributes: { errors: ServiceLocationErrors } } | SyntheticsMonitor> => {
if (id) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import {
LocationStatus,
ScheduleUnit,
SourceType,
VerificationMode,
TLSVersion,
} from '../../../../../../common/runtime_types';

/**
Expand Down Expand Up @@ -338,8 +340,8 @@ function getMonitorDetailsMockSlice() {
'ssl.certificate': '',
'ssl.key': '',
'ssl.key_passphrase': '',
'ssl.verification_mode': 'full',
'ssl.supported_protocols': ['TLSv1.1', 'TLSv1.2', 'TLSv1.3'],
'ssl.verification_mode': VerificationMode.FULL,
'ssl.supported_protocols': ['TLSv1.1', 'TLSv1.2', 'TLSv1.3'] as TLSVersion[],
revision: 1,
updated_at: '2022-07-24T17:15:46.342Z',
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
getNormalizer,
getJsonToJavascriptNormalizer,
} from '../common/normalizers';
import { tlsNormalizers } from '../tls/normalizers';

import { defaultBrowserSimpleFields, defaultBrowserAdvancedFields } from '../contexts';

Expand Down Expand Up @@ -107,10 +108,8 @@ export const browserNormalizers: BrowserNormalizerMap = {
ConfigKey.JOURNEY_FILTERS_TAGS
),
[ConfigKey.IGNORE_HTTPS_ERRORS]: getBrowserNormalizer(ConfigKey.IGNORE_HTTPS_ERRORS),
[ConfigKey.PROJECT_ID]: getBrowserNormalizer(ConfigKey.PROJECT_ID),
[ConfigKey.PLAYWRIGHT_OPTIONS]: getBrowserNormalizer(ConfigKey.PLAYWRIGHT_OPTIONS),
[ConfigKey.CUSTOM_HEARTBEAT_ID]: getBrowserNormalizer(ConfigKey.CUSTOM_HEARTBEAT_ID),
[ConfigKey.ORIGINAL_SPACE]: getBrowserNormalizer(ConfigKey.ORIGINAL_SPACE),
[ConfigKey.TEXT_ASSERTION]: getBrowserNormalizer(ConfigKey.TEXT_ASSERTION),
...commonNormalizers,
...tlsNormalizers,
};
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,7 @@ export const commonNormalizers: CommonNormalizerMap = {
[ConfigKey.MONITOR_SOURCE_TYPE]: getCommonNormalizer(ConfigKey.MONITOR_SOURCE_TYPE),
[ConfigKey.FORM_MONITOR_TYPE]: getCommonNormalizer(ConfigKey.FORM_MONITOR_TYPE),
[ConfigKey.JOURNEY_ID]: getCommonNormalizer(ConfigKey.JOURNEY_ID),
[ConfigKey.PROJECT_ID]: getCommonNormalizer(ConfigKey.PROJECT_ID),
[ConfigKey.CUSTOM_HEARTBEAT_ID]: getCommonNormalizer(ConfigKey.CUSTOM_HEARTBEAT_ID),
[ConfigKey.ORIGINAL_SPACE]: getCommonNormalizer(ConfigKey.ORIGINAL_SPACE),
};
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ export const addSyntheticsMonitorRoute: SyntheticsRestApiRouteFactory = () => ({

const validationResult = validateMonitor(monitorWithDefaults as MonitorFields);

if (!validationResult.valid) {
if (!validationResult.valid || !validationResult.decodedMonitor) {
const { reason: message, details, payload } = validationResult;
return response.badRequest({ body: { message, attributes: { details, ...payload } } });
}
Expand All @@ -78,8 +78,7 @@ export const addSyntheticsMonitorRoute: SyntheticsRestApiRouteFactory = () => ({

try {
const { errors, newMonitor } = await syncNewMonitor({
normalizedMonitor: monitorWithDefaults,
monitor,
normalizedMonitor: validationResult.decodedMonitor,
server,
syntheticsMonitorClient,
savedObjectsClient,
Expand Down Expand Up @@ -140,7 +139,6 @@ export const createNewSavedObjectMonitor = async ({

export const syncNewMonitor = async ({
id,
monitor,
server,
syntheticsMonitorClient,
savedObjectsClient,
Expand All @@ -150,7 +148,6 @@ export const syncNewMonitor = async ({
spaceId,
}: {
id?: string;
monitor: SyntheticsMonitor;
normalizedMonitor: SyntheticsMonitor;
server: UptimeServerSetup;
syntheticsMonitorClient: SyntheticsMonitorClient;
Expand Down Expand Up @@ -201,7 +198,7 @@ export const syncNewMonitor = async ({
formatTelemetryEvent({
errors: syncErrors,
monitor: monitorSavedObject,
isInlineScript: Boolean((monitor as MonitorFields)[ConfigKey.SOURCE_INLINE]),
isInlineScript: Boolean((normalizedMonitor as MonitorFields)[ConfigKey.SOURCE_INLINE]),
kibanaVersion: server.kibanaVersion,
})
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,13 @@ export const editSyntheticsMonitorRoute: SyntheticsRestApiRouteFactory = () => (

const validationResult = validateMonitor(editedMonitor as MonitorFields);

if (!validationResult.valid) {
if (!validationResult.valid || !validationResult.decodedMonitor) {
const { reason: message, details, payload } = validationResult;
return response.badRequest({ body: { message, attributes: { details, ...payload } } });
}

const monitorWithRevision = {
...editedMonitor,
...validationResult.decodedMonitor,
revision: (previousMonitor.attributes[ConfigKey.REVISION] || 0) + 1,
};
const formattedMonitor = formatSecrets(monitorWithRevision);
Expand All @@ -102,7 +102,7 @@ export const editSyntheticsMonitorRoute: SyntheticsRestApiRouteFactory = () => (
syntheticsMonitorClient,
savedObjectsClient,
request,
normalizedMonitor: editedMonitor,
normalizedMonitor: validationResult.decodedMonitor,
monitorWithRevision: formattedMonitor,
spaceId,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import * as t from 'io-ts';

import { isLeft } from 'fp-ts/lib/Either';
import { formatErrors } from '@kbn/securitysolution-io-ts-utils';
Expand All @@ -19,6 +20,7 @@ import {
ICMPSimpleFieldsCodec,
MonitorFields,
TCPFieldsCodec,
SyntheticsMonitor,
} from '../../../common/runtime_types';

type MonitorCodecType =
Expand All @@ -39,6 +41,7 @@ export interface ValidationResult {
reason: string;
details: string;
payload: object;
decodedMonitor?: SyntheticsMonitor;
}

/**
Expand All @@ -58,9 +61,10 @@ export function validateMonitor(monitorFields: MonitorFields): ValidationResult
};
}

const codec = monitorTypeToCodecMap[monitorType];
// Cast it to ICMPCodec to satisfy typing. During runtime, correct codec will be used to decode.
const SyntheticsMonitorCodec = monitorTypeToCodecMap[monitorType] as typeof ICMPSimpleFieldsCodec;

if (!codec) {
if (!SyntheticsMonitorCodec) {
return {
valid: false,
reason: `Payload is not a valid monitor object`,
Expand All @@ -69,8 +73,8 @@ export function validateMonitor(monitorFields: MonitorFields): ValidationResult
};
}

// Cast it to ICMPCodec to satisfy typing. During runtime, correct codec will be used to decode.
const decodedMonitor = (codec as typeof ICMPSimpleFieldsCodec).decode(monitorFields);
const ExactSyntheticsMonitorCodec = t.exact(SyntheticsMonitorCodec);
const decodedMonitor = ExactSyntheticsMonitorCodec.decode(monitorFields);

if (isLeft(decodedMonitor)) {
return {
Expand All @@ -81,7 +85,13 @@ export function validateMonitor(monitorFields: MonitorFields): ValidationResult
};
}

return { valid: true, reason: '', details: '', payload: monitorFields };
return {
valid: true,
reason: '',
details: '',
payload: monitorFields,
decodedMonitor: decodedMonitor.right,
};
}

export function validateProjectMonitor(monitorFields: ProjectMonitor): ValidationResult {
Expand Down
Loading