def test_setting_signature_doesnt_change_canonical_json(self): recipe = RecipeFactory(name='unchanged', signed=False) serialized = recipe.canonical_json() recipe.signature = SignatureFactory() recipe.save() assert recipe.signature is not None assert recipe.canonical_json() == serialized
def test_setting_signature_doesnt_change_canonical_json(self): recipe = RecipeFactory(name="unchanged", signed=False) serialized = recipe.canonical_json() recipe.signature = SignatureFactory() recipe.save() assert recipe.signature is not None assert recipe.canonical_json() == serialized
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_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_canonical_json(self): recipe = RecipeFactory( action=ActionFactory(name="action"), arguments_json='{"foo": 1, "bar": 2}', extra_filter_expression="2 + 2 == 4", name="canonical", filter_object_json=None, ) # Yes, this is really ugly, but we really do need to compare an exact # byte sequence, since this is used for hashing and signing filter_expression = "2 + 2 == 4" expected = ( "{" '"action":"action",' '"arguments":{"bar":2,"foo":1},' '"filter_expression":"%(filter_expression)s",' '"id":%(id)s,' '"name":"canonical",' '"revision_id":"%(revision_id)s"' "}" ) % { "id": recipe.id, "revision_id": recipe.revision_id, "filter_expression": filter_expression, } expected = expected.encode() assert recipe.canonical_json() == expected
def test_canonical_json(self): recipe = RecipeFactory( action=ActionFactory(name="action"), arguments_json='{"foo": 1, "bar": 2}', extra_filter_expression="2 + 2 == 4", name="canonical", filter_object_json=None, ) # Yes, this is really ugly, but we really do need to compare an exact # byte sequence, since this is used for hashing and signing filter_expression = "2 + 2 == 4" expected = ("{" '"action":"action",' '"arguments":{"bar":2,"foo":1},' '"filter_expression":"%(filter_expression)s",' '"id":%(id)s,' '"name":"canonical",' '"revision_id":"%(revision_id)s"' "}") % { "id": recipe.id, "revision_id": recipe.revision_id, "filter_expression": filter_expression, } expected = expected.encode() assert recipe.canonical_json() == expected
def test_canonical_json(self): recipe = RecipeFactory( action=ActionFactory(name='action'), arguments_json='{"foo": 1, "bar": 2}', channels=[ChannelFactory(slug='beta')], countries=[CountryFactory(code='CA')], enabled=False, extra_filter_expression='2 + 2 == 4', locales=[LocaleFactory(code='en-US')], name='canonical', ) # Yes, this is really ugly, but we really do need to compare an exact # byte sequence, since this is used for hashing and signing filter_expression = ( "(normandy.locale in ['en-US']) && (normandy.country in ['CA']) && " "(normandy.channel in ['beta']) && (2 + 2 == 4)") expected = ('{' '"action":"action",' '"arguments":{"bar":2,"foo":1},' '"enabled":false,' '"filter_expression":"%(filter_expression)s",' '"id":%(id)s,' '"is_approved":false,' '"last_updated":"%(last_updated)s",' '"name":"canonical",' '"revision_id":"%(revision_id)s"' '}') % { 'id': recipe.id, 'revision_id': recipe.revision_id, 'last_updated': recipe.last_updated.strftime('%Y-%m-%dT%H:%M:%S.%fZ'), 'filter_expression': filter_expression } expected = expected.encode() assert recipe.canonical_json() == expected
def test_signature_is_updated_if_autograph_available(self, mocked_autograph): recipe = RecipeFactory(name="unchanged", approver=UserFactory(), enabler=UserFactory()) original_signature = recipe.signature assert original_signature is not None recipe.revise(name="changed") assert recipe.latest_revision.name == "changed" assert recipe.signature is not original_signature expected_sig = fake_sign([recipe.canonical_json()])[0]["signature"] assert recipe.signature.signature == expected_sig
def test_signature_is_updated_if_autograph_available( self, mocked_autograph): recipe = RecipeFactory(name='unchanged') original_signature = recipe.signature assert original_signature is not None recipe.revise(name='changed') assert recipe.name == 'changed' assert recipe.signature is not original_signature expected_sig = hashlib.sha256(recipe.canonical_json()).hexdigest() assert recipe.signature.signature == expected_sig
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_signature_is_updated_if_autograph_available(self, mocked_autograph): recipe = RecipeFactory(name='unchanged') original_signature = recipe.signature assert original_signature is not None recipe.name = 'changed' recipe.save() assert recipe.name == 'changed' assert recipe.signature is not original_signature expected_sig = hashlib.sha256(recipe.canonical_json()).hexdigest() assert recipe.signature.signature == expected_sig
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_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_signature_is_correct_on_creation_if_autograph_available(self, mocked_autograph): recipe = RecipeFactory() expected_sig = hashlib.sha256(recipe.canonical_json()).hexdigest() assert recipe.signature.signature == expected_sig
def test_signed_true(self): r = RecipeFactory(signed=True) assert r.signature is not None assert r.signature.signature == hashlib.sha256(r.canonical_json()).hexdigest() assert isinstance(r.signature.timestamp, datetime)
def test_signed_true(self): r = RecipeFactory(signed=True) assert r.signature is not None assert r.signature.signature == hashlib.sha256( r.canonical_json()).hexdigest() assert isinstance(r.signature.timestamp, datetime)
def test_signature_is_correct_on_creation_if_autograph_available( self, mocked_autograph): recipe = RecipeFactory() expected_sig = hashlib.sha256(recipe.canonical_json()).hexdigest() assert recipe.signature.signature == expected_sig
def test_signature_is_correct_on_creation_if_autograph_available( self, mocked_autograph): recipe = RecipeFactory(approver=UserFactory(), enabler=UserFactory()) expected_sig = fake_sign([recipe.canonical_json()])[0]["signature"] assert recipe.signature.signature == expected_sig
def test_signature_is_correct_on_creation_if_autograph_available(self, mocked_autograph): recipe = RecipeFactory(approver=UserFactory(), enabler=UserFactory()) expected_sig = fake_sign([recipe.canonical_json()])[0]["signature"] assert recipe.signature.signature == expected_sig