[Fleet] Fix policy editor error when validationResults.inputs is null (#155079)

Improve various typings and remove non-null assertions to ensure the
policy editor doesn't break when rendering a policy template without
`vars` or `streams` in its inputs.

Closes https://github.com/elastic/kibana/issues/155064


![image](https://user-images.githubusercontent.com/6766512/232572327-df4ee721-722a-4d10-8eba-5ff048f5536b.png)

---------

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Kyle Pollich 2023-04-18 12:17:06 -04:00 committed by GitHub
parent a7c9880263
commit 136876091a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 101 additions and 25 deletions

View file

@ -512,7 +512,7 @@ describe('Fleet - validatePackagePolicy()', () => {
name: null,
description: null,
namespace: null,
inputs: null,
inputs: {},
vars: {},
});
expect(
@ -528,7 +528,7 @@ describe('Fleet - validatePackagePolicy()', () => {
name: null,
description: null,
namespace: null,
inputs: null,
inputs: {},
vars: {},
});
});
@ -547,7 +547,7 @@ describe('Fleet - validatePackagePolicy()', () => {
name: null,
description: null,
namespace: null,
inputs: null,
inputs: {},
vars: {},
});
expect(
@ -563,7 +563,7 @@ describe('Fleet - validatePackagePolicy()', () => {
name: null,
description: null,
namespace: null,
inputs: null,
inputs: {},
vars: {},
});
});

View file

@ -101,7 +101,7 @@ export const validatePackagePolicy = (
(policyTemplate.inputs && policyTemplate.inputs.length > 0)
)
) {
validationResults.inputs = null;
validationResults.inputs = {};
return validationResults;
}
@ -199,7 +199,7 @@ export const validatePackagePolicy = (
});
if (Object.entries(validationResults.inputs!).length === 0) {
validationResults.inputs = null;
validationResults.inputs = {};
}
return validationResults;

View file

@ -7,11 +7,14 @@
import React from 'react';
import { act, fireEvent, waitFor } from '@testing-library/react';
import { safeLoad } from 'js-yaml';
import type { TestRenderer } from '../../../../../../../mock';
import { createFleetTestRendererMock } from '../../../../../../../mock';
import type { NewPackagePolicy, PackageInfo } from '../../../../../types';
import { validatePackagePolicy } from '../../services';
import { StepConfigurePackagePolicy } from './step_configure_package';
describe('StepConfigurePackage', () => {
@ -24,12 +27,12 @@ describe('StepConfigurePackage', () => {
};
});
const validationResults = { name: null, description: null, namespace: null, inputs: {} };
let testRenderer: TestRenderer;
let renderResult: ReturnType<typeof testRenderer.render>;
const render = () =>
(renderResult = testRenderer.render(
const render = () => {
const validationResults = validatePackagePolicy(packagePolicy, packageInfo, safeLoad);
renderResult = testRenderer.render(
<StepConfigurePackagePolicy
packageInfo={packageInfo}
packagePolicy={packagePolicy}
@ -37,7 +40,8 @@ describe('StepConfigurePackage', () => {
validationResults={validationResults}
submitAttempted={false}
/>
));
);
};
beforeEach(() => {
packageInfo = {
@ -150,4 +154,17 @@ describe('StepConfigurePackage', () => {
});
expect(mockUpdatePackagePolicy.mock.calls[0][0].inputs[0].enabled).toEqual(false);
});
it('should render without data streams or vars', async () => {
packageInfo.data_streams = [];
packagePolicy.inputs[0].streams = [];
render();
await waitFor(async () => {
expect(
await renderResult.findByText('Collect logs from Nginx instances')
).toBeInTheDocument();
});
});
});

View file

@ -34,7 +34,7 @@ export const StepConfigurePackagePolicy: React.FunctionComponent<{
showOnlyIntegration?: string;
packagePolicy: NewPackagePolicy;
updatePackagePolicy: (fields: Partial<NewPackagePolicy>) => void;
validationResults: PackagePolicyValidationResults;
validationResults: PackagePolicyValidationResults | undefined;
submitAttempted: boolean;
noTopRule?: boolean;
isEditPage?: boolean;
@ -104,11 +104,11 @@ export const StepConfigurePackagePolicy: React.FunctionComponent<{
});
}}
inputValidationResults={
validationResults!.inputs![
validationResults?.inputs?.[
hasIntegrations
? `${policyTemplate.name}-${packagePolicyInput.type}`
: packagePolicyInput.type
]
] ?? {}
}
forceShowErrors={submitAttempted}
isEditPage={isEditPage}

View file

@ -52,7 +52,7 @@ export const StepDefinePackagePolicy: React.FunctionComponent<{
packageInfo: PackageInfo;
packagePolicy: NewPackagePolicy;
updatePackagePolicy: (fields: Partial<NewPackagePolicy>) => void;
validationResults: PackagePolicyValidationResults;
validationResults: PackagePolicyValidationResults | undefined;
submitAttempted: boolean;
isEditPage?: boolean;
noAdvancedToggle?: boolean;
@ -201,7 +201,7 @@ export const StepDefinePackagePolicy: React.FunctionComponent<{
},
});
}}
errors={validationResults.vars![varName]}
errors={validationResults?.vars?.[varName] ?? []}
forceShowErrors={submitAttempted}
/>
</EuiFlexItem>
@ -350,7 +350,7 @@ export const StepDefinePackagePolicy: React.FunctionComponent<{
},
});
}}
errors={validationResults.vars![varName]}
errors={validationResults?.vars?.[varName] ?? []}
forceShowErrors={submitAttempted}
/>
</EuiFlexItem>

