@@ -60,10 +60,9 @@ def teardown():
6060
6161
6262def setup_shared_modules ():
63- for _ in range (3 ) :
64- _ , module_id = add_custom_module (ORGANIZATION_ID )
65- if module_id != "" :
66- shared_modules .append (module_id )
63+ _ , module_id = add_custom_module (ORGANIZATION_ID )
64+ if module_id != "" :
65+ shared_modules .append (module_id )
6766
6867
6968def add_module_to_cleanup (module_id ):
@@ -132,7 +131,17 @@ def extract_custom_module_id(module_name):
132131 return ""
133132
134133
134+ @backoff .on_exception (
135+ backoff .expo , (InternalServerError , ServiceUnavailable , NotFound ), max_tries = 3
136+ )
135137def add_custom_module (org_id : str ):
138+ """
139+ Adds a new SHA custom module.
140+ Args:
141+ org_id (str): The organization ID.
142+ Returns:
143+ Tuple[str, str]: The name and ID of the created custom module.
144+ """
136145
137146 parent = f"organizations/{ org_id } /locations/global"
138147 client = securitycentermanagement_v1 .SecurityCenterManagementClient ()
@@ -146,24 +155,24 @@ def add_custom_module(org_id: str):
146155 "display_name" : display_name ,
147156 "enablement_state" : "ENABLED" ,
148157 "custom_config" : {
149- "description" : "Sample custom module for testing purpose . Please do not delete." ,
158+ "description" : "Sample custom module for testing purposes . Please do not delete." ,
150159 "predicate" : {
151160 "expression" : "has(resource.rotationPeriod) && (resource.rotationPeriod > duration('2592000s'))" ,
152- "title" : "GCE Instance High Severity " ,
153- "description" : "Custom module to detect high severity issues on GCE instances ." ,
161+ "title" : "Cloud KMS CryptoKey Rotation Period " ,
162+ "description" : "Custom module to detect CryptoKeys with rotation period greater than 30 days ." ,
154163 },
155- "recommendation" : "Ensure proper security configurations on GCE instances ." ,
164+ "recommendation" : "Review and adjust the rotation period for Cloud KMS CryptoKeys ." ,
156165 "resource_selector" : {"resource_types" : ["cloudkms.googleapis.com/CryptoKey" ]},
157166 "severity" : "CRITICAL" ,
158167 "custom_output" : {
159168 "properties" : [
160169 {
161170 "name" : "example_property" ,
162171 "value_expression" : {
163- "description" : "The name of the instance " ,
172+ "description" : "The resource name of the CryptoKey " ,
164173 "expression" : "resource.name" ,
165174 "location" : "global" ,
166- "title" : "Instance Name" ,
175+ "title" : "CryptoKey Resource Name" ,
167176 },
168177 }
169178 ]
@@ -211,7 +220,8 @@ def test_get_security_health_analytics_custom_module():
211220
212221 assert response is not None , "Failed to retrieve the custom module."
213222 assert response .display_name .startswith (PREFIX )
214- assert response .enablement_state == securitycentermanagement_v1 .SecurityHealthAnalyticsCustomModule .EnablementState .ENABLED
223+ response_org_id = response .name .split ("/" )[1 ] # Extract organization ID from the name field
224+ assert response_org_id == ORGANIZATION_ID , f"Organization ID mismatch: Expected { ORGANIZATION_ID } , got { response_org_id } ."
215225
216226
217227@backoff .on_exception (
@@ -229,6 +239,7 @@ def test_delete_security_health_analytics_custom_module():
229239 assert response is None
230240
231241 print (f"Custom module was deleted successfully: { module_id } " )
242+ shared_modules .remove (module_id )
232243
233244
234245@backoff .on_exception (
@@ -249,12 +260,74 @@ def test_list_security_health_analytics_custom_module():
249260)
250261def test_update_security_health_analytics_custom_module ():
251262
252- module_id = get_random_shared_module ()
253263 parent = f"organizations/{ ORGANIZATION_ID } /locations/{ LOCATION } "
264+ response = security_health_analytics_custom_modules .create_security_health_analytics_custom_module (parent )
265+ module_id = extract_custom_module_id (response .name )
266+ add_module_to_cleanup (module_id )
267+
254268 # Retrieve the custom modules
255269 updated_custom_module = security_health_analytics_custom_modules .update_security_health_analytics_custom_module (parent , module_id )
256270
257271 assert updated_custom_module is not None , "Failed to retrieve the updated custom module."
258272 response_org_id = updated_custom_module .name .split ("/" )[1 ] # Extract organization ID from the name field
259273 assert response_org_id == ORGANIZATION_ID , f"Organization ID mismatch: Expected { ORGANIZATION_ID } , got { response_org_id } ."
260274 assert updated_custom_module .enablement_state == securitycentermanagement_v1 .SecurityHealthAnalyticsCustomModule .EnablementState .DISABLED
275+
276+
277+ @backoff .on_exception (
278+ backoff .expo , (InternalServerError , ServiceUnavailable , NotFound ), max_tries = 3
279+ )
280+ def test_get_effective_security_health_analytics_custom_module ():
281+ """Tests getting an effective SHA custom module."""
282+ module_id = get_random_shared_module ()
283+ parent = f"organizations/{ ORGANIZATION_ID } /locations/{ LOCATION } "
284+
285+ # Retrieve the custom module
286+ response = security_health_analytics_custom_modules .get_effective_security_health_analytics_custom_module (parent , module_id )
287+
288+ assert response is not None , "Failed to retrieve the custom module."
289+ # Verify that the custom module was created
290+ assert response .display_name .startswith (PREFIX )
291+ response_org_id = response .name .split ("/" )[1 ] # Extract organization ID from the name field
292+ assert response_org_id == ORGANIZATION_ID , f"Organization ID mismatch: Expected { ORGANIZATION_ID } , got { response_org_id } ."
293+
294+
295+ @backoff .on_exception (
296+ backoff .expo , (InternalServerError , ServiceUnavailable , NotFound ), max_tries = 3
297+ )
298+ def test_list_descendant_security_health_analytics_custom_module ():
299+ """Tests listing descendant SHA custom modules."""
300+ parent = f"organizations/{ ORGANIZATION_ID } /locations/{ LOCATION } "
301+ # Retrieve the list descendant custom modules
302+ custom_modules = security_health_analytics_custom_modules .list_descendant_security_health_analytics_custom_module (parent )
303+
304+ assert custom_modules is not None , "Failed to retrieve the custom modules."
305+ assert len (custom_modules ) > 0 , "No custom modules were retrieved."
306+
307+
308+ @backoff .on_exception (
309+ backoff .expo , (InternalServerError , ServiceUnavailable , NotFound ), max_tries = 3
310+ )
311+ def test_list_effective_security_health_analytics_custom_module ():
312+ """Tests listing effective SHA custom modules."""
313+ parent = f"organizations/{ ORGANIZATION_ID } /locations/{ LOCATION } "
314+ # Retrieve the list of custom modules
315+ custom_modules = security_health_analytics_custom_modules .list_effective_security_health_analytics_custom_module (parent )
316+
317+ assert custom_modules is not None , "Failed to retrieve the custom modules."
318+ assert len (custom_modules ) > 0 , "No custom modules were retrieved."
319+
320+
321+ @backoff .on_exception (
322+ backoff .expo , (InternalServerError , ServiceUnavailable , NotFound ), max_tries = 3
323+ )
324+ def test_simulate_security_health_analytics_custom_module ():
325+ """Tests simulating an SHA custom module."""
326+ parent = f"organizations/{ ORGANIZATION_ID } /locations/{ LOCATION } "
327+
328+ simulated_custom_module = security_health_analytics_custom_modules .simulate_security_health_analytics_custom_module (parent )
329+
330+ assert simulated_custom_module is not None , "Failed to retrieve the simulated custom module."
331+ assert simulated_custom_module .result .no_violation is not None , (
332+ f"Expected no_violation to be present, got { simulated_custom_module .result } ."
333+ )
0 commit comments