From 45f5f3d14c414d7873475e0e49b74919c62c64c3 Mon Sep 17 00:00:00 2001
From: Julia Bardi <90178898+juliaElastic@users.noreply.github.com>
Date: Mon, 13 Feb 2023 12:58:04 +0100
Subject: [PATCH 01/20] [Fleet] fixed bug where installed beta integration was
visible multiple times (#150979)
## Summary
Fixes https://github.com/elastic/kibana/issues/150969
Filtering for only uploaded packages that are not in registry.
This fixes of bug of linux integration showing up multiple times when
the `/packages` call with `prerelease:false` and `prerelease:true`
options are quickly following each other.
To verify:
- Navigate to Integrations, search `linux`.
- Add linux integration to agent policy.
- Repeat the same process again.
- Navigate back to Integrations and search `linux`.
- Only one Linux metrics integration card should be visible.
Uploaded integrations are still visible:
### Checklist
- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
---
.../fleet/server/services/epm/packages/get.test.ts | 6 +++---
x-pack/plugins/fleet/server/services/epm/packages/get.ts | 8 +++++---
2 files changed, 8 insertions(+), 6 deletions(-)
diff --git a/x-pack/plugins/fleet/server/services/epm/packages/get.test.ts b/x-pack/plugins/fleet/server/services/epm/packages/get.test.ts
index 52170f6c302fd..661784a99ced5 100644
--- a/x-pack/plugins/fleet/server/services/epm/packages/get.test.ts
+++ b/x-pack/plugins/fleet/server/services/epm/packages/get.test.ts
@@ -209,7 +209,7 @@ describe('When using EPM `get` services', () => {
attributes: {
name: 'elasticsearch',
version: '0.0.1',
- install_status: 'upload',
+ install_source: 'upload',
},
},
],
@@ -221,16 +221,16 @@ describe('When using EPM `get` services', () => {
})
).resolves.toMatchObject([
{
+ id: 'elasticsearch',
name: 'elasticsearch',
version: '0.0.1',
title: 'Elasticsearch',
- status: 'upload',
savedObject: {
id: 'elasticsearch',
attributes: {
name: 'elasticsearch',
version: '0.0.1',
- install_status: 'upload',
+ install_source: 'upload',
},
},
},
diff --git a/x-pack/plugins/fleet/server/services/epm/packages/get.ts b/x-pack/plugins/fleet/server/services/epm/packages/get.ts
index 83db878ef5b83..7baddd428076b 100644
--- a/x-pack/plugins/fleet/server/services/epm/packages/get.ts
+++ b/x-pack/plugins/fleet/server/services/epm/packages/get.ts
@@ -74,9 +74,11 @@ export async function getPackages(
// get the installed packages
const packageSavedObjects = await getPackageSavedObjects(savedObjectsClient);
- const packagesNotInRegistry = packageSavedObjects.saved_objects
+ const uploadedPackagesNotInRegistry = packageSavedObjects.saved_objects
.filter((pkg) => !registryItems.some((item) => item.name === pkg.id))
- .map((pkg) => createInstallableFrom({ ...pkg.attributes, title: nameAsTitle(pkg.id) }, pkg));
+ .map((pkg) =>
+ createInstallableFrom({ ...pkg.attributes, title: nameAsTitle(pkg.id), id: pkg.id }, pkg)
+ );
const packageList = registryItems
.map((item) =>
@@ -85,7 +87,7 @@ export async function getPackages(
packageSavedObjects.saved_objects.find(({ id }) => id === item.name)
)
)
- .concat(packagesNotInRegistry as Installable)
+ .concat(uploadedPackagesNotInRegistry as Installable)
.sort(sortByName);
if (!excludeInstallStatus) {
From 2315285e37274d8aa724d517055a34272efbe3d7 Mon Sep 17 00:00:00 2001
From: Pablo Machado
Date: Mon, 13 Feb 2023 13:30:26 +0100
Subject: [PATCH 02/20] [Security Solutions] Fix link to ML Job is wrong when
searching within ML Job Settings UI (#150881)
issue: https://github.com/elastic/kibana/issues/150875
## Summary
Describe the bug:
The link to an ML job is wrong when searching for a job.
Steps to reproduce:
1. Open ML Job Settings UI
2. Type DNS in the search bar
3. Verify that the links have the wrong job Id.
### Before
https://user-images.githubusercontent.com/1490444/218104808-94c93669-2de3-4fba-88c9-5f2b7ccaa391.mp4
### After
https://user-images.githubusercontent.com/1490444/218105267-b5aa118c-9d78-4648-9892-68afd5e2707f.mov
---
.../analyze_dataset_in_ml_action.tsx | 31 +++++++++--------
.../plugins/ml/public/locator/use_ml_href.ts | 6 ++--
.../ml/links/create_explorer_link.tsx | 33 +++++++++++--------
.../ml_popover/jobs_table/jobs_table.tsx | 15 ++++++---
.../rules/ml_job_link/ml_job_link.tsx | 15 ++++++---
5 files changed, 61 insertions(+), 39 deletions(-)
diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/analyze_dataset_in_ml_action.tsx b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/analyze_dataset_in_ml_action.tsx
index 4d17b6ed9e8c5..6af0607580c4d 100644
--- a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/analyze_dataset_in_ml_action.tsx
+++ b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/analyze_dataset_in_ml_action.tsx
@@ -25,21 +25,26 @@ export const AnalyzeCategoryDatasetInMlAction: React.FunctionComponent<{
services: { ml, http, application },
} = useKibanaContextForPlugin();
- const viewAnomalyInMachineLearningLink = useMlHref(ml, http.basePath.get(), {
- page: ML_PAGES.SINGLE_METRIC_VIEWER,
- pageState: {
- jobIds: [categorizationJobId],
- timeRange: {
- from: moment(timeRange.startTime).format('YYYY-MM-DDTHH:mm:ss.SSSZ'),
- to: moment(timeRange.endTime).format('YYYY-MM-DDTHH:mm:ss.SSSZ'),
- mode: 'absolute',
- },
- entities: {
- [partitionField]: dataset,
- mlcategory: `${categoryId}`,
+ const viewAnomalyInMachineLearningLink = useMlHref(
+ ml,
+ http.basePath.get(),
+ {
+ page: ML_PAGES.SINGLE_METRIC_VIEWER,
+ pageState: {
+ jobIds: [categorizationJobId],
+ timeRange: {
+ from: moment(timeRange.startTime).format('YYYY-MM-DDTHH:mm:ss.SSSZ'),
+ to: moment(timeRange.endTime).format('YYYY-MM-DDTHH:mm:ss.SSSZ'),
+ mode: 'absolute',
+ },
+ entities: {
+ [partitionField]: dataset,
+ mlcategory: `${categoryId}`,
+ },
},
},
- });
+ [categorizationJobId]
+ );
const handleClick = useCallback(
(e) => {
diff --git a/x-pack/plugins/ml/public/locator/use_ml_href.ts b/x-pack/plugins/ml/public/locator/use_ml_href.ts
index 59b34dffa7c13..1ed7321f3fd2f 100644
--- a/x-pack/plugins/ml/public/locator/use_ml_href.ts
+++ b/x-pack/plugins/ml/public/locator/use_ml_href.ts
@@ -5,6 +5,7 @@
* 2.0.
*/
+import { DependencyList } from 'react';
import { MlPluginStart } from '..';
import { MlLocatorParams } from '../../common/types/locator';
@@ -15,10 +16,11 @@ import { MlLocatorParams } from '../../common/types/locator';
export const useMlHref = (
ml: MlPluginStart | undefined,
basePath: string | undefined,
- params: MlLocatorParams
+ params: MlLocatorParams,
+ dependencies?: DependencyList
) => {
return ml && ml.locator
- ? ml.locator!.useUrl(params)
+ ? ml.locator.useUrl(params, undefined, dependencies)
: basePath !== undefined
? `${basePath}/app/ml/${params.page}`
: '';
diff --git a/x-pack/plugins/security_solution/public/common/components/ml/links/create_explorer_link.tsx b/x-pack/plugins/security_solution/public/common/components/ml/links/create_explorer_link.tsx
index 9f7ed8a526e12..400d715754e92 100644
--- a/x-pack/plugins/security_solution/public/common/components/ml/links/create_explorer_link.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/ml/links/create_explorer_link.tsx
@@ -28,22 +28,27 @@ export const ExplorerLink: React.FC = ({
services: { ml, http },
} = useKibana();
- const explorerUrl = useMlHref(ml, http.basePath.get(), {
- page: 'explorer',
- pageState: {
- jobIds: [score.jobId],
- timeRange: {
- from: new Date(startDate).toISOString(),
- to: new Date(endDate).toISOString(),
- mode: 'absolute',
- },
- refreshInterval: {
- pause: true,
- value: 0,
- display: 'Off',
+ const explorerUrl = useMlHref(
+ ml,
+ http.basePath.get(),
+ {
+ page: 'explorer',
+ pageState: {
+ jobIds: [score.jobId],
+ timeRange: {
+ from: new Date(startDate).toISOString(),
+ to: new Date(endDate).toISOString(),
+ mode: 'absolute',
+ },
+ refreshInterval: {
+ pause: true,
+ value: 0,
+ display: 'Off',
+ },
},
},
- });
+ [score.jobId]
+ );
if (!explorerUrl) return null;
diff --git a/x-pack/plugins/security_solution/public/common/components/ml_popover/jobs_table/jobs_table.tsx b/x-pack/plugins/security_solution/public/common/components/ml_popover/jobs_table/jobs_table.tsx
index f8c27cd71b1d2..8b3bbfa3f5aeb 100644
--- a/x-pack/plugins/security_solution/public/common/components/ml_popover/jobs_table/jobs_table.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/ml_popover/jobs_table/jobs_table.tsx
@@ -47,12 +47,17 @@ const JobName = ({ id, name, description, basePath }: JobNameProps) => {
services: { ml },
} = useKibana();
- const jobUrl = useMlHref(ml, basePath, {
- page: ML_PAGES.ANOMALY_DETECTION_JOBS_MANAGE,
- pageState: {
- jobId: id,
+ const jobUrl = useMlHref(
+ ml,
+ basePath,
+ {
+ page: ML_PAGES.ANOMALY_DETECTION_JOBS_MANAGE,
+ pageState: {
+ jobId: id,
+ },
},
- });
+ [id]
+ );
return (
diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/ml_job_link/ml_job_link.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/ml_job_link/ml_job_link.tsx
index 7680b5b72dff3..cbdddae858085 100644
--- a/x-pack/plugins/security_solution/public/detections/components/rules/ml_job_link/ml_job_link.tsx
+++ b/x-pack/plugins/security_solution/public/detections/components/rules/ml_job_link/ml_job_link.tsx
@@ -25,12 +25,17 @@ const MlJobLinkComponent: React.FC = ({ jobId, jobName }) => {
const {
services: { http, ml },
} = useKibana();
- const jobUrl = useMlHref(ml, http.basePath.get(), {
- page: ML_PAGES.ANOMALY_DETECTION_JOBS_MANAGE,
- pageState: {
- jobId: [jobId],
+ const jobUrl = useMlHref(
+ ml,
+ http.basePath.get(),
+ {
+ page: ML_PAGES.ANOMALY_DETECTION_JOBS_MANAGE,
+ pageState: {
+ jobId: [jobId],
+ },
},
- });
+ [jobId]
+ );
return (
From a37376e72022c6c6e884ed94edbf63a99c70789d Mon Sep 17 00:00:00 2001
From: Gloria Hornero
Date: Mon, 13 Feb 2023 14:45:29 +0100
Subject: [PATCH 03/20] [Security Solution] Automates C18001 (#150973)
Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
---
.../cypress/e2e/cases/creation.cy.ts | 11 ++++++++++-
.../security_solution/cypress/screens/overview.ts | 3 +++
2 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/x-pack/plugins/security_solution/cypress/e2e/cases/creation.cy.ts b/x-pack/plugins/security_solution/cypress/e2e/cases/creation.cy.ts
index 0eaa67b3e1096..46bfd1f388ea6 100644
--- a/x-pack/plugins/security_solution/cypress/e2e/cases/creation.cy.ts
+++ b/x-pack/plugins/security_solution/cypress/e2e/cases/creation.cy.ts
@@ -37,6 +37,8 @@ import {
} from '../../screens/case_details';
import { TIMELINE_DESCRIPTION, TIMELINE_QUERY, TIMELINE_TITLE } from '../../screens/timeline';
+import { OVERVIEW_CASE_DESCRIPTION, OVERVIEW_CASE_NAME } from '../../screens/overview';
+
import { goToCaseDetails, goToCreateNewCase } from '../../tasks/all_cases';
import { createTimeline } from '../../tasks/api_calls/timelines';
import { openCaseTimeline } from '../../tasks/case_details';
@@ -50,7 +52,7 @@ import {
} from '../../tasks/create_new_case';
import { loginWithUser, visitWithoutDateRange } from '../../tasks/login';
-import { CASES_URL } from '../../urls/navigation';
+import { CASES_URL, OVERVIEW_URL } from '../../urls/navigation';
describe('Cases', () => {
before(() => {
@@ -120,5 +122,12 @@ describe('Cases', () => {
cy.get(TIMELINE_TITLE).contains(this.mycase.timeline.title);
cy.get(TIMELINE_DESCRIPTION).contains(this.mycase.timeline.description);
cy.get(TIMELINE_QUERY).should('have.text', this.mycase.timeline.query);
+
+ cy.visit(OVERVIEW_URL);
+ cy.get(OVERVIEW_CASE_NAME).should('have.text', this.mycase.name);
+ cy.get(OVERVIEW_CASE_DESCRIPTION).should(
+ 'have.text',
+ `${this.mycase.description} ${this.mycase.timeline.title}`
+ );
});
});
diff --git a/x-pack/plugins/security_solution/cypress/screens/overview.ts b/x-pack/plugins/security_solution/cypress/screens/overview.ts
index 12de337a51aa3..e7357adc2353d 100644
--- a/x-pack/plugins/security_solution/cypress/screens/overview.ts
+++ b/x-pack/plugins/security_solution/cypress/screens/overview.ts
@@ -140,6 +140,9 @@ export const NETWORK_STATS = [
STAT_TLS,
];
+export const OVERVIEW_CASE_NAME = '[data-test-subj="case-details-link"]';
+export const OVERVIEW_CASE_DESCRIPTION = '.euiText.euiMarkdownFormat';
+
export const OVERVIEW_HOST_STATS = '[data-test-subj="overview-hosts-stats"]';
export const OVERVIEW_NETWORK_STATS = '[data-test-subj="overview-network-stats"]';
From 39197628d2be02fb9a97666993c0514c1950b382 Mon Sep 17 00:00:00 2001
From: Kevin Logan <56395104+kevinlog@users.noreply.github.com>
Date: Mon, 13 Feb 2023 09:14:40 -0500
Subject: [PATCH 04/20] [Security Solution] Update error codes for reporting es
connection errors (#150792)
## Summary
This PR fixes a bug where we weren't checking the uppercase version of
input statuses. In addition, it adds another error code to check for
Endpoint when it cannot ship data to ES.
We also needed to check for `DEGRADED` status in addition to `FAILED`
Mac OS full disk access reporting
ES connection errors:

Response from Agent/Endpoint
### Checklist
Delete any items that are not applicable to this PR.
- [x] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)
- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
---------
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
---
.../plugins/fleet/common/constants/agent.ts | 14 +++++------
.../agent_details_integrations.tsx | 4 ++-
.../common/endpoint/constants.ts | 1 +
.../data_generators/fleet_agent_generator.ts | 2 +-
.../package_action.formatter.test.ts | 25 +++++++++++++++++--
.../package_action_formatter.ts | 7 ++++--
.../endpoint_generic_errors_list.tsx | 2 +-
7 files changed, 41 insertions(+), 14 deletions(-)
diff --git a/x-pack/plugins/fleet/common/constants/agent.ts b/x-pack/plugins/fleet/common/constants/agent.ts
index 6d4133c32c6c7..d05dd66bb096b 100644
--- a/x-pack/plugins/fleet/common/constants/agent.ts
+++ b/x-pack/plugins/fleet/common/constants/agent.ts
@@ -27,11 +27,11 @@ export const AGENT_ACTIONS_INDEX = '.fleet-actions';
export const AGENT_ACTIONS_RESULTS_INDEX = '.fleet-actions-results';
export const FleetServerAgentComponentStatuses = [
- 'starting',
- 'configuring',
- 'healthy',
- 'degraded',
- 'failed',
- 'stopping',
- 'stopped',
+ 'STARTING',
+ 'CONFIGURING',
+ 'HEALTHY',
+ 'DEGRADED',
+ 'FAILED',
+ 'STOPPING',
+ 'STOPPED',
] as const;
diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_details/agent_details_integrations.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_details/agent_details_integrations.tsx
index 16504516c72ab..9283416a111a8 100644
--- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_details/agent_details_integrations.tsx
+++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_details/agent_details_integrations.tsx
@@ -131,7 +131,9 @@ export const AgentDetailsIntegration: React.FunctionComponent<{
});
filteredPackageComponents.forEach((component) => {
- packageErrorUnits.push(...filter(component.units, { status: 'failed' }));
+ packageErrorUnits.push(
+ ...filter(component.units, (u) => u.status === 'DEGRADED' || u.status === 'FAILED')
+ );
});
return packageErrorUnits;
}, [agent.components, packagePolicy]);
diff --git a/x-pack/plugins/security_solution/common/endpoint/constants.ts b/x-pack/plugins/security_solution/common/endpoint/constants.ts
index d005f449d76a3..175f1cfdf14e4 100644
--- a/x-pack/plugins/security_solution/common/endpoint/constants.ts
+++ b/x-pack/plugins/security_solution/common/endpoint/constants.ts
@@ -94,6 +94,7 @@ export const ENDPOINT_DEFAULT_PAGE_SIZE = 10;
export const ENDPOINT_ERROR_CODES: Record = {
ES_CONNECTION_ERROR: -272,
+ OUTPUT_SERVER_ERROR: -273,
};
export const ENDPOINT_FIELDS_SEARCH_STRATEGY = 'endpointFields';
diff --git a/x-pack/plugins/security_solution/common/endpoint/data_generators/fleet_agent_generator.ts b/x-pack/plugins/security_solution/common/endpoint/data_generators/fleet_agent_generator.ts
index 39e7efc47c455..ea5c377102b17 100644
--- a/x-pack/plugins/security_solution/common/endpoint/data_generators/fleet_agent_generator.ts
+++ b/x-pack/plugins/security_solution/common/endpoint/data_generators/fleet_agent_generator.ts
@@ -88,7 +88,7 @@ export class FleetAgentGenerator extends BaseDataGenerator {
FleetServerAgentComponentStatuses
);
const componentInputPayload =
- componentStatus === 'failed'
+ componentStatus === 'FAILED'
? {
error: {
code: ENDPOINT_ERROR_CODES.ES_CONNECTION_ERROR,
diff --git a/x-pack/plugins/security_solution/public/management/components/package_action_item/package_action.formatter.test.ts b/x-pack/plugins/security_solution/public/management/components/package_action_item/package_action.formatter.test.ts
index dc5c443e15e2e..2dee21fcc89da 100644
--- a/x-pack/plugins/security_solution/public/management/components/package_action_item/package_action.formatter.test.ts
+++ b/x-pack/plugins/security_solution/public/management/components/package_action_item/package_action.formatter.test.ts
@@ -15,7 +15,7 @@ describe('PackageActionFormatter', () => {
const unit: FleetServerAgentComponentUnit = {
id: 'test-id',
type: 'input',
- status: 'failed',
+ status: 'FAILED',
message: 'test message',
payload: {
error: {
@@ -32,11 +32,32 @@ describe('PackageActionFormatter', () => {
expect(formatter.linkUrl).toBe(docLinks.es_connection);
});
+ it('correctly formats output connection error', () => {
+ const unit: FleetServerAgentComponentUnit = {
+ id: 'test-id',
+ type: 'input',
+ status: 'DEGRADED',
+ message: 'test message',
+ payload: {
+ error: {
+ code: ENDPOINT_ERROR_CODES.OUTPUT_SERVER_ERROR,
+ message: 'an error message',
+ },
+ },
+ };
+ const docLinks = { es_connection: 'somedoclink' };
+ const formatter = new PackageActionFormatter(unit, docLinks);
+ expect(formatter.key).toBe('es_connection');
+ expect(formatter.title).toBe(titles.get('es_connection'));
+ expect(formatter.description).toBe(descriptions.get('es_connection'));
+ expect(formatter.linkUrl).toBe(docLinks.es_connection);
+ });
+
it('correct formats generic error', () => {
const unit: FleetServerAgentComponentUnit = {
id: 'test-id',
type: 'input',
- status: 'failed',
+ status: 'FAILED',
message: 'test message',
};
const docLinks = { es_connection: 'somedoclink' };
diff --git a/x-pack/plugins/security_solution/public/management/components/package_action_item/package_action_formatter.ts b/x-pack/plugins/security_solution/public/management/components/package_action_item/package_action_formatter.ts
index 9af6983ecfcdb..f611f3d78f1c1 100644
--- a/x-pack/plugins/security_solution/public/management/components/package_action_item/package_action_formatter.ts
+++ b/x-pack/plugins/security_solution/public/management/components/package_action_item/package_action_formatter.ts
@@ -101,9 +101,12 @@ export class PackageActionFormatter {
code: number,
status: FleetServerAgentComponentStatus
): PackageActions {
- if (code === ENDPOINT_ERROR_CODES.ES_CONNECTION_ERROR) {
+ if (
+ code === ENDPOINT_ERROR_CODES.ES_CONNECTION_ERROR ||
+ code === ENDPOINT_ERROR_CODES.OUTPUT_SERVER_ERROR
+ ) {
return 'es_connection';
- } else if (status === 'failed') {
+ } else if (status === 'FAILED' || status === 'DEGRADED') {
return 'policy_failure';
} else {
throw new Error(`Invalid error code ${code}`);
diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_generic_errors_list.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_generic_errors_list.tsx
index babb4c78af147..e3902e965632a 100644
--- a/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_generic_errors_list.tsx
+++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_generic_errors_list.tsx
@@ -23,7 +23,7 @@ export const EndpointGenericErrorsList = memo(
const globalEndpointErrors = useMemo(() => {
const errors: PackageActionFormatter[] = [];
packageErrors.forEach((unit) => {
- if (unit.status === 'failed') {
+ if (unit.status === 'FAILED' || unit.status === 'DEGRADED') {
errors.push(
new PackageActionFormatter(
unit,
From 2749e95fe0a5f0d1617129765eb3b84ea0cec097 Mon Sep 17 00:00:00 2001
From: "Devin W. Hurley"
Date: Mon, 13 Feb 2023 09:29:58 -0500
Subject: [PATCH 05/20] [Security Solution] [Exceptions] fixes download from
list details page (#150933)
## Summary
Fixes: https://github.com/elastic/kibana/issues/148139
When exporting a shared exception list from that lists' detailed view,
the exported file would not have the `.ndjson` extension appended to it.
I think we should update this to be a single hook used between the two
views.
---
.../public/exceptions/hooks/use_list_detail_view/index.ts | 5 +++++
.../public/exceptions/pages/list_detail_view/index.tsx | 4 +++-
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/x-pack/plugins/security_solution/public/exceptions/hooks/use_list_detail_view/index.ts b/x-pack/plugins/security_solution/public/exceptions/hooks/use_list_detail_view/index.ts
index 949854d78ae65..3359ccb760b05 100644
--- a/x-pack/plugins/security_solution/public/exceptions/hooks/use_list_detail_view/index.ts
+++ b/x-pack/plugins/security_solution/public/exceptions/hooks/use_list_detail_view/index.ts
@@ -190,6 +190,10 @@ export const useListDetailsView = (exceptionListId: string) => {
[list, exportExceptionList, handleErrorStatus, toasts]
);
+ const handleOnDownload = useCallback(() => {
+ setExportedList(undefined);
+ }, []);
+
// #region DeleteList
const handleDeleteSuccess = useCallback(
@@ -366,6 +370,7 @@ export const useListDetailsView = (exceptionListId: string) => {
canUserEditList,
linkedRules,
exportedList,
+ handleOnDownload,
viewerStatus,
showManageRulesFlyout,
headerBackOptions,
diff --git a/x-pack/plugins/security_solution/public/exceptions/pages/list_detail_view/index.tsx b/x-pack/plugins/security_solution/public/exceptions/pages/list_detail_view/index.tsx
index 0be51bf851ba1..fc09a603b2e13 100644
--- a/x-pack/plugins/security_solution/public/exceptions/pages/list_detail_view/index.tsx
+++ b/x-pack/plugins/security_solution/public/exceptions/pages/list_detail_view/index.tsx
@@ -39,6 +39,7 @@ export const ListsDetailViewComponent: FC = () => {
listId,
linkedRules,
exportedList,
+ handleOnDownload,
viewerStatus,
listName,
listDescription,
@@ -91,7 +92,7 @@ export const ListsDetailViewComponent: FC = () => {
onManageRules={onManageRules}
/>
-
+
{
canUserEditList,
disableManageButton,
exportedList,
+ handleOnDownload,
headerBackOptions,
invalidListId,
isLoading,
From 4f1f2a84fdf3421d6b56aac82274dee2e881d376 Mon Sep 17 00:00:00 2001
From: Dmitrii Shevchenko
Date: Mon, 13 Feb 2023 16:00:20 +0100
Subject: [PATCH 06/20] [Security Solution] Invalidate prebuilt rules status
after package upgrade or installation (#150292)
**Resolves: https://github.com/elastic/kibana/issues/150306**
## Summary
Fixes the Load Prebuilt rules button not visible when users visit the
rules management page for the first time (no prebuilt detection rules
package installed).
## Steps to test
1. Ensure that the detection engine package is not installed:
2. Navigate to the rules management page.
### Previously
The "Load Elastic Prebuilt Rules" button is not visible, and users
cannot install prebuilt rules.
### With the fix
Users now see loading animation, indicating that the package
installation happens in the background. Once the package installation
finishes, users see the Load Prebuilt rules button appear.
https://user-images.githubusercontent.com/1938181/217585144-879fe288-0ede-4e01-b585-6aced1d89379.mov
---
.../public/app/home/index.tsx | 2 +-
.../hooks/use_upgrade_security_packages.ts | 113 ------------------
.../rule_management/api/api.ts | 61 ++++++++++
...se_bulk_install_fleet_packages_mutation.ts | 44 +++++++
.../use_install_fleet_package_mutation.ts | 41 +++++++
.../logic/use_install_pre_packaged_rules.ts | 11 +-
.../use_upgrade_secuirty_packages.test.tsx | 109 +++++++----------
.../logic/use_upgrade_security_packages.ts | 95 +++++++++++++++
.../components/rules_table/rules_tables.tsx | 4 +-
.../load_prepackaged_rules.tsx | 10 +-
10 files changed, 304 insertions(+), 186 deletions(-)
delete mode 100644 x-pack/plugins/security_solution/public/common/hooks/use_upgrade_security_packages.ts
create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_bulk_install_fleet_packages_mutation.ts
create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_install_fleet_package_mutation.ts
rename x-pack/plugins/security_solution/public/{common/hooks => detection_engine/rule_management/logic}/use_upgrade_secuirty_packages.test.tsx (57%)
create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_upgrade_security_packages.ts
diff --git a/x-pack/plugins/security_solution/public/app/home/index.tsx b/x-pack/plugins/security_solution/public/app/home/index.tsx
index 5aecd3cdc62ba..d74eb3eed5af7 100644
--- a/x-pack/plugins/security_solution/public/app/home/index.tsx
+++ b/x-pack/plugins/security_solution/public/app/home/index.tsx
@@ -18,7 +18,6 @@ import {
getScopeFromPath,
useSourcererDataView,
} from '../../common/containers/sourcerer';
-import { useUpgradeSecurityPackages } from '../../common/hooks/use_upgrade_security_packages';
import { GlobalHeader } from './global_header';
import { ConsoleManager } from '../../management/components/console/components/console_manager';
@@ -26,6 +25,7 @@ import { TourContextProvider } from '../../common/components/guided_onboarding_t
import { useUrlState } from '../../common/hooks/use_url_state';
import { useUpdateBrowserTitle } from '../../common/hooks/use_update_browser_title';
+import { useUpgradeSecurityPackages } from '../../detection_engine/rule_management/logic/use_upgrade_security_packages';
interface HomePageProps {
children: React.ReactNode;
diff --git a/x-pack/plugins/security_solution/public/common/hooks/use_upgrade_security_packages.ts b/x-pack/plugins/security_solution/public/common/hooks/use_upgrade_security_packages.ts
deleted file mode 100644
index 3ffb3ca149b20..0000000000000
--- a/x-pack/plugins/security_solution/public/common/hooks/use_upgrade_security_packages.ts
+++ /dev/null
@@ -1,113 +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 { useEffect } from 'react';
-import type { HttpFetchOptions, HttpStart } from '@kbn/core/public';
-import type { BulkInstallPackagesResponse } from '@kbn/fleet-plugin/common';
-import { epmRouteService } from '@kbn/fleet-plugin/common';
-import type { InstallPackageResponse } from '@kbn/fleet-plugin/common/types';
-import { KibanaServices, useKibana } from '../lib/kibana';
-import { useUserPrivileges } from '../components/user_privileges';
-import { PREBUILT_RULES_PACKAGE_NAME } from '../../../common/detection_engine/constants';
-
-/**
- * Requests that the endpoint and security_detection_engine package be upgraded to the latest version
- *
- * @param http an http client for sending the request
- * @param options an object containing options for the request
- * @param prebuiltRulesPackageVersion specific version of the prebuilt rules package to install
- */
-const sendUpgradeSecurityPackages = async (
- http: HttpStart,
- options: HttpFetchOptions = {},
- prebuiltRulesPackageVersion?: string
-): Promise => {
- const packages = ['endpoint', PREBUILT_RULES_PACKAGE_NAME];
- const requests: Array> = [];
-
- // If `prebuiltRulesPackageVersion` is provided, try to install that version
- // Must be done as two separate requests as bulk API doesn't support versions
- if (prebuiltRulesPackageVersion != null) {
- packages.splice(packages.indexOf(PREBUILT_RULES_PACKAGE_NAME), 1);
- requests.push(
- http.post(
- epmRouteService.getInstallPath(PREBUILT_RULES_PACKAGE_NAME, prebuiltRulesPackageVersion),
- {
- ...options,
- body: JSON.stringify({
- force: true,
- }),
- }
- )
- );
- }
-
- // Note: if `prerelease:true` option is provided, endpoint package will also be installed as prerelease
- requests.push(
- http.post(epmRouteService.getBulkInstallPath(), {
- ...options,
- body: JSON.stringify({
- packages,
- }),
- })
- );
-
- await Promise.allSettled(requests);
-};
-
-export const useUpgradeSecurityPackages = () => {
- const context = useKibana();
- const canAccessFleet = useUserPrivileges().endpointPrivileges.canAccessFleet;
-
- useEffect(() => {
- const abortController = new AbortController();
-
- // cancel any ongoing requests
- const abortRequests = () => {
- abortController.abort();
- };
-
- if (canAccessFleet) {
- const signal = abortController.signal;
-
- (async () => {
- try {
- // Make sure fleet is initialized first
- await context.services.fleet?.isInitialized();
-
- // Always install the latest package if in dev env or snapshot build
- const isPrerelease =
- KibanaServices.getKibanaVersion().includes('-SNAPSHOT') ||
- KibanaServices.getKibanaBranch() === 'main';
-
- // ignore the response for now since we aren't notifying the user
- // Note: response would be Promise.allSettled, so must iterate all responses for errors and throw manually
- await sendUpgradeSecurityPackages(
- context.services.http,
- {
- query: {
- prerelease: isPrerelease,
- },
- signal,
- },
- KibanaServices.getPrebuiltRulesPackageVersion()
- );
- } catch (error) {
- // Ignore Errors, since this should not hinder the user's ability to use the UI
-
- // log to console, except if the error occurred due to aborting a request
- if (!abortController.signal.aborted) {
- // eslint-disable-next-line no-console
- console.error(error);
- }
- }
- })();
-
- return abortRequests;
- }
- }, [canAccessFleet, context.services.fleet, context.services.http]);
-};
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.ts
index 87334a121c993..386dbf3c7b525 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.ts
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.ts
@@ -10,6 +10,9 @@ import type {
ExceptionListItemSchema,
} from '@kbn/securitysolution-io-ts-list-types';
+import type { BulkInstallPackagesResponse } from '@kbn/fleet-plugin/common';
+import { epmRouteService } from '@kbn/fleet-plugin/common';
+import type { InstallPackageResponse } from '@kbn/fleet-plugin/common/types';
import type { RuleManagementFiltersResponse } from '../../../../common/detection_engine/rule_management/api/rules/filters/response_schema';
import { RULE_MANAGEMENT_FILTERS_URL } from '../../../../common/detection_engine/rule_management/api/urls';
import type { BulkActionsDryRunErrCode } from '../../../../common/constants';
@@ -481,3 +484,61 @@ export const addRuleExceptions = async ({
signal,
}
);
+
+export interface InstallFleetPackageProps {
+ packageName: string;
+ packageVersion: string;
+ prerelease?: boolean;
+ force?: boolean;
+}
+
+/**
+ * Install a Fleet package from the registry
+ *
+ * @param packageName Name of the package to install
+ * @param packageVersion Version of the package to install
+ * @param prerelease Whether to install a prerelease version of the package
+ * @param force Whether to force install the package. If false, the package will only be installed if it is not already installed
+ *
+ * @returns The response from the Fleet API
+ */
+export const installFleetPackage = ({
+ packageName,
+ packageVersion,
+ prerelease = false,
+ force = true,
+}: InstallFleetPackageProps): Promise => {
+ return KibanaServices.get().http.post(
+ epmRouteService.getInstallPath(packageName, packageVersion),
+ {
+ query: { prerelease },
+ body: JSON.stringify({ force }),
+ }
+ );
+};
+
+export interface BulkInstallFleetPackagesProps {
+ packages: string[];
+ prerelease?: boolean;
+}
+
+/**
+ * Install multiple Fleet packages from the registry
+ *
+ * @param packages Array of package names to install
+ * @param prerelease Whether to install prerelease versions of the packages
+ *
+ * @returns The response from the Fleet API
+ */
+export const bulkInstallFleetPackages = ({
+ packages,
+ prerelease = false,
+}: BulkInstallFleetPackagesProps): Promise => {
+ return KibanaServices.get().http.post(
+ epmRouteService.getBulkInstallPath(),
+ {
+ query: { prerelease },
+ body: JSON.stringify({ packages }),
+ }
+ );
+};
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_bulk_install_fleet_packages_mutation.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_bulk_install_fleet_packages_mutation.ts
new file mode 100644
index 0000000000000..adbcec981ca3c
--- /dev/null
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_bulk_install_fleet_packages_mutation.ts
@@ -0,0 +1,44 @@
+/*
+ * 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 { EPM_API_ROUTES } from '@kbn/fleet-plugin/common';
+import type { BulkInstallPackagesResponse } from '@kbn/fleet-plugin/common/types';
+import type { UseMutationOptions } from '@tanstack/react-query';
+import { useMutation } from '@tanstack/react-query';
+import { PREBUILT_RULES_PACKAGE_NAME } from '../../../../../common/detection_engine/constants';
+import type { BulkInstallFleetPackagesProps } from '../api';
+import { bulkInstallFleetPackages } from '../api';
+import { useInvalidateFetchPrebuiltRulesStatusQuery } from './use_fetch_prebuilt_rules_status_query';
+
+export const BULK_INSTALL_FLEET_PACKAGES_MUTATION_KEY = [
+ 'POST',
+ EPM_API_ROUTES.BULK_INSTALL_PATTERN,
+];
+
+export const useBulkInstallFleetPackagesMutation = (
+ options?: UseMutationOptions
+) => {
+ const invalidatePrePackagedRulesStatus = useInvalidateFetchPrebuiltRulesStatusQuery();
+
+ return useMutation((props: BulkInstallFleetPackagesProps) => bulkInstallFleetPackages(props), {
+ ...options,
+ mutationKey: BULK_INSTALL_FLEET_PACKAGES_MUTATION_KEY,
+ onSettled: (...args) => {
+ const response = args[0];
+ const rulesPackage = response?.items.find(
+ (item) => item.name === PREBUILT_RULES_PACKAGE_NAME
+ );
+ if (rulesPackage && 'result' in rulesPackage && rulesPackage.result.status === 'installed') {
+ // The rules package was installed/updated, so invalidate the pre-packaged rules status query
+ invalidatePrePackagedRulesStatus();
+ }
+
+ if (options?.onSettled) {
+ options.onSettled(...args);
+ }
+ },
+ });
+};
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_install_fleet_package_mutation.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_install_fleet_package_mutation.ts
new file mode 100644
index 0000000000000..0e6927e1745dd
--- /dev/null
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_install_fleet_package_mutation.ts
@@ -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 { EPM_API_ROUTES } from '@kbn/fleet-plugin/common';
+import type { InstallPackageResponse } from '@kbn/fleet-plugin/common/types';
+import type { UseMutationOptions } from '@tanstack/react-query';
+import { useMutation } from '@tanstack/react-query';
+import { PREBUILT_RULES_PACKAGE_NAME } from '../../../../../common/detection_engine/constants';
+import type { InstallFleetPackageProps } from '../api';
+import { installFleetPackage } from '../api';
+import { useInvalidateFetchPrebuiltRulesStatusQuery } from './use_fetch_prebuilt_rules_status_query';
+
+export const INSTALL_FLEET_PACKAGE_MUTATION_KEY = [
+ 'POST',
+ EPM_API_ROUTES.INSTALL_FROM_REGISTRY_PATTERN,
+];
+
+export const useInstallFleetPackageMutation = (
+ options?: UseMutationOptions
+) => {
+ const invalidatePrePackagedRulesStatus = useInvalidateFetchPrebuiltRulesStatusQuery();
+
+ return useMutation((props: InstallFleetPackageProps) => installFleetPackage(props), {
+ ...options,
+ mutationKey: INSTALL_FLEET_PACKAGE_MUTATION_KEY,
+ onSettled: (...args) => {
+ const { packageName } = args[2];
+ if (packageName === PREBUILT_RULES_PACKAGE_NAME) {
+ // Invalidate the pre-packaged rules status query as there might be new rules to install
+ invalidatePrePackagedRulesStatus();
+ }
+
+ if (options?.onSettled) {
+ options.onSettled(...args);
+ }
+ },
+ });
+};
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_install_pre_packaged_rules.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_install_pre_packaged_rules.ts
index 21ea298986598..b7fa307c0fedc 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_install_pre_packaged_rules.ts
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_install_pre_packaged_rules.ts
@@ -4,8 +4,12 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
+import { useIsMutating } from '@tanstack/react-query';
import { useAppToasts } from '../../../common/hooks/use_app_toasts';
-import { useCreatePrebuiltRulesMutation } from '../api/hooks/use_create_prebuilt_rules_mutation';
+import {
+ CREATE_PREBUILT_RULES_MUTATION_KEY,
+ useCreatePrebuiltRulesMutation,
+} from '../api/hooks/use_create_prebuilt_rules_mutation';
import * as i18n from './translations';
export const useInstallPrePackagedRules = () => {
@@ -21,6 +25,11 @@ export const useInstallPrePackagedRules = () => {
});
};
+export const useIsInstallingPrePackagedRules = () => {
+ const mutationsCount = useIsMutating(CREATE_PREBUILT_RULES_MUTATION_KEY);
+ return mutationsCount > 0;
+};
+
const getSuccessToastMessage = (result: {
rules_installed: number;
rules_updated: number;
diff --git a/x-pack/plugins/security_solution/public/common/hooks/use_upgrade_secuirty_packages.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_upgrade_secuirty_packages.test.tsx
similarity index 57%
rename from x-pack/plugins/security_solution/public/common/hooks/use_upgrade_secuirty_packages.test.tsx
rename to x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_upgrade_secuirty_packages.test.tsx
index 0352dd03bbcff..dd01465b8875a 100644
--- a/x-pack/plugins/security_solution/public/common/hooks/use_upgrade_secuirty_packages.test.tsx
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_upgrade_secuirty_packages.test.tsx
@@ -5,14 +5,13 @@
* 2.0.
*/
-import React, { memo } from 'react';
-import { KibanaServices, useKibana } from '../lib/kibana';
-import type { RenderHookResult } from '@testing-library/react-hooks';
-import { renderHook as _renderHook } from '@testing-library/react-hooks';
-import { useUpgradeSecurityPackages } from './use_upgrade_security_packages';
import { epmRouteService } from '@kbn/fleet-plugin/common';
+import { renderHook } from '@testing-library/react-hooks';
+import { useKibana, KibanaServices } from '../../../common/lib/kibana';
+import { TestProviders } from '../../../common/mock';
+import { useUpgradeSecurityPackages } from './use_upgrade_security_packages';
-jest.mock('../components/user_privileges', () => {
+jest.mock('../../../common/components/user_privileges', () => {
return {
useUserPrivileges: jest.fn().mockReturnValue({
endpointPrivileges: {
@@ -21,48 +20,30 @@ jest.mock('../components/user_privileges', () => {
}),
};
});
-jest.mock('../lib/kibana');
+jest.mock('../../../common/lib/kibana');
-describe('When using the `useUpgradeSecurityPackages()` hook', () => {
- const mockGetPrebuiltRulesPackageVersion =
- KibanaServices.getPrebuiltRulesPackageVersion as jest.Mock;
- const mockGetKibanaVersion = KibanaServices.getKibanaVersion as jest.Mock;
- const mockGetKibanaBranch = KibanaServices.getKibanaBranch as jest.Mock;
- let renderResult: RenderHookResult