def testCannotDeterminePlatform(self, mock_metric): MysteryHost(id='host_id').put() exm_key = test_utils.CreateExemption('host_id') api.Process(exm_key) self.assertEqual(_STATE.DENIED, exm_key.get().state) self.assertBigQueryInsertions([constants.BIGQUERY_TABLE.EXEMPTION] * 2) mock_metric.Increment.assert_called_once()
def testException_InitialStateChange(self, mock_change_state, mock_metric): mock_change_state.side_effect = exemption_models.InvalidStateChangeError exm_key = test_utils.CreateExemption('12345') self.assertEqual(_STATE.REQUESTED, exm_key.get().state) api.Process(exm_key) self.assertEqual(_STATE.REQUESTED, exm_key.get().state) mock_metric.Increment.assert_called_once()
def post(self, host_id): # This request should only be available to admins or users who have (at # least at one time) had control of the host. if not (self.user.is_admin or model_utils.IsHostAssociatedWithUser(self.host, self.user)): logging.warning( 'User %s is not authorized to request an Exemption for host %s', self.user.nickname, host_id) self.abort(httplib.FORBIDDEN, explanation='Host not associated with user %s' % self.user.nickname) # Extract and validate the exemption reason. reason = self.request.get('reason') other_text = self.request.get('otherText') or None if not reason: self.abort(httplib.BAD_REQUEST, explanation='No reason provided') elif reason == constants.EXEMPTION_REASON.OTHER and not other_text: self.abort( httplib.BAD_REQUEST, explanation='No explanation for "Other" reason provided') # Extract and validate the exemption duration. duration = self.request.get('duration') if not duration: self.abort(httplib.BAD_REQUEST, explanation='Exemption term not provided') # Request a new Exemption, and bail if something goes wrong. try: exemption_api.Request(host_id, reason, other_text, duration) except exemption_api.InvalidRenewalError: self.abort(httplib.BAD_REQUEST, 'Request cannot be renewed at this time') except exemption_api.InvalidReasonError: self.abort(httplib.BAD_REQUEST, 'Invalid reason provided') except exemption_api.InvalidDurationError: self.abort(httplib.BAD_REQUEST, 'Invalid duration provided') except Exception: # pylint: disable=broad-except logging.exception( 'Error encountered while escalating Exemption for host %s', host_id) self.abort(httplib.INTERNAL_SERVER_ERROR, explanation='Error while escalating exemption') # Start processing the Exemption right away, rather than waiting for the # 15 minute cron to catch it. On the off chance the cron fires between the # above Request() call and here, catch and ignore InvalidStateChangeErrors. try: exm_key = exemption_models.Exemption.CreateKey(host_id) exemption_api.Process(exm_key) except exemption_models.InvalidStateChangeError: logging.warning('Error encountered while processing Exemption') self._RespondWithExemptionAndTransitiveState(exm_key)
def testInitialStateChange_Exception(self, mock_change_state, mock_metric): exm_key = test_utils.CreateExemption('12345') self.assertEqual(_STATE.REQUESTED, exm_key.get().state) # If the initial state change fails unexpectedly, ensure that the state # remains as REQUESTED, and noise is made. mock_change_state.side_effect = Exception api.Process(exm_key) self.assertEqual(_STATE.REQUESTED, exm_key.get().state) mock_metric.Increment.assert_called_once()
def testEmptyPolicy(self, mock_disable): self._PatchPolicyChecks() host_key = test_utils.CreateSantaHost().key exm_key = test_utils.CreateExemption(host_key.id()) api.Process(exm_key) exm = exm_key.get() mock_disable.assert_called() self.assertEqual(_STATE.APPROVED, exm.state) self.assertBigQueryInsertions([constants.BIGQUERY_TABLE.EXEMPTION] * 2)
def testPolicyNotDefinedForPlatform(self, mock_metric): self._PatchPolicyChecks() host_key = test_utils.CreateBit9Host().key exm_key = test_utils.CreateExemption(host_key.id()) api.Process(exm_key) exm = exm_key.get() self.assertEqual(_STATE.DENIED, exm.state) self.assertBigQueryInsertions([constants.BIGQUERY_TABLE.EXEMPTION] * 2) mock_metric.Increment.assert_called_once()
def testInvalidResultState(self, mock_metric): host_key = test_utils.CreateSantaHost().key exm_key = test_utils.CreateExemption(host_key.id()) self._PatchPolicyChecks(_ApprovingPolicyCheck, _InvalidResultPolicyCheck) api.Process(exm_key) exm = exm_key.get() self.assertEqual(_STATE.DENIED, exm.state) self.assertBigQueryInsertions([constants.BIGQUERY_TABLE.EXEMPTION] * 2) mock_metric.Increment.assert_called_once()
def testDenied(self, mock_disable, mock_enable): host_key = test_utils.CreateSantaHost().key exm_key = test_utils.CreateExemption(host_key.id()) self._PatchPolicyChecks(_ApprovingPolicyCheck, _EscalatingPolicyCheck, _DenyingPolicyCheck) api.Process(exm_key) exm = exm_key.get() self.assertEqual(_STATE.DENIED, exm.state) mock_disable.assert_not_called() mock_enable.assert_not_called() self.assertBigQueryInsertions([constants.BIGQUERY_TABLE.EXEMPTION] * 2)
def testInitialStateChange_InvalidStateChangeError(self, mock_metric): # Simulate a user creating a new Exemption in the REQUESTED state. exm_key = test_utils.CreateExemption('12345') self.assertEqual(_STATE.REQUESTED, exm_key.get().state) # Simulate the Exemption transitioning to PENDING due to either the user # request, or the processing cron. Both end up calling Process(). exemption_models.Exemption.ChangeState(exm_key, _STATE.PENDING) self.assertBigQueryInsertion(constants.BIGQUERY_TABLE.EXEMPTION) # If the user request and processing cron occur around the same time, # they will both be trying to transition from REQUESTED to PENDING, a benign # race condition that shouldn't make noise. api.Process(exm_key) self.assertEqual(_STATE.PENDING, exm_key.get().state) mock_metric.Increment.assert_not_called()