def test_only_signed_when_approved_and_enabled(self, mocked_autograph): sign_data_mock = mocked_autograph.return_value.sign_data # This uses the signer, so do it first action = ActionFactory() sign_data_mock.reset_mock() sign_data_mock.side_effect = Exception("Can't sign yet") recipe = RecipeFactory(name="unchanged", action=action) assert not recipe.enabled assert not recipe.is_approved assert recipe.signature is None # Updating does not generate a signature recipe.revise(name="changed") assert recipe.signature is None # Approving does not sign the recipe rev = recipe.latest_revision approval_request = rev.request_approval(UserFactory()) approval_request.approve(UserFactory(), "r+") recipe.refresh_from_db() assert recipe.signature is None mocked_autograph.return_value.sign_data.assert_not_called() # Enabling signs the recipe mocked_autograph.return_value.sign_data.side_effect = fake_sign rev.enable(UserFactory()) recipe.refresh_from_db() expected_sig = fake_sign([recipe.canonical_json()])[0]["signature"] assert recipe.signature.signature == expected_sig assert mocked_autograph.return_value.sign_data.called_once()
def test_signatures_update_correctly_on_enable(self, mocked_autograph): recipe = RecipeFactory(signed=False, approver=UserFactory()) recipe.approved_revision.enable(user=UserFactory()) recipe.refresh_from_db() assert recipe.signature is not None assert recipe.signature.signature == fake_sign([recipe.canonical_json()])[0]["signature"]
def test_it_doesnt_disable_recipes(self, mock_action): recipe = RecipeFactory( action__name='test-action', action__implementation='old', enabled=True ) action = recipe.action mock_action(action.name, 'impl', action.arguments_schema) call_command('update_actions') recipe.refresh_from_db() assert recipe.enabled
def test_enabled_updates_signatures(self, mocked_autograph): recipe = RecipeFactory(name="first") ar = recipe.latest_revision.request_approval(UserFactory()) ar.approve(approver=UserFactory(), comment="r+") recipe = Recipe.objects.get() recipe.approved_revision.enable(UserFactory()) recipe.refresh_from_db() data_to_sign = recipe.canonical_json() signature_of_data = fake_sign([data_to_sign])[0]["signature"] signature_in_db = recipe.signature.signature assert signature_of_data == signature_in_db
def test_approval_request_property(self): # Make sure it works when there is no approval request recipe = RecipeFactory(name="old") assert recipe.approval_request is None # Make sure it returns an approval request if it exists approval = ApprovalRequestFactory(revision=recipe.latest_revision) assert recipe.approval_request == approval # Check the edge case where there is no latest_revision recipe.latest_revision.delete() recipe.refresh_from_db() assert recipe.approval_request is None
def test_approval_request_property(self): # Make sure it works when there is no approval request recipe = RecipeFactory(name='old') assert recipe.approval_request is None # Make sure it returns an approval request if it exists approval = ApprovalRequestFactory(revision=recipe.latest_revision) assert recipe.approval_request == approval # Check the edge case where there is no latest_revision recipe.latest_revision.delete() recipe.refresh_from_db() assert recipe.approval_request is None
def test_it_can_change_arguments_for_recipes(self, api_client): recipe = RecipeFactory(arguments_json='{}') action = ActionFactory(name='foobarbaz', arguments_schema={ 'type': 'object', 'properties': { 'message': { 'type': 'string' }, 'checkbox': { 'type': 'boolean' }, }, 'required': ['message', 'checkbox'] }) arguments = { 'message': 'test message', 'checkbox': False, } res = api_client.patch('/api/v2/recipe/%s/' % recipe.id, { 'action_id': action.id, 'arguments': arguments, }) assert res.status_code == 200, res.json() recipe.refresh_from_db() assert recipe.arguments == arguments res = api_client.get('/api/v2/recipe/%s/' % recipe.id) assert res.status_code == 200, res.json() assert res.json()['arguments'] == arguments arguments = { 'message': 'second message', 'checkbox': True, } res = api_client.patch('/api/v2/recipe/%s/' % recipe.id, { 'action_id': action.id, 'arguments': arguments, }) assert res.status_code == 200, res.json() recipe.refresh_from_db() assert recipe.arguments == arguments res = api_client.get('/api/v2/recipe/%s/' % recipe.id) assert res.status_code == 200, res.json() assert res.json()['arguments'] == arguments
def test_signatures_update_correctly_on_enable(self, mocker): mock_autograph = mocker.patch('normandy.recipes.models.Autographer') def fake_sign(datas): sigs = [] for d in datas: sigs.append({'signature': hashlib.sha256(d).hexdigest()}) return sigs mock_autograph.return_value.sign_data.side_effect = fake_sign recipe = RecipeFactory(enabled=False, signed=False) recipe.enabled = True recipe.save() recipe.refresh_from_db() assert recipe.signature is not None assert recipe.signature.signature == hashlib.sha256(recipe.canonical_json()).hexdigest()
def test_signatures_update_correctly_on_enable(self, mocker): mock_autograph = mocker.patch('normandy.recipes.models.Autographer') def fake_sign(datas): sigs = [] for d in datas: sigs.append({'signature': hashlib.sha256(d).hexdigest()}) return sigs mock_autograph.return_value.sign_data.side_effect = fake_sign recipe = RecipeFactory(enabled=False, signed=False) recipe.enabled = True recipe.save() recipe.refresh_from_db() assert recipe.signature is not None assert recipe.signature.signature == hashlib.sha256( recipe.canonical_json()).hexdigest()
def test_error_during_approval_rolls_back_changes(self, mocker): recipe = RecipeFactory(approver=UserFactory(), enabler=UserFactory()) old_approved_revision = recipe.approved_revision recipe.revise(name="New name") latest_revision = recipe.latest_revision approval_request = recipe.latest_revision.request_approval(UserFactory()) # Simulate an error during signing mocked_update_signature = mocker.patch.object(recipe, "update_signature") mocked_update_signature.side_effect = Exception with pytest.raises(Exception): approval_request.approve(UserFactory(), "r+") # Ensure the changes to the approval request and the recipe are rolled back and the recipe # is still enabled recipe.refresh_from_db() approval_request.refresh_from_db() assert approval_request.approved is None assert recipe.approved_revision == old_approved_revision assert recipe.latest_revision == latest_revision assert recipe.approved_revision.enabled
def test_signatures_are_updated(self, mocked_autograph, storage): extension = ExtensionFactory() fake_old_url = extension.xpi.url.replace("/media/", "/media-old/") action = ActionFactory(name="opt-out-study") recipe = RecipeFactory( action=action, arguments={addonUrl: fake_old_url}, approver=UserFactory(), enabler=UserFactory(), signed=True, ) # preconditions assert recipe.signature is not None assert recipe.signature.signature == hashlib.sha256(recipe.canonical_json()).hexdigest() signature_before = recipe.signature.signature call_command("update_addon_urls") recipe.refresh_from_db() assert recipe.signature is not None assert recipe.signature != signature_before assert recipe.signature.signature == hashlib.sha256(recipe.canonical_json()).hexdigest()
def test_signatures_are_updated(self, mocked_autograph): action = ActionFactory(name="opt-out-study") recipe = RecipeFactory( action=action, arguments={ "addonUrl": "https://before.example.com/extensions/addon.xpi" }, approver=UserFactory(), enabler=UserFactory(), signed=True, ) # preconditions assert recipe.signature is not None assert recipe.signature.signature == hashlib.sha256( recipe.canonical_json()).hexdigest() signature_before = recipe.signature.signature call_command("update_addon_urls", "after.example.com") recipe.refresh_from_db() assert recipe.signature is not None assert recipe.signature != signature_before assert recipe.signature.signature == hashlib.sha256( recipe.canonical_json()).hexdigest()
def test_it_unsigns_disabled_recipes(self, mocked_autograph): r = RecipeFactory(enabled=False, signed=True) call_command('update_recipe_signatures') r.refresh_from_db() assert r.signature is None
def test_it_signs_unsigned_enabled_recipes(self, mocked_autograph): r = RecipeFactory(approver=UserFactory(), enabled=True, signed=False) call_command('update_recipe_signatures') r.refresh_from_db() assert r.signature is not None
def test_it_unsigns_disabled_recipes(self, mocked_autograph): r = RecipeFactory(approver=UserFactory(), signed=True) call_command("update_recipe_signatures") r.refresh_from_db() assert r.signature is None