mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-08-22 13:51:33 +00:00
Compare commits
11
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9b0487eb9a | ||
|
|
3a99909b75 | ||
|
|
2ecd9ad2c5 | ||
|
|
50dc396aa3 | ||
|
|
acf333493a | ||
|
|
bd6272f5a7 | ||
|
|
8c95e1efaf | ||
|
|
845a0aa0d5 | ||
|
|
75a11be9e6 | ||
|
|
a778d005b6 | ||
|
|
1281f4ec5e |
@@ -16,7 +16,7 @@ AUTH_SECRET="N/c6mnaS5+SWq81+819OrzQZlmx1Vxtp/orjttJSmw8="
|
||||
PROWLER_API_VERSION="stable"
|
||||
# PostgreSQL settings
|
||||
# If running Django and celery on host, use 'localhost', else use 'postgres-db'
|
||||
POSTGRES_HOST=postgres-db
|
||||
POSTGRES_HOST=postgres-db-proxy
|
||||
POSTGRES_PORT=5432
|
||||
POSTGRES_ADMIN_USER=prowler_admin
|
||||
POSTGRES_ADMIN_PASSWORD=postgres
|
||||
|
||||
+5
-4
@@ -9,12 +9,8 @@ All notable changes to the **Prowler API** are documented in this file.
|
||||
- Added new `GET /compliance-overviews` endpoints to retrieve compliance metadata and specific requirements statuses [(#7877)](https://github.com/prowler-cloud/prowler/pull/7877).
|
||||
|
||||
### Changed
|
||||
- Renamed field encrypted_password to password for M365 provider [(#7784)](https://github.com/prowler-cloud/prowler/pull/7784)
|
||||
- Reworked `GET /compliance-overviews` to return proper requirement metrics [(#7877)](https://github.com/prowler-cloud/prowler/pull/7877).
|
||||
|
||||
### Fixed
|
||||
- Fixed the connection status verification before launching a scan [(#7831)](https://github.com/prowler-cloud/prowler/pull/7831)
|
||||
|
||||
---
|
||||
|
||||
## [v1.8.3] (Prowler v5.7.3)
|
||||
@@ -22,9 +18,14 @@ All notable changes to the **Prowler API** are documented in this file.
|
||||
### Added
|
||||
- Database backend to handle already closed connections [(#7935)](https://github.com/prowler-cloud/prowler/pull/7935).
|
||||
|
||||
### Changed
|
||||
- Renamed field encrypted_password to password for M365 provider [(#7784)](https://github.com/prowler-cloud/prowler/pull/7784)
|
||||
|
||||
### Fixed
|
||||
- Fixed transaction persistence with RLS operations [(#7916)](https://github.com/prowler-cloud/prowler/pull/7916).
|
||||
- Reverted the change `get_with_retry` to use the original `get` method for retrieving tasks [(#7932)](https://github.com/prowler-cloud/prowler/pull/7932).
|
||||
- Fixed the connection status verification before launching a scan [(#7831)](https://github.com/prowler-cloud/prowler/pull/7831)
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
+3
-4
@@ -37,18 +37,17 @@ COPY pyproject.toml ./
|
||||
RUN pip install --no-cache-dir --upgrade pip && \
|
||||
pip install --no-cache-dir poetry
|
||||
|
||||
COPY src/backend/ ./backend/
|
||||
|
||||
ENV PATH="/home/prowler/.local/bin:$PATH"
|
||||
|
||||
# Add `--no-root` to avoid installing the current project as a package
|
||||
RUN poetry install --no-root && \
|
||||
rm -rf ~/.cache/pip
|
||||
|
||||
COPY docker-entrypoint.sh ./docker-entrypoint.sh
|
||||
|
||||
RUN poetry run python "$(poetry env info --path)/src/prowler/prowler/providers/m365/lib/powershell/m365_powershell.py"
|
||||
|
||||
COPY src/backend/ ./backend/
|
||||
COPY docker-entrypoint.sh ./docker-entrypoint.sh
|
||||
|
||||
WORKDIR /home/prowler/backend
|
||||
|
||||
# Development image
|
||||
|
||||
+21
-2
@@ -26,6 +26,25 @@ services:
|
||||
ports:
|
||||
- ${UI_PORT:-3000}:${UI_PORT:-3000}
|
||||
|
||||
postgres-proxy:
|
||||
image: edoburu/pgbouncer:latest
|
||||
hostname: "postgres-db-proxy"
|
||||
environment:
|
||||
- DB_HOST=postgres-db
|
||||
- DB_PORT=5432
|
||||
- DB_USER=${POSTGRES_ADMIN_USER}
|
||||
- DB_PASSWORD=${POSTGRES_ADMIN_PASSWORD}
|
||||
- ADMIN_USERS=prowler_admin
|
||||
- AUTH_TYPE=scram-sha-256
|
||||
env_file:
|
||||
- path: ./.env
|
||||
required: false
|
||||
ports:
|
||||
- "5432:5432"
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
|
||||
postgres:
|
||||
image: postgres:16.3-alpine3.20
|
||||
hostname: "postgres-db"
|
||||
@@ -38,8 +57,8 @@ services:
|
||||
env_file:
|
||||
- path: .env
|
||||
required: false
|
||||
ports:
|
||||
- "${POSTGRES_PORT:-5432}:${POSTGRES_PORT:-5432}"
|
||||
# ports:
|
||||
# - "${POSTGRES_PORT:-5432}:${POSTGRES_PORT:-5432}"
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "sh -c 'pg_isready -U ${POSTGRES_ADMIN_USER} -d ${POSTGRES_DB}'"]
|
||||
interval: 5s
|
||||
|
||||
@@ -170,6 +170,9 @@ These two new environment variables are **required** to execute the PowerShell m
|
||||
|
||||
- `M365_USER` should be your Microsoft account email using the **assigned domain in the tenant**. This means it must look like `example@YourCompany.onmicrosoft.com` or `example@YourCompany.com`, but it must be the exact domain assigned to that user in the tenant.
|
||||
|
||||
???+ warning
|
||||
The user must not be MFA capable. Microsoft does not allow MFA capable users to authenticate programmatically. See [Microsoft documentation](https://learn.microsoft.com/en-us/entra/identity-platform/scenario-desktop-acquire-token-username-password?tabs=dotnet) for more information.
|
||||
|
||||
???+ warning
|
||||
Using a tenant domain other than the one assigned — even if it belongs to the same tenant — will cause Prowler to fail, as Microsoft authentication will not succeed.
|
||||
|
||||
|
||||
@@ -138,6 +138,10 @@ Follow these steps to assign the permissions:
|
||||
|
||||

|
||||
|
||||
The final result of permission assignment should be this:
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
### Assign required roles to your user
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 81 KiB |
@@ -4,6 +4,9 @@ The **Prowler App** supports multiple users within a single tenant, enabling sea
|
||||
|
||||
[Roles](#roles) help you control user permissions, determining what actions each user can perform and the data they can access within Prowler. By default, each account includes an immutable **admin** role, ensuring that your account always retains administrative access.
|
||||
|
||||
???+ note
|
||||
If the account is created without an invitation, a new tenant will be provisioned for it. However, if the account is created through an invitation, the user will join the inviter’s tenant.
|
||||
|
||||
## Membership
|
||||
|
||||
To get to User-Invitation Management we will focus on the Membership section.
|
||||
@@ -156,6 +159,9 @@ Follow these steps to create a role for your account:
|
||||
|
||||
<img src="../img/rbac/role_create_1.png" alt="Role parameters" width="700"/>
|
||||
|
||||
???+ note
|
||||
To assign read-only access, select only the `Unlimited Visibility` permission when creating the role. Then, go to the Users page and assign this role to the appropriate user.
|
||||
|
||||
#### Editing a Role
|
||||
|
||||
Follow these steps to edit a role on your account:
|
||||
|
||||
+12
-6
@@ -2,7 +2,7 @@
|
||||
|
||||
All notable changes to the **Prowler SDK** are documented in this file.
|
||||
|
||||
## [5.8.0] (Prowler v5.8.0)
|
||||
## [v5.8.0] (Prowler UNRELEASED)
|
||||
|
||||
### Added
|
||||
- Add CIS 1.11 compliance framework for Kubernetes. [(#7790)](https://github.com/prowler-cloud/prowler/pull/7790)
|
||||
@@ -25,7 +25,17 @@ All notable changes to the **Prowler SDK** are documented in this file.
|
||||
|
||||
---
|
||||
|
||||
### [v5.7.2] Fixed
|
||||
## [v5.7.3] (Prowler v5.7.3)
|
||||
|
||||
### Fixed
|
||||
- Automatically encrypt password in Microsoft365 provider. [(#7784)](https://github.com/prowler-cloud/prowler/pull/7784)
|
||||
- Remove last encrypted password appearances. [(#7825)](https://github.com/prowler-cloud/prowler/pull/7825)
|
||||
|
||||
---
|
||||
|
||||
## [v5.7.2] (Prowler v5.7.2)
|
||||
|
||||
### Fixed
|
||||
- Fix `m365_powershell test_credentials` to use sanitized credentials. [(#7761)](https://github.com/prowler-cloud/prowler/pull/7761)
|
||||
- Fix `admincenter_users_admins_reduced_license_footprint` check logic to pass when admin user has no license. [(#7779)](https://github.com/prowler-cloud/prowler/pull/7779)
|
||||
- Fix `m365_powershell` to close the PowerShell sessions in msgraph services. [(#7816)](https://github.com/prowler-cloud/prowler/pull/7816)
|
||||
@@ -60,14 +70,12 @@ All notable changes to the **Prowler SDK** are documented in this file.
|
||||
- Update and upgrade CIS for all the providers [(#7738)](https://github.com/prowler-cloud/prowler/pull/7738)
|
||||
- Cover policies with conditions with SNS endpoint in `sns_topics_not_publicly_accessible`. [(#7750)](https://github.com/prowler-cloud/prowler/pull/7750)
|
||||
- Change severity logic for `ec2_securitygroup_allow_ingress_from_internet_to_all_ports` check. [(#7764)](https://github.com/prowler-cloud/prowler/pull/7764)
|
||||
- Automatically encrypt password in Microsoft365 provider. [(#7784)](https://github.com/prowler-cloud/prowler/pull/7784)
|
||||
|
||||
---
|
||||
|
||||
## [v5.6.0] (Prowler v5.6.0)
|
||||
|
||||
### Added
|
||||
|
||||
- Add SOC2 compliance framework to Azure. [(#7489)](https://github.com/prowler-cloud/prowler/pull/7489)
|
||||
- Add check for unused Service Accounts in GCP. [(#7419)](https://github.com/prowler-cloud/prowler/pull/7419)
|
||||
- Add Powershell to Microsoft365. [(#7331)](https://github.com/prowler-cloud/prowler/pull/7331)
|
||||
@@ -117,7 +125,6 @@ All notable changes to the **Prowler SDK** are documented in this file.
|
||||
- Add Microsoft User and User Credential auth to reports [(#7681)](https://github.com/prowler-cloud/prowler/pull/7681)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix package name location in pyproject.toml while replicating for prowler-cloud. [(#7531)](https://github.com/prowler-cloud/prowler/pull/7531)
|
||||
- Remove cache in PyPI release action. [(#7532)](https://github.com/prowler-cloud/prowler/pull/7532)
|
||||
- Add the correct values for logger.info inside iam service. [(#7526)](https://github.com/prowler-cloud/prowler/pull/7526)
|
||||
@@ -138,7 +145,6 @@ All notable changes to the **Prowler SDK** are documented in this file.
|
||||
## [v5.5.1] (Prowler v5.5.1)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Add default name to contacts in Azure Defender. [(#7483)](https://github.com/prowler-cloud/prowler/pull/7483)
|
||||
- Handle projects without ID in GCP. [(#7496)](https://github.com/prowler-cloud/prowler/pull/7496)
|
||||
- Restore packages location in PyProject. [(#7510)](https://github.com/prowler-cloud/prowler/pull/7510)
|
||||
|
||||
@@ -19,10 +19,20 @@ All notable changes to the **Prowler UI** are documented in this file.
|
||||
- Add compliance detail view: ISO [(#7897)](https://github.com/prowler-cloud/prowler/pull/7897)
|
||||
- Add compliance detail view: CIS [(#7913)](https://github.com/prowler-cloud/prowler/pull/7913)
|
||||
- Add compliance detail view: AWS Well-Architected Framework [(#7925)](https://github.com/prowler-cloud/prowler/pull/7925)
|
||||
- Improve `Scan ID` filter by adding more context and enhancing the UI/UX. [(#7949)](https://github.com/prowler-cloud/prowler/pull/7949)
|
||||
|
||||
### 🔄 Changed
|
||||
|
||||
- Add `Provider UID` filter to scans page. [(#7820)](https://github.com/prowler-cloud/prowler/pull/7820)
|
||||
- Aligned Next.js version to `v14.2.29` across Prowler and Cloud environments for consistency and improved maintainability. [(#7962)](https://github.com/prowler-cloud/prowler/pull/7962)
|
||||
|
||||
---
|
||||
|
||||
## [v1.7.3] (Prowler v5.7.3)
|
||||
|
||||
### 🐞 Fixes
|
||||
|
||||
- Fix encrypted password typo in `formSchemas`. [(#7828)](https://github.com/prowler-cloud/prowler/pull/7828)
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ import { ContentLayout } from "@/components/ui";
|
||||
import { DataTable, DataTableFilterCustom } from "@/components/ui/table";
|
||||
import {
|
||||
createDict,
|
||||
createScanDetailsMapping,
|
||||
extractFiltersAndQuery,
|
||||
extractSortAndKey,
|
||||
hasDateOrScanFilter,
|
||||
@@ -48,7 +49,7 @@ export default async function Findings({
|
||||
filters,
|
||||
}),
|
||||
getProviders({ pageSize: 50 }),
|
||||
getScans({}),
|
||||
getScans({ pageSize: 50 }),
|
||||
]);
|
||||
|
||||
// Extract unique regions and services from the new endpoint
|
||||
@@ -76,20 +77,17 @@ export default async function Findings({
|
||||
});
|
||||
|
||||
// Extract scan UUIDs with "completed" state and more than one resource
|
||||
const completedScans = scansData?.data
|
||||
?.filter(
|
||||
(scan: ScanProps) =>
|
||||
scan.attributes.state === "completed" &&
|
||||
scan.attributes.unique_resource_count > 1,
|
||||
)
|
||||
.map((scan: ScanProps) => ({
|
||||
id: scan.id,
|
||||
name: scan.attributes.name,
|
||||
}));
|
||||
const completedScans = scansData?.data?.filter(
|
||||
(scan: ScanProps) =>
|
||||
scan.attributes.state === "completed" &&
|
||||
scan.attributes.unique_resource_count > 1,
|
||||
);
|
||||
|
||||
const completedScanIds =
|
||||
completedScans?.map((scan: ScanProps) => scan.id) || [];
|
||||
|
||||
const scanDetails = createScanDetailsMapping(completedScans, providersData);
|
||||
|
||||
return (
|
||||
<ContentLayout title="Findings" icon="carbon:data-view-alt">
|
||||
<FilterControls search date />
|
||||
@@ -119,6 +117,7 @@ export default async function Findings({
|
||||
key: "scan__in",
|
||||
labelCheckboxGroup: "Scan ID",
|
||||
values: completedScanIds,
|
||||
valueLabelMapping: scanDetails,
|
||||
index: 9,
|
||||
},
|
||||
]}
|
||||
|
||||
@@ -6,7 +6,7 @@ import { FilterControls } from "@/components/filters";
|
||||
import { DataTableFilterCustom } from "@/components/ui/table/data-table-filter-custom";
|
||||
|
||||
import { DataCompliance } from "./data-compliance";
|
||||
import { SelectScanComplianceDataProps } from "./select-scan-compliance-data";
|
||||
import { SelectScanComplianceDataProps } from "./scan-selector";
|
||||
|
||||
interface ComplianceHeaderProps {
|
||||
scans: SelectScanComplianceDataProps["scans"];
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Divider } from "@nextui-org/react";
|
||||
import { Divider, Tooltip } from "@nextui-org/react";
|
||||
import React from "react";
|
||||
|
||||
import { DateWithTime, EntityInfoShort } from "@/components/ui/entities";
|
||||
@@ -22,18 +22,25 @@ export const ComplianceScanInfo: React.FC<ComplianceScanInfoProps> = ({
|
||||
scan,
|
||||
}) => {
|
||||
return (
|
||||
<div className="flex w-fit items-center">
|
||||
<div className="flex items-center gap-2">
|
||||
<EntityInfoShort
|
||||
cloudProvider={scan.providerInfo.provider}
|
||||
entityAlias={scan.providerInfo.alias}
|
||||
entityId={scan.providerInfo.uid}
|
||||
hideCopyButton
|
||||
snippetWidth="max-w-[100px]"
|
||||
/>
|
||||
<Divider orientation="vertical" className="mx-2 h-6" />
|
||||
<div className="flex flex-col items-start">
|
||||
<p className="text-xs text-default-500">
|
||||
{scan.attributes.name || "- -"}
|
||||
</p>
|
||||
<Divider orientation="vertical" className="h-6" />
|
||||
<div className="flex flex-col items-start whitespace-nowrap">
|
||||
<Tooltip
|
||||
content={scan.attributes.name || "- -"}
|
||||
placement="top"
|
||||
size="sm"
|
||||
>
|
||||
<p className="text-xs text-default-500">
|
||||
{scan.attributes.name || "- -"}
|
||||
</p>
|
||||
</Tooltip>
|
||||
<DateWithTime inline dateTime={scan.attributes.completed_at} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useRouter, useSearchParams } from "next/navigation";
|
||||
import { useEffect } from "react";
|
||||
|
||||
import {
|
||||
SelectScanComplianceData,
|
||||
ScanSelector,
|
||||
SelectScanComplianceDataProps,
|
||||
} from "@/components/compliance/compliance-header/index";
|
||||
interface DataComplianceProps {
|
||||
@@ -35,8 +35,8 @@ export const DataCompliance = ({ scans }: DataComplianceProps) => {
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="grid grid-cols-1 items-center gap-x-4 gap-y-4 md:grid-cols-2 lg:grid-cols-3">
|
||||
<SelectScanComplianceData
|
||||
<div className="flex max-w-fit">
|
||||
<ScanSelector
|
||||
scans={scans}
|
||||
selectedScanId={selectedScanId}
|
||||
onSelectionChange={handleScanChange}
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
export * from "./data-compliance";
|
||||
export * from "./select-scan-compliance-data";
|
||||
export * from "./scan-selector";
|
||||
|
||||
+2
-2
@@ -16,7 +16,7 @@ export interface SelectScanComplianceDataProps {
|
||||
onSelectionChange: (selectedKey: string) => void;
|
||||
}
|
||||
|
||||
export const SelectScanComplianceData = ({
|
||||
export const ScanSelector = ({
|
||||
scans,
|
||||
selectedScanId,
|
||||
onSelectionChange,
|
||||
@@ -26,7 +26,7 @@ export const SelectScanComplianceData = ({
|
||||
aria-label="Select a Scan"
|
||||
placeholder="Select a scan"
|
||||
classNames={{
|
||||
selectorIcon: "right-2",
|
||||
trigger: "w-full min-w-[365px]",
|
||||
}}
|
||||
size="lg"
|
||||
labelPlacement="outside"
|
||||
@@ -12,7 +12,7 @@ export * from "./compliance-custom-details/iso-details";
|
||||
export * from "./compliance-header/compliance-header";
|
||||
export * from "./compliance-header/compliance-scan-info";
|
||||
export * from "./compliance-header/data-compliance";
|
||||
export * from "./compliance-header/select-scan-compliance-data";
|
||||
export * from "./compliance-header/scan-selector";
|
||||
export * from "./no-scans-available";
|
||||
export * from "./skeletons/bar-chart-skeleton";
|
||||
export * from "./skeletons/compliance-accordion-skeleton";
|
||||
|
||||
@@ -20,8 +20,15 @@ import React, {
|
||||
useState,
|
||||
} from "react";
|
||||
|
||||
import { ComplianceScanInfo } from "@/components/compliance/compliance-header/compliance-scan-info";
|
||||
import { EntityInfoShort } from "@/components/ui/entities";
|
||||
import { CustomDropdownFilterProps } from "@/types";
|
||||
import { isScanEntity } from "@/lib/helper-filters";
|
||||
import {
|
||||
CustomDropdownFilterProps,
|
||||
FilterEntity,
|
||||
ProviderEntity,
|
||||
ScanEntity,
|
||||
} from "@/types";
|
||||
|
||||
export const CustomDropdownFilter = ({
|
||||
filter,
|
||||
@@ -177,10 +184,25 @@ export const CustomDropdownFilter = ({
|
||||
|
||||
const getDisplayLabel = useCallback(
|
||||
(value: string) => {
|
||||
const entity = filter.valueLabelMapping?.find((entry) => entry[value])?.[
|
||||
value
|
||||
];
|
||||
return entity?.alias || entity?.uid || value;
|
||||
const entity: FilterEntity | undefined = filter.valueLabelMapping?.find(
|
||||
(entry) => entry[value],
|
||||
)?.[value];
|
||||
if (!entity) return value;
|
||||
|
||||
if (isScanEntity(entity as ScanEntity)) {
|
||||
return (
|
||||
(entity as ScanEntity).attributes?.name ||
|
||||
(entity as ScanEntity).providerInfo?.alias ||
|
||||
(entity as ScanEntity).providerInfo?.uid ||
|
||||
value
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
(entity as ProviderEntity).alias ||
|
||||
(entity as ProviderEntity).uid ||
|
||||
value
|
||||
);
|
||||
}
|
||||
},
|
||||
[filter.valueLabelMapping],
|
||||
);
|
||||
@@ -239,7 +261,7 @@ export const CustomDropdownFilter = ({
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter" || e.key === " ") {
|
||||
e.preventDefault();
|
||||
handleClearAll(e as any);
|
||||
handleClearAll(e as unknown as React.MouseEvent);
|
||||
}
|
||||
}}
|
||||
>
|
||||
@@ -251,7 +273,7 @@ export const CustomDropdownFilter = ({
|
||||
</div>
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-80 dark:bg-prowler-blue-800">
|
||||
<PopoverContent className="w-auto min-w-80 dark:bg-prowler-blue-800">
|
||||
<div className="flex w-full flex-col gap-4 p-2">
|
||||
<CheckboxGroup
|
||||
color="default"
|
||||
@@ -279,9 +301,10 @@ export const CustomDropdownFilter = ({
|
||||
className="flex max-h-96 max-w-full flex-col gap-y-2 py-2"
|
||||
>
|
||||
{filterValues.map((value) => {
|
||||
const entity = filter.valueLabelMapping?.find(
|
||||
(entry) => entry[value],
|
||||
)?.[value];
|
||||
const entity: FilterEntity | undefined =
|
||||
filter.valueLabelMapping?.find((entry) => entry[value])?.[
|
||||
value
|
||||
];
|
||||
|
||||
return (
|
||||
<Checkbox
|
||||
@@ -293,12 +316,18 @@ export const CustomDropdownFilter = ({
|
||||
value={value}
|
||||
>
|
||||
{entity ? (
|
||||
<EntityInfoShort
|
||||
cloudProvider={entity.provider}
|
||||
entityAlias={entity.alias ?? undefined}
|
||||
entityId={entity.uid}
|
||||
hideCopyButton
|
||||
/>
|
||||
isScanEntity(entity as ScanEntity) ? (
|
||||
<ComplianceScanInfo scan={entity as ScanEntity} />
|
||||
) : (
|
||||
<EntityInfoShort
|
||||
cloudProvider={(entity as ProviderEntity).provider}
|
||||
entityAlias={
|
||||
(entity as ProviderEntity).alias ?? undefined
|
||||
}
|
||||
entityId={(entity as ProviderEntity).uid}
|
||||
hideCopyButton
|
||||
/>
|
||||
)
|
||||
) : (
|
||||
value
|
||||
)}
|
||||
|
||||
@@ -30,9 +30,13 @@ export const DateWithTime: React.FC<DateWithTimeProps> = ({
|
||||
<div
|
||||
className={`flex ${inline ? "flex-row items-center gap-2" : "flex-col"}`}
|
||||
>
|
||||
<span className="text-xs font-semibold">{formattedDate}</span>
|
||||
<span className="whitespace-nowrap text-xs font-semibold">
|
||||
{formattedDate}
|
||||
</span>
|
||||
{showTime && (
|
||||
<span className="text-xs text-gray-500">{formattedTime}</span>
|
||||
<span className="whitespace-nowrap text-xs text-gray-500">
|
||||
{formattedTime}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { Tooltip } from "@nextui-org/react";
|
||||
import React from "react";
|
||||
|
||||
import { IdIcon } from "@/components/icons";
|
||||
@@ -11,6 +12,7 @@ interface EntityInfoProps {
|
||||
entityAlias?: string;
|
||||
entityId?: string;
|
||||
hideCopyButton?: boolean;
|
||||
snippetWidth?: string;
|
||||
}
|
||||
|
||||
export const EntityInfoShort: React.FC<EntityInfoProps> = ({
|
||||
@@ -20,12 +22,16 @@ export const EntityInfoShort: React.FC<EntityInfoProps> = ({
|
||||
hideCopyButton = false,
|
||||
}) => {
|
||||
return (
|
||||
<div className="flex w-full items-center justify-between space-x-2">
|
||||
<div className="flex items-center gap-x-2">
|
||||
<div className="flex items-center justify-start">
|
||||
<div className="flex items-center justify-between gap-x-2">
|
||||
<div className="flex-shrink-0">{getProviderLogo(cloudProvider)}</div>
|
||||
<div className="flex flex-col">
|
||||
<div className="flex max-w-[120px] flex-col">
|
||||
{entityAlias && (
|
||||
<span className="text-xs text-default-500">{entityAlias}</span>
|
||||
<Tooltip content={entityAlias} placement="top" size="sm">
|
||||
<span className="truncate text-ellipsis text-xs text-default-500">
|
||||
{entityAlias}
|
||||
</span>
|
||||
</Tooltip>
|
||||
)}
|
||||
<SnippetChip
|
||||
value={entityId ?? ""}
|
||||
|
||||
@@ -23,6 +23,10 @@ export const SnippetChip = ({
|
||||
return (
|
||||
<Snippet
|
||||
className={cn("h-6", className)}
|
||||
classNames={{
|
||||
content: "min-w-0 overflow-hidden",
|
||||
pre: "min-w-0 overflow-hidden text-ellipsis whitespace-nowrap",
|
||||
}}
|
||||
color="default"
|
||||
size="sm"
|
||||
variant="flat"
|
||||
@@ -34,10 +38,13 @@ export const SnippetChip = ({
|
||||
codeString={value}
|
||||
{...props}
|
||||
>
|
||||
<div className="flex items-center space-x-2" aria-label={ariaLabel}>
|
||||
<div
|
||||
className="flex min-w-0 items-center space-x-2"
|
||||
aria-label={ariaLabel}
|
||||
>
|
||||
{icon}
|
||||
<Tooltip content={value} placement="top" size="sm">
|
||||
<span className="no-scrollbar max-w-24 overflow-hidden overflow-x-scroll text-ellipsis whitespace-nowrap text-xs">
|
||||
<span className="min-w-0 flex-1 truncate text-xs">
|
||||
{formatter ? formatter(value) : value}
|
||||
</span>
|
||||
</Tooltip>
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
import { ProviderProps, ProvidersApiResponse, ScanProps } from "@/types";
|
||||
import { ScanEntity } from "@/types/scans";
|
||||
|
||||
/**
|
||||
* Extracts normalized filters and search query from the URL search params.
|
||||
* Used Server Side Rendering (SSR). There is a hook (useUrlFilters) for client side.
|
||||
@@ -44,3 +47,54 @@ export const extractSortAndKey = (searchParams: Record<string, unknown>) => {
|
||||
|
||||
return { searchParamsKey, rawSort, encodedSort };
|
||||
};
|
||||
|
||||
export const isScanEntity = (entity: ScanEntity) => {
|
||||
return entity && entity.providerInfo && entity.attributes;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a scan details mapping for filters from completed scans.
|
||||
* Used to provide detailed information for scan filters in the UI.
|
||||
*/
|
||||
export const createScanDetailsMapping = (
|
||||
completedScans: ScanProps[],
|
||||
providersData?: ProvidersApiResponse,
|
||||
) => {
|
||||
if (!completedScans || completedScans.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const scanMappings = completedScans.map((scan: ScanProps) => {
|
||||
// Get provider info from providerInfo if available, or find from providers data
|
||||
let providerInfo = scan.providerInfo;
|
||||
|
||||
if (!providerInfo && scan.relationships?.provider?.data?.id) {
|
||||
const provider = providersData?.data?.find(
|
||||
(p: ProviderProps) => p.id === scan.relationships.provider.data.id,
|
||||
);
|
||||
if (provider) {
|
||||
providerInfo = {
|
||||
provider: provider.attributes.provider,
|
||||
alias: provider.attributes.alias,
|
||||
uid: provider.attributes.uid,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
[scan.id]: {
|
||||
providerInfo: {
|
||||
provider: providerInfo?.provider || "aws",
|
||||
alias: providerInfo?.alias,
|
||||
uid: providerInfo?.uid,
|
||||
},
|
||||
attributes: {
|
||||
name: scan.attributes.name,
|
||||
completed_at: scan.attributes.completed_at,
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
return scanMappings;
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {
|
||||
ProviderAccountProps,
|
||||
ProviderEntity,
|
||||
ProviderProps,
|
||||
ProvidersApiResponse,
|
||||
} from "@/types/providers";
|
||||
@@ -21,7 +21,7 @@ export const extractProviderUIDs = (
|
||||
export const createProviderDetailsMapping = (
|
||||
providerUIDs: string[],
|
||||
providersData: ProvidersApiResponse,
|
||||
): Array<{ [uid: string]: ProviderAccountProps }> => {
|
||||
): Array<{ [uid: string]: ProviderEntity }> => {
|
||||
if (!providersData?.data) return [];
|
||||
|
||||
return providerUIDs.map((uid) => {
|
||||
|
||||
Generated
+44
-44
@@ -37,7 +37,7 @@
|
||||
"jose": "^5.9.3",
|
||||
"jwt-decode": "^4.0.0",
|
||||
"lucide-react": "^0.471.0",
|
||||
"next": "^14.2.26",
|
||||
"next": "14.2.29",
|
||||
"next-auth": "^5.0.0-beta.25",
|
||||
"next-themes": "^0.2.1",
|
||||
"radix-ui": "^1.1.3",
|
||||
@@ -988,9 +988,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/env": {
|
||||
"version": "14.2.27",
|
||||
"resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.27.tgz",
|
||||
"integrity": "sha512-VLGHu7aBMK0rmSEPjx6qb4njGYfEfN5HpeYV32II1dNZZvPxqa+RfWVgPf4q6hmicavceAGeQneTxofx7Zm/yw==",
|
||||
"version": "14.2.29",
|
||||
"resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.29.tgz",
|
||||
"integrity": "sha512-UzgLR2eBfhKIQt0aJ7PWH7XRPYw7SXz0Fpzdl5THjUnvxy4kfBk9OU4RNPNiETewEEtaBcExNFNn1QWH8wQTjg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@next/eslint-plugin-next": {
|
||||
@@ -1004,9 +1004,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-darwin-arm64": {
|
||||
"version": "14.2.27",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.27.tgz",
|
||||
"integrity": "sha512-WKJsKqY1f8NkwcfVbUtoTjJ5e8Q2kEFhjM7tVFA3jqesetBR2EegUTed1Ov7lZebQ7XRrphAg665egiCLc9+Iw==",
|
||||
"version": "14.2.29",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.29.tgz",
|
||||
"integrity": "sha512-wWtrAaxCVMejxPHFb1SK/PVV1WDIrXGs9ki0C/kUM8ubKHQm+3hU9MouUywCw8Wbhj3pewfHT2wjunLEr/TaLA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1020,9 +1020,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-darwin-x64": {
|
||||
"version": "14.2.27",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.27.tgz",
|
||||
"integrity": "sha512-fsXAM07rt7FQ/dpPFk+YZ8LVQ48xP37KzPFAwdQFmVzNLgizdUyNSg9zwu7l0ziMtHFBofYgBXayg9qAxIhorQ==",
|
||||
"version": "14.2.29",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.29.tgz",
|
||||
"integrity": "sha512-7Z/jk+6EVBj4pNLw/JQrvZVrAh9Bv8q81zCFSfvTMZ51WySyEHWVpwCEaJY910LyBftv2F37kuDPQm0w9CEXyg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1036,9 +1036,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-arm64-gnu": {
|
||||
"version": "14.2.27",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.27.tgz",
|
||||
"integrity": "sha512-yMIvV5nTOk4p0TDhd9DU6QswEm8YjZnr1o9ZI7A6jh25JHvPsIvjgyTVSlnrGFKlNNtOOJCIv5mwVU7+4VZvsg==",
|
||||
"version": "14.2.29",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.29.tgz",
|
||||
"integrity": "sha512-o6hrz5xRBwi+G7JFTHc+RUsXo2lVXEfwh4/qsuWBMQq6aut+0w98WEnoNwAwt7hkEqegzvazf81dNiwo7KjITw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1052,9 +1052,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-arm64-musl": {
|
||||
"version": "14.2.27",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.27.tgz",
|
||||
"integrity": "sha512-gpOtTwE9GUkp+VNPwTYFn1fN1UINQTulbgO8UJzBgi77g/+T+yQxfBsKUy2H96aKjoMT/AYfn3yyomNXXVoZZg==",
|
||||
"version": "14.2.29",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.29.tgz",
|
||||
"integrity": "sha512-9i+JEHBOVgqxQ92HHRFlSW1EQXqa/89IVjtHgOqsShCcB/ZBjTtkWGi+SGCJaYyWkr/lzu51NTMCfKuBf7ULNw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1068,9 +1068,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-x64-gnu": {
|
||||
"version": "14.2.27",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.27.tgz",
|
||||
"integrity": "sha512-b7bogYfYyutEhyDST5qpBkmVENZz1mVOO2632KerJjwWgr2cdycAPU33VmpTVvTs/fT8+oeoUuZ31aQV6cUhpw==",
|
||||
"version": "14.2.29",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.29.tgz",
|
||||
"integrity": "sha512-B7JtMbkUwHijrGBOhgSQu2ncbCYq9E7PZ7MX58kxheiEOwdkM+jGx0cBb+rN5AeqF96JypEppK6i/bEL9T13lA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1084,9 +1084,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-x64-musl": {
|
||||
"version": "14.2.27",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.27.tgz",
|
||||
"integrity": "sha512-yGZX038wBDSRJ7tbZ6OFZtCUvLXZDVpw9rEgNUK/0PL++65hENaiMXhxJtupeCFqzHdMuJwrCnEW29saF4NmEw==",
|
||||
"version": "14.2.29",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.29.tgz",
|
||||
"integrity": "sha512-yCcZo1OrO3aQ38B5zctqKU1Z3klOohIxug6qdiKO3Q3qNye/1n6XIs01YJ+Uf+TdpZQ0fNrOQI2HrTLF3Zprnw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1100,9 +1100,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-win32-arm64-msvc": {
|
||||
"version": "14.2.27",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.27.tgz",
|
||||
"integrity": "sha512-yRY9RzPpk+Jex4DthdKja8C3evh6jB+22AeVd6yTbcnGAFGXQWJTs6DfEcEfeFpqIEcIGbWYq7pinz6vRv7tJA==",
|
||||
"version": "14.2.29",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.29.tgz",
|
||||
"integrity": "sha512-WnrfeOEtTVidI9Z6jDLy+gxrpDcEJtZva54LYC0bSKQqmyuHzl0ego+v0F/v2aXq0am67BRqo/ybmmt45Tzo4A==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1116,9 +1116,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-win32-ia32-msvc": {
|
||||
"version": "14.2.27",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.27.tgz",
|
||||
"integrity": "sha512-VSqDGpoKoUgkE2Ba4/89ZchktDOwPhKy3HgQgTf3gOhK/ZEibujLJN4qzp3rSIadn4cXUID3PmuEEM6uRPA7nQ==",
|
||||
"version": "14.2.29",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.29.tgz",
|
||||
"integrity": "sha512-vkcriFROT4wsTdSeIzbxaZjTNTFKjSYmLd8q/GVH3Dn8JmYjUKOuKXHK8n+lovW/kdcpIvydO5GtN+It2CvKWA==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
@@ -1132,9 +1132,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-win32-x64-msvc": {
|
||||
"version": "14.2.27",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.27.tgz",
|
||||
"integrity": "sha512-bK46G4uS5SVlq88FnxyupRuuaCfHPtB/7heBRAZCiHD9GdVktadjiQPCzlXWTKgv6pJxP8bE7J9GGDwodtn9Mw==",
|
||||
"version": "14.2.29",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.29.tgz",
|
||||
"integrity": "sha512-iPPwUEKnVs7pwR0EBLJlwxLD7TTHWS/AoVZx1l9ZQzfQciqaFEr5AlYzA2uB6Fyby1IF18t4PL0nTpB+k4Tzlw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -13169,12 +13169,12 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/next": {
|
||||
"version": "14.2.27",
|
||||
"resolved": "https://registry.npmjs.org/next/-/next-14.2.27.tgz",
|
||||
"integrity": "sha512-xmTsnu6rbXVaupRmU2k3BHVpQp7kK+/Ge9XYZlwXQNS2IPP/U9ToDoO6tTSzZIV36fmDBnwKqBUd7KuFXTi0Mw==",
|
||||
"version": "14.2.29",
|
||||
"resolved": "https://registry.npmjs.org/next/-/next-14.2.29.tgz",
|
||||
"integrity": "sha512-s98mCOMOWLGGpGOfgKSnleXLuegvvH415qtRZXpSp00HeEgdmrxmwL9cgKU+h4XrhB16zEI5d/7BnkS3ATInsA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@next/env": "14.2.27",
|
||||
"@next/env": "14.2.29",
|
||||
"@swc/helpers": "0.5.5",
|
||||
"busboy": "1.6.0",
|
||||
"caniuse-lite": "^1.0.30001579",
|
||||
@@ -13189,15 +13189,15 @@
|
||||
"node": ">=18.17.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@next/swc-darwin-arm64": "14.2.27",
|
||||
"@next/swc-darwin-x64": "14.2.27",
|
||||
"@next/swc-linux-arm64-gnu": "14.2.27",
|
||||
"@next/swc-linux-arm64-musl": "14.2.27",
|
||||
"@next/swc-linux-x64-gnu": "14.2.27",
|
||||
"@next/swc-linux-x64-musl": "14.2.27",
|
||||
"@next/swc-win32-arm64-msvc": "14.2.27",
|
||||
"@next/swc-win32-ia32-msvc": "14.2.27",
|
||||
"@next/swc-win32-x64-msvc": "14.2.27"
|
||||
"@next/swc-darwin-arm64": "14.2.29",
|
||||
"@next/swc-darwin-x64": "14.2.29",
|
||||
"@next/swc-linux-arm64-gnu": "14.2.29",
|
||||
"@next/swc-linux-arm64-musl": "14.2.29",
|
||||
"@next/swc-linux-x64-gnu": "14.2.29",
|
||||
"@next/swc-linux-x64-musl": "14.2.29",
|
||||
"@next/swc-win32-arm64-msvc": "14.2.29",
|
||||
"@next/swc-win32-ia32-msvc": "14.2.29",
|
||||
"@next/swc-win32-x64-msvc": "14.2.29"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@opentelemetry/api": "^1.1.0",
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@
|
||||
"jose": "^5.9.3",
|
||||
"jwt-decode": "^4.0.0",
|
||||
"lucide-react": "^0.471.0",
|
||||
"next": "^14.2.26",
|
||||
"next": "14.2.29",
|
||||
"next-auth": "^5.0.0-beta.25",
|
||||
"next-themes": "^0.2.1",
|
||||
"radix-ui": "^1.1.3",
|
||||
|
||||
+5
-2
@@ -1,10 +1,13 @@
|
||||
import { ProviderAccountProps } from "./providers";
|
||||
import { ProviderEntity } from "./providers";
|
||||
import { ScanEntity } from "./scans";
|
||||
|
||||
export type FilterEntity = ProviderEntity | ScanEntity;
|
||||
|
||||
export interface FilterOption {
|
||||
key: string;
|
||||
labelCheckboxGroup: string;
|
||||
values: string[];
|
||||
valueLabelMapping?: Array<{ [uid: string]: ProviderAccountProps }>;
|
||||
valueLabelMapping?: Array<{ [uid: string]: FilterEntity }>;
|
||||
index?: number;
|
||||
showSelectAll?: boolean;
|
||||
defaultToSelectAll?: boolean;
|
||||
|
||||
@@ -45,7 +45,7 @@ export interface ProviderProps {
|
||||
groupNames?: string[];
|
||||
}
|
||||
|
||||
export interface ProviderAccountProps {
|
||||
export interface ProviderEntity {
|
||||
provider: ProviderType;
|
||||
uid: string;
|
||||
alias: string | null;
|
||||
|
||||
@@ -47,3 +47,15 @@ export interface ScanProps {
|
||||
alias: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface ScanEntity {
|
||||
providerInfo: {
|
||||
provider: ProviderType;
|
||||
alias?: string;
|
||||
uid?: string;
|
||||
};
|
||||
attributes: {
|
||||
name?: string;
|
||||
completed_at: string;
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user