From 10a63990c02195cf1a01937de26ec2fdcdbc3988 Mon Sep 17 00:00:00 2001 From: Patryk Kopycinski Date: Fri, 18 Mar 2022 22:58:46 +0100 Subject: [PATCH 01/13] [Osquery] Add support for osquery pack integration assets --- .../plugins/fleet/common/types/models/epm.ts | 2 + .../integrations/sections/epm/constants.tsx | 6 +- .../services/epm/kibana/assets/install.ts | 3 +- x-pack/plugins/osquery/common/types.ts | 2 + .../osquery/public/assets/constants.ts | 8 + .../public/assets/use_assets_status.ts | 23 ++ .../public/assets/use_import_assets.ts | 43 ++++ .../public/packs/active_state_switch.tsx | 3 +- .../osquery/public/packs/add_pack_button.tsx | 33 +++ .../osquery/public/packs/form/index.tsx | 8 +- .../public/packs/form/queries_field.tsx | 65 +++--- .../public/packs/pack_queries_table.tsx | 38 ++-- x-pack/plugins/osquery/public/packs/types.ts | 10 +- .../public/routes/packs/list/empty_state.tsx | 41 ++++ .../public/routes/packs/list/index.tsx | 57 +++-- .../packs/list/load_integration_assets.tsx | 37 ++++ .../public/routes/packs/list/translations.ts | 30 +++ x-pack/plugins/osquery/server/common/types.ts | 34 +++ .../lib/saved_query/saved_object_mappings.ts | 58 ++++- .../routes/asset/get_assets_status_route.ts | 99 +++++++++ .../osquery/server/routes/asset/index.ts | 16 ++ .../routes/asset/update_assets_route.ts | 200 ++++++++++++++++++ .../osquery/server/routes/asset/utils.ts | 26 +++ x-pack/plugins/osquery/server/routes/index.ts | 2 + .../server/routes/pack/find_pack_route.ts | 8 +- .../server/routes/pack/read_pack_route.ts | 18 +- .../server/routes/pack/update_pack_route.ts | 29 ++- .../plugins/osquery/server/saved_objects.ts | 3 +- 28 files changed, 808 insertions(+), 94 deletions(-) create mode 100644 x-pack/plugins/osquery/public/assets/constants.ts create mode 100644 x-pack/plugins/osquery/public/assets/use_assets_status.ts create mode 100644 x-pack/plugins/osquery/public/assets/use_import_assets.ts create mode 100644 x-pack/plugins/osquery/public/packs/add_pack_button.tsx create mode 100644 x-pack/plugins/osquery/public/routes/packs/list/empty_state.tsx create mode 100644 x-pack/plugins/osquery/public/routes/packs/list/load_integration_assets.tsx create mode 100644 x-pack/plugins/osquery/public/routes/packs/list/translations.ts create mode 100644 x-pack/plugins/osquery/server/common/types.ts create mode 100644 x-pack/plugins/osquery/server/routes/asset/get_assets_status_route.ts create mode 100644 x-pack/plugins/osquery/server/routes/asset/index.ts create mode 100644 x-pack/plugins/osquery/server/routes/asset/update_assets_route.ts create mode 100644 x-pack/plugins/osquery/server/routes/asset/utils.ts diff --git a/x-pack/plugins/fleet/common/types/models/epm.ts b/x-pack/plugins/fleet/common/types/models/epm.ts index dcff9f503bfe0..e746c81a1881a 100644 --- a/x-pack/plugins/fleet/common/types/models/epm.ts +++ b/x-pack/plugins/fleet/common/types/models/epm.ts @@ -74,6 +74,7 @@ export enum KibanaAssetType { securityRule = 'security_rule', mlModule = 'ml_module', tag = 'tag', + osqueryPackAsset = 'osquery_pack_asset', } /* @@ -89,6 +90,7 @@ export enum KibanaSavedObjectType { mlModule = 'ml-module', securityRule = 'security-rule', tag = 'tag', + osqueryPackAsset = 'osquery-pack-asset', } export enum ElasticsearchAssetType { diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/constants.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/constants.tsx index 3d241c668e32b..451ca4b536bf5 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/constants.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/constants.tsx @@ -11,7 +11,7 @@ import { i18n } from '@kbn/i18n'; import type { ServiceName } from '../../types'; import { ElasticsearchAssetType, KibanaAssetType } from '../../types'; -// only allow Kibana assets for the kibana key, ES asssets for elasticsearch, etc +// only allow Kibana assets for the kibana key, ES assets for elasticsearch, etc type ServiceNameToAssetTypes = Record, KibanaAssetType[]> & Record, ElasticsearchAssetType[]>; @@ -62,6 +62,9 @@ export const AssetTitleMap: Record = { security_rule: i18n.translate('xpack.fleet.epm.assetTitles.securityRules', { defaultMessage: 'Security rules', }), + osquery_pack_asset: i18n.translate('xpack.fleet.epm.assetTitles.osqueryPackAsset', { + defaultMessage: 'Osquery packs', + }), ml_module: i18n.translate('xpack.fleet.epm.assetTitles.mlModules', { defaultMessage: 'ML modules', }), @@ -91,6 +94,7 @@ export const AssetIcons: Record = { security_rule: 'securityApp', ml_module: 'mlApp', tag: 'tagApp', + osquery_pack_asset: 'osqueryApp', }; export const ServiceIcons: Record = { diff --git a/x-pack/plugins/fleet/server/services/epm/kibana/assets/install.ts b/x-pack/plugins/fleet/server/services/epm/kibana/assets/install.ts index e76e44476df03..1404dcaa3dca1 100644 --- a/x-pack/plugins/fleet/server/services/epm/kibana/assets/install.ts +++ b/x-pack/plugins/fleet/server/services/epm/kibana/assets/install.ts @@ -53,6 +53,7 @@ const KibanaSavedObjectTypeMapping: Record ArchiveAsset[]> = { @@ -250,7 +251,7 @@ export async function installKibanaSavedObjects({ /* A reference error here means that a saved object reference in the references array cannot be found. This is an error in the package its-self but not a fatal - one. For example a dashboard may still refer to the legacy `metricbeat-*` index + one. For example a dashboard may still refer to the legacy `metricbeat-*` index pattern. We ignore reference errors here so that legacy version of a package can still be installed, but if a warning is logged it should be reported to the integrations team. */ diff --git a/x-pack/plugins/osquery/common/types.ts b/x-pack/plugins/osquery/common/types.ts index f543057d773fe..2d3fc6e972c7c 100644 --- a/x-pack/plugins/osquery/common/types.ts +++ b/x-pack/plugins/osquery/common/types.ts @@ -9,6 +9,7 @@ import { PackagePolicy, PackagePolicyInput, PackagePolicyInputStream } from '../ export const savedQuerySavedObjectType = 'osquery-saved-query'; export const packSavedObjectType = 'osquery-pack'; +export const packAssetSavedObjectType = 'osquery-pack-asset'; export const usageMetricSavedObjectType = 'osquery-manager-usage-metric'; export type SavedObjectType = | 'osquery-saved-query' @@ -68,4 +69,5 @@ export interface OsqueryManagerPackagePolicyInput extends Omit { inputs: OsqueryManagerPackagePolicyInput[]; + read_only?: boolean; } diff --git a/x-pack/plugins/osquery/public/assets/constants.ts b/x-pack/plugins/osquery/public/assets/constants.ts new file mode 100644 index 0000000000000..00b9067d83089 --- /dev/null +++ b/x-pack/plugins/osquery/public/assets/constants.ts @@ -0,0 +1,8 @@ +/* + * 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. + */ + +export const INTEGRATION_ASSETS_STATUS_ID = 'integrationAssetsStatus'; diff --git a/x-pack/plugins/osquery/public/assets/use_assets_status.ts b/x-pack/plugins/osquery/public/assets/use_assets_status.ts new file mode 100644 index 0000000000000..e902c1b94244b --- /dev/null +++ b/x-pack/plugins/osquery/public/assets/use_assets_status.ts @@ -0,0 +1,23 @@ +/* + * 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. + */ + +import { SavedObject } from 'kibana/public'; +import { useQuery } from 'react-query'; +import { useKibana } from '../common/lib/kibana'; +import { INTEGRATION_ASSETS_STATUS_ID } from './constants'; + +export const useAssetsStatus = () => { + const { http } = useKibana().services; + + return useQuery<{ install: SavedObject[]; update: SavedObject[]; up_to_date: SavedObject[] }>( + [INTEGRATION_ASSETS_STATUS_ID], + () => http.get('/internal/osquery/assets'), + { + keepPreviousData: true, + } + ); +}; diff --git a/x-pack/plugins/osquery/public/assets/use_import_assets.ts b/x-pack/plugins/osquery/public/assets/use_import_assets.ts new file mode 100644 index 0000000000000..5e2a966a54e62 --- /dev/null +++ b/x-pack/plugins/osquery/public/assets/use_import_assets.ts @@ -0,0 +1,43 @@ +/* + * 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. + */ + +import { useMutation, useQueryClient } from 'react-query'; +import { i18n } from '@kbn/i18n'; +import { useKibana } from '../common/lib/kibana'; +import { useErrorToast } from '../common/hooks/use_error_toast'; +import { PACKS_ID } from '../packs/constants'; +import { INTEGRATION_ASSETS_STATUS_ID } from './constants'; + +export const useImportAssets = () => { + const queryClient = useQueryClient(); + const { + http, + notifications: { toasts }, + } = useKibana().services; + const setErrorToast = useErrorToast(); + + return useMutation( + () => + // eslint-disable-next-line @typescript-eslint/no-explicit-any + http.post('/internal/osquery/assets/update'), + { + onSuccess: () => { + setErrorToast(); + queryClient.invalidateQueries(PACKS_ID); + queryClient.invalidateQueries(INTEGRATION_ASSETS_STATUS_ID); + toasts.addSuccess( + i18n.translate('xpack.osquery.integrationAssetsImport.successToastMessageText', { + defaultMessage: 'Successfully imported prebuilt assets', + }) + ); + }, + onError: (error) => { + setErrorToast(error); + }, + } + ); +}; diff --git a/x-pack/plugins/osquery/public/packs/active_state_switch.tsx b/x-pack/plugins/osquery/public/packs/active_state_switch.tsx index da1581f5f7bfe..1dbb145430a3e 100644 --- a/x-pack/plugins/osquery/public/packs/active_state_switch.tsx +++ b/x-pack/plugins/osquery/public/packs/active_state_switch.tsx @@ -17,6 +17,7 @@ import { useAgentPolicies } from '../agent_policies/use_agent_policies'; import { ConfirmDeployAgentPolicyModal } from './form/confirmation_modal'; import { useErrorToast } from '../common/hooks/use_error_toast'; import { useUpdatePack } from './use_update_pack'; +import { PACKS_ID } from './constants'; const StyledEuiLoadingSpinner = styled(EuiLoadingSpinner)` margin-right: ${({ theme }) => theme.eui.paddingSizes.s}; @@ -55,7 +56,7 @@ const ActiveStateSwitchComponent: React.FC = ({ item }) options: { // @ts-expect-error update types onSuccess: (response) => { - queryClient.invalidateQueries('packList'); + queryClient.invalidateQueries(PACKS_ID); setErrorToast(); toasts.addSuccess( response.attributes.enabled diff --git a/x-pack/plugins/osquery/public/packs/add_pack_button.tsx b/x-pack/plugins/osquery/public/packs/add_pack_button.tsx new file mode 100644 index 0000000000000..1473cee6e7aa2 --- /dev/null +++ b/x-pack/plugins/osquery/public/packs/add_pack_button.tsx @@ -0,0 +1,33 @@ +/* + * 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. + */ + +import React from 'react'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { EuiButton, EuiButtonProps } from '@elastic/eui'; +import { useKibana, useRouterNavigate } from '../common/lib/kibana'; + +interface AddPackButtonComponentProps { + fill?: EuiButtonProps['fill']; +} + +const AddPackButtonComponent: React.FC = ({ fill = true }) => { + const permissions = useKibana().services.application.capabilities.osquery; + const newQueryLinkProps = useRouterNavigate('packs/add'); + + return ( + + + + ); +}; + +export const AddPackButton = React.memo(AddPackButtonComponent); diff --git a/x-pack/plugins/osquery/public/packs/form/index.tsx b/x-pack/plugins/osquery/public/packs/form/index.tsx index b68336e6705be..f327239560345 100644 --- a/x-pack/plugins/osquery/public/packs/form/index.tsx +++ b/x-pack/plugins/osquery/public/packs/form/index.tsx @@ -51,6 +51,7 @@ interface PackFormProps { } const PackFormComponent: React.FC = ({ defaultValue, editMode = false }) => { + const isReadOnly = !!defaultValue?.read_only; const [showConfirmationModal, setShowConfirmationModal] = useState(false); const handleHideConfirmationModal = useCallback(() => setShowConfirmationModal(false), []); @@ -183,18 +184,20 @@ const PackFormComponent: React.FC = ({ defaultValue, editMode = f setShowConfirmationModal(false); }, [submit]); + const euiFieldProps = useMemo(() => ({ isDisabled: isReadOnly }), [isReadOnly]); + return ( <>
- + - + @@ -213,6 +216,7 @@ const PackFormComponent: React.FC = ({ defaultValue, editMode = f path="queries" component={QueriesField} handleNameChange={handleNameChange} + euiFieldProps={euiFieldProps} /> diff --git a/x-pack/plugins/osquery/public/packs/form/queries_field.tsx b/x-pack/plugins/osquery/public/packs/form/queries_field.tsx index 2ae946a0f2e8f..8e049e3fc5fc1 100644 --- a/x-pack/plugins/osquery/public/packs/form/queries_field.tsx +++ b/x-pack/plugins/osquery/public/packs/form/queries_field.tsx @@ -6,7 +6,7 @@ */ import { isEmpty, findIndex, forEach, pullAt, pullAllBy, pickBy } from 'lodash'; -import { EuiFlexGroup, EuiFlexItem, EuiButton, EuiSpacer } from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiButton, EuiSpacer, EuiComboBoxProps } from '@elastic/eui'; import { produce } from 'immer'; import React, { useCallback, useMemo, useState } from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; @@ -21,9 +21,15 @@ import { getSupportedPlatforms } from '../queries/platforms/helpers'; interface QueriesFieldProps { handleNameChange: (name: string) => void; field: FieldHook>>; + euiFieldProps: EuiComboBoxProps<{}>; } -const QueriesFieldComponent: React.FC = ({ field, handleNameChange }) => { +const QueriesFieldComponent: React.FC = ({ + field, + handleNameChange, + euiFieldProps, +}) => { + const isReadOnly = !!euiFieldProps?.isDisabled; const [showAddQueryFlyout, setShowAddQueryFlyout] = useState(false); const [showEditQueryFlyout, setShowEditQueryFlyout] = useState(-1); const [tableSelectedItems, setTableSelectedItems] = useState< @@ -174,34 +180,39 @@ const QueriesFieldComponent: React.FC = ({ field, handleNameC return ( <> - - - {!tableSelectedItems.length ? ( - - - - ) : ( - - - - )} - - - + {!isReadOnly && ( + <> + + + {!tableSelectedItems.length ? ( + + + + ) : ( + + + + )} + + + + + )} {field.value?.length ? ( = ({ field, handleNameC /> ) : null} - {} + {!isReadOnly && } {showAddQueryFlyout && ( void; onEditClick?: (item: OsqueryManagerPackagePolicyInputStream) => void; selectedItems?: OsqueryManagerPackagePolicyInputStream[]; @@ -23,6 +24,7 @@ export interface PackQueriesTableProps { const PackQueriesTableComponent: React.FC = ({ data, + isReadOnly, onDeleteClick, onEditClick, selectedItems, @@ -127,22 +129,27 @@ const PackQueriesTableComponent: React.FC = ({ }), render: renderVersionColumn, }, - { - name: i18n.translate('xpack.osquery.pack.queriesTable.actionsColumnTitle', { - defaultMessage: 'Actions', - }), - width: '120px', - actions: [ - { - render: renderEditAction, - }, - { - render: renderDeleteAction, - }, - ], - }, + ...(!isReadOnly + ? [ + { + name: i18n.translate('xpack.osquery.pack.queriesTable.actionsColumnTitle', { + defaultMessage: 'Actions', + }), + width: '120px', + actions: [ + { + render: renderEditAction, + }, + { + render: renderDeleteAction, + }, + ], + }, + ] + : []), ], [ + isReadOnly, renderDeleteAction, renderEditAction, renderPlatformColumn, @@ -177,8 +184,7 @@ const PackQueriesTableComponent: React.FC = ({ itemId={itemId} columns={columns} sorting={sorting} - selection={selection} - isSelectable + {...(!isReadOnly ? { selection, isSelectable: true } : {})} /> ); }; diff --git a/x-pack/plugins/osquery/public/packs/types.ts b/x-pack/plugins/osquery/public/packs/types.ts index 30cae97b006bb..07f4149cab1ef 100644 --- a/x-pack/plugins/osquery/public/packs/types.ts +++ b/x-pack/plugins/osquery/public/packs/types.ts @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { SavedObject } from 'kibana/server'; +import { SavedObject } from 'kibana/public'; export interface IQueryPayload { attributes?: { @@ -16,7 +16,13 @@ export interface IQueryPayload { export type PackSavedObject = SavedObject<{ name: string; description: string | undefined; - queries: Array>; + queries: Array<{ + id: string; + name: string; + interval: number; + ecs_mapping: Record; + }>; + version?: number; enabled: boolean | undefined; created_at: string; created_by: string | undefined; diff --git a/x-pack/plugins/osquery/public/routes/packs/list/empty_state.tsx b/x-pack/plugins/osquery/public/routes/packs/list/empty_state.tsx new file mode 100644 index 0000000000000..2cd3cbc2d4009 --- /dev/null +++ b/x-pack/plugins/osquery/public/routes/packs/list/empty_state.tsx @@ -0,0 +1,41 @@ +/* + * 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. + */ + +import React, { useMemo } from 'react'; +import { EuiFlexGroup, EuiFlexItem, EuiEmptyPrompt } from '@elastic/eui'; +import { AddPackButton } from '../../../packs/add_pack_button'; +import { OsqueryIcon } from '../../../components/osquery_icon'; +import { LoadIntegrationAssetsButton } from './load_integration_assets'; +import { PRE_BUILT_TITLE, PRE_BUILT_MSG } from './translations'; + +const PacksTableEmptyStateComponent = () => { + const actions = useMemo( + () => ( + + + + + + + + + ), + [] + ); + + return ( + } + color="transparent" + title={

{PRE_BUILT_TITLE}

} + body={

{PRE_BUILT_MSG}

} + actions={actions} + /> + ); +}; + +export const PacksTableEmptyState = React.memo(PacksTableEmptyStateComponent); diff --git a/x-pack/plugins/osquery/public/routes/packs/list/index.tsx b/x-pack/plugins/osquery/public/routes/packs/list/index.tsx index c4b9f94b32287..7ed81a5d87a01 100644 --- a/x-pack/plugins/osquery/public/routes/packs/list/index.tsx +++ b/x-pack/plugins/osquery/public/routes/packs/list/index.tsx @@ -5,17 +5,25 @@ * 2.0. */ -import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiText, EuiLoadingContent } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import React, { useMemo } from 'react'; -import { useKibana, useRouterNavigate } from '../../../common/lib/kibana'; import { WithHeaderLayout } from '../../../components/layouts'; import { PacksTable } from '../../../packs/packs_table'; +import { AddPackButton } from '../../../packs/add_pack_button'; +import { LoadIntegrationAssetsButton } from './load_integration_assets'; +import { PacksTableEmptyState } from './empty_state'; +import { useAssetsStatus } from '../../../assets/use_assets_status'; +import { usePacks } from '../../../packs/use_packs'; const PacksPageComponent = () => { - const permissions = useKibana().services.application.capabilities.osquery; - const newQueryLinkProps = useRouterNavigate('packs/add'); + const { data: assetsData, isLoading: isLoadingAssetsStatus } = useAssetsStatus(); + const { data: packsData, isLoading: isLoadingPacks } = usePacks({}); + const showEmptyState = useMemo( + () => !packsData?.total && assetsData?.install?.length, + [assetsData?.install?.length, packsData?.total] + ); const LeftColumn = useMemo( () => ( @@ -44,24 +52,37 @@ const PacksPageComponent = () => { const RightColumn = useMemo( () => ( - - - + + + + + + + + ), - [newQueryLinkProps, permissions.writePacks] + [] ); + const Content = useMemo(() => { + if (isLoadingAssetsStatus || isLoadingPacks) { + return ; + } + + if (showEmptyState) { + return ; + } + + return ; + }, [isLoadingAssetsStatus, isLoadingPacks, showEmptyState]); + return ( - - + + {Content} ); }; diff --git a/x-pack/plugins/osquery/public/routes/packs/list/load_integration_assets.tsx b/x-pack/plugins/osquery/public/routes/packs/list/load_integration_assets.tsx new file mode 100644 index 0000000000000..e86496a0ccca1 --- /dev/null +++ b/x-pack/plugins/osquery/public/routes/packs/list/load_integration_assets.tsx @@ -0,0 +1,37 @@ +/* + * 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. + */ + +import React, { useCallback } from 'react'; +import { EuiButton, EuiButtonProps } from '@elastic/eui'; +import { useImportAssets } from '../../../assets/use_import_assets'; +import { useAssetsStatus } from '../../../assets/use_assets_status'; +import { LOAD_PREBUILT_PACKS_BUTTON } from './translations'; + +interface LoadIntegrationAssetsButtonProps { + fill?: EuiButtonProps['fill']; +} + +const LoadIntegrationAssetsButtonComponent: React.FC = ({ + fill, +}) => { + const { data } = useAssetsStatus(); + const { isLoading, mutateAsync } = useImportAssets(); + + const handleClick = useCallback(() => mutateAsync(), [mutateAsync]); + + if (data?.install.length || data?.update.length) { + return ( + + {LOAD_PREBUILT_PACKS_BUTTON} + + ); + } + + return null; +}; + +export const LoadIntegrationAssetsButton = React.memo(LoadIntegrationAssetsButtonComponent); diff --git a/x-pack/plugins/osquery/public/routes/packs/list/translations.ts b/x-pack/plugins/osquery/public/routes/packs/list/translations.ts new file mode 100644 index 0000000000000..115f713e6227a --- /dev/null +++ b/x-pack/plugins/osquery/public/routes/packs/list/translations.ts @@ -0,0 +1,30 @@ +/* + * 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. + */ + +import { i18n } from '@kbn/i18n'; + +export const PRE_BUILT_TITLE = i18n.translate( + 'xpack.osquery.packList.prePackagedPacks.emptyPromptTitle', + { + defaultMessage: 'Load Elastic prebuilt packs', + } +); + +export const LOAD_PREBUILT_PACKS_BUTTON = i18n.translate( + 'xpack.osquery.packList.prePackagedPacks.loadButtonLabel', + { + defaultMessage: 'Load Elastic prebuilt packs', + } +); + +export const PRE_BUILT_MSG = i18n.translate( + 'xpack.osquery.packList.prePackagedPacks.emptyPromptTitle.emptyPromptMessage', + { + defaultMessage: + 'A pack is a set of queries that you can schedule. Load prebuilt packs or create your own.', + } +); diff --git a/x-pack/plugins/osquery/server/common/types.ts b/x-pack/plugins/osquery/server/common/types.ts new file mode 100644 index 0000000000000..3021cadb6cae3 --- /dev/null +++ b/x-pack/plugins/osquery/server/common/types.ts @@ -0,0 +1,34 @@ +/* + * 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. + */ + +import { SavedObject } from 'kibana/server'; + +export interface IQueryPayload { + attributes?: { + name: string; + id: string; + }; +} + +export interface PackSavedObjectAttributes { + name: string; + description: string | undefined; + queries: Array<{ + id: string; + name: string; + interval: number; + ecs_mapping: Record; + }>; + version?: number; + enabled: boolean | undefined; + created_at: string; + created_by: string | undefined; + updated_at: string; + updated_by: string | undefined; +} + +export type PackSavedObject = SavedObject; diff --git a/x-pack/plugins/osquery/server/lib/saved_query/saved_object_mappings.ts b/x-pack/plugins/osquery/server/lib/saved_query/saved_object_mappings.ts index bed2ba2efe688..274ab89355b47 100644 --- a/x-pack/plugins/osquery/server/lib/saved_query/saved_object_mappings.ts +++ b/x-pack/plugins/osquery/server/lib/saved_query/saved_object_mappings.ts @@ -7,7 +7,11 @@ import { produce } from 'immer'; import { SavedObjectsType } from '../../../../../../src/core/server'; -import { savedQuerySavedObjectType, packSavedObjectType } from '../../../common/types'; +import { + savedQuerySavedObjectType, + packSavedObjectType, + packAssetSavedObjectType, +} from '../../../common/types'; export const savedQuerySavedObjectMappings: SavedObjectsType['mappings'] = { properties: { @@ -87,6 +91,9 @@ export const packSavedObjectMappings: SavedObjectsType['mappings'] = { enabled: { type: 'boolean', }, + version: { + type: 'long', + }, queries: { properties: { id: { @@ -137,3 +144,52 @@ export const packType: SavedObjectsType = { }), }, }; + +export const packAssetSavedObjectMappings: SavedObjectsType['mappings'] = { + dynamic: false, + properties: { + description: { + type: 'text', + }, + name: { + type: 'text', + }, + version: { + type: 'long', + }, + queries: { + properties: { + id: { + type: 'keyword', + }, + query: { + type: 'text', + }, + interval: { + type: 'text', + }, + platform: { + type: 'keyword', + }, + version: { + type: 'keyword', + }, + ecs_mapping: { + type: 'object', + enabled: false, + }, + }, + }, + }, +}; + +export const packAssetType: SavedObjectsType = { + name: packAssetSavedObjectType, + hidden: false, + management: { + importableAndExportable: true, + visibleInManagement: false, + }, + namespaceType: 'agnostic', + mappings: packAssetSavedObjectMappings, +}; diff --git a/x-pack/plugins/osquery/server/routes/asset/get_assets_status_route.ts b/x-pack/plugins/osquery/server/routes/asset/get_assets_status_route.ts new file mode 100644 index 0000000000000..539f7083f0f2e --- /dev/null +++ b/x-pack/plugins/osquery/server/routes/asset/get_assets_status_route.ts @@ -0,0 +1,99 @@ +/* + * 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. + */ + +import { filter } from 'lodash/fp'; +import { schema } from '@kbn/config-schema'; +import { asyncForEach } from '@kbn/std'; +import { IRouter } from 'kibana/server'; + +import { packAssetSavedObjectType, packSavedObjectType } from '../../../common/types'; +import { PLUGIN_ID, OSQUERY_INTEGRATION_NAME } from '../../../common'; +import { OsqueryAppContext } from '../../lib/osquery_app_context_services'; +import { KibanaAssetReference } from '../../../../fleet/common'; + +export const getAssetsStatusRoute = (router: IRouter, osqueryContext: OsqueryAppContext) => { + router.get( + { + path: '/internal/osquery/assets', + validate: { + params: schema.object({}, { unknowns: 'allow' }), + }, + options: { tags: [`access:${PLUGIN_ID}-writePacks`] }, + }, + async (context, request, response) => { + const savedObjectsClient = context.core.savedObjects.client; + + let installation; + + try { + installation = await osqueryContext.service + .getPackageService() + ?.asInternalUser?.getInstallation(OSQUERY_INTEGRATION_NAME); + } catch (err) { + return response.notFound(); + } + + if (installation) { + const installationPackAssets = filter( + ['type', packAssetSavedObjectType], + installation.installed_kibana + ); + + const install: KibanaAssetReference[] = []; + const update: KibanaAssetReference[] = []; + const upToDate: KibanaAssetReference[] = []; + + await asyncForEach(installationPackAssets, async (installationPackAsset) => { + const isInstalled = await savedObjectsClient.find<{ version: number }>({ + type: packSavedObjectType, + hasReference: { + type: installationPackAsset.type, + id: installationPackAsset.id, + }, + }); + + if (!isInstalled.total) { + install.push(installationPackAsset); + } + + if (isInstalled.total) { + const packAssetSavedObject = await savedObjectsClient.get<{ version: number }>( + installationPackAsset.type, + installationPackAsset.id + ); + + if (packAssetSavedObject) { + if ( + !packAssetSavedObject.attributes.version || + !isInstalled.saved_objects[0].attributes.version + ) { + install.push(installationPackAsset); + } else if ( + packAssetSavedObject.attributes.version > + isInstalled.saved_objects[0].attributes.version + ) { + update.push(installationPackAsset); + } else { + upToDate.push(installationPackAsset); + } + } + } + }); + + return response.ok({ + body: { + install, + update, + upToDate, + }, + }); + } + + return response.ok(); + } + ); +}; diff --git a/x-pack/plugins/osquery/server/routes/asset/index.ts b/x-pack/plugins/osquery/server/routes/asset/index.ts new file mode 100644 index 0000000000000..d232d499f9bd0 --- /dev/null +++ b/x-pack/plugins/osquery/server/routes/asset/index.ts @@ -0,0 +1,16 @@ +/* + * 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. + */ + +import { IRouter } from '../../../../../../src/core/server'; +import { getAssetsStatusRoute } from './get_assets_status_route'; +import { updateAssetsRoute } from './update_assets_route'; +import { OsqueryAppContext } from '../../lib/osquery_app_context_services'; + +export const initAssetRoutes = (router: IRouter, context: OsqueryAppContext) => { + getAssetsStatusRoute(router, context); + updateAssetsRoute(router, context); +}; diff --git a/x-pack/plugins/osquery/server/routes/asset/update_assets_route.ts b/x-pack/plugins/osquery/server/routes/asset/update_assets_route.ts new file mode 100644 index 0000000000000..8cafdc11bd124 --- /dev/null +++ b/x-pack/plugins/osquery/server/routes/asset/update_assets_route.ts @@ -0,0 +1,200 @@ +/* + * 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. + */ + +import moment from 'moment-timezone'; +import { filter, omit } from 'lodash'; +import { schema } from '@kbn/config-schema'; +import { asyncForEach } from '@kbn/std'; +import deepmerge from 'deepmerge'; + +import { packAssetSavedObjectType, packSavedObjectType } from '../../../common/types'; +import { combineMerge } from './utils'; +import { PLUGIN_ID, OSQUERY_INTEGRATION_NAME } from '../../../common'; +import { IRouter } from '../../../../../../src/core/server'; +import { OsqueryAppContext } from '../../lib/osquery_app_context_services'; +import { convertSOQueriesToPack, convertPackQueriesToSO } from '../pack/utils'; +import { KibanaAssetReference } from '../../../../fleet/common'; +import { PackSavedObjectAttributes } from '../../common/types'; + +export const updateAssetsRoute = (router: IRouter, osqueryContext: OsqueryAppContext) => { + router.post( + { + path: '/internal/osquery/assets/update', + validate: { + params: schema.object({}, { unknowns: 'allow' }), + }, + options: { tags: [`access:${PLUGIN_ID}-all`] }, + }, + async (context, request, response) => { + const savedObjectsClient = context.core.savedObjects.client; + const currentUser = await osqueryContext.security.authc.getCurrentUser(request)?.username; + + let installation; + + try { + installation = await osqueryContext.service + .getPackageService() + ?.asInternalUser?.getInstallation(OSQUERY_INTEGRATION_NAME); + } catch (err) { + return response.notFound(); + } + + if (installation) { + const installationPackAssets = filter(installation.installed_kibana, [ + 'type', + packAssetSavedObjectType, + ]); + + const install: KibanaAssetReference[] = []; + const update: KibanaAssetReference[] = []; + const upToDate: KibanaAssetReference[] = []; + + await asyncForEach(installationPackAssets, async (installationPackAsset) => { + const isInstalled = await savedObjectsClient.find<{ version: number }>({ + type: packSavedObjectType, + hasReference: { + type: installationPackAsset.type, + id: installationPackAsset.id, + }, + }); + + if (!isInstalled.total) { + install.push(installationPackAsset); + } + + if (isInstalled.total) { + const packAssetSavedObject = await savedObjectsClient.get<{ version: number }>( + installationPackAsset.type, + installationPackAsset.id + ); + + if (packAssetSavedObject) { + if ( + !packAssetSavedObject.attributes.version || + !isInstalled.saved_objects[0].attributes.version + ) { + install.push(installationPackAsset); + } else if ( + packAssetSavedObject.attributes.version > + isInstalled.saved_objects[0].attributes.version + ) { + update.push(installationPackAsset); + } else { + upToDate.push(installationPackAsset); + } + } + } + }); + + await Promise.all([ + ...install.map(async (installationPackAsset) => { + const packAssetSavedObject = await savedObjectsClient.get( + installationPackAsset.type, + installationPackAsset.id + ); + + const conflictingEntries = await savedObjectsClient.find({ + type: packSavedObjectType, + filter: `${packSavedObjectType}.attributes.name: "${packAssetSavedObject.attributes.name}"`, + }); + + const name = conflictingEntries.saved_objects.length + ? `${packAssetSavedObject.attributes.name}-elastic` + : packAssetSavedObject.attributes.name; + + await savedObjectsClient.create( + packSavedObjectType, + { + name, + description: packAssetSavedObject.attributes.description, + queries: packAssetSavedObject.attributes.queries, + enabled: false, + created_at: moment().toISOString(), + created_by: currentUser, + updated_at: moment().toISOString(), + updated_by: currentUser, + version: packAssetSavedObject.attributes.version ?? 1, + }, + { + references: [ + ...packAssetSavedObject.references, + { + type: packAssetSavedObject.type, + id: packAssetSavedObject.id, + name: packAssetSavedObject.attributes.name, + }, + ], + refresh: 'wait_for', + } + ); + }), + ...update.map(async (updatePackAsset) => { + const packAssetSavedObject = await savedObjectsClient.get( + updatePackAsset.type, + updatePackAsset.id + ); + + const packSavedObjectsResponse = + await savedObjectsClient.find({ + type: 'osquery-pack', + hasReference: { + type: updatePackAsset.type, + id: updatePackAsset.id, + }, + }); + + if (packSavedObjectsResponse.total) { + await savedObjectsClient.update( + packSavedObjectsResponse.saved_objects[0].type, + packSavedObjectsResponse.saved_objects[0].id, + deepmerge.all([ + omit(packSavedObjectsResponse.saved_objects[0].attributes, 'queries'), + omit(packAssetSavedObject.attributes, 'queries'), + { + updated_at: moment().toISOString(), + updated_by: currentUser, + queries: convertPackQueriesToSO( + deepmerge( + convertSOQueriesToPack( + packSavedObjectsResponse.saved_objects[0].attributes.queries + ), + convertSOQueriesToPack(packAssetSavedObject.attributes.queries), + { + arrayMerge: combineMerge, + } + ) + ), + }, + { + arrayMerge: combineMerge, + }, + ]), + { refresh: 'wait_for' } + ); + } + }), + ]); + + return response.ok({ + body: { + install, + update, + upToDate, + }, + }); + } + + return response.ok({ + body: { + install: 0, + update: 0, + upToDate: 0, + }, + }); + } + ); +}; diff --git a/x-pack/plugins/osquery/server/routes/asset/utils.ts b/x-pack/plugins/osquery/server/routes/asset/utils.ts new file mode 100644 index 0000000000000..4ad80c924920d --- /dev/null +++ b/x-pack/plugins/osquery/server/routes/asset/utils.ts @@ -0,0 +1,26 @@ +/* + * 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. + */ + +import deepmerge from 'deepmerge'; + +// https://www.npmjs.com/package/deepmerge#arraymerge-example-combine-arrays +// @ts-expect-error update types +export const combineMerge = (target, source, options) => { + const destination = target.slice(); + + // @ts-expect-error update types + source.forEach((item, index) => { + if (typeof destination[index] === 'undefined') { + destination[index] = options.cloneUnlessOtherwiseSpecified(item, options); + } else if (options.isMergeableObject(item)) { + destination[index] = deepmerge(target[index], item, options); + } else if (target.indexOf(item) === -1) { + destination.push(item); + } + }); + return destination; +}; diff --git a/x-pack/plugins/osquery/server/routes/index.ts b/x-pack/plugins/osquery/server/routes/index.ts index b32f0c5578207..5eb35f2a444a8 100644 --- a/x-pack/plugins/osquery/server/routes/index.ts +++ b/x-pack/plugins/osquery/server/routes/index.ts @@ -13,6 +13,7 @@ import { initStatusRoutes } from './status'; import { initFleetWrapperRoutes } from './fleet_wrapper'; import { initPackRoutes } from './pack'; import { initPrivilegesCheckRoutes } from './privileges_check'; +import { initAssetRoutes } from './asset'; export const defineRoutes = (router: IRouter, context: OsqueryAppContext) => { initActionRoutes(router, context); @@ -21,4 +22,5 @@ export const defineRoutes = (router: IRouter, context: OsqueryAppContext) => { initFleetWrapperRoutes(router, context); initPrivilegesCheckRoutes(router, context); initSavedQueryRoutes(router, context); + initAssetRoutes(router, context); }; diff --git a/x-pack/plugins/osquery/server/routes/pack/find_pack_route.ts b/x-pack/plugins/osquery/server/routes/pack/find_pack_route.ts index 12ca65143f587..4f09ad1dcffbe 100644 --- a/x-pack/plugins/osquery/server/routes/pack/find_pack_route.ts +++ b/x-pack/plugins/osquery/server/routes/pack/find_pack_route.ts @@ -13,6 +13,7 @@ import { IRouter } from '../../../../../../src/core/server'; import { packSavedObjectType } from '../../../common/types'; import { OsqueryAppContext } from '../../lib/osquery_app_context_services'; import { PLUGIN_ID } from '../../../common'; +import { PackSavedObjectAttributes } from '../../common/types'; // eslint-disable-next-line @typescript-eslint/no-unused-vars export const findPackRoute = (router: IRouter, osqueryContext: OsqueryAppContext) => { @@ -35,12 +36,7 @@ export const findPackRoute = (router: IRouter, osqueryContext: OsqueryAppContext async (context, request, response) => { const savedObjectsClient = context.core.savedObjects.client; - const soClientResponse = await savedObjectsClient.find<{ - name: string; - description: string; - queries: Array<{ name: string; interval: number }>; - policy_ids: string[]; - }>({ + const soClientResponse = await savedObjectsClient.find({ type: packSavedObjectType, page: parseInt(request.query.pageIndex ?? '0', 10) + 1, perPage: request.query.pageSize ?? 20, diff --git a/x-pack/plugins/osquery/server/routes/pack/read_pack_route.ts b/x-pack/plugins/osquery/server/routes/pack/read_pack_route.ts index 066938603a2d6..a181b4c52a730 100644 --- a/x-pack/plugins/osquery/server/routes/pack/read_pack_route.ts +++ b/x-pack/plugins/osquery/server/routes/pack/read_pack_route.ts @@ -7,6 +7,7 @@ import { filter, map } from 'lodash'; import { schema } from '@kbn/config-schema'; +import { PackSavedObjectAttributes } from '../../common/types'; import { PLUGIN_ID } from '../../../common'; import { AGENT_POLICY_SAVED_OBJECT_TYPE } from '../../../../fleet/common'; @@ -30,18 +31,14 @@ export const readPackRoute = (router: IRouter, osqueryContext: OsqueryAppContext async (context, request, response) => { const savedObjectsClient = context.core.savedObjects.client; - const { attributes, references, ...rest } = await savedObjectsClient.get<{ - name: string; - description: string; - queries: Array<{ - id: string; - name: string; - interval: number; - ecs_mapping: Record; - }>; - }>(packSavedObjectType, request.params.id); + const { attributes, references, ...rest } = + await savedObjectsClient.get( + packSavedObjectType, + request.params.id + ); const policyIds = map(filter(references, ['type', AGENT_POLICY_SAVED_OBJECT_TYPE]), 'id'); + const osqueryPackAssetReference = !!filter(references, ['type', 'osquery-pack-asset']); return response.ok({ body: { @@ -49,6 +46,7 @@ export const readPackRoute = (router: IRouter, osqueryContext: OsqueryAppContext ...attributes, queries: convertSOQueriesToPack(attributes.queries), policy_ids: policyIds, + read_only: attributes.version !== undefined && osqueryPackAssetReference, }, }); } diff --git a/x-pack/plugins/osquery/server/routes/pack/update_pack_route.ts b/x-pack/plugins/osquery/server/routes/pack/update_pack_route.ts index b2cff1b769d1c..d30a44665cc1f 100644 --- a/x-pack/plugins/osquery/server/routes/pack/update_pack_route.ts +++ b/x-pack/plugins/osquery/server/routes/pack/update_pack_route.ts @@ -22,6 +22,7 @@ import { OsqueryAppContext } from '../../lib/osquery_app_context_services'; import { PLUGIN_ID } from '../../../common'; import { convertSOQueriesToPack, convertPackQueriesToSO } from './utils'; import { getInternalSavedObjectsClient } from '../../usage/collector'; +import { PackSavedObjectAttributes } from '../../common/types'; export const updatePackRoute = (router: IRouter, osqueryContext: OsqueryAppContext) => { router.put( @@ -87,14 +88,17 @@ export const updatePackRoute = (router: IRouter, osqueryContext: OsqueryAppConte ); if (name) { - const conflictingEntries = await savedObjectsClient.find({ + const conflictingEntries = await savedObjectsClient.find({ type: packSavedObjectType, filter: `${packSavedObjectType}.attributes.name: "${name}"`, }); if ( - filter(conflictingEntries.saved_objects, (packSO) => packSO.id !== currentPackSO.id) - .length + filter( + conflictingEntries.saved_objects, + (packSO) => + packSO.id !== currentPackSO.id && packSO.attributes.name.length === name.length + ) ) { return response.conflict({ body: `Pack with name "${name}" already exists.` }); } @@ -116,6 +120,11 @@ export const updatePackRoute = (router: IRouter, osqueryContext: OsqueryAppConte : {}; const agentPolicyIds = Object.keys(agentPolicies); + const nonAgentPolicyReferences = filter( + currentPackSO.references, + (reference) => reference.type !== AGENT_POLICY_SAVED_OBJECT_TYPE + ); + await savedObjectsClient.update( packSavedObjectType, request.params.id, @@ -130,14 +139,18 @@ export const updatePackRoute = (router: IRouter, osqueryContext: OsqueryAppConte policy_ids ? { refresh: 'wait_for', - references: policy_ids.map((id) => ({ - id, - name: agentPolicies[id].name, - type: AGENT_POLICY_SAVED_OBJECT_TYPE, - })), + references: [ + ...nonAgentPolicyReferences, + ...policy_ids.map((id) => ({ + id, + name: agentPolicies[id].name, + type: AGENT_POLICY_SAVED_OBJECT_TYPE, + })), + ], } : { refresh: 'wait_for', + references: nonAgentPolicyReferences, } ); diff --git a/x-pack/plugins/osquery/server/saved_objects.ts b/x-pack/plugins/osquery/server/saved_objects.ts index 16a1f2efb7e9d..3080c728a4d3c 100644 --- a/x-pack/plugins/osquery/server/saved_objects.ts +++ b/x-pack/plugins/osquery/server/saved_objects.ts @@ -7,11 +7,12 @@ import { CoreSetup } from '../../../../src/core/server'; -import { savedQueryType, packType } from './lib/saved_query/saved_object_mappings'; +import { savedQueryType, packType, packAssetType } from './lib/saved_query/saved_object_mappings'; import { usageMetricType } from './routes/usage/saved_object_mappings'; export const initSavedObjects = (savedObjects: CoreSetup['savedObjects']) => { savedObjects.registerType(usageMetricType); savedObjects.registerType(savedQueryType); savedObjects.registerType(packType); + savedObjects.registerType(packAssetType); }; From 0e1709c44db651fbd3f47f51a6a84e5a404f5078 Mon Sep 17 00:00:00 2001 From: Patryk Kopycinski Date: Sun, 20 Mar 2022 21:27:29 +0100 Subject: [PATCH 02/13] fix types --- .../migrations/integration_tests/type_registrations.test.ts | 1 + .../fleet/.storybook/context/fixtures/integration.nginx.ts | 1 + .../fleet/.storybook/context/fixtures/integration.okta.ts | 1 + .../fleet/common/services/package_to_package_policy.test.ts | 1 + .../sections/epm/components/assets_facet_group.stories.tsx | 1 + .../services/package_policies_to_agent_permissions.test.ts | 4 ++++ 6 files changed, 9 insertions(+) diff --git a/src/core/server/saved_objects/migrations/integration_tests/type_registrations.test.ts b/src/core/server/saved_objects/migrations/integration_tests/type_registrations.test.ts index 844f57c8bf5c5..7f8d10b50edf5 100644 --- a/src/core/server/saved_objects/migrations/integration_tests/type_registrations.test.ts +++ b/src/core/server/saved_objects/migrations/integration_tests/type_registrations.test.ts @@ -75,6 +75,7 @@ const previouslyRegisteredTypes = [ 'ml-telemetry', 'monitoring-telemetry', 'osquery-pack', + 'osquery-pack-asset', 'osquery-saved-query', 'osquery-usage-metric', 'osquery-manager-usage-metric', diff --git a/x-pack/plugins/fleet/.storybook/context/fixtures/integration.nginx.ts b/x-pack/plugins/fleet/.storybook/context/fixtures/integration.nginx.ts index 6f48b15158f8d..c2c4a1caaab69 100644 --- a/x-pack/plugins/fleet/.storybook/context/fixtures/integration.nginx.ts +++ b/x-pack/plugins/fleet/.storybook/context/fixtures/integration.nginx.ts @@ -253,6 +253,7 @@ export const item: GetInfoResponse['item'] = { map: [], security_rule: [], tag: [], + osquery_pack_asset: [], }, elasticsearch: { ingest_pipeline: [ diff --git a/x-pack/plugins/fleet/.storybook/context/fixtures/integration.okta.ts b/x-pack/plugins/fleet/.storybook/context/fixtures/integration.okta.ts index 6b766c2d126df..de31e519c5fc2 100644 --- a/x-pack/plugins/fleet/.storybook/context/fixtures/integration.okta.ts +++ b/x-pack/plugins/fleet/.storybook/context/fixtures/integration.okta.ts @@ -125,6 +125,7 @@ export const item: GetInfoResponse['item'] = { index_template: [], transform: [], ml_model: [], + osquery_pack_asset: [], }, }, policy_templates: [ diff --git a/x-pack/plugins/fleet/common/services/package_to_package_policy.test.ts b/x-pack/plugins/fleet/common/services/package_to_package_policy.test.ts index 0cf8c3e88f568..2aed17e0c93f2 100644 --- a/x-pack/plugins/fleet/common/services/package_to_package_policy.test.ts +++ b/x-pack/plugins/fleet/common/services/package_to_package_policy.test.ts @@ -34,6 +34,7 @@ describe('Fleet - packageToPackagePolicy', () => { ml_module: [], security_rule: [], tag: [], + osquery_pack_asset: [], }, elasticsearch: { ingest_pipeline: [], diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/assets_facet_group.stories.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/assets_facet_group.stories.tsx index 8b949fe8634ee..c18ac973ccfed 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/assets_facet_group.stories.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/assets_facet_group.stories.tsx @@ -37,6 +37,7 @@ export const AssetsFacetGroup = ({ width }: Args) => { security_rule: [], ml_module: [], tag: [], + osquery_pack_asset: [], }, elasticsearch: { component_template: [], diff --git a/x-pack/plugins/fleet/server/services/package_policies_to_agent_permissions.test.ts b/x-pack/plugins/fleet/server/services/package_policies_to_agent_permissions.test.ts index 074484529bfb8..236629f932042 100644 --- a/x-pack/plugins/fleet/server/services/package_policies_to_agent_permissions.test.ts +++ b/x-pack/plugins/fleet/server/services/package_policies_to_agent_permissions.test.ts @@ -67,6 +67,7 @@ describe('storedPackagePoliciesToAgentPermissions()', () => { security_rule: [], ml_module: [], tag: [], + osquery_pack_asset: [], }, elasticsearch: { component_template: [], @@ -179,6 +180,7 @@ describe('storedPackagePoliciesToAgentPermissions()', () => { security_rule: [], ml_module: [], tag: [], + osquery_pack_asset: [], }, elasticsearch: { component_template: [], @@ -271,6 +273,7 @@ describe('storedPackagePoliciesToAgentPermissions()', () => { security_rule: [], ml_module: [], tag: [], + osquery_pack_asset: [], }, elasticsearch: { component_template: [], @@ -395,6 +398,7 @@ describe('storedPackagePoliciesToAgentPermissions()', () => { security_rule: [], ml_module: [], tag: [], + osquery_pack_asset: [], }, elasticsearch: { component_template: [], From c9bcf9a09e62b5ce0cee86917470927e72c4296e Mon Sep 17 00:00:00 2001 From: Patryk Kopycinski Date: Wed, 23 Mar 2022 11:15:22 +0100 Subject: [PATCH 03/13] update fleet fixtures --- .../context/fixtures/integration.okta.ts | 2 +- .../apis/epm/install_remove_assets.ts | 9 ++ .../sample_osquery_asset_rule.json | 133 ++++++++++++++++++ 3 files changed, 143 insertions(+), 1 deletion(-) create mode 100644 x-pack/test/fleet_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/kibana/osquery_pack_asset/sample_osquery_asset_rule.json diff --git a/x-pack/plugins/fleet/.storybook/context/fixtures/integration.okta.ts b/x-pack/plugins/fleet/.storybook/context/fixtures/integration.okta.ts index de31e519c5fc2..0c9a308a3827b 100644 --- a/x-pack/plugins/fleet/.storybook/context/fixtures/integration.okta.ts +++ b/x-pack/plugins/fleet/.storybook/context/fixtures/integration.okta.ts @@ -104,6 +104,7 @@ export const item: GetInfoResponse['item'] = { index_pattern: [], lens: [], ml_module: [], + osquery_pack_asset: [], security_rule: [], tag: [], }, @@ -125,7 +126,6 @@ export const item: GetInfoResponse['item'] = { index_template: [], transform: [], ml_model: [], - osquery_pack_asset: [], }, }, policy_templates: [ diff --git a/x-pack/test/fleet_api_integration/apis/epm/install_remove_assets.ts b/x-pack/test/fleet_api_integration/apis/epm/install_remove_assets.ts index a44b8be478874..492c6340c3a10 100644 --- a/x-pack/test/fleet_api_integration/apis/epm/install_remove_assets.ts +++ b/x-pack/test/fleet_api_integration/apis/epm/install_remove_assets.ts @@ -447,6 +447,11 @@ const expectAssetsInstalled = ({ id: 'sample_security_rule', }); expect(resSecurityRule.id).equal('sample_security_rule'); + const resOsqueryPackAsset = await kibanaServer.savedObjects.get({ + type: 'osquery-pack-asset', + id: 'sample_osquery_pack_asset', + }); + expect(resOsqueryPackAsset.id).equal('sample_osquery_pack_asset'); const resTag = await kibanaServer.savedObjects.get({ type: 'tag', id: 'sample_tag', @@ -526,6 +531,10 @@ const expectAssetsInstalled = ({ id: 'sample_security_rule', type: 'security-rule', }, + { + id: 'sample_osquery_pack_asset', + type: 'osquery-pack-asset', + }, { id: 'sample_tag', type: 'tag', diff --git a/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/kibana/osquery_pack_asset/sample_osquery_asset_rule.json b/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/kibana/osquery_pack_asset/sample_osquery_asset_rule.json new file mode 100644 index 0000000000000..5dcbb8c32d3ad --- /dev/null +++ b/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/kibana/osquery_pack_asset/sample_osquery_asset_rule.json @@ -0,0 +1,133 @@ +{ + "attributes": { + "name": "vuln-management", + "version": 1, + "queries": [ + { + "id": "kernel_info", + "interval": 86400, + "query": "select * from kernel_info;", + "version": "1.4.5" + }, + { + "id": "os_version", + "interval": 86400, + "query": "select * from os_version;", + "version": "1.4.5" + }, + { + "id": "kextstat", + "interval": 86400, + "platform": "darwin", + "query": "select * from kernel_extensions;", + "version": "1.4.5" + }, + { + "id": "kernel_modules", + "interval": 86400, + "platform": "linux", + "query": "select * from kernel_modules;", + "version": "1.4.5" + }, + { + "id": "installed_applications", + "interval": 86400, + "platform": "darwin", + "query": "select * from apps;", + "version": "1.4.5" + }, + { + "id": "browser_plugins", + "interval": 86400, + "platform": "darwin", + "query": "select browser_plugins.* from users join browser_plugins using (uid);", + "version": "1.6.1" + }, + { + "id": "safari_extensions", + "interval": 86400, + "platform": "darwin", + "query": "select safari_extensions.* from users join safari_extensions using (uid);", + "version": "1.6.1" + }, + { + "id": "opera_extensions", + "interval": 86400, + "platform": "darwin,linux", + "query": "select opera_extensions.* from users join opera_extensions using (uid);", + "version": "1.6.1" + }, + { + "id": "chrome_extensions", + "interval": 86400, + "query": "select chrome_extensions.* from users join chrome_extensions using (uid);", + "version": "1.6.1" + }, + { + "id": "firefox_addons", + "interval": 86400, + "platform": "darwin,linux", + "query": "select firefox_addons.* from users join firefox_addons using (uid);", + "version": "1.6.1" + }, + { + "id": "homebrew_packages", + "interval": 86400, + "platform": "darwin", + "query": "select * from homebrew_packages;", + "version": "1.4.5" + }, + { + "id": "package_receipts", + "interval": 86400, + "platform": "darwin", + "query": "select * from package_receipts;", + "version": "1.4.5" + }, + { + "id": "deb_packages", + "interval": 86400, + "platform": "linux", + "query": "select * from deb_packages;", + "version": "1.4.5" + }, + { + "id": "apt_sources", + "interval": 86400, + "platform": "linux", + "query": "select * from apt_sources;", + "version": "1.4.5" + }, + { + "id": "portage_packages", + "interval": 86400, + "platform": "linux", + "query": "select * from portage_packages;", + "version": "2.0.0" + }, + { + "id": "rpm_packages", + "interval": 86400, + "platform": "linux", + "query": "select * from rpm_packages;", + "version": "1.4.5" + }, + { + "id": "unauthenticated_sparkle_feeds", + "interval": 86400, + "platform": "darwin", + "query": "select feeds.*, p2.value as sparkle_version from (select a.name as app_name, a.path as app_path, a.bundle_identifier as bundle_id, p.value as feed_url from (select name, path, bundle_identifier from apps) a, plist p where p.path = a.path || '/Contents/Info.plist' and p.key = 'SUFeedURL' and feed_url like 'http://%') feeds left outer join plist p2 on p2.path = app_path || '/Contents/Frameworks/Sparkle.framework/Resources/Info.plist' where (p2.key = 'CFBundleShortVersionString' OR coalesce(p2.key, '') = '');", + "version": "1.4.5" + }, + { + "id": "backdoored_python_packages", + "interval": 86400, + "platform": "darwin,linux", + "query": "select name as package_name, version as package_version, path as package_path from python_packages where package_name = 'acqusition' or package_name = 'apidev-coop' or package_name = 'bzip' or package_name = 'crypt' or package_name = 'django-server' or package_name = 'pwd' or package_name = 'setup-tools' or package_name = 'telnet' or package_name = 'urlib3' or package_name = 'urllib';", + "version": "1.4.5" + } + ] + }, + "id": "sample_osquery_pack_asset", + "type": "osquery-pack-asset" +} From 04fe523979fbccbcc8bb33d4d7495e996707fa8c Mon Sep 17 00:00:00 2001 From: Patryk Kopycinski Date: Wed, 23 Mar 2022 12:20:12 +0100 Subject: [PATCH 04/13] fix route --- .../server/routes/pack/update_pack_route.ts | 37 ++++++++++--------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/x-pack/plugins/osquery/server/routes/pack/update_pack_route.ts b/x-pack/plugins/osquery/server/routes/pack/update_pack_route.ts index d30a44665cc1f..f04a0a37d0c5d 100644 --- a/x-pack/plugins/osquery/server/routes/pack/update_pack_route.ts +++ b/x-pack/plugins/osquery/server/routes/pack/update_pack_route.ts @@ -98,7 +98,7 @@ export const updatePackRoute = (router: IRouter, osqueryContext: OsqueryAppConte conflictingEntries.saved_objects, (packSO) => packSO.id !== currentPackSO.id && packSO.attributes.name.length === name.length - ) + ).length ) { return response.conflict({ body: `Pack with name "${name}" already exists.` }); } @@ -125,6 +125,21 @@ export const updatePackRoute = (router: IRouter, osqueryContext: OsqueryAppConte (reference) => reference.type !== AGENT_POLICY_SAVED_OBJECT_TYPE ); + const getUpdatedReferences = () => { + if (policy_ids) { + return [ + ...nonAgentPolicyReferences, + ...policy_ids.map((id) => ({ + id, + name: agentPolicies[id].name, + type: AGENT_POLICY_SAVED_OBJECT_TYPE, + })), + ]; + } + + return currentPackSO.references; + }; + await savedObjectsClient.update( packSavedObjectType, request.params.id, @@ -136,22 +151,10 @@ export const updatePackRoute = (router: IRouter, osqueryContext: OsqueryAppConte updated_at: moment().toISOString(), updated_by: currentUser, }, - policy_ids - ? { - refresh: 'wait_for', - references: [ - ...nonAgentPolicyReferences, - ...policy_ids.map((id) => ({ - id, - name: agentPolicies[id].name, - type: AGENT_POLICY_SAVED_OBJECT_TYPE, - })), - ], - } - : { - refresh: 'wait_for', - references: nonAgentPolicyReferences, - } + { + refresh: 'wait_for', + references: getUpdatedReferences(), + } ); const currentAgentPolicyIds = map( From 3b3d1f0ac010e9b1c25beefdaf2bb64d3347207d Mon Sep 17 00:00:00 2001 From: Patryk Kopycinski Date: Wed, 23 Mar 2022 12:40:31 +0100 Subject: [PATCH 05/13] fix --- .../public/assets/use_assets_status.ts | 2 +- .../public/assets/use_import_assets.ts | 13 ++++++------ .../public/routes/packs/edit/index.tsx | 1 + .../public/routes/packs/list/index.tsx | 12 ++++------- .../packs/list/load_integration_assets.tsx | 15 ++++++++++--- .../public/routes/packs/list/translations.ts | 21 +++++++++++++++++++ 6 files changed, 45 insertions(+), 19 deletions(-) diff --git a/x-pack/plugins/osquery/public/assets/use_assets_status.ts b/x-pack/plugins/osquery/public/assets/use_assets_status.ts index e902c1b94244b..41307952b222c 100644 --- a/x-pack/plugins/osquery/public/assets/use_assets_status.ts +++ b/x-pack/plugins/osquery/public/assets/use_assets_status.ts @@ -13,7 +13,7 @@ import { INTEGRATION_ASSETS_STATUS_ID } from './constants'; export const useAssetsStatus = () => { const { http } = useKibana().services; - return useQuery<{ install: SavedObject[]; update: SavedObject[]; up_to_date: SavedObject[] }>( + return useQuery<{ install: SavedObject[]; update: SavedObject[]; upToDate: SavedObject[] }>( [INTEGRATION_ASSETS_STATUS_ID], () => http.get('/internal/osquery/assets'), { diff --git a/x-pack/plugins/osquery/public/assets/use_import_assets.ts b/x-pack/plugins/osquery/public/assets/use_import_assets.ts index 5e2a966a54e62..f63f3e7096f03 100644 --- a/x-pack/plugins/osquery/public/assets/use_import_assets.ts +++ b/x-pack/plugins/osquery/public/assets/use_import_assets.ts @@ -6,13 +6,16 @@ */ import { useMutation, useQueryClient } from 'react-query'; -import { i18n } from '@kbn/i18n'; import { useKibana } from '../common/lib/kibana'; import { useErrorToast } from '../common/hooks/use_error_toast'; import { PACKS_ID } from '../packs/constants'; import { INTEGRATION_ASSETS_STATUS_ID } from './constants'; -export const useImportAssets = () => { +interface UseImportAssetsProps { + successToastText: string; +} + +export const useImportAssets = ({ successToastText }: UseImportAssetsProps) => { const queryClient = useQueryClient(); const { http, @@ -29,11 +32,7 @@ export const useImportAssets = () => { setErrorToast(); queryClient.invalidateQueries(PACKS_ID); queryClient.invalidateQueries(INTEGRATION_ASSETS_STATUS_ID); - toasts.addSuccess( - i18n.translate('xpack.osquery.integrationAssetsImport.successToastMessageText', { - defaultMessage: 'Successfully imported prebuilt assets', - }) - ); + toasts.addSuccess(successToastText); }, onError: (error) => { setErrorToast(error); diff --git a/x-pack/plugins/osquery/public/routes/packs/edit/index.tsx b/x-pack/plugins/osquery/public/routes/packs/edit/index.tsx index 2409a9524a8c2..341312a45ae8a 100644 --- a/x-pack/plugins/osquery/public/routes/packs/edit/index.tsx +++ b/x-pack/plugins/osquery/public/routes/packs/edit/index.tsx @@ -112,6 +112,7 @@ const EditPackPageComponent = () => { } onCancel={handleCloseDeleteConfirmationModal} onConfirm={handleDeleteConfirmClick} + confirmButtonDisabled={deletePackMutation.isLoading} cancelButtonText={ { () => ( - + - + ), - [] + [showEmptyState] ); const Content = useMemo(() => { @@ -77,11 +77,7 @@ const PacksPageComponent = () => { }, [isLoadingAssetsStatus, isLoadingPacks, showEmptyState]); return ( - + {Content} ); diff --git a/x-pack/plugins/osquery/public/routes/packs/list/load_integration_assets.tsx b/x-pack/plugins/osquery/public/routes/packs/list/load_integration_assets.tsx index e86496a0ccca1..a4d7374d21697 100644 --- a/x-pack/plugins/osquery/public/routes/packs/list/load_integration_assets.tsx +++ b/x-pack/plugins/osquery/public/routes/packs/list/load_integration_assets.tsx @@ -9,7 +9,12 @@ import React, { useCallback } from 'react'; import { EuiButton, EuiButtonProps } from '@elastic/eui'; import { useImportAssets } from '../../../assets/use_import_assets'; import { useAssetsStatus } from '../../../assets/use_assets_status'; -import { LOAD_PREBUILT_PACKS_BUTTON } from './translations'; +import { + LOAD_PREBUILT_PACKS_BUTTON, + UPDATE_PREBUILT_PACKS_BUTTON, + LOAD_PREBUILT_PACKS_SUCCESS_TEXT, + UPDATE_PREBUILT_PACKS_SUCCESS_TEXT, +} from './translations'; interface LoadIntegrationAssetsButtonProps { fill?: EuiButtonProps['fill']; @@ -19,14 +24,18 @@ const LoadIntegrationAssetsButtonComponent: React.FC { const { data } = useAssetsStatus(); - const { isLoading, mutateAsync } = useImportAssets(); + const { isLoading, mutateAsync } = useImportAssets({ + successToastText: data?.upToDate?.length + ? UPDATE_PREBUILT_PACKS_SUCCESS_TEXT + : LOAD_PREBUILT_PACKS_SUCCESS_TEXT, + }); const handleClick = useCallback(() => mutateAsync(), [mutateAsync]); if (data?.install.length || data?.update.length) { return ( - {LOAD_PREBUILT_PACKS_BUTTON} + {data?.upToDate?.length ? UPDATE_PREBUILT_PACKS_BUTTON : LOAD_PREBUILT_PACKS_BUTTON} ); } diff --git a/x-pack/plugins/osquery/public/routes/packs/list/translations.ts b/x-pack/plugins/osquery/public/routes/packs/list/translations.ts index 115f713e6227a..6bbee2a2eb59d 100644 --- a/x-pack/plugins/osquery/public/routes/packs/list/translations.ts +++ b/x-pack/plugins/osquery/public/routes/packs/list/translations.ts @@ -21,6 +21,27 @@ export const LOAD_PREBUILT_PACKS_BUTTON = i18n.translate( } ); +export const UPDATE_PREBUILT_PACKS_BUTTON = i18n.translate( + 'xpack.osquery.packList.prePackagedPacks.updateButtonLabel', + { + defaultMessage: 'Update Elastic prebuilt packs', + } +); + +export const LOAD_PREBUILT_PACKS_SUCCESS_TEXT = i18n.translate( + 'xpack.osquery.packList.integrationAssets.loadSuccessToastMessageText', + { + defaultMessage: 'Successfully loaded prebuilt packs', + } +); + +export const UPDATE_PREBUILT_PACKS_SUCCESS_TEXT = i18n.translate( + 'xpack.osquery.packList.integrationAssets.updateSuccessToastMessageText', + { + defaultMessage: 'Successfully updated prebuilt packs', + } +); + export const PRE_BUILT_MSG = i18n.translate( 'xpack.osquery.packList.prePackagedPacks.emptyPromptTitle.emptyPromptMessage', { From 19d3808164ed05623c283aee1b8718311ecfb88a Mon Sep 17 00:00:00 2001 From: Patryk Kopycinski Date: Wed, 23 Mar 2022 16:10:09 +0100 Subject: [PATCH 06/13] fix --- x-pack/test/fleet_api_integration/apis/epm/update_assets.ts | 4 ++++ ...osquery_asset_rule.json => sample_osquery_pack_asset.json} | 0 2 files changed, 4 insertions(+) rename x-pack/test/fleet_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/kibana/osquery_pack_asset/{sample_osquery_asset_rule.json => sample_osquery_pack_asset.json} (100%) diff --git a/x-pack/test/fleet_api_integration/apis/epm/update_assets.ts b/x-pack/test/fleet_api_integration/apis/epm/update_assets.ts index 7d28b04c28a53..cd242ce86d625 100644 --- a/x-pack/test/fleet_api_integration/apis/epm/update_assets.ts +++ b/x-pack/test/fleet_api_integration/apis/epm/update_assets.ts @@ -393,6 +393,10 @@ export default function (providerContext: FtrProviderContext) { id: 'sample_security_rule', type: 'security-rule', }, + { + id: 'sample_osquery_pack_asset', + type: 'osquery-pack-asset', + }, { id: 'sample_ml_module', type: 'ml-module', diff --git a/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/kibana/osquery_pack_asset/sample_osquery_asset_rule.json b/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/kibana/osquery_pack_asset/sample_osquery_pack_asset.json similarity index 100% rename from x-pack/test/fleet_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/kibana/osquery_pack_asset/sample_osquery_asset_rule.json rename to x-pack/test/fleet_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/kibana/osquery_pack_asset/sample_osquery_pack_asset.json From ebdd8939cfbd2fb67bb2c2a9c6a9dd06366abe67 Mon Sep 17 00:00:00 2001 From: Patryk Kopycinski Date: Wed, 23 Mar 2022 19:48:17 +0100 Subject: [PATCH 07/13] fix --- .../apis/epm/install_remove_assets.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/x-pack/test/fleet_api_integration/apis/epm/install_remove_assets.ts b/x-pack/test/fleet_api_integration/apis/epm/install_remove_assets.ts index 492c6340c3a10..6b710c00b2bfa 100644 --- a/x-pack/test/fleet_api_integration/apis/epm/install_remove_assets.ts +++ b/x-pack/test/fleet_api_integration/apis/epm/install_remove_assets.ts @@ -523,6 +523,10 @@ const expectAssetsInstalled = ({ id: 'sample_ml_module', type: 'ml-module', }, + { + id: 'sample_osquery_pack_asset', + type: 'osquery-pack-asset', + }, { id: 'sample_search', type: 'search', @@ -531,10 +535,6 @@ const expectAssetsInstalled = ({ id: 'sample_security_rule', type: 'security-rule', }, - { - id: 'sample_osquery_pack_asset', - type: 'osquery-pack-asset', - }, { id: 'sample_tag', type: 'tag', From 27e58ed3a0946ebff754c4b707259021a34cff29 Mon Sep 17 00:00:00 2001 From: Patryk Kopycinski Date: Wed, 23 Mar 2022 22:00:22 +0100 Subject: [PATCH 08/13] fix --- .../apis/epm/update_assets.ts | 8 +- .../sample_osquery_pack_asset.json | 262 +++++++++--------- .../sample_osquery_pack_asset.json | 133 +++++++++ 3 files changed, 268 insertions(+), 135 deletions(-) create mode 100644 x-pack/test/fleet_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/kibana/osquery_pack_asset/sample_osquery_pack_asset.json diff --git a/x-pack/test/fleet_api_integration/apis/epm/update_assets.ts b/x-pack/test/fleet_api_integration/apis/epm/update_assets.ts index cd242ce86d625..3cb91aeedb9ba 100644 --- a/x-pack/test/fleet_api_integration/apis/epm/update_assets.ts +++ b/x-pack/test/fleet_api_integration/apis/epm/update_assets.ts @@ -389,14 +389,14 @@ export default function (providerContext: FtrProviderContext) { id: 'sample_lens', type: 'lens', }, - { - id: 'sample_security_rule', - type: 'security-rule', - }, { id: 'sample_osquery_pack_asset', type: 'osquery-pack-asset', }, + { + id: 'sample_security_rule', + type: 'security-rule', + }, { id: 'sample_ml_module', type: 'ml-module', diff --git a/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/kibana/osquery_pack_asset/sample_osquery_pack_asset.json b/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/kibana/osquery_pack_asset/sample_osquery_pack_asset.json index 5dcbb8c32d3ad..d22f8eb083d3e 100644 --- a/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/kibana/osquery_pack_asset/sample_osquery_pack_asset.json +++ b/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/kibana/osquery_pack_asset/sample_osquery_pack_asset.json @@ -1,133 +1,133 @@ { - "attributes": { - "name": "vuln-management", - "version": 1, - "queries": [ - { - "id": "kernel_info", - "interval": 86400, - "query": "select * from kernel_info;", - "version": "1.4.5" - }, - { - "id": "os_version", - "interval": 86400, - "query": "select * from os_version;", - "version": "1.4.5" - }, - { - "id": "kextstat", - "interval": 86400, - "platform": "darwin", - "query": "select * from kernel_extensions;", - "version": "1.4.5" - }, - { - "id": "kernel_modules", - "interval": 86400, - "platform": "linux", - "query": "select * from kernel_modules;", - "version": "1.4.5" - }, - { - "id": "installed_applications", - "interval": 86400, - "platform": "darwin", - "query": "select * from apps;", - "version": "1.4.5" - }, - { - "id": "browser_plugins", - "interval": 86400, - "platform": "darwin", - "query": "select browser_plugins.* from users join browser_plugins using (uid);", - "version": "1.6.1" - }, - { - "id": "safari_extensions", - "interval": 86400, - "platform": "darwin", - "query": "select safari_extensions.* from users join safari_extensions using (uid);", - "version": "1.6.1" - }, - { - "id": "opera_extensions", - "interval": 86400, - "platform": "darwin,linux", - "query": "select opera_extensions.* from users join opera_extensions using (uid);", - "version": "1.6.1" - }, - { - "id": "chrome_extensions", - "interval": 86400, - "query": "select chrome_extensions.* from users join chrome_extensions using (uid);", - "version": "1.6.1" - }, - { - "id": "firefox_addons", - "interval": 86400, - "platform": "darwin,linux", - "query": "select firefox_addons.* from users join firefox_addons using (uid);", - "version": "1.6.1" - }, - { - "id": "homebrew_packages", - "interval": 86400, - "platform": "darwin", - "query": "select * from homebrew_packages;", - "version": "1.4.5" - }, - { - "id": "package_receipts", - "interval": 86400, - "platform": "darwin", - "query": "select * from package_receipts;", - "version": "1.4.5" - }, - { - "id": "deb_packages", - "interval": 86400, - "platform": "linux", - "query": "select * from deb_packages;", - "version": "1.4.5" - }, - { - "id": "apt_sources", - "interval": 86400, - "platform": "linux", - "query": "select * from apt_sources;", - "version": "1.4.5" - }, - { - "id": "portage_packages", - "interval": 86400, - "platform": "linux", - "query": "select * from portage_packages;", - "version": "2.0.0" - }, - { - "id": "rpm_packages", - "interval": 86400, - "platform": "linux", - "query": "select * from rpm_packages;", - "version": "1.4.5" - }, - { - "id": "unauthenticated_sparkle_feeds", - "interval": 86400, - "platform": "darwin", - "query": "select feeds.*, p2.value as sparkle_version from (select a.name as app_name, a.path as app_path, a.bundle_identifier as bundle_id, p.value as feed_url from (select name, path, bundle_identifier from apps) a, plist p where p.path = a.path || '/Contents/Info.plist' and p.key = 'SUFeedURL' and feed_url like 'http://%') feeds left outer join plist p2 on p2.path = app_path || '/Contents/Frameworks/Sparkle.framework/Resources/Info.plist' where (p2.key = 'CFBundleShortVersionString' OR coalesce(p2.key, '') = '');", - "version": "1.4.5" - }, - { - "id": "backdoored_python_packages", - "interval": 86400, - "platform": "darwin,linux", - "query": "select name as package_name, version as package_version, path as package_path from python_packages where package_name = 'acqusition' or package_name = 'apidev-coop' or package_name = 'bzip' or package_name = 'crypt' or package_name = 'django-server' or package_name = 'pwd' or package_name = 'setup-tools' or package_name = 'telnet' or package_name = 'urlib3' or package_name = 'urllib';", - "version": "1.4.5" - } - ] - }, - "id": "sample_osquery_pack_asset", - "type": "osquery-pack-asset" + "attributes": { + "name": "vuln-management", + "version": 1, + "queries": [ + { + "id": "kernel_info", + "interval": 86400, + "query": "select * from kernel_info;", + "version": "1.4.5" + }, + { + "id": "os_version", + "interval": 86400, + "query": "select * from os_version;", + "version": "1.4.5" + }, + { + "id": "kextstat", + "interval": 86400, + "platform": "darwin", + "query": "select * from kernel_extensions;", + "version": "1.4.5" + }, + { + "id": "kernel_modules", + "interval": 86400, + "platform": "linux", + "query": "select * from kernel_modules;", + "version": "1.4.5" + }, + { + "id": "installed_applications", + "interval": 86400, + "platform": "darwin", + "query": "select * from apps;", + "version": "1.4.5" + }, + { + "id": "browser_plugins", + "interval": 86400, + "platform": "darwin", + "query": "select browser_plugins.* from users join browser_plugins using (uid);", + "version": "1.6.1" + }, + { + "id": "safari_extensions", + "interval": 86400, + "platform": "darwin", + "query": "select safari_extensions.* from users join safari_extensions using (uid);", + "version": "1.6.1" + }, + { + "id": "opera_extensions", + "interval": 86400, + "platform": "darwin,linux", + "query": "select opera_extensions.* from users join opera_extensions using (uid);", + "version": "1.6.1" + }, + { + "id": "chrome_extensions", + "interval": 86400, + "query": "select chrome_extensions.* from users join chrome_extensions using (uid);", + "version": "1.6.1" + }, + { + "id": "firefox_addons", + "interval": 86400, + "platform": "darwin,linux", + "query": "select firefox_addons.* from users join firefox_addons using (uid);", + "version": "1.6.1" + }, + { + "id": "homebrew_packages", + "interval": 86400, + "platform": "darwin", + "query": "select * from homebrew_packages;", + "version": "1.4.5" + }, + { + "id": "package_receipts", + "interval": 86400, + "platform": "darwin", + "query": "select * from package_receipts;", + "version": "1.4.5" + }, + { + "id": "deb_packages", + "interval": 86400, + "platform": "linux", + "query": "select * from deb_packages;", + "version": "1.4.5" + }, + { + "id": "apt_sources", + "interval": 86400, + "platform": "linux", + "query": "select * from apt_sources;", + "version": "1.4.5" + }, + { + "id": "portage_packages", + "interval": 86400, + "platform": "linux", + "query": "select * from portage_packages;", + "version": "2.0.0" + }, + { + "id": "rpm_packages", + "interval": 86400, + "platform": "linux", + "query": "select * from rpm_packages;", + "version": "1.4.5" + }, + { + "id": "unauthenticated_sparkle_feeds", + "interval": 86400, + "platform": "darwin", + "query": "select feeds.*, p2.value as sparkle_version from (select a.name as app_name, a.path as app_path, a.bundle_identifier as bundle_id, p.value as feed_url from (select name, path, bundle_identifier from apps) a, plist p where p.path = a.path || '/Contents/Info.plist' and p.key = 'SUFeedURL' and feed_url like 'http://%') feeds left outer join plist p2 on p2.path = app_path || '/Contents/Frameworks/Sparkle.framework/Resources/Info.plist' where (p2.key = 'CFBundleShortVersionString' OR coalesce(p2.key, '') = '');", + "version": "1.4.5" + }, + { + "id": "backdoored_python_packages", + "interval": 86400, + "platform": "darwin,linux", + "query": "select name as package_name, version as package_version, path as package_path from python_packages where package_name = 'acqusition' or package_name = 'apidev-coop' or package_name = 'bzip' or package_name = 'crypt' or package_name = 'django-server' or package_name = 'pwd' or package_name = 'setup-tools' or package_name = 'telnet' or package_name = 'urlib3' or package_name = 'urllib';", + "version": "1.4.5" + } + ] + }, + "id": "sample_osquery_pack_asset", + "type": "osquery-pack-asset" } diff --git a/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/kibana/osquery_pack_asset/sample_osquery_pack_asset.json b/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/kibana/osquery_pack_asset/sample_osquery_pack_asset.json new file mode 100644 index 0000000000000..d22f8eb083d3e --- /dev/null +++ b/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/kibana/osquery_pack_asset/sample_osquery_pack_asset.json @@ -0,0 +1,133 @@ +{ + "attributes": { + "name": "vuln-management", + "version": 1, + "queries": [ + { + "id": "kernel_info", + "interval": 86400, + "query": "select * from kernel_info;", + "version": "1.4.5" + }, + { + "id": "os_version", + "interval": 86400, + "query": "select * from os_version;", + "version": "1.4.5" + }, + { + "id": "kextstat", + "interval": 86400, + "platform": "darwin", + "query": "select * from kernel_extensions;", + "version": "1.4.5" + }, + { + "id": "kernel_modules", + "interval": 86400, + "platform": "linux", + "query": "select * from kernel_modules;", + "version": "1.4.5" + }, + { + "id": "installed_applications", + "interval": 86400, + "platform": "darwin", + "query": "select * from apps;", + "version": "1.4.5" + }, + { + "id": "browser_plugins", + "interval": 86400, + "platform": "darwin", + "query": "select browser_plugins.* from users join browser_plugins using (uid);", + "version": "1.6.1" + }, + { + "id": "safari_extensions", + "interval": 86400, + "platform": "darwin", + "query": "select safari_extensions.* from users join safari_extensions using (uid);", + "version": "1.6.1" + }, + { + "id": "opera_extensions", + "interval": 86400, + "platform": "darwin,linux", + "query": "select opera_extensions.* from users join opera_extensions using (uid);", + "version": "1.6.1" + }, + { + "id": "chrome_extensions", + "interval": 86400, + "query": "select chrome_extensions.* from users join chrome_extensions using (uid);", + "version": "1.6.1" + }, + { + "id": "firefox_addons", + "interval": 86400, + "platform": "darwin,linux", + "query": "select firefox_addons.* from users join firefox_addons using (uid);", + "version": "1.6.1" + }, + { + "id": "homebrew_packages", + "interval": 86400, + "platform": "darwin", + "query": "select * from homebrew_packages;", + "version": "1.4.5" + }, + { + "id": "package_receipts", + "interval": 86400, + "platform": "darwin", + "query": "select * from package_receipts;", + "version": "1.4.5" + }, + { + "id": "deb_packages", + "interval": 86400, + "platform": "linux", + "query": "select * from deb_packages;", + "version": "1.4.5" + }, + { + "id": "apt_sources", + "interval": 86400, + "platform": "linux", + "query": "select * from apt_sources;", + "version": "1.4.5" + }, + { + "id": "portage_packages", + "interval": 86400, + "platform": "linux", + "query": "select * from portage_packages;", + "version": "2.0.0" + }, + { + "id": "rpm_packages", + "interval": 86400, + "platform": "linux", + "query": "select * from rpm_packages;", + "version": "1.4.5" + }, + { + "id": "unauthenticated_sparkle_feeds", + "interval": 86400, + "platform": "darwin", + "query": "select feeds.*, p2.value as sparkle_version from (select a.name as app_name, a.path as app_path, a.bundle_identifier as bundle_id, p.value as feed_url from (select name, path, bundle_identifier from apps) a, plist p where p.path = a.path || '/Contents/Info.plist' and p.key = 'SUFeedURL' and feed_url like 'http://%') feeds left outer join plist p2 on p2.path = app_path || '/Contents/Frameworks/Sparkle.framework/Resources/Info.plist' where (p2.key = 'CFBundleShortVersionString' OR coalesce(p2.key, '') = '');", + "version": "1.4.5" + }, + { + "id": "backdoored_python_packages", + "interval": 86400, + "platform": "darwin,linux", + "query": "select name as package_name, version as package_version, path as package_path from python_packages where package_name = 'acqusition' or package_name = 'apidev-coop' or package_name = 'bzip' or package_name = 'crypt' or package_name = 'django-server' or package_name = 'pwd' or package_name = 'setup-tools' or package_name = 'telnet' or package_name = 'urlib3' or package_name = 'urllib';", + "version": "1.4.5" + } + ] + }, + "id": "sample_osquery_pack_asset", + "type": "osquery-pack-asset" +} From c4e1dd6d19641180054ce8ac152e52cc7d666e68 Mon Sep 17 00:00:00 2001 From: Patryk Kopycinski Date: Wed, 23 Mar 2022 22:58:45 +0100 Subject: [PATCH 09/13] fix --- .../test/fleet_api_integration/apis/epm/install_remove_assets.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/test/fleet_api_integration/apis/epm/install_remove_assets.ts b/x-pack/test/fleet_api_integration/apis/epm/install_remove_assets.ts index 6b710c00b2bfa..7a5db3a599b1b 100644 --- a/x-pack/test/fleet_api_integration/apis/epm/install_remove_assets.ts +++ b/x-pack/test/fleet_api_integration/apis/epm/install_remove_assets.ts @@ -627,6 +627,7 @@ const expectAssetsInstalled = ({ { id: '318959c9-997b-5a14-b328-9fc7355b4b74', type: 'epm-packages-assets' }, { id: 'e21b59b5-eb76-5ab0-bef2-1c8e379e6197', type: 'epm-packages-assets' }, { id: '4c758d70-ecf1-56b3-b704-6d8374841b34', type: 'epm-packages-assets' }, + { id: '313ddb31-e70a-59e8-8287-310d4652a9b7', type: 'epm-packages-assets' }, { id: 'e786cbd9-0f3b-5a0b-82a6-db25145ebf58', type: 'epm-packages-assets' }, { id: 'd8b175c3-0d42-5ec7-90c1-d1e4b307a4c2', type: 'epm-packages-assets' }, { id: 'b265a5e0-c00b-5eda-ac44-2ddbd36d9ad0', type: 'epm-packages-assets' }, From ba4d192c82ed68fad34c0ed1238660c3e406c4b6 Mon Sep 17 00:00:00 2001 From: Patryk Kopycinski Date: Thu, 24 Mar 2022 08:55:54 +0100 Subject: [PATCH 10/13] fix --- x-pack/test/fleet_api_integration/apis/epm/update_assets.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/test/fleet_api_integration/apis/epm/update_assets.ts b/x-pack/test/fleet_api_integration/apis/epm/update_assets.ts index 3cb91aeedb9ba..2844b414a63e3 100644 --- a/x-pack/test/fleet_api_integration/apis/epm/update_assets.ts +++ b/x-pack/test/fleet_api_integration/apis/epm/update_assets.ts @@ -495,6 +495,7 @@ export default function (providerContext: FtrProviderContext) { { id: 'bf3b0b65-9fdc-53c6-a9ca-e76140e56490', type: 'epm-packages-assets' }, { id: '7f4c5aca-b4f5-5f0a-95af-051da37513fc', type: 'epm-packages-assets' }, { id: '4281a436-45a8-54ab-9724-fda6849f789d', type: 'epm-packages-assets' }, + { id: 'cb0bbdd7-e043-508b-91c0-09e4cc0f5a3c', type: 'epm-packages-assets' }, { id: '2e56f08b-1d06-55ed-abee-4708e1ccf0aa', type: 'epm-packages-assets' }, { id: '4035007b-9c33-5227-9803-2de8a17523b5', type: 'epm-packages-assets' }, { id: 'e6ae7d31-6920-5408-9219-91ef1662044b', type: 'epm-packages-assets' }, From 8c1166ed0e1f94238435610b550fc82600fd7ab4 Mon Sep 17 00:00:00 2001 From: Patryk Kopycinski Date: Thu, 24 Mar 2022 10:22:20 +0100 Subject: [PATCH 11/13] fix --- .../test/fleet_api_integration/apis/epm/update_assets.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/x-pack/test/fleet_api_integration/apis/epm/update_assets.ts b/x-pack/test/fleet_api_integration/apis/epm/update_assets.ts index 2844b414a63e3..4742c6308be3d 100644 --- a/x-pack/test/fleet_api_integration/apis/epm/update_assets.ts +++ b/x-pack/test/fleet_api_integration/apis/epm/update_assets.ts @@ -389,10 +389,6 @@ export default function (providerContext: FtrProviderContext) { id: 'sample_lens', type: 'lens', }, - { - id: 'sample_osquery_pack_asset', - type: 'osquery-pack-asset', - }, { id: 'sample_security_rule', type: 'security-rule', @@ -405,6 +401,10 @@ export default function (providerContext: FtrProviderContext) { id: 'sample_tag', type: 'tag', }, + { + id: 'sample_osquery_pack_asset', + type: 'osquery-pack-asset', + }, ], installed_es: [ { From 79f5eb44bf12c987208557d29fdabb2762bf67a0 Mon Sep 17 00:00:00 2001 From: Patryk Kopycinski Date: Thu, 24 Mar 2022 12:48:34 +0100 Subject: [PATCH 12/13] add uninstall check --- .../apis/epm/install_remove_assets.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/x-pack/test/fleet_api_integration/apis/epm/install_remove_assets.ts b/x-pack/test/fleet_api_integration/apis/epm/install_remove_assets.ts index 7a5db3a599b1b..a3ae05e7f8db2 100644 --- a/x-pack/test/fleet_api_integration/apis/epm/install_remove_assets.ts +++ b/x-pack/test/fleet_api_integration/apis/epm/install_remove_assets.ts @@ -253,6 +253,16 @@ export default function (providerContext: FtrProviderContext) { resIndexPattern = err; } expect(resIndexPattern.response.data.statusCode).equal(404); + let resOsqueryPackAsset; + try { + resOsqueryPackAsset = await kibanaServer.savedObjects.get({ + type: 'osquery-pack-asset', + id: 'sample_osquery_pack_asset', + }); + } catch (err) { + resOsqueryPackAsset = err; + } + expect(resOsqueryPackAsset.response.data.statusCode).equal(404); }); it('should have removed the saved object', async function () { let res; From 3e7abc2ecc41dcd5345ab9d4b2199cfebb76cf3b Mon Sep 17 00:00:00 2001 From: Patryk Kopycinski Date: Thu, 24 Mar 2022 16:05:26 +0100 Subject: [PATCH 13/13] fix --- .../fleet_api_integration/apis/epm/install_remove_assets.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/x-pack/test/fleet_api_integration/apis/epm/install_remove_assets.ts b/x-pack/test/fleet_api_integration/apis/epm/install_remove_assets.ts index 908ca3ed6b748..4212ca46fc3c9 100644 --- a/x-pack/test/fleet_api_integration/apis/epm/install_remove_assets.ts +++ b/x-pack/test/fleet_api_integration/apis/epm/install_remove_assets.ts @@ -706,6 +706,10 @@ const expectAssetsInstalled = ({ id: '4c758d70-ecf1-56b3-b704-6d8374841b34', type: 'epm-packages-assets', }, + { + id: '313ddb31-e70a-59e8-8287-310d4652a9b7', + type: 'epm-packages-assets', + }, { id: 'e786cbd9-0f3b-5a0b-82a6-db25145ebf58', type: 'epm-packages-assets',