[Osquery] Fix 7.16.0 BC1 issues (#116074)

This commit is contained in:
Patryk Kopyciński 2021-10-26 21:14:03 +02:00 committed by GitHub
parent 645cecdf1f
commit f6dd54a00a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
30 changed files with 460 additions and 177 deletions

View file

@ -330,7 +330,7 @@
"react-moment-proptypes": "^1.7.0",
"react-monaco-editor": "^0.41.2",
"react-popper-tooltip": "^2.10.1",
"react-query": "^3.27.0",
"react-query": "^3.28.0",
"react-redux": "^7.2.0",
"react-resizable": "^1.7.5",
"react-resize-detector": "^4.2.0",

View file

@ -28,13 +28,12 @@ const AgentsPolicyLinkComponent: React.FC<AgentsPolicyLinkProps> = ({ policyId }
const {
application: { getUrlForApp, navigateToApp },
} = useKibana().services;
const { data } = useAgentPolicy({ policyId });
const href = useMemo(
() =>
getUrlForApp(PLUGIN_ID, {
path: `#` + pagePathGetters.policy_details({ policyId })[1],
path: pagePathGetters.policy_details({ policyId })[1],
}),
[getUrlForApp, policyId]
);
@ -45,7 +44,7 @@ const AgentsPolicyLinkComponent: React.FC<AgentsPolicyLinkProps> = ({ policyId }
event.preventDefault();
return navigateToApp(PLUGIN_ID, {
path: `#` + pagePathGetters.policy_details({ policyId })[1],
path: pagePathGetters.policy_details({ policyId })[1],
});
}
},

View file

@ -25,7 +25,7 @@ const AgentIdToNameComponent: React.FC<AgentIdToNameProps> = ({ agentId }) => {
<EuiLink
className="eui-textTruncate"
href={getUrlForApp(PLUGIN_ID, {
path: `#` + pagePathGetters.agent_details({ agentId })[1],
path: pagePathGetters.agent_details({ agentId })[1],
})}
target="_blank"
>

View file

@ -43,7 +43,7 @@ interface AgentsTableProps {
}
const perPage = 10;
const DEBOUNCE_DELAY = 100; // ms
const DEBOUNCE_DELAY = 300; // ms
const AgentsTableComponent: React.FC<AgentsTableProps> = ({ agentSelection, onChange }) => {
// search related

View file

@ -22,8 +22,8 @@ export const useAgentPolicies = (policyIds: string[] = []) => {
queryFn: () => http.get(`/internal/osquery/fleet_wrapper/agent_policies/${policyId}`),
enabled: policyIds.length > 0,
onSuccess: () => setErrorToast(),
onError: (error) =>
setErrorToast(error as Error, {
onError: (error: Error) =>
setErrorToast(error, {
title: i18n.translate('xpack.osquery.action_policy_details.fetchError', {
defaultMessage: 'Error while fetching policy details',
}),

File diff suppressed because one or more lines are too long

View file

@ -1,37 +0,0 @@
/*
* 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 { EuiBetaBadge, EuiText } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import React from 'react';
import styled from 'styled-components';
export const BetaBadgeRowWrapper = styled(EuiText)`
display: flex;
align-items: center;
`;
const Wrapper = styled.div`
padding-left: ${({ theme }) => theme.eui.paddingSizes.s};
`;
const betaBadgeLabel = i18n.translate('xpack.osquery.common.tabBetaBadgeLabel', {
defaultMessage: 'Beta',
});
const betaBadgeTooltipContent = i18n.translate('xpack.osquery.common.tabBetaBadgeTooltipContent', {
defaultMessage:
'This feature is under active development. Extra functionality is coming, and some functionality may change.',
});
const BetaBadgeComponent = () => (
<Wrapper>
<EuiBetaBadge label={betaBadgeLabel} tooltipContent={betaBadgeTooltipContent} />
</Wrapper>
);
export const BetaBadge = React.memo(BetaBadgeComponent);

View file

@ -0,0 +1,132 @@
/*
* 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 { EuiLink, EuiFormRow, EuiFilePicker, EuiSpacer } from '@elastic/eui';
import React, { useCallback, useState, useRef } from 'react';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
const SUPPORTED_CONFIG_EXTENSIONS = ['application/json', 'text/plain'];
const ExampleConfigLink = React.memo(() => (
<EuiLink
href="https://github.com/osquery/osquery/blob/master/tools/deployment/osquery.example.conf"
target="_blank"
>
<FormattedMessage
id="xpack.osquery.configUploader.exampleConfigLinkLabel"
defaultMessage="Example config"
/>
</EuiLink>
));
ExampleConfigLink.displayName = 'ExampleOsqueryConfigLink';
interface ConfigUploaderProps {
onChange: (payload: Record<string, unknown>) => void;
}
const ConfigUploaderComponent: React.FC<ConfigUploaderProps> = ({ onChange }) => {
const filePickerRef = useRef<EuiFilePicker>(null);
const [isInvalid, setIsInvalid] = useState<string | null>(null);
// @ts-expect-error update types
let fileReader;
const handleFileRead = () => {
// @ts-expect-error update types
const content = fileReader.result;
let parsedContent;
try {
parsedContent = JSON.parse(content.replaceAll('\\\n', ''), (key, value) => {
if (key === 'query') {
// remove any multiple spaces from the query
return value.replaceAll(/\s(?=\s)/gm, '');
}
return value;
});
setIsInvalid(null);
} catch (error) {
setIsInvalid(error);
// @ts-expect-error update types
filePickerRef.current?.removeFiles(new Event('fake'));
}
onChange(parsedContent);
// @ts-expect-error update types
filePickerRef.current?.removeFiles(new Event('fake'));
};
// @ts-expect-error update types
// eslint-disable-next-line react-hooks/exhaustive-deps
const handleFileChosen = (file) => {
fileReader = new FileReader();
fileReader.onloadend = handleFileRead;
fileReader.readAsText(file);
};
const handleInputChange = useCallback(
(inputFiles) => {
if (!inputFiles.length) {
return;
}
if (
inputFiles.length &&
((!!inputFiles[0].type.length &&
!SUPPORTED_CONFIG_EXTENSIONS.includes(inputFiles[0].type)) ??
!inputFiles[0].name.endsWith('.conf'))
) {
setIsInvalid(
i18n.translate('xpack.osquery.configUploader.unsupportedFileTypeText', {
defaultMessage:
'File type {fileType} is not supported, please upload {supportedFileTypes} config file',
values: {
fileType: inputFiles[0].type,
supportedFileTypes: SUPPORTED_CONFIG_EXTENSIONS.join(' or '),
},
})
);
// @ts-expect-error update types
filePickerRef.current?.removeFiles(new Event('fake'));
return;
}
handleFileChosen(inputFiles[0]);
},
[handleFileChosen]
);
return (
<>
<EuiSpacer size="xl" />
<EuiFormRow
fullWidth
labelAppend={<ExampleConfigLink />}
isInvalid={!!isInvalid}
error={<>{`${isInvalid}`}</>}
>
<EuiFilePicker
ref={filePickerRef}
id="osquery_config_picker"
initialPromptText={i18n.translate('xpack.osquery.configUploader.initialPromptTextLabel', {
defaultMessage: 'Select or drag and drop osquery config file',
})}
onChange={handleInputChange}
display="large"
fullWidth
isInvalid={!!isInvalid}
accept={SUPPORTED_CONFIG_EXTENSIONS.join(',')}
/>
</EuiFormRow>
</>
);
};
export const ConfigUploader = React.memo(ConfigUploaderComponent);

View file

@ -14,13 +14,11 @@ import { useKibana, isModifiedEvent, isLeftClickEvent } from '../common/lib/kiba
interface NavigationButtonsProps {
isDisabled?: boolean;
integrationPolicyId?: string | undefined;
agentPolicyId?: string | undefined;
}
const NavigationButtonsComponent: React.FC<NavigationButtonsProps> = ({
isDisabled = false,
integrationPolicyId,
agentPolicyId,
}) => {
const {
@ -52,7 +50,7 @@ const NavigationButtonsComponent: React.FC<NavigationButtonsProps> = ({
);
const packsHref = getUrlForApp(PLUGIN_ID, {
path: integrationPolicyId ? `/packs/${integrationPolicyId}/edit` : `/packs`,
path: `/packs`,
});
const packsClick = useCallback(
@ -60,11 +58,11 @@ const NavigationButtonsComponent: React.FC<NavigationButtonsProps> = ({
if (!isModifiedEvent(event) && isLeftClickEvent(event)) {
event.preventDefault();
navigateToApp(PLUGIN_ID, {
path: integrationPolicyId ? `/packs/${integrationPolicyId}/edit` : `/packs`,
path: `/packs`,
});
}
},
[navigateToApp, integrationPolicyId]
[navigateToApp]
);
return (

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { get, isEmpty, unset, set } from 'lodash';
import { pickBy, get, isEmpty, isString, unset, set, intersection } from 'lodash';
import satisfies from 'semver/functions/satisfies';
import {
EuiFlexGroup,
@ -15,7 +15,7 @@ import {
EuiLink,
EuiAccordion,
} from '@elastic/eui';
import React, { useEffect, useMemo, useState } from 'react';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { produce } from 'immer';
import { i18n } from '@kbn/i18n';
import useDebounce from 'react-use/lib/useDebounce';
@ -35,7 +35,105 @@ import {
import { useKibana } from '../common/lib/kibana';
import { NavigationButtons } from './navigation_buttons';
import { DisabledCallout } from './disabled_callout';
import { Form, useForm, Field, getUseField, FIELD_TYPES, fieldValidators } from '../shared_imports';
import { ConfigUploader } from './config_uploader';
import {
Form,
useForm,
useFormData,
Field,
getUseField,
FIELD_TYPES,
fieldValidators,
ValidationFunc,
} from '../shared_imports';
// https://github.com/elastic/beats/blob/master/x-pack/osquerybeat/internal/osqd/args.go#L57
const RESTRICTED_CONFIG_OPTIONS = [
'force',
'disable_watchdog',
'utc',
'events_expiry',
'extensions_socket',
'extensions_interval',
'extensions_timeout',
'pidfile',
'database_path',
'extensions_autoload',
'flagfile',
'config_plugin',
'logger_plugin',
'pack_delimiter',
'config_refresh',
];
export const configProtectedKeysValidator = (
...args: Parameters<ValidationFunc>
): ReturnType<ValidationFunc> => {
const [{ value }] = args;
let configJSON;
try {
configJSON = JSON.parse(value as string);
} catch (e) {
return;
}
const restrictedFlags = intersection(
Object.keys(configJSON?.options ?? {}),
RESTRICTED_CONFIG_OPTIONS
);
if (restrictedFlags.length) {
return {
code: 'ERR_RESTRICTED_OPTIONS',
message: i18n.translate(
'xpack.osquery.fleetIntegration.osqueryConfig.restrictedOptionsErrorMessage',
{
defaultMessage:
'The following osquery options are not supported and must be removed: {restrictedFlags}.',
values: {
restrictedFlags: restrictedFlags.join(', '),
},
}
),
};
}
return;
};
export const packConfigFilesValidator = (
...args: Parameters<ValidationFunc>
): ReturnType<ValidationFunc> => {
const [{ value }] = args;
let configJSON;
try {
configJSON = JSON.parse(value as string);
} catch (e) {
return;
}
const packsWithConfigPaths = Object.keys(pickBy(configJSON?.packs ?? {}, isString));
if (packsWithConfigPaths.length) {
return {
code: 'ERR_RESTRICTED_OPTIONS',
message: i18n.translate(
'xpack.osquery.fleetIntegration.osqueryConfig.packConfigFilesErrorMessage',
{
defaultMessage:
'Pack configuration files are not supported. These packs must be removed: {packNames}.',
values: {
packNames: packsWithConfigPaths.join(', '),
},
}
),
};
}
return;
};
const CommonUseField = getUseField({ component: Field });
@ -67,6 +165,16 @@ export const OsqueryManagedPolicyCreateImportExtension = React.memo<
defaultValue: {
config: JSON.stringify(get(newPolicy, 'inputs[0].config.osquery.value', {}), null, 2),
},
serializer: (formData) => {
let config;
try {
// @ts-expect-error update types
config = JSON.parse(formData.config);
} catch (e) {
config = {};
}
return { config };
},
schema: {
config: {
label: i18n.translate('xpack.osquery.fleetIntegration.osqueryConfig.configFieldLabel', {
@ -82,35 +190,63 @@ export const OsqueryManagedPolicyCreateImportExtension = React.memo<
{ allowEmptyString: true }
),
},
{ validator: packConfigFilesValidator },
{
validator: configProtectedKeysValidator,
},
],
},
},
});
const { isValid, getFormData } = configForm;
const [{ config }] = useFormData({ form: configForm, watch: 'config' });
const { isValid, setFieldValue } = configForm;
const agentsLinkHref = useMemo(() => {
if (!policy?.policy_id) return '#';
return getUrlForApp(PLUGIN_ID, {
path:
`#` +
pagePathGetters.policy_details({ policyId: policy?.policy_id })[1] +
'?openEnrollmentFlyout=true',
path: pagePathGetters.policy_details({ policyId: policy?.policy_id })[1],
});
}, [getUrlForApp, policy?.policy_id]);
const handleConfigUpload = useCallback(
(newConfig) => {
let currentPacks = {};
try {
currentPacks = JSON.parse(config)?.packs;
// eslint-disable-next-line no-empty
} catch (e) {}
if (newConfig) {
setFieldValue(
'config',
JSON.stringify(
{
...newConfig,
...(currentPacks || newConfig.packs
? { packs: { ...newConfig.packs, ...currentPacks } }
: {}),
},
null,
2
)
);
}
},
[config, setFieldValue]
);
useDebounce(
() => {
// if undefined it means that config was not modified
if (isValid === undefined) return;
const configData = getFormData().config;
const updatedPolicy = produce(newPolicy, (draft) => {
if (isEmpty(configData)) {
if (isEmpty(config)) {
unset(draft, 'inputs[0].config');
} else {
set(draft, 'inputs[0].config.osquery.value', configData);
set(draft, 'inputs[0].config.osquery.value', config);
}
return draft;
});
@ -118,7 +254,7 @@ export const OsqueryManagedPolicyCreateImportExtension = React.memo<
onChange({ isValid: !!isValid, updatedPolicy: isValid ? updatedPolicy : newPolicy });
},
500,
[isValid]
[isValid, config]
);
useEffect(() => {
@ -220,11 +356,7 @@ export const OsqueryManagedPolicyCreateImportExtension = React.memo<
</>
) : null}
<NavigationButtons
isDisabled={!editMode}
integrationPolicyId={policy?.id}
agentPolicyId={policy?.policy_id}
/>
<NavigationButtons isDisabled={!editMode} agentPolicyId={policy?.policy_id} />
<EuiSpacer size="xxl" />
<StyledEuiAccordion
id="advanced"
@ -238,6 +370,7 @@ export const OsqueryManagedPolicyCreateImportExtension = React.memo<
<EuiSpacer size="xs" />
<Form form={configForm}>
<CommonUseField path="config" />
<ConfigUploader onChange={handleConfigUpload} />
</Form>
</StyledEuiAccordion>
</>

View file

@ -48,14 +48,19 @@ const LiveQueryComponent: React.FC<LiveQueryProps> = ({
const { data: hasActionResultsPrivileges, isFetched } = useActionResultsPrivileges();
const defaultValue = useMemo(() => {
if (agentId || agentPolicyIds || query) {
if (agentId || agentPolicyIds?.length || query?.length) {
const agentSelection =
agentId || agentPolicyIds?.length
? {
allAgentsSelected: false,
agents: castArray(agentId ?? agentIds ?? []),
platformsSelected: [],
policiesSelected: agentPolicyIds ?? [],
}
: null;
return {
agentSelection: {
allAgentsSelected: false,
agents: castArray(agentId ?? agentIds ?? []),
platformsSelected: [],
policiesSelected: agentPolicyIds ?? [],
},
...(agentSelection ? { agentSelection } : {}),
query,
savedQueryId,
ecs_mapping,

View file

@ -5,9 +5,17 @@
* 2.0.
*/
import { EuiInMemoryTable, EuiBasicTableColumn, EuiLink, EuiToolTip } from '@elastic/eui';
import {
EuiButtonEmpty,
EuiText,
EuiPopover,
EuiInMemoryTable,
EuiBasicTableColumn,
EuiLink,
EuiToolTip,
} from '@elastic/eui';
import moment from 'moment-timezone';
import React, { useCallback, useMemo } from 'react';
import React, { useCallback, useMemo, useState } from 'react';
import styled from 'styled-components';
import { i18n } from '@kbn/i18n';
@ -15,6 +23,7 @@ import { PackagePolicy } from '../../../fleet/common';
import { useRouterNavigate } from '../common/lib/kibana';
import { usePacks } from './use_packs';
import { ActiveStateSwitch } from './active_state_switch';
import { AgentsPolicyLink } from '../agent_policies/agents_policy_link';
const UpdatedBy = styled.span`
white-space: nowrap;
@ -32,10 +41,53 @@ const renderName = (_: unknown, item: { id: string; attributes: { name: string }
<ScheduledQueryName id={item.id} name={item.attributes.name} />
);
export const AgentPoliciesPopover = ({ agentPolicyIds }: { agentPolicyIds: string[] }) => {
const [isPopoverOpen, setIsPopoverOpen] = useState(false);
const onButtonClick = useCallback(
() => setIsPopoverOpen((currentIsPopoverOpen) => !currentIsPopoverOpen),
[]
);
const closePopover = useCallback(() => setIsPopoverOpen(false), []);
const button = useMemo(
() => (
<EuiButtonEmpty flush="both" onClick={onButtonClick}>
<>{agentPolicyIds?.length ?? 0}</>
</EuiButtonEmpty>
),
[agentPolicyIds?.length, onButtonClick]
);
if (!agentPolicyIds?.length) {
return <>{agentPolicyIds?.length ?? 0}</>;
}
return (
<EuiPopover
button={button}
isOpen={isPopoverOpen}
closePopover={closePopover}
initialFocus={false}
>
<EuiText size="s">
{agentPolicyIds?.map((policyId) => (
<div key={policyId}>
<AgentsPolicyLink policyId={policyId} />
</div>
))}
</EuiText>
</EuiPopover>
);
};
const PacksTableComponent = () => {
const { data } = usePacks({});
const renderAgentPolicy = useCallback((policyIds) => <>{policyIds?.length ?? 0}</>, []);
const renderAgentPolicy = useCallback(
(agentPolicyIds) => <AgentPoliciesPopover agentPolicyIds={agentPolicyIds} />,
[]
);
const renderQueries = useCallback(
(queries) => <>{(queries && Object.keys(queries).length) ?? 0}</>,

View file

@ -93,6 +93,7 @@ const StyledFieldSpan = styled.span`
// align the icon to the inputs
const StyledButtonWrapper = styled.div`
margin-top: 11px;
width: 24px;
`;
const ECSFieldWrapper = styled(EuiFlexItem)`
@ -476,12 +477,19 @@ export const ECSMappingEditorForm = forwardRef<ECSMappingEditorFormRef, ECSMappi
[__validateFields, editForm, formData, validate]
);
useEffect(() => {
if (onAdd && !deepEqual(formData, currentFormData.current)) {
currentFormData.current = formData;
handleSubmit();
}
}, [handleSubmit, formData, onAdd]);
useEffect(() => {
if (onChange && !deepEqual(formData, currentFormData.current)) {
currentFormData.current = formData;
onChange(formData);
}
}, [defaultValue, formData, onChange]);
}, [defaultValue, formData, handleDeleteClick, onChange]);
useEffect(() => {
if (defaultValue) {
@ -497,18 +505,15 @@ export const ECSMappingEditorForm = forwardRef<ECSMappingEditorFormRef, ECSMappi
<EuiFlexGroup alignItems="flexStart" gutterSize="s" wrap>
<EuiFlexItem>
<CommonUseField
path="value.field"
component={OsqueryColumnField}
path="key"
component={ECSComboboxField}
// eslint-disable-next-line react-perf/jsx-no-new-object-as-prop
euiFieldProps={{
options: osquerySchemaOptions,
isDisabled,
}}
euiFieldProps={{ isDisabled }}
/>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<StyledButtonWrapper>
<EuiIcon type="arrowRight" />
<EuiIcon type="arrowLeft" />
</StyledButtonWrapper>
</EuiFlexItem>
</EuiFlexGroup>
@ -517,16 +522,19 @@ export const ECSMappingEditorForm = forwardRef<ECSMappingEditorFormRef, ECSMappi
<EuiFlexGroup alignItems="flexStart" gutterSize="s" wrap>
<ECSFieldWrapper>
<CommonUseField
path="key"
component={ECSComboboxField}
path="value.field"
component={OsqueryColumnField}
// eslint-disable-next-line react-perf/jsx-no-new-object-as-prop
euiFieldProps={{ isDisabled }}
euiFieldProps={{
options: osquerySchemaOptions,
isDisabled,
}}
/>
</ECSFieldWrapper>
{!isDisabled && (
<EuiFlexItem grow={false}>
<StyledButtonWrapper>
{defaultValue ? (
{defaultValue && (
<EuiButtonIcon
aria-label={i18n.translate(
'xpack.osquery.pack.queryFlyoutForm.deleteECSMappingRowButtonAriaLabel',
@ -538,18 +546,6 @@ export const ECSMappingEditorForm = forwardRef<ECSMappingEditorFormRef, ECSMappi
color="danger"
onClick={handleDeleteClick}
/>
) : (
<EuiButtonIcon
aria-label={i18n.translate(
'xpack.osquery.pack.queryFlyoutForm.addECSMappingRowButtonAriaLabel',
{
defaultMessage: 'Add ECS mapping row',
}
)}
iconType="plus"
color="primary"
onClick={handleSubmit}
/>
)}
</StyledButtonWrapper>
</EuiFlexItem>
@ -873,16 +869,16 @@ export const ECSMappingEditorField = ({
<EuiFlexItem>
<EuiFormLabel>
<FormattedMessage
id="xpack.osquery.pack.queryFlyoutForm.osqueryResultFieldLabel"
defaultMessage="Osquery result"
id="xpack.osquery.pack.queryFlyoutForm.ecsFieldLabel"
defaultMessage="ECS field"
/>
</EuiFormLabel>
</EuiFlexItem>
<EuiFlexItem>
<EuiFormLabel>
<FormattedMessage
id="xpack.osquery.pack.queryFlyoutForm.ecsFieldLabel"
defaultMessage="ECS field"
id="xpack.osquery.pack.queryFlyoutForm.osqueryResultFieldLabel"
defaultMessage="Osquery result"
/>
</EuiFormLabel>
</EuiFlexItem>

View file

@ -77,7 +77,7 @@ const ResultsTableComponent: React.FC<ResultsTableComponentProps> = ({
const getFleetAppUrl = useCallback(
(agentId) =>
getUrlForApp('fleet', {
path: `#` + pagePathGetters.agent_details({ agentId })[1],
path: pagePathGetters.agent_details({ agentId })[1],
}),
[getUrlForApp]
);

View file

@ -6,7 +6,14 @@
*/
import { get } from 'lodash';
import { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem, EuiCodeBlock, EuiSpacer } from '@elastic/eui';
import {
EuiButtonEmpty,
EuiFlexGroup,
EuiFlexItem,
EuiCodeBlock,
EuiSpacer,
EuiText,
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import React, { useMemo } from 'react';
import { useParams } from 'react-router-dom';
@ -16,7 +23,6 @@ import { WithHeaderLayout } from '../../../components/layouts';
import { useActionDetails } from '../../../actions/use_action_details';
import { ResultTabs } from '../../saved_queries/edit/tabs';
import { useBreadcrumbs } from '../../../common/hooks/use_breadcrumbs';
import { BetaBadge, BetaBadgeRowWrapper } from '../../../components/beta_badge';
const LiveQueryDetailsPageComponent = () => {
const { actionId } = useParams<{ actionId: string }>();
@ -37,15 +43,14 @@ const LiveQueryDetailsPageComponent = () => {
</EuiButtonEmpty>
</EuiFlexItem>
<EuiFlexItem>
<BetaBadgeRowWrapper>
<EuiText>
<h1>
<FormattedMessage
id="xpack.osquery.liveQueryDetails.pageTitle"
defaultMessage="Live query details"
/>
</h1>
<BetaBadge />
</BetaBadgeRowWrapper>
</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
),

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { EuiButton, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import React, { useMemo } from 'react';
@ -13,7 +13,6 @@ import { useKibana, useRouterNavigate } from '../../../common/lib/kibana';
import { ActionsTable } from '../../../actions/actions_table';
import { WithHeaderLayout } from '../../../components/layouts';
import { useBreadcrumbs } from '../../../common/hooks/use_breadcrumbs';
import { BetaBadge, BetaBadgeRowWrapper } from '../../../components/beta_badge';
const LiveQueriesPageComponent = () => {
const permissions = useKibana().services.application.capabilities.osquery;
@ -24,15 +23,14 @@ const LiveQueriesPageComponent = () => {
() => (
<EuiFlexGroup direction="column" gutterSize="m">
<EuiFlexItem>
<BetaBadgeRowWrapper>
<EuiText>
<h1>
<FormattedMessage
id="xpack.osquery.liveQueriesHistory.pageTitle"
defaultMessage="Live queries history"
/>
</h1>
<BetaBadge />
</BetaBadgeRowWrapper>
</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
),

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import React, { useEffect, useMemo, useState } from 'react';
import { useHistory, useLocation } from 'react-router-dom';
@ -15,7 +15,6 @@ import { WithHeaderLayout } from '../../../components/layouts';
import { useRouterNavigate } from '../../../common/lib/kibana';
import { LiveQuery } from '../../../live_queries';
import { useBreadcrumbs } from '../../../common/hooks/use_breadcrumbs';
import { BetaBadge, BetaBadgeRowWrapper } from '../../../components/beta_badge';
const NewLiveQueryPageComponent = () => {
useBreadcrumbs('live_query_new');
@ -49,15 +48,14 @@ const NewLiveQueryPageComponent = () => {
</EuiButtonEmpty>
</EuiFlexItem>
<EuiFlexItem>
<BetaBadgeRowWrapper>
<EuiText>
<h1>
<FormattedMessage
id="xpack.osquery.newLiveQuery.pageTitle"
defaultMessage="New live query"
/>
</h1>
<BetaBadge />
</BetaBadgeRowWrapper>
</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
),

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import React, { useMemo } from 'react';
@ -13,7 +13,6 @@ import { WithHeaderLayout } from '../../../components/layouts';
import { useRouterNavigate } from '../../../common/lib/kibana';
import { PackForm } from '../../../packs/form';
import { useBreadcrumbs } from '../../../common/hooks/use_breadcrumbs';
import { BetaBadge, BetaBadgeRowWrapper } from '../../../components/beta_badge';
const AddPackPageComponent = () => {
useBreadcrumbs('pack_add');
@ -31,12 +30,11 @@ const AddPackPageComponent = () => {
</EuiButtonEmpty>
</EuiFlexItem>
<EuiFlexItem>
<BetaBadgeRowWrapper>
<EuiText>
<h1>
<FormattedMessage id="xpack.osquery.addPack.pageTitle" defaultMessage="Add pack" />
</h1>
<BetaBadge />
</BetaBadgeRowWrapper>
</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
),

View file

@ -26,8 +26,8 @@ import { WithHeaderLayout } from '../../../components/layouts';
import { usePack } from '../../../packs/use_pack';
import { PackQueriesStatusTable } from '../../../packs/pack_queries_status_table';
import { useBreadcrumbs } from '../../../common/hooks/use_breadcrumbs';
import { BetaBadge, BetaBadgeRowWrapper } from '../../../components/beta_badge';
import { useAgentPolicyAgentIds } from '../../../agents/use_agent_policy_agent_ids';
import { AgentPoliciesPopover } from '../../../packs/packs_table';
const Divider = styled.div`
width: 0;
@ -69,7 +69,7 @@ const PackDetailsPageComponent = () => {
</EuiButtonEmpty>
</EuiFlexItem>
<EuiFlexItem>
<BetaBadgeRowWrapper>
<EuiText>
<h1>
<FormattedMessage
id="xpack.osquery.packDetails.pageTitle"
@ -80,8 +80,7 @@ const PackDetailsPageComponent = () => {
}}
/>
</h1>
<BetaBadge />
</BetaBadgeRowWrapper>
</EuiText>
</EuiFlexItem>
{data?.description && (
<EuiFlexItem>
@ -111,7 +110,7 @@ const PackDetailsPageComponent = () => {
<EuiDescriptionListDescription className="eui-textNoWrap">
{
// @ts-expect-error update types
data?.policy_ids?.length
<AgentPoliciesPopover agentPolicyIds={data?.policy_ids} />
}
</EuiDescriptionListDescription>
</EuiDescriptionList>

View file

@ -12,6 +12,7 @@ import {
EuiFlexGroup,
EuiFlexItem,
EuiLoadingContent,
EuiText,
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import React, { useCallback, useMemo, useState } from 'react';
@ -24,7 +25,6 @@ import { usePack } from '../../../packs/use_pack';
import { useDeletePack } from '../../../packs/use_delete_pack';
import { useBreadcrumbs } from '../../../common/hooks/use_breadcrumbs';
import { BetaBadge, BetaBadgeRowWrapper } from '../../../components/beta_badge';
const EditPackPageComponent = () => {
const { packId } = useParams<{ packId: string }>();
@ -67,7 +67,7 @@ const EditPackPageComponent = () => {
</EuiButtonEmpty>
</EuiFlexItem>
<EuiFlexItem>
<BetaBadgeRowWrapper>
<EuiText>
<h1>
<FormattedMessage
id="xpack.osquery.editPack.pageTitle"
@ -78,8 +78,7 @@ const EditPackPageComponent = () => {
}}
/>
</h1>
<BetaBadge />
</BetaBadgeRowWrapper>
</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
),

View file

@ -5,14 +5,13 @@
* 2.0.
*/
import { EuiButton, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiText } 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 { BetaBadge, BetaBadgeRowWrapper } from '../../../components/beta_badge';
const PacksPageComponent = () => {
const permissions = useKibana().services.application.capabilities.osquery;
@ -22,12 +21,11 @@ const PacksPageComponent = () => {
() => (
<EuiFlexGroup direction="column" gutterSize="m">
<EuiFlexItem>
<BetaBadgeRowWrapper>
<EuiText>
<h1>
<FormattedMessage id="xpack.osquery.packList.pageTitle" defaultMessage="Packs" />
</h1>
<BetaBadge />
</BetaBadgeRowWrapper>
</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
),

View file

@ -11,6 +11,7 @@ import {
EuiFlexGroup,
EuiFlexItem,
EuiConfirmModal,
EuiText,
} from '@elastic/eui';
import { isEmpty } from 'lodash/fp';
import React, { useCallback, useMemo, useState } from 'react';
@ -20,7 +21,6 @@ import { useParams } from 'react-router-dom';
import { useKibana, useRouterNavigate } from '../../../common/lib/kibana';
import { WithHeaderLayout } from '../../../components/layouts';
import { useBreadcrumbs } from '../../../common/hooks/use_breadcrumbs';
import { BetaBadge, BetaBadgeRowWrapper } from '../../../components/beta_badge';
import { EditSavedQueryForm } from './form';
import { useDeleteSavedQuery, useUpdateSavedQuery, useSavedQuery } from '../../../saved_queries';
@ -65,7 +65,7 @@ const EditSavedQueryPageComponent = () => {
</EuiButtonEmpty>
</EuiFlexItem>
<EuiFlexItem>
<BetaBadgeRowWrapper>
<EuiText>
<h1>
{viewMode ? (
<FormattedMessage
@ -87,8 +87,7 @@ const EditSavedQueryPageComponent = () => {
/>
)}
</h1>
<BetaBadge />
</BetaBadgeRowWrapper>
</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
),

View file

@ -12,6 +12,7 @@ import {
EuiButtonIcon,
EuiFlexGroup,
EuiFlexItem,
EuiText,
} from '@elastic/eui';
import React, { useCallback, useMemo, useState } from 'react';
import { i18n } from '@kbn/i18n';
@ -23,7 +24,6 @@ import { ECSMapping } from '../../../../common/schemas/common';
import { WithHeaderLayout } from '../../../components/layouts';
import { useBreadcrumbs } from '../../../common/hooks/use_breadcrumbs';
import { useKibana, useRouterNavigate } from '../../../common/lib/kibana';
import { BetaBadge, BetaBadgeRowWrapper } from '../../../components/beta_badge';
import { useSavedQueries } from '../../../saved_queries/use_saved_queries';
type SavedQuerySO = SavedObject<{
@ -218,15 +218,14 @@ const SavedQueriesPageComponent = () => {
() => (
<EuiFlexGroup alignItems="flexStart" direction="column" gutterSize="m">
<EuiFlexItem>
<BetaBadgeRowWrapper>
<EuiText>
<h1>
<FormattedMessage
id="xpack.osquery.savedQueryList.pageTitle"
defaultMessage="Saved queries"
/>
</h1>
<BetaBadge />
</BetaBadgeRowWrapper>
</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
),

View file

@ -5,14 +5,13 @@
* 2.0.
*/
import { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui';
import React, { useMemo } from 'react';
import { FormattedMessage } from '@kbn/i18n/react';
import { useRouterNavigate } from '../../../common/lib/kibana';
import { WithHeaderLayout } from '../../../components/layouts';
import { useBreadcrumbs } from '../../../common/hooks/use_breadcrumbs';
import { BetaBadge, BetaBadgeRowWrapper } from '../../../components/beta_badge';
import { NewSavedQueryForm } from './form';
import { useCreateSavedQuery } from '../../../saved_queries/use_create_saved_query';
@ -34,15 +33,14 @@ const NewSavedQueryPageComponent = () => {
</EuiButtonEmpty>
</EuiFlexItem>
<EuiFlexItem>
<BetaBadgeRowWrapper>
<EuiText>
<h1>
<FormattedMessage
id="xpack.osquery.addSavedQuery.pageTitle"
defaultMessage="Add saved query"
/>
</h1>
<BetaBadge />
</BetaBadgeRowWrapper>
</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
),

View file

@ -156,7 +156,12 @@ const SavedQueryFormComponent = forwardRef<SavedQueryFormRefObject, SavedQueryFo
<CommonUseField path="platform" component={PlatformCheckBoxGroupField} />
</EuiFlexItem>
</EuiFlexGroup>
{playgroundVisible && <PlaygroundFlyout enabled={isValid} onClose={handleHidePlayground} />}
{playgroundVisible && (
<PlaygroundFlyout
enabled={isValid !== undefined ? isValid : true}
onClose={handleHidePlayground}
/>
)}
</>
);
}

View file

@ -5,13 +5,14 @@
* 2.0.
*/
import { map, partialRight, pick } from 'lodash';
import { find, map, partialRight, pick } from 'lodash';
import { promises as fs } from 'fs';
import path from 'path';
import { run } from '@kbn/dev-utils';
const OSQUERY_COLUMN_SCHEMA_FIELDS = ['name', 'description', 'platforms', 'columns'];
const ELASTIC_OSQUERY_HOSTFS_TABLES = ['users', 'groups', 'processes'];
run(
async ({ flags }) => {
@ -20,9 +21,14 @@ run(
const schemaData = await require(schemaFile);
const formattedSchema = map(schemaData, partialRight(pick, OSQUERY_COLUMN_SCHEMA_FIELDS));
const elasticTables = map(ELASTIC_OSQUERY_HOSTFS_TABLES, (tableName) => ({
...find(formattedSchema, { name: tableName }),
name: `host_${tableName}`,
}));
formattedSchema.push(...elasticTables);
await fs.writeFile(
path.join(schemaPath, `v${flags.schema_version}-formatted.json`),
path.join(schemaPath, `${flags.schema_version}`),
JSON.stringify(formattedSchema)
);
},

View file

@ -17,6 +17,7 @@ import { PLUGIN_ID, OSQUERY_INTEGRATION_NAME } from '../../../common';
import { IRouter } from '../../../../../../src/core/server';
import { OsqueryAppContext } from '../../lib/osquery_app_context_services';
import { convertPackQueriesToSO } from '../pack/utils';
import { getInternalSavedObjectsClient } from '../../usage/collector';
export const createStatusRoute = (router: IRouter, osqueryContext: OsqueryAppContext) => {
router.get(
@ -27,18 +28,21 @@ export const createStatusRoute = (router: IRouter, osqueryContext: OsqueryAppCon
},
async (context, request, response) => {
const esClient = context.core.elasticsearch.client.asInternalUser;
const soClient = context.core.savedObjects.client;
const internalSavedObjectsClient = await getInternalSavedObjectsClient(
osqueryContext.getStartServices
);
const packageService = osqueryContext.service.getPackageService();
const packagePolicyService = osqueryContext.service.getPackagePolicyService();
const agentPolicyService = osqueryContext.service.getAgentPolicyService();
const packageInfo = await osqueryContext.service
.getPackageService()
?.getInstallation({ savedObjectsClient: soClient, pkgName: OSQUERY_INTEGRATION_NAME });
const packageInfo = await osqueryContext.service.getPackageService()?.getInstallation({
savedObjectsClient: internalSavedObjectsClient,
pkgName: OSQUERY_INTEGRATION_NAME,
});
if (packageInfo?.install_version && satisfies(packageInfo?.install_version, '<0.6.0')) {
try {
const policyPackages = await packagePolicyService?.list(soClient, {
const policyPackages = await packagePolicyService?.list(internalSavedObjectsClient, {
kuery: `${PACKAGE_POLICY_SAVED_OBJECT_TYPE}.package.name:${OSQUERY_INTEGRATION_NAME}`,
perPage: 10000,
page: 1,
@ -99,7 +103,7 @@ export const createStatusRoute = (router: IRouter, osqueryContext: OsqueryAppCon
await packageService?.ensureInstalledPackage({
esClient,
savedObjectsClient: soClient,
savedObjectsClient: internalSavedObjectsClient,
pkgName: OSQUERY_INTEGRATION_NAME,
});
@ -110,12 +114,15 @@ export const createStatusRoute = (router: IRouter, osqueryContext: OsqueryAppCon
// @ts-expect-error update types
pack.policy_ids.includes(key)
);
await packagePolicyService?.upgrade(soClient, esClient, [value]);
const packagePolicy = await packagePolicyService?.get(soClient, value);
await packagePolicyService?.upgrade(internalSavedObjectsClient, esClient, [value]);
const packagePolicy = await packagePolicyService?.get(
internalSavedObjectsClient,
value
);
if (packagePolicy) {
return packagePolicyService?.update(
soClient,
internalSavedObjectsClient,
esClient,
packagePolicy.id,
produce(packagePolicy, (draft) => {
@ -147,13 +154,13 @@ export const createStatusRoute = (router: IRouter, osqueryContext: OsqueryAppCon
const agentPolicyIds = uniq(map(policyPackages?.items, 'policy_id'));
const agentPolicies = mapKeys(
await agentPolicyService?.getByIds(soClient, agentPolicyIds),
await agentPolicyService?.getByIds(internalSavedObjectsClient, agentPolicyIds),
'id'
);
await Promise.all(
map(migrationObject.packs, async (packObject) => {
await soClient.create(
await internalSavedObjectsClient.create(
packSavedObjectType,
{
// @ts-expect-error update types
@ -183,7 +190,7 @@ export const createStatusRoute = (router: IRouter, osqueryContext: OsqueryAppCon
);
await packagePolicyService?.delete(
soClient,
internalSavedObjectsClient,
esClient,
migrationObject.packagePoliciesToDelete
);

View file

@ -18834,8 +18834,6 @@
"xpack.osquery.breadcrumbs.newSavedQueryPageTitle": "新規",
"xpack.osquery.breadcrumbs.overviewPageTitle": "概要",
"xpack.osquery.breadcrumbs.savedQueriesPageTitle": "保存されたクエリ",
"xpack.osquery.common.tabBetaBadgeLabel": "ベータ",
"xpack.osquery.common.tabBetaBadgeTooltipContent": "この機能は現在開発中です。他にも機能が追加され、機能によっては変更されるものもあります。",
"xpack.osquery.editSavedQuery.deleteSavedQueryButtonLabel": "クエリを削除",
"xpack.osquery.editSavedQuery.deleteSuccessToastMessageText": "保存されたクエリが正常に削除されました。",
"xpack.osquery.editSavedQuery.form.cancelButtonLabel": "キャンセル",

View file

@ -19105,8 +19105,6 @@
"xpack.osquery.breadcrumbs.newSavedQueryPageTitle": "新建",
"xpack.osquery.breadcrumbs.overviewPageTitle": "概览",
"xpack.osquery.breadcrumbs.savedQueriesPageTitle": "已保存查询",
"xpack.osquery.common.tabBetaBadgeLabel": "公测版",
"xpack.osquery.common.tabBetaBadgeTooltipContent": "我们正在开发此功能。将会有更多的功能,某些功能可能有变更。",
"xpack.osquery.createScheduledQuery.agentPolicyAgentsCountText": "{count, plural, other {# 个代理}}已注册",
"xpack.osquery.editSavedQuery.deleteSavedQueryButtonLabel": "删除查询",
"xpack.osquery.editSavedQuery.deleteSuccessToastMessageText": "已成功删除已保存查询",

View file

@ -24093,10 +24093,10 @@ react-popper@^2.2.4:
react-fast-compare "^3.0.1"
warning "^4.0.2"
react-query@^3.27.0:
version "3.27.0"
resolved "https://registry.yarnpkg.com/react-query/-/react-query-3.27.0.tgz#77c76377ae41d180c4718da07ef72df82e07306b"
integrity sha512-2MR5LBXnR6OMXQVLcv/57x1zkDNj6gK5J5mtjGi6pu0aQ6Y4jGQysVvkrAErMKMZJVZELFcYGA8LsGIHzlo/zg==
react-query@^3.28.0:
version "3.28.0"
resolved "https://registry.yarnpkg.com/react-query/-/react-query-3.28.0.tgz#1bfe12944860b2b773680054de37f19438f59d1d"
integrity sha512-OeX+nRqs7Zi0MvvtaKxKWE4N966UGtqSVuedOsz8cJh9eW195fgtYZ9nW3hZjIPPmeDY1PkArLUiV4wZvNRDPw==
dependencies:
"@babel/runtime" "^7.5.5"
broadcast-channel "^3.4.1"