feat(googleworkspace): add Drive and Docs service checks using Cloud Identity Policy API (#10648)

This commit is contained in:
lydiavilchez
2026-04-13 10:48:24 +02:00
committed by GitHub
parent 6534faf678
commit d919d979dd
53 changed files with 3160 additions and 17 deletions
+1
View File
@@ -18,6 +18,7 @@ All notable changes to the **Prowler SDK** are documented in this file.
- CISA SCuBA Google Workspace Baselines compliance [(#10466)](https://github.com/prowler-cloud/prowler/pull/10466)
- CIS Google Workspace Foundations Benchmark v1.3.0 compliance [(#10462)](https://github.com/prowler-cloud/prowler/pull/10462)
- `calendar_external_sharing_primary_calendar`, `calendar_external_sharing_secondary_calendar`, and `calendar_external_invitations_warning` checks for Google Workspace provider using the Cloud Identity Policy API [(#10597)](https://github.com/prowler-cloud/prowler/pull/10597)
- 11 Drive and Docs checks for Google Workspace provider (`drive_external_sharing_warn_users`, `drive_publishing_files_disabled`, `drive_sharing_allowlisted_domains`, `drive_warn_sharing_with_allowlisted_domains`, `drive_access_checker_recipients_only`, `drive_internal_users_distribute_content`, `drive_shared_drive_creation_allowed`, `drive_shared_drive_managers_cannot_override`, `drive_shared_drive_members_only_access`, `drive_shared_drive_disable_download_print_copy`, `drive_desktop_access_disabled`) using the Cloud Identity Policy API [(#10648)](https://github.com/prowler-cloud/prowler/pull/10648)
- `entra_conditional_access_policy_device_registration_mfa_required` check and `entra_intune_enrollment_sign_in_frequency_every_time` enhancement for M365 provider [(#10222)](https://github.com/prowler-cloud/prowler/pull/10222)
- `entra_conditional_access_policy_block_elevated_insider_risk` check for M365 provider [(#10234)](https://github.com/prowler-cloud/prowler/pull/10234)
- `Vercel` provider support with 30 checks [(#10189)](https://github.com/prowler-cloud/prowler/pull/10189)
@@ -230,7 +230,9 @@
{
"Id": "3.1.2.1.1.1",
"Description": "Ensure users are warned when they share a file outside their domain",
"Checks": [],
"Checks": [
"drive_external_sharing_warn_users"
],
"Attributes": [
{
"Section": "3 Apps",
@@ -251,7 +253,9 @@
{
"Id": "3.1.2.1.1.2",
"Description": "Ensure users cannot publish files to the web or make visible to the world as public or unlisted",
"Checks": [],
"Checks": [
"drive_publishing_files_disabled"
],
"Attributes": [
{
"Section": "3 Apps",
@@ -272,7 +276,9 @@
{
"Id": "3.1.2.1.1.3",
"Description": "Ensure document sharing is being controlled by domain with allowlists",
"Checks": [],
"Checks": [
"drive_sharing_allowlisted_domains"
],
"Attributes": [
{
"Section": "3 Apps",
@@ -293,7 +299,9 @@
{
"Id": "3.1.2.1.1.4",
"Description": "Ensure users are warned when they share a file with users in an allowlisted domain",
"Checks": [],
"Checks": [
"drive_warn_sharing_with_allowlisted_domains"
],
"Attributes": [
{
"Section": "3 Apps",
@@ -314,7 +322,9 @@
{
"Id": "3.1.2.1.1.5",
"Description": "Ensure Access Checker is configured to limit file access",
"Checks": [],
"Checks": [
"drive_access_checker_recipients_only"
],
"Attributes": [
{
"Section": "3 Apps",
@@ -335,7 +345,9 @@
{
"Id": "3.1.2.1.1.6",
"Description": "Ensure only users inside your organization can distribute content externally",
"Checks": [],
"Checks": [
"drive_internal_users_distribute_content"
],
"Attributes": [
{
"Section": "3 Apps",
@@ -356,7 +368,9 @@
{
"Id": "3.1.2.1.2.1",
"Description": "Ensure users can create new shared drives",
"Checks": [],
"Checks": [
"drive_shared_drive_creation_allowed"
],
"Attributes": [
{
"Section": "3 Apps",
@@ -377,7 +391,9 @@
{
"Id": "3.1.2.1.2.2",
"Description": "Ensure manager access members cannot modify shared drive settings",
"Checks": [],
"Checks": [
"drive_shared_drive_managers_cannot_override"
],
"Attributes": [
{
"Section": "3 Apps",
@@ -398,7 +414,9 @@
{
"Id": "3.1.2.1.2.3",
"Description": "Ensure shared drive file access is restricted to members only",
"Checks": [],
"Checks": [
"drive_shared_drive_members_only_access"
],
"Attributes": [
{
"Section": "3 Apps",
@@ -419,7 +437,9 @@
{
"Id": "3.1.2.1.2.4",
"Description": "Ensure viewers and commenters ability to download, print, and copy files is disabled",
"Checks": [],
"Checks": [
"drive_shared_drive_disable_download_print_copy"
],
"Attributes": [
{
"Section": "3 Apps",
@@ -461,7 +481,9 @@
{
"Id": "3.1.2.2.2",
"Description": "Ensure desktop access to Drive is disabled",
"Checks": [],
"Checks": [
"drive_desktop_access_disabled"
],
"Attributes": [
{
"Section": "3 Apps",
@@ -1089,7 +1089,9 @@
{
"Id": "GWS.DRIVEDOCS.1.1",
"Description": "External sharing SHALL be restricted to allowlisted domains",
"Checks": [],
"Checks": [
"drive_sharing_allowlisted_domains"
],
"Attributes": [
{
"Section": "Drive and Docs",
@@ -1115,7 +1117,9 @@
{
"Id": "GWS.DRIVEDOCS.1.3",
"Description": "Warnings SHALL be enabled when a user is attempting to share with someone not in allowlisted domains",
"Checks": [],
"Checks": [
"drive_warn_sharing_with_allowlisted_domains"
],
"Attributes": [
{
"Section": "Drive and Docs",
@@ -1141,7 +1145,9 @@
{
"Id": "GWS.DRIVEDOCS.1.5",
"Description": "Any OUs that do allow external sharing SHOULD disable making content available to anyone with the link",
"Checks": [],
"Checks": [
"drive_publishing_files_disabled"
],
"Attributes": [
{
"Section": "Drive and Docs",
@@ -1154,7 +1160,9 @@
{
"Id": "GWS.DRIVEDOCS.1.6",
"Description": "Agencies SHALL set access checking to recipients only",
"Checks": [],
"Checks": [
"drive_access_checker_recipients_only"
],
"Attributes": [
{
"Section": "Drive and Docs",
@@ -1193,7 +1201,9 @@
{
"Id": "GWS.DRIVEDOCS.1.9",
"Description": "Out-of-Domain file-level warnings SHALL be enabled",
"Checks": [],
"Checks": [
"drive_external_sharing_warn_users"
],
"Attributes": [
{
"Section": "Drive and Docs",
@@ -1232,7 +1242,9 @@
{
"Id": "GWS.DRIVEDOCS.2.1",
"Description": "Agencies SHOULD NOT allow members with manager access to override shared Google Drive creation settings",
"Checks": [],
"Checks": [
"drive_shared_drive_managers_cannot_override"
],
"Attributes": [
{
"Section": "Drive and Docs",
@@ -41,6 +41,22 @@ class GoogleWorkspaceService:
)
return None
@staticmethod
def _is_customer_level_policy(policy: dict) -> bool:
"""Check if a policy applies at the customer (domain-wide) level.
The Cloud Identity Policy API returns policies at multiple
organizational levels (customer, OU, group). Customer-level
policies have no group targeting and no sub-OU targeting in
their policyQuery.
"""
policy_query = policy.get("policyQuery", {})
if policy_query.get("group"):
return False
if policy_query.get("orgUnit"):
return False
return True
def _handle_api_error(self, error, context: str, resource_name: str = ""):
"""
Centralized Google Workspace API error handling.
@@ -0,0 +1,40 @@
{
"Provider": "googleworkspace",
"CheckID": "drive_access_checker_recipients_only",
"CheckTitle": "Drive Access Checker is configured to recipients only",
"CheckType": [],
"ServiceName": "drive",
"SubServiceName": "",
"ResourceIdTemplate": "",
"Severity": "medium",
"ResourceType": "NotDefined",
"ResourceGroup": "collaboration",
"Description": "The domain-wide Access Checker configuration ensures that when a user shares a Drive file via a Google product other than Drive itself (e.g. by pasting a link in Gmail), the suggestions never expand sharing to a wider audience or to anyone with the link. Access Checker is set to **recipients only**.",
"Risk": "If Access Checker suggests broader audiences or public visibility, users may **inadvertently widen access** to a file beyond the people they intended to share with. This is a common cause of unintentional internal or external over-sharing.",
"RelatedUrl": "",
"AdditionalURLs": [
"https://support.google.com/a/answer/60781",
"https://cloud.google.com/identity/docs/concepts/supported-policy-api-settings"
],
"Remediation": {
"Code": {
"CLI": "",
"NativeIaC": "",
"Other": "1. Sign in to the Google **Admin console** at https://admin.google.com\n2. Navigate to **Apps** > **Google Workspace** > **Drive and Docs**\n3. Click **Sharing settings** > **Sharing options**\n4. Under **Access Checker**, select **Recipients only**\n5. Click **Save**",
"Terraform": ""
},
"Recommendation": {
"Text": "Configure the Drive Access Checker to suggest sharing only with the explicit recipients of a link. This prevents accidental over-sharing through Gmail and other Google integrations.",
"Url": "https://hub.prowler.com/check/drive_access_checker_recipients_only"
}
},
"Categories": [
"internet-exposed"
],
"DependsOn": [],
"RelatedTo": [
"drive_external_sharing_warn_users",
"drive_publishing_files_disabled"
],
"Notes": ""
}
@@ -0,0 +1,55 @@
from typing import List
from prowler.lib.check.models import Check, CheckReportGoogleWorkspace
from prowler.providers.googleworkspace.services.drive.drive_client import drive_client
class drive_access_checker_recipients_only(Check):
"""Check that Access Checker is configured to recipients only
This check verifies that the domain-level Drive and Docs Access Checker
setting suggests granting access only to the explicit recipients of a
shared link, rather than expanding access to wider audiences or making
files publicly accessible.
"""
def execute(self) -> List[CheckReportGoogleWorkspace]:
findings = []
if drive_client.policies_fetched:
report = CheckReportGoogleWorkspace(
metadata=self.metadata(),
resource=drive_client.provider.identity,
resource_name=drive_client.provider.identity.domain,
resource_id=drive_client.provider.identity.customer_id,
customer_id=drive_client.provider.identity.customer_id,
location="global",
)
access_checker = drive_client.policies.access_checker_suggestions
if access_checker == "RECIPIENTS_ONLY":
report.status = "PASS"
report.status_extended = (
f"Drive and Docs Access Checker in domain "
f"{drive_client.provider.identity.domain} is restricted to "
f"recipients only."
)
else:
report.status = "FAIL"
if access_checker is None:
report.status_extended = (
f"Drive and Docs Access Checker is not explicitly "
f"configured in domain {drive_client.provider.identity.domain}. "
f"Access Checker should be set to recipients only."
)
else:
report.status_extended = (
f"Drive and Docs Access Checker in domain "
f"{drive_client.provider.identity.domain} is set to "
f"{access_checker}. Access Checker should be set to recipients only."
)
findings.append(report)
return findings
@@ -0,0 +1,4 @@
from prowler.providers.common.provider import Provider
from prowler.providers.googleworkspace.services.drive.drive_service import Drive
drive_client = Drive(Provider.get_global_provider())
@@ -0,0 +1,35 @@
{
"Provider": "googleworkspace",
"CheckID": "drive_desktop_access_disabled",
"CheckTitle": "Google Drive for desktop is disabled",
"CheckType": [],
"ServiceName": "drive",
"SubServiceName": "",
"ResourceIdTemplate": "",
"Severity": "medium",
"ResourceType": "NotDefined",
"ResourceGroup": "collaboration",
"Description": "The domain-wide default **disables Google Drive for desktop** for the organization. The Drive for desktop client synchronizes Drive content to local devices and uses its own \"offline\" mechanism that does not respect the central offline-access device policy, so disabling it closes a synchronization channel that would otherwise place organizational content on potentially unmanaged endpoints.",
"Risk": "When Drive for desktop is enabled, organizational files are **synchronized to local devices** and remain accessible if the device is lost, stolen, or compromised. Because Drive for desktop bypasses the central offline-access controls, this channel is a frequently overlooked path for sensitive data to leave organization-managed environments.",
"RelatedUrl": "",
"AdditionalURLs": [
"https://support.google.com/a/answer/7491144",
"https://cloud.google.com/identity/docs/concepts/supported-policy-api-settings"
],
"Remediation": {
"Code": {
"CLI": "",
"NativeIaC": "",
"Other": "1. Sign in to the Google **Admin console** at https://admin.google.com\n2. Navigate to **Apps** > **Google Workspace** > **Drive and Docs**\n3. Click **Features and Applications** > **Google Drive for desktop**\n4. **Uncheck** *Allow Google Drive for desktop in your organization*\n5. Click **Save**",
"Terraform": ""
},
"Recommendation": {
"Text": "Disable Google Drive for desktop to prevent local synchronization of organizational content. This reduces the risk of data loss when devices are lost or stolen and closes a channel that bypasses central offline-access controls.",
"Url": "https://hub.prowler.com/check/drive_desktop_access_disabled"
}
},
"Categories": [],
"DependsOn": [],
"RelatedTo": [],
"Notes": ""
}
@@ -0,0 +1,57 @@
from typing import List
from prowler.lib.check.models import Check, CheckReportGoogleWorkspace
from prowler.providers.googleworkspace.services.drive.drive_client import drive_client
class drive_desktop_access_disabled(Check):
"""Check that Google Drive for desktop is disabled
This check verifies that the domain-level Drive and Docs policy disables
Google Drive for desktop. The desktop client synchronizes Drive content
to local devices and bypasses the standard offline access controls,
so disabling it reduces the risk of organizational data being lost or
stolen along with an end-user device.
"""
def execute(self) -> List[CheckReportGoogleWorkspace]:
findings = []
if drive_client.policies_fetched:
report = CheckReportGoogleWorkspace(
metadata=self.metadata(),
resource=drive_client.provider.identity,
resource_name=drive_client.provider.identity.domain,
resource_id=drive_client.provider.identity.customer_id,
customer_id=drive_client.provider.identity.customer_id,
location="global",
)
allow_desktop = drive_client.policies.allow_drive_for_desktop
if allow_desktop is False:
report.status = "PASS"
report.status_extended = (
f"Google Drive for desktop is disabled in domain "
f"{drive_client.provider.identity.domain}."
)
else:
report.status = "FAIL"
if allow_desktop is None:
report.status_extended = (
f"Google Drive for desktop is not explicitly configured "
f"in domain {drive_client.provider.identity.domain}. "
f"Drive for desktop should be disabled to prevent local "
f"synchronization of organizational content."
)
else:
report.status_extended = (
f"Google Drive for desktop is enabled in domain "
f"{drive_client.provider.identity.domain}. "
f"Drive for desktop should be disabled to prevent local "
f"synchronization of organizational content."
)
findings.append(report)
return findings
@@ -0,0 +1,43 @@
{
"Provider": "googleworkspace",
"CheckID": "drive_external_sharing_warn_users",
"CheckTitle": "Users are warned when sharing files outside the domain",
"CheckType": [],
"ServiceName": "drive",
"SubServiceName": "",
"ResourceIdTemplate": "",
"Severity": "medium",
"ResourceType": "NotDefined",
"ResourceGroup": "collaboration",
"Description": "The domain-wide Drive and Docs configuration **warns users** when they attempt to share a file with users outside the organization. This prompt gives users an opportunity to reconsider before exposing organizational content to external parties, reducing the likelihood of **accidental data disclosure** through everyday sharing actions.",
"Risk": "Without external sharing warnings, users may unintentionally share **sensitive documents** with external recipients who are not entitled to the data. This is a common vector for inadvertent leakage of intellectual property, personally identifiable information, and confidential business data through routine Drive sharing.",
"RelatedUrl": "",
"AdditionalURLs": [
"https://support.google.com/a/answer/60781",
"https://cloud.google.com/identity/docs/concepts/supported-policy-api-settings"
],
"Remediation": {
"Code": {
"CLI": "",
"NativeIaC": "",
"Other": "1. Sign in to the Google **Admin console** at https://admin.google.com\n2. Navigate to **Apps** > **Google Workspace** > **Drive and Docs**\n3. Click **Sharing settings** > **Sharing options**\n4. Under **Sharing outside of <Company>**, ensure sharing outside the domain is allowed and check **For files owned by users in <Company> warn when sharing outside of <Company>**\n5. Click **Save**",
"Terraform": ""
},
"Recommendation": {
"Text": "Enable external sharing warnings so users are notified whenever they attempt to share a file outside the organization. This simple prompt helps prevent accidental disclosure of sensitive content to unintended recipients.",
"Url": "https://hub.prowler.com/check/drive_external_sharing_warn_users"
}
},
"Categories": [
"internet-exposed"
],
"DependsOn": [],
"RelatedTo": [
"drive_publishing_files_disabled",
"drive_sharing_allowlisted_domains",
"drive_warn_sharing_with_allowlisted_domains",
"drive_access_checker_recipients_only",
"drive_internal_users_distribute_content"
],
"Notes": ""
}
@@ -0,0 +1,54 @@
from typing import List
from prowler.lib.check.models import Check, CheckReportGoogleWorkspace
from prowler.providers.googleworkspace.services.drive.drive_client import drive_client
class drive_external_sharing_warn_users(Check):
"""Check that users are warned when sharing files outside the domain
This check verifies that the domain-level Drive and Docs policy warns
users when they attempt to share a file with someone outside the
organization, reducing the risk of accidental information disclosure.
"""
def execute(self) -> List[CheckReportGoogleWorkspace]:
findings = []
if drive_client.policies_fetched:
report = CheckReportGoogleWorkspace(
metadata=self.metadata(),
resource=drive_client.provider.identity,
resource_name=drive_client.provider.identity.domain,
resource_id=drive_client.provider.identity.customer_id,
customer_id=drive_client.provider.identity.customer_id,
location="global",
)
warning_enabled = drive_client.policies.warn_for_external_sharing
if warning_enabled is True:
report.status = "PASS"
report.status_extended = (
f"External sharing warnings for Drive and Docs are enabled "
f"in domain {drive_client.provider.identity.domain}."
)
else:
report.status = "FAIL"
if warning_enabled is None:
report.status_extended = (
f"External sharing warnings for Drive and Docs are not "
f"explicitly configured in domain "
f"{drive_client.provider.identity.domain}. "
f"Users should be warned when sharing files outside the organization."
)
else:
report.status_extended = (
f"External sharing warnings for Drive and Docs are disabled "
f"in domain {drive_client.provider.identity.domain}. "
f"Users should be warned when sharing files outside the organization."
)
findings.append(report)
return findings
@@ -0,0 +1,40 @@
{
"Provider": "googleworkspace",
"CheckID": "drive_internal_users_distribute_content",
"CheckTitle": "Only internal users can distribute content outside the organization",
"CheckType": [],
"ServiceName": "drive",
"SubServiceName": "",
"ResourceIdTemplate": "",
"Severity": "medium",
"ResourceType": "NotDefined",
"ResourceGroup": "collaboration",
"Description": "The domain-wide default restricts distributing organizational content to shared drives owned by **another organization** to eligible **internal users** only. This prevents external collaborators with manager access to internal shared drives from moving content out of the organization.",
"Risk": "If external users can move files from internal shared drives into shared drives owned by another organization, the organization **loses authoritative control** over its own data. This is a frequently overlooked path for unintentional or malicious data exfiltration through shared drive collaboration.",
"RelatedUrl": "",
"AdditionalURLs": [
"https://support.google.com/a/answer/60781",
"https://cloud.google.com/identity/docs/concepts/supported-policy-api-settings"
],
"Remediation": {
"Code": {
"CLI": "",
"NativeIaC": "",
"Other": "1. Sign in to the Google **Admin console** at https://admin.google.com\n2. Navigate to **Apps** > **Google Workspace** > **Drive and Docs**\n3. Click **Sharing settings** > **Sharing options**\n4. Under **Distributing content outside of <Company>**, select **Only users in <Company>**\n5. Click **Save**",
"Terraform": ""
},
"Recommendation": {
"Text": "Restrict the ability to distribute content to shared drives owned by another organization to internal users only. This preserves authoritative control over organizational data and closes a common shared-drive exfiltration path.",
"Url": "https://hub.prowler.com/check/drive_internal_users_distribute_content"
}
},
"Categories": [
"internet-exposed"
],
"DependsOn": [],
"RelatedTo": [
"drive_external_sharing_warn_users",
"drive_publishing_files_disabled"
],
"Notes": ""
}
@@ -0,0 +1,56 @@
from typing import List
from prowler.lib.check.models import Check, CheckReportGoogleWorkspace
from prowler.providers.googleworkspace.services.drive.drive_client import drive_client
class drive_internal_users_distribute_content(Check):
"""Check that only internal users can distribute content externally
This check verifies that the domain-level Drive and Docs policy restricts
distributing content to shared drives owned by another organization to
eligible internal users only, preventing external collaborators from
moving organizational content out of the domain.
"""
def execute(self) -> List[CheckReportGoogleWorkspace]:
findings = []
if drive_client.policies_fetched:
report = CheckReportGoogleWorkspace(
metadata=self.metadata(),
resource=drive_client.provider.identity,
resource_name=drive_client.provider.identity.domain,
resource_id=drive_client.provider.identity.customer_id,
customer_id=drive_client.provider.identity.customer_id,
location="global",
)
allowed = drive_client.policies.allowed_parties_for_distributing_content
if allowed in ("ELIGIBLE_INTERNAL_USERS", "NONE"):
report.status = "PASS"
report.status_extended = (
f"Distributing content outside the organization in domain "
f"{drive_client.provider.identity.domain} is restricted to "
f"{allowed}."
)
else:
report.status = "FAIL"
if allowed is None:
report.status_extended = (
f"Allowed parties for distributing content externally is not "
f"explicitly configured in domain "
f"{drive_client.provider.identity.domain}. "
f"Only internal users should be allowed to distribute content externally."
)
else:
report.status_extended = (
f"Distributing content outside the organization in domain "
f"{drive_client.provider.identity.domain} is set to {allowed}. "
f"Only internal users should be allowed to distribute content externally."
)
findings.append(report)
return findings
@@ -0,0 +1,41 @@
{
"Provider": "googleworkspace",
"CheckID": "drive_publishing_files_disabled",
"CheckTitle": "Publishing Drive files to the web is disabled",
"CheckType": [],
"ServiceName": "drive",
"SubServiceName": "",
"ResourceIdTemplate": "",
"Severity": "medium",
"ResourceType": "NotDefined",
"ResourceGroup": "collaboration",
"Description": "The domain-wide Drive and Docs default **prevents users from publishing files to the web** or making them visible to the world as public or unlisted. Publishing a file to the web exposes its content to anyone on the internet, often without any audit trail, making it one of the highest-impact misconfigurations available to end users.",
"Risk": "Allowing users to publish Drive files to the web creates a path for **unbounded data exposure**. Sensitive documents, intellectual property, customer data, or internal communications can be made publicly accessible — and indexed by search engines — with a single click, often unintentionally.",
"RelatedUrl": "",
"AdditionalURLs": [
"https://support.google.com/a/answer/60781",
"https://cloud.google.com/identity/docs/concepts/supported-policy-api-settings"
],
"Remediation": {
"Code": {
"CLI": "",
"NativeIaC": "",
"Other": "1. Sign in to the Google **Admin console** at https://admin.google.com\n2. Navigate to **Apps** > **Google Workspace** > **Drive and Docs**\n3. Click **Sharing settings** > **Sharing options**\n4. Under **Sharing outside of <Company>**, **uncheck** *When sharing outside of <Company> is allowed, users in <Company> can make files and published web content visible to anyone with the link*\n5. Click **Save**",
"Terraform": ""
},
"Recommendation": {
"Text": "Disable the ability for users to publish Drive files to the web or make them visible to anyone with the link. This eliminates the most direct path to unintentional public data exposure through Drive.",
"Url": "https://hub.prowler.com/check/drive_publishing_files_disabled"
}
},
"Categories": [
"internet-exposed"
],
"DependsOn": [],
"RelatedTo": [
"drive_external_sharing_warn_users",
"drive_sharing_allowlisted_domains",
"drive_internal_users_distribute_content"
],
"Notes": ""
}
@@ -0,0 +1,54 @@
from typing import List
from prowler.lib.check.models import Check, CheckReportGoogleWorkspace
from prowler.providers.googleworkspace.services.drive.drive_client import drive_client
class drive_publishing_files_disabled(Check):
"""Check that publishing Drive files to the web is disabled
This check verifies that the domain-level Drive and Docs policy prevents
users from publishing files to the web or making them visible to anyone
with the link, blocking unintended public exposure of organizational
content.
"""
def execute(self) -> List[CheckReportGoogleWorkspace]:
findings = []
if drive_client.policies_fetched:
report = CheckReportGoogleWorkspace(
metadata=self.metadata(),
resource=drive_client.provider.identity,
resource_name=drive_client.provider.identity.domain,
resource_id=drive_client.provider.identity.customer_id,
customer_id=drive_client.provider.identity.customer_id,
location="global",
)
allow_publishing = drive_client.policies.allow_publishing_files
if allow_publishing is False:
report.status = "PASS"
report.status_extended = (
f"Publishing files to the web is disabled in domain "
f"{drive_client.provider.identity.domain}."
)
else:
report.status = "FAIL"
if allow_publishing is None:
report.status_extended = (
f"Publishing files to the web is not explicitly configured "
f"in domain {drive_client.provider.identity.domain}. "
f"Users should not be able to publish files to the web or make them public."
)
else:
report.status_extended = (
f"Publishing files to the web is enabled in domain "
f"{drive_client.provider.identity.domain}. "
f"Users should not be able to publish files to the web or make them public."
)
findings.append(report)
return findings
@@ -0,0 +1,150 @@
from typing import Optional
from pydantic import BaseModel
from prowler.lib.logger import logger
from prowler.providers.googleworkspace.lib.service.service import GoogleWorkspaceService
class Drive(GoogleWorkspaceService):
"""Google Workspace Drive and Docs service for auditing domain-level Drive policies.
Uses the Cloud Identity Policy API v1 to read Drive and Docs sharing,
shared drive creation, and Drive for desktop settings configured in the
Admin Console.
"""
def __init__(self, provider):
super().__init__(provider)
self.policies = DrivePolicies()
self.policies_fetched = False
self._fetch_drive_policies()
def _fetch_drive_policies(self):
"""Fetch Drive and Docs policies from the Cloud Identity Policy API v1."""
logger.info("Drive - Fetching Drive and Docs policies...")
try:
service = self._build_service("cloudidentity", "v1")
if not service:
logger.error("Failed to build Cloud Identity service")
return
request = service.policies().list(pageSize=100)
fetch_succeeded = True
while request is not None:
try:
response = request.execute()
for policy in response.get("policies", []):
if not self._is_customer_level_policy(policy):
continue
setting = policy.get("setting", {})
setting_type = setting.get("type", "").removeprefix("settings/")
value = setting.get("value", {})
if setting_type == "drive_and_docs.external_sharing":
self.policies.external_sharing_mode = value.get(
"externalSharingMode"
)
self.policies.warn_for_external_sharing = value.get(
"warnForExternalSharing"
)
self.policies.warn_for_sharing_outside_allowlisted_domains = value.get(
"warnForSharingOutsideAllowlistedDomains"
)
self.policies.allow_publishing_files = value.get(
"allowPublishingFiles"
)
self.policies.access_checker_suggestions = value.get(
"accessCheckerSuggestions"
)
self.policies.allowed_parties_for_distributing_content = (
value.get("allowedPartiesForDistributingContent")
)
logger.debug(
"Drive external sharing settings fetched: "
f"mode={self.policies.external_sharing_mode}, "
f"warn={self.policies.warn_for_external_sharing}, "
f"publish={self.policies.allow_publishing_files}"
)
elif setting_type == "drive_and_docs.shared_drive_creation":
self.policies.allow_shared_drive_creation = value.get(
"allowSharedDriveCreation"
)
self.policies.allow_managers_to_override_settings = (
value.get("allowManagersToOverrideSettings")
)
self.policies.allow_non_member_access = value.get(
"allowNonMemberAccess"
)
self.policies.allowed_parties_for_download_print_copy = (
value.get("allowedPartiesForDownloadPrintCopy")
)
logger.debug(
"Drive shared drive creation settings fetched: "
f"creation={self.policies.allow_shared_drive_creation}, "
f"managers_override={self.policies.allow_managers_to_override_settings}"
)
elif setting_type == "drive_and_docs.drive_for_desktop":
self.policies.allow_drive_for_desktop = value.get(
"allowDriveForDesktop"
)
logger.debug(
"Drive for desktop setting fetched: "
f"{self.policies.allow_drive_for_desktop}"
)
request = service.policies().list_next(request, response)
except Exception as error:
self._handle_api_error(
error,
"fetching Drive and Docs policies",
self.provider.identity.customer_id,
)
fetch_succeeded = False
break
self.policies_fetched = fetch_succeeded
logger.info(
f"Drive and Docs policies fetched - "
f"External sharing mode: {self.policies.external_sharing_mode}, "
f"Shared drive creation: {self.policies.allow_shared_drive_creation}, "
f"Drive for desktop: {self.policies.allow_drive_for_desktop}"
)
except Exception as error:
self._handle_api_error(
error,
"fetching Drive and Docs policies",
self.provider.identity.customer_id,
)
self.policies_fetched = False
class DrivePolicies(BaseModel):
"""Model for domain-level Drive and Docs policy settings."""
# drive_and_docs.external_sharing
external_sharing_mode: Optional[str] = None
warn_for_external_sharing: Optional[bool] = None
warn_for_sharing_outside_allowlisted_domains: Optional[bool] = None
allow_publishing_files: Optional[bool] = None
access_checker_suggestions: Optional[str] = None
allowed_parties_for_distributing_content: Optional[str] = None
# drive_and_docs.shared_drive_creation
allow_shared_drive_creation: Optional[bool] = None
allow_managers_to_override_settings: Optional[bool] = None
allow_non_member_access: Optional[bool] = None
allowed_parties_for_download_print_copy: Optional[str] = None
# drive_and_docs.drive_for_desktop
allow_drive_for_desktop: Optional[bool] = None
@@ -0,0 +1,39 @@
{
"Provider": "googleworkspace",
"CheckID": "drive_shared_drive_creation_allowed",
"CheckTitle": "Users are allowed to create new shared drives",
"CheckType": [],
"ServiceName": "drive",
"SubServiceName": "",
"ResourceIdTemplate": "",
"Severity": "medium",
"ResourceType": "NotDefined",
"ResourceGroup": "collaboration",
"Description": "The domain-wide default **allows users to create new shared drives**. Shared drives are owned by the organization (not the individual user), so content stored in them survives the deletion of the original creator's account, supporting data continuity and reducing the risk of accidental data loss.",
"Risk": "When users cannot create shared drives, they store collaborative content in their personal **My Drive** instead. When that user account is deleted, the data is also deleted, leading to **unintentional data loss** of organizationally significant information. Allowing shared drive creation makes data survivable across account lifecycle events.",
"RelatedUrl": "",
"AdditionalURLs": [
"https://support.google.com/a/answer/7212025",
"https://cloud.google.com/identity/docs/concepts/supported-policy-api-settings"
],
"Remediation": {
"Code": {
"CLI": "",
"NativeIaC": "",
"Other": "1. Sign in to the Google **Admin console** at https://admin.google.com\n2. Navigate to **Apps** > **Google Workspace** > **Drive and Docs**\n3. Click **Sharing settings** > **Shared drive creation**\n4. **Uncheck** *Prevent users in <Company> from creating new shared drives*\n5. Click **Save**",
"Terraform": ""
},
"Recommendation": {
"Text": "Allow users to create new shared drives. This protects the organization from data loss when user accounts are deleted by ensuring collaborative content lives in organization-owned shared drives instead of personal My Drive folders.",
"Url": "https://hub.prowler.com/check/drive_shared_drive_creation_allowed"
}
},
"Categories": [],
"DependsOn": [],
"RelatedTo": [
"drive_shared_drive_managers_cannot_override",
"drive_shared_drive_members_only_access",
"drive_shared_drive_disable_download_print_copy"
],
"Notes": ""
}
@@ -0,0 +1,57 @@
from typing import List
from prowler.lib.check.models import Check, CheckReportGoogleWorkspace
from prowler.providers.googleworkspace.services.drive.drive_client import drive_client
class drive_shared_drive_creation_allowed(Check):
"""Check that users are allowed to create new shared drives
This check verifies that the domain-level Drive and Docs policy permits
users to create new shared drives. Allowing shared drive creation helps
prevent data loss when individual user accounts are deleted, since
content lives in shared drives owned by the organization rather than
in personal My Drive folders.
"""
def execute(self) -> List[CheckReportGoogleWorkspace]:
findings = []
if drive_client.policies_fetched:
report = CheckReportGoogleWorkspace(
metadata=self.metadata(),
resource=drive_client.provider.identity,
resource_name=drive_client.provider.identity.domain,
resource_id=drive_client.provider.identity.customer_id,
customer_id=drive_client.provider.identity.customer_id,
location="global",
)
allow_creation = drive_client.policies.allow_shared_drive_creation
if allow_creation is True:
report.status = "PASS"
report.status_extended = (
f"Users in domain {drive_client.provider.identity.domain} "
f"are allowed to create new shared drives."
)
else:
report.status = "FAIL"
if allow_creation is None:
report.status_extended = (
f"Shared drive creation is not explicitly configured in "
f"domain {drive_client.provider.identity.domain}. "
f"Users should be allowed to create new shared drives to avoid "
f"data loss when accounts are deleted."
)
else:
report.status_extended = (
f"Users in domain {drive_client.provider.identity.domain} "
f"are prevented from creating new shared drives. "
f"Users should be allowed to create new shared drives to avoid "
f"data loss when accounts are deleted."
)
findings.append(report)
return findings
@@ -0,0 +1,39 @@
{
"Provider": "googleworkspace",
"CheckID": "drive_shared_drive_disable_download_print_copy",
"CheckTitle": "Viewers and commenters cannot download, print, or copy shared drive files",
"CheckType": [],
"ServiceName": "drive",
"SubServiceName": "",
"ResourceIdTemplate": "",
"Severity": "medium",
"ResourceType": "NotDefined",
"ResourceGroup": "collaboration",
"Description": "The domain-wide default prevents viewers and commenters of files stored in shared drives from **downloading, printing, or copying** the file contents. They can only read and comment on the existing content, preventing bulk extraction of sensitive material from shared drives.",
"Risk": "When viewers and commenters can download, print, or copy shared drive files, they can **bulk-extract sensitive content** — including intellectual property, personally identifiable information, and confidential business documents — using nothing more than read access. This is one of the most direct paths to data exfiltration through Drive.",
"RelatedUrl": "",
"AdditionalURLs": [
"https://support.google.com/a/answer/7662202",
"https://cloud.google.com/identity/docs/concepts/supported-policy-api-settings"
],
"Remediation": {
"Code": {
"CLI": "",
"NativeIaC": "",
"Other": "1. Sign in to the Google **Admin console** at https://admin.google.com\n2. Navigate to **Apps** > **Google Workspace** > **Drive and Docs**\n3. Click **Sharing settings** > **Shared drive creation**\n4. **Uncheck** *Allow viewers and commenters to download, print, and copy files*\n5. Click **Save**",
"Terraform": ""
},
"Recommendation": {
"Text": "Restrict download, print, and copy actions in shared drives to editors or managers only. This prevents bulk data exfiltration by users who only need read or comment access to the underlying content.",
"Url": "https://hub.prowler.com/check/drive_shared_drive_disable_download_print_copy"
}
},
"Categories": [],
"DependsOn": [],
"RelatedTo": [
"drive_shared_drive_creation_allowed",
"drive_shared_drive_managers_cannot_override",
"drive_shared_drive_members_only_access"
],
"Notes": ""
}
@@ -0,0 +1,56 @@
from typing import List
from prowler.lib.check.models import Check, CheckReportGoogleWorkspace
from prowler.providers.googleworkspace.services.drive.drive_client import drive_client
class drive_shared_drive_disable_download_print_copy(Check):
"""Check that download/print/copy is disabled for viewers and commenters
This check verifies that the domain-level Drive and Docs policy prevents
viewers and commenters of shared drive files from downloading, printing,
or copying their contents — limiting them to read and comment actions
only and reducing the risk of bulk data exfiltration.
"""
def execute(self) -> List[CheckReportGoogleWorkspace]:
findings = []
if drive_client.policies_fetched:
report = CheckReportGoogleWorkspace(
metadata=self.metadata(),
resource=drive_client.provider.identity,
resource_name=drive_client.provider.identity.domain,
resource_id=drive_client.provider.identity.customer_id,
customer_id=drive_client.provider.identity.customer_id,
location="global",
)
allowed = drive_client.policies.allowed_parties_for_download_print_copy
if allowed in ("EDITORS_ONLY", "MANAGERS_ONLY"):
report.status = "PASS"
report.status_extended = (
f"Download, print, and copy in shared drives in domain "
f"{drive_client.provider.identity.domain} is restricted to "
f"{allowed}."
)
else:
report.status = "FAIL"
if allowed is None:
report.status_extended = (
f"Download, print, and copy restrictions for shared drive "
f"viewers and commenters are not explicitly configured in "
f"domain {drive_client.provider.identity.domain}. "
f"These actions should be restricted to editors or managers only."
)
else:
report.status_extended = (
f"Download, print, and copy in shared drives in domain "
f"{drive_client.provider.identity.domain} is set to {allowed}. "
f"These actions should be restricted to editors or managers only."
)
findings.append(report)
return findings
@@ -0,0 +1,39 @@
{
"Provider": "googleworkspace",
"CheckID": "drive_shared_drive_managers_cannot_override",
"CheckTitle": "Shared drive managers cannot override shared drive settings",
"CheckType": [],
"ServiceName": "drive",
"SubServiceName": "",
"ResourceIdTemplate": "",
"Severity": "medium",
"ResourceType": "NotDefined",
"ResourceGroup": "collaboration",
"Description": "The domain-wide default prevents members with **manager access** to a shared drive from overriding the shared drive settings established by administrators. This ensures that security controls — such as external access, member-only access, and download restrictions — cannot be relaxed at the individual shared drive level.",
"Risk": "If shared drive managers can override organizational defaults, **unauthorized data exposure** can occur when a manager intentionally or accidentally weakens a shared drive's security posture (for example, allowing external members or enabling download for viewers).",
"RelatedUrl": "",
"AdditionalURLs": [
"https://support.google.com/a/answer/7662202",
"https://cloud.google.com/identity/docs/concepts/supported-policy-api-settings"
],
"Remediation": {
"Code": {
"CLI": "",
"NativeIaC": "",
"Other": "1. Sign in to the Google **Admin console** at https://admin.google.com\n2. Navigate to **Apps** > **Google Workspace** > **Drive and Docs**\n3. Click **Sharing settings** > **Shared drive creation**\n4. **Uncheck** *Allow members with manager access to override the settings below*\n5. Click **Save**",
"Terraform": ""
},
"Recommendation": {
"Text": "Prevent shared drive managers from overriding organizationally established shared drive settings. This ensures that security controls remain consistent across all shared drives and cannot be relaxed by non-administrators.",
"Url": "https://hub.prowler.com/check/drive_shared_drive_managers_cannot_override"
}
},
"Categories": [],
"DependsOn": [],
"RelatedTo": [
"drive_shared_drive_creation_allowed",
"drive_shared_drive_members_only_access",
"drive_shared_drive_disable_download_print_copy"
],
"Notes": ""
}
@@ -0,0 +1,57 @@
from typing import List
from prowler.lib.check.models import Check, CheckReportGoogleWorkspace
from prowler.providers.googleworkspace.services.drive.drive_client import drive_client
class drive_shared_drive_managers_cannot_override(Check):
"""Check that shared drive managers cannot override shared drive settings
This check verifies that the domain-level Drive and Docs policy prevents
members with manager access from overriding the shared drive settings
configured by administrators, ensuring that security controls cannot be
relaxed at the shared drive level.
"""
def execute(self) -> List[CheckReportGoogleWorkspace]:
findings = []
if drive_client.policies_fetched:
report = CheckReportGoogleWorkspace(
metadata=self.metadata(),
resource=drive_client.provider.identity,
resource_name=drive_client.provider.identity.domain,
resource_id=drive_client.provider.identity.customer_id,
customer_id=drive_client.provider.identity.customer_id,
location="global",
)
allow_override = drive_client.policies.allow_managers_to_override_settings
if allow_override is False:
report.status = "PASS"
report.status_extended = (
f"Shared drive managers in domain "
f"{drive_client.provider.identity.domain} cannot override "
f"shared drive settings."
)
else:
report.status = "FAIL"
if allow_override is None:
report.status_extended = (
f"Manager override of shared drive settings is not "
f"explicitly configured in domain "
f"{drive_client.provider.identity.domain}. "
f"Managers should not be allowed to override shared drive settings."
)
else:
report.status_extended = (
f"Shared drive managers in domain "
f"{drive_client.provider.identity.domain} are allowed to "
f"override shared drive settings. "
f"Managers should not be allowed to override shared drive settings."
)
findings.append(report)
return findings
@@ -0,0 +1,39 @@
{
"Provider": "googleworkspace",
"CheckID": "drive_shared_drive_members_only_access",
"CheckTitle": "Shared drive file access is restricted to members only",
"CheckType": [],
"ServiceName": "drive",
"SubServiceName": "",
"ResourceIdTemplate": "",
"Severity": "medium",
"ResourceType": "NotDefined",
"ResourceGroup": "collaboration",
"Description": "The domain-wide default restricts shared drive file access to **explicit members** only. Non-members cannot be added to individual files inside the drive, preserving the shared drive's membership boundary as the authoritative access control surface.",
"Risk": "If non-members can be added to files inside a shared drive, the **drive's membership becomes meaningless** as a security control. Sensitive content scoped to a specific team can be silently extended to users who were never granted access to the drive itself, leading to unintended information disclosure.",
"RelatedUrl": "",
"AdditionalURLs": [
"https://support.google.com/a/answer/7662202",
"https://cloud.google.com/identity/docs/concepts/supported-policy-api-settings"
],
"Remediation": {
"Code": {
"CLI": "",
"NativeIaC": "",
"Other": "1. Sign in to the Google **Admin console** at https://admin.google.com\n2. Navigate to **Apps** > **Google Workspace** > **Drive and Docs**\n3. Click **Sharing settings** > **Shared drive creation**\n4. **Uncheck** *Allow people who aren't shared drive members to be added to files*\n5. Click **Save**",
"Terraform": ""
},
"Recommendation": {
"Text": "Restrict shared drive file access to explicit shared drive members. This preserves the drive membership as the authoritative access boundary and prevents silent expansion of access to non-members.",
"Url": "https://hub.prowler.com/check/drive_shared_drive_members_only_access"
}
},
"Categories": [],
"DependsOn": [],
"RelatedTo": [
"drive_shared_drive_creation_allowed",
"drive_shared_drive_managers_cannot_override",
"drive_shared_drive_disable_download_print_copy"
],
"Notes": ""
}
@@ -0,0 +1,56 @@
from typing import List
from prowler.lib.check.models import Check, CheckReportGoogleWorkspace
from prowler.providers.googleworkspace.services.drive.drive_client import drive_client
class drive_shared_drive_members_only_access(Check):
"""Check that shared drive file access is restricted to members only
This check verifies that the domain-level Drive and Docs policy prevents
people who are not shared drive members from being added to files within
a shared drive, restricting file access to that drive's explicit
membership.
"""
def execute(self) -> List[CheckReportGoogleWorkspace]:
findings = []
if drive_client.policies_fetched:
report = CheckReportGoogleWorkspace(
metadata=self.metadata(),
resource=drive_client.provider.identity,
resource_name=drive_client.provider.identity.domain,
resource_id=drive_client.provider.identity.customer_id,
customer_id=drive_client.provider.identity.customer_id,
location="global",
)
allow_non_member = drive_client.policies.allow_non_member_access
if allow_non_member is False:
report.status = "PASS"
report.status_extended = (
f"Shared drive file access in domain "
f"{drive_client.provider.identity.domain} is restricted to "
f"shared drive members only."
)
else:
report.status = "FAIL"
if allow_non_member is None:
report.status_extended = (
f"Shared drive non-member access is not explicitly "
f"configured in domain {drive_client.provider.identity.domain}. "
f"Shared drive file access should be restricted to members only."
)
else:
report.status_extended = (
f"Shared drive file access in domain "
f"{drive_client.provider.identity.domain} allows non-members "
f"to be added to files. "
f"Shared drive file access should be restricted to members only."
)
findings.append(report)
return findings
@@ -0,0 +1,41 @@
{
"Provider": "googleworkspace",
"CheckID": "drive_sharing_allowlisted_domains",
"CheckTitle": "Document sharing is restricted to allowlisted domains",
"CheckType": [],
"ServiceName": "drive",
"SubServiceName": "",
"ResourceIdTemplate": "",
"Severity": "medium",
"ResourceType": "NotDefined",
"ResourceGroup": "collaboration",
"Description": "The domain-wide default restricts external sharing of Drive and Docs files to **a curated list of allowlisted domains**, rather than allowing sharing with arbitrary external recipients. This converts external sharing from an open default into a controlled allow-list that aligns with documented business relationships.",
"Risk": "When external sharing is unrestricted, users can share organizational content with **any external Google account**, including untrusted or unknown parties. Restricting sharing to allowlisted domains drastically reduces the surface area for accidental and malicious data exfiltration through Drive.",
"RelatedUrl": "",
"AdditionalURLs": [
"https://support.google.com/a/answer/60781",
"https://cloud.google.com/identity/docs/concepts/supported-policy-api-settings"
],
"Remediation": {
"Code": {
"CLI": "",
"NativeIaC": "",
"Other": "1. Sign in to the Google **Admin console** at https://admin.google.com\n2. Navigate to **Apps** > **Google Workspace** > **Drive and Docs**\n3. Click **Sharing settings** > **Sharing options**\n4. Under **Sharing outside of <Company>**, select **ALLOWLISTED DOMAINS - Files owned by users in <Company> can be shared with Google Accounts in compatible allowlisted domains**\n5. Configure the allowlisted domains list as appropriate for your organization\n6. Click **Save**",
"Terraform": ""
},
"Recommendation": {
"Text": "Restrict Drive and Docs external sharing to allowlisted domains. This converts external sharing from an open default into a controlled allow-list aligned with documented business relationships and reduces the risk of accidental or malicious data exposure.",
"Url": "https://hub.prowler.com/check/drive_sharing_allowlisted_domains"
}
},
"Categories": [
"internet-exposed"
],
"DependsOn": [],
"RelatedTo": [
"drive_external_sharing_warn_users",
"drive_warn_sharing_with_allowlisted_domains",
"drive_publishing_files_disabled"
],
"Notes": ""
}
@@ -0,0 +1,54 @@
from typing import List
from prowler.lib.check.models import Check, CheckReportGoogleWorkspace
from prowler.providers.googleworkspace.services.drive.drive_client import drive_client
class drive_sharing_allowlisted_domains(Check):
"""Check that document sharing is restricted to allowlisted domains
This check verifies that the domain-level Drive and Docs policy restricts
external sharing to a list of explicitly allowlisted domains, blocking
sharing with arbitrary external recipients.
"""
def execute(self) -> List[CheckReportGoogleWorkspace]:
findings = []
if drive_client.policies_fetched:
report = CheckReportGoogleWorkspace(
metadata=self.metadata(),
resource=drive_client.provider.identity,
resource_name=drive_client.provider.identity.domain,
resource_id=drive_client.provider.identity.customer_id,
customer_id=drive_client.provider.identity.customer_id,
location="global",
)
mode = drive_client.policies.external_sharing_mode
if mode == "ALLOWLISTED_DOMAINS":
report.status = "PASS"
report.status_extended = (
f"Drive and Docs external sharing in domain "
f"{drive_client.provider.identity.domain} is restricted to "
f"allowlisted domains."
)
else:
report.status = "FAIL"
if mode is None:
report.status_extended = (
f"Drive and Docs external sharing mode is not explicitly "
f"configured in domain {drive_client.provider.identity.domain}. "
f"Sharing should be restricted to allowlisted domains."
)
else:
report.status_extended = (
f"Drive and Docs external sharing in domain "
f"{drive_client.provider.identity.domain} is set to {mode}. "
f"Sharing should be restricted to allowlisted domains."
)
findings.append(report)
return findings
@@ -0,0 +1,40 @@
{
"Provider": "googleworkspace",
"CheckID": "drive_warn_sharing_with_allowlisted_domains",
"CheckTitle": "Users are warned when sharing files with allowlisted domains",
"CheckType": [],
"ServiceName": "drive",
"SubServiceName": "",
"ResourceIdTemplate": "",
"Severity": "medium",
"ResourceType": "NotDefined",
"ResourceGroup": "collaboration",
"Description": "At the domain level, even when external sharing is restricted to allowlisted domains, Google Drive **warns users** before they share a file with a user in an allowlisted domain. This second-step prompt helps users recognize when they are crossing the organizational boundary, even within permitted destinations.",
"Risk": "Allowlisted domains are still external. Users may not realize that even an allowlisted recipient is outside the organization, leading to **unintentional disclosure of sensitive content** to legitimate but external collaborators. A warning prompt at share time mitigates that without preventing the sharing itself.",
"RelatedUrl": "",
"AdditionalURLs": [
"https://support.google.com/a/answer/60781",
"https://cloud.google.com/identity/docs/concepts/supported-policy-api-settings"
],
"Remediation": {
"Code": {
"CLI": "",
"NativeIaC": "",
"Other": "1. Sign in to the Google **Admin console** at https://admin.google.com\n2. Navigate to **Apps** > **Google Workspace** > **Drive and Docs**\n3. Click **Sharing settings** > **Sharing options**\n4. Under **Sharing outside of <Company>**, ensure **ALLOWLISTED DOMAINS** is selected\n5. Check **Warn when files owned by users or shared drives in <Company> are shared with users in allowlisted domains**\n6. Click **Save**",
"Terraform": ""
},
"Recommendation": {
"Text": "Enable warnings for sharing with allowlisted domains so users are reminded that they are sharing externally, even when the destination is permitted. This preserves the convenience of allowlisted sharing while reducing accidental disclosure.",
"Url": "https://hub.prowler.com/check/drive_warn_sharing_with_allowlisted_domains"
}
},
"Categories": [
"internet-exposed"
],
"DependsOn": [],
"RelatedTo": [
"drive_external_sharing_warn_users",
"drive_sharing_allowlisted_domains"
],
"Notes": "This check is meaningful only when external sharing is restricted to allowlisted domains. See the related check drive_sharing_allowlisted_domains."
}
@@ -0,0 +1,57 @@
from typing import List
from prowler.lib.check.models import Check, CheckReportGoogleWorkspace
from prowler.providers.googleworkspace.services.drive.drive_client import drive_client
class drive_warn_sharing_with_allowlisted_domains(Check):
"""Check that users are warned when sharing with allowlisted domains
This check verifies that the domain-level Drive and Docs policy warns
users when they share files with users in allowlisted domains, providing
an opportunity to reconsider before sharing externally even within
permitted domains.
"""
def execute(self) -> List[CheckReportGoogleWorkspace]:
findings = []
if drive_client.policies_fetched:
report = CheckReportGoogleWorkspace(
metadata=self.metadata(),
resource=drive_client.provider.identity,
resource_name=drive_client.provider.identity.domain,
resource_id=drive_client.provider.identity.customer_id,
customer_id=drive_client.provider.identity.customer_id,
location="global",
)
warn_enabled = (
drive_client.policies.warn_for_sharing_outside_allowlisted_domains
)
if warn_enabled is True:
report.status = "PASS"
report.status_extended = (
f"Users are warned when sharing files with allowlisted "
f"domains in domain {drive_client.provider.identity.domain}."
)
else:
report.status = "FAIL"
if warn_enabled is None:
report.status_extended = (
f"Warning when sharing with allowlisted domains is not "
f"explicitly configured in domain "
f"{drive_client.provider.identity.domain}. "
f"Users should be warned when sharing files with users in allowlisted domains."
)
else:
report.status_extended = (
f"Warning when sharing with allowlisted domains is disabled "
f"in domain {drive_client.provider.identity.domain}. "
f"Users should be warned when sharing files with users in allowlisted domains."
)
findings.append(report)
return findings
@@ -0,0 +1,46 @@
from prowler.providers.googleworkspace.lib.service.service import GoogleWorkspaceService
class TestIsCustomerLevelPolicy:
def test_no_policy_query(self):
"""Policy without policyQuery is customer-level"""
assert GoogleWorkspaceService._is_customer_level_policy({}) is True
def test_empty_policy_query(self):
"""Policy with empty policyQuery is customer-level"""
assert (
GoogleWorkspaceService._is_customer_level_policy({"policyQuery": {}})
is True
)
def test_org_unit_targeted(self):
"""Policy targeting a specific OU is not customer-level"""
assert (
GoogleWorkspaceService._is_customer_level_policy(
{"policyQuery": {"orgUnit": "orgUnits/abc123"}}
)
is False
)
def test_group_targeted(self):
"""Policy targeting a specific group is not customer-level"""
assert (
GoogleWorkspaceService._is_customer_level_policy(
{"policyQuery": {"group": "groups/xyz789"}}
)
is False
)
def test_org_unit_and_group_targeted(self):
"""Policy targeting both OU and group is not customer-level"""
assert (
GoogleWorkspaceService._is_customer_level_policy(
{
"policyQuery": {
"orgUnit": "orgUnits/abc123",
"group": "groups/xyz789",
}
}
)
is False
)
@@ -0,0 +1,156 @@
from unittest.mock import patch
from prowler.providers.googleworkspace.services.drive.drive_service import DrivePolicies
from tests.providers.googleworkspace.googleworkspace_fixtures import (
CUSTOMER_ID,
DOMAIN,
set_mocked_googleworkspace_provider,
)
class TestDriveAccessCheckerRecipientsOnly:
def test_pass_recipients_only(self):
"""Test PASS when Access Checker is set to recipients only"""
mock_provider = set_mocked_googleworkspace_provider()
with (
patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=mock_provider,
),
patch(
"prowler.providers.googleworkspace.services.drive.drive_access_checker_recipients_only.drive_access_checker_recipients_only.drive_client"
) as mock_drive_client,
):
from prowler.providers.googleworkspace.services.drive.drive_access_checker_recipients_only.drive_access_checker_recipients_only import (
drive_access_checker_recipients_only,
)
mock_drive_client.provider = mock_provider
mock_drive_client.policies_fetched = True
mock_drive_client.policies = DrivePolicies(
access_checker_suggestions="RECIPIENTS_ONLY"
)
check = drive_access_checker_recipients_only()
findings = check.execute()
assert len(findings) == 1
assert findings[0].status == "PASS"
assert "recipients only" in findings[0].status_extended
assert findings[0].resource_name == DOMAIN
assert findings[0].customer_id == CUSTOMER_ID
def test_fail_recipients_or_audience(self):
"""Test FAIL when Access Checker allows audience suggestions"""
mock_provider = set_mocked_googleworkspace_provider()
with (
patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=mock_provider,
),
patch(
"prowler.providers.googleworkspace.services.drive.drive_access_checker_recipients_only.drive_access_checker_recipients_only.drive_client"
) as mock_drive_client,
):
from prowler.providers.googleworkspace.services.drive.drive_access_checker_recipients_only.drive_access_checker_recipients_only import (
drive_access_checker_recipients_only,
)
mock_drive_client.provider = mock_provider
mock_drive_client.policies_fetched = True
mock_drive_client.policies = DrivePolicies(
access_checker_suggestions="RECIPIENTS_OR_AUDIENCE"
)
check = drive_access_checker_recipients_only()
findings = check.execute()
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "RECIPIENTS_OR_AUDIENCE" in findings[0].status_extended
def test_fail_recipients_or_audience_or_public(self):
"""Test FAIL when Access Checker allows public suggestions"""
mock_provider = set_mocked_googleworkspace_provider()
with (
patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=mock_provider,
),
patch(
"prowler.providers.googleworkspace.services.drive.drive_access_checker_recipients_only.drive_access_checker_recipients_only.drive_client"
) as mock_drive_client,
):
from prowler.providers.googleworkspace.services.drive.drive_access_checker_recipients_only.drive_access_checker_recipients_only import (
drive_access_checker_recipients_only,
)
mock_drive_client.provider = mock_provider
mock_drive_client.policies_fetched = True
mock_drive_client.policies = DrivePolicies(
access_checker_suggestions="RECIPIENTS_OR_AUDIENCE_OR_PUBLIC"
)
check = drive_access_checker_recipients_only()
findings = check.execute()
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "RECIPIENTS_OR_AUDIENCE_OR_PUBLIC" in findings[0].status_extended
def test_fail_no_policy_set(self):
"""Test FAIL when no explicit policy is set (None) but fetch succeeded"""
mock_provider = set_mocked_googleworkspace_provider()
with (
patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=mock_provider,
),
patch(
"prowler.providers.googleworkspace.services.drive.drive_access_checker_recipients_only.drive_access_checker_recipients_only.drive_client"
) as mock_drive_client,
):
from prowler.providers.googleworkspace.services.drive.drive_access_checker_recipients_only.drive_access_checker_recipients_only import (
drive_access_checker_recipients_only,
)
mock_drive_client.provider = mock_provider
mock_drive_client.policies_fetched = True
mock_drive_client.policies = DrivePolicies(access_checker_suggestions=None)
check = drive_access_checker_recipients_only()
findings = check.execute()
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "not explicitly configured" in findings[0].status_extended
def test_no_findings_when_fetch_failed(self):
"""Test no findings returned when the API fetch failed"""
mock_provider = set_mocked_googleworkspace_provider()
with (
patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=mock_provider,
),
patch(
"prowler.providers.googleworkspace.services.drive.drive_access_checker_recipients_only.drive_access_checker_recipients_only.drive_client"
) as mock_drive_client,
):
from prowler.providers.googleworkspace.services.drive.drive_access_checker_recipients_only.drive_access_checker_recipients_only import (
drive_access_checker_recipients_only,
)
mock_drive_client.provider = mock_provider
mock_drive_client.policies_fetched = False
mock_drive_client.policies = DrivePolicies()
check = drive_access_checker_recipients_only()
findings = check.execute()
assert len(findings) == 0
@@ -0,0 +1,122 @@
from unittest.mock import patch
from prowler.providers.googleworkspace.services.drive.drive_service import DrivePolicies
from tests.providers.googleworkspace.googleworkspace_fixtures import (
CUSTOMER_ID,
DOMAIN,
set_mocked_googleworkspace_provider,
)
class TestDriveDesktopAccessDisabled:
def test_pass_desktop_disabled(self):
"""Test PASS when Drive for desktop is disabled"""
mock_provider = set_mocked_googleworkspace_provider()
with (
patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=mock_provider,
),
patch(
"prowler.providers.googleworkspace.services.drive.drive_desktop_access_disabled.drive_desktop_access_disabled.drive_client"
) as mock_drive_client,
):
from prowler.providers.googleworkspace.services.drive.drive_desktop_access_disabled.drive_desktop_access_disabled import (
drive_desktop_access_disabled,
)
mock_drive_client.provider = mock_provider
mock_drive_client.policies_fetched = True
mock_drive_client.policies = DrivePolicies(allow_drive_for_desktop=False)
check = drive_desktop_access_disabled()
findings = check.execute()
assert len(findings) == 1
assert findings[0].status == "PASS"
assert "disabled" in findings[0].status_extended
assert findings[0].resource_name == DOMAIN
assert findings[0].customer_id == CUSTOMER_ID
def test_fail_desktop_enabled(self):
"""Test FAIL when Drive for desktop is enabled"""
mock_provider = set_mocked_googleworkspace_provider()
with (
patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=mock_provider,
),
patch(
"prowler.providers.googleworkspace.services.drive.drive_desktop_access_disabled.drive_desktop_access_disabled.drive_client"
) as mock_drive_client,
):
from prowler.providers.googleworkspace.services.drive.drive_desktop_access_disabled.drive_desktop_access_disabled import (
drive_desktop_access_disabled,
)
mock_drive_client.provider = mock_provider
mock_drive_client.policies_fetched = True
mock_drive_client.policies = DrivePolicies(allow_drive_for_desktop=True)
check = drive_desktop_access_disabled()
findings = check.execute()
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "enabled" in findings[0].status_extended
def test_fail_no_policy_set(self):
"""Test FAIL when no explicit policy is set (None) but fetch succeeded"""
mock_provider = set_mocked_googleworkspace_provider()
with (
patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=mock_provider,
),
patch(
"prowler.providers.googleworkspace.services.drive.drive_desktop_access_disabled.drive_desktop_access_disabled.drive_client"
) as mock_drive_client,
):
from prowler.providers.googleworkspace.services.drive.drive_desktop_access_disabled.drive_desktop_access_disabled import (
drive_desktop_access_disabled,
)
mock_drive_client.provider = mock_provider
mock_drive_client.policies_fetched = True
mock_drive_client.policies = DrivePolicies(allow_drive_for_desktop=None)
check = drive_desktop_access_disabled()
findings = check.execute()
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "not explicitly configured" in findings[0].status_extended
def test_no_findings_when_fetch_failed(self):
"""Test no findings returned when the API fetch failed"""
mock_provider = set_mocked_googleworkspace_provider()
with (
patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=mock_provider,
),
patch(
"prowler.providers.googleworkspace.services.drive.drive_desktop_access_disabled.drive_desktop_access_disabled.drive_client"
) as mock_drive_client,
):
from prowler.providers.googleworkspace.services.drive.drive_desktop_access_disabled.drive_desktop_access_disabled import (
drive_desktop_access_disabled,
)
mock_drive_client.provider = mock_provider
mock_drive_client.policies_fetched = False
mock_drive_client.policies = DrivePolicies()
check = drive_desktop_access_disabled()
findings = check.execute()
assert len(findings) == 0
@@ -0,0 +1,122 @@
from unittest.mock import patch
from prowler.providers.googleworkspace.services.drive.drive_service import DrivePolicies
from tests.providers.googleworkspace.googleworkspace_fixtures import (
CUSTOMER_ID,
DOMAIN,
set_mocked_googleworkspace_provider,
)
class TestDriveExternalSharingWarnUsers:
def test_pass_warning_enabled(self):
"""Test PASS when external sharing warning is enabled"""
mock_provider = set_mocked_googleworkspace_provider()
with (
patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=mock_provider,
),
patch(
"prowler.providers.googleworkspace.services.drive.drive_external_sharing_warn_users.drive_external_sharing_warn_users.drive_client"
) as mock_drive_client,
):
from prowler.providers.googleworkspace.services.drive.drive_external_sharing_warn_users.drive_external_sharing_warn_users import (
drive_external_sharing_warn_users,
)
mock_drive_client.provider = mock_provider
mock_drive_client.policies_fetched = True
mock_drive_client.policies = DrivePolicies(warn_for_external_sharing=True)
check = drive_external_sharing_warn_users()
findings = check.execute()
assert len(findings) == 1
assert findings[0].status == "PASS"
assert "enabled" in findings[0].status_extended
assert findings[0].resource_name == DOMAIN
assert findings[0].customer_id == CUSTOMER_ID
def test_fail_warning_disabled(self):
"""Test FAIL when external sharing warning is explicitly disabled"""
mock_provider = set_mocked_googleworkspace_provider()
with (
patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=mock_provider,
),
patch(
"prowler.providers.googleworkspace.services.drive.drive_external_sharing_warn_users.drive_external_sharing_warn_users.drive_client"
) as mock_drive_client,
):
from prowler.providers.googleworkspace.services.drive.drive_external_sharing_warn_users.drive_external_sharing_warn_users import (
drive_external_sharing_warn_users,
)
mock_drive_client.provider = mock_provider
mock_drive_client.policies_fetched = True
mock_drive_client.policies = DrivePolicies(warn_for_external_sharing=False)
check = drive_external_sharing_warn_users()
findings = check.execute()
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "disabled" in findings[0].status_extended
def test_fail_no_policy_set(self):
"""Test FAIL when no explicit policy is set (None) but fetch succeeded"""
mock_provider = set_mocked_googleworkspace_provider()
with (
patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=mock_provider,
),
patch(
"prowler.providers.googleworkspace.services.drive.drive_external_sharing_warn_users.drive_external_sharing_warn_users.drive_client"
) as mock_drive_client,
):
from prowler.providers.googleworkspace.services.drive.drive_external_sharing_warn_users.drive_external_sharing_warn_users import (
drive_external_sharing_warn_users,
)
mock_drive_client.provider = mock_provider
mock_drive_client.policies_fetched = True
mock_drive_client.policies = DrivePolicies(warn_for_external_sharing=None)
check = drive_external_sharing_warn_users()
findings = check.execute()
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "not explicitly configured" in findings[0].status_extended
def test_no_findings_when_fetch_failed(self):
"""Test no findings returned when the API fetch failed"""
mock_provider = set_mocked_googleworkspace_provider()
with (
patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=mock_provider,
),
patch(
"prowler.providers.googleworkspace.services.drive.drive_external_sharing_warn_users.drive_external_sharing_warn_users.drive_client"
) as mock_drive_client,
):
from prowler.providers.googleworkspace.services.drive.drive_external_sharing_warn_users.drive_external_sharing_warn_users import (
drive_external_sharing_warn_users,
)
mock_drive_client.provider = mock_provider
mock_drive_client.policies_fetched = False
mock_drive_client.policies = DrivePolicies()
check = drive_external_sharing_warn_users()
findings = check.execute()
assert len(findings) == 0
@@ -0,0 +1,158 @@
from unittest.mock import patch
from prowler.providers.googleworkspace.services.drive.drive_service import DrivePolicies
from tests.providers.googleworkspace.googleworkspace_fixtures import (
CUSTOMER_ID,
DOMAIN,
set_mocked_googleworkspace_provider,
)
class TestDriveInternalUsersDistributeContent:
def test_pass_eligible_internal_users(self):
"""Test PASS when content distribution is restricted to eligible internal users"""
mock_provider = set_mocked_googleworkspace_provider()
with (
patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=mock_provider,
),
patch(
"prowler.providers.googleworkspace.services.drive.drive_internal_users_distribute_content.drive_internal_users_distribute_content.drive_client"
) as mock_drive_client,
):
from prowler.providers.googleworkspace.services.drive.drive_internal_users_distribute_content.drive_internal_users_distribute_content import (
drive_internal_users_distribute_content,
)
mock_drive_client.provider = mock_provider
mock_drive_client.policies_fetched = True
mock_drive_client.policies = DrivePolicies(
allowed_parties_for_distributing_content="ELIGIBLE_INTERNAL_USERS"
)
check = drive_internal_users_distribute_content()
findings = check.execute()
assert len(findings) == 1
assert findings[0].status == "PASS"
assert "ELIGIBLE_INTERNAL_USERS" in findings[0].status_extended
assert findings[0].resource_name == DOMAIN
assert findings[0].customer_id == CUSTOMER_ID
def test_pass_none_allowed(self):
"""Test PASS when content distribution is set to NONE (nobody can distribute)"""
mock_provider = set_mocked_googleworkspace_provider()
with (
patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=mock_provider,
),
patch(
"prowler.providers.googleworkspace.services.drive.drive_internal_users_distribute_content.drive_internal_users_distribute_content.drive_client"
) as mock_drive_client,
):
from prowler.providers.googleworkspace.services.drive.drive_internal_users_distribute_content.drive_internal_users_distribute_content import (
drive_internal_users_distribute_content,
)
mock_drive_client.provider = mock_provider
mock_drive_client.policies_fetched = True
mock_drive_client.policies = DrivePolicies(
allowed_parties_for_distributing_content="NONE"
)
check = drive_internal_users_distribute_content()
findings = check.execute()
assert len(findings) == 1
assert findings[0].status == "PASS"
assert "NONE" in findings[0].status_extended
def test_fail_all_eligible_users(self):
"""Test FAIL when all users (including external) can distribute content"""
mock_provider = set_mocked_googleworkspace_provider()
with (
patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=mock_provider,
),
patch(
"prowler.providers.googleworkspace.services.drive.drive_internal_users_distribute_content.drive_internal_users_distribute_content.drive_client"
) as mock_drive_client,
):
from prowler.providers.googleworkspace.services.drive.drive_internal_users_distribute_content.drive_internal_users_distribute_content import (
drive_internal_users_distribute_content,
)
mock_drive_client.provider = mock_provider
mock_drive_client.policies_fetched = True
mock_drive_client.policies = DrivePolicies(
allowed_parties_for_distributing_content="ALL_ELIGIBLE_USERS"
)
check = drive_internal_users_distribute_content()
findings = check.execute()
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "ALL_ELIGIBLE_USERS" in findings[0].status_extended
def test_fail_no_policy_set(self):
"""Test FAIL when no explicit policy is set (None) but fetch succeeded"""
mock_provider = set_mocked_googleworkspace_provider()
with (
patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=mock_provider,
),
patch(
"prowler.providers.googleworkspace.services.drive.drive_internal_users_distribute_content.drive_internal_users_distribute_content.drive_client"
) as mock_drive_client,
):
from prowler.providers.googleworkspace.services.drive.drive_internal_users_distribute_content.drive_internal_users_distribute_content import (
drive_internal_users_distribute_content,
)
mock_drive_client.provider = mock_provider
mock_drive_client.policies_fetched = True
mock_drive_client.policies = DrivePolicies(
allowed_parties_for_distributing_content=None
)
check = drive_internal_users_distribute_content()
findings = check.execute()
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "not explicitly configured" in findings[0].status_extended
def test_no_findings_when_fetch_failed(self):
"""Test no findings returned when the API fetch failed"""
mock_provider = set_mocked_googleworkspace_provider()
with (
patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=mock_provider,
),
patch(
"prowler.providers.googleworkspace.services.drive.drive_internal_users_distribute_content.drive_internal_users_distribute_content.drive_client"
) as mock_drive_client,
):
from prowler.providers.googleworkspace.services.drive.drive_internal_users_distribute_content.drive_internal_users_distribute_content import (
drive_internal_users_distribute_content,
)
mock_drive_client.provider = mock_provider
mock_drive_client.policies_fetched = False
mock_drive_client.policies = DrivePolicies()
check = drive_internal_users_distribute_content()
findings = check.execute()
assert len(findings) == 0
@@ -0,0 +1,122 @@
from unittest.mock import patch
from prowler.providers.googleworkspace.services.drive.drive_service import DrivePolicies
from tests.providers.googleworkspace.googleworkspace_fixtures import (
CUSTOMER_ID,
DOMAIN,
set_mocked_googleworkspace_provider,
)
class TestDrivePublishingFilesDisabled:
def test_pass_publishing_disabled(self):
"""Test PASS when publishing files to web is disabled"""
mock_provider = set_mocked_googleworkspace_provider()
with (
patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=mock_provider,
),
patch(
"prowler.providers.googleworkspace.services.drive.drive_publishing_files_disabled.drive_publishing_files_disabled.drive_client"
) as mock_drive_client,
):
from prowler.providers.googleworkspace.services.drive.drive_publishing_files_disabled.drive_publishing_files_disabled import (
drive_publishing_files_disabled,
)
mock_drive_client.provider = mock_provider
mock_drive_client.policies_fetched = True
mock_drive_client.policies = DrivePolicies(allow_publishing_files=False)
check = drive_publishing_files_disabled()
findings = check.execute()
assert len(findings) == 1
assert findings[0].status == "PASS"
assert "disabled" in findings[0].status_extended
assert findings[0].resource_name == DOMAIN
assert findings[0].customer_id == CUSTOMER_ID
def test_fail_publishing_enabled(self):
"""Test FAIL when publishing files to web is enabled"""
mock_provider = set_mocked_googleworkspace_provider()
with (
patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=mock_provider,
),
patch(
"prowler.providers.googleworkspace.services.drive.drive_publishing_files_disabled.drive_publishing_files_disabled.drive_client"
) as mock_drive_client,
):
from prowler.providers.googleworkspace.services.drive.drive_publishing_files_disabled.drive_publishing_files_disabled import (
drive_publishing_files_disabled,
)
mock_drive_client.provider = mock_provider
mock_drive_client.policies_fetched = True
mock_drive_client.policies = DrivePolicies(allow_publishing_files=True)
check = drive_publishing_files_disabled()
findings = check.execute()
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "enabled" in findings[0].status_extended
def test_fail_no_policy_set(self):
"""Test FAIL when no explicit policy is set (None) but fetch succeeded"""
mock_provider = set_mocked_googleworkspace_provider()
with (
patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=mock_provider,
),
patch(
"prowler.providers.googleworkspace.services.drive.drive_publishing_files_disabled.drive_publishing_files_disabled.drive_client"
) as mock_drive_client,
):
from prowler.providers.googleworkspace.services.drive.drive_publishing_files_disabled.drive_publishing_files_disabled import (
drive_publishing_files_disabled,
)
mock_drive_client.provider = mock_provider
mock_drive_client.policies_fetched = True
mock_drive_client.policies = DrivePolicies(allow_publishing_files=None)
check = drive_publishing_files_disabled()
findings = check.execute()
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "not explicitly configured" in findings[0].status_extended
def test_no_findings_when_fetch_failed(self):
"""Test no findings returned when the API fetch failed"""
mock_provider = set_mocked_googleworkspace_provider()
with (
patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=mock_provider,
),
patch(
"prowler.providers.googleworkspace.services.drive.drive_publishing_files_disabled.drive_publishing_files_disabled.drive_client"
) as mock_drive_client,
):
from prowler.providers.googleworkspace.services.drive.drive_publishing_files_disabled.drive_publishing_files_disabled import (
drive_publishing_files_disabled,
)
mock_drive_client.provider = mock_provider
mock_drive_client.policies_fetched = False
mock_drive_client.policies = DrivePolicies()
check = drive_publishing_files_disabled()
findings = check.execute()
assert len(findings) == 0
@@ -0,0 +1,349 @@
from unittest.mock import MagicMock, patch
from tests.providers.googleworkspace.googleworkspace_fixtures import (
set_mocked_googleworkspace_provider,
)
class TestDriveService:
def test_drive_fetch_policies_all_settings(self):
"""Test fetching all 3 Drive and Docs policy settings from Cloud Identity API"""
mock_provider = set_mocked_googleworkspace_provider()
mock_provider.audit_config = {}
mock_provider.fixer_config = {}
mock_credentials = MagicMock()
mock_session = MagicMock()
mock_session.credentials = mock_credentials
mock_provider.session = mock_session
mock_service = MagicMock()
mock_policies_list = MagicMock()
# Mock the actual Cloud Identity Policy API v1 response shape:
# - "type" (not "name"), prefixed with "settings/"
# - inner value field names are camelCase
mock_policies_list.execute.return_value = {
"policies": [
{
"setting": {
"type": "settings/drive_and_docs.external_sharing",
"value": {
"externalSharingMode": "ALLOWLISTED_DOMAINS",
"warnForExternalSharing": True,
"warnForSharingOutsideAllowlistedDomains": True,
"allowPublishingFiles": False,
"accessCheckerSuggestions": "RECIPIENTS_ONLY",
"allowedPartiesForDistributingContent": "ELIGIBLE_INTERNAL_USERS",
},
}
},
{
"setting": {
"type": "settings/drive_and_docs.shared_drive_creation",
"value": {
"allowSharedDriveCreation": True,
"allowManagersToOverrideSettings": False,
"allowNonMemberAccess": False,
"allowedPartiesForDownloadPrintCopy": "EDITORS_ONLY",
},
}
},
{
"setting": {
"type": "settings/drive_and_docs.drive_for_desktop",
"value": {"allowDriveForDesktop": False},
}
},
]
}
mock_service.policies().list.return_value = mock_policies_list
mock_service.policies().list_next.return_value = None
with (
patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=mock_provider,
),
patch(
"prowler.providers.googleworkspace.services.drive.drive_service.GoogleWorkspaceService._build_service",
return_value=mock_service,
),
):
from prowler.providers.googleworkspace.services.drive.drive_service import (
Drive,
)
drive = Drive(mock_provider)
assert drive.policies_fetched is True
assert drive.policies.external_sharing_mode == "ALLOWLISTED_DOMAINS"
assert drive.policies.warn_for_external_sharing is True
assert drive.policies.warn_for_sharing_outside_allowlisted_domains is True
assert drive.policies.allow_publishing_files is False
assert drive.policies.access_checker_suggestions == "RECIPIENTS_ONLY"
assert (
drive.policies.allowed_parties_for_distributing_content
== "ELIGIBLE_INTERNAL_USERS"
)
assert drive.policies.allow_shared_drive_creation is True
assert drive.policies.allow_managers_to_override_settings is False
assert drive.policies.allow_non_member_access is False
assert (
drive.policies.allowed_parties_for_download_print_copy == "EDITORS_ONLY"
)
assert drive.policies.allow_drive_for_desktop is False
def test_drive_fetch_policies_empty_response(self):
"""Test handling empty policies response"""
mock_provider = set_mocked_googleworkspace_provider()
mock_provider.audit_config = {}
mock_provider.fixer_config = {}
mock_session = MagicMock()
mock_session.credentials = MagicMock()
mock_provider.session = mock_session
mock_service = MagicMock()
mock_policies_list = MagicMock()
mock_policies_list.execute.return_value = {"policies": []}
mock_service.policies().list.return_value = mock_policies_list
mock_service.policies().list_next.return_value = None
with (
patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=mock_provider,
),
patch(
"prowler.providers.googleworkspace.services.drive.drive_service.GoogleWorkspaceService._build_service",
return_value=mock_service,
),
):
from prowler.providers.googleworkspace.services.drive.drive_service import (
Drive,
)
drive = Drive(mock_provider)
assert drive.policies_fetched is True
assert drive.policies.external_sharing_mode is None
assert drive.policies.warn_for_external_sharing is None
assert drive.policies.allow_publishing_files is None
assert drive.policies.allow_shared_drive_creation is None
assert drive.policies.allow_drive_for_desktop is None
def test_drive_fetch_policies_api_error(self):
"""Test handling of API errors during policy fetch"""
mock_provider = set_mocked_googleworkspace_provider()
mock_provider.audit_config = {}
mock_provider.fixer_config = {}
mock_session = MagicMock()
mock_session.credentials = MagicMock()
mock_provider.session = mock_session
mock_service = MagicMock()
mock_service.policies().list.side_effect = Exception("API Error")
with (
patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=mock_provider,
),
patch(
"prowler.providers.googleworkspace.services.drive.drive_service.GoogleWorkspaceService._build_service",
return_value=mock_service,
),
):
from prowler.providers.googleworkspace.services.drive.drive_service import (
Drive,
)
drive = Drive(mock_provider)
assert drive.policies_fetched is False
assert drive.policies.external_sharing_mode is None
assert drive.policies.allow_shared_drive_creation is None
assert drive.policies.allow_drive_for_desktop is None
def test_drive_fetch_policies_build_service_returns_none(self):
"""Test early return when _build_service fails to construct the client"""
mock_provider = set_mocked_googleworkspace_provider()
mock_provider.audit_config = {}
mock_provider.fixer_config = {}
mock_session = MagicMock()
mock_session.credentials = MagicMock()
mock_provider.session = mock_session
with (
patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=mock_provider,
),
patch(
"prowler.providers.googleworkspace.services.drive.drive_service.GoogleWorkspaceService._build_service",
return_value=None,
),
):
from prowler.providers.googleworkspace.services.drive.drive_service import (
Drive,
)
drive = Drive(mock_provider)
assert drive.policies_fetched is False
assert drive.policies.external_sharing_mode is None
assert drive.policies.allow_shared_drive_creation is None
assert drive.policies.allow_drive_for_desktop is None
def test_drive_fetch_policies_execute_raises(self):
"""Test inner except handler when request.execute() raises during pagination"""
mock_provider = set_mocked_googleworkspace_provider()
mock_provider.audit_config = {}
mock_provider.fixer_config = {}
mock_session = MagicMock()
mock_session.credentials = MagicMock()
mock_provider.session = mock_session
mock_service = MagicMock()
mock_request = MagicMock()
mock_request.execute.side_effect = Exception("Execute failed")
mock_service.policies().list.return_value = mock_request
with (
patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=mock_provider,
),
patch(
"prowler.providers.googleworkspace.services.drive.drive_service.GoogleWorkspaceService._build_service",
return_value=mock_service,
),
):
from prowler.providers.googleworkspace.services.drive.drive_service import (
Drive,
)
drive = Drive(mock_provider)
assert drive.policies_fetched is False
assert drive.policies.external_sharing_mode is None
assert drive.policies.allow_shared_drive_creation is None
assert drive.policies.allow_drive_for_desktop is None
def test_drive_policies_model(self):
"""Test DrivePolicies Pydantic model"""
from prowler.providers.googleworkspace.services.drive.drive_service import (
DrivePolicies,
)
policies = DrivePolicies(
external_sharing_mode="ALLOWLISTED_DOMAINS",
warn_for_external_sharing=True,
warn_for_sharing_outside_allowlisted_domains=True,
allow_publishing_files=False,
access_checker_suggestions="RECIPIENTS_ONLY",
allowed_parties_for_distributing_content="ELIGIBLE_INTERNAL_USERS",
allow_shared_drive_creation=True,
allow_managers_to_override_settings=False,
allow_non_member_access=False,
allowed_parties_for_download_print_copy="EDITORS_ONLY",
allow_drive_for_desktop=False,
)
assert policies.external_sharing_mode == "ALLOWLISTED_DOMAINS"
assert policies.warn_for_external_sharing is True
assert policies.allow_publishing_files is False
assert policies.access_checker_suggestions == "RECIPIENTS_ONLY"
assert policies.allow_shared_drive_creation is True
assert policies.allow_managers_to_override_settings is False
assert policies.allow_non_member_access is False
assert policies.allowed_parties_for_download_print_copy == "EDITORS_ONLY"
assert policies.allow_drive_for_desktop is False
def test_drive_fetch_policies_ignores_ou_and_group_level(self):
"""Test that OU-level and group-level policies are skipped, only customer-level used"""
mock_provider = set_mocked_googleworkspace_provider()
mock_provider.audit_config = {}
mock_provider.fixer_config = {}
mock_session = MagicMock()
mock_session.credentials = MagicMock()
mock_provider.session = mock_session
mock_service = MagicMock()
mock_policies_list = MagicMock()
# Response includes 3 policies of the same type at different org levels:
# customer-level (no policyQuery), OU-level, and group-level
mock_policies_list.execute.return_value = {
"policies": [
{
# Customer-level: no policyQuery → should be used
"setting": {
"type": "settings/drive_and_docs.external_sharing",
"value": {
"externalSharingMode": "ALLOWLISTED_DOMAINS",
"warnForExternalSharing": True,
},
}
},
{
# OU-level: has policyQuery.orgUnit → should be skipped
"policyQuery": {"orgUnit": "orgUnits/sales_team"},
"setting": {
"type": "settings/drive_and_docs.external_sharing",
"value": {
"externalSharingMode": "ALLOWED",
"warnForExternalSharing": False,
},
},
},
{
# Group-level: has policyQuery.group → should be skipped
"policyQuery": {"group": "groups/contractors"},
"setting": {
"type": "settings/drive_and_docs.external_sharing",
"value": {
"externalSharingMode": "DISALLOWED",
"warnForExternalSharing": False,
},
},
},
{
# Customer-level shared drive creation
"setting": {
"type": "settings/drive_and_docs.shared_drive_creation",
"value": {"allowSharedDriveCreation": True},
}
},
{
# OU-level shared drive creation → should be skipped
"policyQuery": {"orgUnit": "orgUnits/engineering"},
"setting": {
"type": "settings/drive_and_docs.shared_drive_creation",
"value": {"allowSharedDriveCreation": False},
},
},
]
}
mock_service.policies().list.return_value = mock_policies_list
mock_service.policies().list_next.return_value = None
with (
patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=mock_provider,
),
patch(
"prowler.providers.googleworkspace.services.drive.drive_service.GoogleWorkspaceService._build_service",
return_value=mock_service,
),
):
from prowler.providers.googleworkspace.services.drive.drive_service import (
Drive,
)
drive = Drive(mock_provider)
assert drive.policies_fetched is True
# Customer-level values should be stored
assert drive.policies.external_sharing_mode == "ALLOWLISTED_DOMAINS"
assert drive.policies.warn_for_external_sharing is True
assert drive.policies.allow_shared_drive_creation is True
# OU/group-level values (ALLOWED, False, False) should NOT have overwritten
@@ -0,0 +1,124 @@
from unittest.mock import patch
from prowler.providers.googleworkspace.services.drive.drive_service import DrivePolicies
from tests.providers.googleworkspace.googleworkspace_fixtures import (
CUSTOMER_ID,
DOMAIN,
set_mocked_googleworkspace_provider,
)
class TestDriveSharedDriveCreationAllowed:
def test_pass_creation_allowed(self):
"""Test PASS when users are allowed to create shared drives"""
mock_provider = set_mocked_googleworkspace_provider()
with (
patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=mock_provider,
),
patch(
"prowler.providers.googleworkspace.services.drive.drive_shared_drive_creation_allowed.drive_shared_drive_creation_allowed.drive_client"
) as mock_drive_client,
):
from prowler.providers.googleworkspace.services.drive.drive_shared_drive_creation_allowed.drive_shared_drive_creation_allowed import (
drive_shared_drive_creation_allowed,
)
mock_drive_client.provider = mock_provider
mock_drive_client.policies_fetched = True
mock_drive_client.policies = DrivePolicies(allow_shared_drive_creation=True)
check = drive_shared_drive_creation_allowed()
findings = check.execute()
assert len(findings) == 1
assert findings[0].status == "PASS"
assert "allowed" in findings[0].status_extended
assert findings[0].resource_name == DOMAIN
assert findings[0].customer_id == CUSTOMER_ID
def test_fail_creation_disabled(self):
"""Test FAIL when users are prevented from creating shared drives"""
mock_provider = set_mocked_googleworkspace_provider()
with (
patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=mock_provider,
),
patch(
"prowler.providers.googleworkspace.services.drive.drive_shared_drive_creation_allowed.drive_shared_drive_creation_allowed.drive_client"
) as mock_drive_client,
):
from prowler.providers.googleworkspace.services.drive.drive_shared_drive_creation_allowed.drive_shared_drive_creation_allowed import (
drive_shared_drive_creation_allowed,
)
mock_drive_client.provider = mock_provider
mock_drive_client.policies_fetched = True
mock_drive_client.policies = DrivePolicies(
allow_shared_drive_creation=False
)
check = drive_shared_drive_creation_allowed()
findings = check.execute()
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "prevented" in findings[0].status_extended
def test_fail_no_policy_set(self):
"""Test FAIL when no explicit policy is set (None) but fetch succeeded"""
mock_provider = set_mocked_googleworkspace_provider()
with (
patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=mock_provider,
),
patch(
"prowler.providers.googleworkspace.services.drive.drive_shared_drive_creation_allowed.drive_shared_drive_creation_allowed.drive_client"
) as mock_drive_client,
):
from prowler.providers.googleworkspace.services.drive.drive_shared_drive_creation_allowed.drive_shared_drive_creation_allowed import (
drive_shared_drive_creation_allowed,
)
mock_drive_client.provider = mock_provider
mock_drive_client.policies_fetched = True
mock_drive_client.policies = DrivePolicies(allow_shared_drive_creation=None)
check = drive_shared_drive_creation_allowed()
findings = check.execute()
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "not explicitly configured" in findings[0].status_extended
def test_no_findings_when_fetch_failed(self):
"""Test no findings returned when the API fetch failed"""
mock_provider = set_mocked_googleworkspace_provider()
with (
patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=mock_provider,
),
patch(
"prowler.providers.googleworkspace.services.drive.drive_shared_drive_creation_allowed.drive_shared_drive_creation_allowed.drive_client"
) as mock_drive_client,
):
from prowler.providers.googleworkspace.services.drive.drive_shared_drive_creation_allowed.drive_shared_drive_creation_allowed import (
drive_shared_drive_creation_allowed,
)
mock_drive_client.provider = mock_provider
mock_drive_client.policies_fetched = False
mock_drive_client.policies = DrivePolicies()
check = drive_shared_drive_creation_allowed()
findings = check.execute()
assert len(findings) == 0
@@ -0,0 +1,158 @@
from unittest.mock import patch
from prowler.providers.googleworkspace.services.drive.drive_service import DrivePolicies
from tests.providers.googleworkspace.googleworkspace_fixtures import (
CUSTOMER_ID,
DOMAIN,
set_mocked_googleworkspace_provider,
)
class TestDriveSharedDriveDisableDownloadPrintCopy:
def test_pass_editors_only(self):
"""Test PASS when download/print/copy is restricted to editors only"""
mock_provider = set_mocked_googleworkspace_provider()
with (
patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=mock_provider,
),
patch(
"prowler.providers.googleworkspace.services.drive.drive_shared_drive_disable_download_print_copy.drive_shared_drive_disable_download_print_copy.drive_client"
) as mock_drive_client,
):
from prowler.providers.googleworkspace.services.drive.drive_shared_drive_disable_download_print_copy.drive_shared_drive_disable_download_print_copy import (
drive_shared_drive_disable_download_print_copy,
)
mock_drive_client.provider = mock_provider
mock_drive_client.policies_fetched = True
mock_drive_client.policies = DrivePolicies(
allowed_parties_for_download_print_copy="EDITORS_ONLY"
)
check = drive_shared_drive_disable_download_print_copy()
findings = check.execute()
assert len(findings) == 1
assert findings[0].status == "PASS"
assert "EDITORS_ONLY" in findings[0].status_extended
assert findings[0].resource_name == DOMAIN
assert findings[0].customer_id == CUSTOMER_ID
def test_pass_managers_only(self):
"""Test PASS when download/print/copy is restricted to managers only"""
mock_provider = set_mocked_googleworkspace_provider()
with (
patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=mock_provider,
),
patch(
"prowler.providers.googleworkspace.services.drive.drive_shared_drive_disable_download_print_copy.drive_shared_drive_disable_download_print_copy.drive_client"
) as mock_drive_client,
):
from prowler.providers.googleworkspace.services.drive.drive_shared_drive_disable_download_print_copy.drive_shared_drive_disable_download_print_copy import (
drive_shared_drive_disable_download_print_copy,
)
mock_drive_client.provider = mock_provider
mock_drive_client.policies_fetched = True
mock_drive_client.policies = DrivePolicies(
allowed_parties_for_download_print_copy="MANAGERS_ONLY"
)
check = drive_shared_drive_disable_download_print_copy()
findings = check.execute()
assert len(findings) == 1
assert findings[0].status == "PASS"
assert "MANAGERS_ONLY" in findings[0].status_extended
def test_fail_all_allowed(self):
"""Test FAIL when all users (including viewers/commenters) can download/print/copy"""
mock_provider = set_mocked_googleworkspace_provider()
with (
patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=mock_provider,
),
patch(
"prowler.providers.googleworkspace.services.drive.drive_shared_drive_disable_download_print_copy.drive_shared_drive_disable_download_print_copy.drive_client"
) as mock_drive_client,
):
from prowler.providers.googleworkspace.services.drive.drive_shared_drive_disable_download_print_copy.drive_shared_drive_disable_download_print_copy import (
drive_shared_drive_disable_download_print_copy,
)
mock_drive_client.provider = mock_provider
mock_drive_client.policies_fetched = True
mock_drive_client.policies = DrivePolicies(
allowed_parties_for_download_print_copy="ALL"
)
check = drive_shared_drive_disable_download_print_copy()
findings = check.execute()
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "ALL" in findings[0].status_extended
def test_fail_no_policy_set(self):
"""Test FAIL when no explicit policy is set (None) but fetch succeeded"""
mock_provider = set_mocked_googleworkspace_provider()
with (
patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=mock_provider,
),
patch(
"prowler.providers.googleworkspace.services.drive.drive_shared_drive_disable_download_print_copy.drive_shared_drive_disable_download_print_copy.drive_client"
) as mock_drive_client,
):
from prowler.providers.googleworkspace.services.drive.drive_shared_drive_disable_download_print_copy.drive_shared_drive_disable_download_print_copy import (
drive_shared_drive_disable_download_print_copy,
)
mock_drive_client.provider = mock_provider
mock_drive_client.policies_fetched = True
mock_drive_client.policies = DrivePolicies(
allowed_parties_for_download_print_copy=None
)
check = drive_shared_drive_disable_download_print_copy()
findings = check.execute()
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "not explicitly configured" in findings[0].status_extended
def test_no_findings_when_fetch_failed(self):
"""Test no findings returned when the API fetch failed"""
mock_provider = set_mocked_googleworkspace_provider()
with (
patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=mock_provider,
),
patch(
"prowler.providers.googleworkspace.services.drive.drive_shared_drive_disable_download_print_copy.drive_shared_drive_disable_download_print_copy.drive_client"
) as mock_drive_client,
):
from prowler.providers.googleworkspace.services.drive.drive_shared_drive_disable_download_print_copy.drive_shared_drive_disable_download_print_copy import (
drive_shared_drive_disable_download_print_copy,
)
mock_drive_client.provider = mock_provider
mock_drive_client.policies_fetched = False
mock_drive_client.policies = DrivePolicies()
check = drive_shared_drive_disable_download_print_copy()
findings = check.execute()
assert len(findings) == 0
@@ -0,0 +1,128 @@
from unittest.mock import patch
from prowler.providers.googleworkspace.services.drive.drive_service import DrivePolicies
from tests.providers.googleworkspace.googleworkspace_fixtures import (
CUSTOMER_ID,
DOMAIN,
set_mocked_googleworkspace_provider,
)
class TestDriveSharedDriveManagersCannotOverride:
def test_pass_override_disabled(self):
"""Test PASS when managers cannot override shared drive settings"""
mock_provider = set_mocked_googleworkspace_provider()
with (
patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=mock_provider,
),
patch(
"prowler.providers.googleworkspace.services.drive.drive_shared_drive_managers_cannot_override.drive_shared_drive_managers_cannot_override.drive_client"
) as mock_drive_client,
):
from prowler.providers.googleworkspace.services.drive.drive_shared_drive_managers_cannot_override.drive_shared_drive_managers_cannot_override import (
drive_shared_drive_managers_cannot_override,
)
mock_drive_client.provider = mock_provider
mock_drive_client.policies_fetched = True
mock_drive_client.policies = DrivePolicies(
allow_managers_to_override_settings=False
)
check = drive_shared_drive_managers_cannot_override()
findings = check.execute()
assert len(findings) == 1
assert findings[0].status == "PASS"
assert "cannot override" in findings[0].status_extended
assert findings[0].resource_name == DOMAIN
assert findings[0].customer_id == CUSTOMER_ID
def test_fail_override_allowed(self):
"""Test FAIL when managers can override shared drive settings"""
mock_provider = set_mocked_googleworkspace_provider()
with (
patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=mock_provider,
),
patch(
"prowler.providers.googleworkspace.services.drive.drive_shared_drive_managers_cannot_override.drive_shared_drive_managers_cannot_override.drive_client"
) as mock_drive_client,
):
from prowler.providers.googleworkspace.services.drive.drive_shared_drive_managers_cannot_override.drive_shared_drive_managers_cannot_override import (
drive_shared_drive_managers_cannot_override,
)
mock_drive_client.provider = mock_provider
mock_drive_client.policies_fetched = True
mock_drive_client.policies = DrivePolicies(
allow_managers_to_override_settings=True
)
check = drive_shared_drive_managers_cannot_override()
findings = check.execute()
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "allowed to override" in findings[0].status_extended
def test_fail_no_policy_set(self):
"""Test FAIL when no explicit policy is set (None) but fetch succeeded"""
mock_provider = set_mocked_googleworkspace_provider()
with (
patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=mock_provider,
),
patch(
"prowler.providers.googleworkspace.services.drive.drive_shared_drive_managers_cannot_override.drive_shared_drive_managers_cannot_override.drive_client"
) as mock_drive_client,
):
from prowler.providers.googleworkspace.services.drive.drive_shared_drive_managers_cannot_override.drive_shared_drive_managers_cannot_override import (
drive_shared_drive_managers_cannot_override,
)
mock_drive_client.provider = mock_provider
mock_drive_client.policies_fetched = True
mock_drive_client.policies = DrivePolicies(
allow_managers_to_override_settings=None
)
check = drive_shared_drive_managers_cannot_override()
findings = check.execute()
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "not explicitly configured" in findings[0].status_extended
def test_no_findings_when_fetch_failed(self):
"""Test no findings returned when the API fetch failed"""
mock_provider = set_mocked_googleworkspace_provider()
with (
patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=mock_provider,
),
patch(
"prowler.providers.googleworkspace.services.drive.drive_shared_drive_managers_cannot_override.drive_shared_drive_managers_cannot_override.drive_client"
) as mock_drive_client,
):
from prowler.providers.googleworkspace.services.drive.drive_shared_drive_managers_cannot_override.drive_shared_drive_managers_cannot_override import (
drive_shared_drive_managers_cannot_override,
)
mock_drive_client.provider = mock_provider
mock_drive_client.policies_fetched = False
mock_drive_client.policies = DrivePolicies()
check = drive_shared_drive_managers_cannot_override()
findings = check.execute()
assert len(findings) == 0
@@ -0,0 +1,122 @@
from unittest.mock import patch
from prowler.providers.googleworkspace.services.drive.drive_service import DrivePolicies
from tests.providers.googleworkspace.googleworkspace_fixtures import (
CUSTOMER_ID,
DOMAIN,
set_mocked_googleworkspace_provider,
)
class TestDriveSharedDriveMembersOnlyAccess:
def test_pass_non_member_access_disabled(self):
"""Test PASS when non-member access to shared drive files is disabled"""
mock_provider = set_mocked_googleworkspace_provider()
with (
patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=mock_provider,
),
patch(
"prowler.providers.googleworkspace.services.drive.drive_shared_drive_members_only_access.drive_shared_drive_members_only_access.drive_client"
) as mock_drive_client,
):
from prowler.providers.googleworkspace.services.drive.drive_shared_drive_members_only_access.drive_shared_drive_members_only_access import (
drive_shared_drive_members_only_access,
)
mock_drive_client.provider = mock_provider
mock_drive_client.policies_fetched = True
mock_drive_client.policies = DrivePolicies(allow_non_member_access=False)
check = drive_shared_drive_members_only_access()
findings = check.execute()
assert len(findings) == 1
assert findings[0].status == "PASS"
assert "members only" in findings[0].status_extended
assert findings[0].resource_name == DOMAIN
assert findings[0].customer_id == CUSTOMER_ID
def test_fail_non_member_access_enabled(self):
"""Test FAIL when non-members can be added to shared drive files"""
mock_provider = set_mocked_googleworkspace_provider()
with (
patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=mock_provider,
),
patch(
"prowler.providers.googleworkspace.services.drive.drive_shared_drive_members_only_access.drive_shared_drive_members_only_access.drive_client"
) as mock_drive_client,
):
from prowler.providers.googleworkspace.services.drive.drive_shared_drive_members_only_access.drive_shared_drive_members_only_access import (
drive_shared_drive_members_only_access,
)
mock_drive_client.provider = mock_provider
mock_drive_client.policies_fetched = True
mock_drive_client.policies = DrivePolicies(allow_non_member_access=True)
check = drive_shared_drive_members_only_access()
findings = check.execute()
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "non-members" in findings[0].status_extended
def test_fail_no_policy_set(self):
"""Test FAIL when no explicit policy is set (None) but fetch succeeded"""
mock_provider = set_mocked_googleworkspace_provider()
with (
patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=mock_provider,
),
patch(
"prowler.providers.googleworkspace.services.drive.drive_shared_drive_members_only_access.drive_shared_drive_members_only_access.drive_client"
) as mock_drive_client,
):
from prowler.providers.googleworkspace.services.drive.drive_shared_drive_members_only_access.drive_shared_drive_members_only_access import (
drive_shared_drive_members_only_access,
)
mock_drive_client.provider = mock_provider
mock_drive_client.policies_fetched = True
mock_drive_client.policies = DrivePolicies(allow_non_member_access=None)
check = drive_shared_drive_members_only_access()
findings = check.execute()
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "not explicitly configured" in findings[0].status_extended
def test_no_findings_when_fetch_failed(self):
"""Test no findings returned when the API fetch failed"""
mock_provider = set_mocked_googleworkspace_provider()
with (
patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=mock_provider,
),
patch(
"prowler.providers.googleworkspace.services.drive.drive_shared_drive_members_only_access.drive_shared_drive_members_only_access.drive_client"
) as mock_drive_client,
):
from prowler.providers.googleworkspace.services.drive.drive_shared_drive_members_only_access.drive_shared_drive_members_only_access import (
drive_shared_drive_members_only_access,
)
mock_drive_client.provider = mock_provider
mock_drive_client.policies_fetched = False
mock_drive_client.policies = DrivePolicies()
check = drive_shared_drive_members_only_access()
findings = check.execute()
assert len(findings) == 0
@@ -0,0 +1,154 @@
from unittest.mock import patch
from prowler.providers.googleworkspace.services.drive.drive_service import DrivePolicies
from tests.providers.googleworkspace.googleworkspace_fixtures import (
CUSTOMER_ID,
DOMAIN,
set_mocked_googleworkspace_provider,
)
class TestDriveSharingAllowlistedDomains:
def test_pass_allowlisted_domains(self):
"""Test PASS when external sharing is restricted to allowlisted domains"""
mock_provider = set_mocked_googleworkspace_provider()
with (
patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=mock_provider,
),
patch(
"prowler.providers.googleworkspace.services.drive.drive_sharing_allowlisted_domains.drive_sharing_allowlisted_domains.drive_client"
) as mock_drive_client,
):
from prowler.providers.googleworkspace.services.drive.drive_sharing_allowlisted_domains.drive_sharing_allowlisted_domains import (
drive_sharing_allowlisted_domains,
)
mock_drive_client.provider = mock_provider
mock_drive_client.policies_fetched = True
mock_drive_client.policies = DrivePolicies(
external_sharing_mode="ALLOWLISTED_DOMAINS"
)
check = drive_sharing_allowlisted_domains()
findings = check.execute()
assert len(findings) == 1
assert findings[0].status == "PASS"
assert "allowlisted domains" in findings[0].status_extended
assert findings[0].resource_name == DOMAIN
assert findings[0].customer_id == CUSTOMER_ID
def test_fail_allowed(self):
"""Test FAIL when external sharing is set to ALLOWED (unrestricted)"""
mock_provider = set_mocked_googleworkspace_provider()
with (
patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=mock_provider,
),
patch(
"prowler.providers.googleworkspace.services.drive.drive_sharing_allowlisted_domains.drive_sharing_allowlisted_domains.drive_client"
) as mock_drive_client,
):
from prowler.providers.googleworkspace.services.drive.drive_sharing_allowlisted_domains.drive_sharing_allowlisted_domains import (
drive_sharing_allowlisted_domains,
)
mock_drive_client.provider = mock_provider
mock_drive_client.policies_fetched = True
mock_drive_client.policies = DrivePolicies(external_sharing_mode="ALLOWED")
check = drive_sharing_allowlisted_domains()
findings = check.execute()
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "ALLOWED" in findings[0].status_extended
def test_fail_disallowed(self):
"""Test FAIL when external sharing is DISALLOWED (stricter than allowlist but not the expected value)"""
mock_provider = set_mocked_googleworkspace_provider()
with (
patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=mock_provider,
),
patch(
"prowler.providers.googleworkspace.services.drive.drive_sharing_allowlisted_domains.drive_sharing_allowlisted_domains.drive_client"
) as mock_drive_client,
):
from prowler.providers.googleworkspace.services.drive.drive_sharing_allowlisted_domains.drive_sharing_allowlisted_domains import (
drive_sharing_allowlisted_domains,
)
mock_drive_client.provider = mock_provider
mock_drive_client.policies_fetched = True
mock_drive_client.policies = DrivePolicies(
external_sharing_mode="DISALLOWED"
)
check = drive_sharing_allowlisted_domains()
findings = check.execute()
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "DISALLOWED" in findings[0].status_extended
def test_fail_no_policy_set(self):
"""Test FAIL when no explicit policy is set (None) but fetch succeeded"""
mock_provider = set_mocked_googleworkspace_provider()
with (
patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=mock_provider,
),
patch(
"prowler.providers.googleworkspace.services.drive.drive_sharing_allowlisted_domains.drive_sharing_allowlisted_domains.drive_client"
) as mock_drive_client,
):
from prowler.providers.googleworkspace.services.drive.drive_sharing_allowlisted_domains.drive_sharing_allowlisted_domains import (
drive_sharing_allowlisted_domains,
)
mock_drive_client.provider = mock_provider
mock_drive_client.policies_fetched = True
mock_drive_client.policies = DrivePolicies(external_sharing_mode=None)
check = drive_sharing_allowlisted_domains()
findings = check.execute()
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "not explicitly configured" in findings[0].status_extended
def test_no_findings_when_fetch_failed(self):
"""Test no findings returned when the API fetch failed"""
mock_provider = set_mocked_googleworkspace_provider()
with (
patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=mock_provider,
),
patch(
"prowler.providers.googleworkspace.services.drive.drive_sharing_allowlisted_domains.drive_sharing_allowlisted_domains.drive_client"
) as mock_drive_client,
):
from prowler.providers.googleworkspace.services.drive.drive_sharing_allowlisted_domains.drive_sharing_allowlisted_domains import (
drive_sharing_allowlisted_domains,
)
mock_drive_client.provider = mock_provider
mock_drive_client.policies_fetched = False
mock_drive_client.policies = DrivePolicies()
check = drive_sharing_allowlisted_domains()
findings = check.execute()
assert len(findings) == 0
@@ -0,0 +1,128 @@
from unittest.mock import patch
from prowler.providers.googleworkspace.services.drive.drive_service import DrivePolicies
from tests.providers.googleworkspace.googleworkspace_fixtures import (
CUSTOMER_ID,
DOMAIN,
set_mocked_googleworkspace_provider,
)
class TestDriveWarnSharingWithAllowlistedDomains:
def test_pass_warning_enabled(self):
"""Test PASS when warning for sharing with allowlisted domains is enabled"""
mock_provider = set_mocked_googleworkspace_provider()
with (
patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=mock_provider,
),
patch(
"prowler.providers.googleworkspace.services.drive.drive_warn_sharing_with_allowlisted_domains.drive_warn_sharing_with_allowlisted_domains.drive_client"
) as mock_drive_client,
):
from prowler.providers.googleworkspace.services.drive.drive_warn_sharing_with_allowlisted_domains.drive_warn_sharing_with_allowlisted_domains import (
drive_warn_sharing_with_allowlisted_domains,
)
mock_drive_client.provider = mock_provider
mock_drive_client.policies_fetched = True
mock_drive_client.policies = DrivePolicies(
warn_for_sharing_outside_allowlisted_domains=True
)
check = drive_warn_sharing_with_allowlisted_domains()
findings = check.execute()
assert len(findings) == 1
assert findings[0].status == "PASS"
assert "warned" in findings[0].status_extended
assert findings[0].resource_name == DOMAIN
assert findings[0].customer_id == CUSTOMER_ID
def test_fail_warning_disabled(self):
"""Test FAIL when warning for sharing with allowlisted domains is disabled"""
mock_provider = set_mocked_googleworkspace_provider()
with (
patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=mock_provider,
),
patch(
"prowler.providers.googleworkspace.services.drive.drive_warn_sharing_with_allowlisted_domains.drive_warn_sharing_with_allowlisted_domains.drive_client"
) as mock_drive_client,
):
from prowler.providers.googleworkspace.services.drive.drive_warn_sharing_with_allowlisted_domains.drive_warn_sharing_with_allowlisted_domains import (
drive_warn_sharing_with_allowlisted_domains,
)
mock_drive_client.provider = mock_provider
mock_drive_client.policies_fetched = True
mock_drive_client.policies = DrivePolicies(
warn_for_sharing_outside_allowlisted_domains=False
)
check = drive_warn_sharing_with_allowlisted_domains()
findings = check.execute()
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "disabled" in findings[0].status_extended
def test_fail_no_policy_set(self):
"""Test FAIL when no explicit policy is set (None) but fetch succeeded"""
mock_provider = set_mocked_googleworkspace_provider()
with (
patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=mock_provider,
),
patch(
"prowler.providers.googleworkspace.services.drive.drive_warn_sharing_with_allowlisted_domains.drive_warn_sharing_with_allowlisted_domains.drive_client"
) as mock_drive_client,
):
from prowler.providers.googleworkspace.services.drive.drive_warn_sharing_with_allowlisted_domains.drive_warn_sharing_with_allowlisted_domains import (
drive_warn_sharing_with_allowlisted_domains,
)
mock_drive_client.provider = mock_provider
mock_drive_client.policies_fetched = True
mock_drive_client.policies = DrivePolicies(
warn_for_sharing_outside_allowlisted_domains=None
)
check = drive_warn_sharing_with_allowlisted_domains()
findings = check.execute()
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "not explicitly configured" in findings[0].status_extended
def test_no_findings_when_fetch_failed(self):
"""Test no findings returned when the API fetch failed"""
mock_provider = set_mocked_googleworkspace_provider()
with (
patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=mock_provider,
),
patch(
"prowler.providers.googleworkspace.services.drive.drive_warn_sharing_with_allowlisted_domains.drive_warn_sharing_with_allowlisted_domains.drive_client"
) as mock_drive_client,
):
from prowler.providers.googleworkspace.services.drive.drive_warn_sharing_with_allowlisted_domains.drive_warn_sharing_with_allowlisted_domains import (
drive_warn_sharing_with_allowlisted_domains,
)
mock_drive_client.provider = mock_provider
mock_drive_client.policies_fetched = False
mock_drive_client.policies = DrivePolicies()
check = drive_warn_sharing_with_allowlisted_domains()
findings = check.execute()
assert len(findings) == 0