Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions central/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,16 @@ func main() {
devmode.StartOnDevBuilds("central")

log.Infof("Running StackRox Version: %s", pkgVersion.GetMainVersion())
// TODO: ROX-12750 update with new list of replaced/deprecated resources
log.Warn("The following permission resources have been replaced:\n" +
" Access replaces AuthProvider, Group, Licenses, and User\n" +
" DeploymentExtension replaces Indicator, NetworkBaseline, ProcessWhitelist, and Risk\n" +
" Integration replaces APIToken, BackupPlugins, ImageIntegration, Notifier, and SignatureIntegration\n" +
" Image now also covers ImageComponent\n" +
"The following permission resources will be replaced in the upcoming versions:\n" +
" Administration will replace AllComments, Config, DebugLogs, NetworkGraphConfig, ProbeUpload, ScannerBundle, ScannerDefinitions, SensorUpgradeConfig, and ServiceIdentity\n" +
" Compliance will replace ComplianceRuns\n" +
" Cluster will cover ClusterCVE.")
ensureDB(ctx)

// Need to remove the backup clone and set the current version
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ describe('Access Control Permission sets', () => {
$tds.get().forEach((td) => {
const resource = td.textContent;
// TODO: ROX-12750 Rename DebugLogs to Administration
if (resource === 'DebugLogs') {
if (resource.includes('DebugLogs')) {
cy.get(getReadAccessIconForResource(resource)).should(
'have.attr',
'aria-label',
Expand Down Expand Up @@ -209,7 +209,7 @@ describe('Access Control Permission sets', () => {

$tds.get().forEach((td) => {
const resource = td.textContent;
if (!resourcesLimited.includes(resource)) {
if (!resourcesLimited.some((v) => resource.includes(v))) {
cy.get(getReadAccessIconForResource(resource)).should(
'have.attr',
'aria-label',
Expand Down Expand Up @@ -315,7 +315,7 @@ describe('Access Control Permission sets', () => {

$tds.get().forEach((td) => {
const resource = td.textContent;
if (!resourcesLimited.includes(resource)) {
if (!resourcesLimited.some((v) => resource.includes(v))) {
cy.get(getReadAccessIconForResource(resource)).should(
'have.attr',
'aria-label',
Expand Down
55 changes: 53 additions & 2 deletions ui/apps/platform/src/Containers/AccessControl/AccessControl.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Redirect, Route, Switch } from 'react-router-dom';

import usePermissions from 'hooks/usePermissions';

import { Alert, List, ListItem } from '@patternfly/react-core';
import { accessControlBasePath, accessControlPath, getEntityPath } from './accessControlPaths';

import AccessControlNoPermission from './AccessControlNoPermission';
Expand All @@ -18,11 +19,61 @@ function AccessControl(): ReactElement {
// TODO is read access required for all routes in improved Access Control?
// TODO Is write access required anywhere in classic Access Control?
const { hasReadAccess } = usePermissions();
const hasReadAccessForAuthProvider = hasReadAccess('Access');
const hasReadAccessForAccessControlPages = hasReadAccess('Access');

return (
<>
{hasReadAccessForAuthProvider ? (
<Alert
isInline
variant="warning"
title={
<>
<p>The following permission resources have been replaced:</p>
<List>
<ListItem>
<b>Access</b> replaces{' '}
<b>AuthProvider, Group, Licenses, and User</b>
</ListItem>
<ListItem>
<b>DeploymentExtension</b> replaces{' '}
<b>Indicator, NetworkBaseline, ProcessWhitelist, and Risk</b>
</ListItem>
<ListItem>
<b>Integration</b> replaces{' '}
<b>
APIToken, BackupPlugins, ImageIntegration, Notifier, and
SignatureIntegration
</b>
</ListItem>
<ListItem>
<b>Image</b> now also covers <b>ImageComponent</b>
</ListItem>
</List>

<p>
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe a list for readability?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I try to use a list within this Alert component, it does not show up as a list. Wanted to ask @pedrottimark or @vjwilson if they know what might be the reason for this behaviour.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I try to use a list within this Alert component, it does not show up as a list. Wanted to ask @pedrottimark or @vjwilson if they know what might be the reason for this behaviour.

There were were pretty strict style resets in pre-Red Hat style sheet, and we can't remove them until all the old style pages have been updated. We'd probably need to add a specific override in this file until then, to make a list show in this component.

https://github.com/stackrox/stackrox/blob/master/ui/apps/platform/src/css/trumps.css

The following permission resources will be replaced in the upcoming
versions:
</p>
<List>
<ListItem>
<b>Administration</b> will replace{' '}
<b>
AllComments, Config, DebugLogs, NetworkGraphConfig, ProbeUpload,
ScannerBundle, ScannerDefinitions, SensorUpgradeConfig, and
ServiceIdentity
</b>
</ListItem>
<ListItem>
<b>Compliance</b> will replace <b>ComplianceRuns</b>
</ListItem>
<ListItem>
<b>Cluster</b> will cover <b>ClusterCVE</b>
</ListItem>
</List>
</>
}
/>
{hasReadAccessForAccessControlPages ? (
<Switch>
<Route exact path={accessControlBasePath}>
<Redirect to={getEntityPath('AUTH_PROVIDER')} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,14 @@ import { PermissionsMap } from 'services/RolesService';

import { ReadAccessIcon, WriteAccessIcon } from './AccessIcons';
import { getReadAccessCount, getWriteAccessCount } from './permissionSets.utils';
import ResourceDescription from './ResourceDescription';
import { ResourceDescription } from './ResourceDescription';
import {
replacedResourceMapping,
resourceRemovalReleaseVersions,
resourceSubstitutions,
deprecatedResourceRowStyle,
} from '../../../constants/accessControl';
import { ResourceName } from '../../../types/roleResources';

export type PermissionsTableProps = {
resourceToAccess: PermissionsMap;
Expand Down Expand Up @@ -51,8 +58,41 @@ function PermissionsTable({
</Thead>
<Tbody>
{resourceToAccessEntries.map(([resource, accessLevel]) => (
<Tr key={resource}>
<Td dataLabel="Resource">{resource}</Td>
<Tr
key={resource}
style={
resourceRemovalReleaseVersions.has(resource as ResourceName)
? deprecatedResourceRowStyle
: {}
}
>
<Td dataLabel="Resource">
<p>{resource}</p>
<p style={{ fontStyle: 'italic' }}>
{resourceSubstitutions[resource] && (
<>Replaces {resourceSubstitutions[resource].join(', ')}</>
)}
</p>
<p style={{ fontStyle: 'italic' }}>
{resourceRemovalReleaseVersions.has(resource as ResourceName) && (
<>
Will be removed in{' '}
{resourceRemovalReleaseVersions.get(
resource as ResourceName
)}
.
</>
)}
</p>
<p style={{ fontStyle: 'italic' }}>
{replacedResourceMapping.has(resource as ResourceName) && (
<>
Will be replaced by{' '}
{replacedResourceMapping.get(resource as ResourceName)}.
</>
)}
</p>
</Td>
<Td dataLabel="Description">
<ResourceDescription resource={resource} />
</Td>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const resourceDescriptions: Record<ResourceName, string> = {
Alert: 'Read: View policy violations. Write: Resolve or edit policy violations.',
CVE: 'Internal use only',
Cluster: 'Read: View secured clusters. Write: Add, modify, or delete secured clusters.',
ClusterCVE: 'Internal use only',
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have to add it within the UI as a new resource? I know we have other resources that are being leaked to the UI that are for internal use only, but why add another one?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ClusterCVE is returned as a resource from the backend, this change just makes sure it's description is not empty

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. It's unfortunate that we return it then in the first place, I suppose such is life then for the internal resources.

Compliance:
'Read: View compliance standards, results, and runs. Write: Add, modify, or delete scheduled compliance runs.',
Deployment: 'Read: View deployments (workloads) in secured clusters. Write: N/A',
Expand Down Expand Up @@ -72,7 +73,7 @@ export type ResourceDescriptionProps = {
resource: string;
};

function ResourceDescription({ resource }: ResourceDescriptionProps): ReactElement {
export function ResourceDescription({ resource }: ResourceDescriptionProps): ReactElement {
// The description becomes the prop for possible future request from backend.
const description = resourceDescriptions[resource] ?? '';
const readIndex = description.indexOf('Read: ');
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React, { ReactElement } from 'react';
import {
Alert,
AlertVariant,
Divider,
PageSection,
PageSectionVariants,
Title,
} from '@patternfly/react-core';

function IntegrationsNoPermission(): ReactElement {
return (
<>
<PageSection variant="light">
<Title headingLevel="h1">Integrations</Title>
</PageSection>
<Divider component="div" />
<PageSection variant={PageSectionVariants.light}>
<Alert
className="pf-u-mt-md"
title="You do not have permission to view Integrations"
variant={AlertVariant.info}
isInline
/>
</PageSection>
</>
);
}

export default IntegrationsNoPermission;
32 changes: 22 additions & 10 deletions ui/apps/platform/src/Containers/Integrations/IntegrationsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,28 @@ import IntegrationsListPage from './IntegrationsListPage';
import CreateIntegrationPage from './CreateIntegrationPage';
import EditIntegrationPage from './EditIntegrationPage';
import IntegrationDetailsPage from './IntegrationDetailsPage';
import usePermissions from '../../hooks/usePermissions';
import IntegrationsNoPermission from './IntegrationsNoPermission';

const Page = (): ReactElement => (
<Switch>
<Route exact path={integrationsPath} component={IntegrationTilesPage} />
<Route exact path={integrationsListPath} component={IntegrationsListPage} />
<Route path={integrationCreatePath} component={CreateIntegrationPage} />
<Route path={integrationEditPath} component={EditIntegrationPage} />
<Route path={integrationDetailsPath} component={IntegrationDetailsPage} />
<Route component={IntegrationsNotFoundPage} />
</Switch>
);
const Page = (): ReactElement => {
const { hasReadAccess } = usePermissions();
const hasReadAccessForIntegrations = hasReadAccess('Integration');
return (
<>
{hasReadAccessForIntegrations ? (
<Switch>
<Route exact path={integrationsPath} component={IntegrationTilesPage} />
<Route exact path={integrationsListPath} component={IntegrationsListPage} />
<Route path={integrationCreatePath} component={CreateIntegrationPage} />
<Route path={integrationEditPath} component={EditIntegrationPage} />
<Route path={integrationDetailsPath} component={IntegrationDetailsPage} />
<Route component={IntegrationsNotFoundPage} />
</Switch>
) : (
<IntegrationsNoPermission />
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What’s done is done. Was this a broken page which requires this change just before release?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

)}
</>
);
};

export default Page;
14 changes: 13 additions & 1 deletion ui/apps/platform/src/Containers/User/UserPermissionsTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ import {
ReadAccessIcon,
WriteAccessIcon,
} from 'Containers/AccessControl/PermissionSets/AccessIcons';
import {
deprecatedResourceRowStyle,
resourceRemovalReleaseVersions,
} from '../../constants/accessControl';
import { ResourceName } from '../../types/roleResources';

export type UserPermissionsTableProps = {
permissions: PermissionsMap;
Expand All @@ -24,7 +29,14 @@ function UserPermissionsTable({ permissions }: UserPermissionsTableProps): React
</Thead>
<Tbody>
{Object.entries(permissions).map(([resource, accessLevel]) => (
<Tr key={resource}>
<Tr
key={resource}
style={
resourceRemovalReleaseVersions.has(resource as ResourceName)
? deprecatedResourceRowStyle
: {}
}
>
<Td key="resourceName" dataLabel="Resource">
{resource}
</Td>
Expand Down
50 changes: 50 additions & 0 deletions ui/apps/platform/src/constants/accessControl.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
/* constants specific to Roles */
import { ResourceName } from '../types/roleResources';

export const NO_ACCESS = 'NO_ACCESS';
export const READ_ACCESS = 'READ_ACCESS';
export const READ_WRITE_ACCESS = 'READ_WRITE_ACCESS';
Expand Down Expand Up @@ -86,3 +88,51 @@ export const defaultSelectedRole = {
name: '',
resourceToAccess: defaultNewRolePermissions,
};

// TODO: ROX-12750 update with new list of replaced/deprecated resources
export const resourceSubstitutions: Record<string, string[]> = {
Access: ['AuthProvider', 'Group', 'Licenses', 'User'],
DeploymentExtension: ['Indicator', 'NetworkBaseline', 'ProcessWhitelist', 'Risk'],
Integration: [
'APIToken',
'BackupPlugins',
'ImageIntegration',
'Notifier',
'SignatureIntegration',
],
Image: ['ImageComponent'],
};

// TODO: ROX-12750 update with new list of replaced/deprecated resources
export const resourceRemovalReleaseVersions = new Map<ResourceName, string>([
['AllComments', '3.75'],
['ComplianceRuns', '3.75'],
['Config', '3.75'],
['DebugLogs', '3.75'],
['NetworkGraphConfig', '3.75'],
['ProbeUpload', '3.75'],
['ScannerBundle', '3.75'],
['ScannerDefinitions', '3.75'],
['SensorUpgradeConfig', '3.75'],
['ServiceIdentity', '3.75'],
['ClusterCVE', '3.74'],
]);

// TODO(ROX-11453): Remove this mapping once the old resources are fully deprecated.
export const replacedResourceMapping = new Map<ResourceName, string>([
// TODO: ROX-12750 Remove AllComments, ComplianceRunSchedule, ComplianceRuns, Config, DebugLogs,
// NetworkGraphConfig, ProbeUpload, ScannerBundle, ScannerDefinitions, SensorUpgradeConfig and ServiceIdentity.
['AllComments', 'Administration'],
['ComplianceRuns', 'Compliance'],
['Config', 'Administration'],
['DebugLogs', 'Administration'],
['NetworkGraphConfig', 'Administration'],
['ProbeUpload', 'Administration'],
['ScannerBundle', 'Administration'],
['ScannerDefinitions', 'Administration'],
['SensorUpgradeConfig', 'Administration'],
['ServiceIdentity', 'Administration'],
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason why ClusterCVE is not in this list?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My understanding was that ClusterCVE will be removed and not replaced by anything. @rhybrillou is that the case?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@md2119 @theencee

How is ClusterCVE related to this change?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ClusterCVE -> Cluster

['ClusterCVE', 'Cluster'],
]);

export const deprecatedResourceRowStyle = { backgroundColor: 'rgb(255,250,205)' };
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We will follow up with a PatternFly variable if explicit color does not work for dark mode

17 changes: 1 addition & 16 deletions ui/apps/platform/src/hooks/usePermissions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { createStructuredSelector } from 'reselect';
import { selectors } from 'reducers';
import { Access } from 'types/role.proto';
import { ResourceName } from 'types/roleResources';
import { replacedResourceMapping } from 'constants/accessControl';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


export type HasNoAccess = (resourceName: ResourceName) => boolean;
export type HasReadAccess = (resourceName: ResourceName) => boolean;
Expand All @@ -24,22 +25,6 @@ const stateSelector = createStructuredSelector<{
isLoadingPermissions: selectors.getIsLoadingUserRolePermissions,
});

// TODO(ROX-11453): Remove this mapping once the old resources are fully deprecated.
const replacedResourceMapping = new Map<ResourceName, string>([
// TODO: ROX-12750 Remove AllComments, ComplianceRunSchedule, ComplianceRuns, Config, DebugLogs,
// NetworkGraphConfig, ProbeUpload, ScannerBundle, ScannerDefinitions, SensorUpgradeConfig and ServiceIdentity.
['AllComments', 'Administration'],
['ComplianceRuns', 'Compliance'],
['Config', 'Administration'],
['DebugLogs', 'Administration'],
['NetworkGraphConfig', 'Administration'],
['ProbeUpload', 'Administration'],
['ScannerBundle', 'Administration'],
['ScannerDefinitions', 'Administration'],
['SensorUpgradeConfig', 'Administration'],
['ServiceIdentity', 'Administration'],
]);

const usePermissions = (): UsePermissionsResponse => {
const { userRolePermissions, isLoadingPermissions } = useSelector(stateSelector);

Expand Down
Loading