v2Wizrd: add kernel and services data

this commit adds kernel arguments and enabled/disabled services to Oscap step.
and also add to Review step, add some tests to kernel and services as well.
This commit is contained in:
mgold1234 2024-01-30 17:38:07 +02:00 committed by Lucas Garfield
parent 74f71f2dca
commit 40b1d4de57
6 changed files with 204 additions and 89 deletions

View file

@ -26,12 +26,23 @@ import {
} from '../../../../store/imageBuilderApi'; } from '../../../../store/imageBuilderApi';
import { import {
changeOscapProfile, changeOscapProfile,
changeKernel,
selectDistribution, selectDistribution,
selectProfile, selectProfile,
selectKernel,
selectDisabledServices,
selectEnabledServices,
changeDisabledServices,
changeEnabledServices,
} from '../../../../store/wizardSlice'; } from '../../../../store/wizardSlice';
const ProfileSelector = () => { const ProfileSelector = () => {
const oscapProfile = useAppSelector((state) => selectProfile(state)); const oscapProfile = useAppSelector((state) => selectProfile(state));
let kernel = useAppSelector((state) => selectKernel(state));
let disabledServices = useAppSelector((state) =>
selectDisabledServices(state)
);
let enabledServices = useAppSelector((state) => selectEnabledServices(state));
const release = useAppSelector((state) => selectDistribution(state)); const release = useAppSelector((state) => selectDistribution(state));
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const [profileName, setProfileName] = useState<string | undefined>('None'); const [profileName, setProfileName] = useState<string | undefined>('None');
@ -56,6 +67,26 @@ const ProfileSelector = () => {
skip: !oscapProfile, skip: !oscapProfile,
} }
); );
kernel = data?.kernel?.append;
disabledServices = data?.services?.disabled;
enabledServices = data?.services?.enabled;
useEffect(() => {
if (isFetching || !isSuccess) return;
dispatch(changeKernel(kernel));
dispatch(changeDisabledServices(disabledServices));
dispatch(changeEnabledServices(enabledServices));
}, [
isFetching,
isSuccess,
dispatch,
data?.kernel?.append,
data?.services?.disabled,
data?.services?.enabled,
disabledServices,
enabledServices,
kernel,
]);
useEffect(() => { useEffect(() => {
if ( if (
@ -76,6 +107,9 @@ const ProfileSelector = () => {
const handleClear = () => { const handleClear = () => {
dispatch(changeOscapProfile(undefined)); dispatch(changeOscapProfile(undefined));
dispatch(changeKernel(undefined));
dispatch(changeDisabledServices(undefined));
dispatch(changeEnabledServices(undefined));
setProfileName(undefined); setProfileName(undefined);
}; };
@ -84,6 +118,9 @@ const ProfileSelector = () => {
selection: DistributionProfileItem selection: DistributionProfileItem
) => { ) => {
dispatch(changeOscapProfile(selection)); dispatch(changeOscapProfile(selection));
dispatch(changeKernel(kernel));
dispatch(changeDisabledServices(disabledServices));
dispatch(changeEnabledServices(enabledServices));
setIsOpen(false); setIsOpen(false);
}; };

View file

@ -1,6 +1,9 @@
import React from 'react'; import React from 'react';
import { import {
Alert,
CodeBlock,
CodeBlockCode,
Spinner, Spinner,
TextContent, TextContent,
TextList, TextList,
@ -17,7 +20,7 @@ import {
selectProfile, selectProfile,
} from '../../../../store/wizardSlice'; } from '../../../../store/wizardSlice';
const OscapProfileInformation = (): JSX.Element => { export const OscapProfileInformation = (): JSX.Element => {
const release = useAppSelector((state) => selectDistribution(state)); const release = useAppSelector((state) => selectDistribution(state));
const oscapProfile = useAppSelector((state) => selectProfile(state)); const oscapProfile = useAppSelector((state) => selectProfile(state));
@ -36,46 +39,97 @@ const OscapProfileInformation = (): JSX.Element => {
} }
); );
const enabledServicesDisplayString =
oscapProfileInfo?.services?.enabled?.join(' ');
const disableServicesDisplayString =
oscapProfileInfo?.services?.disabled?.join(' ');
return ( return (
<> <>
{isFetchingOscapProfileInfo && <Spinner size="lg" />} {isFetchingOscapProfileInfo && <Spinner size="lg" />}
{isSuccessOscapProfileInfo && ( {isSuccessOscapProfileInfo && (
<TextContent> <>
<br /> <TextContent>
<TextList component={TextListVariants.dl}> <br />
<TextListItem <TextList component={TextListVariants.dl}>
component={TextListItemVariants.dt} <TextListItem
className="pf-u-min-width" component={TextListItemVariants.dt}
> className="pf-u-min-width"
Profile description: >
</TextListItem> Profile description:
<TextListItem component={TextListItemVariants.dd}> </TextListItem>
{oscapProfileInfo.openscap?.profile_description} <TextListItem component={TextListItemVariants.dd}>
</TextListItem> {oscapProfileInfo.openscap?.profile_description}
</TextList> </TextListItem>
<TextList component={TextListVariants.dl}> component={TextListVariants.dl}
<TextListItem <TextListItem
component={TextListItemVariants.dt} component={TextListItemVariants.dt}
className="pf-u-min-width" className="pf-u-min-width"
> >
Operating system: Operating system:
</TextListItem> </TextListItem>
<TextListItem component={TextListItemVariants.dd}> <TextListItem component={TextListItemVariants.dd}>
{RELEASES.get(release)} {RELEASES.get(release)}
</TextListItem> </TextListItem>
</TextList> component={TextListVariants.dl}
<TextList component={TextListVariants.dl}> <TextListItem
<TextListItem component={TextListItemVariants.dt}
component={TextListItemVariants.dt} className="pf-u-min-width"
className="pf-u-min-width" >
> Reference ID:
Reference ID: </TextListItem>
</TextListItem> <TextListItem component={TextListItemVariants.dd}>
<TextListItem component={TextListItemVariants.dd}> {oscapProfileInfo.openscap?.profile_id}
{oscapProfileInfo.openscap?.profile_id} </TextListItem>
</TextListItem> <TextListItem
</TextList> component={TextListItemVariants.dt}
</TextContent> className="pf-u-min-width"
>
Kernel arguments:
</TextListItem>
<TextListItem component={TextListItemVariants.dd}>
<CodeBlock>
<CodeBlockCode>
{oscapProfileInfo?.kernel?.append}
</CodeBlockCode>
</CodeBlock>
</TextListItem>
<TextListItem
component={TextListItemVariants.dt}
className="pf-u-min-width"
>
Disabled services:
</TextListItem>
<TextListItem component={TextListItemVariants.dd}>
<CodeBlock>
<CodeBlockCode>{disableServicesDisplayString}</CodeBlockCode>
</CodeBlock>
</TextListItem>
<TextListItem
component={TextListItemVariants.dt}
className="pf-u-min-width"
>
Enabled services:
</TextListItem>
<TextListItem component={TextListItemVariants.dd}>
<CodeBlock>
<CodeBlockCode>{enabledServicesDisplayString}</CodeBlockCode>
</CodeBlock>
</TextListItem>
</TextList>
</TextContent>
<Alert
variant="info"
isInline
isPlain
title="Additional customizations"
>
Selecting an OpenSCAP profile will cause the appropriate packages,
file system configuration, kernel arguments, and services to be
added to your image.
</Alert>
</>
)} )}
</> </>
); );

View file

@ -30,7 +30,6 @@ import {
} from '../../../../constants'; } from '../../../../constants';
import { extractProvisioningList } from '../../../../store/helpers'; import { extractProvisioningList } from '../../../../store/helpers';
import { useAppSelector } from '../../../../store/hooks'; import { useAppSelector } from '../../../../store/hooks';
import { useGetOscapCustomizationsQuery } from '../../../../store/imageBuilderApi';
import { useGetSourceListQuery } from '../../../../store/provisioningApi'; import { useGetSourceListQuery } from '../../../../store/provisioningApi';
import { useShowActivationKeyQuery } from '../../../../store/rhsmApi'; import { useShowActivationKeyQuery } from '../../../../store/rhsmApi';
import { import {
@ -45,12 +44,12 @@ import {
selectGcpAccountType, selectGcpAccountType,
selectGcpEmail, selectGcpEmail,
selectGcpShareMethod, selectGcpShareMethod,
selectProfile,
selectRegistrationType, selectRegistrationType,
} from '../../../../store/wizardSlice'; } from '../../../../store/wizardSlice';
import { toMonthAndYear } from '../../../../Utilities/time'; import { toMonthAndYear } from '../../../../Utilities/time';
import { useGetEnvironment } from '../../../../Utilities/useGetEnvironment'; import { useGetEnvironment } from '../../../../Utilities/useGetEnvironment';
import { MajorReleasesLifecyclesChart } from '../../../CreateImageWizard/formComponents/ReleaseLifecycle'; import { MajorReleasesLifecyclesChart } from '../../../CreateImageWizard/formComponents/ReleaseLifecycle';
import OscapProfileInformation from '../Oscap/OscapProfileInformation';
const ExpirationWarning = () => { const ExpirationWarning = () => {
return ( return (
@ -501,54 +500,5 @@ export const ImageDetailsList = () => {
}; };
export const OscapList = () => { export const OscapList = () => {
const oscapProfile = useAppSelector((state) => selectProfile(state)); return <OscapProfileInformation />;
const release = useAppSelector((state) => selectDistribution(state));
const { data } = useGetOscapCustomizationsQuery(
{
distribution: release,
// @ts-ignore if oscapProfile is undefined the query is going to get skipped, so it's safe here to ignore the linter here
profile: oscapProfile,
},
{
skip: !oscapProfile,
}
);
return (
<TextContent>
<TextList component={TextListVariants.dl}>
<TextListItem
component={TextListItemVariants.dt}
className="pf-u-min-width"
>
Profile name:
</TextListItem>
<TextListItem component={TextListItemVariants.dd}>
{data?.openscap?.profile_name}
</TextListItem>
</TextList>
<TextList component={TextListVariants.dl}>
<TextListItem
component={TextListItemVariants.dt}
className="pf-u-min-width"
>
Profile description:
</TextListItem>
<TextListItem component={TextListItemVariants.dd}>
{data?.openscap?.profile_description}
</TextListItem>
</TextList>
<TextList component={TextListVariants.dl}>
<TextListItem
component={TextListItemVariants.dt}
className="pf-u-min-width"
>
Reference ID:
</TextListItem>
<TextListItem component={TextListItemVariants.dd}>
{oscapProfile}
</TextListItem>
</TextList>
<br />
</TextContent>
);
}; };

View file

@ -45,7 +45,15 @@ type wizardState = {
}; };
openScap: { openScap: {
profile: DistributionProfileItem | undefined; profile: DistributionProfileItem | undefined;
kernel: {
kernelAppend: string | undefined;
};
services: {
disabled: string[] | undefined;
enabled: string[] | undefined;
};
}; };
repositories: { repositories: {
customRepositories: CustomRepository[]; customRepositories: CustomRepository[];
}; };
@ -79,6 +87,13 @@ const initialState: wizardState = {
}, },
openScap: { openScap: {
profile: undefined, profile: undefined,
kernel: {
kernelAppend: '',
},
services: {
disabled: [],
enabled: [],
},
}, },
repositories: { repositories: {
customRepositories: [], customRepositories: [],
@ -147,6 +162,18 @@ export const selectProfile = (state: RootState) => {
return state.wizard.openScap.profile; return state.wizard.openScap.profile;
}; };
export const selectKernel = (state: RootState) => {
return state.wizard.openScap.kernel.kernelAppend;
};
export const selectDisabledServices = (state: RootState) => {
return state.wizard.openScap.services.disabled;
};
export const selectEnabledServices = (state: RootState) => {
return state.wizard.openScap.services.enabled;
};
export const selectCustomRepositories = (state: RootState) => { export const selectCustomRepositories = (state: RootState) => {
return state.wizard.repositories.customRepositories; return state.wizard.repositories.customRepositories;
}; };
@ -238,6 +265,22 @@ export const wizardSlice = createSlice({
) => { ) => {
state.openScap.profile = action.payload; state.openScap.profile = action.payload;
}, },
changeKernel: (state, action: PayloadAction<string | undefined>) => {
state.openScap.kernel.kernelAppend = action.payload;
},
changeDisabledServices: (
state,
action: PayloadAction<string[] | undefined>
) => {
state.openScap.services.disabled = action.payload;
},
changeEnabledServices: (
state,
action: PayloadAction<string[] | undefined>
) => {
state.openScap.services.enabled = action.payload;
},
changeCustomRepositories: ( changeCustomRepositories: (
state, state,
action: PayloadAction<CustomRepository[]> action: PayloadAction<CustomRepository[]>
@ -271,6 +314,9 @@ export const {
changeRegistrationType, changeRegistrationType,
changeActivationKey, changeActivationKey,
changeOscapProfile, changeOscapProfile,
changeKernel,
changeDisabledServices,
changeEnabledServices,
changeCustomRepositories, changeCustomRepositories,
changeBlueprintName, changeBlueprintName,
changeBlueprintDescription, changeBlueprintDescription,

View file

@ -154,6 +154,13 @@ describe('Step Compliance', () => {
/cis red hat enterprise linux 8 benchmark for level 1 - workstation/i /cis red hat enterprise linux 8 benchmark for level 1 - workstation/i
) )
); );
await screen.findByText(/kernel arguments:/i);
await screen.findByText(/audit_backlog_limit=8192 audit=1/i);
await screen.findByText(/disabled services:/i);
await screen.findByText(/nfs-server/i);
await screen.findByText(/enabled services:/i);
await screen.findByText(/crond/i);
// check that the FSC contains a /tmp partition // check that the FSC contains a /tmp partition
await clickNext(); await clickNext();
// await screen.findByRole('heading', { name: /File system configuration/i }); // await screen.findByRole('heading', { name: /File system configuration/i });

View file

@ -32,6 +32,13 @@ export const oscapCustomizations = (
'nftables', 'nftables',
'libselinux', 'libselinux',
], ],
kernel: {
append: 'audit_backlog_limit=8192 audit=1',
},
services: {
disabled: ['nfs-server'],
enabled: ['crond'],
},
}; };
} }
if (profile === 'xccdf_org.ssgproject.content_profile_cis_workstation_l2') { if (profile === 'xccdf_org.ssgproject.content_profile_cis_workstation_l2') {
@ -52,6 +59,13 @@ export const oscapCustomizations = (
'nftables', 'nftables',
'libselinux', 'libselinux',
], ],
kernel: {
append: 'audit_backlog_limit=8192 audit=1',
},
services: {
disabled: ['nfs-server', 'nftables'],
enabled: ['crond', 'firewalld'],
},
}; };
} }
return { return {
@ -70,5 +84,12 @@ export const oscapCustomizations = (
'nftables', 'nftables',
'libselinux', 'libselinux',
], ],
kernel: {
append: 'audit_backlog_limit=8192 audit=1',
},
services: {
disabled: ['nfs-server', 'rpcbind', 'autofs', 'nftables'],
enabled: ['crond', 'firewalld', 'systemd-journald', 'rsyslog', 'auditd'],
},
}; };
}; };