mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-01-25 02:08:11 +00:00
Compare commits
4 Commits
PRWLR-8424
...
5.1.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c172f75f1a | ||
|
|
ec492fa13a | ||
|
|
702659959c | ||
|
|
fef332a591 |
@@ -12,7 +12,7 @@ from prowler.lib.logger import logger
|
||||
|
||||
timestamp = datetime.today()
|
||||
timestamp_utc = datetime.now(timezone.utc).replace(tzinfo=timezone.utc)
|
||||
prowler_version = "5.1.0"
|
||||
prowler_version = "5.1.1"
|
||||
html_logo_url = "https://github.com/prowler-cloud/prowler/"
|
||||
square_logo_img = "https://prowler.com/wp-content/uploads/logo-html.png"
|
||||
aws_logo = "https://user-images.githubusercontent.com/38561120/235953920-3e3fba08-0795-41dc-b480-9bea57db9f2e.png"
|
||||
|
||||
@@ -12,6 +12,8 @@ class sqlserver_tde_encryption_enabled(Check):
|
||||
)
|
||||
if len(databases) > 0:
|
||||
for database in databases:
|
||||
if database.name.lower() == "master":
|
||||
continue
|
||||
report = Check_Report_Azure(self.metadata())
|
||||
report.subscription = subscription
|
||||
report.resource_name = database.name
|
||||
|
||||
@@ -23,7 +23,7 @@ packages = [
|
||||
{include = "dashboard"}
|
||||
]
|
||||
readme = "README.md"
|
||||
version = "5.1.0"
|
||||
version = "5.1.1"
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
alive-progress = "3.2.0"
|
||||
|
||||
@@ -177,3 +177,68 @@ class Test_sqlserver_tde_encryption_enabled:
|
||||
assert result[0].resource_name == database_name
|
||||
assert result[0].resource_id == database_id
|
||||
assert result[0].location == "location"
|
||||
|
||||
def test_sql_servers_database_encryption_disabled_on_master_db(self):
|
||||
sqlserver_client = mock.MagicMock
|
||||
sql_server_name = "SQL Server Name"
|
||||
sql_server_id = str(uuid4())
|
||||
database_master_name = "MASTER"
|
||||
database_master_id = str(uuid4())
|
||||
database_master = Database(
|
||||
id=database_master_id,
|
||||
name=database_master_name,
|
||||
type="type",
|
||||
location="location",
|
||||
managed_by="managed_by",
|
||||
tde_encryption=TransparentDataEncryption(status="Disabled"),
|
||||
)
|
||||
database_name = "Database Name"
|
||||
database_id = str(uuid4())
|
||||
database = Database(
|
||||
id=database_id,
|
||||
name=database_name,
|
||||
type="type",
|
||||
location="location",
|
||||
managed_by="managed_by",
|
||||
tde_encryption=TransparentDataEncryption(status="Enabled"),
|
||||
)
|
||||
sqlserver_client.sql_servers = {
|
||||
AZURE_SUBSCRIPTION_ID: [
|
||||
Server(
|
||||
id=sql_server_id,
|
||||
name=sql_server_name,
|
||||
public_network_access="",
|
||||
minimal_tls_version="",
|
||||
administrators=None,
|
||||
auditing_policies=None,
|
||||
firewall_rules=None,
|
||||
databases=[database_master, database],
|
||||
encryption_protector=None,
|
||||
location="location",
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_azure_provider(),
|
||||
), mock.patch(
|
||||
"prowler.providers.azure.services.sqlserver.sqlserver_tde_encryption_enabled.sqlserver_tde_encryption_enabled.sqlserver_client",
|
||||
new=sqlserver_client,
|
||||
):
|
||||
from prowler.providers.azure.services.sqlserver.sqlserver_tde_encryption_enabled.sqlserver_tde_encryption_enabled import (
|
||||
sqlserver_tde_encryption_enabled,
|
||||
)
|
||||
|
||||
check = sqlserver_tde_encryption_enabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"Database {database_name} from SQL Server {sql_server_name} from subscription {AZURE_SUBSCRIPTION_ID} has TDE enabled"
|
||||
)
|
||||
assert result[0].subscription == AZURE_SUBSCRIPTION_ID
|
||||
assert result[0].resource_name == database_name
|
||||
assert result[0].resource_id == database_id
|
||||
assert result[0].location == "location"
|
||||
|
||||
@@ -28,7 +28,11 @@ export const getFindings = async ({
|
||||
if (sort) url.searchParams.append("sort", sort);
|
||||
|
||||
Object.entries(filters).forEach(([key, value]) => {
|
||||
if (key !== "filter[search]") {
|
||||
const excludedFilters = ["region__in", "service__in", "resource_type__in"];
|
||||
if (
|
||||
key !== "filter[search]" &&
|
||||
!excludedFilters.some((filter) => key.includes(filter))
|
||||
) {
|
||||
url.searchParams.append(key, String(value));
|
||||
}
|
||||
});
|
||||
@@ -51,7 +55,7 @@ export const getFindings = async ({
|
||||
}
|
||||
};
|
||||
|
||||
export const getServicesRegions = async ({
|
||||
export const getMetadataInfo = async ({
|
||||
query = "",
|
||||
sort = "",
|
||||
filters = {},
|
||||
@@ -59,13 +63,18 @@ export const getServicesRegions = async ({
|
||||
const session = await auth();
|
||||
|
||||
const keyServer = process.env.API_BASE_URL;
|
||||
const url = new URL(`${keyServer}/findings/findings_services_regions`);
|
||||
const url = new URL(`${keyServer}/findings/metadata`);
|
||||
|
||||
if (query) url.searchParams.append("filter[search]", query);
|
||||
if (sort) url.searchParams.append("sort", sort);
|
||||
|
||||
Object.entries(filters).forEach(([key, value]) => {
|
||||
if (key !== "filter[search]") {
|
||||
// Define filters to exclude
|
||||
const excludedFilters = ["region__in", "service__in", "resource_type__in"];
|
||||
if (
|
||||
key !== "filter[search]" &&
|
||||
!excludedFilters.some((filter) => key.includes(filter))
|
||||
) {
|
||||
url.searchParams.append(key, String(value));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -81,25 +81,32 @@ export const addRole = async (formData: FormData) => {
|
||||
|
||||
const name = formData.get("name") as string;
|
||||
const groups = formData.getAll("groups[]") as string[];
|
||||
// Prepare base payload
|
||||
|
||||
const payload: any = {
|
||||
data: {
|
||||
type: "roles",
|
||||
attributes: {
|
||||
name,
|
||||
manage_users: formData.get("manage_users") === "true",
|
||||
manage_account: formData.get("manage_account") === "true",
|
||||
manage_billing: formData.get("manage_billing") === "true",
|
||||
manage_providers: formData.get("manage_providers") === "true",
|
||||
manage_integrations: formData.get("manage_integrations") === "true",
|
||||
manage_scans: formData.get("manage_scans") === "true",
|
||||
// TODO: Add back when we have integrations ready
|
||||
// manage_integrations: formData.get("manage_integrations") === "true",
|
||||
unlimited_visibility: formData.get("unlimited_visibility") === "true",
|
||||
},
|
||||
relationships: {},
|
||||
},
|
||||
};
|
||||
|
||||
// Add relationships only if there are items
|
||||
// Conditionally include manage_account and manage_billing for cloud environment
|
||||
if (process.env.NEXT_PUBLIC_IS_CLOUD_ENV === "true") {
|
||||
payload.data.attributes.manage_account =
|
||||
formData.get("manage_account") === "true";
|
||||
payload.data.attributes.manage_billing =
|
||||
formData.get("manage_billing") === "true";
|
||||
}
|
||||
|
||||
// Add provider groups relationships only if there are items
|
||||
if (groups.length > 0) {
|
||||
payload.data.relationships.provider_groups = {
|
||||
data: groups.map((groupId: string) => ({
|
||||
@@ -147,19 +154,27 @@ export const updateRole = async (formData: FormData, roleId: string) => {
|
||||
type: "roles",
|
||||
id: roleId,
|
||||
attributes: {
|
||||
...(name && { name }),
|
||||
...(name && { name }), // Include name only if provided
|
||||
manage_users: formData.get("manage_users") === "true",
|
||||
manage_account: formData.get("manage_account") === "true",
|
||||
manage_billing: formData.get("manage_billing") === "true",
|
||||
manage_providers: formData.get("manage_providers") === "true",
|
||||
manage_integrations: formData.get("manage_integrations") === "true",
|
||||
manage_scans: formData.get("manage_scans") === "true",
|
||||
// TODO: Add back when we have integrations ready
|
||||
// manage_integrations: formData.get("manage_integrations") === "true",
|
||||
unlimited_visibility: formData.get("unlimited_visibility") === "true",
|
||||
},
|
||||
relationships: {},
|
||||
},
|
||||
};
|
||||
|
||||
// Conditionally include manage_account and manage_billing for cloud environments
|
||||
if (process.env.NEXT_PUBLIC_IS_CLOUD_ENV === "true") {
|
||||
payload.data.attributes.manage_account =
|
||||
formData.get("manage_account") === "true";
|
||||
payload.data.attributes.manage_billing =
|
||||
formData.get("manage_billing") === "true";
|
||||
}
|
||||
|
||||
// Add provider groups relationships only if there are items
|
||||
if (groups.length > 0) {
|
||||
payload.data.relationships.provider_groups = {
|
||||
data: groups.map((groupId: string) => ({
|
||||
@@ -182,6 +197,7 @@ export const updateRole = async (formData: FormData, roleId: string) => {
|
||||
},
|
||||
body,
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
revalidatePath("/roles");
|
||||
return data;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Spacer } from "@nextui-org/react";
|
||||
import React, { Suspense } from "react";
|
||||
|
||||
import { getFindings, getServicesRegions } from "@/actions/findings";
|
||||
import { getFindings, getMetadataInfo } from "@/actions/findings";
|
||||
import { getProviders } from "@/actions/providers";
|
||||
import { getScans } from "@/actions/scans";
|
||||
import { filterFindings } from "@/components/filters/data-filters";
|
||||
@@ -47,15 +47,17 @@ export default async function Findings({
|
||||
|
||||
const query = filters["filter[search]"] || "";
|
||||
|
||||
const servicesRegionsData = await getServicesRegions({
|
||||
const metadataInfoData = await getMetadataInfo({
|
||||
query,
|
||||
sort: encodedSort,
|
||||
filters,
|
||||
});
|
||||
|
||||
// Extract unique regions and services from the new endpoint
|
||||
const uniqueRegions = servicesRegionsData?.data?.attributes?.regions || [];
|
||||
const uniqueServices = servicesRegionsData?.data?.attributes?.services || [];
|
||||
const uniqueRegions = metadataInfoData?.data?.attributes?.regions || [];
|
||||
const uniqueServices = metadataInfoData?.data?.attributes?.services || [];
|
||||
const uniqueResourceTypes =
|
||||
metadataInfoData?.data?.attributes?.resource_types || [];
|
||||
// Get findings data
|
||||
const providersData = await getProviders({});
|
||||
const scansData = await getScans({});
|
||||
@@ -72,7 +74,7 @@ export default async function Findings({
|
||||
// Extract scan UUIDs with "completed" state and more than one resource
|
||||
const completedScans = scansData?.data
|
||||
?.filter(
|
||||
(scan: any) =>
|
||||
(scan: ScanProps) =>
|
||||
scan.attributes.state === "completed" &&
|
||||
scan.attributes.unique_resource_count > 1,
|
||||
)
|
||||
@@ -104,6 +106,11 @@ export default async function Findings({
|
||||
labelCheckboxGroup: "Services",
|
||||
values: uniqueServices,
|
||||
},
|
||||
{
|
||||
key: "resource_type__in",
|
||||
labelCheckboxGroup: "Resource Type",
|
||||
values: uniqueResourceTypes,
|
||||
},
|
||||
{
|
||||
key: "provider_uid__in",
|
||||
labelCheckboxGroup: "Provider UID",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Alert, cn } from "@nextui-org/react";
|
||||
import React from "react";
|
||||
|
||||
import { InfoIcon } from "@/components/icons";
|
||||
import {
|
||||
UpdateViaCredentialsForm,
|
||||
UpdateViaRoleForm,
|
||||
@@ -17,33 +17,23 @@ export default function UpdateCredentialsPage({ searchParams }: Props) {
|
||||
{searchParams.type === "aws" && !searchParams.via && (
|
||||
<>
|
||||
<div className="flex flex-col gap-4">
|
||||
<p className="text-sm text-default-500">
|
||||
If the provider was set up with static credentials, updates must
|
||||
use static credentials. If it was set up with a role, updates must
|
||||
use a role.
|
||||
<p className="text-sm text-default-700">
|
||||
To update provider credentials,{" "}
|
||||
<strong>
|
||||
the same type that was originally configured must be used.
|
||||
</strong>
|
||||
</p>
|
||||
|
||||
<Alert
|
||||
color="warning"
|
||||
variant="faded"
|
||||
classNames={{
|
||||
base: cn([
|
||||
"border-1 border-default-200 dark:border-default-100",
|
||||
"gap-x-4",
|
||||
]),
|
||||
}}
|
||||
description={
|
||||
<>
|
||||
To update provider credentials,{" "}
|
||||
<strong>
|
||||
you must use the same type that was originally configured.
|
||||
</strong>{" "}
|
||||
</>
|
||||
}
|
||||
/>
|
||||
<p className="text-sm text-default-500">
|
||||
To switch from static credentials to a role (or vice versa), you
|
||||
need to delete the provider and set it up again.
|
||||
<div className="flex items-center rounded-lg border border-system-warning bg-system-warning-medium p-4 text-sm dark:text-default-300">
|
||||
<InfoIcon className="mr-2 inline h-4 w-4 flex-shrink-0" />
|
||||
<p>
|
||||
If the provider was configured with static credentials, updates
|
||||
must also use static credentials. If it was configured with a
|
||||
role, updates must use a role.
|
||||
</p>
|
||||
</div>
|
||||
<p className="text-sm text-default-700">
|
||||
To switch from static credentials to a role (or vice versa), the
|
||||
provider must be deleted and set up again.
|
||||
</p>
|
||||
<SelectViaAWS initialVia={searchParams.via} />
|
||||
</div>
|
||||
|
||||
@@ -66,17 +66,18 @@ export default async function Scans({
|
||||
<>
|
||||
<Spacer y={8} />
|
||||
<NoProvidersConnected />
|
||||
<Spacer y={4} />
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<LaunchScanWorkflow providers={providerInfo} />
|
||||
<Spacer y={4} />
|
||||
<ScanWarningBar />
|
||||
<Spacer y={8} />
|
||||
</>
|
||||
)}
|
||||
<div className="grid grid-cols-12 items-start gap-4">
|
||||
<div className="col-span-12">
|
||||
<ScanWarningBar />
|
||||
<Spacer y={4} />
|
||||
<div className="flex flex-row items-center justify-between">
|
||||
<DataTableFilterCustom filters={filterScans || []} />
|
||||
<ButtonRefreshData
|
||||
|
||||
@@ -33,13 +33,14 @@ export const AddRoleForm = ({
|
||||
defaultValues: {
|
||||
name: "",
|
||||
manage_users: false,
|
||||
manage_account: false,
|
||||
manage_billing: false,
|
||||
manage_providers: false,
|
||||
manage_integrations: false,
|
||||
manage_scans: false,
|
||||
unlimited_visibility: false,
|
||||
groups: [],
|
||||
...(process.env.NEXT_PUBLIC_IS_CLOUD_ENV === "true" && {
|
||||
manage_account: false,
|
||||
manage_billing: false,
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -64,7 +65,7 @@ export const AddRoleForm = ({
|
||||
"manage_account",
|
||||
"manage_billing",
|
||||
"manage_providers",
|
||||
"manage_integrations",
|
||||
// "manage_integrations",
|
||||
"manage_scans",
|
||||
"unlimited_visibility",
|
||||
];
|
||||
@@ -79,18 +80,22 @@ export const AddRoleForm = ({
|
||||
|
||||
const onSubmitClient = async (values: FormValues) => {
|
||||
const formData = new FormData();
|
||||
|
||||
formData.append("name", values.name);
|
||||
formData.append("manage_users", String(values.manage_users));
|
||||
formData.append("manage_account", String(values.manage_account));
|
||||
formData.append("manage_billing", String(values.manage_billing));
|
||||
formData.append("manage_providers", String(values.manage_providers));
|
||||
formData.append("manage_integrations", String(values.manage_integrations));
|
||||
formData.append("manage_scans", String(values.manage_scans));
|
||||
formData.append(
|
||||
"unlimited_visibility",
|
||||
String(values.unlimited_visibility),
|
||||
);
|
||||
|
||||
// Conditionally append manage_account and manage_billing
|
||||
if (process.env.NEXT_PUBLIC_IS_CLOUD_ENV === "true") {
|
||||
formData.append("manage_account", String(values.manage_account));
|
||||
formData.append("manage_billing", String(values.manage_billing));
|
||||
}
|
||||
|
||||
if (values.groups && values.groups.length > 0) {
|
||||
values.groups.forEach((group) => {
|
||||
formData.append("groups[]", group);
|
||||
|
||||
@@ -95,16 +95,21 @@ export const EditRoleForm = ({
|
||||
}
|
||||
|
||||
updatedFields.manage_users = values.manage_users;
|
||||
updatedFields.manage_account = values.manage_account;
|
||||
updatedFields.manage_billing = values.manage_billing;
|
||||
updatedFields.manage_providers = values.manage_providers;
|
||||
updatedFields.manage_integrations = values.manage_integrations;
|
||||
// updatedFields.manage_integrations = values.manage_integrations;
|
||||
updatedFields.manage_scans = values.manage_scans;
|
||||
updatedFields.unlimited_visibility = values.unlimited_visibility;
|
||||
|
||||
if (process.env.NEXT_PUBLIC_IS_CLOUD_ENV === "true") {
|
||||
updatedFields.manage_account = values.manage_account;
|
||||
updatedFields.manage_billing = values.manage_billing;
|
||||
}
|
||||
|
||||
if (
|
||||
JSON.stringify(values.groups) !==
|
||||
JSON.stringify(roleData.data.relationships?.provider_groups?.data)
|
||||
JSON.stringify(
|
||||
roleData.data.relationships?.provider_groups?.data.map((g) => g.id),
|
||||
)
|
||||
) {
|
||||
updatedFields.groups = values.groups;
|
||||
}
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
import { Alert, cn } from "@nextui-org/react";
|
||||
"use client";
|
||||
|
||||
import { InfoIcon } from "../icons";
|
||||
|
||||
export const ScanWarningBar = () => {
|
||||
return (
|
||||
<Alert
|
||||
color="warning"
|
||||
title="Waiting for Your Scan to Show Up?"
|
||||
description="Your scan is being processed and may take a few minutes to appear on the table. It will show up shortly."
|
||||
variant="faded"
|
||||
isClosable
|
||||
classNames={{
|
||||
base: cn([
|
||||
"border-1 border-default-200 dark:border-default-100",
|
||||
"gap-x-4",
|
||||
]),
|
||||
}}
|
||||
/>
|
||||
<div className="flex items-center rounded-lg border border-system-warning bg-system-warning-medium p-4 text-sm dark:text-default-300">
|
||||
<InfoIcon className="mr-4 inline h-4 w-4 flex-shrink-0" />
|
||||
<div className="flex flex-col gap-1">
|
||||
<strong>Waiting for Your Scan to Show Up?</strong>
|
||||
<p>
|
||||
It may take a few minutes for the scan to appear on the table and be
|
||||
displayed.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
6739
ui/package-lock.json
generated
6739
ui/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"@hookform/resolvers": "^3.9.0",
|
||||
"@nextui-org/react": "^2.6.11",
|
||||
"@nextui-org/react": "2.4.8",
|
||||
"@nextui-org/system": "2.2.1",
|
||||
"@nextui-org/theme": "2.2.5",
|
||||
"@radix-ui/react-alert-dialog": "^1.1.1",
|
||||
@@ -89,5 +89,8 @@
|
||||
"format:write": "./node_modules/.bin/prettier --config .prettierrc.json --write ./app",
|
||||
"prepare": "husky"
|
||||
},
|
||||
"overrides": {
|
||||
"@react-types/shared": "3.26.0"
|
||||
},
|
||||
"version": "0.0.1"
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ export const addRoleFormSchema = z.object({
|
||||
manage_account: z.boolean().default(false),
|
||||
manage_billing: z.boolean().default(false),
|
||||
manage_providers: z.boolean().default(false),
|
||||
manage_integrations: z.boolean().default(false),
|
||||
// manage_integrations: z.boolean().default(false),
|
||||
manage_scans: z.boolean().default(false),
|
||||
unlimited_visibility: z.boolean().default(false),
|
||||
groups: z.array(z.string()).optional(),
|
||||
@@ -18,7 +18,7 @@ export const editRoleFormSchema = z.object({
|
||||
manage_account: z.boolean().default(false),
|
||||
manage_billing: z.boolean().default(false),
|
||||
manage_providers: z.boolean().default(false),
|
||||
manage_integrations: z.boolean().default(false),
|
||||
// manage_integrations: z.boolean().default(false),
|
||||
manage_scans: z.boolean().default(false),
|
||||
unlimited_visibility: z.boolean().default(false),
|
||||
groups: z.array(z.string()).optional(),
|
||||
|
||||
Reference in New Issue
Block a user