diff --git a/deepfence_frontend/apps/dashboard/api-spec.json b/deepfence_frontend/apps/dashboard/api-spec.json index 3d4d644b2c..fcd062a70c 100644 --- a/deepfence_frontend/apps/dashboard/api-spec.json +++ b/deepfence_frontend/apps/dashboard/api-spec.json @@ -11488,7 +11488,7 @@ "application/json": { "schema": { "type": "array", - "items": { "$ref": "#/components/schemas/ModelSettingsResponse" } + "items": { "$ref": "#/components/schemas/SettingSettingsResponse" } } } } @@ -11540,7 +11540,7 @@ "requestBody": { "content": { "application/json": { - "schema": { "$ref": "#/components/schemas/ModelSettingUpdateRequest" } + "schema": { "$ref": "#/components/schemas/SettingSettingUpdateRequest" } } } }, @@ -15516,28 +15516,6 @@ } } }, - "ModelSettingUpdateRequest": { - "required": ["key", "value"], - "type": "object", - "properties": { - "key": { - "enum": ["console_url", "file_server_url", "inactive_delete_scan_results"], - "type": "string" - }, - "value": { "type": "string" } - } - }, - "ModelSettingsResponse": { - "required": ["id", "key", "label", "value", "description"], - "type": "object", - "properties": { - "description": { "type": "string" }, - "id": { "type": "integer" }, - "key": { "type": "string" }, - "label": { "type": "string" }, - "value": {} - } - }, "ModelStopScanRequest": { "required": ["scan_ids", "scan_type"], "type": "object", @@ -16157,6 +16135,28 @@ "window": { "$ref": "#/components/schemas/ModelFetchWindow" } } }, + "SettingSettingUpdateRequest": { + "required": ["key", "value"], + "type": "object", + "properties": { + "key": { + "enum": ["console_url", "file_server_url", "inactive_delete_scan_results"], + "type": "string" + }, + "value": { "type": "string" } + } + }, + "SettingSettingsResponse": { + "required": ["id", "key", "label", "value", "description"], + "type": "object", + "properties": { + "description": { "type": "string" }, + "id": { "type": "integer" }, + "key": { "type": "string" }, + "label": { "type": "string" }, + "value": {} + } + }, "SqlNullTime": { "type": "object" }, "UtilsAdvancedReportFilters": { "type": "object", diff --git a/deepfence_frontend/apps/dashboard/src/api/generated/.openapi-generator/FILES b/deepfence_frontend/apps/dashboard/src/api/generated/.openapi-generator/FILES index 3d78d6a659..235b55e07c 100644 --- a/deepfence_frontend/apps/dashboard/src/api/generated/.openapi-generator/FILES +++ b/deepfence_frontend/apps/dashboard/src/api/generated/.openapi-generator/FILES @@ -198,8 +198,6 @@ models/ModelSecretRule.ts models/ModelSecretScanResult.ts models/ModelSecretScanResultRules.ts models/ModelSecretScanTriggerReq.ts -models/ModelSettingUpdateRequest.ts -models/ModelSettingsResponse.ts models/ModelStopScanRequest.ts models/ModelSummary.ts models/ModelTopologyDeltaReq.ts @@ -233,6 +231,8 @@ models/SearchSearchCountResp.ts models/SearchSearchFilter.ts models/SearchSearchNodeReq.ts models/SearchSearchScanReq.ts +models/SettingSettingUpdateRequest.ts +models/SettingSettingsResponse.ts models/UtilsAdvancedReportFilters.ts models/UtilsReportFilters.ts models/UtilsReportOptions.ts diff --git a/deepfence_frontend/apps/dashboard/src/api/generated/apis/SettingsApi.ts b/deepfence_frontend/apps/dashboard/src/api/generated/apis/SettingsApi.ts index dd08a1d9ae..68679116ab 100644 --- a/deepfence_frontend/apps/dashboard/src/api/generated/apis/SettingsApi.ts +++ b/deepfence_frontend/apps/dashboard/src/api/generated/apis/SettingsApi.ts @@ -29,12 +29,12 @@ import type { ModelMessageResponse, ModelRegisterLicenseRequest, ModelRegisterLicenseResponse, - ModelSettingUpdateRequest, - ModelSettingsResponse, ModelUpdateScheduledTaskRequest, PostgresqlDbGetAuditLogsRow, PostgresqlDbScheduler, SearchSearchCountResp, + SettingSettingUpdateRequest, + SettingSettingsResponse, } from '../models'; import { ApiDocsBadRequestResponseFromJSON, @@ -65,10 +65,6 @@ import { ModelRegisterLicenseRequestToJSON, ModelRegisterLicenseResponseFromJSON, ModelRegisterLicenseResponseToJSON, - ModelSettingUpdateRequestFromJSON, - ModelSettingUpdateRequestToJSON, - ModelSettingsResponseFromJSON, - ModelSettingsResponseToJSON, ModelUpdateScheduledTaskRequestFromJSON, ModelUpdateScheduledTaskRequestToJSON, PostgresqlDbGetAuditLogsRowFromJSON, @@ -77,6 +73,10 @@ import { PostgresqlDbSchedulerToJSON, SearchSearchCountRespFromJSON, SearchSearchCountRespToJSON, + SettingSettingUpdateRequestFromJSON, + SettingSettingUpdateRequestToJSON, + SettingSettingsResponseFromJSON, + SettingSettingsResponseToJSON, } from '../models'; export interface AddEmailConfigurationRequest { @@ -118,7 +118,7 @@ export interface UpdateScheduledTaskRequest { export interface UpdateSettingRequest { id: number; - modelSettingUpdateRequest?: ModelSettingUpdateRequest; + settingSettingUpdateRequest?: SettingSettingUpdateRequest; } export interface UploadAgentVersionRequest { @@ -325,13 +325,13 @@ export interface SettingsApiInterface { * @throws {RequiredError} * @memberof SettingsApiInterface */ - getSettingsRaw(initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise>>; + getSettingsRaw(initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise>>; /** * Get all settings * Get settings */ - getSettings(initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise>; + getSettings(initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise>; /** * Get audit logs for all users @@ -432,7 +432,7 @@ export interface SettingsApiInterface { * Update setting * @summary Update setting * @param {number} id - * @param {ModelSettingUpdateRequest} [modelSettingUpdateRequest] + * @param {SettingSettingUpdateRequest} [settingSettingUpdateRequest] * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof SettingsApiInterface @@ -945,7 +945,7 @@ export class SettingsApi extends runtime.BaseAPI implements SettingsApiInterface * Get all settings * Get settings */ - async getSettingsRaw(initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise>> { + async getSettingsRaw(initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise>> { const queryParameters: any = {}; const headerParameters: runtime.HTTPHeaders = {}; @@ -965,14 +965,14 @@ export class SettingsApi extends runtime.BaseAPI implements SettingsApiInterface query: queryParameters, }, initOverrides); - return new runtime.JSONApiResponse(response, (jsonValue) => jsonValue.map(ModelSettingsResponseFromJSON)); + return new runtime.JSONApiResponse(response, (jsonValue) => jsonValue.map(SettingSettingsResponseFromJSON)); } /** * Get all settings * Get settings */ - async getSettings(initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise> { + async getSettings(initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise> { const response = await this.getSettingsRaw(initOverrides); return await response.value(); } @@ -1236,7 +1236,7 @@ export class SettingsApi extends runtime.BaseAPI implements SettingsApiInterface method: 'PATCH', headers: headerParameters, query: queryParameters, - body: ModelSettingUpdateRequestToJSON(requestParameters.modelSettingUpdateRequest), + body: SettingSettingUpdateRequestToJSON(requestParameters.settingSettingUpdateRequest), }, initOverrides); return new runtime.VoidApiResponse(response); diff --git a/deepfence_frontend/apps/dashboard/src/api/generated/models/ModelSettingUpdateRequest.ts b/deepfence_frontend/apps/dashboard/src/api/generated/models/SettingSettingUpdateRequest.ts similarity index 64% rename from deepfence_frontend/apps/dashboard/src/api/generated/models/ModelSettingUpdateRequest.ts rename to deepfence_frontend/apps/dashboard/src/api/generated/models/SettingSettingUpdateRequest.ts index 9df16f3603..58a4a75920 100644 --- a/deepfence_frontend/apps/dashboard/src/api/generated/models/ModelSettingUpdateRequest.ts +++ b/deepfence_frontend/apps/dashboard/src/api/generated/models/SettingSettingUpdateRequest.ts @@ -16,19 +16,19 @@ import { exists, mapValues } from '../runtime'; /** * * @export - * @interface ModelSettingUpdateRequest + * @interface SettingSettingUpdateRequest */ -export interface ModelSettingUpdateRequest { +export interface SettingSettingUpdateRequest { /** * * @type {string} - * @memberof ModelSettingUpdateRequest + * @memberof SettingSettingUpdateRequest */ - key: ModelSettingUpdateRequestKeyEnum; + key: SettingSettingUpdateRequestKeyEnum; /** * * @type {string} - * @memberof ModelSettingUpdateRequest + * @memberof SettingSettingUpdateRequest */ value: string; } @@ -37,18 +37,18 @@ export interface ModelSettingUpdateRequest { /** * @export */ -export const ModelSettingUpdateRequestKeyEnum = { +export const SettingSettingUpdateRequestKeyEnum = { ConsoleUrl: 'console_url', FileServerUrl: 'file_server_url', InactiveDeleteScanResults: 'inactive_delete_scan_results' } as const; -export type ModelSettingUpdateRequestKeyEnum = typeof ModelSettingUpdateRequestKeyEnum[keyof typeof ModelSettingUpdateRequestKeyEnum]; +export type SettingSettingUpdateRequestKeyEnum = typeof SettingSettingUpdateRequestKeyEnum[keyof typeof SettingSettingUpdateRequestKeyEnum]; /** - * Check if a given object implements the ModelSettingUpdateRequest interface. + * Check if a given object implements the SettingSettingUpdateRequest interface. */ -export function instanceOfModelSettingUpdateRequest(value: object): boolean { +export function instanceOfSettingSettingUpdateRequest(value: object): boolean { let isInstance = true; isInstance = isInstance && "key" in value; isInstance = isInstance && "value" in value; @@ -56,11 +56,11 @@ export function instanceOfModelSettingUpdateRequest(value: object): boolean { return isInstance; } -export function ModelSettingUpdateRequestFromJSON(json: any): ModelSettingUpdateRequest { - return ModelSettingUpdateRequestFromJSONTyped(json, false); +export function SettingSettingUpdateRequestFromJSON(json: any): SettingSettingUpdateRequest { + return SettingSettingUpdateRequestFromJSONTyped(json, false); } -export function ModelSettingUpdateRequestFromJSONTyped(json: any, ignoreDiscriminator: boolean): ModelSettingUpdateRequest { +export function SettingSettingUpdateRequestFromJSONTyped(json: any, ignoreDiscriminator: boolean): SettingSettingUpdateRequest { if ((json === undefined) || (json === null)) { return json; } @@ -71,7 +71,7 @@ export function ModelSettingUpdateRequestFromJSONTyped(json: any, ignoreDiscrimi }; } -export function ModelSettingUpdateRequestToJSON(value?: ModelSettingUpdateRequest | null): any { +export function SettingSettingUpdateRequestToJSON(value?: SettingSettingUpdateRequest | null): any { if (value === undefined) { return undefined; } diff --git a/deepfence_frontend/apps/dashboard/src/api/generated/models/ModelSettingsResponse.ts b/deepfence_frontend/apps/dashboard/src/api/generated/models/SettingSettingsResponse.ts similarity index 72% rename from deepfence_frontend/apps/dashboard/src/api/generated/models/ModelSettingsResponse.ts rename to deepfence_frontend/apps/dashboard/src/api/generated/models/SettingSettingsResponse.ts index 8190aece9d..70b6f6f0dc 100644 --- a/deepfence_frontend/apps/dashboard/src/api/generated/models/ModelSettingsResponse.ts +++ b/deepfence_frontend/apps/dashboard/src/api/generated/models/SettingSettingsResponse.ts @@ -16,45 +16,45 @@ import { exists, mapValues } from '../runtime'; /** * * @export - * @interface ModelSettingsResponse + * @interface SettingSettingsResponse */ -export interface ModelSettingsResponse { +export interface SettingSettingsResponse { /** * * @type {string} - * @memberof ModelSettingsResponse + * @memberof SettingSettingsResponse */ description: string; /** * * @type {number} - * @memberof ModelSettingsResponse + * @memberof SettingSettingsResponse */ id: number; /** * * @type {string} - * @memberof ModelSettingsResponse + * @memberof SettingSettingsResponse */ key: string; /** * * @type {string} - * @memberof ModelSettingsResponse + * @memberof SettingSettingsResponse */ label: string; /** * * @type {any} - * @memberof ModelSettingsResponse + * @memberof SettingSettingsResponse */ value: any | null; } /** - * Check if a given object implements the ModelSettingsResponse interface. + * Check if a given object implements the SettingSettingsResponse interface. */ -export function instanceOfModelSettingsResponse(value: object): boolean { +export function instanceOfSettingSettingsResponse(value: object): boolean { let isInstance = true; isInstance = isInstance && "description" in value; isInstance = isInstance && "id" in value; @@ -65,11 +65,11 @@ export function instanceOfModelSettingsResponse(value: object): boolean { return isInstance; } -export function ModelSettingsResponseFromJSON(json: any): ModelSettingsResponse { - return ModelSettingsResponseFromJSONTyped(json, false); +export function SettingSettingsResponseFromJSON(json: any): SettingSettingsResponse { + return SettingSettingsResponseFromJSONTyped(json, false); } -export function ModelSettingsResponseFromJSONTyped(json: any, ignoreDiscriminator: boolean): ModelSettingsResponse { +export function SettingSettingsResponseFromJSONTyped(json: any, ignoreDiscriminator: boolean): SettingSettingsResponse { if ((json === undefined) || (json === null)) { return json; } @@ -83,7 +83,7 @@ export function ModelSettingsResponseFromJSONTyped(json: any, ignoreDiscriminato }; } -export function ModelSettingsResponseToJSON(value?: ModelSettingsResponse | null): any { +export function SettingSettingsResponseToJSON(value?: SettingSettingsResponse | null): any { if (value === undefined) { return undefined; } diff --git a/deepfence_frontend/apps/dashboard/src/api/generated/models/index.ts b/deepfence_frontend/apps/dashboard/src/api/generated/models/index.ts index bdb5fbfccf..a333d92699 100644 --- a/deepfence_frontend/apps/dashboard/src/api/generated/models/index.ts +++ b/deepfence_frontend/apps/dashboard/src/api/generated/models/index.ts @@ -172,8 +172,6 @@ export * from './ModelSecretRule'; export * from './ModelSecretScanResult'; export * from './ModelSecretScanResultRules'; export * from './ModelSecretScanTriggerReq'; -export * from './ModelSettingUpdateRequest'; -export * from './ModelSettingsResponse'; export * from './ModelStopScanRequest'; export * from './ModelSummary'; export * from './ModelTopologyDeltaReq'; @@ -207,6 +205,8 @@ export * from './SearchSearchCountResp'; export * from './SearchSearchFilter'; export * from './SearchSearchNodeReq'; export * from './SearchSearchScanReq'; +export * from './SettingSettingUpdateRequest'; +export * from './SettingSettingsResponse'; export * from './UtilsAdvancedReportFilters'; export * from './UtilsReportFilters'; export * from './UtilsReportOptions'; diff --git a/deepfence_frontend/apps/dashboard/src/components/clouds-connector/AzureConnectorForm.tsx b/deepfence_frontend/apps/dashboard/src/components/clouds-connector/AzureConnectorForm.tsx index 38bc022f1b..62bd72dd00 100644 --- a/deepfence_frontend/apps/dashboard/src/components/clouds-connector/AzureConnectorForm.tsx +++ b/deepfence_frontend/apps/dashboard/src/components/clouds-connector/AzureConnectorForm.tsx @@ -20,8 +20,7 @@ export const AzureConnectorForm = () => { title="Terraform" >
- Connect to your Azure Cloud Account via Terraform. Find out more information - by{' '} + Connect to your Microsoft Azure via terraform. Find out more information by{' '} void; onClearAll?: () => void; defaultSelectedAccounts?: string[]; @@ -90,8 +92,10 @@ const SearchableCloudAccounts = ({ : cloudProvider ? displayValue ? displayValue - : `${cloudProvider} account` - : 'Cloud account' + : `${cloudProvider} ${getDisplayNameOfNodeType( + cloudProvider as ModelCloudNodeAccountsListReqCloudProviderEnum, + ).toLowerCase()}` + : 'Cloud' } multiple value={selectedAccounts} @@ -147,8 +151,10 @@ export const SearchableCloudAccountsList = (props: SearchableCloudAccountsListPr return displayValue ? displayValue : cloudProvider - ? `${cloudProvider} account` - : 'Cloud account'; + ? `${cloudProvider} ${getDisplayNameOfNodeType( + cloudProvider as ModelCloudNodeAccountsListReqCloudProviderEnum, + ).toLowerCase()}` + : `Cloud`; }} multiple onQueryChange={() => { diff --git a/deepfence_frontend/apps/dashboard/src/components/icons/posture/index.tsx b/deepfence_frontend/apps/dashboard/src/components/icons/posture/index.tsx index 0cd3daca72..ed470aac5b 100644 --- a/deepfence_frontend/apps/dashboard/src/components/icons/posture/index.tsx +++ b/deepfence_frontend/apps/dashboard/src/components/icons/posture/index.tsx @@ -1,3 +1,4 @@ +import { ModelCloudNodeAccountsListReqCloudProviderEnum } from '@/api/generated'; import { ShieldCheckSolidIcon } from '@/components/icons/posture/ShieldCheckSolid'; import { ShieldWarningSolidIcon } from '@/components/icons/posture/ShieldWarningSolid'; import { ShieldXSolidIcon } from '@/components/icons/posture/ShieldXSolid'; @@ -10,19 +11,21 @@ import { KubernetesIcon } from './Kubernetes'; import { LinuxIcon } from './Linux'; export const PostureLogos = ({ name }: { name: string }) => { - if (name === 'aws') { + if (name === ModelCloudNodeAccountsListReqCloudProviderEnum.Aws) { return ; - } else if (name === 'aws_org') { + } else if (name === ModelCloudNodeAccountsListReqCloudProviderEnum.AwsOrg) { return ; - } else if (name === 'azure') { + } else if (name === ModelCloudNodeAccountsListReqCloudProviderEnum.Azure) { return ; - } else if (name === 'gcp_org') { + } else if (name === ModelCloudNodeAccountsListReqCloudProviderEnum.GcpOrg) { return ; - } else if (name === 'gcp') { + } else if (name === ModelCloudNodeAccountsListReqCloudProviderEnum.AzureOrg) { + return ; + } else if (name === ModelCloudNodeAccountsListReqCloudProviderEnum.Gcp) { return ; - } else if (name === 'kubernetes') { + } else if (name === ModelCloudNodeAccountsListReqCloudProviderEnum.Kubernetes) { return ; - } else if (name === 'linux') { + } else if (name === ModelCloudNodeAccountsListReqCloudProviderEnum.Linux) { return ; } return null; diff --git a/deepfence_frontend/apps/dashboard/src/components/scan-configure-forms/ComplianceScanConfigureForm.tsx b/deepfence_frontend/apps/dashboard/src/components/scan-configure-forms/ComplianceScanConfigureForm.tsx index bcb269537a..daf214a066 100644 --- a/deepfence_frontend/apps/dashboard/src/components/scan-configure-forms/ComplianceScanConfigureForm.tsx +++ b/deepfence_frontend/apps/dashboard/src/components/scan-configure-forms/ComplianceScanConfigureForm.tsx @@ -15,6 +15,7 @@ import { CircleSpinner, createColumnHelper, Switch, Table } from 'ui-components' import { getComplianceApiClient, getSettingsApiClient } from '@/api/api'; import { ModelBenchmarkType, + ModelCloudNodeAccountsListReqCloudProviderEnum, ModelComplianceScanTriggerReq, ModelNodeIdentifierNodeTypeEnum, ModelScanResultsActionRequestScanTypeEnum, @@ -23,8 +24,13 @@ import { ModelCloudNodeComplianceControl } from '@/api/generated/models/ModelClo import { ScheduleScanForm } from '@/components/scan-configure-forms/ScheduleScanForm'; import { TruncatedText } from '@/components/TruncatedText'; import { ActionEnumType } from '@/features/postures/data-component/toggleControlApiAction'; +import { + isCloudNonOrgNode, + isCloudOrgNode, + isNonCloudNode, +} from '@/features/postures/utils'; import { invalidateAllQueries, queries } from '@/queries'; -import { ComplianceScanNodeTypeEnum, isCloudNode, isCloudOrgNode } from '@/types/common'; +import { ComplianceScanNodeTypeEnum } from '@/types/common'; import { get403Message, getResponseErrors } from '@/utils/403'; import { apiWrapper } from '@/utils/api'; import { getBenchmarkPrettyName } from '@/utils/enum'; @@ -52,6 +58,7 @@ export const complianceType: { gcp: [ModelBenchmarkType.Cis], gcp_org: [ModelBenchmarkType.Cis], azure: [ModelBenchmarkType.Cis, ModelBenchmarkType.Nist, ModelBenchmarkType.Hipaa], + azure_org: [ModelBenchmarkType.Cis, ModelBenchmarkType.Nist, ModelBenchmarkType.Hipaa], host: [ ModelBenchmarkType.Hipaa, ModelBenchmarkType.Gdpr, @@ -90,14 +97,6 @@ type TabsType = { value: ModelBenchmarkType; }; -export const CLOUDS = [ - ComplianceScanNodeTypeEnum.aws, - ComplianceScanNodeTypeEnum.aws_org, - ComplianceScanNodeTypeEnum.azure, - ComplianceScanNodeTypeEnum.gcp, - ComplianceScanNodeTypeEnum.gcp_org, -]; - const isKubernetesNode = (nodeType: ComplianceScanNodeTypeEnum) => nodeType == ComplianceScanNodeTypeEnum.kubernetes_cluster; @@ -110,7 +109,8 @@ export const scanPostureApiAction = async ({ let nodeType = body._nodeType.toString(); const checkTypes = body._checkTypes.toString()?.split(',') as Array; - const isCloudScan = CLOUDS.includes(nodeType as ComplianceScanNodeTypeEnum); + const isCloudScan = !isNonCloudNode(nodeType); + if (isKubernetesNode(nodeType as ComplianceScanNodeTypeEnum)) { nodeType = 'cluster'; } else if (isCloudScan) { @@ -333,19 +333,20 @@ const ControlTable = ({ const _nodeType = useMemo(() => { switch (nodeType) { case ComplianceScanNodeTypeEnum.host: - return 'linux'; + return ModelCloudNodeAccountsListReqCloudProviderEnum.Linux; case ComplianceScanNodeTypeEnum.kubernetes_cluster: - return 'kubernetes'; - case ComplianceScanNodeTypeEnum.aws_org: - return ComplianceScanNodeTypeEnum.aws; - case ComplianceScanNodeTypeEnum.gcp_org: - return ComplianceScanNodeTypeEnum.gcp; + return ModelCloudNodeAccountsListReqCloudProviderEnum.Kubernetes; + case ModelCloudNodeAccountsListReqCloudProviderEnum.AwsOrg: + return ModelCloudNodeAccountsListReqCloudProviderEnum.Aws; + case ModelCloudNodeAccountsListReqCloudProviderEnum.GcpOrg: + return ModelCloudNodeAccountsListReqCloudProviderEnum.Gcp; + case ModelCloudNodeAccountsListReqCloudProviderEnum.AzureOrg: + return ModelCloudNodeAccountsListReqCloudProviderEnum.Azure; default: return nodeType; } }, [nodeType]); - const fetcher = useFetcher(); const [pageSize, setPageSize] = useState(10); const { data } = useGetControls({ checkType: selectedTab, @@ -571,7 +572,7 @@ export const ComplianceScanConfigureForm = ({ ) : null} - {!isCloudNode(nodeType) && + {!isCloudNonOrgNode(nodeType) && !isCloudOrgNode(nodeType) && !isKubernetesNode(nodeType) ? (
diff --git a/deepfence_frontend/apps/dashboard/src/features/integrations/components/report-form/AdvanceFilter.tsx b/deepfence_frontend/apps/dashboard/src/features/integrations/components/report-form/AdvanceFilter.tsx index 738388a9f5..7639d34bce 100644 --- a/deepfence_frontend/apps/dashboard/src/features/integrations/components/report-form/AdvanceFilter.tsx +++ b/deepfence_frontend/apps/dashboard/src/features/integrations/components/report-form/AdvanceFilter.tsx @@ -3,6 +3,7 @@ import { useMemo, useState } from 'react'; import { Listbox, ListboxOption } from 'ui-components'; import { + ModelCloudNodeAccountsListReqCloudProviderEnum, UtilsReportFiltersNodeTypeEnum, UtilsReportFiltersScanTypeEnum, } from '@/api/generated'; @@ -11,7 +12,12 @@ import { SearchableClusterList } from '@/components/forms/SearchableClusterList' import { SearchableContainerList } from '@/components/forms/SearchableContainerList'; import { SearchableHostList } from '@/components/forms/SearchableHostList'; import { SearchableImageList } from '@/components/forms/SearchableImageList'; -import { isCloudNode, ScanTypeEnum } from '@/types/common'; +import { + getDisplayNameOfNodeType, + isCloudNonOrgNode, + isCloudOrgNode, +} from '@/features/postures/utils'; +import { ScanTypeEnum } from '@/types/common'; const getNodeTypeByProviderName = (providerName: string): string | undefined => { switch (providerName) { @@ -67,6 +73,10 @@ export const AdvancedFilter = ({ const [images, setImages] = useState([]); const [containers, setContainers] = useState([]); + const isCloudNode = (nodeType: string) => + isCloudNonOrgNode(nodeType as ModelCloudNodeAccountsListReqCloudProviderEnum) || + isCloudOrgNode(nodeType as ModelCloudNodeAccountsListReqCloudProviderEnum); + return ( <> {resourceType && provider ? ( @@ -75,9 +85,11 @@ export const AdvancedFilter = ({
Advanced Filter (Optional)
- {isCloudNode(nodeType) && ( + {nodeType && isCloudNode(nodeType) && ( {
)} - {ACCOUNT_CONNECTOR.AZURE === account && } + {account.startsWith(ACCOUNT_CONNECTOR.AZURE) && } {account.startsWith(ACCOUNT_CONNECTOR.GCP) && } ); diff --git a/deepfence_frontend/apps/dashboard/src/features/postures/pages/Accounts.tsx b/deepfence_frontend/apps/dashboard/src/features/postures/pages/Accounts.tsx index 9118b88f0d..2199285c50 100644 --- a/deepfence_frontend/apps/dashboard/src/features/postures/pages/Accounts.tsx +++ b/deepfence_frontend/apps/dashboard/src/features/postures/pages/Accounts.tsx @@ -37,16 +37,14 @@ import { getCloudNodesApiClient, getScanResultsApiClient } from '@/api/api'; import { ModelBulkDeleteScansRequestScanTypeEnum, ModelCloudNodeAccountInfo, + ModelCloudNodeAccountsListReqCloudProviderEnum, UtilsReportFiltersNodeTypeEnum, UtilsReportFiltersScanTypeEnum, } from '@/api/generated'; import { ConfigureScanModal } from '@/components/ConfigureScanModal'; import { DFLink } from '@/components/DFLink'; import { FilterBadge } from '@/components/filters/FilterBadge'; -import { - ICloudAccountType, - SearchableCloudAccountsList, -} from '@/components/forms/SearchableCloudAccountsList'; +import { SearchableCloudAccountsList } from '@/components/forms/SearchableCloudAccountsList'; import { SearchableClusterList } from '@/components/forms/SearchableClusterList'; import { SearchableHostList } from '@/components/forms/SearchableHostList'; import { ArrowUpCircleLine } from '@/components/icons/common/ArrowUpCircleLine'; @@ -57,10 +55,7 @@ import { PlusIcon } from '@/components/icons/common/Plus'; import { RefreshIcon } from '@/components/icons/common/Refresh'; import { TimesIcon } from '@/components/icons/common/Times'; import { TrashLineIcon } from '@/components/icons/common/TrashLine'; -import { - CLOUDS, - ComplianceScanConfigureFormProps, -} from '@/components/scan-configure-forms/ComplianceScanConfigureForm'; +import { ComplianceScanConfigureFormProps } from '@/components/scan-configure-forms/ComplianceScanConfigureForm'; import { StopScanForm } from '@/components/scan-configure-forms/StopScanForm'; import { ScanStatusBadge } from '@/components/ScanStatusBadge'; import { PostureIcon } from '@/components/sideNavigation/icons/Posture'; @@ -68,19 +63,24 @@ import { getColorForCompliancePercent } from '@/constants/charts'; import { BreadcrumbWrapper } from '@/features/common/BreadcrumbWrapper'; import { useDownloadScan } from '@/features/common/data-component/downloadScanAction'; import { FilterWrapper } from '@/features/common/FilterWrapper'; +import { providersToNameMapping } from '@/features/postures/pages/Posture'; import { - isKubernetesProvider, - isLinuxProvider, - isNonCloudProvider, - providersToNameMapping, -} from '@/features/postures/pages/Posture'; + getDeleteConfirmationDisplayName, + getDisplayNameOfNodeType, + getSearchableCloudAccountDisplayName, + isCloudNonOrgNode, + isCloudOrgNode, + isKubernetesNodeType, + isLinuxNodeType, + isNonCloudNode, +} from '@/features/postures/utils'; import { SuccessModalContent } from '@/features/settings/components/SuccessModalContent'; import { invalidateAllQueries, queries } from '@/queries'; import { useTheme } from '@/theme/ThemeContext'; import { + CloudNodeNonOrgType, + CloudNodeType, ComplianceScanNodeTypeEnum, - isCloudNode, - isCloudOrgNode, ScanTypeEnum, } from '@/types/common'; import { get403Message, getResponseErrors } from '@/utils/403'; @@ -126,6 +126,8 @@ const getNodeTypeByProviderName = (providerName: string): ComplianceScanNodeType return ComplianceScanNodeTypeEnum.gcp_org; case 'azure': return ComplianceScanNodeTypeEnum.azure; + case 'azure_org': + return ComplianceScanNodeTypeEnum.azure_org; case 'kubernetes': return ComplianceScanNodeTypeEnum.kubernetes_cluster; default: @@ -305,10 +307,10 @@ const FILTER_SEARCHPARAMS_DYNAMIC_KEYS = [ const FILTER_SEARCHPARAMS: Record = { complianceScanStatus: 'Posture scan status', status: 'Status', - org_accounts: 'Organization accounts', + org_accounts: 'Organization account', aws_accounts: 'Account', gcp_accounts: 'Account', - azure_accounts: 'Account', + azure_accounts: 'Subscription', hosts: 'Account', clusters: 'Account', }; @@ -320,7 +322,7 @@ const getAppliedFiltersCount = (searchParams: URLSearchParams) => { }; const Filters = () => { const { nodeType } = useParams() as { - nodeType: 'aws' | 'gcp' | 'azure'; + nodeType: string; }; const [searchParams, setSearchParams] = useSearchParams(); @@ -420,56 +422,61 @@ const Filters = () => { ); })} - {(nodeType === 'aws' || nodeType === 'gcp') && ( - { - setSearchParams((prev) => { - prev.delete('org_accounts'); - prev.delete('page'); - return prev; - }); - }} - onChange={(value) => { - setSearchParams((prev) => { - prev.delete('org_accounts'); - value.forEach((id) => { - prev.append('org_accounts', id); + {isCloudNonOrgNode(nodeType) ? ( + <> + { + setSearchParams((prev) => { + prev.delete('org_accounts'); + prev.delete('page'); + return prev; }); - prev.delete('page'); - return prev; - }); - }} - /> - )} - {isCloudNode(nodeType) ? ( - { - setSearchParams((prev) => { - prev.delete(`${nodeType}_accounts`); - prev.delete('page'); - return prev; - }); - }} - onChange={(value) => { - setSearchParams((prev) => { - prev.delete(`${nodeType}_accounts`); - value.forEach((id) => { - prev.append(`${nodeType}_accounts`, id); + }} + onChange={(value) => { + setSearchParams((prev) => { + prev.delete('org_accounts'); + value.forEach((id) => { + prev.append('org_accounts', id); + }); + prev.delete('page'); + return prev; }); - prev.delete('page'); - return prev; - }); - }} - /> + }} + /> + { + setSearchParams((prev) => { + prev.delete(`${nodeType}_accounts`); + prev.delete('page'); + return prev; + }); + }} + onChange={(value) => { + setSearchParams((prev) => { + prev.delete(`${nodeType}_accounts`); + value.forEach((id) => { + prev.append(`${nodeType}_accounts`, id); + }); + prev.delete('page'); + return prev; + }); + }} + /> + ) : null} - {isLinuxProvider(nodeType) ? ( + + {isLinuxNodeType(nodeType) ? ( { }} /> ) : null} - {isKubernetesProvider(nodeType) ? ( + {isKubernetesNodeType(nodeType) ? ( { return Object.keys(FILTER_SEARCHPARAMS).includes(key); }) as Array<[FILTER_SEARCHPARAMS_KEYS_ENUM, string]> ).map(([key, value]) => { + if (key === FILTER_SEARCHPARAMS_KEYS_ENUM.org_accounts) { + return ( + + ); + } + if (FILTER_SEARCHPARAMS_DYNAMIC_KEYS.includes(key)) { return ( void; }) => { const fetcher = useFetcher(); - const params = useParams(); + const params = useParams() as { + nodeType: string; + }; const onDeleteAction = useCallback( (actionType: string) => { @@ -715,7 +737,10 @@ const DeleteAccountConfirmationModal = ({ - Delete account + Delete{' '} + {getDisplayNameOfNodeType( + params.nodeType as ModelCloudNodeAccountsListReqCloudProviderEnum, + )}
) : undefined } @@ -749,12 +774,9 @@ const DeleteAccountConfirmationModal = ({ {!fetcher.data?.success ? (
- {isCloudNode(params.nodeType) - ? `The Selected cloud account, resources and scans related to the account will be - deleted.` - : isCloudOrgNode(params.nodeType) - ? `The Selected org cloud account, child accounts related to org account, resources and scans related to the cloud accounts will be deleted.` - : ''} + {getDeleteConfirmationDisplayName( + params.nodeType as ModelCloudNodeAccountsListReqCloudProviderEnum, + )}
Are you sure you want to delete? @@ -877,7 +899,10 @@ const ActionDropdown = ({ onTableAction(row, ActionEnumType.REFRESH_ACCOUNT); }} > - Refresh account + Refresh{' '} + {getDisplayNameOfNodeType( + nodeType as ModelCloudNodeAccountsListReqCloudProviderEnum, + ).toLowerCase()} - Delete account + Delete{' '} + {getDisplayNameOfNodeType( + nodeType as ModelCloudNodeAccountsListReqCloudProviderEnum, + ).toLowerCase()} ) : null} @@ -985,7 +1013,10 @@ const BulkActions = ({ ); }} > - ADD NEW ACCOUNT + ADD NEW{' '} + {getDisplayNameOfNodeType( + nodeType as ModelCloudNodeAccountsListReqCloudProviderEnum, + ).toUpperCase()} ) : null} @@ -1198,9 +1235,14 @@ const AccountTable = ({ let path = '/posture/scan-results/:nodeType/:scanId'; if ( - cell.row.original.cloud_provider && - CLOUDS.includes( - cell.row.original.cloud_provider as ComplianceScanNodeTypeEnum, + (cell.row.original.cloud_provider && + isCloudNode( + cell.row.original + .cloud_provider as ModelCloudNodeAccountsListReqCloudProviderEnum, + )) || + isCloudOrgNode( + cell.row.original + .cloud_provider as ModelCloudNodeAccountsListReqCloudProviderEnum, ) ) { path = '/posture/cloud/scan-results/:nodeType/:scanId'; @@ -1224,7 +1266,10 @@ const AccountTable = ({ ); }, - header: () => 'Account', + header: () => + getDisplayNameOfNodeType( + nodeType as ModelCloudNodeAccountsListReqCloudProviderEnum, + ), ...columnWidth.node_name, }), columnHelper.accessor('compliance_percentage', { @@ -1289,7 +1334,7 @@ const AccountTable = ({ }), ]; - if (isCloudNode(nodeType) || isCloudOrgNode(nodeType)) { + if (isCloudNonOrgNode(nodeType) || isCloudOrgNode(nodeType)) { columns.push( columnHelper.accessor('version', { enableSorting: false, @@ -1471,7 +1516,7 @@ const Accounts = () => { const [showCancelScan, setShowCancelScan] = useState(false); const [openStartScan, setOpenStartScan] = useState(false); - const scanType = isNonCloudProvider(routeParams.nodeType) + const scanType = isNonCloudNode(routeParams.nodeType) ? ScanTypeEnum.ComplianceScan : ScanTypeEnum.CloudComplianceScan; @@ -1587,7 +1632,7 @@ const Accounts = () => { return (
- {!hasOrgCloudAccount(nodeType ?? '') ?
: null} + {!isCloudNode(nodeType ?? '') ?
: null} {showCancelScan && ( { showDialog={showDeleteDialog} scanIds={rowToAction.scanIdsToDeleteScan} scanType={ - isNonCloudProvider(routeParams.nodeType) + isNonCloudNode(routeParams.nodeType) ? ModelBulkDeleteScansRequestScanTypeEnum.Compliance : ModelBulkDeleteScansRequestScanTypeEnum.CloudCompliance } @@ -1684,16 +1729,18 @@ const Accounts = () => { ); }; -const tabs = [ - { - label: 'Regular Accounts', - value: 'accounts', - }, - { - label: 'Organization Accounts', - value: 'org-accounts', - }, -]; +const tabs = ['accounts', 'org-accounts'] as const; + +function getTabLabel(value: (typeof tabs)[number], nodeType: string) { + if (nodeType?.includes?.('azure')) { + if (value === 'accounts') { + return 'Subscriptions'; + } else { + return 'Tenants'; + } + } + return value === 'accounts' ? 'Regular Accounts' : 'Organization Accounts'; +} const AccountWithTab = () => { const { nodeType } = useParams() as { @@ -1705,13 +1752,20 @@ const AccountWithTab = () => { }); const { navigate } = usePageNavigation(); + const tabOpts = tabs.map((tab) => { + return { + label: getTabLabel(tab, nodeType), + value: tab, + }; + }); + return ( <>
{ if (currentTab === value) return; let _nodeType = nodeType; @@ -1742,15 +1796,15 @@ const ConditionalAccount = () => { nodeType: string; }; - if (hasOrgCloudAccount(nodeType)) { + if (isCloudNode(nodeType)) { return ; } return ; }; -const hasOrgCloudAccount = (nodeType: string) => { - return nodeType.startsWith('aws') || nodeType.startsWith('gcp'); -}; +const isCloudNode = (nodeType: string) => + isCloudNonOrgNode(nodeType as ModelCloudNodeAccountsListReqCloudProviderEnum) || + isCloudOrgNode(nodeType as ModelCloudNodeAccountsListReqCloudProviderEnum); export const module = { action, diff --git a/deepfence_frontend/apps/dashboard/src/features/postures/pages/Posture.tsx b/deepfence_frontend/apps/dashboard/src/features/postures/pages/Posture.tsx index 451540eecb..a62d43cb2d 100644 --- a/deepfence_frontend/apps/dashboard/src/features/postures/pages/Posture.tsx +++ b/deepfence_frontend/apps/dashboard/src/features/postures/pages/Posture.tsx @@ -3,12 +3,20 @@ import { Suspense } from 'react'; import { cn } from 'tailwind-preset'; import { Breadcrumb, BreadcrumbLink, Card, Separator } from 'ui-components'; -import { ModelPostureProvider } from '@/api/generated'; +import { + ModelCloudNodeAccountsListReqCloudProviderEnum, + ModelPostureProvider, +} from '@/api/generated'; import { DFLink } from '@/components/DFLink'; import { ComplianceIconByPercent, PostureLogos } from '@/components/icons/posture'; import { PostureIcon } from '@/components/sideNavigation/icons/Posture'; import { getColorForCompliancePercent } from '@/constants/charts'; import { BreadcrumbWrapper } from '@/features/common/BreadcrumbWrapper'; +import { + isKubernetesNodeType, + isLinuxNodeType, + isNonCloudNode, +} from '@/features/postures/utils'; import { queries } from '@/queries'; import { useTheme } from '@/theme/ThemeContext'; import { abbreviateNumber, formatPercentage } from '@/utils/number'; @@ -18,17 +26,12 @@ export const providersToNameMapping: { [key: string]: string } = { aws_org: 'AWS Organizations', gcp: 'GCP', gcp_org: 'GCP Organizations', + azure_org: 'Azure', azure: 'Azure', linux: 'Linux Hosts', kubernetes: 'Kubernetes', }; -export const isNonCloudProvider = (provider: string) => { - return provider === 'linux' || provider === 'kubernetes'; -}; -export const isLinuxProvider = (provider: string) => provider === 'linux'; -export const isKubernetesProvider = (provider: string) => provider === 'kubernetes'; - const HeaderSkeleton = () => { return (
@@ -147,56 +150,41 @@ const CardIconSection = ({ provider }: { provider: ModelPostureProvider }) => { ); }; +function getAccountProductName(provider: ModelPostureProvider) { + if (isLinuxNodeType(provider.name ?? '')) { + return 'Hosts'; + } else if (isKubernetesNodeType(provider.name ?? '')) { + return 'Clusters'; + } else if (provider.name === ModelCloudNodeAccountsListReqCloudProviderEnum.Azure) { + return 'Subscriptions'; + } else if (!isNonCloudNode(provider.name ?? '')) { + return 'Accounts'; + } +} + const CardCountSection = ({ provider }: { provider: ModelPostureProvider }) => { const textStyle = 'text-p7a leading-6 text-text-text-and-icon min-w-[120px]'; const countStyle = 'text-h3 text-text-input-value'; return (
- - {!isNonCloudProvider(provider.name ?? '') ? ( - 'Active Accounts' - ) : ( - <> - {isLinuxProvider(provider.name ?? '') && 'Active hosts'} - {isKubernetesProvider(provider.name ?? '') && 'Active clusters'} - - )} - + Active {getAccountProductName(provider)} {abbreviateNumber(provider.node_count ?? 0)}
- - {!isNonCloudProvider(provider.name ?? '') ? ( - 'Inactive Accounts' - ) : ( - <> - {isLinuxProvider(provider.name ?? '') && 'Inactive hosts'} - {isKubernetesProvider(provider.name ?? '') && 'Inactive clusters'} - - )} - + Inactive {getAccountProductName(provider)} {abbreviateNumber(provider.node_count_inactive ?? 0)}
- - {!isNonCloudProvider(provider.name ?? '') ? ( - 'Scanned Accounts' - ) : ( - <> - {isLinuxProvider(provider.name ?? '') && 'Scanned hosts'} - {isKubernetesProvider(provider.name ?? '') && 'Scanned clusters'} - - )} - + Scanned {getAccountProductName(provider)} {abbreviateNumber(provider.scan_count ?? 0)}
- {!isNonCloudProvider(provider.name ?? '') ? ( + {!isNonCloudNode(provider.name ?? '') ? (
Resources @@ -240,7 +228,7 @@ const PostureCloudList = () => { return ( <> {providers - ?.filter((provider) => !isNonCloudProvider(provider.name ?? '')) + ?.filter((provider) => !isNonCloudNode(provider.name ?? '')) .map((provider) => { return ; })} @@ -259,7 +247,7 @@ const PosturenNonCloudList = () => { return ( <> {providers - ?.filter((provider) => isNonCloudProvider(provider.name ?? '')) + ?.filter((provider) => isNonCloudNode(provider.name ?? '')) .map((provider) => { return ; })} diff --git a/deepfence_frontend/apps/dashboard/src/features/postures/pages/PostureCloudDetailModal.tsx b/deepfence_frontend/apps/dashboard/src/features/postures/pages/PostureCloudDetailModal.tsx index 2621746b73..4f96d829fb 100644 --- a/deepfence_frontend/apps/dashboard/src/features/postures/pages/PostureCloudDetailModal.tsx +++ b/deepfence_frontend/apps/dashboard/src/features/postures/pages/PostureCloudDetailModal.tsx @@ -10,6 +10,7 @@ import { SlidingModalHeader, } from 'ui-components'; +import { ModelCloudNodeAccountsListReqCloudProviderEnum } from '@/api/generated'; import { CopyButton, useCopyToClipboardState } from '@/components/CopyToClipboard'; import { CopyLineIcon } from '@/components/icons/common/CopyLine'; import { RemediationBlock } from '@/components/remediation/RemediationBlock'; @@ -148,32 +149,45 @@ const DetailsComponent = ({ ); } - const keyValues = getFieldsKeyValue(cloudPosture ?? {}, { - hiddenFields: [ - 'status', - 'description', - 'node_name', - 'severity', - 'type', - 'count', - 'node_id', - 'resources', - ], - priorityFields: [ - 'cloud_provider', - 'region', - 'account_id', - 'compliance_check_type', - 'control_id', - 'group', - 'title', - 'service', - 'reason', - 'resource', - 'masked', - 'updated_at', - ], - }); + const keyValues = getFieldsKeyValue( + { + ...(cloudPosture ?? {}), + subscription_id: cloudPosture.account_id, + }, + { + hiddenFields: [ + 'status', + 'description', + 'node_name', + 'severity', + 'type', + 'count', + 'node_id', + 'resources', + cloudPosture.cloud_provider === + ModelCloudNodeAccountsListReqCloudProviderEnum.Azure + ? 'account_id' + : 'subscription_id', + ], + priorityFields: [ + 'cloud_provider', + 'region', + cloudPosture.cloud_provider === + ModelCloudNodeAccountsListReqCloudProviderEnum.Azure + ? 'subscription_id' + : 'account_id', + 'compliance_check_type', + 'control_id', + 'group', + 'title', + 'service', + 'reason', + 'resource', + 'masked', + 'updated_at', + ], + }, + ); return (
diff --git a/deepfence_frontend/apps/dashboard/src/features/postures/pages/PostureCloudScanResults.tsx b/deepfence_frontend/apps/dashboard/src/features/postures/pages/PostureCloudScanResults.tsx index 5d517919f7..30f9ddca88 100644 --- a/deepfence_frontend/apps/dashboard/src/features/postures/pages/PostureCloudScanResults.tsx +++ b/deepfence_frontend/apps/dashboard/src/features/postures/pages/PostureCloudScanResults.tsx @@ -82,11 +82,7 @@ import { PostureScanResultsPieChart } from '@/features/postures/components/scan- import { PosturesCloudCompare } from '@/features/postures/components/scan-result/PosturesCloudCompare'; import { SearchableControl } from '@/features/postures/components/scan-result/SearchableControl'; import { providersToNameMapping } from '@/features/postures/pages/Posture'; -import { SuccessModalContent } from '@/features/settings/components/SuccessModalContent'; -import { invalidateAllQueries, queries } from '@/queries'; -import { useTheme } from '@/theme/ThemeContext'; import { - ComplianceScanNodeTypeEnum, isAlarmStatus, isDeleteStatus, isInfoStatus, @@ -95,6 +91,12 @@ import { isPassStatus, isSkipStatus, isWarnStatus, +} from '@/features/postures/utils'; +import { SuccessModalContent } from '@/features/settings/components/SuccessModalContent'; +import { invalidateAllQueries, queries } from '@/queries'; +import { useTheme } from '@/theme/ThemeContext'; +import { + ComplianceScanNodeTypeEnum, PostureSeverityType, ScanTypeEnum, } from '@/types/common'; diff --git a/deepfence_frontend/apps/dashboard/src/features/postures/pages/PostureScanResults.tsx b/deepfence_frontend/apps/dashboard/src/features/postures/pages/PostureScanResults.tsx index fa83d34331..395d46d9af 100644 --- a/deepfence_frontend/apps/dashboard/src/features/postures/pages/PostureScanResults.tsx +++ b/deepfence_frontend/apps/dashboard/src/features/postures/pages/PostureScanResults.tsx @@ -83,11 +83,7 @@ import { PostureScanResultsPieChart } from '@/features/postures/components/scan- import { PosturesCompare } from '@/features/postures/components/scan-result/PosturesCompare'; import { SearchablePostureTestNumber } from '@/features/postures/components/scan-result/SearchableTestNumber'; import { providersToNameMapping } from '@/features/postures/pages/Posture'; -import { SuccessModalContent } from '@/features/settings/components/SuccessModalContent'; -import { invalidateAllQueries, queries } from '@/queries'; -import { useTheme } from '@/theme/ThemeContext'; import { - ComplianceScanNodeTypeEnum, isAlarmStatus, isDeleteStatus, isInfoStatus, @@ -96,6 +92,12 @@ import { isPassStatus, isSkipStatus, isWarnStatus, +} from '@/features/postures/utils'; +import { SuccessModalContent } from '@/features/settings/components/SuccessModalContent'; +import { invalidateAllQueries, queries } from '@/queries'; +import { useTheme } from '@/theme/ThemeContext'; +import { + ComplianceScanNodeTypeEnum, PostureSeverityType, ScanTypeEnum, } from '@/types/common'; diff --git a/deepfence_frontend/apps/dashboard/src/features/postures/utils/index.ts b/deepfence_frontend/apps/dashboard/src/features/postures/utils/index.ts new file mode 100644 index 0000000000..be51b15476 --- /dev/null +++ b/deepfence_frontend/apps/dashboard/src/features/postures/utils/index.ts @@ -0,0 +1,109 @@ +import { + ModelCloudComplianceStatusEnum, + ModelCloudNodeAccountsListReqCloudProviderEnum, + ModelComplianceStatusEnum, +} from '@/api/generated'; + +export const isCloudNonOrgNode = (nodeType?: string) => { + return ( + nodeType === ModelCloudNodeAccountsListReqCloudProviderEnum.Aws || + nodeType === ModelCloudNodeAccountsListReqCloudProviderEnum.Azure || + nodeType === ModelCloudNodeAccountsListReqCloudProviderEnum.Gcp + ); +}; + +export const isCloudOrgNode = (nodeType?: string) => + nodeType === ModelCloudNodeAccountsListReqCloudProviderEnum.AwsOrg || + nodeType === ModelCloudNodeAccountsListReqCloudProviderEnum.GcpOrg || + nodeType === ModelCloudNodeAccountsListReqCloudProviderEnum.AzureOrg; + +export const isNonCloudNode = (nodeType: string) => { + return ( + nodeType === ModelCloudNodeAccountsListReqCloudProviderEnum.Linux || + nodeType === ModelCloudNodeAccountsListReqCloudProviderEnum.Kubernetes + ); +}; + +export const isLinuxNodeType = (nodeType: string) => + nodeType === ModelCloudNodeAccountsListReqCloudProviderEnum.Linux; + +export const isKubernetesNodeType = (nodeType: string) => + nodeType === ModelCloudNodeAccountsListReqCloudProviderEnum.Kubernetes; + +export const isAlarmStatus = (status: string) => { + return status?.toLowerCase() === ModelCloudComplianceStatusEnum.Alarm; +}; +export const isInfoStatus = (status: string) => { + return status?.toLowerCase() === ModelCloudComplianceStatusEnum.Info; +}; +export const isOkStatus = (status: string) => { + return status?.toLowerCase() === ModelCloudComplianceStatusEnum.Ok; +}; +export const isSkipStatus = (status: string) => { + return status?.toLowerCase() === ModelCloudComplianceStatusEnum.Skip; +}; +export const isPassStatus = (status: string) => { + return status?.toLowerCase() === ModelComplianceStatusEnum.Pass; +}; +export const isWarnStatus = (status: string) => { + return status?.toLowerCase() === ModelComplianceStatusEnum.Warn; +}; +export const isNoteStatus = (status: string) => { + return status?.toLowerCase() === ModelComplianceStatusEnum.Note; +}; +export const isDeleteStatus = (status: string) => { + return ( + status?.toLowerCase() === ModelCloudComplianceStatusEnum.Delete || + status?.toLowerCase() === '' + ); +}; + +export function getDisplayNameOfNodeType( + nodeType?: ModelCloudNodeAccountsListReqCloudProviderEnum, +) { + if (!nodeType) { + throw new Error(`Node type cannot be empty for display name`); + } + + if (nodeType === ModelCloudNodeAccountsListReqCloudProviderEnum.Azure) { + return 'Subscription'; + } else if (nodeType === ModelCloudNodeAccountsListReqCloudProviderEnum.AzureOrg) { + return 'Tenant'; + } else { + return 'Account'; + } +} + +export function getSearchableCloudAccountDisplayName( + nodeType?: ModelCloudNodeAccountsListReqCloudProviderEnum, +) { + if (!nodeType) { + throw new Error(`Node type cannot be empty for display name`); + } + if (nodeType === ModelCloudNodeAccountsListReqCloudProviderEnum.Azure) { + return 'Subscription'; + } else if (nodeType === ModelCloudNodeAccountsListReqCloudProviderEnum.AzureOrg) { + return 'Tenant'; + } else if (isCloudOrgNode(nodeType)) { + return 'Organization account'; + } else { + return 'Account'; + } +} + +export function getDeleteConfirmationDisplayName( + nodeType?: ModelCloudNodeAccountsListReqCloudProviderEnum, +) { + if (!nodeType) { + throw new Error(`Node type cannot be empty for display name`); + } + if (nodeType === ModelCloudNodeAccountsListReqCloudProviderEnum.Azure) { + return 'The Selected subscription, resources and scans related to the subscription will be deleted.'; + } else if (nodeType === ModelCloudNodeAccountsListReqCloudProviderEnum.AzureOrg) { + return 'The Selected tenant, child subscriptions related to tenant, resources and scans related to tenant will be deleted.'; + } else if (isCloudOrgNode()) { + return 'The Selected org cloud account, child accounts related to org account, resources and scans related to the cloud accounts will be deleted.'; + } else { + return 'The Selected cloud account, resources and scans related to the account will be deleted.'; + } +} diff --git a/deepfence_frontend/apps/dashboard/src/features/settings/pages/GlobalSettings.tsx b/deepfence_frontend/apps/dashboard/src/features/settings/pages/GlobalSettings.tsx index 65d17f1d7b..d9ad6c992c 100644 --- a/deepfence_frontend/apps/dashboard/src/features/settings/pages/GlobalSettings.tsx +++ b/deepfence_frontend/apps/dashboard/src/features/settings/pages/GlobalSettings.tsx @@ -17,7 +17,10 @@ import { } from 'ui-components'; import { getSettingsApiClient } from '@/api/api'; -import { ModelSettingsResponse, ModelSettingUpdateRequestKeyEnum } from '@/api/generated'; +import { + SettingSettingsResponse, + SettingSettingUpdateRequestKeyEnum, +} from '@/api/generated'; import { EllipsisIcon } from '@/components/icons/common/Ellipsis'; import { SlidingModalHeaderWrapper } from '@/features/common/SlidingModalHeaderWrapper'; import { SuccessModalContent } from '@/features/settings/components/SuccessModalContent'; @@ -47,8 +50,8 @@ const action = async ({ request }: ActionFunctionArgs): Promise>; - setting: ModelSettingsResponse; + setting: SettingSettingsResponse; }) => { const fetcher = useFetcher(); const { data, state } = fetcher; @@ -141,7 +144,7 @@ const ActionDropdown = ({ setting, trigger, }: { - setting: ModelSettingsResponse; + setting: SettingSettingsResponse; trigger: React.ReactNode; }) => { const [openEditSetting, setOpenEditSetting] = useState(false); @@ -175,7 +178,7 @@ const ActionDropdown = ({ ); }; const SettingTable = () => { - const columnHelper = createColumnHelper(); + const columnHelper = createColumnHelper(); const columns = useMemo(() => { const columns = [ diff --git a/deepfence_frontend/apps/dashboard/src/features/threat-graph/pages/ThreatGraph.tsx b/deepfence_frontend/apps/dashboard/src/features/threat-graph/pages/ThreatGraph.tsx index 2ddc6b815d..bf5b366439 100644 --- a/deepfence_frontend/apps/dashboard/src/features/threat-graph/pages/ThreatGraph.tsx +++ b/deepfence_frontend/apps/dashboard/src/features/threat-graph/pages/ThreatGraph.tsx @@ -137,7 +137,7 @@ const FILTER_SEARCHPARAMS: Record< cloud_resource_only: { label: 'Scope', possibleValues: THREAT_GRAPH_SCOPE }, aws_account_ids: { label: 'AWS account' }, gcp_account_ids: { label: 'GCP account' }, - azure_account_ids: { label: 'Azure account' }, + azure_account_ids: { label: 'Azure subscription' }, }; const getAppliedFiltersCount = (searchParams: URLSearchParams) => { @@ -219,6 +219,7 @@ const Filters = () => { { setSearchParams((prev) => { @@ -238,6 +239,7 @@ const Filters = () => { /> { setSearchParams((prev) => { @@ -257,6 +259,7 @@ const Filters = () => { /> { setSearchParams((prev) => { diff --git a/deepfence_frontend/apps/dashboard/src/features/topology/data-components/tables/CloudResourcesTable.tsx b/deepfence_frontend/apps/dashboard/src/features/topology/data-components/tables/CloudResourcesTable.tsx index 22691955ed..d3ddf3e2db 100644 --- a/deepfence_frontend/apps/dashboard/src/features/topology/data-components/tables/CloudResourcesTable.tsx +++ b/deepfence_frontend/apps/dashboard/src/features/topology/data-components/tables/CloudResourcesTable.tsx @@ -98,7 +98,7 @@ const FILTER_SEARCHPARAMS: Record = { serviceType: 'Service type', aws_account_ids: 'AWS account', gcp_account_ids: 'GCP account', - azure_account_ids: 'Azure account', + azure_account_ids: 'Azure subscription', }; const getAppliedFiltersCount = (searchParams: URLSearchParams) => { @@ -229,6 +229,20 @@ function Filters() { const [cloudProvidersSearchText, setCloudProvidersSearchText] = useState(''); const appliedFilterCount = getAppliedFiltersCount(searchParams); + const onFilterRemove = ({ key, value }: { key: string; value: string }) => { + return () => { + setSearchParams((prev) => { + const existingValues = prev.getAll(key); + prev.delete(key); + existingValues.forEach((existingValue) => { + if (existingValue !== value) prev.append(key, existingValue); + }); + prev.delete('page'); + return prev; + }); + }; + }; + return (
@@ -313,7 +327,7 @@ function Filters() { /> { setSearchParams((prev) => { @@ -344,17 +358,7 @@ function Filters() { return ( { - setSearchParams((prev) => { - const existingValues = prev.getAll(key); - prev.delete(key); - existingValues.forEach((existingValue) => { - if (existingValue !== value) prev.append(key, existingValue); - }); - prev.delete('page'); - return prev; - }); - }} + onRemove={onFilterRemove({ key, value })} text={`${FILTER_SEARCHPARAMS[key]}: ${value}`} /> ); diff --git a/deepfence_frontend/apps/dashboard/src/queries/onboard.ts b/deepfence_frontend/apps/dashboard/src/queries/onboard.ts index 39446a1447..6c386e5c4d 100644 --- a/deepfence_frontend/apps/dashboard/src/queries/onboard.ts +++ b/deepfence_frontend/apps/dashboard/src/queries/onboard.ts @@ -140,6 +140,16 @@ export const onboardQueries = createQueryKeys('onboard', { }, }); + const azureOrgResultsPromise = listCloudNodeAccountApi({ + modelCloudNodeAccountsListReq: { + cloud_provider: 'azure_org', + window: { + offset: 0, + size: 1000000, + }, + }, + }); + const searchHostsApi = apiWrapper({ fn: getSearchApiClient().searchHosts, }); @@ -203,6 +213,7 @@ export const onboardQueries = createQueryKeys('onboard', { azureResults, awsOrgResults, gcpOrgResults, + azureOrgResults, ] = await Promise.all([ awsResultsPromise, hostsResultsPromise, @@ -212,6 +223,7 @@ export const onboardQueries = createQueryKeys('onboard', { azureResultsPromise, awsOrgResultsPromise, gcpOrgResultsPromise, + azureOrgResultsPromise, ]); if ( @@ -222,7 +234,8 @@ export const onboardQueries = createQueryKeys('onboard', { !gcpResults.ok || !azureResults.ok || !awsOrgResults.ok || - !gcpOrgResults.ok + !gcpOrgResults.ok || + !azureOrgResults.ok ) { // TODO(manan) handle error cases return []; @@ -328,7 +341,7 @@ export const onboardQueries = createQueryKeys('onboard', { count: azureResults.value.total, connections: ( azureResults.value.cloud_node_accounts_info?.map((result) => ({ - id: `gcp-${result.node_id}`, + id: `azure-${result.node_id}`, urlId: result.node_id ?? '', accountType: 'Azure', urlType: 'azure', @@ -342,6 +355,29 @@ export const onboardQueries = createQueryKeys('onboard', { }); } + if (azureOrgResults.value.total) { + data.push({ + id: 'azure_org', + urlId: 'azure_org', + urlType: 'azure_org', + accountType: 'Azure Organizations', + count: azureOrgResults.value.total, + connections: ( + azureOrgResults.value.cloud_node_accounts_info?.map((result) => ({ + id: `azure_org-${result.node_id}`, + urlId: result.node_id ?? '', + accountType: 'Azure Organizations', + urlType: 'azure_org', + connectionMethod: 'Cloud connector', + accountId: result.node_name ?? '-', + active: !!result.active, + })) ?? [] + ).sort((a, b) => { + return (a.accountId ?? '').localeCompare(b.accountId ?? ''); + }), + }); + } + if (hostsResults.value.length) { data.push({ id: 'hosts', diff --git a/deepfence_frontend/apps/dashboard/src/types/common.ts b/deepfence_frontend/apps/dashboard/src/types/common.ts index 5a4b4ad812..bd68afd113 100644 --- a/deepfence_frontend/apps/dashboard/src/types/common.ts +++ b/deepfence_frontend/apps/dashboard/src/types/common.ts @@ -1,5 +1,6 @@ import { ModelCloudComplianceStatusEnum, + ModelCloudNodeAccountsListReqCloudProviderEnum, ModelComplianceStatusEnum, ModelMalwareFileSeverityEnum, ModelScanResultsActionRequestScanTypeEnum, @@ -41,11 +42,21 @@ export enum ComplianceScanNodeTypeEnum { aws_org = 'aws_org', gcp = 'gcp', gcp_org = 'gcp_org', + azure_org = 'azure_org', azure = 'azure', host = 'host', kubernetes_cluster = 'kubernetes_cluster', } +type PostureEnum = + (typeof ModelCloudNodeAccountsListReqCloudProviderEnum)[keyof typeof ModelCloudNodeAccountsListReqCloudProviderEnum]; + +export type CloudNodeType = Exclude; +export type CloudNodeNonOrgType = Exclude< + PostureEnum, + 'aws_org' | 'gcp_org' | 'azure_org' | 'linux' | 'kubernetes' +>; + export const RegistryType = { azure_container_registry: 'azure_container_registry', docker_hub: 'docker_hub', @@ -69,12 +80,6 @@ export const registryTypeToNameMapping: { [key: string]: string } = { quay: 'Quay', } as const; -export type CloudNodeType = 'aws' | 'azure' | 'gcp'; -export const isCloudNode = (nodeType?: string) => - nodeType === 'aws' || nodeType === 'azure' || nodeType === 'gcp'; -export const isCloudOrgNode = (nodeType?: string) => - nodeType === 'aws_org' || nodeType === 'gcp_org'; - export type GenerativeAIIntegrationType = 'openai' | 'amazon-bedrock'; export const isCriticalSeverity = (severity: string) => { @@ -94,30 +99,3 @@ export const isUnknownSeverity = (severity: string) => { severity?.toLowerCase() === SeverityEnum.Unknown || severity?.toLowerCase() === '' ); }; -export const isAlarmStatus = (status: string) => { - return status?.toLowerCase() === ModelCloudComplianceStatusEnum.Alarm; -}; -export const isInfoStatus = (status: string) => { - return status?.toLowerCase() === ModelCloudComplianceStatusEnum.Info; -}; -export const isOkStatus = (status: string) => { - return status?.toLowerCase() === ModelCloudComplianceStatusEnum.Ok; -}; -export const isSkipStatus = (status: string) => { - return status?.toLowerCase() === ModelCloudComplianceStatusEnum.Skip; -}; -export const isPassStatus = (status: string) => { - return status?.toLowerCase() === ModelComplianceStatusEnum.Pass; -}; -export const isWarnStatus = (status: string) => { - return status?.toLowerCase() === ModelComplianceStatusEnum.Warn; -}; -export const isNoteStatus = (status: string) => { - return status?.toLowerCase() === ModelComplianceStatusEnum.Note; -}; -export const isDeleteStatus = (status: string) => { - return ( - status?.toLowerCase() === ModelCloudComplianceStatusEnum.Delete || - status?.toLowerCase() === '' - ); -};