Skip to content

Commit

Permalink
Chore/update py42 exceptions (#392)
Browse files Browse the repository at this point in the history
* fix unit tests

* update changelog

* add properties to unit tests
  • Loading branch information
tora-kozic committed Dec 14, 2021
1 parent 4174216 commit 1bab157
Show file tree
Hide file tree
Showing 11 changed files with 228 additions and 55 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ how a consumer would use the library (e.g. adding unit tests, updating documenta
- Updated `sdk.queries.alerts.filters.alerts_filter.Severity` enum to use updated `riskSeverity` search propert instead of deprecated `severity`.
- New values `CRITICAL` and `MODERATE`.
- Aliased previous `severity.MEDIUM` > `riskSeverity.MODERATE` for backwards compatibility.
- Updated custom exception behavior such that the parameters relating to the exception are:
- Printed in addition to the error message.
- Accessible as properties of the custom exception class.

## 1.19.3 - 2021-11-09

Expand Down
224 changes: 192 additions & 32 deletions src/py42/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ class Py42Error(Exception):
class Py42ResponseError(Py42Error):
"""A base custom class to manage all errors raised because of an HTTP response."""

def __init__(self, response, message):
super().__init__(message)
def __init__(self, response, message, *args):
super().__init__(message, *args)
self._response = response

@property
Expand All @@ -25,15 +25,39 @@ def __init__(self, response, device_guid, file_path):
message = (
f"File not found in archive for device {device_guid} at path {file_path}"
)
super().__init__(response, message)
super().__init__(response, message, device_guid, file_path)
self._device_guid = device_guid
self._file_path = file_path

@property
def device_guid(self):
"""The device GUID provided."""
return self._device_guid

@property
def file_path(self):
"""The file path provided."""
return self._file_path


class Py42ChecksumNotFoundError(Py42ResponseError):
"""An exception raised when a user-supplied hash could not successfully locate its corresponding resource."""

def __init__(self, response, checksum_name, checksum_value):
message = f"No files found with {checksum_name} checksum {checksum_value}."
super().__init__(response, message)
super().__init__(response, message, checksum_name, checksum_value)
self._checksum_name = checksum_name
self._checksum_value = checksum_value

@property
def checksum_name(self):
""" The checksum name. """
return self._checksum_name

@property
def checksum_value(self):
""" The checksum value. """
return self.checksum_value


class Py42FeatureUnavailableError(Py42ResponseError):
Expand All @@ -49,13 +73,13 @@ def __init__(self, response):
class Py42HTTPError(Py42ResponseError):
"""A base custom class to manage all HTTP errors raised by an API endpoint."""

def __init__(self, exception, message=None):
def __init__(self, exception, message=None, *args):
if not message:
response_content = f"Response content: {exception.response.text}"
message = f"Failure in HTTP call {exception}. {response_content}"
debug.logger.debug(message)

super().__init__(exception.response, message)
super().__init__(exception.response, message, *args)


class Py42DeviceNotConnectedError(Py42ResponseError):
Expand All @@ -67,7 +91,13 @@ def __init__(self, response, device_guid):
f"Device with GUID '{device_guid}' is not currently connected to the Authority "
"server."
)
super().__init__(response, message)
super().__init__(response, message, device_guid)
self._device_guid = device_guid

@property
def device_guid(self):
""" The device GUID. """
return self._device_guid


class Py42InvalidArchivePassword(Py42HTTPError):
Expand All @@ -91,8 +121,8 @@ class Py42StorageSessionInitializationError(Py42HTTPError):
may occur when trying to restore a file or trying to get events for file activity on removable
media, in cloud sync folders, and browser uploads."""

def __init__(self, exception, error_message):
super().__init__(exception, error_message)
def __init__(self, exception, message):
super().__init__(exception, message)


class Py42SessionInitializationError(Py42Error):
Expand All @@ -101,11 +131,11 @@ class Py42SessionInitializationError(Py42Error):
"""

def __init__(self, exception):
error_message = (
message = (
"An error occurred while requesting "
f"server environment information, caused by {exception}"
)
super().__init__(exception, error_message)
super().__init__(exception, message)


class Py42BadRequestError(Py42HTTPError):
Expand Down Expand Up @@ -142,7 +172,13 @@ class Py42OrgNotFoundError(Py42BadRequestError):

def __init__(self, exception, org_uid):
msg = f"The organization with UID '{org_uid}' was not found."
super().__init__(exception, msg)
super().__init__(exception, msg, org_uid)
self._org_uid = org_uid

@property
def org_uid(self):
"""" The org UID. """
return self._org_uid


class Py42ActiveLegalHoldError(Py42BadRequestError):
Expand All @@ -151,7 +187,19 @@ class Py42ActiveLegalHoldError(Py42BadRequestError):

def __init__(self, exception, resource, resource_id):
msg = f"Cannot deactivate the {resource} with ID {resource_id} as the {resource} is involved in a legal hold matter."
super().__init__(exception, msg)
super().__init__(exception, msg, resource, resource_id)
self._resource = resource
self._resource_id = resource_id

@property
def resource(self):
""" The user or device resource. """
return self._resource

@property
def resource_id(self):
""" The resource ID. """
return self._resource_id


class Py42UserAlreadyAddedError(Py42BadRequestError):
Expand All @@ -160,18 +208,28 @@ class Py42UserAlreadyAddedError(Py42BadRequestError):

def __init__(self, exception, user_id, list_name):
msg = f"User with ID {user_id} is already on the {list_name}."
super().__init__(exception, msg)
super().__init__(exception, msg, user_id, list_name)
self._user_id = user_id

@property
def user_id(self):
""" The user ID. """
return self._user_id


class Py42LegalHoldNotFoundOrPermissionDeniedError(Py42ForbiddenError):
"""An exception raised when a legal hold matter is inaccessible from your account or
the matter ID is not valid."""

def __init__(self, exception, matter_id):
super().__init__(
exception,
f"Matter with ID={matter_id} can not be found. Your account may not have permission to view the matter.",
)
def __init__(self, exception, resource_uid, legal_hold_resource="matter"):
message = f"{legal_hold_resource.capitalize()} with UID '{resource_uid}' can not be found. Your account may not have permission to view the {legal_hold_resource.lower()}."
super().__init__(exception, message, resource_uid)
self._resource_uid = resource_uid

@property
def uid(self):
""" The UID of the legal hold resource. """
return self._resource_uid


class Py42LegalHoldCriteriaMissingError(Py42BadRequestError):
Expand All @@ -180,9 +238,39 @@ class Py42LegalHoldCriteriaMissingError(Py42BadRequestError):
def __init__(self, exception):
super().__init__(
exception,
"At least one criteria must be specified; legal_hold_membership_uid, "
"legal_hold_uid, user_uid, or user.",
"At least one criteria must be specified: legal_hold_membership_uid, "
"legal_hold_matter_uid, user_uid, or user.",
)


class Py42LegalHoldAlreadyDeactivatedError(Py42BadRequestError):
"""An exception raised when trying to deactivate a Legal Hold Matter that is already inactive."""

def __init__(self, exception, legal_hold_matter_uid):
message = f"Legal Hold Matter with UID '{legal_hold_matter_uid}' has already been deactivated."
super().__init__(exception, message, legal_hold_matter_uid)
self._legal_hold_matter_uid = legal_hold_matter_uid

@property
def legal_hold_matter_uid(self):
""" The legal hold matter UID. """
return self._legal_hold_matter_uid


class Py42LegalHoldAlreadyActiveError(Py42BadRequestError):
"""An exception raised when trying to activate a Legal Hold Matter that is already active."""

def __init__(self, exception, legal_hold_matter_uid):
message = (
f"Legal Hold Matter with UID '{legal_hold_matter_uid}' is already active."
)
super().__init__(exception, message, legal_hold_matter_uid)
self._legal_hold_matter_uid = legal_hold_matter_uid

@property
def legal_hold_matter_uid(self):
""" The legal hold matter UID. """
return self._legal_hold_matter_uid


class Py42InvalidRuleOperationError(Py42HTTPError):
Expand All @@ -191,7 +279,19 @@ class Py42InvalidRuleOperationError(Py42HTTPError):
def __init__(self, exception, rule_id, source):
msg = "Only alert rules with a source of 'Alerting' can be targeted by this command. "
msg += f"Rule {rule_id} has a source of '{source}'."
super().__init__(exception, msg)
super().__init__(exception, msg, rule_id, source)
self._rule_id = rule_id
self._source = source

@property
def rule_id(self):
""" The rule ID. """
return self._rule_id

@property
def source(self):
""" The rule source. """
return self._source


class Py42MFARequiredError(Py42UnauthorizedError):
Expand Down Expand Up @@ -224,7 +324,13 @@ class Py42InvalidEmailError(Py42InternalServerError):

def __init__(self, email, exception):
message = f"'{email}' is not a valid email."
super().__init__(exception, message)
super().__init__(exception, message, email)
self._email = email

@property
def email(self):
""" The email being assigned to a user. """
return self._email


class Py42InvalidPasswordError(Py42InternalServerError):
Expand Down Expand Up @@ -266,15 +372,33 @@ class Py42InvalidPageTokenError(Py42BadRequestError):

def __init__(self, exception, page_token):
message = f'Invalid page token: "{page_token}".'
super().__init__(exception, message)
super().__init__(exception, message, page_token)
self._page_token = page_token

@property
def page_token(self):
""" The page token. """
return self._page_token


class Py42UserNotOnListError(Py42NotFoundError):
"""An exception raised when the user is not on a detection list."""

def __init__(self, exception, user_id, list_name):
message = f"User with ID '{user_id}' is not currently on the {list_name} list."
super(Py42NotFoundError, self).__init__(exception, message)
super(Py42NotFoundError, self).__init__(exception, message, user_id, list_name)
self._user_id = user_id
self._list_name = list_name

@property
def user_id(self):
""" The user ID. """
return self._user_id

@property
def list_name(self):
""" The list name. """
return self._list_name


class Py42UnableToCreateProfileError(Py42BadRequestError):
Expand All @@ -290,15 +414,27 @@ def __init__(self, exception, username):
"It is possibly still being created if you just recently created the "
"Code42 user."
)
super().__init__(exception, message)
super().__init__(exception, message, username)
self._username = username

@property
def username(self):
""" The username of the user. """
return self._username


class Py42InvalidRuleError(Py42NotFoundError):
"""An exception raised when the observer rule ID does not exist."""

def __init__(self, exception, rule_id):
message = f"Invalid Observer Rule ID '{rule_id}'."
super(Py42NotFoundError, self).__init__(exception, message)
super(Py42NotFoundError, self).__init__(exception, message, rule_id)
self._rule_id = rule_id

@property
def rule_id(self):
""" The observer rule ID. """
return self._rule_id


class Py42UpdateClosedCaseError(Py42BadRequestError):
Expand All @@ -314,7 +450,13 @@ class Py42CaseNameExistsError(Py42BadRequestError):

def __init__(self, exception, case_name):
msg = f"Case name '{case_name}' already exists, please set another name."
super().__init__(exception, msg)
super().__init__(exception, msg, case_name)
self._case_name = case_name

@property
def case_name(self):
""" The case name. """
return self._case_name


class Py42DescriptionLimitExceededError(Py42BadRequestError):
Expand All @@ -328,9 +470,15 @@ def __init__(self, exception):
class Py42InvalidCaseUserError(Py42BadRequestError):
"""An error raised when a case subject or assignee is not a valid user."""

def __init__(self, exception, user_field):
msg = f"The provided {user_field} is not a valid user."
def __init__(self, exception, user_uid):
msg = f"The provided {user_uid} is not a valid user."
super().__init__(exception, msg)
self._user_uid = user_uid

@property
def user(self):
""" The user UID. """
return self._user_uid


class Py42CaseAlreadyHasEventError(Py42BadRequestError):
Expand All @@ -357,7 +505,13 @@ def __init__(self, exception, value):
f"Duplicate URL or workspace name, '{value}' already exists on your trusted list. "
"Please provide a unique value"
)
super().__init__(exception, msg)
super().__init__(exception, msg, value)
self._value = value

@property
def value(self):
""" The domain, URL or workspace name. """
return self._value


class Py42TrustedActivityInvalidCharacterError(Py42BadRequestError):
Expand All @@ -373,7 +527,13 @@ class Py42TrustedActivityIdNotFound(Py42NotFoundError):

def __init__(self, exception, resource_id):
message = f"Resource ID '{resource_id}' not found."
super(Py42NotFoundError, self).__init__(exception, message)
super().__init__(exception, message, resource_id)
self._resource_id = resource_id

@property
def resource_id(self):
""" The resource ID. """
return self._resource_id


def raise_py42_error(raised_error):
Expand Down

0 comments on commit 1bab157

Please sign in to comment.