mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[Cloud Security] Adding MSW for mocking server responses in React integration tests (#184555)
## Summary It closes #183977 This PR introduces the MSW library into Kibana and setups for MSW usage with Jest for integration testing of React components in the Cloud Security Posture plugin. It also adds the setup for the initial [handlers](https://mswjs.io/docs/concepts/request-handler/), and configures a test for the `<NoFindingsStates/>` components using MSW to exemplify how the library works. ### Problem Statement Currently, integration tests for React components that interact with the server are hard to write and maintain, as they often require mocking functions implementation and responses, this can lead to tests that do not accurately verify the intended functionality and can be hard to maintain as the implementation of the functions changes. This leads to situations our team faces now, where due to the difficult maintainability of integration tests, we rely much more on End-to-End tests, and maintaining those many End-to-End comes with its own set of tradeoffs, as oftentimes End-to-End tests are detected by the CI as failing or flaky, and as flakiness can happen in End-to-end tests due to its nature of multiple integrated systems, this concept proposes that it's better to reserve End-to-end tests for the features in the most critical path and tests that test multiple integrated systems as those will benefit most of the end-to-end testing. For all the other tests we should focus on unit and integration tests. ### How MSW works MSW is a library that allows you to mock server responses in your tests, it works by intercepting the requests made by the client and returning the mocked responses, this way we can test how the client behaves in different states of the lifecycle such as loading, error, and success. This proposes that we should use MSW to enhance our integration tests, and give preference to writing integration tests over End-to-End tests whenever possible, but this doesn't mean that we should stop writing end-to-end tests, as end-to-end tests are still important for the features in the most critical path and tests that tests multiple integrated systems. ### MSW Diagram Here's a diagram that shows how MSW works with Jest tests: ```mermaid %%{init:{'themeCSS':' g:nth-of-type(3) rect.actor { fill: #eee; };g:nth-of-type(7) rect.actor { fill: #eee; };'}}%% sequenceDiagram participant ReactComponent as React Component participant API as API participant MSW as MSW Mock Server participant Jest as Jest Test Jest->>ReactComponent: Setup component test and mock providers Jest->>MSW: Setup Mock Server Note over Jest,MSW: start listening for requests activate MSW ReactComponent->>API: Make API Call Note over ReactComponent,API: loading state activate API MSW-->>API: Intercepts API Call deactivate API alt is success MSW-->>ReactComponent: Send Mocked success Response else is error MSW-->>ReactComponent: Send Mocked error Response end deactivate MSW ReactComponent-->>Jest: Receive Mocked data and render ``` ### Documentation - Refer to this [PR](https://github.com/elastic/security-team/pull/9624) containing the documentation of how MSW works and how to use it. - Refer to this [presentation](https://docs.google.com/presentation/d/1KYtBaeDMZrpoU5lnKASm8GvCxhrXVqMKxWgR-Xvaxzc/edit#slide=id.g11f0f180654_1_0) to understand the main motivations behind this proposal. ### How to test it ``` yarn test:jest x-pack/plugins/cloud_security_posture/public/components/no_findings_states.test.tsx ``` ### Screenshot  Intercepted requests logged with `{debug: true}`:  --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
e2a98cf965
commit
cb11a1b004
21 changed files with 1182 additions and 346 deletions
|
@ -1675,6 +1675,7 @@
|
|||
"mochawesome-merge": "^4.3.0",
|
||||
"mock-fs": "^5.1.2",
|
||||
"ms-chromium-edge-driver": "^0.5.1",
|
||||
"msw": "^2.3.1",
|
||||
"multistream": "^4.1.0",
|
||||
"mutation-observer": "^1.0.3",
|
||||
"native-hdr-histogram": "^1.0.0",
|
||||
|
|
|
@ -427,6 +427,14 @@
|
|||
"prCreation": "not-pending",
|
||||
"minimumReleaseAge": "7 days",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"groupName": "MSW",
|
||||
"matchPackageNames": ["msw"],
|
||||
"reviewers": ["team:kibana-cloud-security-posture"],
|
||||
"matchBaseBranches": ["main"],
|
||||
"labels": ["Team: Cloud Security", "release_note:skip", "backport:skip"],
|
||||
"enabled": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -15,4 +15,13 @@ module.exports = {
|
|||
collectCoverageFrom: [
|
||||
'<rootDir>/x-pack/plugins/cloud_security_posture/{common,public,server}/**/*.{ts,tsx}',
|
||||
],
|
||||
// An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation
|
||||
transformIgnorePatterns: [
|
||||
// ignore all node_modules except the modules below (monaco-editor, monaco-yaml, react-monaco-editor, etc) which requires babel transforms to handle dynamic import()
|
||||
// since ESM modules are not natively supported in Jest yet (https://github.com/facebook/jest/issues/4842)
|
||||
'[/\\\\]node_modules(?)[/\\\\].+\\.js$',
|
||||
'packages/kbn-pm/dist/index.js',
|
||||
'[/\\\\]node_modules(?)/dist/[/\\\\].+\\.js$',
|
||||
'[/\\\\]node_modules(?)/dist/util/[/\\\\].+\\.js$',
|
||||
],
|
||||
};
|
||||
|
|
|
@ -5,23 +5,21 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { useKibana } from '../hooks/use_kibana';
|
||||
|
||||
const LICENSE_MANAGEMENT_LOCATOR = 'LICENSE_MANAGEMENT_LOCATOR';
|
||||
|
||||
const getLicenseManagementLocatorKey = 'license_management_url_key';
|
||||
|
||||
/**
|
||||
* Hook to get the license management locator
|
||||
* @returns a callback to navigate to the license management page
|
||||
*/
|
||||
export const useLicenseManagementLocatorApi = () => {
|
||||
const { share } = useKibana().services;
|
||||
|
||||
return useQuery([getLicenseManagementLocatorKey], () => {
|
||||
const locator = share.url.locators.get(LICENSE_MANAGEMENT_LOCATOR);
|
||||
// license management does not exist on serverless
|
||||
if (!locator) return;
|
||||
const locator = share.url.locators.get(LICENSE_MANAGEMENT_LOCATOR);
|
||||
|
||||
return locator.getUrl({
|
||||
page: 'dashboard',
|
||||
});
|
||||
});
|
||||
// license management does not exist on serverless
|
||||
if (!locator) return;
|
||||
|
||||
return () => locator.navigate({ page: 'dashboard' });
|
||||
};
|
||||
|
|
|
@ -43,12 +43,7 @@ describe('<CloudPosturePage />', () => {
|
|||
})
|
||||
);
|
||||
|
||||
(useLicenseManagementLocatorApi as jest.Mock).mockImplementation(() =>
|
||||
createReactQueryResponse({
|
||||
status: 'success',
|
||||
data: true,
|
||||
})
|
||||
);
|
||||
(useLicenseManagementLocatorApi as jest.Mock).mockImplementation(undefined);
|
||||
});
|
||||
|
||||
const renderCloudPosturePage = (
|
||||
|
@ -85,7 +80,10 @@ describe('<CloudPosturePage />', () => {
|
|||
})
|
||||
);
|
||||
|
||||
(useLicenseManagementLocatorApi as jest.Mock).mockImplementation(() => 'http://license-url');
|
||||
|
||||
renderCloudPosturePage();
|
||||
|
||||
expect(screen.getByTestId('has_locator')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
|
@ -97,12 +95,7 @@ describe('<CloudPosturePage />', () => {
|
|||
})
|
||||
);
|
||||
|
||||
(useLicenseManagementLocatorApi as jest.Mock).mockImplementation(() =>
|
||||
createReactQueryResponse({
|
||||
status: 'success',
|
||||
data: undefined,
|
||||
})
|
||||
);
|
||||
(useLicenseManagementLocatorApi as jest.Mock).mockImplementation(undefined);
|
||||
|
||||
renderCloudPosturePage();
|
||||
expect(screen.getByTestId('no_locator')).toBeInTheDocument();
|
||||
|
|
|
@ -15,7 +15,6 @@ import { SubscriptionNotAllowed } from './subscription_not_allowed';
|
|||
import { useSubscriptionStatus } from '../common/hooks/use_subscription_status';
|
||||
import { FullSizeCenteredPage } from './full_size_centered_page';
|
||||
import { CspLoadingState } from './csp_loading_state';
|
||||
import { useLicenseManagementLocatorApi } from '../common/api/use_license_management_locator_api';
|
||||
|
||||
export const LOADING_STATE_TEST_SUBJECT = 'cloud_posture_page_loading';
|
||||
export const ERROR_STATE_TEST_SUBJECT = 'cloud_posture_page_error';
|
||||
|
@ -151,9 +150,9 @@ export const defaultNoDataRenderer = () => (
|
|||
</FullSizeCenteredPage>
|
||||
);
|
||||
|
||||
const subscriptionNotAllowedRenderer = (licenseManagementLocator?: string) => (
|
||||
const subscriptionNotAllowedRenderer = () => (
|
||||
<FullSizeCenteredPage data-test-subj={SUBSCRIPTION_NOT_ALLOWED_TEST_SUBJECT}>
|
||||
<SubscriptionNotAllowed licenseManagementLocator={licenseManagementLocator} />
|
||||
<SubscriptionNotAllowed />
|
||||
</FullSizeCenteredPage>
|
||||
);
|
||||
|
||||
|
@ -173,19 +172,18 @@ export const CloudPosturePage = <TData, TError>({
|
|||
noDataRenderer = defaultNoDataRenderer,
|
||||
}: CloudPosturePageProps<TData, TError>) => {
|
||||
const subscriptionStatus = useSubscriptionStatus();
|
||||
const getLicenseManagementLocator = useLicenseManagementLocatorApi();
|
||||
|
||||
const render = () => {
|
||||
if (subscriptionStatus.isError) {
|
||||
return defaultErrorRenderer(subscriptionStatus.error);
|
||||
}
|
||||
|
||||
if (subscriptionStatus.isLoading || getLicenseManagementLocator.isLoading) {
|
||||
if (subscriptionStatus.isLoading) {
|
||||
return defaultLoadingRenderer();
|
||||
}
|
||||
|
||||
if (!subscriptionStatus.data) {
|
||||
return subscriptionNotAllowedRenderer(getLicenseManagementLocator.data);
|
||||
return subscriptionNotAllowedRenderer();
|
||||
}
|
||||
|
||||
if (!query) {
|
||||
|
|
|
@ -1,245 +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 React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
import { createReactQueryResponse } from '../test/fixtures/react_query';
|
||||
import { TestProvider } from '../test/test_provider';
|
||||
import { NoFindingsStates } from './no_findings_states';
|
||||
import { useCspSetupStatusApi } from '../common/api/use_setup_status_api';
|
||||
import { useCspIntegrationLink } from '../common/navigation/use_csp_integration_link';
|
||||
import { useLicenseManagementLocatorApi } from '../common/api/use_license_management_locator_api';
|
||||
import { useSubscriptionStatus } from '../common/hooks/use_subscription_status';
|
||||
|
||||
jest.mock('../common/api/use_setup_status_api', () => ({
|
||||
useCspSetupStatusApi: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('../common/navigation/use_csp_integration_link', () => ({
|
||||
useCspIntegrationLink: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('../common/api/use_license_management_locator_api', () => ({
|
||||
useLicenseManagementLocatorApi: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('../common/hooks/use_subscription_status', () => ({
|
||||
useSubscriptionStatus: jest.fn(),
|
||||
}));
|
||||
|
||||
const customRederer = (postureType: 'cspm' | 'kspm') => {
|
||||
return render(
|
||||
<TestProvider>
|
||||
<NoFindingsStates postureType={postureType} />
|
||||
</TestProvider>
|
||||
);
|
||||
};
|
||||
|
||||
describe('NoFindingsStates', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
|
||||
(useSubscriptionStatus as jest.Mock).mockImplementation(() =>
|
||||
createReactQueryResponse({
|
||||
status: 'success',
|
||||
data: true,
|
||||
})
|
||||
);
|
||||
|
||||
(useLicenseManagementLocatorApi as jest.Mock).mockImplementation(() =>
|
||||
createReactQueryResponse({
|
||||
status: 'success',
|
||||
data: true,
|
||||
})
|
||||
);
|
||||
|
||||
(useCspIntegrationLink as jest.Mock).mockReturnValue('http://cspm-or-kspm-integration-link');
|
||||
});
|
||||
|
||||
it('should show the indexing notification when CSPM is not installed and KSPM is indexing', async () => {
|
||||
(useCspSetupStatusApi as jest.Mock).mockImplementation(() =>
|
||||
createReactQueryResponse({
|
||||
status: 'success',
|
||||
data: {
|
||||
cspm: {
|
||||
status: 'not-deployed',
|
||||
},
|
||||
kspm: {
|
||||
status: 'indexing',
|
||||
},
|
||||
indicesDetails: [
|
||||
{ index: 'logs-cloud_security_posture.findings_latest-default', status: 'empty' },
|
||||
{ index: 'logs-cloud_security_posture.findings-default*', status: 'empty' },
|
||||
],
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
const { getByText } = customRederer('kspm');
|
||||
expect(getByText(/posture evaluation underway/i)).toBeInTheDocument();
|
||||
expect(
|
||||
getByText(
|
||||
/waiting for data to be collected and indexed. check back later to see your findings/i
|
||||
)
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should show the indexing notification when KSPM is not installed and CSPM is indexing', async () => {
|
||||
(useCspSetupStatusApi as jest.Mock).mockImplementation(() =>
|
||||
createReactQueryResponse({
|
||||
status: 'success',
|
||||
data: {
|
||||
kspm: {
|
||||
status: 'not-deployed',
|
||||
},
|
||||
cspm: {
|
||||
status: 'indexing',
|
||||
},
|
||||
indicesDetails: [
|
||||
{ index: 'logs-cloud_security_posture.findings_latest-default', status: 'empty' },
|
||||
{ index: 'logs-cloud_security_posture.findings-default*', status: 'empty' },
|
||||
],
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
const { getByText } = customRederer('cspm');
|
||||
expect(getByText(/posture evaluation underway/i)).toBeInTheDocument();
|
||||
expect(
|
||||
getByText(
|
||||
/waiting for data to be collected and indexed. Check back later to see your findings/i
|
||||
)
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should show the indexing timout notification when CSPM is status is index-timeout', async () => {
|
||||
(useCspSetupStatusApi as jest.Mock).mockImplementation(() =>
|
||||
createReactQueryResponse({
|
||||
status: 'success',
|
||||
data: {
|
||||
kspm: {
|
||||
status: 'installed',
|
||||
},
|
||||
cspm: {
|
||||
status: 'index-timeout',
|
||||
},
|
||||
indicesDetails: [
|
||||
{ index: 'logs-cloud_security_posture.findings_latest-default', status: 'empty' },
|
||||
{ index: 'logs-cloud_security_posture.findings-default*', status: 'empty' },
|
||||
],
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
const { getByText } = customRederer('cspm');
|
||||
expect(getByText(/waiting for findings data/i)).toBeInTheDocument();
|
||||
const indexTimeOutMessage = getByText(/collecting findings is taking longer than expected/i);
|
||||
expect(indexTimeOutMessage).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should show the indexing timout notification when KSPM is status is index-timeout', async () => {
|
||||
(useCspSetupStatusApi as jest.Mock).mockImplementation(() =>
|
||||
createReactQueryResponse({
|
||||
status: 'success',
|
||||
data: {
|
||||
kspm: {
|
||||
status: 'index-timeout',
|
||||
},
|
||||
cspm: {
|
||||
status: 'installed',
|
||||
},
|
||||
indicesDetails: [
|
||||
{ index: 'logs-cloud_security_posture.findings_latest-default', status: 'empty' },
|
||||
{ index: 'logs-cloud_security_posture.findings-default*', status: 'empty' },
|
||||
],
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
const { getByText } = customRederer('kspm');
|
||||
expect(getByText(/waiting for findings data/i)).toBeInTheDocument();
|
||||
expect(getByText(/collecting findings is taking longer than expected/i)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should show the unprivileged notification when CSPM is status is index-timeout', async () => {
|
||||
(useCspSetupStatusApi as jest.Mock).mockImplementation(() =>
|
||||
createReactQueryResponse({
|
||||
status: 'success',
|
||||
data: {
|
||||
kspm: {
|
||||
status: 'installed',
|
||||
},
|
||||
cspm: {
|
||||
status: 'unprivileged',
|
||||
},
|
||||
indicesDetails: [
|
||||
{
|
||||
index: 'logs-cloud_security_posture.findings_latest-default',
|
||||
status: 'unprivileged',
|
||||
},
|
||||
{ index: 'logs-cloud_security_posture.findings-default*', status: 'unprivileged' },
|
||||
],
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
const { getByText } = customRederer('cspm');
|
||||
expect(getByText(/privileges required/i)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should show the unprivileged notification when KSPM is status is index-timeout', async () => {
|
||||
(useCspSetupStatusApi as jest.Mock).mockImplementation(() =>
|
||||
createReactQueryResponse({
|
||||
status: 'success',
|
||||
data: {
|
||||
kspm: {
|
||||
status: 'unprivileged',
|
||||
},
|
||||
cspm: {
|
||||
status: 'installed',
|
||||
},
|
||||
indicesDetails: [
|
||||
{
|
||||
index: 'logs-cloud_security_posture.findings_latest-default',
|
||||
status: 'unprivileged',
|
||||
},
|
||||
{ index: 'logs-cloud_security_posture.findings-default*', status: 'unprivileged' },
|
||||
],
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
const { getByText } = customRederer('kspm');
|
||||
expect(getByText(/privileges required/i)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should show the not-installed notification when CSPM and KSPM status is not-installed', async () => {
|
||||
(useCspSetupStatusApi as jest.Mock).mockImplementation(() =>
|
||||
createReactQueryResponse({
|
||||
status: 'success',
|
||||
data: {
|
||||
kspm: {
|
||||
status: 'not-installed',
|
||||
},
|
||||
cspm: {
|
||||
status: 'not-installed',
|
||||
},
|
||||
indicesDetails: [
|
||||
{
|
||||
index: 'logs-cloud_security_posture.findings_latest-default',
|
||||
status: 'success',
|
||||
},
|
||||
{ index: 'logs-cloud_security_posture.findings-default*', status: 'success' },
|
||||
],
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
const { getByText } = customRederer('cspm');
|
||||
expect(getByText(/learn more about cloud security posture/i)).toBeInTheDocument();
|
||||
});
|
||||
});
|
|
@ -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 * from './no_findings_states';
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* 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 { http, HttpResponse } from 'msw';
|
||||
|
||||
export const fleetCspPackageHandler = http.get(
|
||||
`/api/fleet/epm/packages/cloud_security_posture`,
|
||||
() => {
|
||||
return HttpResponse.json({
|
||||
item: {
|
||||
name: 'cloud_security_posture',
|
||||
version: '1.9.0',
|
||||
},
|
||||
});
|
||||
}
|
||||
);
|
|
@ -0,0 +1,163 @@
|
|||
/*
|
||||
* 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 { screen, waitFor } from '@testing-library/react';
|
||||
import { setupMockServer, startMockServer } from '../../test/mock_server/mock_server';
|
||||
import { renderWrapper } from '../../test/mock_server/mock_server_test_provider';
|
||||
import { NoFindingsStates } from './no_findings_states';
|
||||
import * as statusHandlers from '../../../server/routes/status/status.handlers.mock';
|
||||
import * as benchmarksHandlers from '../../../server/routes/benchmarks/benchmarks.handlers.mock';
|
||||
import { fleetCspPackageHandler } from './no_findings_states.handlers.mock';
|
||||
|
||||
const server = setupMockServer();
|
||||
|
||||
const renderNoFindingsStates = (postureType: 'cspm' | 'kspm' = 'cspm') => {
|
||||
return renderWrapper(<NoFindingsStates postureType={postureType} />);
|
||||
};
|
||||
|
||||
describe('NoFindingsStates', () => {
|
||||
startMockServer(server);
|
||||
|
||||
beforeEach(() => {
|
||||
server.use(fleetCspPackageHandler);
|
||||
});
|
||||
|
||||
it('shows integrations installation prompt with installation links when integration is not-installed', async () => {
|
||||
server.use(statusHandlers.notInstalledHandler);
|
||||
renderNoFindingsStates();
|
||||
expect(screen.getByText(/loading/i)).toBeInTheDocument();
|
||||
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
screen.getByText(/detect security misconfigurations in your cloud infrastructure!/i)
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole('link', { name: /add cspm integration/i })).toHaveAttribute(
|
||||
'href',
|
||||
'/app/fleet/integrations/cloud_security_posture-1.9.0/add-integration/cspm'
|
||||
);
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole('link', { name: /add kspm integration/i })).toHaveAttribute(
|
||||
'href',
|
||||
'/app/fleet/integrations/cloud_security_posture-1.9.0/add-integration/kspm'
|
||||
);
|
||||
});
|
||||
});
|
||||
it('shows install agent prompt with install agent link when status is not-deployed', async () => {
|
||||
server.use(statusHandlers.notDeployedHandler);
|
||||
server.use(benchmarksHandlers.cspmInstalledHandler);
|
||||
renderNoFindingsStates();
|
||||
expect(screen.getByText(/loading/i)).toBeInTheDocument();
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText(/no agents installed/i)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole('link', { name: /install agent/i })).toHaveAttribute(
|
||||
'href',
|
||||
'/app/integrations/detail/cloud_security_posture-1.9.0/policies?addAgentToPolicyId=30cba674-531c-4225-b392-3f7810957511&integration=630f3e42-659e-4499-9007-61e36adf1d97'
|
||||
);
|
||||
});
|
||||
});
|
||||
it('shows install agent prompt with install agent link when status is not-deployed and postureType is KSPM', async () => {
|
||||
server.use(statusHandlers.notDeployedHandler);
|
||||
server.use(benchmarksHandlers.kspmInstalledHandler);
|
||||
renderNoFindingsStates('kspm');
|
||||
expect(screen.getByText(/loading/i)).toBeInTheDocument();
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText(/no agents installed/i)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
const link = screen.getByRole('link', {
|
||||
name: /install agent/i,
|
||||
});
|
||||
expect(link).toHaveAttribute(
|
||||
'href',
|
||||
'/app/integrations/detail/cloud_security_posture-1.9.0/policies?addAgentToPolicyId=e2f72eea-bf76-4576-bed8-e29d2df102a7&integration=6aedf856-bc21-49aa-859a-a0952789f898'
|
||||
);
|
||||
});
|
||||
});
|
||||
it('shows indexing message when status is indexing', async () => {
|
||||
server.use(statusHandlers.indexingHandler);
|
||||
|
||||
renderNoFindingsStates();
|
||||
expect(screen.getByText(/loading/i)).toBeInTheDocument();
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText(/posture evaluation underway/i)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
expect(
|
||||
screen.getByText(
|
||||
/waiting for data to be collected and indexed. check back later to see your findings/i
|
||||
)
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
it('shows timeout message when status is index-timeout', async () => {
|
||||
server.use(statusHandlers.indexTimeoutHandler);
|
||||
|
||||
renderNoFindingsStates();
|
||||
expect(screen.getByText(/loading/i)).toBeInTheDocument();
|
||||
|
||||
await waitFor(() => {
|
||||
screen.getByRole('heading', {
|
||||
name: /waiting for findings data/i,
|
||||
});
|
||||
});
|
||||
|
||||
expect(
|
||||
screen.getByText(/collecting findings is taking longer than expected/i)
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
it('shows unprivileged message when status is unprivileged', async () => {
|
||||
server.use(statusHandlers.unprivilegedHandler);
|
||||
|
||||
renderNoFindingsStates();
|
||||
expect(screen.getByText(/loading/i)).toBeInTheDocument();
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText(/privileges required/i)).toBeInTheDocument();
|
||||
|
||||
expect(
|
||||
screen.getByText(/required elasticsearch index privilege for the following indices:/i)
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText('logs-cloud_security_posture.findings_latest-default')
|
||||
).toBeInTheDocument();
|
||||
expect(screen.getByText('logs-cloud_security_posture.findings-default*')).toBeInTheDocument();
|
||||
expect(screen.getByText('logs-cloud_security_posture.scores-default')).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText('logs-cloud_security_posture.vulnerabilities_latest-default')
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
it('renders empty container when the status does not match a no finding status', async () => {
|
||||
server.use(statusHandlers.indexedHandler);
|
||||
|
||||
const { container } = renderNoFindingsStates();
|
||||
|
||||
expect(screen.getByText(/loading/i)).toBeInTheDocument();
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByText(/loading/i)).not.toBeInTheDocument();
|
||||
});
|
||||
expect(container).toMatchInlineSnapshot(`
|
||||
<div>
|
||||
<div
|
||||
class="euiFlexGroup emotion-euiFlexGroup-l-center-center-column"
|
||||
/>
|
||||
</div>
|
||||
`);
|
||||
});
|
||||
});
|
|
@ -20,21 +20,21 @@ import {
|
|||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { css } from '@emotion/react';
|
||||
import { CSPM_POLICY_TEMPLATE, KSPM_POLICY_TEMPLATE } from '../../common/constants';
|
||||
import { FullSizeCenteredPage } from './full_size_centered_page';
|
||||
import { useCISIntegrationPoliciesLink } from '../common/navigation/use_navigate_to_cis_integration_policies';
|
||||
import { CSPM_POLICY_TEMPLATE, KSPM_POLICY_TEMPLATE } from '../../../common/constants';
|
||||
import { FullSizeCenteredPage } from '../full_size_centered_page';
|
||||
import { useCISIntegrationPoliciesLink } from '../../common/navigation/use_navigate_to_cis_integration_policies';
|
||||
import {
|
||||
CSPM_NOT_INSTALLED_ACTION_SUBJ,
|
||||
KSPM_NOT_INSTALLED_ACTION_SUBJ,
|
||||
NO_FINDINGS_STATUS_TEST_SUBJ,
|
||||
} from './test_subjects';
|
||||
import { CloudPosturePage, PACKAGE_NOT_INSTALLED_TEST_SUBJECT } from './cloud_posture_page';
|
||||
import { useCspSetupStatusApi } from '../common/api/use_setup_status_api';
|
||||
import type { IndexDetails, PostureTypes, CspStatusCode } from '../../common/types_old';
|
||||
import noDataIllustration from '../assets/illustrations/no_data_illustration.svg';
|
||||
import { useCspIntegrationLink } from '../common/navigation/use_csp_integration_link';
|
||||
import { NO_FINDINGS_STATUS_REFRESH_INTERVAL_MS } from '../common/constants';
|
||||
import { cspIntegrationDocsNavigation } from '../common/navigation/constants';
|
||||
} from '../test_subjects';
|
||||
import { CloudPosturePage, PACKAGE_NOT_INSTALLED_TEST_SUBJECT } from '../cloud_posture_page';
|
||||
import { useCspSetupStatusApi } from '../../common/api/use_setup_status_api';
|
||||
import type { IndexDetails, PostureTypes, CspStatusCode } from '../../../common/types_old';
|
||||
import noDataIllustration from '../../assets/illustrations/no_data_illustration.svg';
|
||||
import { useCspIntegrationLink } from '../../common/navigation/use_csp_integration_link';
|
||||
import { NO_FINDINGS_STATUS_REFRESH_INTERVAL_MS } from '../../common/constants';
|
||||
import { cspIntegrationDocsNavigation } from '../../common/navigation/constants';
|
||||
|
||||
const NotDeployed = ({ postureType }: { postureType: PostureTypes }) => {
|
||||
const integrationPoliciesLink = useCISIntegrationPoliciesLink({
|
||||
|
@ -169,13 +169,10 @@ const Unprivileged = ({ unprivilegedIndices }: { unprivilegedIndices: string[] }
|
|||
/>
|
||||
);
|
||||
|
||||
const EmptySecurityFindingsPrompt = ({
|
||||
kspmIntegrationLink,
|
||||
cspmIntegrationLink,
|
||||
}: {
|
||||
kspmIntegrationLink?: string;
|
||||
cspmIntegrationLink?: string;
|
||||
}) => {
|
||||
const EmptySecurityFindingsPrompt = () => {
|
||||
const kspmIntegrationLink = useCspIntegrationLink(KSPM_POLICY_TEMPLATE);
|
||||
const cspmIntegrationLink = useCspIntegrationLink(CSPM_POLICY_TEMPLATE);
|
||||
|
||||
return (
|
||||
<EuiEmptyPrompt
|
||||
data-test-subj={PACKAGE_NOT_INSTALLED_TEST_SUBJECT}
|
||||
|
@ -215,6 +212,7 @@ const EmptySecurityFindingsPrompt = ({
|
|||
color="primary"
|
||||
fill
|
||||
href={cspmIntegrationLink}
|
||||
isDisabled={!cspmIntegrationLink}
|
||||
data-test-subj={CSPM_NOT_INSTALLED_ACTION_SUBJ}
|
||||
>
|
||||
<FormattedMessage
|
||||
|
@ -228,6 +226,7 @@ const EmptySecurityFindingsPrompt = ({
|
|||
color="primary"
|
||||
fill
|
||||
href={kspmIntegrationLink}
|
||||
isDisabled={!kspmIntegrationLink}
|
||||
data-test-subj={KSPM_NOT_INSTALLED_ACTION_SUBJ}
|
||||
>
|
||||
<FormattedMessage
|
||||
|
@ -253,9 +252,6 @@ const NoFindingsStatesNotification = ({
|
|||
indicesStatus?: IndexDetails[];
|
||||
isNotInstalled: boolean;
|
||||
}) => {
|
||||
const kspmIntegrationLink = useCspIntegrationLink(KSPM_POLICY_TEMPLATE);
|
||||
const cspmIntegrationLink = useCspIntegrationLink(CSPM_POLICY_TEMPLATE);
|
||||
|
||||
const unprivilegedIndices =
|
||||
indicesStatus &&
|
||||
indicesStatus
|
||||
|
@ -267,13 +263,7 @@ const NoFindingsStatesNotification = ({
|
|||
return <Unprivileged unprivilegedIndices={unprivilegedIndices || []} />;
|
||||
if (status === 'indexing' || status === 'waiting_for_results') return <Indexing />;
|
||||
if (status === 'index-timeout') return <IndexTimeout />;
|
||||
if (isNotInstalled)
|
||||
return (
|
||||
<EmptySecurityFindingsPrompt
|
||||
kspmIntegrationLink={kspmIntegrationLink}
|
||||
cspmIntegrationLink={cspmIntegrationLink}
|
||||
/>
|
||||
);
|
||||
if (isNotInstalled) return <EmptySecurityFindingsPrompt />;
|
||||
if (status === 'not-deployed') return <NotDeployed postureType={postureType} />;
|
||||
|
||||
return null;
|
|
@ -8,12 +8,11 @@
|
|||
import React from 'react';
|
||||
import { EuiEmptyPrompt, EuiLink, EuiPageSection } from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { useLicenseManagementLocatorApi } from '../common/api/use_license_management_locator_api';
|
||||
|
||||
export const SubscriptionNotAllowed = () => {
|
||||
const handleNavigateToLicenseManagement = useLicenseManagementLocatorApi();
|
||||
|
||||
export const SubscriptionNotAllowed = ({
|
||||
licenseManagementLocator,
|
||||
}: {
|
||||
licenseManagementLocator?: string;
|
||||
}) => {
|
||||
return (
|
||||
<EuiPageSection color="danger" alignment="center">
|
||||
<EuiEmptyPrompt
|
||||
|
@ -27,14 +26,14 @@ export const SubscriptionNotAllowed = ({
|
|||
</h2>
|
||||
}
|
||||
body={
|
||||
licenseManagementLocator ? (
|
||||
handleNavigateToLicenseManagement ? (
|
||||
<p data-test-subj={'has_locator'}>
|
||||
<FormattedMessage
|
||||
id="xpack.csp.subscriptionNotAllowed.promptDescription"
|
||||
defaultMessage="To use these cloud security features, you must {link}."
|
||||
values={{
|
||||
link: (
|
||||
<EuiLink href={licenseManagementLocator}>
|
||||
<EuiLink onClick={handleNavigateToLicenseManagement}>
|
||||
<FormattedMessage
|
||||
id="xpack.csp.subscriptionNotAllowed.promptLinkText"
|
||||
defaultMessage="start a trial or upgrade your subscription"
|
||||
|
|
28
x-pack/plugins/cloud_security_posture/public/test/fixtures/get_mock_dependencies.ts
vendored
Normal file
28
x-pack/plugins/cloud_security_posture/public/test/fixtures/get_mock_dependencies.ts
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* 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 { dataPluginMock } from '@kbn/data-plugin/public/mocks';
|
||||
import { chartPluginMock } from '@kbn/charts-plugin/public/mocks';
|
||||
import { unifiedSearchPluginMock } from '@kbn/unified-search-plugin/public/mocks';
|
||||
import { discoverPluginMock } from '@kbn/discover-plugin/public/mocks';
|
||||
import { fleetMock } from '@kbn/fleet-plugin/public/mocks';
|
||||
import { licensingMock } from '@kbn/licensing-plugin/public/mocks';
|
||||
import { uiActionsPluginMock } from '@kbn/ui-actions-plugin/public/mocks';
|
||||
import { sessionStorageMock } from '@kbn/core-http-server-mocks';
|
||||
import { sharePluginMock } from '@kbn/share-plugin/public/mocks';
|
||||
|
||||
export const getMockDependencies = () => ({
|
||||
data: dataPluginMock.createStartContract(),
|
||||
unifiedSearch: unifiedSearchPluginMock.createStartContract(),
|
||||
charts: chartPluginMock.createStartContract(),
|
||||
discover: discoverPluginMock.createStartContract(),
|
||||
fleet: fleetMock.createStartMock(),
|
||||
licensing: licensingMock.createStart(),
|
||||
uiActions: uiActionsPluginMock.createStartContract(),
|
||||
storage: sessionStorageMock.create(),
|
||||
share: sharePluginMock.createStartContract(),
|
||||
});
|
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* 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 { defaultApiLicensingInfo } from './licensing.handlers.mock';
|
||||
|
||||
/**
|
||||
* Default handlers for the mock server, these are the handlers that are always enabled
|
||||
* when the mock server is started, but can be overridden by specific tests when needed.
|
||||
* Recommended to use these handlers for common endpoints.
|
||||
*/
|
||||
export const defaultHandlers = [defaultApiLicensingInfo];
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* 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 { http, HttpResponse } from 'msw';
|
||||
|
||||
export const MOCK_SERVER_LICENSING_INFO_URL = `/api/licensing/info`;
|
||||
|
||||
export const defaultApiLicensingInfo = http.get(MOCK_SERVER_LICENSING_INFO_URL, () => {
|
||||
const date = new Date();
|
||||
const expiryDateInMillis = date.setDate(date.getDate() + 30);
|
||||
|
||||
return HttpResponse.json({
|
||||
license: {
|
||||
uid: '000000-0000-0000-0000-000000000',
|
||||
type: 'trial',
|
||||
mode: 'trial',
|
||||
expiryDateInMillis,
|
||||
status: 'active',
|
||||
},
|
||||
features: {
|
||||
security: {
|
||||
isAvailable: true,
|
||||
isEnabled: true,
|
||||
},
|
||||
},
|
||||
signature: '0000000000000000000000000000000000000000000000000000000',
|
||||
});
|
||||
});
|
|
@ -0,0 +1,174 @@
|
|||
/*
|
||||
* 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 { setupServer, SetupServerApi } from 'msw/node';
|
||||
import { coreMock } from '@kbn/core/public/mocks';
|
||||
import type { CoreStart } from '@kbn/core/public';
|
||||
import { licenseMock } from '@kbn/licensing-plugin/common/licensing.mock';
|
||||
import { createStubDataView } from '@kbn/data-views-plugin/common/stubs';
|
||||
import { indexPatternFieldEditorPluginMock as dataViewFieldEditorMock } from '@kbn/data-view-field-editor-plugin/public/mocks';
|
||||
import SearchBar from '@kbn/unified-search-plugin/public/search_bar/search_bar';
|
||||
import { http, HttpResponse, JsonBodyType } from 'msw';
|
||||
import { defaultHandlers } from './handlers';
|
||||
import { getMockDependencies } from '../fixtures/get_mock_dependencies';
|
||||
import { CspClientPluginStartDeps } from '../../types';
|
||||
import { MOCK_SERVER_LICENSING_INFO_URL } from './handlers/licensing.handlers.mock';
|
||||
|
||||
/**
|
||||
* Mock the lastValueFrom function from rxjs to return the result of the promise instead of the Observable
|
||||
* This is for simplifying the testing by avoiding the need to subscribe to the Observable while producing the same result
|
||||
*/
|
||||
jest.mock('rxjs', () => {
|
||||
const actual = jest.requireActual('rxjs');
|
||||
return {
|
||||
...actual,
|
||||
lastValueFrom: async (source: Promise<any>) => {
|
||||
const value = await source;
|
||||
return value.result;
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* Setup a mock server with the default handlers
|
||||
* @param debug - If true, log all requests to the console
|
||||
* @returns The mock server
|
||||
*/
|
||||
export const setupMockServer = ({ debug = false }: { debug?: boolean } = {}) => {
|
||||
const server = setupServer(...defaultHandlers);
|
||||
|
||||
if (debug) {
|
||||
// Debug: log all requests to the console
|
||||
server.events.on('request:start', async ({ request }) => {
|
||||
const payload = await request.clone().text();
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('MSW intercepted request:', request.method, request.url, payload);
|
||||
});
|
||||
server.events.on('response:mocked', async ({ request, response }) => {
|
||||
const body = await response.json();
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(
|
||||
'%s %s received %s %s %s',
|
||||
request.method,
|
||||
request.url,
|
||||
response.status,
|
||||
response.statusText,
|
||||
JSON.stringify(body, null, 2)
|
||||
);
|
||||
});
|
||||
}
|
||||
return server;
|
||||
};
|
||||
|
||||
/**
|
||||
* This function wraps beforeAll, afterAll and beforeEach for setup MSW server into a single call.
|
||||
* That makes the describe code further down easier to read and makes
|
||||
* sure we don't forget the handlers. Can easily be shared between tests.
|
||||
* @param server - The MSW server instance, created with setupMockServer
|
||||
*/
|
||||
export const startMockServer = (server: SetupServerApi) => {
|
||||
beforeAll(() => server.listen({ onUnhandledRequest: 'warn' }));
|
||||
afterAll(() => server.close());
|
||||
beforeEach(() => {
|
||||
server.resetHandlers();
|
||||
});
|
||||
};
|
||||
|
||||
const MOCK_SERVER_BASE_URL = 'http://localhost';
|
||||
|
||||
/**
|
||||
* Get a set of dependencies for the mock server overriding default mock dependencies to perform
|
||||
* HTTP calls that will be intercepted by the mock server
|
||||
* @returns The core and deps dependencies used by the KibanaContextProvider
|
||||
*/
|
||||
export const getMockServerDependencies = () => {
|
||||
return {
|
||||
deps: {
|
||||
...getMockDependencies(),
|
||||
data: {
|
||||
...getMockDependencies().data,
|
||||
search: {
|
||||
...getMockDependencies().data.search,
|
||||
search: async ({ params }: { params: any }) => {
|
||||
const response = await fetch(`${MOCK_SERVER_BASE_URL}/internal/bsearch`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(params),
|
||||
});
|
||||
return response.json();
|
||||
},
|
||||
},
|
||||
dataViews: {
|
||||
...getMockDependencies().data.dataViews,
|
||||
find: async (pattern: string) => {
|
||||
const response = await fetch(
|
||||
`${MOCK_SERVER_BASE_URL}/internal/data_views/fields?pattern=${pattern}`
|
||||
);
|
||||
|
||||
const responseJson = await response.json();
|
||||
|
||||
const fields = responseJson.fields.reduce((acc: any, field: any) => {
|
||||
acc[field.name] = field;
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
const dataView = createStubDataView({
|
||||
spec: {
|
||||
id: pattern,
|
||||
title: pattern,
|
||||
fields,
|
||||
},
|
||||
});
|
||||
|
||||
return [dataView];
|
||||
},
|
||||
},
|
||||
},
|
||||
licensing: {
|
||||
...getMockDependencies().licensing,
|
||||
refresh: async () => {
|
||||
const response = await fetch(MOCK_SERVER_LICENSING_INFO_URL);
|
||||
const responseJson = await response.json();
|
||||
return licenseMock.createLicense(responseJson);
|
||||
},
|
||||
},
|
||||
dataViewFieldEditor: dataViewFieldEditorMock.createStartContract(),
|
||||
unifiedSearch: {
|
||||
...getMockDependencies().unifiedSearch,
|
||||
ui: {
|
||||
...getMockDependencies().unifiedSearch.ui,
|
||||
SearchBar,
|
||||
},
|
||||
},
|
||||
storage: {
|
||||
...getMockDependencies().storage,
|
||||
get: (key: string) => {
|
||||
return localStorage.getItem(key);
|
||||
},
|
||||
set: (key: string, value: string) => {
|
||||
localStorage.setItem(key, value);
|
||||
},
|
||||
},
|
||||
} as unknown as Partial<CspClientPluginStartDeps>,
|
||||
core: {
|
||||
...coreMock.createStart(),
|
||||
http: {
|
||||
...coreMock.createStart().http,
|
||||
get: async (path: string, options: any) => {
|
||||
const response = await fetch(`${MOCK_SERVER_BASE_URL}${path}`, options);
|
||||
return response.json();
|
||||
},
|
||||
},
|
||||
} as unknown as CoreStart,
|
||||
};
|
||||
};
|
||||
|
||||
export const mockGetRequest = (path: string, response: JsonBodyType) => {
|
||||
return http.get(path, () => HttpResponse.json(response));
|
||||
};
|
|
@ -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 from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
import type { CoreStart } from '@kbn/core/public';
|
||||
import { CspClientPluginStartDeps } from '../../types';
|
||||
import { TestProvider } from '../test_provider';
|
||||
import { getMockServerDependencies } from './mock_server';
|
||||
interface MockServerDependencies {
|
||||
deps: Partial<CspClientPluginStartDeps>;
|
||||
core: CoreStart;
|
||||
}
|
||||
|
||||
interface MockServerTestProviderProps {
|
||||
children: React.ReactNode;
|
||||
dependencies?: MockServerDependencies;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple wrapper around the TestProvider that provides dependencies for the mock server.
|
||||
*/
|
||||
export const MockServerTestProvider = ({
|
||||
children,
|
||||
dependencies = getMockServerDependencies(),
|
||||
}: MockServerTestProviderProps) => {
|
||||
return <TestProvider {...dependencies}>{children}</TestProvider>;
|
||||
};
|
||||
|
||||
/**
|
||||
* Renders a component wrapped in the MockServerTestProvider.
|
||||
*/
|
||||
export const renderWrapper = (children: React.ReactNode, dependencies?: MockServerDependencies) => {
|
||||
return render(
|
||||
<MockServerTestProvider dependencies={dependencies}>{children}</MockServerTestProvider>
|
||||
);
|
||||
};
|
|
@ -6,23 +6,16 @@
|
|||
*/
|
||||
|
||||
import type { AppMountParameters, CoreStart } from '@kbn/core/public';
|
||||
import React, { useMemo } from 'react';
|
||||
import React from 'react';
|
||||
import { I18nProvider } from '@kbn/i18n-react';
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { Router } from 'react-router-dom';
|
||||
import { Route, Routes } from '@kbn/shared-ux-router';
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||
import { coreMock } from '@kbn/core/public/mocks';
|
||||
import { dataPluginMock } from '@kbn/data-plugin/public/mocks';
|
||||
import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
|
||||
import { chartPluginMock } from '@kbn/charts-plugin/public/mocks';
|
||||
import { unifiedSearchPluginMock } from '@kbn/unified-search-plugin/public/mocks';
|
||||
import { discoverPluginMock } from '@kbn/discover-plugin/public/mocks';
|
||||
import { fleetMock } from '@kbn/fleet-plugin/public/mocks';
|
||||
import { licensingMock } from '@kbn/licensing-plugin/public/mocks';
|
||||
import { uiActionsPluginMock } from '@kbn/ui-actions-plugin/public/mocks';
|
||||
import { sessionStorageMock } from '@kbn/core-http-server-mocks';
|
||||
import type { CspClientPluginStartDeps } from '../types';
|
||||
import { getMockDependencies } from './fixtures/get_mock_dependencies';
|
||||
|
||||
interface CspAppDeps {
|
||||
core: CoreStart;
|
||||
|
@ -33,20 +26,17 @@ interface CspAppDeps {
|
|||
|
||||
export const TestProvider: React.FC<Partial<CspAppDeps>> = ({
|
||||
core = coreMock.createStart(),
|
||||
deps = {
|
||||
data: dataPluginMock.createStartContract(),
|
||||
unifiedSearch: unifiedSearchPluginMock.createStartContract(),
|
||||
charts: chartPluginMock.createStartContract(),
|
||||
discover: discoverPluginMock.createStartContract(),
|
||||
fleet: fleetMock.createStartMock(),
|
||||
licensing: licensingMock.createStart(),
|
||||
uiActions: uiActionsPluginMock.createStartContract(),
|
||||
storage: sessionStorageMock.create(),
|
||||
},
|
||||
deps = getMockDependencies(),
|
||||
params = coreMock.createAppMountParameters(),
|
||||
children,
|
||||
} = {}) => {
|
||||
const queryClient = useMemo(() => new QueryClient(), []);
|
||||
const queryClient = new QueryClient({
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
retry: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<KibanaContextProvider services={{ ...core, ...deps }}>
|
||||
|
|
|
@ -0,0 +1,192 @@
|
|||
/*
|
||||
* 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 { http, HttpResponse } from 'msw';
|
||||
|
||||
export const cspmInstalledHandler = http.get('/internal/cloud_security_posture/benchmarks', () => {
|
||||
return HttpResponse.json({
|
||||
items: [
|
||||
{
|
||||
package_policy: {
|
||||
id: '630f3e42-659e-4499-9007-61e36adf1d97',
|
||||
name: 'cspm-1',
|
||||
namespace: 'default',
|
||||
description: '',
|
||||
package: {
|
||||
name: 'cloud_security_posture',
|
||||
title: 'Security Posture Management',
|
||||
version: '1.9.0',
|
||||
},
|
||||
enabled: true,
|
||||
policy_id: '30cba674-531c-4225-b392-3f7810957511',
|
||||
inputs: [
|
||||
{
|
||||
type: 'cloudbeat/cis_aws',
|
||||
policy_template: 'cspm',
|
||||
enabled: true,
|
||||
streams: [
|
||||
{
|
||||
enabled: true,
|
||||
data_stream: {
|
||||
type: 'logs',
|
||||
dataset: 'cloud_security_posture.findings',
|
||||
},
|
||||
vars: {
|
||||
access_key_id: {
|
||||
type: 'text',
|
||||
},
|
||||
secret_access_key: {
|
||||
type: 'text',
|
||||
},
|
||||
session_token: {
|
||||
type: 'text',
|
||||
},
|
||||
shared_credential_file: {
|
||||
type: 'text',
|
||||
},
|
||||
credential_profile_name: {
|
||||
type: 'text',
|
||||
},
|
||||
role_arn: {
|
||||
type: 'text',
|
||||
},
|
||||
'aws.credentials.type': {
|
||||
type: 'text',
|
||||
},
|
||||
'aws.account_type': {
|
||||
value: 'organization-account',
|
||||
type: 'text',
|
||||
},
|
||||
},
|
||||
id: 'cloudbeat/cis_aws-cloud_security_posture.findings-630f3e42-659e-4499-9007-61e36adf1d97',
|
||||
compiled_stream: {
|
||||
period: '24h',
|
||||
config: {
|
||||
v1: {
|
||||
type: 'cspm',
|
||||
deployment: 'aws',
|
||||
benchmark: 'cis_aws',
|
||||
aws: {
|
||||
account_type: 'organization-account',
|
||||
credentials: {
|
||||
type: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
config: {
|
||||
cloud_formation_template_url: {
|
||||
value:
|
||||
'https://console.aws.amazon.com/cloudformation/home#/stacks/quickcreate?templateURL=https://elastic-cspm-cft.s3.eu-central-1.amazonaws.com/cloudformation-cspm-ACCOUNT_TYPE-8.14.0.yml&stackName=Elastic-Cloud-Security-Posture-Management¶m_EnrollmentToken=FLEET_ENROLLMENT_TOKEN¶m_FleetUrl=FLEET_URL¶m_ElasticAgentVersion=KIBANA_VERSION¶m_ElasticArtifactServer=https://artifacts.elastic.co/downloads/beats/elastic-agent',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
vars: {
|
||||
posture: {
|
||||
value: 'cspm',
|
||||
type: 'text',
|
||||
},
|
||||
deployment: {
|
||||
value: 'aws',
|
||||
type: 'text',
|
||||
},
|
||||
},
|
||||
revision: 1,
|
||||
created_at: '2024-06-03T21:06:20.786Z',
|
||||
created_by: 'system',
|
||||
updated_at: '2024-06-03T21:06:20.786Z',
|
||||
updated_by: 'system',
|
||||
},
|
||||
agent_policy: {
|
||||
id: '30cba674-531c-4225-b392-3f7810957511',
|
||||
name: 'Agent policy 3',
|
||||
agents: 0,
|
||||
},
|
||||
rules_count: 55,
|
||||
},
|
||||
],
|
||||
total: 1,
|
||||
page: 1,
|
||||
perPage: 100,
|
||||
});
|
||||
});
|
||||
|
||||
export const kspmInstalledHandler = http.get('/internal/cloud_security_posture/benchmarks', () => {
|
||||
return HttpResponse.json({
|
||||
items: [
|
||||
{
|
||||
package_policy: {
|
||||
id: '6aedf856-bc21-49aa-859a-a0952789f898',
|
||||
version: 'WzE4ODcxLDE0XQ==',
|
||||
name: 'kspm-1',
|
||||
namespace: 'default',
|
||||
description: '',
|
||||
package: {
|
||||
name: 'cloud_security_posture',
|
||||
title: 'Security Posture Management',
|
||||
version: '1.9.0',
|
||||
},
|
||||
enabled: true,
|
||||
policy_id: 'e2f72eea-bf76-4576-bed8-e29d2df102a7',
|
||||
inputs: [
|
||||
{
|
||||
type: 'cloudbeat/cis_k8s',
|
||||
policy_template: 'kspm',
|
||||
enabled: true,
|
||||
streams: [
|
||||
{
|
||||
enabled: true,
|
||||
data_stream: {
|
||||
type: 'logs',
|
||||
dataset: 'cloud_security_posture.findings',
|
||||
},
|
||||
id: 'cloudbeat/cis_k8s-cloud_security_posture.findings-6aedf856-bc21-49aa-859a-a0952789f898',
|
||||
compiled_stream: {
|
||||
config: {
|
||||
v1: {
|
||||
type: 'kspm',
|
||||
deployment: 'self_managed',
|
||||
benchmark: 'cis_k8s',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
vars: {
|
||||
posture: {
|
||||
value: 'kspm',
|
||||
type: 'text',
|
||||
},
|
||||
deployment: {
|
||||
value: 'self_managed',
|
||||
type: 'text',
|
||||
},
|
||||
},
|
||||
revision: 1,
|
||||
created_at: '2024-06-03T21:23:23.139Z',
|
||||
created_by: 'system',
|
||||
updated_at: '2024-06-03T21:23:23.139Z',
|
||||
updated_by: 'system',
|
||||
},
|
||||
agent_policy: {
|
||||
id: 'e2f72eea-bf76-4576-bed8-e29d2df102a7',
|
||||
name: 'Agent policy 1',
|
||||
agents: 0,
|
||||
},
|
||||
rules_count: 92,
|
||||
},
|
||||
],
|
||||
total: 1,
|
||||
page: 1,
|
||||
perPage: 100,
|
||||
});
|
||||
});
|
|
@ -0,0 +1,251 @@
|
|||
/*
|
||||
* 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 { http, HttpResponse } from 'msw';
|
||||
|
||||
const STATUS_URL = `/internal/cloud_security_posture/status`;
|
||||
|
||||
export const notInstalledHandler = http.get(STATUS_URL, () => {
|
||||
return HttpResponse.json({
|
||||
cspm: {
|
||||
status: 'not-installed',
|
||||
healthyAgents: 1,
|
||||
installedPackagePolicies: 1,
|
||||
},
|
||||
kspm: {
|
||||
status: 'not-installed',
|
||||
healthyAgents: 1,
|
||||
installedPackagePolicies: 1,
|
||||
},
|
||||
vuln_mgmt: {
|
||||
status: 'not-installed',
|
||||
healthyAgents: 1,
|
||||
installedPackagePolicies: 1,
|
||||
},
|
||||
indicesDetails: [
|
||||
{
|
||||
index: 'logs-cloud_security_posture.findings_latest-default',
|
||||
status: 'empty',
|
||||
},
|
||||
{
|
||||
index: 'logs-cloud_security_posture.findings-default*',
|
||||
status: 'empty',
|
||||
},
|
||||
{
|
||||
index: 'logs-cloud_security_posture.scores-default',
|
||||
status: 'empty',
|
||||
},
|
||||
{
|
||||
index: 'logs-cloud_security_posture.vulnerabilities_latest-default',
|
||||
status: 'empty',
|
||||
},
|
||||
],
|
||||
isPluginInitialized: true,
|
||||
latestPackageVersion: '1.9.0',
|
||||
});
|
||||
});
|
||||
|
||||
export const notDeployedHandler = http.get(STATUS_URL, () => {
|
||||
return HttpResponse.json({
|
||||
cspm: {
|
||||
status: 'not-deployed',
|
||||
healthyAgents: 1,
|
||||
installedPackagePolicies: 1,
|
||||
},
|
||||
kspm: {
|
||||
status: 'not-deployed',
|
||||
healthyAgents: 1,
|
||||
installedPackagePolicies: 1,
|
||||
},
|
||||
vuln_mgmt: {
|
||||
status: 'not-deployed',
|
||||
healthyAgents: 1,
|
||||
installedPackagePolicies: 1,
|
||||
},
|
||||
indicesDetails: [
|
||||
{
|
||||
index: 'logs-cloud_security_posture.findings_latest-default',
|
||||
status: 'empty',
|
||||
},
|
||||
{
|
||||
index: 'logs-cloud_security_posture.findings-default*',
|
||||
status: 'empty',
|
||||
},
|
||||
{
|
||||
index: 'logs-cloud_security_posture.scores-default',
|
||||
status: 'not-empty',
|
||||
},
|
||||
{
|
||||
index: 'logs-cloud_security_posture.vulnerabilities_latest-default',
|
||||
status: 'empty',
|
||||
},
|
||||
],
|
||||
isPluginInitialized: true,
|
||||
latestPackageVersion: '1.9.0',
|
||||
installedPackageVersion: '1.9.0',
|
||||
});
|
||||
});
|
||||
|
||||
export const indexingHandler = http.get(STATUS_URL, () => {
|
||||
return HttpResponse.json({
|
||||
cspm: {
|
||||
status: 'indexing',
|
||||
healthyAgents: 1,
|
||||
installedPackagePolicies: 1,
|
||||
},
|
||||
kspm: {
|
||||
status: 'indexing',
|
||||
healthyAgents: 1,
|
||||
installedPackagePolicies: 1,
|
||||
},
|
||||
vuln_mgmt: {
|
||||
status: 'indexing',
|
||||
healthyAgents: 1,
|
||||
installedPackagePolicies: 1,
|
||||
},
|
||||
indicesDetails: [
|
||||
{
|
||||
index: 'logs-cloud_security_posture.findings_latest-default',
|
||||
status: 'empty',
|
||||
},
|
||||
{
|
||||
index: 'logs-cloud_security_posture.findings-default*',
|
||||
status: 'not-empty',
|
||||
},
|
||||
{
|
||||
index: 'logs-cloud_security_posture.scores-default',
|
||||
status: 'empty',
|
||||
},
|
||||
{
|
||||
index: 'logs-cloud_security_posture.vulnerabilities_latest-default',
|
||||
status: 'empty',
|
||||
},
|
||||
],
|
||||
isPluginInitialized: true,
|
||||
latestPackageVersion: '1.9.0',
|
||||
});
|
||||
});
|
||||
|
||||
export const indexTimeoutHandler = http.get(STATUS_URL, () => {
|
||||
return HttpResponse.json({
|
||||
cspm: {
|
||||
status: 'index-timeout',
|
||||
healthyAgents: 1,
|
||||
installedPackagePolicies: 1,
|
||||
},
|
||||
kspm: {
|
||||
status: 'index-timeout',
|
||||
healthyAgents: 1,
|
||||
installedPackagePolicies: 1,
|
||||
},
|
||||
vuln_mgmt: {
|
||||
status: 'index-timeout',
|
||||
healthyAgents: 1,
|
||||
installedPackagePolicies: 1,
|
||||
},
|
||||
indicesDetails: [
|
||||
{
|
||||
index: 'logs-cloud_security_posture.findings_latest-default',
|
||||
status: 'empty',
|
||||
},
|
||||
{
|
||||
index: 'logs-cloud_security_posture.findings-default*',
|
||||
status: 'empty',
|
||||
},
|
||||
{
|
||||
index: 'logs-cloud_security_posture.scores-default',
|
||||
status: 'empty',
|
||||
},
|
||||
{
|
||||
index: 'logs-cloud_security_posture.vulnerabilities_latest-default',
|
||||
status: 'empty',
|
||||
},
|
||||
],
|
||||
isPluginInitialized: true,
|
||||
latestPackageVersion: '1.9.0',
|
||||
});
|
||||
});
|
||||
|
||||
export const unprivilegedHandler = http.get(STATUS_URL, () => {
|
||||
return HttpResponse.json({
|
||||
cspm: {
|
||||
status: 'unprivileged',
|
||||
healthyAgents: 1,
|
||||
installedPackagePolicies: 1,
|
||||
},
|
||||
kspm: {
|
||||
status: 'unprivileged',
|
||||
healthyAgents: 1,
|
||||
installedPackagePolicies: 1,
|
||||
},
|
||||
vuln_mgmt: {
|
||||
status: 'unprivileged',
|
||||
healthyAgents: 1,
|
||||
installedPackagePolicies: 1,
|
||||
},
|
||||
indicesDetails: [
|
||||
{
|
||||
index: 'logs-cloud_security_posture.findings_latest-default',
|
||||
status: 'unprivileged',
|
||||
},
|
||||
{
|
||||
index: 'logs-cloud_security_posture.findings-default*',
|
||||
status: 'unprivileged',
|
||||
},
|
||||
{
|
||||
index: 'logs-cloud_security_posture.scores-default',
|
||||
status: 'unprivileged',
|
||||
},
|
||||
{
|
||||
index: 'logs-cloud_security_posture.vulnerabilities_latest-default',
|
||||
status: 'unprivileged',
|
||||
},
|
||||
],
|
||||
isPluginInitialized: true,
|
||||
latestPackageVersion: '1.9.0',
|
||||
});
|
||||
});
|
||||
|
||||
export const indexedHandler = http.get(STATUS_URL, () => {
|
||||
return HttpResponse.json({
|
||||
cspm: {
|
||||
status: 'indexed',
|
||||
healthyAgents: 1,
|
||||
installedPackagePolicies: 1,
|
||||
},
|
||||
kspm: {
|
||||
status: 'indexed',
|
||||
healthyAgents: 1,
|
||||
installedPackagePolicies: 1,
|
||||
},
|
||||
vuln_mgmt: {
|
||||
status: 'indexed',
|
||||
healthyAgents: 1,
|
||||
installedPackagePolicies: 1,
|
||||
},
|
||||
indicesDetails: [
|
||||
{
|
||||
index: 'logs-cloud_security_posture.findings_latest-default',
|
||||
status: 'not-empty',
|
||||
},
|
||||
{
|
||||
index: 'logs-cloud_security_posture.findings-default*',
|
||||
status: 'not-empty',
|
||||
},
|
||||
{
|
||||
index: 'logs-cloud_security_posture.scores-default',
|
||||
status: 'not-empty',
|
||||
},
|
||||
{
|
||||
index: 'logs-cloud_security_posture.vulnerabilities_latest-default',
|
||||
status: 'not-empty',
|
||||
},
|
||||
],
|
||||
isPluginInitialized: true,
|
||||
latestPackageVersion: '1.9.0',
|
||||
installedPackageVersion: '1.9.0',
|
||||
});
|
||||
});
|
205
yarn.lock
205
yarn.lock
|
@ -1431,6 +1431,20 @@
|
|||
resolved "https://registry.yarnpkg.com/@bufbuild/protobuf/-/protobuf-1.2.1.tgz#f8b1fbbe79726a4eafa9772ddde147b57f85d177"
|
||||
integrity sha512-cwwGvLGqvoaOZmoP5+i4v/rbW+rHkguvTehuZyM2p/xpmaNSdT2h3B7kHw33aiffv35t1XrYHIkdJSEkSEMJuA==
|
||||
|
||||
"@bundled-es-modules/cookie@^2.0.0":
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@bundled-es-modules/cookie/-/cookie-2.0.0.tgz#c3b82703969a61cf6a46e959a012b2c257f6b164"
|
||||
integrity sha512-Or6YHg/kamKHpxULAdSqhGqnWFneIXu1NKvvfBBzKGwpVsYuFIQ5aBPHDnnoR3ghW1nvSkALd+EF9iMtY7Vjxw==
|
||||
dependencies:
|
||||
cookie "^0.5.0"
|
||||
|
||||
"@bundled-es-modules/statuses@^1.0.1":
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@bundled-es-modules/statuses/-/statuses-1.0.1.tgz#761d10f44e51a94902c4da48675b71a76cc98872"
|
||||
integrity sha512-yn7BklA5acgcBr+7w064fGV+SGIFySjCKpqjcWgBAIfrAkY+4GQTJJHQMeT3V/sgz23VTEVV8TtOmkvJAhFVfg==
|
||||
dependencies:
|
||||
statuses "^2.0.1"
|
||||
|
||||
"@cbor-extract/cbor-extract-darwin-arm64@2.0.0":
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@cbor-extract/cbor-extract-darwin-arm64/-/cbor-extract-darwin-arm64-2.0.0.tgz#cf0667e4c22111c9d45e16c29964892b12460a76"
|
||||
|
@ -2830,6 +2844,43 @@
|
|||
resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3"
|
||||
integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==
|
||||
|
||||
"@inquirer/confirm@^3.0.0":
|
||||
version "3.1.8"
|
||||
resolved "https://registry.yarnpkg.com/@inquirer/confirm/-/confirm-3.1.8.tgz#db80f23f775d9b980c6de2425dde39f9786bf1d3"
|
||||
integrity sha512-f3INZ+ca4dQdn+MQiq1yP/mOIR/Oc8BLRYuDh6ciToWd6z4W8yArfzjBCMQ0BPY8PcJKwZxGIt8Z6yNT32eSTw==
|
||||
dependencies:
|
||||
"@inquirer/core" "^8.2.1"
|
||||
"@inquirer/type" "^1.3.2"
|
||||
|
||||
"@inquirer/core@^8.2.1":
|
||||
version "8.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@inquirer/core/-/core-8.2.1.tgz#ee92c2bf25f378819f56290f8ed8bfef8c6cc94d"
|
||||
integrity sha512-TIcuQMn2qrtyYe0j136UpHeYpk7AcR/trKeT/7YY0vRgcS9YSfJuQ2+PudPhSofLLsHNnRYAHScQCcVZrJkMqA==
|
||||
dependencies:
|
||||
"@inquirer/figures" "^1.0.2"
|
||||
"@inquirer/type" "^1.3.2"
|
||||
"@types/mute-stream" "^0.0.4"
|
||||
"@types/node" "^20.12.12"
|
||||
"@types/wrap-ansi" "^3.0.0"
|
||||
ansi-escapes "^4.3.2"
|
||||
chalk "^4.1.2"
|
||||
cli-spinners "^2.9.2"
|
||||
cli-width "^4.1.0"
|
||||
mute-stream "^1.0.0"
|
||||
signal-exit "^4.1.0"
|
||||
strip-ansi "^6.0.1"
|
||||
wrap-ansi "^6.2.0"
|
||||
|
||||
"@inquirer/figures@^1.0.2":
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@inquirer/figures/-/figures-1.0.2.tgz#a6af5e9f9969efb9ed3469130566315c36506b8a"
|
||||
integrity sha512-4F1MBwVr3c/m4bAUef6LgkvBfSjzwH+OfldgHqcuacWwSUetFebM2wi58WfG9uk1rR98U6GwLed4asLJbwdV5w==
|
||||
|
||||
"@inquirer/type@^1.3.2":
|
||||
version "1.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@inquirer/type/-/type-1.3.2.tgz#439b0b50c152c89fd369d2a17eff54869b4d79b8"
|
||||
integrity sha512-5Frickan9c89QbPkSu6I6y8p+9eR6hZkdPahGmNDsTFX8FHLPAozyzCZMKUeW8FyYwnlCKUjqIEqxY+UctARiw==
|
||||
|
||||
"@isaacs/cliui@^8.0.2":
|
||||
version "8.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550"
|
||||
|
@ -7305,6 +7356,23 @@
|
|||
resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.2.tgz#0f164b726869f71da3c594171df5ebc1c4b0a407"
|
||||
integrity sha512-O+6Gs8UeDbyFpbSh2CPEz/UOrrdWPTBYNblZK5CxxLisYt4kGX3Sc+czffFonyjiGSq3jWLwJS/CCJc7tBr4sQ==
|
||||
|
||||
"@mswjs/cookies@^1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@mswjs/cookies/-/cookies-1.1.0.tgz#1528eb43630caf83a1d75d5332b30e75e9bb1b5b"
|
||||
integrity sha512-0ZcCVQxifZmhwNBoQIrystCb+2sWBY2Zw8lpfJBPCHGCA/HWqehITeCRVIv4VMy8MPlaHo2w2pTHFV2pFfqKPw==
|
||||
|
||||
"@mswjs/interceptors@^0.29.0":
|
||||
version "0.29.1"
|
||||
resolved "https://registry.yarnpkg.com/@mswjs/interceptors/-/interceptors-0.29.1.tgz#e77fc58b5188569041d0440b25c9e9ebb1ccd60a"
|
||||
integrity sha512-3rDakgJZ77+RiQUuSK69t1F0m8BQKA8Vh5DCS5V0DWvNY67zob2JhhQrhCO0AKLGINTRSFd1tBaHcJTkhefoSw==
|
||||
dependencies:
|
||||
"@open-draft/deferred-promise" "^2.2.0"
|
||||
"@open-draft/logger" "^0.3.0"
|
||||
"@open-draft/until" "^2.0.0"
|
||||
is-node-process "^1.2.0"
|
||||
outvariant "^1.2.1"
|
||||
strict-event-emitter "^0.5.1"
|
||||
|
||||
"@nicolo-ribaudo/chokidar-2@2.1.8-no-fsevents.3":
|
||||
version "2.1.8-no-fsevents.3"
|
||||
resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz#323d72dd25103d0c4fbdce89dadf574a787b1f9b"
|
||||
|
@ -7603,6 +7671,24 @@
|
|||
dependencies:
|
||||
"@octokit/openapi-types" "^18.0.0"
|
||||
|
||||
"@open-draft/deferred-promise@^2.2.0":
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@open-draft/deferred-promise/-/deferred-promise-2.2.0.tgz#4a822d10f6f0e316be4d67b4d4f8c9a124b073bd"
|
||||
integrity sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==
|
||||
|
||||
"@open-draft/logger@^0.3.0":
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@open-draft/logger/-/logger-0.3.0.tgz#2b3ab1242b360aa0adb28b85f5d7da1c133a0954"
|
||||
integrity sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==
|
||||
dependencies:
|
||||
is-node-process "^1.2.0"
|
||||
outvariant "^1.4.0"
|
||||
|
||||
"@open-draft/until@^2.0.0", "@open-draft/until@^2.1.0":
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@open-draft/until/-/until-2.1.0.tgz#0acf32f470af2ceaf47f095cdecd40d68666efda"
|
||||
integrity sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==
|
||||
|
||||
"@opentelemetry/api-metrics@0.31.0", "@opentelemetry/api-metrics@^0.31.0":
|
||||
version "0.31.0"
|
||||
resolved "https://registry.yarnpkg.com/@opentelemetry/api-metrics/-/api-metrics-0.31.0.tgz#0ed4cf4d7c731f968721c2b303eaf5e9fd42f736"
|
||||
|
@ -9783,6 +9869,11 @@
|
|||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/cookie@^0.6.0":
|
||||
version "0.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.6.0.tgz#eac397f28bf1d6ae0ae081363eca2f425bedf0d5"
|
||||
integrity sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==
|
||||
|
||||
"@types/cookiejar@^2.1.5":
|
||||
version "2.1.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/cookiejar/-/cookiejar-2.1.5.tgz#14a3e83fa641beb169a2dd8422d91c3c345a9a78"
|
||||
|
@ -10474,6 +10565,13 @@
|
|||
resolved "https://registry.yarnpkg.com/@types/mustache/-/mustache-0.8.31.tgz#7c86cbf74f7733f9e3bdc28817623927eb386616"
|
||||
integrity sha512-72flCZJkEJHPwhmpHgg4a0ZBLssMhg5NB0yltRblRlZMo4py3B/u/d7icevc4EeN9MPQUo/dPtuVOoVy9ih6cQ==
|
||||
|
||||
"@types/mute-stream@^0.0.4":
|
||||
version "0.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/mute-stream/-/mute-stream-0.0.4.tgz#77208e56a08767af6c5e1237be8888e2f255c478"
|
||||
integrity sha512-CPM9nzrCPPJHQNA9keH9CVkVI+WR5kMa+7XEs5jcGQ0VoAGnLv242w8lIVgwAEfmE4oufJRaTc9PNLQl0ioAow==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/nock@^10.0.3":
|
||||
version "10.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/nock/-/nock-10.0.3.tgz#dab1d18ffbccfbf2db811dab9584304eeb6e1c4c"
|
||||
|
@ -10511,7 +10609,7 @@
|
|||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/node@*", "@types/node@14 || 16 || 17", "@types/node@20.10.5", "@types/node@>= 8", "@types/node@>=12.12.47", "@types/node@>=13.7.0", "@types/node@>=18.0.0", "@types/node@^14.0.10 || ^16.0.0", "@types/node@^14.14.20 || ^16.0.0", "@types/node@^18.0.0", "@types/node@^18.11.18":
|
||||
"@types/node@*", "@types/node@14 || 16 || 17", "@types/node@20.10.5", "@types/node@>= 8", "@types/node@>=12.12.47", "@types/node@>=13.7.0", "@types/node@>=18.0.0", "@types/node@^14.0.10 || ^16.0.0", "@types/node@^14.14.20 || ^16.0.0", "@types/node@^18.0.0", "@types/node@^18.11.18", "@types/node@^20.12.12":
|
||||
version "20.10.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.10.5.tgz#47ad460b514096b7ed63a1dae26fad0914ed3ab2"
|
||||
integrity sha512-nNPsNE65wjMxEKI93yOP+NPGGBJz/PoN3kZsVLee0XMiJolxSekEVD8wRwBUBqkwc7UWop0edW50yrCQW4CyRw==
|
||||
|
@ -10929,6 +11027,11 @@
|
|||
resolved "https://registry.yarnpkg.com/@types/stats-lite/-/stats-lite-2.2.0.tgz#bc8190bf9dfa1e16b89eaa2b433c99dff0804de9"
|
||||
integrity sha512-YV6SS4QC+pbzqjMIV8qVSTDOOazgKBLTVaN+7PfuxELjz/eyzc20KwDVGPrbHt2OcYMA7K2ezLB45Cp6DpNOSQ==
|
||||
|
||||
"@types/statuses@^2.0.4":
|
||||
version "2.0.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/statuses/-/statuses-2.0.5.tgz#f61ab46d5352fd73c863a1ea4e1cef3b0b51ae63"
|
||||
integrity sha512-jmIUGWrAiwu3dZpxntxieC+1n/5c3mjrImkmOSQ2NC5uP6cYO4aAZDdSmRcI5C1oiTmqlZGHC+/NmJrKogbP5A==
|
||||
|
||||
"@types/styled-components@^5.1.0":
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/styled-components/-/styled-components-5.1.0.tgz#24d3412ba5395aa06e14fbc93c52f9454cebd0d6"
|
||||
|
@ -11139,6 +11242,11 @@
|
|||
tapable "^2.2.0"
|
||||
webpack "^5"
|
||||
|
||||
"@types/wrap-ansi@^3.0.0":
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/wrap-ansi/-/wrap-ansi-3.0.0.tgz#18b97a972f94f60a679fd5c796d96421b9abb9fd"
|
||||
integrity sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g==
|
||||
|
||||
"@types/ws@*", "@types/ws@^8.5.1":
|
||||
version "8.5.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.3.tgz#7d25a1ffbecd3c4f2d35068d0b283c037003274d"
|
||||
|
@ -11892,12 +12000,12 @@ ansi-colors@^3.0.0:
|
|||
resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf"
|
||||
integrity sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==
|
||||
|
||||
ansi-escapes@^4.2.1, ansi-escapes@^4.3.0:
|
||||
version "4.3.0"
|
||||
resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.0.tgz#a4ce2b33d6b214b7950d8595c212f12ac9cc569d"
|
||||
integrity sha512-EiYhwo0v255HUL6eDyuLrXEkTi7WwVCLAw+SeOQ7M7qdun1z1pum4DEm/nuqIVbPvi9RPPc9k9LbyBv6H0DwVg==
|
||||
ansi-escapes@^4.2.1, ansi-escapes@^4.3.0, ansi-escapes@^4.3.2:
|
||||
version "4.3.2"
|
||||
resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e"
|
||||
integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==
|
||||
dependencies:
|
||||
type-fest "^0.8.1"
|
||||
type-fest "^0.21.3"
|
||||
|
||||
ansi-escapes@^6.2.0:
|
||||
version "6.2.1"
|
||||
|
@ -13922,7 +14030,7 @@ cli-progress@^3.12.0:
|
|||
dependencies:
|
||||
string-width "^4.2.3"
|
||||
|
||||
cli-spinners@^2.2.0, cli-spinners@^2.5.0:
|
||||
cli-spinners@^2.2.0, cli-spinners@^2.5.0, cli-spinners@^2.9.2:
|
||||
version "2.9.2"
|
||||
resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.9.2.tgz#1773a8f4b9c4d6ac31563df53b3fc1d79462fe41"
|
||||
integrity sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==
|
||||
|
@ -13957,6 +14065,11 @@ cli-width@^3.0.0:
|
|||
resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6"
|
||||
integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==
|
||||
|
||||
cli-width@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-4.1.0.tgz#42daac41d3c254ef38ad8ac037672130173691c5"
|
||||
integrity sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==
|
||||
|
||||
client-only@^0.0.1:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.yarnpkg.com/client-only/-/client-only-0.0.1.tgz#38bba5d403c41ab150bff64a95c85013cf73bca1"
|
||||
|
@ -18725,7 +18838,7 @@ graphql-tag@^2.12.6:
|
|||
dependencies:
|
||||
tslib "^2.1.0"
|
||||
|
||||
graphql@^16.6.0:
|
||||
graphql@^16.6.0, graphql@^16.8.1:
|
||||
version "16.8.1"
|
||||
resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.8.1.tgz#1930a965bef1170603702acdb68aedd3f3cf6f07"
|
||||
integrity sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==
|
||||
|
@ -19081,6 +19194,11 @@ he@1.2.0, he@^1.2.0:
|
|||
resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
|
||||
integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
|
||||
|
||||
headers-polyfill@^4.0.2:
|
||||
version "4.0.3"
|
||||
resolved "https://registry.yarnpkg.com/headers-polyfill/-/headers-polyfill-4.0.3.tgz#922a0155de30ecc1f785bcf04be77844ca95ad07"
|
||||
integrity sha512-IScLbePpkvO846sIwOtOTDjutRMWdXdJmXdMvk6gCBHxFO8d+QKOQedyZSxFTTFYRSmlgSTDtXqqq4pcenBXLQ==
|
||||
|
||||
heap@^0.2.6:
|
||||
version "0.2.6"
|
||||
resolved "https://registry.yarnpkg.com/heap/-/heap-0.2.6.tgz#087e1f10b046932fc8594dd9e6d378afc9d1e5ac"
|
||||
|
@ -20083,6 +20201,11 @@ is-nil@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/is-nil/-/is-nil-1.0.1.tgz#2daba29e0b585063875e7b539d071f5b15937969"
|
||||
integrity sha1-LauingtYUGOHXntTnQcfWxWTeWk=
|
||||
|
||||
is-node-process@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/is-node-process/-/is-node-process-1.2.0.tgz#ea02a1b90ddb3934a19aea414e88edef7e11d134"
|
||||
integrity sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==
|
||||
|
||||
is-npm@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-6.0.0.tgz#b59e75e8915543ca5d881ecff864077cba095261"
|
||||
|
@ -23336,6 +23459,29 @@ msgpackr@^1.9.9:
|
|||
optionalDependencies:
|
||||
msgpackr-extract "^3.0.2"
|
||||
|
||||
msw@^2.3.1:
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/msw/-/msw-2.3.1.tgz#bfc73e256ffc2c74ec4381b604abb258df35f32b"
|
||||
integrity sha512-ocgvBCLn/5l3jpl1lssIb3cniuACJLoOfZu01e3n5dbJrpA5PeeWn28jCLgQDNt6d7QT8tF2fYRzm9JoEHtiig==
|
||||
dependencies:
|
||||
"@bundled-es-modules/cookie" "^2.0.0"
|
||||
"@bundled-es-modules/statuses" "^1.0.1"
|
||||
"@inquirer/confirm" "^3.0.0"
|
||||
"@mswjs/cookies" "^1.1.0"
|
||||
"@mswjs/interceptors" "^0.29.0"
|
||||
"@open-draft/until" "^2.1.0"
|
||||
"@types/cookie" "^0.6.0"
|
||||
"@types/statuses" "^2.0.4"
|
||||
chalk "^4.1.2"
|
||||
graphql "^16.8.1"
|
||||
headers-polyfill "^4.0.2"
|
||||
is-node-process "^1.2.0"
|
||||
outvariant "^1.4.2"
|
||||
path-to-regexp "^6.2.0"
|
||||
strict-event-emitter "^0.5.1"
|
||||
type-fest "^4.9.0"
|
||||
yargs "^17.7.2"
|
||||
|
||||
multicast-dns@^7.2.5:
|
||||
version "7.2.5"
|
||||
resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-7.2.5.tgz#77eb46057f4d7adbd16d9290fa7299f6fa64cced"
|
||||
|
@ -23385,6 +23531,11 @@ mute-stream@0.0.8:
|
|||
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d"
|
||||
integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==
|
||||
|
||||
mute-stream@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-1.0.0.tgz#e31bd9fe62f0aed23520aa4324ea6671531e013e"
|
||||
integrity sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==
|
||||
|
||||
nan@^2.18.0:
|
||||
version "2.18.0"
|
||||
resolved "https://registry.yarnpkg.com/nan/-/nan-2.18.0.tgz#26a6faae7ffbeb293a39660e88a76b82e30b7554"
|
||||
|
@ -24342,6 +24493,11 @@ ospath@^1.2.2:
|
|||
resolved "https://registry.yarnpkg.com/ospath/-/ospath-1.2.2.tgz#1276639774a3f8ef2572f7fe4280e0ea4550c07b"
|
||||
integrity sha1-EnZjl3Sj+O8lcvf+QoDg6kVQwHs=
|
||||
|
||||
outvariant@^1.2.1, outvariant@^1.4.0, outvariant@^1.4.2:
|
||||
version "1.4.2"
|
||||
resolved "https://registry.yarnpkg.com/outvariant/-/outvariant-1.4.2.tgz#f54f19240eeb7f15b28263d5147405752d8e2066"
|
||||
integrity sha512-Ou3dJ6bA/UJ5GVHxah4LnqDwZRwAmWxrG3wtrHrbGnP4RnLCtA64A4F+ae7Y8ww660JaddSoArUR5HjipWSHAQ==
|
||||
|
||||
p-all@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/p-all/-/p-all-2.1.0.tgz#91419be56b7dee8fe4c5db875d55e0da084244a0"
|
||||
|
@ -24737,6 +24893,11 @@ path-to-regexp@^2.2.1:
|
|||
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-2.4.0.tgz#35ce7f333d5616f1c1e1bfe266c3aba2e5b2e704"
|
||||
integrity sha512-G6zHoVqC6GGTQkZwF4lkuEyMbVOjoBKAEybQUypI1WTkqinCOrq2x6U2+phkJ1XsEMTy4LjtwPI7HW+NVrRR2w==
|
||||
|
||||
path-to-regexp@^6.2.0:
|
||||
version "6.2.2"
|
||||
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-6.2.2.tgz#324377a83e5049cbecadc5554d6a63a9a4866b36"
|
||||
integrity sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw==
|
||||
|
||||
path-type@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441"
|
||||
|
@ -28261,10 +28422,10 @@ signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7:
|
|||
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9"
|
||||
integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==
|
||||
|
||||
signal-exit@^4.0.1:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.0.2.tgz#ff55bb1d9ff2114c13b400688fa544ac63c36967"
|
||||
integrity sha512-MY2/qGx4enyjprQnFaZsHib3Yadh3IXyV2C321GY0pjGfVBu4un0uDJkwgdxqO+Rdx8JMT8IfJIRwbYVz3Ob3Q==
|
||||
signal-exit@^4.0.1, signal-exit@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04"
|
||||
integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==
|
||||
|
||||
simple-bin-help@^1.8.0:
|
||||
version "1.8.0"
|
||||
|
@ -28938,7 +29099,7 @@ stats-lite@^2.2.0:
|
|||
dependencies:
|
||||
isnumber "~1.0.0"
|
||||
|
||||
statuses@2.0.1:
|
||||
statuses@2.0.1, statuses@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63"
|
||||
integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==
|
||||
|
@ -29026,6 +29187,11 @@ streamx@^2.12.0, streamx@^2.12.5, streamx@^2.13.0, streamx@^2.13.2, streamx@^2.1
|
|||
optionalDependencies:
|
||||
bare-events "^2.2.0"
|
||||
|
||||
strict-event-emitter@^0.5.1:
|
||||
version "0.5.1"
|
||||
resolved "https://registry.yarnpkg.com/strict-event-emitter/-/strict-event-emitter-0.5.1.tgz#1602ece81c51574ca39c6815e09f1a3e8550bd93"
|
||||
integrity sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==
|
||||
|
||||
strict-uri-encode@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546"
|
||||
|
@ -30286,6 +30452,11 @@ type-fest@^0.20.2:
|
|||
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4"
|
||||
integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==
|
||||
|
||||
type-fest@^0.21.3:
|
||||
version "0.21.3"
|
||||
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37"
|
||||
integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==
|
||||
|
||||
type-fest@^0.6.0:
|
||||
version "0.6.0"
|
||||
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b"
|
||||
|
@ -30306,10 +30477,10 @@ type-fest@^2.13.0:
|
|||
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.19.0.tgz#88068015bb33036a598b952e55e9311a60fd3a9b"
|
||||
integrity sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==
|
||||
|
||||
type-fest@^4.15.0, type-fest@^4.17.0:
|
||||
version "4.17.0"
|
||||
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-4.17.0.tgz#4c1b2c2852d2a40ba8c0236d3afc6fc68229e5bf"
|
||||
integrity sha512-9flrz1zkfLRH3jO3bLflmTxryzKMxVa7841VeMgBaNQGY6vH4RCcpN/sQLB7mQQYh1GZ5utT2deypMuCy4yicw==
|
||||
type-fest@^4.15.0, type-fest@^4.17.0, type-fest@^4.9.0:
|
||||
version "4.18.3"
|
||||
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-4.18.3.tgz#5249f96e7c2c3f0f1561625f54050e343f1c8f68"
|
||||
integrity sha512-Q08/0IrpvM+NMY9PA2rti9Jb+JejTddwmwmVQGskAlhtcrw1wsRzoR6ode6mR+OAabNa75w/dxedSUY2mlphaQ==
|
||||
|
||||
type-is@~1.6.18:
|
||||
version "1.6.18"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue