Add unit tests for policy_api.py (#862)

This commit is contained in:
Roy Lane
2026-01-02 15:04:20 -05:00
committed by GitHub
parent 5d6d1d13f0
commit 00e5d3a906
17 changed files with 2038 additions and 7 deletions

View File

@@ -1,6 +1,8 @@
# This package is used for software development and is not needed by
# These packages are used for software development and are not needed by
# the Scubagoggles users:
build
pytest>=9
pytest-mock
# There are many Python versions for users to install for ScubaGoggles, and
# because of this, it is too restrictive to limit versions of the dependent

View File

@@ -6,6 +6,15 @@ We focus on verifying the behavior of `scubagoggles` public class methods and ho
## Running Unit Tests
### Prerequisites
Running unit tests locally requires `pytest` and associated packages. You
can install them with using `pip`.
```bash
pip install -r requirements.txt
```
To run all Python unit tests:
```bash

View File

@@ -0,0 +1,134 @@
{
"comment": "apply Google Policy API default values to empty top OU",
"defaults": {
"calendar_external_invitations": {"warnOnInvite": true},
"chat_chat_history": {"allowUserModification": true,
"historyOnByDefault": false},
"chat_external_chat_restriction": {
"allowExternalChat": false,
"externalChatRestriction": "NO_RESTRICTION"},
"drive_and_docs_drive_sdk": {"enableDriveSdkApiAccess": true},
"drive_and_docs_external_sharing": {
"accessCheckerSuggestions": "RECIPIENTS_OR_AUDIENCE_OR_PUBLIC",
"allowNonGoogleInvites": true,
"allowNonGoogleInvitesInAllowlistedDomains": false,
"allowPublishingFiles": true,
"allowReceivingExternalFiles": true,
"allowReceivingFilesOutsideAllowlistedDomains": true,
"allowedPartiesForDistributingContent": "ALL_ELIGIBLE_USERS",
"externalSharingMode": "ALLOWED",
"warnForExternalSharing": true,
"warnForSharingOutsideAllowlistedDomains": true},
"drive_and_docs_general_access_default": {
"defaultFileAccess": "LINK_SHARING_PRIVATE"},
"gmail_workspace_sync_for_outlook": {
"enableGoogleWorkspaceSyncForMicrosoftOutlook": true},
"gmail_email_spam_filter_ip_allowlist": {
"allowedIpAddresses": []},
"gmail_links_and_external_images": {
"applyFutureSettingsAutomatically": true,
"enableAggressiveWarningsOnUntrustedLinks": false},
"gmail_spoofing_and_authentication": {
"applyFutureSettingsAutomatically": true},
"groups_for_business_groups_sharing": {
"collaborationCapability": "DOMAIN_USERS_ONLY",
"createGroupsAccessLevel": "USERS_IN_DOMAIN",
"newGroupsAreHidden": false,
"ownersCanAllowExternalMembers": false,
"ownersCanAllowIncomingMailFromPublic": true,
"ownersCanHideGroups": false,
"viewTopicsDefaultAccessLevel": "DOMAIN_USERS"},
"security_less_secure_apps": {"allowLessSecureApps": false},
"security_super_admin_account_recovery": {
"enableAccountRecovery": false},
"security_user_account_recovery": {"enableAccountRecovery": false},
"workspace_marketplace_apps_access_options": {
"accessLevel": "ALLOW_ALL",
"allowAllInternalApps": false}
},
"service_status": [
"chat",
"drive_and_docs",
"gmail"
],
"policies": {
"topOU": {}
},
"results": {
"topOU": {
"chat_service_status": {
"serviceState": "DISABLED"
},
"drive_and_docs_service_status": {
"serviceState": "DISABLED"
},
"gmail_service_status": {
"serviceState": "DISABLED"
},
"calendar_external_invitations": {
"warnOnInvite": true
},
"chat_chat_history": {
"allowUserModification": true,
"historyOnByDefault": false
},
"chat_external_chat_restriction": {
"allowExternalChat": false,
"externalChatRestriction": "NO_RESTRICTION"
},
"drive_and_docs_drive_sdk": {
"enableDriveSdkApiAccess": true
},
"drive_and_docs_external_sharing": {
"accessCheckerSuggestions": "RECIPIENTS_OR_AUDIENCE_OR_PUBLIC",
"allowNonGoogleInvites": true,
"allowNonGoogleInvitesInAllowlistedDomains": false,
"allowPublishingFiles": true,
"allowReceivingExternalFiles": true,
"allowReceivingFilesOutsideAllowlistedDomains": true,
"allowedPartiesForDistributingContent": "ALL_ELIGIBLE_USERS",
"externalSharingMode": "ALLOWED",
"warnForExternalSharing": true,
"warnForSharingOutsideAllowlistedDomains": true
},
"drive_and_docs_general_access_default": {
"defaultFileAccess": "LINK_SHARING_PRIVATE"
},
"gmail_workspace_sync_for_outlook": {
"enableGoogleWorkspaceSyncForMicrosoftOutlook": true
},
"gmail_email_spam_filter_ip_allowlist": {
"allowedIpAddresses": []
},
"gmail_links_and_external_images": {
"applyFutureSettingsAutomatically": true,
"enableAggressiveWarningsOnUntrustedLinks": false
},
"gmail_spoofing_and_authentication": {
"applyFutureSettingsAutomatically": true
},
"groups_for_business_groups_sharing": {
"collaborationCapability": "DOMAIN_USERS_ONLY",
"createGroupsAccessLevel": "USERS_IN_DOMAIN",
"newGroupsAreHidden": false,
"ownersCanAllowExternalMembers": false,
"ownersCanAllowIncomingMailFromPublic": true,
"ownersCanHideGroups": false,
"viewTopicsDefaultAccessLevel": "DOMAIN_USERS"
},
"security_less_secure_apps": {
"allowLessSecureApps": false
},
"security_super_admin_account_recovery": {
"enableAccountRecovery": false
},
"security_user_account_recovery": {
"enableAccountRecovery": false
},
"workspace_marketplace_apps_access_options": {
"accessLevel": "ALLOW_ALL",
"allowAllInternalApps": false
}
}
}
}

View File

@@ -0,0 +1,64 @@
{
"comment": "apply subset of default values",
"defaults": {
"drive_and_docs_external_sharing": {
"accessCheckerSuggestions": "RECIPIENTS_OR_AUDIENCE_OR_PUBLIC",
"allowNonGoogleInvites": true,
"allowNonGoogleInvitesInAllowlistedDomains": false,
"allowPublishingFiles": true,
"allowReceivingExternalFiles": true,
"allowReceivingFilesOutsideAllowlistedDomains": true,
"allowedPartiesForDistributingContent": "ALL_ELIGIBLE_USERS",
"externalSharingMode": "ALLOWED",
"warnForExternalSharing": true,
"warnForSharingOutsideAllowlistedDomains": true}
},
"service_status": [
"chat",
"drive_and_docs",
"gmail"
],
"policies": {
"topOU": {
"drive_and_docs_service_status": {
"serviceState": "ENABLED"
},
"chat_service_status": {
"serviceState": "ENABLED"
},
"drive_and_docs_external_sharing": {
"allowReceivingExternalFiles": true,
"warnForSharingOutsideAllowlistedDomains": true,
"allowNonGoogleInvitesInAllowlistedDomains": true,
"allowNonGoogleInvites": false,
"allowPublishingFiles": true,
"accessCheckerSuggestions": "RECIPIENTS_ONLY"
}
}
},
"results": {
"topOU": {
"chat_service_status": {
"serviceState": "ENABLED"
},
"drive_and_docs_service_status": {
"serviceState": "ENABLED"
},
"gmail_service_status": {
"serviceState": "DISABLED"
},
"drive_and_docs_external_sharing": {
"accessCheckerSuggestions": "RECIPIENTS_ONLY",
"allowNonGoogleInvites": false,
"allowNonGoogleInvitesInAllowlistedDomains": true,
"allowPublishingFiles": true,
"allowReceivingExternalFiles": true,
"allowReceivingFilesOutsideAllowlistedDomains": true,
"allowedPartiesForDistributingContent": "ALL_ELIGIBLE_USERS",
"externalSharingMode": "ALLOWED",
"warnForExternalSharing": true,
"warnForSharingOutsideAllowlistedDomains": true
}
}
}
}

View File

@@ -0,0 +1,24 @@
{
"comment": "tests construction of group_id_map in PolicyAPI",
"response": {
"groups": [
{
"id": "00gjdgxs0jy4ar3",
"name": "Security Group"
},
{
"id": "02u6wntf4co42dm",
"name": "Secret Group"
},
{
"id": "03mzq4wv2ss2jml",
"name": "test-alias-domains-are-added-to-group-info"
}
]
},
"results": {
"00gjdgxs0jy4ar3": "Security Group",
"02u6wntf4co42dm": "Secret Group",
"03mzq4wv2ss2jml": "test-alias-domains-are-added-to-group-info"
}
}

View File

@@ -0,0 +1,7 @@
{
"comment": "tests no orgunits returned",
"response": {
"groups": []
},
"results": {}
}

View File

@@ -0,0 +1,107 @@
{
"comment": "tests construction of group_id_map in PolicyAPI; 2 responses",
"responses": [
{
"kind": "admin#directory#groups",
"groups": [
{
"id": "00nmf14n3jmlbdu",
"name": "AI DLP Test"
},
{
"id": "03oy7u293r1pgxf",
"name": "CISA VM Team"
},
{
"id": "0206ipza2q1azh5",
"name": "Classroom Teachers"
},
{
"id": "04h042r028q8apg",
"name": "eyesgroup"
},
{
"id": "02y3w247347wbks",
"name": "Intune Users"
},
{
"id": "01664s553blj2nq",
"name": "#junkgroup"
},
{
"id": "0319y80a1pvou5v",
"name": "Even More Secret Group"
},
{
"id": "00kgcv8k1hs05fy",
"name": "SCB Feedback"
},
{
"id": "00lnxbz9168dtgx",
"name": "Techncial Content Owners (Internal)"
}
],
"nextPageToken": "AUdqofHs4_xKcy-HKSs"
},
{
"groups": [
{
"id": "00gjdgxs0jy4ar3",
"name": "Security Group"
},
{
"id": "02u6wntf4co42dm",
"name": "Secret Group"
},
{
"id": "03mzq4wv2ss2jml",
"name": "test-alias-domains-are-added-to-group-info"
},
{
"id": "030j0zll1d0gajt",
"name": "Test Hide 2"
},
{
"id": "02xcytpi2smgulh",
"name": "Test Group"
},
{
"id": "0206ipza0o6vlal",
"name": "Test Google Services"
},
{
"id": "019c6y181lsgu1p",
"name": "Test group without any settings modified"
},
{
"id": "025b2l0r1gxcd5o",
"name": "Test Hiding"
},
{
"id": "045jfvxd4j2cq8t",
"name": "TH-HUNT"
}
]
}
],
"results": {
"00nmf14n3jmlbdu": "AI DLP Test",
"03oy7u293r1pgxf": "CISA VM Team",
"0206ipza2q1azh5": "Classroom Teachers",
"04h042r028q8apg": "eyesgroup",
"02y3w247347wbks": "Intune Users",
"01664s553blj2nq": "#junkgroup",
"0319y80a1pvou5v": "Even More Secret Group",
"00kgcv8k1hs05fy": "SCB Feedback",
"00lnxbz9168dtgx": "Techncial Content Owners (Internal)",
"00gjdgxs0jy4ar3": "Security Group",
"02u6wntf4co42dm": "Secret Group",
"03mzq4wv2ss2jml": "test-alias-domains-are-added-to-group-info",
"030j0zll1d0gajt": "Test Hide 2",
"02xcytpi2smgulh": "Test Group",
"0206ipza0o6vlal": "Test Google Services",
"019c6y181lsgu1p": "Test group without any settings modified",
"025b2l0r1gxcd5o": "Test Hiding",
"045jfvxd4j2cq8t": "TH-HUNT"
}
}

View File

@@ -0,0 +1,21 @@
{
"comment": "tests construction of orgunit_id_map in PolicyAPI",
"response": {
"organizationUnits": [
{"orgUnitId": "id:01abc23defgh456", "name": "Root OU",
"orgUnitPath": "/Root OU"},
{"orgUnitId": "id:02ijk45lmnop789", "name": "Test OU 1",
"orgUnitPath": "/Test OU 1"},
{"orgUnitId": "id:03ph8a2z3oekqyk", "name": "1-1-1-1",
"orgUnitPath": "/1/1-1/1-1-1/1-1-1-1"}
]
},
"results": {
"01abc23defgh456": {"name": "Root OU",
"path": "/Root OU"},
"02ijk45lmnop789": {"name": "Test OU 1",
"path": "/Test OU 1"},
"03ph8a2z3oekqyk": {"name": "1-1-1-1",
"path": "/1/1-1/1-1-1/1-1-1-1"}
}
}

View File

@@ -0,0 +1,7 @@
{
"comment": "tests no orgunits returned",
"response": {
"organizationUnits": []
},
"results": {}
}

View File

@@ -0,0 +1,289 @@
{
"comment": "tests get_policies() in PolicyAPI, two response pages",
"orgunits": {
"03ph8a2z2dvk5ts": {
"name": "topOU",
"path": "/"
}
},
"groups": {},
"defaults": {
"drive_and_docs_external_sharing": {
"accessCheckerSuggestions": "RECIPIENTS_OR_AUDIENCE_OR_PUBLIC",
"allowNonGoogleInvites": true,
"allowNonGoogleInvitesInAllowlistedDomains": false,
"allowPublishingFiles": true,
"allowReceivingExternalFiles": true,
"allowReceivingFilesOutsideAllowlistedDomains": true,
"allowedPartiesForDistributingContent": "ALL_ELIGIBLE_USERS",
"externalSharingMode": "ALLOWED",
"warnForExternalSharing": true,
"warnForSharingOutsideAllowlistedDomains": true}
},
"service_status": [
"chat",
"drive_and_docs",
"gmail"
],
"responses": [
{
"policies": [
{
"name": "policies/axp3f257c243vrgabojnvrfpuefam",
"customer": "customers/C03ymv5su",
"policyQuery": {
"orgUnit": "orgUnits/03ph8a2z2dvk5ts",
"sortOrder": 101
},
"setting": {
"type": "settings/security.super_admin_account_recovery",
"value": {
"enableAccountRecovery": false
}
},
"type": "SYSTEM"
},
{
"name": "policies/axp3f257c243vrgabojnvrfpueffm",
"customer": "customers/C03ymv5su",
"policyQuery": {
"orgUnit": "orgUnits/03ph8a2z2dvk5ts",
"sortOrder": 101
},
"setting": {
"type": "settings/security.two_step_verification_enrollment",
"value": {
"allowEnrollment": true
}
},
"type": "SYSTEM"
},
{
"name": "policies/axp3f257c243vrgabp76r2hb2qgew",
"customer": "customers/C03ymv5su",
"policyQuery": {
"orgUnit": "orgUnits/03ph8a2z2dvk5ts",
"sortOrder": 101
},
"setting": {
"type": "settings/calendar.primary_calendar_max_allowed_external_sharing",
"value": {
"maxAllowedExternalSharing": "EXTERNAL_FREE_BUSY_ONLY"
}
},
"type": "SYSTEM"
},
{
"name": "policies/axp3f257c243vrgabp76r2hb2qgey",
"customer": "customers/C03ymv5su",
"policyQuery": {
"orgUnit": "orgUnits/03ph8a2z2dvk5ts",
"sortOrder": 101
},
"setting": {
"type": "settings/calendar.secondary_calendar_max_allowed_external_sharing",
"value": {
"maxAllowedExternalSharing": "EXTERNAL_ALL_INFO_READ_ONLY"
}
},
"type": "SYSTEM"
},
{
"name": "policies/axp3f257c243vrgabpezjp4byykto",
"customer": "customers/C03ymv5su",
"policyQuery": {
"orgUnit": "orgUnits/03ph8a2z2dvk5ts",
"sortOrder": 101
},
"setting": {
"type": "settings/gmail.user_email_uploads",
"value": {
"enableMailAndContactsImport": true
}
},
"type": "SYSTEM"
}
],
"nextPageToken": "AUdqofHs4_xKcy-HKSs"
},
{
"policies": [
{
"name": "policies/axp3f257c2n4t57edknjfewmr4kwm",
"customer": "customers/C03ymv5su",
"policyQuery": {
"orgUnit": "orgUnits/03ph8a2z2dvk5ts",
"sortOrder": 101.00104
},
"setting": {
"type": "settings/meet.meet_polls",
"value": {
"enabled": true
}
},
"type": "SYSTEM"
},
{
"name": "policies/axp3f257c2n4t57edknjfewmr4kwo",
"customer": "customers/C03ymv5su",
"policyQuery": {
"orgUnit": "orgUnits/03ph8a2z2dvk5ts",
"sortOrder": 101.00104
},
"setting": {
"type": "settings/meet.meet_joining",
"value": {
"allowedAudience": "TRUSTED"
}
},
"type": "SYSTEM"
},
{
"name": "policies/axp3f257c2n4t57edknjfewmr4roy",
"customer": "customers/C03ymv5su",
"policyQuery": {
"orgUnit": "orgUnits/03ph8a2z2dvk5ts",
"sortOrder": 101.00104
},
"setting": {
"type": "settings/meet.meet_joining",
"value": {
"unexpectedSetting": true
}
},
"type": "SYSTEM"
},
{
"name": "policies/axp3f257c3dlbz7scxklpmh2ymcgi",
"customer": "customers/C03ymv5su",
"policyQuery": {
"orgUnit": "orgUnits/03ph8a2z2dvk5ts",
"sortOrder": 101.00107
},
"setting": {
"type": "settings/data_regions.data_processing_region",
"value": {
"limitToStorageRegion": false
}
},
"type": "SYSTEM"
},
{
"name": "policies/axp3f257c3dlbz7scxklpmh2ymcgk",
"customer": "customers/C03ymv5su",
"policyQuery": {
"orgUnit": "orgUnits/03ph8a2z2dvk5ts",
"sortOrder": 101.00107
},
"setting": {
"type": "settings/data_regions.data_at_rest_region",
"value": {
"region": "ANY_REGION"
}
},
"type": "SYSTEM"
},
{
"name": "policies/axp3f257c2op7ruobtezjp4byykr4",
"customer": "customers/C03ymv5su",
"policyQuery": {
"orgUnit": "orgUnits/03ph8a2z2dvk5ts",
"sortOrder": 101.00112
},
"setting": {
"type": "settings/gmail.enhanced_pre_delivery_message_scanning",
"value": {
"enableImprovedSuspiciousContentDetection": true
}
},
"type": "SYSTEM"
},
{
"name": "policies/ahp3f257c3uo74hbesy4pl4rvadac",
"customer": "customers/C03ymv5su",
"policyQuery": {
"orgUnit": "orgUnits/03ph8a2z2dvk5ts",
"sortOrder": 201.00087
},
"setting": {
"type": "settings/chat.service_status",
"value": {
"serviceState": "ENABLED"
}
},
"type": "ADMIN"
},
{
"name": "policies/ahp3f257c26j53pgc22nz4nkz4aqc",
"customer": "customers/C03ymv5su",
"policyQuery": {
"orgUnit": "orgUnits/03ph8a2z2dvk5ts",
"sortOrder": 201.00075
},
"setting": {
"type": "settings/drive_and_docs.service_status",
"value": {
"serviceState": "ENABLED"
}
},
"type": "ADMIN"
}
]
}
],
"results": {
"topOU": {
"security_super_admin_account_recovery": {
"enableAccountRecovery": false
},
"security_two_step_verification_enrollment": {
"allowEnrollment": true
},
"calendar_primary_calendar_max_allowed_external_sharing": {
"maxAllowedExternalSharing": "EXTERNAL_FREE_BUSY_ONLY"
},
"calendar_secondary_calendar_max_allowed_external_sharing": {
"maxAllowedExternalSharing": "EXTERNAL_ALL_INFO_READ_ONLY"
},
"drive_and_docs_external_sharing": {
"accessCheckerSuggestions": "RECIPIENTS_OR_AUDIENCE_OR_PUBLIC",
"allowNonGoogleInvites": true,
"allowNonGoogleInvitesInAllowlistedDomains": false,
"allowPublishingFiles": true,
"allowReceivingExternalFiles": true,
"allowReceivingFilesOutsideAllowlistedDomains": true,
"allowedPartiesForDistributingContent": "ALL_ELIGIBLE_USERS",
"externalSharingMode": "ALLOWED",
"warnForExternalSharing": true,
"warnForSharingOutsideAllowlistedDomains": true
},
"gmail_user_email_uploads": {
"enableMailAndContactsImport": true
},
"meet_meet_polls": {
"enabled": true
},
"meet_meet_joining": {
"allowedAudience": "TRUSTED"
},
"data_regions_data_processing_region": {
"limitToStorageRegion": false
},
"data_regions_data_at_rest_region": {
"region": "ANY_REGION"
},
"gmail_enhanced_pre_delivery_message_scanning": {
"enableImprovedSuspiciousContentDetection": true
},
"chat_service_status": {
"serviceState": "ENABLED"
},
"drive_and_docs_service_status": {
"serviceState": "ENABLED"
},
"gmail_service_status": {
"serviceState": "DISABLED"
}
}
}
}

View File

@@ -0,0 +1,394 @@
{
"comment": "tests get_policies() in PolicyAPI, merge reduction",
"orgunits": {
"03ph8a2z2dvk5ts": {
"name": "topOU",
"path": "/"
},
"03ph8a2z35ltz5g": {
"name": "subOU",
"path": "/subOU"
},
"03ph8a2z1edfqxd": {
"name": "secondOU",
"path": "/secondOU"
},
"03ph8a2z3oekqyk": {
"name": "1-1-1-1",
"path": "/1/1-1/1-1-1/1-1-1-1"
}
},
"groups": {
"02xcytpi2smgulh": "group1",
"019c6y181lsgu1p": "group2"
},
"defaults": {
"groups_for_business_groups_sharing": {
"collaborationCapability": "DOMAIN_USERS_ONLY",
"createGroupsAccessLevel": "USERS_IN_DOMAIN",
"newGroupsAreHidden": false,
"ownersCanAllowExternalMembers": false,
"ownersCanAllowIncomingMailFromPublic": true,
"ownersCanHideGroups": false,
"viewTopicsDefaultAccessLevel": "DOMAIN_USERS"}
},
"service_status": [
"chat",
"drive_and_docs",
"gmail"
],
"responses": [
{
"policies": [
{
"name": "policies/axp3f257c243vrgabojnvrfpuefam",
"customer": "customers/C03ymv5su",
"policyQuery": {
"orgUnit": "orgUnits/03ph8a2z2dvk5ts",
"sortOrder": 101
},
"setting": {
"type": "settings/security.super_admin_account_recovery",
"value": {
"enableAccountRecovery": false
}
},
"type": "SYSTEM"
},
{
"name": "policies/axp3f257c26mjo6eekjnvrfpuefam",
"customer": "customers/C03ymv5su",
"policyQuery": {
"orgUnit": "orgUnits/03ph8a2z2dvk5ts",
"sortOrder": 101.00025
},
"setting": {
"type": "settings/security.super_admin_account_recovery",
"value": {
"enableAccountRecovery": true
}
},
"type": "SYSTEM"
},
{
"name": "policies/axp3f257c3bpbigfbwjnvrfpuefam",
"customer": "customers/C03ymv5su",
"policyQuery": {
"orgUnit": "orgUnits/03ph8a2z2dvk5ts",
"sortOrder": 101.00075
},
"setting": {
"type": "settings/security.super_admin_account_recovery",
"value": {
"enableAccountRecovery": true
}
},
"type": "SYSTEM"
},
{
"name": "policies/ahp3f257c2c7p5gpcwjnvrfpuefam",
"customer": "customers/C03ymv5su",
"policyQuery": {
"orgUnit": "orgUnits/03ph8a2z2dvk5ts",
"sortOrder": 201.00048
},
"setting": {
"type": "settings/security.super_admin_account_recovery",
"value": {
"enableAccountRecovery": false
}
},
"type": "ADMIN"
},
{
"name": "policies/ahp3f257c3pmrbp5asjnvrfpuefam",
"customer": "customers/C03ymv5su",
"policyQuery": {
"orgUnit": "orgUnits/03ph8a2z35ltz5g",
"sortOrder": 202.00002
},
"setting": {
"type": "settings/security.super_admin_account_recovery",
"value": {
"enableAccountRecovery": true
}
},
"type": "ADMIN"
},
{
"name": "policies/ahp3f257c2l6hlozdgjnvrfpuefam",
"customer": "customers/C03ymv5su",
"policyQuery": {
"orgUnit": "orgUnits/03ph8a2z1edfqxd",
"sortOrder": 202
},
"setting": {
"type": "settings/security.super_admin_account_recovery",
"value": {
"enableAccountRecovery": false
}
},
"type": "ADMIN"
},
{
"name": "policies/axp3f257c2v67spzegjnvrfpuefam",
"customer": "customers/C03ymv5su",
"policyQuery": {
"orgUnit": "orgUnits/03ph8a2z2dvk5ts",
"sortOrder": 101.00161
},
"setting": {
"type": "settings/security.super_admin_account_recovery",
"value": {
"enableAccountRecovery": true
}
},
"type": "SYSTEM"
},
{
"name": "policies/axp3f257c3d2dk6tecjnvrfpuefam",
"customer": "customers/C03ymv5su",
"policyQuery": {
"orgUnit": "orgUnits/03ph8a2z2dvk5ts",
"sortOrder": 101.00222
},
"setting": {
"type": "settings/security.super_admin_account_recovery",
"value": {
"enableAccountRecovery": false
}
},
"type": "SYSTEM"
},
{
"name": "policies/ahp3f257c23mlpuvcwjnvrfpuefam",
"customer": "customers/C03ymv5su",
"policyQuery": {
"orgUnit": "orgUnits/03ph8a2z2dvk5ts",
"group": "groups/02xcytpi2smgulh",
"sortOrder": 399.00027
},
"setting": {
"type": "settings/security.super_admin_account_recovery",
"value": {
"enableAccountRecovery": true
}
},
"type": "ADMIN"
},
{
"name": "policies/ahp3f257c3x2xivobcjnvrfpuefam",
"customer": "customers/C03ymv5su",
"policyQuery": {
"orgUnit": "orgUnits/03ph8a2z2dvk5ts",
"group": "groups/019c6y181lsgu1p",
"sortOrder": 399.00013
},
"setting": {
"type": "settings/security.super_admin_account_recovery",
"value": {
"enableAccountRecovery": true
}
},
"type": "ADMIN"
},
{
"name": "policies/ahp3f257c3x2xivobcjnvrfpuefam",
"customer": "customers/C03ymv5su",
"policyQuery": {
"orgUnit": "orgUnits/03ph8a2z2dvk5ts",
"testing comment": "NOTE atypical group name",
"group": "WORKSPACE_ALL_ADMIN_GROUP",
"sortOrder": 2
},
"setting": {
"type": "settings/chat.space_history",
"value": {
"historyState": "DEFAULT_HISTORY_ON"
}
},
"type": "ADMIN"
},
{
"name": "policies/ahp3f257c2c7p5gpcwy4pl4rvadcw",
"customer": "customers/C03ymv5su",
"policyQuery": {
"orgUnit": "orgUnits/03ph8a2z2dvk5ts",
"sortOrder": 201.00048
},
"setting": {
"type": "settings/chat.chat_history",
"value": {
"historyOnByDefault": true
}
},
"type": "ADMIN"
},
{
"name": "policies/ahp3f257c2pnhwhjboy4pl4rvadac",
"customer": "customers/C03ymv5su",
"policyQuery": {
"testing comment": "sub-orgunit",
"orgUnit": "orgUnits/03ph8a2z3oekqyk",
"sortOrder": 205.00001
},
"setting": {
"type": "settings/chat.service_status",
"value": {
"serviceState": "DISABLED"
}
},
"type": "ADMIN"
}
],
"nextPageToken": "AUdqofHs4_xKcy-HKSs"
},
{
"policies": [
{
"name": "policies/ahp3f257c2c7p5gpcwy4pl4rvadcw",
"customer": "customers/C03ymv5su",
"policyQuery": {
"orgUnit": "orgUnits/03ph8a2z2dvk5ts",
"sortOrder": 202
},
"setting": {
"type": "settings/chat.chat_history",
"value": {
"allowUserModification": false
}
},
"type": "ADMIN"
},
{
"name": "policies/ahp3f257c2c7p5gpcwy4pl4rvadcw",
"customer": "customers/C03ymv5su",
"policyQuery": {
"orgUnit": "orgUnits/03ph8a2z2dvk5ts",
"sortOrder": 101.00048
},
"setting": {
"type": "settings/chat.chat_history",
"value": {
"historyOnByDefault": false,
"allowUserModification": true
}
},
"type": "ADMIN"
},
{
"name": "policies/ahp3f257c3uo74hbesy4pl4rvadac",
"customer": "customers/C03ymv5su",
"policyQuery": {
"orgUnit": "orgUnits/03ph8a2z2dvk5ts",
"sortOrder": 201.00087
},
"setting": {
"type": "settings/chat.service_status",
"value": {
"serviceState": "ENABLED"
}
},
"type": "ADMIN"
},
{
"name": "policies/ahp3f257c26j53pgc22nz4nkz4aqc",
"customer": "customers/C03ymv5su",
"policyQuery": {
"orgUnit": "orgUnits/03ph8a2z2dvk5ts",
"sortOrder": 201.00075
},
"setting": {
"type": "settings/groups_for_business.service_status",
"value": {
"serviceState": "ENABLED"
}
},
"type": "ADMIN"
},
{
"name": "policies/awd5vxv7ckojjohaegy4pl4rvaddg",
"customer": "customers/C027ru8g4",
"policyQuery": {
"sortOrder": 101.00125
},
"setting": {
"testing comment": "NOTE no orgunit!",
"type": "settings/chat.chat_file_sharing",
"value": {
"externalFileSharing": "ALL_FILES",
"internalFileSharing": "ALL_FILES"
}
},
"type": "SYSTEM"
}
]
}
],
"results": {
"topOU (group \"group1\")": {
"security_super_admin_account_recovery": {
"enableAccountRecovery": true
}
},
"topOU (group \"group2\")": {
"security_super_admin_account_recovery": {
"enableAccountRecovery": true
}
},
"subOU": {
"security_super_admin_account_recovery": {
"enableAccountRecovery": true
}
},
"secondOU": {
"security_super_admin_account_recovery": {
"enableAccountRecovery": false
}
},
"topOU": {
"chat_chat_history": {
"allowUserModification": false,
"historyOnByDefault": true
},
"chat_chat_file_sharing": {
"externalFileSharing": "ALL_FILES",
"internalFileSharing": "ALL_FILES"
},
"chat_service_status": {
"serviceState": "ENABLED"
},
"groups_for_business_service_status": {
"serviceState": "ENABLED"
},
"security_super_admin_account_recovery": {
"enableAccountRecovery": false
},
"drive_and_docs_service_status": {
"serviceState": "DISABLED"
},
"gmail_service_status": {
"serviceState": "DISABLED"
},
"groups_for_business_groups_sharing": {
"collaborationCapability": "DOMAIN_USERS_ONLY",
"createGroupsAccessLevel": "USERS_IN_DOMAIN",
"newGroupsAreHidden": false,
"ownersCanAllowExternalMembers": false,
"ownersCanAllowIncomingMailFromPublic": true,
"ownersCanHideGroups": false,
"viewTopicsDefaultAccessLevel": "DOMAIN_USERS"
}
},
"topOU (group \"WORKSPACE_ALL_ADMIN_GROUP\")": {
"chat_space_history": {
"historyState": "DEFAULT_HISTORY_ON"
}
},
"1-1-1-1 (in 1/1-1/1-1-1)": {
"chat_service_status": {
"serviceState": "DISABLED"
}
}
}
}

View File

@@ -0,0 +1,62 @@
{
"comment": "tests max reduction for Policy API",
"orgunits": {
"03ph8a2z2dvk5ts": {
"name": "DHS-CISA",
"path": "/"
}
},
"groups": {},
"policies": [
{
"name": "policies/axp3f257c243vrgabpezjp4byykto",
"customer": "customers/C03ymv5su",
"policyQuery": {
"query": "entity.org_units.exists(org_unit, org_unit.org_unit_id == orgUnitId('03ph8a2z2dvk5ts')) && entity.licenses.exists(license, license in ['/product/Google-Apps/sku/1010020020'])",
"orgUnit": "orgUnits/03ph8a2z2dvk5ts",
"sortOrder": 101
},
"setting": {
"type": "settings/gmail.user_email_uploads",
"value": {
"enableMailAndContactsImport": true
}
},
"type": "SYSTEM"
},
{
"name": "policies/ahp3f257c2c7p5gpcxezjp4byykto",
"customer": "customers/C03ymv5su",
"policyQuery": {
"query": "entity.org_units.exists(org_unit, org_unit.org_unit_id == orgUnitId('03ph8a2z2dvk5ts')) && entity.licenses.exists(license, license in ['/product/Google-Apps/sku/1010020020'])",
"orgUnit": "orgUnits/03ph8a2z2dvk5ts",
"sortOrder": 201.00049
},
"setting": {
"type": "settings/gmail.user_email_uploads",
"value": {
"enableMailAndContactsImport": false
}
},
"type": "ADMIN"
}
],
"results": {
"DHS-CISA/gmail_user_email_uploads": {
"name": "policies/ahp3f257c2c7p5gpcxezjp4byykto",
"customer": "customers/C03ymv5su",
"policyQuery": {
"query": "entity.org_units.exists(org_unit, org_unit.org_unit_id == orgUnitId('03ph8a2z2dvk5ts')) && entity.licenses.exists(license, license in ['/product/Google-Apps/sku/1010020020'])",
"orgUnit": "orgUnits/03ph8a2z2dvk5ts",
"sortOrder": 201.00049
},
"setting": {
"type": "settings/gmail.user_email_uploads",
"value": {
"enableMailAndContactsImport": false
}
},
"type": "ADMIN"
}
}
}

View File

@@ -0,0 +1,150 @@
{
"comment": "tests merge reduction for Policy API",
"orgunits": {
"03ph8a2z2dvk5ts": {
"name": "DHS-CISA",
"path": "/"
},
"03ph8a2z35ltz5g": {
"name": "Alden's test OU",
"path": "/Alden's test OU"
},
"03ph8a2z1edfqxd": {
"name": "super admins (test)",
"path": "/super admins (test)"
}
},
"groups": {},
"policies": [
{
"name": "policies/axp3f257c243vrgabojnvrfpuefam",
"customer": "customers/C03ymv5su",
"policyQuery": {
"query": "entity.org_units.exists(org_unit, org_unit.org_unit_id == orgUnitId('03ph8a2z2dvk5ts'))",
"orgUnit": "orgUnits/03ph8a2z2dvk5ts",
"sortOrder": 101
},
"setting": {
"type": "settings/security.super_admin_account_recovery",
"value": {
"enableAccountRecovery": false
}
},
"type": "SYSTEM"
},
{
"name": "policies/ahp3f257c2c7p5gpcwjnvrfpuefam",
"customer": "customers/C03ymv5su",
"policyQuery": {
"query": "entity.org_units.exists(org_unit, org_unit.org_unit_id == orgUnitId('03ph8a2z2dvk5ts'))",
"orgUnit": "orgUnits/03ph8a2z2dvk5ts",
"sortOrder": 201.00049
},
"setting": {
"type": "settings/security.super_admin_account_recovery",
"value": {
"enableAccountRecovery": false
}
},
"type": "ADMIN"
},
{
"name": "policies/ahp3f257c3pmrbp5asjnvrfpuefam",
"customer": "customers/C03ymv5su",
"policyQuery": {
"query": "entity.org_units.exists(org_unit, org_unit.org_unit_id == orgUnitId('03ph8a2z35ltz5g'))",
"orgUnit": "orgUnits/03ph8a2z35ltz5g",
"sortOrder": 202
},
"setting": {
"type": "settings/security.super_admin_account_recovery",
"value": {
"enableAccountRecovery": false
}
},
"type": "ADMIN"
},
{
"name": "policies/ahp3f257c2l6hlozdgjnvrfpuefam",
"customer": "customers/C03ymv5su",
"policyQuery": {
"query": "entity.org_units.exists(org_unit, org_unit.org_unit_id == orgUnitId('03ph8a2z1edfqxd'))",
"orgUnit": "orgUnits/03ph8a2z1edfqxd",
"sortOrder": 202
},
"setting": {
"type": "settings/security.super_admin_account_recovery",
"value": {
"enableAccountRecovery": false
}
},
"type": "ADMIN"
},
{
"name": "policies/axp3f257c3d2dk6tecjnvrfpuefam",
"customer": "customers/C03ymv5su",
"policyQuery": {
"query": "entity.org_units.exists(org_unit, org_unit.org_unit_id == orgUnitId('03ph8a2z2dvk5ts'))",
"orgUnit": "orgUnits/03ph8a2z2dvk5ts",
"sortOrder": 101.00213
},
"setting": {
"type": "settings/security.super_admin_account_recovery",
"value": {
"enableAccountRecovery": false
}
},
"type": "SYSTEM"
}
],
"results": {
"Alden's test OU/security_super_admin_account_recovery": {
"name": "policies/ahp3f257c3pmrbp5asjnvrfpuefam",
"customer": "customers/C03ymv5su",
"policyQuery": {
"query": "entity.org_units.exists(org_unit, org_unit.org_unit_id == orgUnitId('03ph8a2z35ltz5g'))",
"orgUnit": "orgUnits/03ph8a2z35ltz5g",
"sortOrder": 202
},
"setting": {
"type": "settings/security.super_admin_account_recovery",
"value": {
"enableAccountRecovery": false
}
},
"type": "ADMIN"
},
"super admins (test)/security_super_admin_account_recovery": {
"name": "policies/ahp3f257c2l6hlozdgjnvrfpuefam",
"customer": "customers/C03ymv5su",
"policyQuery": {
"query": "entity.org_units.exists(org_unit, org_unit.org_unit_id == orgUnitId('03ph8a2z1edfqxd'))",
"orgUnit": "orgUnits/03ph8a2z1edfqxd",
"sortOrder": 202
},
"setting": {
"type": "settings/security.super_admin_account_recovery",
"value": {
"enableAccountRecovery": false
}
},
"type": "ADMIN"
},
"DHS-CISA/security_super_admin_account_recovery": {
"name": "policies/ahp3f257c2c7p5gpcwjnvrfpuefam",
"customer": "customers/C03ymv5su",
"policyQuery": {
"query": "entity.org_units.exists(org_unit, org_unit.org_unit_id == orgUnitId('03ph8a2z2dvk5ts'))",
"orgUnit": "orgUnits/03ph8a2z2dvk5ts",
"sortOrder": 201.00049
},
"setting": {
"type": "settings/security.super_admin_account_recovery",
"value": {
"enableAccountRecovery": false
}
},
"type": "ADMIN"
}
}
}

View File

@@ -0,0 +1,97 @@
{
"comment": "successful Policy API verification (includes non-verified values)",
"policies": {
"topOU": {
"calendar_service_status": {
"serviceState": "ENABLED"
},
"classroom_service_status": {
"serviceState": "ENABLED"
},
"notebooklm_service_status": {
"serviceState": "untracked setting"
},
"ai_studio_service_status": {
"serviceState": "ENABLED"
},
"domains_service_status": {
"serviceState": "ENABLED"
},
"drive_and_docs_external_sharing": {
"externalSharingMode": "ALLOWED",
"allowReceivingExternalFiles": true,
"warnForSharingOutsideAllowlistedDomains": true,
"allowReceivingFilesOutsideAllowlistedDomains": true,
"allowNonGoogleInvitesInAllowlistedDomains": true,
"warnForExternalSharing": true,
"allowNonGoogleInvites": false,
"allowPublishingFiles": true,
"accessCheckerSuggestions": "RECIPIENTS_ONLY",
"allowedPartiesForDistributingContent": "ALL_ELIGIBLE_USERS"
},
"security_two_step_verification_enforcement": {
"enforcedFrom": "2025-02-04T11:11:28.346Z"
},
"gmail_email_spam_filter_ip_allowlist": {
"allowedIpAddresses": [
"8.8.8.8/24"
]
},
"security_password": {
"allowedStrength": "STRONG",
"minimumLength": 12,
"maximumLength": 100,
"enforceRequirementsAtLogin": true,
"allowReuse": false,
"expirationDuration": "0s"
}
}
},
"expected_settings": {
"calendar_service_status": {
"settings": {
"serviceState": "isState"
}
},
"classroom_service_status": {
"settings": {
"serviceState": "isState"
}
},
"drive_and_docs_external_sharing": {
"settings": {
"accessCheckerSuggestions": "isEnum",
"allowNonGoogleInvites": "isBool",
"allowNonGoogleInvitesInAllowlistedDomains": "isBool",
"allowPublishingFiles": "isBool",
"allowReceivingExternalFiles": "isBool",
"allowReceivingFilesOutsideAllowlistedDomains": "isBool",
"allowedPartiesForDistributingContent": "isEnum",
"externalSharingMode": "isEnum",
"warnForExternalSharing": "isBool",
"warnForSharingOutsideAllowlistedDomains": "isBool"
}
},
"security_password": {
"settings": {
"allowedStrength": "isEnum",
"allowReuse": "isBool",
"enforceRequirementsAtLogin": "isBool",
"expirationDuration": "isDuration",
"maximumLength": "isInt",
"minimumLength": "isInt"
}
},
"security_two_step_verification_enforcement": {
"settings": {
"enforcedFrom": "isTimestamp"
}
},
"gmail_email_spam_filter_ip_allowlist": {
"settings": {
"allowedIpAddresses": "isListStrings"
}
}
},
"results": []
}

View File

@@ -0,0 +1,99 @@
{
"comment": "successful Policy API verification (includes non-verified values)",
"policies": {
"topOU": {
"classroom_service_status": {
"serviceState": "bad value"
},
"notebooklm_service_status": {
"serviceState": "untracked setting"
},
"drive_and_docs_external_sharing": {
"externalSharingMode": "not an enum",
"allowReceivingExternalFiles": 1,
"warnForSharingOutsideAllowlistedDomains": true,
"allowReceivingFilesOutsideAllowlistedDomains": true,
"allowNonGoogleInvitesInAllowlistedDomains": true,
"warnForExternalSharing": "true",
"allowNonGoogleInvites": false,
"allowPublishingFiles": true,
"accessCheckerSuggestions": "RECIPIENTS_ONLY",
"allowedPartiesForDistributingContent": "ALL_ELIGIBLE_USERS"
},
"security_two_step_verification_enforcement": {
"enforcedFrom": "20253-02-04T11:11:28.346Z"
},
"gmail_email_spam_filter_ip_allowlist": {
"allowedIpAddresses": [
"8.8.8.8/24",
100
]
},
"security_password": {
"allowedStrength": 3,
"maximumLength": 100,
"enforceRequirementsAtLogin": true,
"allowReuse": false,
"expirationDuration": "20d"
}
}
},
"expected_settings": {
"calendar_service_status": {
"settings": {
"serviceState": "isState"
}
},
"classroom_service_status": {
"settings": {
"serviceState": "isState"
}
},
"drive_and_docs_external_sharing": {
"settings": {
"accessCheckerSuggestions": "isEnum",
"allowNonGoogleInvites": "isBool",
"allowNonGoogleInvitesInAllowlistedDomains": "isBool",
"allowPublishingFiles": "isBool",
"allowReceivingExternalFiles": "isBool",
"allowReceivingFilesOutsideAllowlistedDomains": "isBool",
"allowedPartiesForDistributingContent": "isEnum",
"externalSharingMode": "isEnum",
"warnForExternalSharing": "isBool",
"warnForSharingOutsideAllowlistedDomains": "isBool"
}
},
"security_password": {
"settings": {
"allowedStrength": "isEnum",
"allowReuse": "isBool",
"enforceRequirementsAtLogin": "isBool",
"expirationDuration": "isDuration",
"maximumLength": "isInt",
"minimumLength": "isInt"
}
},
"security_two_step_verification_enforcement": {
"settings": {
"enforcedFrom": "isTimestamp"
}
},
"gmail_email_spam_filter_ip_allowlist": {
"settings": {
"allowedIpAddresses": "isListStrings"
}
}
},
"results": [
"calendar_service_status.serviceState",
"classroom_service_status.serviceState",
"drive_and_docs_external_sharing.allowReceivingExternalFiles",
"drive_and_docs_external_sharing.externalSharingMode",
"drive_and_docs_external_sharing.warnForExternalSharing",
"gmail_email_spam_filter_ip_allowlist.allowedIpAddresses",
"security_two_step_verification_enforcement.enforcedFrom",
"security_password.allowedStrength",
"security_password.expirationDuration",
"security_password.minimumLength"
]
}

View File

@@ -0,0 +1,559 @@
"""Tests for the PolicyAPI class.
"""
import json
import re
from pathlib import Path
import pytest
# The import is needed as stated and not how pylint wants it.
# pylint: disable=consider-using-from-import
import google.auth.transport.requests as requests
import scubagoggles.auth as auth
from scubagoggles.policy_api import PolicyAPI
class MockGwsAuth:
"""Mocks the GwsAuth class - the tests in this module do not call any
Google API.
"""
# pylint: disable=missing-function-docstring
# pylint: disable=too-few-public-methods
@property
def credentials(self):
return None
class MockSession:
"""Mocks Google's AuthorizedSession class. This along with the above
class are used to allow the instantiation of the PolicyAPI class without
making any calls to the Google API.
"""
# pylint: disable=missing-function-docstring
def __init__(self, credentials):
self._close_count = 0
self._credentials = credentials
def close(self):
self._close_count += 1
def get(self, *_):
pass
auth.GwsAuth = MockGwsAuth
requests.AuthorizedSession = MockSession
class TestPolicyApi:
"""This class contains unit tests for the PolicyAPI class.
"""
# The test module needs to access "internal" methods.
# pylint: disable=protected-access
_data_dir = Path(__file__).parent / 'data'
def test_close(self, monkeypatch):
"""Tests that the AuthorizedSession is closed when the PolicyAPI is
used as a context manager. Closing the session causes the resources
to be cleaned up.
"""
self._patch_policy_api(monkeypatch)
with PolicyAPI(auth.GwsAuth(), 'topOU') as policy_api:
session = policy_api._session
assert session._close_count == 1
@pytest.mark.parametrize(('value', 'expected'),
(# Valid values
(True, True),
(False, True),
# Invalid values
(1100, False),
('true', False),
('False', False)))
def test_isbool(self, value, expected):
"""Tests for the isBool() lambda used in the PolicyAPI expected
settings.
"""
assert PolicyAPI.isBool(value) is expected
@pytest.mark.parametrize(('value', 'expected'),
(# Valid values
('TEST', True),
('TRUSTED_DOMAINS', True),
# Invalid values
(32768, False),
('192.168.0.1', False)))
def test_isenum(self, value, expected):
"""Tests for the isEnum() lambda used in the PolicyAPI expected
settings.
"""
assert PolicyAPI.isEnum(value) is expected
@pytest.mark.parametrize(('value', 'expected'),
(# Valid values
(50, True),
(-463, True),
# Invalid values
(3.14, False),
('TEST', False)))
def test_isint(self, value, expected):
"""Tests for the isInt() lambda used in the PolicyAPI expected
settings.
"""
assert PolicyAPI.isInt(value) is expected
@pytest.mark.parametrize(('value', 'expected'),
(# Valid values
(['one', 'two', 'three'], True),
# Invalid values
([1, 2, 3], False),
(['four', 6, 'six'], False),
('test', False)))
def test_isliststrings(self, value, expected):
"""Tests for the isListStrings() lambda used in the PolicyAPI expected
settings.
"""
assert PolicyAPI.isListStrings(value) is expected
@pytest.mark.parametrize(('value', 'expected'),
(# Valid values
('enabled', True),
('disabled', True),
('EnAblEd', True),
('disABLEd', True),
# Invalid values
('NOTHING', False),
('disable', False)))
def test_isstate(self, value, expected):
"""Tests for the isState() lambda used in the PolicyAPI expected
settings.
"""
assert PolicyAPI.isState(value) is expected
@pytest.mark.parametrize(('value', 'expected'),
(# Valid values
('test', True),
('disabled', True),
# Invalid values
(True, False),
(82, False)))
def test_isstring(self, value, expected):
"""Tests for the isString() lambda used in the PolicyAPI expected
settings.
"""
assert PolicyAPI.isString(value) is expected
@pytest.mark.parametrize(('value', 'expected'),
(# Valid values
('5s', True),
('24h', True),
('7m', True),
# Invalid values
(2, False),
('tomorrow', False),
('7z', False),
('-2d', False),
('4months', False),
('3d', False),
('8.5h', False)))
def test_isduration(self, value, expected):
"""Tests for the isDuration() lambda used in the PolicyAPI expected
settings.
"""
assert PolicyAPI.isDuration(value) is expected
@pytest.mark.parametrize(('value', 'expected'),
(# Valid values
('2025-02-24T17:40:27.050Z', True),
('2032-04-13T06:34:27Z', True),
# Invalid values
('2012-10-312T17:40:0Z', False),
('22-', False)))
def test_istimestamp(self, value, expected):
"""Tests for the isTimestamp() lambda used in the PolicyAPI expected
settings.
"""
assert PolicyAPI.isTimestamp(value) is expected
def test_expected_settings(self):
"""Tests the PolicyAPI expected settings data structure.
"""
expected_settings = PolicyAPI._expectedPolicySettings
for section_name, section_data in expected_settings.items():
assert isinstance(section_name, str)
# Each section must contain settings, and optionally a reducer.
settings_found = False
for name, value in section_data.items():
assert name in ('settings', 'reducer')
match name:
case 'settings':
settings_found = True
# Each setting must contain a validator.
for setting_name, validator in value.items():
assert isinstance(setting_name, str)
assert validator in (PolicyAPI.isBool,
PolicyAPI.isDuration,
PolicyAPI.isEnum,
PolicyAPI.isInt,
PolicyAPI.isListStrings,
PolicyAPI.isState,
PolicyAPI.isString,
PolicyAPI.isTimestamp)
case 'reducer':
assert value in (PolicyAPI._merge_reducer,)
assert settings_found, f'section: {section_name}'
def test_default_value(self):
"""Tests the default values in the PolicyAPI class.
"""
expected_settings = PolicyAPI._expectedPolicySettings
# For each default value, it must belong to a valid section and
# setting (as defined in the expected policy settings data structure).
# The default value itself must pass the validator.
for section_name, section_data in PolicyAPI._defaults.items():
section_settings = expected_settings[section_name]['settings']
for setting_name, setting_default in section_data.items():
assert section_name in expected_settings
assert setting_name in section_settings
validator = section_settings[setting_name]
assert validator(setting_default)
def test_get_groups(self, monkeypatch, subtests):
"""Tests the Policy API method for getting GWS groups and storing
them internally in the '_group_id_map'.
"""
monkeypatch.setattr(PolicyAPI, '_get_ou', lambda x: None)
for test_name, test_data in self._next_test_data('policyapi_get_groups'):
with subtests.test(msg = f'subtest: {test_name}'):
self._patch_get(monkeypatch, test_data)
policy_api = PolicyAPI(auth.GwsAuth(), 'topOU')
result = policy_api._group_id_map
assert result == test_data['results']
def test_get_policies(self, monkeypatch, subtests):
"""Tests the Policy API method for converting the raw policy data
returned by Google to the format used by ScubaGoggles for Rego.
"""
for test_name, test_data in self._next_test_data('policyapi_get_policies'):
with subtests.test(msg = f'subtest: {test_name}'):
self._patch_policy_api(monkeypatch, test_data)
self._patch_get(monkeypatch, test_data)
self._patch_service_status(monkeypatch, test_data)
test_defaults = test_data['defaults']
monkeypatch.setattr(PolicyAPI, '_defaults', test_defaults)
policy_api = PolicyAPI(auth.GwsAuth(), 'topOU')
result = policy_api.get_policies()
assert result == test_data['results']
def test_get_ou(self, monkeypatch, subtests):
"""Tests the Policy API method for getting GWS orgunits and storing
them internally in the '_orgunit_id_map'.
"""
monkeypatch.setattr(PolicyAPI, '_get_groups', lambda x: None)
for test_name, test_data in self._next_test_data('policyapi_get_ou'):
with subtests.test(msg = f'subtest: {test_name}'):
self._patch_get(monkeypatch, test_data)
policy_api = PolicyAPI(auth.GwsAuth(), 'topOU')
result = policy_api._orgunit_id_map
assert result == test_data['results']
def test_verify(self, monkeypatch, subtests):
"""Tests the PolicyAPI verify() method for ensuring that policy
setting values are the expected type. Test data is stored in
JSON-formatted files in the "data" subdirectory. This includes
the input policy settings and the expected list of invalid
settings.
"""
for test_name, test_data in self._next_test_data('policyapi_verify'):
with subtests.test(msg = f'subtest: {test_name}'):
self._patch_policy_api(monkeypatch, test_data)
expected_settings = test_data['expected_settings']
self._add_validators(expected_settings)
monkeypatch.setattr(PolicyAPI,
'_expectedPolicySettings',
expected_settings)
policy_api = PolicyAPI(auth.GwsAuth(), 'topOU')
missing_policies = policy_api.verify(test_data['policies'])
self._compare_verify(missing_policies, test_data)
def test_verify_novalue(self, monkeypatch, caplog):
"""Tests the simple case where the Policy API verify() method
is provided with no policy settings for the top-level orgunit.
"""
top_ou = 'topOU'
self._patch_policy_api(monkeypatch, {'orgunits': {top_ou}})
expected_message = f'No policy settings found for orgunit: {top_ou}'
policy_api = PolicyAPI(auth.GwsAuth(), top_ou)
policy_api.verify({})
assert len(caplog.records) == 1
assert caplog.records[0].message == expected_message
def test_reducer(self, monkeypatch, subtests):
"""Tests the Policy API reduction of policy data. Test data is
stored in JSON-formatted files in the "data" subdirectory. The
data is manually generated by extracting portions of real data
returned by Google's Policy API - see the dump() method in the
policy_api module. The expected results are produced by calling
the PolicyAPI _reduce() method using the input data, and then
calling _write_reduction() in this module to write the JSON to
be included in the test input data.
"""
for test_name, test_data in self._next_test_data('policyapi_reducer'):
with subtests.test(msg = f'subtest: {test_name}'):
self._patch_policy_api(monkeypatch, test_data)
policy_api = PolicyAPI(auth.GwsAuth(), 'topOU')
policy_api._reduce(test_data['policies'])
self._compare_reduction(policy_api, test_data)
def test_apply_defaults(self, monkeypatch, subtests):
"""Tests the method of the Policy API that applies default values
to policy settings in the top-level orgunit when certain settings
are missing. Test data includes a set of defaults to apply, the
policy settings, and the expected result once the defaults have
been applied.
"""
for test_name, test_data in self._next_test_data('policyapi_defaults'):
with subtests.test(msg = f'subtest: {test_name}'):
self._patch_policy_api(monkeypatch, test_data)
test_defaults = test_data['defaults']
monkeypatch.setattr(PolicyAPI, '_defaults', test_defaults)
self._patch_service_status(monkeypatch, test_data)
policy_api = PolicyAPI(auth.GwsAuth(), 'topOU')
policy_api._apply_defaults(test_data['policies'])
self._compare_defaults(test_data)
@classmethod
def _next_test_data(cls, test_prefix):
for input_file in cls._data_dir.glob(f'{test_prefix}*.json'):
test_name = input_file.stem
if not re.match(fr'{test_prefix}\d*$', test_name):
continue
test_data = json.loads(input_file.read_text())
yield test_name, test_data
@staticmethod
def _compare_defaults(test_data: dict):
"""Compares the result of applying policy setting defaults with the
expected result from the test data.
"""
policies = test_data['policies']
results = test_data['results']
assert policies == results
@staticmethod
def _compare_reduction(policy_api: PolicyAPI, test_data: dict):
"""Compares the result of a policy reduction with the expected
result from the test data.
"""
# Because the test data is stored as a JSON-formatted file, the
# key for the policy reduction map was converted to a slash (/)
# separated string and this needs to be converted to a tuple
# before the comparison.
expected_result = {tuple(k.split('/')): v
for k, v in test_data['results'].items()}
assert policy_api._reduction_map == expected_result
@staticmethod
def _compare_verify(missing_policies: set, test_data: dict):
"""Compares the result of policy setting verification with the
expected result from the test data.
"""
expected_result = sorted(test_data['results'])
assert sorted(missing_policies) == expected_result
@staticmethod
def _write_reduction(policy_api: PolicyAPI, temp_file: Path):
"""Used to generate test data by writing the policy reduction map
produced by the PolicyAPI's _reduce() method. Use the written JSON
data to cut/paste it into the test input data, which should already
include the orgunits, groups, and policy data for the test.
"""
# The key for the reduction map is a tuple, which isn't supported in
# JSON, so this is converted into a string key, with the components
# of the tuple separated by a slash (/).
save_dict = {'results': {'/'.join(k): v
for k, v in policy_api._reduction_map.items()}}
with temp_file.open('w', encoding = 'utf-8') as out_stream:
json.dump(save_dict, out_stream, indent = 2)
@staticmethod
def _patch_get(monkeypatch, test_data: dict):
def multi_get(_, _unused_url, params):
# This simulates multi-page responses. The test data must contain
# a "responses" (plural) section and all but the last response
# must contain a "nextPageToken".
next_token = 'nextPageToken'
responses = test_data.get('responses')
if not responses:
return None
if not params or 'pageToken' not in params:
return responses[0]
for index, response in enumerate(responses):
if (next_token in response
and response[next_token].startswith(params['pageToken'])):
return responses[index + 1]
raise RuntimeError('missing or mismatched next page token')
def single_get(*_):
# This simulates a single-page response. The test data must
# contain a "response" (singular) section.
return test_data.get('response')
mock_get = multi_get if 'responses' in test_data else single_get
monkeypatch.setattr(PolicyAPI, '_get', mock_get)
@staticmethod
def _patch_policy_api(monkeypatch, test_data: dict = None):
"""Sets up the PolicyAPI class so it can be used with test methods.
The given test data must include a dictionary with optional keys
"orgunits" and "groups" that may contain a set of orgunit and group
names, respectively. These take the place of the PolicyAPI class
calling Google for those names.
"""
def mock_get_ou(_):
return test_data.get('orgunits') if test_data else None
def mock_get_groups(_):
return test_data.get('groups') if test_data else None
monkeypatch.setattr(PolicyAPI, '_get_ou', mock_get_ou)
monkeypatch.setattr(PolicyAPI, '_get_groups', mock_get_groups)
@staticmethod
def _patch_service_status(monkeypatch, test_data: dict):
"""Adds the service status expected Policy API settings using
the list of services in the test data. This allows the test to
have a predictable number of expected services.
"""
services = test_data.get('service_status', ())
# To insulate the testing somewhat from changes made by Google over
# time, we remove the service status settings from the expected set
# and replace them with specific settings defined for the test.
expected_settings = {k: v for k, v
in PolicyAPI._expectedPolicySettings.items()
if not k.endswith('_service_status')}
for service in services:
service_status = f'{service}_service_status'
expected_settings[service_status] = {'settings':
{'serviceState':
PolicyAPI.isState}}
monkeypatch.setattr(PolicyAPI,
'_expectedPolicySettings',
expected_settings)
@staticmethod
def _add_validators(expected_settings: dict):
"""Given expected policy settings from test data that includes
the verifier as a string, this method replaces the verifier
string with the function from the PolicyAPI class that
performs the verification.
"""
for section_data in expected_settings.values():
expected_settings = section_data['settings']
for setting_name, verifier_name in expected_settings.items():
verifier = getattr(PolicyAPI, verifier_name)
expected_settings[setting_name] = verifier

View File

@@ -15,7 +15,10 @@ from pathlib import Path
from random import random
from time import sleep
from google.auth.transport.requests import AuthorizedSession
# Required for unit testing:
# pylint: disable=consider-using-from-import
import google.auth.transport.requests as requests
from scubagoggles.auth import GwsAuth
@@ -44,7 +47,8 @@ class PolicyAPI:
# Google's "enum" type is essentially the string name for the enumeration
# member. It must be all alphanumeric characters with possible underscores.
isEnum = lambda x: isinstance(x, str) and re.match(r'^[A-Z0-9_]+$', x)
isEnum = lambda x: (isinstance(x, str)
and re.match(r'^[A-Z0-9_]+$', x) is not None)
isInt = lambda x: isinstance(x, int)
@@ -55,12 +59,13 @@ class PolicyAPI:
isString = lambda x: isinstance(x, str)
isDuration = lambda x: isinstance(x, str) and re.match(r'(?i)^\d+[hms]$', x)
isDuration = lambda x: (isinstance(x, str)
and re.match(r'(?i)^\d+[hms]$', x) is not None)
isTimestamp = lambda x: (isinstance(x, str)
and re.match(r'(?i)^\d{4}(?:-\d{2}){2}T\d{2}'
r'(?::\d{2}){2}(?:\.\d+)?z$',
x))
x) is not None)
# There may be duplicate policies returned for an orgunit/group and
# section. The policies must be "reduced" to single settings using
@@ -133,6 +138,7 @@ class PolicyAPI:
'allowAccess': isBool,
'whoCanManageGuardianAccess': isEnum}},
'classroom_roster_import': {'settings': {'rosterImportOption': isEnum}},
'classroom_service_status': {'settings': {'serviceState': isState}},
'classroom_student_unenrollment': {'settings': {
'whoCanUnenrollStudents': isEnum}},
'classroom_teacher_permissions': {'settings': {
@@ -377,7 +383,7 @@ class PolicyAPI:
# Google's AuthorizedSession is currently being used because this
# API is not available in the Google API Client interface.
self._session = AuthorizedSession(gws_auth.credentials)
self._session = requests.AuthorizedSession(gws_auth.credentials)
self._top_orgunit = top_orgunit
@@ -711,7 +717,7 @@ class PolicyAPI:
# If there is a reducer associated with this policy, it will
# be invoked.
reduce_name = expected_settings.get('reduce_method')
reduce_name = expected_settings.get('reducer')
if reduce_name:
reduce_method = getattr(self, reduce_name)