def test_sandbox_api_build_id(self): """ Test the SandboxAPI build_id property """ sandbox_api = SandboxAPI( app_id=constants.VALID_SANDBOX_API["app_id"], sandbox_name=constants.VALID_SANDBOX_API["sandbox_name"], ) # Succeed when getting a valid build_id property self.assertIsInstance(sandbox_api.build_id, str) # Succeed when setting the build_id property to a valid value self.assertIsNone( setattr(sandbox_api, "build_id", constants.VALID_SANDBOX_API["build_id"])) # Fail when attempting to set the build_id property to an invalid value self.assertRaises( ValueError, setattr, sandbox_api, "build_id", constants.INVALID_SANDBOX_API_BUILD_ID["build_id"], ) # Fail when attempting to get the build_id property when it contains an # invalid value sandbox_api._build_id = ( # pylint: disable=protected-access constants.INVALID_SANDBOX_API_BUILD_ID["build_id"]) self.assertRaises(ValueError, getattr, sandbox_api, "build_id") # Fail when attempting to delete the build_id property, because the # deleter is intentionally missing self.assertRaises(AttributeError, delattr, sandbox_api, "build_id")
def test_sandbox_api_version(self): """ Test the SandboxAPI version property """ sandbox_api = SandboxAPI( app_id=constants.VALID_SANDBOX_API["app_id"], sandbox_name=constants.VALID_SANDBOX_API["sandbox_name"], ) # Succeed when getting a valid version property self.assertIsInstance(sandbox_api.version, dict) # Succeed when setting the version property to a valid value self.assertIsNone( setattr(sandbox_api, "version", constants.VALID_SANDBOX_API["version"])) # Fail when attempting to set the version property to an invalid value self.assertRaises( ValueError, setattr, sandbox_api, "version", constants.INVALID_SANDBOX_API_INCORRECT_VERSION_VALUES["version"], ) # Fail when attempting to get the version property when it contains an # invalid value sandbox_api._version = constants.INVALID_SANDBOX_API_INCORRECT_VERSION_VALUES[ # pylint: disable=protected-access "version"] self.assertRaises(ValueError, getattr, sandbox_api, "version") # Fail when attempting to delete the version property, because the # deleter is intentionally missing self.assertRaises(AttributeError, delattr, sandbox_api, "version")
def test_create_sandbox(self): """ Test the create_sandbox function """ # Succeed when calling the create_sandbox function and the api call # gets a valid response with patch.object( SandboxAPI, "http_post", return_value=test_constants.VALID_SANDBOX_CREATESANDBOX_API_RESPONSE_XML[ "Element" ], ): with patch("veracode.api.get_app_id", return_value="1337"): sandbox_api = SandboxAPI( app_name="31337", sandbox_name="Project Security" ) with patch( "veracode.submit_artifacts.element_contains_error", return_value=False ): self.assertEqual( submit_artifacts.create_sandbox(sandbox_api=sandbox_api), "1111111" ) # Raise a RuntimeError when element_contains_error returns True with patch( "veracode.submit_artifacts.element_contains_error", return_value=True ): self.assertRaises( RuntimeError, submit_artifacts.create_sandbox, sandbox_api=sandbox_api, ) # Raise a RuntimeError when calling the create_sandbox function and the # api call gets a response, but does not contain the requested # sandbox_name with patch.object( SandboxAPI, "http_post", return_value=test_constants.INVALID_SANDBOX_CREATESANDBOX_API_RESPONSE_XML_NO_SANDBOX[ "Element" ], ): with patch("veracode.api.get_app_id", return_value="1337"): sandbox_api = SandboxAPI( app_name="TestApp", sandbox_name="Project Security" ) with patch( "veracode.submit_artifacts.element_contains_error", return_value=False ): self.assertRaises( RuntimeError, submit_artifacts.create_sandbox, sandbox_api=sandbox_api, )
def test_get_sandbox_id(self): """ Test the get_sandbox_id function """ # Succeed when calling the get_sandbox_id function and the api call # gets a valid response with patch.object( SandboxAPI, "http_get", return_value=test_constants.VALID_SANDBOX_GETSANDBOXLIST_API_RESPONSE_XML[ "Element" ], ): with patch("veracode.api.get_app_id", return_value="1337"): sandbox_api = SandboxAPI( app_name="TestApp", sandbox_name="Project Security" ) with patch( "veracode.submit_artifacts.element_contains_error", return_value=False ): self.assertEqual( submit_artifacts.get_sandbox_id(sandbox_api=sandbox_api), "111111111", ) # Raise a RuntimeError when element_contains_error returns True with patch( "veracode.submit_artifacts.element_contains_error", return_value=True ): self.assertRaises( RuntimeError, submit_artifacts.get_sandbox_id, sandbox_api=sandbox_api, ) # Return None when calling the get_sandbox_id function and the api call # gets a valid response, but does not contain the requested # sandbox_name with patch.object( SandboxAPI, "http_get", return_value=test_constants.VALID_SANDBOX_GETSANDBOXLIST_API_RESPONSE_XML[ "Element" ], ): with patch("veracode.api.get_app_id", return_value="1337"): sandbox_api = SandboxAPI( app_name="TestApp", sandbox_name="Unknown Sandbox Name" ) with patch( "veracode.submit_artifacts.element_contains_error", return_value=False ): self.assertIsNone( submit_artifacts.get_sandbox_id(sandbox_api=sandbox_api) )
def test_sandbox_api_app_name(self): """ Test the SandboxAPI app_name property """ # Fail when attempting to create an SandboxAPI object when the app_name # property wasn't provided to the constructor self.assertRaises(TypeError, SandboxAPI) # Succeed when creating an SandboxAPI object when the app_name property is # properly provided to the constructor with patch("veracode.api.get_app_id", return_value=constants.VALID_UPLOAD_API["app_id"]): sandbox_api = SandboxAPI( app_name=constants.VALID_SANDBOX_API["app_name"], sandbox_name=constants.VALID_SANDBOX_API["sandbox_name"], ) self.assertIsInstance(getattr(sandbox_api, "app_name"), str) # Succeed when setting the app_name property to a valid value self.assertIsNone( setattr(sandbox_api, "app_name", constants.VALID_SANDBOX_API["app_name"])) # Succeed when getting a valid app_name property self.assertIsInstance(sandbox_api.app_name, str) # Fail when attempting to set the app_name property to an invalid value self.assertRaises( ValueError, setattr, sandbox_api, "app_name", constants.INVALID_RESULTS_API_INCORRECT_APP_NAME["app_name"], ) # Fail when attempting to get the app_name property when it contains an # invalid value sandbox_api._app_name = constants.INVALID_RESULTS_API_INCORRECT_APP_NAME[ # pylint: disable=protected-access "app_name"] self.assertRaises(ValueError, getattr, sandbox_api, "app_name") # Fail when attempting to delete the app_name property, because the # deleter is intentionally missing self.assertRaises(AttributeError, delattr, sandbox_api, "app_name")
def test_sandbox_api_sandbox_id(self): """ Test the SandboxAPI sandbox_id property """ with patch("veracode.api.get_app_id", return_value=constants.VALID_UPLOAD_API["app_id"]): sandbox_api = SandboxAPI( app_name=constants.VALID_SANDBOX_API["app_name"], sandbox_name=constants.VALID_SANDBOX_API["sandbox_name"], ) # Succeed when getting a the default sandbox_id property self.assertIsNone(sandbox_api.sandbox_id) # Succeed when setting the sandbox_id property to a valid value self.assertIsNone(setattr(sandbox_api, "sandbox_id", None)) self.assertIsNone(setattr(sandbox_api, "sandbox_id", "12489")) # Succeed when getting a valid sandbox_id property self.assertIsInstance(sandbox_api.sandbox_id, str) # Fail when attempting to set the sandbox_id property to an invalid # value self.assertRaises( ValueError, setattr, sandbox_api, "sandbox_id", 12489, ) # Fail when attempting to get the sandbox_id property when it contains # an invalid value sandbox_api._sandbox_id = 12489 # pylint: disable=protected-access self.assertRaises(ValueError, getattr, sandbox_api, "sandbox_id") # Fail when attempting to delete the sandbox_id property, because the # deleter is intentionally missing self.assertRaises(AttributeError, delattr, sandbox_api, "sandbox_id")
def test_apply_config(self): """ Test the apply_config function """ configuration = copy.deepcopy(test_constants.CLEAN_EFFECTIVE_CONFIG) # Succeed when calling the apply_config function with a valid # Upload API object and config upload_api = UploadAPI(app_id="31337") applied_upload_api = config.apply_config(api=upload_api, config=configuration) self.assertEqual(applied_upload_api, upload_api) # Succeed when calling the apply_config function with a valid # Results API object and config results_api = ResultsAPI(app_id="31337") applied_results_api = config.apply_config(api=results_api, config=configuration) self.assertEqual(applied_results_api, results_api) # Succeed when calling the apply_config function with a valid # Sandbox API object and config sandbox_api = SandboxAPI( app_id="31337", sandbox_name="easy_sast/fb/jonzeolla/testing" ) applied_sandbox_api = config.apply_config(api=sandbox_api, config=configuration) self.assertEqual(applied_sandbox_api, sandbox_api) # Ensure calling the apply_config function with different `app_id`s # does not result in an object with the same version string (which is # unique per-API) upload_api = UploadAPI(app_id="31337") applied_upload_api = config.apply_config(api=upload_api, config=configuration) # Note: This must be different than the above app_id results_api = ResultsAPI(app_id="1337") applied_results_api = config.apply_config(api=results_api, config=configuration) self.assertNotEqual(applied_results_api.version, applied_upload_api.version) # Fail when calling the apply_config function with a string instead of # an API object astring = "wrong type" self.assertRaises( TypeError, config.apply_config, api=astring, config=configuration ) # Succeed when calling the apply_config function with a valid # Results API object and config configuration["apis"]["unknown"] = {"a": "b"} results_api = ResultsAPI(app_id="31337") self.assertEqual( config.apply_config(api=results_api, config=configuration), results_api )
def test_sandbox_api_base_url(self): """ Test the SandboxAPI base_url property """ with patch("veracode.api.get_app_id", return_value=constants.VALID_UPLOAD_API["app_id"]): sandbox_api = SandboxAPI( app_name=constants.VALID_SANDBOX_API["app_name"], sandbox_name=constants.VALID_SANDBOX_API["sandbox_name"], ) # Succeed when getting a valid base_url property self.assertIsInstance(sandbox_api.base_url, str) # Succeed when setting the base_url property to a valid value self.assertIsNone( setattr(sandbox_api, "base_url", constants.VALID_SANDBOX_API["base_url"])) # Fail when attempting to set the base_url property to an invalid value self.assertRaises( ValueError, setattr, sandbox_api, "base_url", constants.INVALID_SANDBOX_API_INCORRECT_DOMAIN["base_url"], ) # Fail when attempting to get the base_url property when it contains an # invalid value sandbox_api._base_url = constants.INVALID_SANDBOX_API_INCORRECT_DOMAIN[ # pylint: disable=protected-access "base_url"] self.assertRaises(ValueError, getattr, sandbox_api, "base_url") # Fail when attempting to delete the base_url property, because the # deleter is intentionally missing self.assertRaises(AttributeError, delattr, sandbox_api, "base_url")
def test_sandbox_api_sandbox_name(self): """ Test the SandboxAPI sandbox_name property """ sandbox_api = SandboxAPI( app_id=constants.VALID_SANDBOX_API["app_id"], sandbox_name=constants.VALID_SANDBOX_API["sandbox_name"], ) # Succeed when getting a valid sandbox_name property self.assertIsInstance(sandbox_api.sandbox_name, str) # Succeed when setting the sandbox_name property to a valid value self.assertIsNone( setattr(sandbox_api, "sandbox_name", constants.VALID_SANDBOX_API["sandbox_name"])) # Fail when attempting to set the sandbox_name property to an invalid # value self.assertRaises( ValueError, setattr, sandbox_api, "sandbox_name", constants.INVALID_SANDBOX_API_SANDBOX_NAME["sandbox_name"], ) # Fail when attempting to get the sandbox_name property when it # contains an invalid value sandbox_api._sandbox_name = constants.INVALID_SANDBOX_API_SANDBOX_NAME[ # pylint: disable=protected-access "sandbox_name"] self.assertRaises(ValueError, getattr, sandbox_api, "sandbox_name") # Fail when attempting to delete the sandbox_name property, because the # deleter is intentionally missing self.assertRaises(AttributeError, delattr, sandbox_api, "sandbox_name")
def get_sandbox_id(*, sandbox_api: SandboxAPI) -> Union[str, None]: """ Query for and return the sandbox_id https://help.veracode.com/reader/LMv_dtSHyb7iIxAQznC~9w/twPT73YBy_iQvrsGEZamhQ """ try: endpoint = "getsandboxlist.do" params = {"app_id": sandbox_api.app_id} sandboxes = sandbox_api.http_get(endpoint=endpoint, params=params) if element_contains_error(parsed_xml=sandboxes): LOG.error("Veracode returned an error when attempting to call %s", endpoint) raise RuntimeError for sandbox in sandboxes: if sandbox_api.sandbox_name == sandbox.get("sandbox_name"): # Returns the first sandbox_name match as duplicates are not # allowed by Veracode return sandbox.get("sandbox_id") # No sandbox_id exists with the provided sandbox_name LOG.info( "A sandbox named %s does not exist in application id %s", sandbox_api.sandbox_name, sandbox_api.app_id, ) return None except ( HTTPError, ConnectionError, Timeout, TooManyRedirects, RequestException, RuntimeError, ) as e: raise RuntimeError from e
def create_sandbox(*, sandbox_api: SandboxAPI) -> str: """ Create a sandbox and return the sandbox_id https://help.veracode.com/reader/LMv_dtSHyb7iIxAQznC~9w/jp8rPey8I5WsuWz7bY2SZg """ try: endpoint = "createsandbox.do" params = { "app_id": sandbox_api.app_id, "sandbox_name": sandbox_api.sandbox_name, } response = sandbox_api.http_post(endpoint=endpoint, params=params) if element_contains_error(parsed_xml=response): LOG.error("Veracode returned an error when attempting to call %s", endpoint) raise RuntimeError try: # Because we only make one sandbox at a time, we can use index 0 to # extract and then return the sandbox_id return response[0].get("sandbox_id") except (KeyError, IndexError) as e: LOG.error( "Unable to extract the sandbox_id from the Veracode response") raise RuntimeError from e except ( HTTPError, ConnectionError, Timeout, TooManyRedirects, RequestException, RuntimeError, ) as e: raise RuntimeError from e
def test_submit_artifacts( # pylint: disable=too-many-arguments, too-many-statements self, mock_get_sandbox_id, mock_create_sandbox, mock_iterdir, mock_setup_scan_prereqs, mock_filter_file, mock_upload_large_file, mock_begin_prescan, ): """ Test the submit_artifacts function """ with patch("veracode.api.get_app_id", return_value="1337"): upload_api = UploadAPI(app_name=test_constants.VALID_UPLOAD_API["app_name"]) sandbox_api = SandboxAPI( app_name=test_constants.VALID_SANDBOX_API["app_name"], sandbox_name=test_constants.VALID_SANDBOX_API["sandbox_name"], ) def iterdir_generator_valid(): f = test_constants.VALID_FILE["Path"] yield f def iterdir_generator_invalid(): f = test_constants.INVALID_FILE["Path"] yield f ## Testing with sandbox_api set # Return True if sandbox_api is set, the sandbox was already created, # and everything else follows the Happy Path mock_get_sandbox_id.return_value = test_constants.VALID_SANDBOX_API[ "sandbox_id" ] mock_create_sandbox.return_value = None # Unused mock_setup_scan_prereqs.return_value = True mock_iterdir.return_value = iterdir_generator_valid() mock_filter_file.return_value = True mock_upload_large_file.return_value = True mock_begin_prescan.return_value = True self.assertTrue( submit_artifacts.submit_artifacts( upload_api=upload_api, sandbox_api=sandbox_api ) ) # Return True if sandbox_api is set, the sandbox wasn't yet created in # Veracode, and everything else follows the Happy Path mock_get_sandbox_id.return_value = None mock_create_sandbox.return_value = test_constants.VALID_SANDBOX_API[ "sandbox_id" ] mock_setup_scan_prereqs.return_value = True mock_iterdir.return_value = iterdir_generator_valid() mock_filter_file.return_value = True mock_upload_large_file.return_value = True mock_begin_prescan.return_value = True self.assertTrue( submit_artifacts.submit_artifacts( upload_api=upload_api, sandbox_api=sandbox_api ) ) # Return False if sandbox_api is set, and get_sandbox_id raises a # RuntimeError with patch( "veracode.submit_artifacts.get_sandbox_id", side_effect=RuntimeError ): mock_get_sandbox_id.return_value = None mock_create_sandbox.return_value = None # Unused mock_setup_scan_prereqs.return_value = True # Unused mock_iterdir.return_value = iterdir_generator_valid() # Unused mock_filter_file.return_value = True # Unused mock_upload_large_file.return_value = True # Unused mock_begin_prescan.return_value = True # Unused self.assertFalse( submit_artifacts.submit_artifacts( upload_api=upload_api, sandbox_api=sandbox_api ) ) # Return False if sandbox_api is set, get_sandbox_id returns None, but # create_sandbox raises a RuntimeError with patch( "veracode.submit_artifacts.create_sandbox", side_effect=RuntimeError ): mock_get_sandbox_id.return_value = None mock_create_sandbox.return_value = None mock_setup_scan_prereqs.return_value = True # Unused mock_iterdir.return_value = iterdir_generator_valid() # Unused mock_filter_file.return_value = True # Unused mock_upload_large_file.return_value = True # Unused mock_begin_prescan.return_value = True # Unused self.assertFalse( submit_artifacts.submit_artifacts( upload_api=upload_api, sandbox_api=sandbox_api ) ) ## Testing without sandbox_api set # Return True if sandbox_api isn't set and everything follows the Happy # Path mock_get_sandbox_id.return_value = None # Unused mock_create_sandbox.return_value = None # Unused mock_setup_scan_prereqs.return_value = True mock_iterdir.return_value = iterdir_generator_valid() mock_filter_file.return_value = True mock_upload_large_file.return_value = True mock_begin_prescan.return_value = True self.assertTrue(submit_artifacts.submit_artifacts(upload_api=upload_api)) # Return False if setup_scan_prereqs returns False mock_get_sandbox_id.return_value = None # Unused mock_create_sandbox.return_value = None # Unused mock_setup_scan_prereqs.return_value = False mock_iterdir.return_value = iterdir_generator_valid() mock_filter_file.return_value = True mock_upload_large_file.return_value = True mock_begin_prescan.return_value = True self.assertFalse(submit_artifacts.submit_artifacts(upload_api=upload_api)) # Return False if filter_file always returns False, meaning artifacts # is empty mock_get_sandbox_id.return_value = None # Unused mock_create_sandbox.return_value = None # Unused mock_setup_scan_prereqs.return_value = True mock_iterdir.return_value = iterdir_generator_invalid() mock_filter_file.return_value = False mock_upload_large_file.return_value = True mock_begin_prescan.return_value = True self.assertFalse(submit_artifacts.submit_artifacts(upload_api=upload_api)) # Return False if upload_large_file always returns False, meaning # something is wrong with the file upload mock_get_sandbox_id.return_value = None # Unused mock_create_sandbox.return_value = None # Unused mock_setup_scan_prereqs.return_value = True mock_iterdir.return_value = iterdir_generator_valid() mock_filter_file.return_value = True mock_upload_large_file.return_value = False mock_begin_prescan.return_value = True self.assertFalse(submit_artifacts.submit_artifacts(upload_api=upload_api)) # Return False if begin_prescan returns False, meaning the prescan was # unable to be started mock_get_sandbox_id.return_value = None # Unused mock_create_sandbox.return_value = None # Unused mock_setup_scan_prereqs.return_value = True mock_iterdir.return_value = iterdir_generator_valid() mock_filter_file.return_value = True mock_upload_large_file.return_value = True mock_begin_prescan.return_value = False self.assertFalse(submit_artifacts.submit_artifacts(upload_api=upload_api))
def main() -> None: """ Integration with Veracode Static Analysis """ ## Setup logging # Format the logs as JSON for simplicity formatting = json.dumps( { "timestamp": "%(asctime)s", "namespace": "%(name)s", "loglevel": "%(levelname)s", "message": "%(message)s", } ) # Default to a log level of WARNING until the config is parsed logging.basicConfig(level="WARNING", format=formatting) log = logging.getLogger(__project_name__) # Get the effective config try: config = get_config() except ValueError: log.error("Unable to create a valid configuration") sys.exit(1) # Update the log level to whatever was set in the config logging.getLogger().setLevel(config["loglevel"]) # Create the API objects and apply the config try: results_api = apply_config( api=ResultsAPI(app_id=config["apis"]["results"]["app_id"]), config=config ) upload_api = apply_config( api=UploadAPI(app_id=config["apis"]["upload"]["app_id"]), config=config ) if "sandbox_name" in config["apis"]["sandbox"]: sandbox_api = apply_config( api=SandboxAPI( app_id=config["apis"]["sandbox"]["app_id"], sandbox_name=config["apis"]["sandbox"]["sandbox_name"], ), config=config, ) else: sandbox_api = None except (TypeError, NameError): log.error("Unable to create valid API objects") sys.exit(1) # Configure the environment for step in config["workflow"]: if step == "submit_artifacts": configure_environment( api_key_id=config["api_key_id"], api_key_secret=config["api_key_secret"] ) success = submit_artifacts(upload_api=upload_api, sandbox_api=sandbox_api) if success: log.info("Successfully submit build artifacts for scanning") else: log.error("Failed to submit build artifacts for scanning") sys.exit(1) elif step == "check_compliance": configure_environment( api_key_id=config["api_key_id"], api_key_secret=config["api_key_secret"] ) if not check_compliance(results_api=results_api): sys.exit(1)