View file

@ -238,7 +238,7 @@ export const AddIntegrationPageStep: React.FC<MultiPageStepLayoutProps> = (props
showOnlyIntegration={integrationInfo?.name}
packagePolicy={packagePolicy}
updatePackagePolicy={updatePackagePolicy}
validationResults={validationResults!}
validationResults={validationResults}
submitAttempted={formState === 'INVALID'}
noTopRule={true}
/>
@ -248,7 +248,7 @@ export const AddIntegrationPageStep: React.FC<MultiPageStepLayoutProps> = (props
packageInfo={packageInfo}
packagePolicy={packagePolicy}
updatePackagePolicy={updatePackagePolicy}
validationResults={validationResults!}
validationResults={validationResults}
submitAttempted={formState === 'INVALID'}
noAdvancedToggle={true}
/>

View file

@ -307,7 +307,7 @@ export const CreatePackagePolicySinglePage: CreatePackagePolicyParams = ({
packageInfo={packageInfo}
packagePolicy={packagePolicy}
updatePackagePolicy={updatePackagePolicy}
validationResults={validationResults!}
validationResults={validationResults}
submitAttempted={formState === 'INVALID'}
/>
@ -318,7 +318,7 @@ export const CreatePackagePolicySinglePage: CreatePackagePolicyParams = ({
showOnlyIntegration={integrationInfo?.name}
packagePolicy={packagePolicy}
updatePackagePolicy={updatePackagePolicy}
validationResults={validationResults!}
validationResults={validationResults}
submitAttempted={formState === 'INVALID'}
/>
)}

View file

@ -293,7 +293,7 @@ export const EditPackagePolicyForm = memo<{
packageInfo={packageInfo}
packagePolicy={packagePolicy}
updatePackagePolicy={updatePackagePolicy}
validationResults={validationResults!}
validationResults={validationResults}
submitAttempted={formState === 'INVALID'}
isEditPage={true}
/>
@ -305,7 +305,7 @@ export const EditPackagePolicyForm = memo<{
packageInfo={packageInfo}
packagePolicy={packagePolicy}
updatePackagePolicy={updatePackagePolicy}
validationResults={validationResults!}
validationResults={validationResults}
submitAttempted={formState === 'INVALID'}
isEditPage={true}
/>

View file

@ -1,7 +1,7 @@
format_version: 1.0.0
name: all_assets
name: all_assets
title: All Assets Updated
description: tests that all assets are updated
description: tests that all assets are updated
version: 0.2.0
categories: []
release: beta

View file

@ -0,0 +1,3 @@
# Test package
Test package with a single input and no defined data streams

View file

@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64">
<g fill="none" fill-rule="evenodd">
<path fill="#F04E98" d="M29,32.0001 L15.935,9.4321 C13.48,5.1941 7,6.9351 7,11.8321 L7,52.1681 C7,57.0651 13.48,58.8061 15.935,54.5671 L29,32.0001 Z"/>
<path fill="#FA744E" d="M34.7773,32.0001 L33.3273,34.5051 L20.2613,57.0731 C19.8473,57.7871 19.3533,58.4271 18.8023,59.0001 L34.9273,59.0001 C38.7073,59.0001 42.2213,57.0601 44.2363,53.8611 L58.0003,32.0001 L34.7773,32.0001 Z"/>
<path fill="#343741" d="M44.2363,10.1392 C42.2213,6.9402 38.7073,5.0002 34.9273,5.0002 L18.8023,5.0002 C19.3533,5.5732 19.8473,6.2122 20.2613,6.9272 L33.3273,29.4942 L34.7773,32.0002 L58.0003,32.0002 L44.2363,10.1392 Z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 751 B

View file

@ -0,0 +1,24 @@
format_version: 1.1.0
name: single_input_no_streams
title: Single input, no stream
description: Test package with a single input and no streams
version: 0.1.0
categories: []
conditions:
kibana.version: ^8.8.0
elastic.subscription: basic
policy_templates:
- name: Single Input
title: Single Input
description: Single Input
inputs:
- title: Single Input
description: Single input
type: single_input
type: integration
owner:
github: elastic/fleet
icons:
- src: '/img/logo_overrides_64_color.svg'
size: '16x16'
type: 'image/svg+xml'

View file

@ -446,6 +446,31 @@ export default function (providerContext: FtrProviderContext) {
expect(policy.name).to.equal(nameWithWhitespace.trim());
});
it('should return a 200 when a package has no variables or data streams', async function () {
await supertest
.post('/api/fleet/package_policies')
.set('kbn-xsrf', 'xxxx')
.send({
name: 'no-variables-or-data-streams',
description: '',
namespace: 'default',
policy_id: agentPolicyId,
enabled: true,
inputs: [
{
enabled: true,
streams: [],
type: 'single_input',
},
],
package: {
name: 'single_input_no_streams',
version: '0.1.0',
},
})
.expect(200);
});
describe('input only packages', () => {
it('should default dataset if not provided for input only pkg', async function () {
await supertest