Add use-autograph flag, time autograph specific signing calls. (#7401)

* Add use-autograph flag, make use of it everywhere.

This adds support for a use-autograph flag to our management commands,
signing and language pack fetching to allow us to enable it gradually
and to re-sign add-ons manually with autograph for testing purposes.

Fixes #7380

* Use different statsd key for autograph signing.

* Various cleanups and fixes

* Fix command tests and others

* Fix ui-tests

* Unify flag usage, fix crypto tests

* Fix sign_file calls

* Just not use autograph for langpacks unless we switch it on for the broad mass.

* Fix tests and codestyle

* More codestyle...
This commit is contained in:
Christopher Grebs 2018-01-30 11:14:16 +01:00 коммит произвёл GitHub
Родитель f1d1289a86
Коммит e949076363
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
17 изменённых файлов: 188 добавлений и 87 удалений

Просмотреть файл

@ -27,7 +27,10 @@ tasks = {
'qs': [
Q(_current_version__autoapprovalsummary__verdict=amo.AUTO_APPROVED)
]},
'sign_addons': {'method': sign_addons, 'qs': []},
'sign_addons': {
'method': sign_addons,
'qs': [],
'allowed_kwargs': ('use_autograph',)},
'add_firefox57_tag_to_webextensions': {
'method': add_firefox57_tag,
'qs': [
@ -61,6 +64,8 @@ class Command(BaseCommand):
pre: a method to further pre process the pks, must return the pks (opt.)
qs: a list of Q objects to apply to the method
kwargs: any extra kwargs you want to apply to the delay method (optional)
allowed_kwargs: any extra boolean kwargs that can be applied via
additional arguments. Make sure to add it to `add_arguments` too.
"""
def add_arguments(self, parser):
"""Handle command arguments."""
@ -78,6 +83,12 @@ class Command(BaseCommand):
help='Include deleted add-ons when determining which '
'add-ons to process.')
parser.add_argument(
'--use-autograph',
action='store_true',
dest='use_autograph',
help='Use our new autograph signing.')
def handle(self, *args, **options):
task = tasks.get(options.get('task'))
if not task:
@ -94,17 +105,22 @@ class Command(BaseCommand):
# This is run in process to ensure its run before the tasks.
pks = task['pre'](pks)
if pks:
kw = task.get('kwargs', {})
kwargs = task.get('kwargs', {})
if task.get('allowed_kwargs'):
kwargs.update({
arg: options.get(arg, None)
for arg in task['allowed_kwargs']})
# All the remaining tasks go in one group.
grouping = []
for chunk in chunked(pks, 100):
grouping.append(
task['method'].subtask(args=[chunk], kwargs=kw))
task['method'].subtask(args=[chunk], kwargs=kwargs))
# Add the post task on to the end.
post = None
if 'post' in task:
post = task['post'].subtask(args=[], kwargs=kw, immutable=True)
post = task['post'].subtask(
args=[], kwargs=kwargs, immutable=True)
ts = chord(grouping, post)
else:
ts = group(grouping)

Просмотреть файл

@ -26,6 +26,12 @@ class Command(BaseCommand):
help='The reason for the resign that we will send '
'the developer.')
parser.add_argument(
'--use-autograph',
action='store_true',
dest='use_autograph',
help='Use our new autograph signing.')
def handle(self, *args, **options):
if len(options['addon_id']) == 0: # Sign all the addons?
raise CommandError(
@ -39,4 +45,5 @@ class Command(BaseCommand):
with override_settings(
SIGNING_SERVER=full_server):
sign_addons(
addon_ids, force=options['force'], reason=options['reason'])
addon_ids, force=options['force'], reason=options['reason'],
use_autograph=options['use_autograph'])

Просмотреть файл

@ -49,12 +49,12 @@ def test_override_SIGNING_SERVER_setting(monkeypatch):
def test_force_signing(monkeypatch):
"""You can force signing an addon even if it's already signed."""
def not_forced(ids, force, reason):
def not_forced(ids, force, reason, use_autograph):
assert not force
monkeypatch.setattr(SIGN_ADDONS, not_forced)
call_command('sign_addons', '123')
def is_forced(ids, force, reason):
def is_forced(ids, force, reason, use_autograph):
assert force
monkeypatch.setattr(SIGN_ADDONS, is_forced)
call_command('sign_addons', '123', force=True)
@ -62,7 +62,7 @@ def test_force_signing(monkeypatch):
def test_reason(monkeypatch):
"""You can pass a reason."""
def has_reason(ids, force, reason):
def has_reason(ids, force, reason, use_autograph):
assert reason == 'expiry'
monkeypatch.setattr(SIGN_ADDONS, has_reason)
call_command('sign_addons', '123', reason='expiry')

Просмотреть файл

@ -74,26 +74,28 @@ def validate(file_, listed=None, subtask=None, synchronous=False):
return result
def validate_and_submit(addon, file_, channel):
def validate_and_submit(addon, file_, channel, use_autograph=False):
return validate(
file_, listed=(channel == amo.RELEASE_CHANNEL_LISTED),
subtask=submit_file.si(addon.pk, file_.pk, channel))
subtask=submit_file.si(
addon.pk, file_.pk, channel, use_autograph=use_autograph))
@task
@write
def submit_file(addon_pk, upload_pk, channel):
def submit_file(addon_pk, upload_pk, channel, use_autograph=False):
addon = Addon.unfiltered.get(pk=addon_pk)
upload = FileUpload.objects.get(pk=upload_pk)
if upload.passed_all_validations:
create_version_for_upload(addon, upload, channel)
create_version_for_upload(
addon, upload, channel, use_autograph=use_autograph)
else:
log.info('Skipping version creation for {upload_uuid} that failed '
'validation'.format(upload_uuid=upload.uuid))
@atomic
def create_version_for_upload(addon, upload, channel):
def create_version_for_upload(addon, upload, channel, use_autograph=False):
"""Note this function is only used for API uploads."""
fileupload_exists = addon.fileupload_set.filter(
created__gt=upload.created, version=upload.version).exists()
@ -118,7 +120,8 @@ def create_version_for_upload(addon, upload, channel):
if (addon.status == amo.STATUS_NULL and
channel == amo.RELEASE_CHANNEL_LISTED):
addon.update(status=amo.STATUS_NOMINATED)
auto_sign_version(version, is_beta=version.is_beta)
auto_sign_version(
version, is_beta=version.is_beta, use_autograph=use_autograph)
# Override the validator's stock timeout exception so that it can

Просмотреть файл

@ -1015,7 +1015,8 @@ class TestSubmitFile(TestCase):
upload = self.create_upload()
tasks.submit_file(self.addon.pk, upload.pk, amo.RELEASE_CHANNEL_LISTED)
self.create_version_for_upload.assert_called_with(
self.addon, upload, amo.RELEASE_CHANNEL_LISTED)
self.addon, upload, amo.RELEASE_CHANNEL_LISTED,
use_autograph=False)
@mock.patch('olympia.devhub.tasks.FileUpload.passed_all_validations',
False)

Просмотреть файл

@ -323,8 +323,9 @@ class TestAddonSubmitUpload(UploadTest, TestCase):
response, reverse('devhub.submit.finish', args=[addon.slug]))
all_ = sorted([f.filename for f in latest_version.all_files])
assert all_ == [u'xpi_name-0.1-linux.xpi', u'xpi_name-0.1-mac.xpi']
mock_auto_sign_file.assert_has_calls(
[mock.call(f, is_beta=False) for f in latest_version.all_files])
mock_auto_sign_file.assert_has_calls([
mock.call(f, is_beta=False, use_autograph=False)
for f in latest_version.all_files])
def test_with_source(self):
response = self.client.get(
@ -1453,8 +1454,9 @@ class TestVersionSubmitUploadUnlisted(VersionSubmitUploadMixin, UploadTest):
self).test_one_xpi_for_multiple_platforms()
version = self.addon.find_latest_version(
channel=amo.RELEASE_CHANNEL_UNLISTED)
mock_auto_sign_file.assert_has_calls(
[mock.call(f, is_beta=False) for f in version.all_files])
mock_auto_sign_file.assert_has_calls([
mock.call(f, is_beta=False, use_autograph=False)
for f in version.all_files])
def test_no_force_beta_for_unlisted(self):
"""No beta version for unlisted addons."""

Просмотреть файл

@ -550,7 +550,7 @@ def check_addon_compatibility(request):
'new_addon_form': forms.DistributionChoiceForm()})
def handle_upload(filedata, user, channel, app_id=None, version_id=None,
def handle_upload(filedata, request, channel, app_id=None, version_id=None,
addon=None, is_standalone=False, submit=False):
automated_signing = channel == amo.RELEASE_CHANNEL_UNLISTED
@ -558,8 +558,8 @@ def handle_upload(filedata, user, channel, app_id=None, version_id=None,
filedata, filedata.name, filedata.size,
automated_signing=automated_signing, addon=addon)
log.info('FileUpload created: %s' % upload.uuid.hex)
if user.is_authenticated():
upload.user = user
if request.user.is_authenticated():
upload.user = request.user
upload.save()
if app_id and version_id:
# If app_id and version_id are present, we are dealing with a
@ -573,7 +573,10 @@ def handle_upload(filedata, user, channel, app_id=None, version_id=None,
ver = get_object_or_404(AppVersion, pk=version_id)
tasks.compatibility_check.delay(upload.pk, app.guid, ver.version)
elif submit:
tasks.validate_and_submit(addon, upload, channel=channel)
tasks.validate_and_submit(
addon, upload, channel=channel,
use_autograph=waffle.flag_is_active(
request, 'activate-autograph-signing'))
else:
tasks.validate(upload, listed=(channel == amo.RELEASE_CHANNEL_LISTED))
@ -588,7 +591,7 @@ def upload(request, channel='listed', addon=None, is_standalone=False):
app_id = request.POST.get('app_id')
version_id = request.POST.get('version_id')
upload = handle_upload(
filedata=filedata, user=request.user, app_id=app_id,
filedata=filedata, request=request, app_id=app_id,
version_id=version_id, addon=addon, is_standalone=is_standalone,
channel=channel)
if addon:
@ -1190,18 +1193,18 @@ def check_validation_override(request, form, addon, version):
helper.actions['super']['method']()
def auto_sign_file(file_, is_beta=False):
def auto_sign_file(file_, use_autograph=False, is_beta=False):
"""If the file should be automatically reviewed and signed, do it."""
addon = file_.version.addon
if file_.is_experiment: # See bug 1220097.
ActivityLog.create(amo.LOG.EXPERIMENT_SIGNED, file_)
sign_file(file_)
sign_file(file_, use_autograph=use_autograph)
elif is_beta:
# Beta won't be reviewed. They will always get signed, and logged, for
# further review if needed.
ActivityLog.create(amo.LOG.BETA_SIGNED, file_)
sign_file(file_)
sign_file(file_, use_autograph=use_autograph)
elif file_.version.channel == amo.RELEASE_CHANNEL_UNLISTED:
# Sign automatically without manual review.
helper = ReviewHelper(request=None, addon=addon,
@ -1213,10 +1216,10 @@ def auto_sign_file(file_, is_beta=False):
ActivityLog.create(amo.LOG.UNLISTED_SIGNED, file_)
def auto_sign_version(version, **kwargs):
def auto_sign_version(version, use_autograph=False, **kwargs):
# Sign all the unapproved files submitted, one for each platform.
for file_ in version.files.exclude(status=amo.STATUS_PUBLIC):
auto_sign_file(file_, **kwargs)
auto_sign_file(file_, use_autograph=use_autograph, **kwargs)
@dev_required
@ -1397,7 +1400,12 @@ def _submit_upload(request, addon, channel, next_details, next_finish,
channel == amo.RELEASE_CHANNEL_LISTED):
addon.update(status=amo.STATUS_NOMINATED)
# auto-sign versions (the method checks eligibility)
auto_sign_version(version, is_beta=is_beta)
use_autograph = waffle.flag_is_active(
request, 'activate-autograph-signing')
auto_sign_version(
version,
is_beta=is_beta,
use_autograph=use_autograph)
next_url = (next_details
if channel == amo.RELEASE_CHANNEL_LISTED and not is_beta
else next_finish)

Просмотреть файл

@ -4,6 +4,7 @@ import random
from django.conf import settings
from django.utils.translation import activate
from django.core.files.uploadedfile import SimpleUploadedFile
from django.test.client import RequestFactory
from rest_framework import serializers
from olympia.amo.tests import user_factory, addon_factory, copy_file_to_temp
@ -274,9 +275,12 @@ class GenerateAddonsSerializer(serializers.Serializer):
# now, lets upload the file into the system
from olympia.devhub.views import handle_upload
request = RequestFactory().get('/')
request.user = user
upload = handle_upload(
filedata=filedata,
user=user,
request=request,
channel=amo.RELEASE_CHANNEL_LISTED,
addon=addon,
)

Просмотреть файл

@ -11,7 +11,6 @@ from django.core.files.storage import default_storage as storage
from django.utils.encoding import force_bytes
import requests
import waffle
from django_statsd.clients import statsd
from requests_hawk import HawkAuth
@ -61,14 +60,13 @@ def get_id(addon):
return hashlib.sha256(guid).hexdigest()
def call_signing(file_obj):
def call_signing(file_obj, use_autograph=False):
"""Get the jar signature and send it to the signing server to be signed."""
# Extract jar signature.
jar = JarExtractor(path=storage.open(file_obj.file_path))
log.debug(u'File signature contents: {0}'.format(jar.signatures))
use_autograph = waffle.switch_is_active('activate-autograph-signing')
signed_manifest = unicode(jar.signatures)
has_error = False
@ -86,7 +84,7 @@ def call_signing(file_obj):
}]
# post the request
with statsd.timer('services.sign.addon'):
with statsd.timer('services.sign.addon.autograph'):
response = requests.post(
'{server}/sign/data'.format(server=conf['server_url']),
json=signing_request,
@ -135,7 +133,7 @@ def call_signing(file_obj):
return cert_serial_num
def sign_file(file_obj):
def sign_file(file_obj, use_autograph=False):
"""Sign a File.
If there's no endpoint (signing is not enabled), or the file is a hotfix,
@ -180,7 +178,8 @@ def sign_file(file_obj):
return
# Sign the file. If there's any exception, we skip the rest.
cert_serial_num = unicode(call_signing(file_obj))
cert_serial_num = unicode(
call_signing(file_obj, use_autograph=use_autograph))
size = storage.size(file_obj.file_path)

Просмотреть файл

@ -88,7 +88,7 @@ def get_new_version_number(version):
@task
def sign_addons(addon_ids, force=False, **kw):
def sign_addons(addon_ids, force=False, use_autograph=False, **kw):
"""Used to sign all the versions of an addon.
This is used in the 'sign_addons' and 'process_addons --task sign_addons'
@ -138,7 +138,7 @@ def sign_addons(addon_ids, force=False, **kw):
# Need to bump the version (modify manifest file)
# before the file is signed.
update_version_number(file_obj, bumped_version_number)
signed = bool(sign_file(file_obj))
signed = bool(sign_file(file_obj, use_autograph=False))
if signed: # Bump the version number if at least one signed.
signed_at_least_a_file = True
else: # We didn't sign, so revert the version bump.

Просмотреть файл

@ -16,11 +16,11 @@ import pytest
import responses
from signing_clients.apps import SignatureInfo
from waffle.models import Switch
from waffle.models import Flag
from olympia import amo
from olympia.addons.models import AddonUser
from olympia.amo.tests import TestCase, create_switch
from olympia.amo.tests import TestCase, create_flag
from olympia.files.utils import extract_xpi
from olympia.lib.crypto import packaged, tasks
from olympia.versions.compare import version_int
@ -86,6 +86,9 @@ class TestPackagedTrunion(TestCase):
json={'mozilla.rsa': base64.b64encode(signature)},
status=200)
def _sign_file(self, file_):
packaged.sign_file(file_)
def assert_not_signed(self):
assert not self.file_.is_signed
assert not self.file_.cert_serial_num
@ -108,7 +111,7 @@ class TestPackagedTrunion(TestCase):
max_appversion.update(version='4', version_int=version_int('4'))
self.file_.update(binary_components=True, strict_compatibility=True)
self.assert_not_signed()
packaged.sign_file(self.file_)
self._sign_file(self.file_)
self.assert_signed()
@responses.activate
@ -120,7 +123,7 @@ class TestPackagedTrunion(TestCase):
version='4', version_int=version_int('4'))
self.file_.update(binary_components=True, strict_compatibility=True)
self.assert_not_signed()
packaged.sign_file(self.file_)
self._sign_file(self.file_)
self.assert_signed()
@responses.activate
@ -131,7 +134,7 @@ class TestPackagedTrunion(TestCase):
max_appversion.update(version='4', version_int=version_int('4'))
self.file_.update(binary_components=False, strict_compatibility=False)
self.assert_not_signed()
packaged.sign_file(self.file_)
self._sign_file(self.file_)
self.assert_signed()
@responses.activate
@ -143,7 +146,7 @@ class TestPackagedTrunion(TestCase):
version='4', version_int=version_int('4'))
self.file_.update(binary_components=False, strict_compatibility=False)
self.assert_not_signed()
packaged.sign_file(self.file_)
self._sign_file(self.file_)
self.assert_signed()
@responses.activate
@ -154,7 +157,7 @@ class TestPackagedTrunion(TestCase):
max_appversion.update(version='37', version_int=version_int('37'))
self.file_.update(binary_components=False, strict_compatibility=False)
self.assert_not_signed()
packaged.sign_file(self.file_)
self._sign_file(self.file_)
self.assert_signed()
@responses.activate
@ -166,7 +169,7 @@ class TestPackagedTrunion(TestCase):
version='37', version_int=version_int('37'))
self.file_.update(binary_components=True, strict_compatibility=True)
self.assert_not_signed()
packaged.sign_file(self.file_)
self._sign_file(self.file_)
self.assert_signed()
def test_get_trunion_endpoint(self):
@ -177,13 +180,13 @@ class TestPackagedTrunion(TestCase):
def test_no_server_full(self):
with self.settings(SIGNING_SERVER=''):
packaged.sign_file(self.file_)
self._sign_file(self.file_)
self.assert_not_signed()
@responses.activate
def test_sign_file(self):
self.assert_not_signed()
packaged.sign_file(self.file_)
self._sign_file(self.file_)
self.assert_signed()
# Make sure there's two newlines at the end of the mozilla.sf file (see
# bug 1158938).
@ -197,7 +200,7 @@ class TestPackagedTrunion(TestCase):
self.file_.update(filename=u'jétpack.xpi')
shutil.move(src, self.file_.file_path)
self.assert_not_signed()
packaged.sign_file(self.file_)
self._sign_file(self.file_)
self.assert_signed()
def test_no_sign_missing_file(self):
@ -205,7 +208,7 @@ class TestPackagedTrunion(TestCase):
assert not self.file_.is_signed
assert not self.file_.cert_serial_num
assert not self.file_.hash
packaged.sign_file(self.file_)
self._sign_file(self.file_)
assert not self.file_.is_signed
assert not self.file_.cert_serial_num
assert not self.file_.hash
@ -215,25 +218,25 @@ class TestPackagedTrunion(TestCase):
"""Don't sign hotfix addons."""
for hotfix_guid in settings.HOTFIX_ADDON_GUIDS:
self.addon.update(guid=hotfix_guid)
packaged.sign_file(self.file_)
self._sign_file(self.file_)
self.assert_not_signed()
def test_no_sign_again_mozilla_signed_extensions(self):
"""Don't try to resign mozilla signed extensions."""
self.file_.update(is_mozilla_signed_extension=True)
packaged.sign_file(self.file_)
self._sign_file(self.file_)
self.assert_not_signed()
@responses.activate
def test_is_signed(self):
assert not packaged.is_signed(self.file_.file_path)
packaged.sign_file(self.file_)
self._sign_file(self.file_)
assert packaged.is_signed(self.file_.file_path)
@responses.activate
def test_size_updated(self):
unsigned_size = storage.size(self.file_.file_path)
packaged.sign_file(self.file_)
self._sign_file(self.file_)
signed_size = storage.size(self.file_.file_path)
assert self.file_.size == signed_size
assert unsigned_size < signed_size
@ -245,7 +248,7 @@ class TestPackagedTrunion(TestCase):
self.file_.update(is_multi_package=True)
self.assert_not_signed()
packaged.sign_file(self.file_)
self._sign_file(self.file_)
self.assert_not_signed()
# The multi-package itself isn't signed.
assert not packaged.is_signed(self.file_.file_path)
@ -313,11 +316,11 @@ class TestPackagedTrunion(TestCase):
class TestPackagedAutograph(TestPackagedTrunion):
def setUp(self):
create_switch('activate-autograph-signing')
create_flag('activate-autograph-signing')
super(TestPackagedAutograph, self).setUp()
def tearDown(self):
Switch.objects.filter(name='activate-autograph-signing').delete()
Flag.objects.filter(name='activate-autograph-signing').delete()
super(TestPackagedAutograph, self).tearDown()
def _register_urls(self):
@ -330,6 +333,9 @@ class TestPackagedAutograph(TestPackagedTrunion):
return SignatureInfo(pkcs7)
def _sign_file(self, file_):
packaged.sign_file(file_, use_autograph=True)
def assert_not_signed(self):
# Overwritten to not rely on `responses` but check the real deal
assert not self.file_.is_signed
@ -349,7 +355,7 @@ class TestPackagedAutograph(TestPackagedTrunion):
return
def test_call_signing(self):
packaged.sign_file(self.file_)
self._sign_file(self.file_)
signature_info = self._get_signature_info()
@ -360,7 +366,7 @@ class TestPackagedAutograph(TestPackagedTrunion):
long_guid = 'x' * 65
hashed = hashlib.sha256(long_guid).hexdigest()
self.addon.update(guid=long_guid)
packaged.sign_file(self.file_)
self._sign_file(self.file_)
signature_info = self._get_signature_info()
@ -460,7 +466,7 @@ class TestTasks(TestCase):
'src/olympia/files/fixtures/files/jetpack.xpi',
self.file_.file_path):
tasks.sign_addons([self.addon.pk])
mock_sign_file.assert_called_with(self.file_)
mock_sign_file.assert_called_with(self.file_, use_autograph=False)
@mock.patch('olympia.lib.crypto.tasks.sign_file')
def test_sign_supported_applications(self, mock_sign_file):
@ -471,7 +477,8 @@ class TestTasks(TestCase):
for app in (amo.ANDROID.id, amo.FIREFOX.id):
self.max_appversion.update(application=app)
tasks.sign_addons([self.addon.pk])
mock_sign_file.assert_called_with(self.file_)
mock_sign_file.assert_called_with(
self.file_, use_autograph=False)
mock_sign_file.reset_mock()
def assert_not_signed(self, mock_sign_file, file_hash):
@ -661,7 +668,7 @@ class TestTasks(TestCase):
'src/olympia/files/fixtures/files/jetpack.xpi',
self.file_.file_path):
tasks.sign_addons([self.addon.pk], reason='expiry')
mock_sign_file.assert_called_with(self.file_)
mock_sign_file.assert_called_with(self.file_, use_autograph=False)
assert 'expiration' in mail.outbox[0].message().as_string()

Просмотреть файл

@ -556,7 +556,7 @@ class TestReviewHelper(TestCase):
approval_counter = AddonApprovalsCounter.objects.get(addon=self.addon)
assert approval_counter.counter == 1
sign_mock.assert_called_with(self.file)
sign_mock.assert_called_with(self.file, use_autograph=False)
assert storage.exists(self.file.file_path)
assert self.check_log_count(amo.LOG.APPROVE_VERSION.id) == 1
@ -584,7 +584,7 @@ class TestReviewHelper(TestCase):
approval_counter = AddonApprovalsCounter.objects.get(addon=self.addon)
assert approval_counter.counter == 1
sign_mock.assert_called_with(self.file)
sign_mock.assert_called_with(self.file, use_autograph=False)
assert storage.exists(self.file.file_path)
assert self.check_log_count(amo.LOG.APPROVE_VERSION.id) == 1
@ -618,7 +618,7 @@ class TestReviewHelper(TestCase):
# human review field should be empty.
assert approval_counter.last_human_review is None
sign_mock.assert_called_with(self.file)
sign_mock.assert_called_with(self.file, use_autograph=False)
assert storage.exists(self.file.file_path)
assert self.check_log_count(amo.LOG.APPROVE_VERSION.id) == 1
@ -669,7 +669,7 @@ class TestReviewHelper(TestCase):
assert approval_counter.counter == 2
self.assertCloseToNow(approval_counter.last_human_review)
sign_mock.assert_called_with(self.file)
sign_mock.assert_called_with(self.file, use_autograph=False)
assert storage.exists(self.file.file_path)
assert self.check_log_count(amo.LOG.APPROVE_VERSION.id) == 1
@ -875,7 +875,7 @@ class TestReviewHelper(TestCase):
'%s signed and ready to download' % self.preamble)
assert 'our automatic tests and is now signed' in mail.outbox[0].body
sign_mock.assert_called_with(self.file)
sign_mock.assert_called_with(self.file, use_autograph=False)
assert storage.exists(self.file.file_path)
assert self.check_log_count(amo.LOG.APPROVE_VERSION.id) == 1

Просмотреть файл

@ -11,6 +11,7 @@ from django.utils.translation import ugettext, ugettext_lazy as _, ungettext
import django_tables2 as tables
import jinja2
import waffle
import olympia.core.logger
@ -611,8 +612,10 @@ class ReviewBase(object):
assert not self.content_review_only
# Sign addon.
use_autograph = waffle.flag_is_active(
self.request, 'activate-autograph-signing')
for file_ in self.files:
sign_file(file_)
sign_file(file_, use_autograph=use_autograph)
# Hold onto the status before we change it.
status = self.addon.status
@ -809,8 +812,10 @@ class ReviewUnlisted(ReviewBase):
assert self.version.channel == amo.RELEASE_CHANNEL_UNLISTED
# Sign addon.
use_autograph = waffle.flag_is_active(
self.request, 'activate-autograph-signing')
for file_ in self.files:
sign_file(file_)
sign_file(file_, use_autograph=use_autograph)
self.set_files(amo.STATUS_PUBLIC, self.files)

Просмотреть файл

@ -17,7 +17,7 @@ from rest_framework.response import Response
from olympia import amo
from olympia.access.models import Group, GroupUser
from olympia.addons.models import Addon, AddonUser
from olympia.amo.tests import addon_factory
from olympia.amo.tests import addon_factory, create_flag
from olympia.api.tests.utils import APIKeyAuthTestCase
from olympia.applications.models import AppVersion
from olympia.devhub import tasks
@ -122,7 +122,28 @@ class TestUploadVersion(BaseUploadVersionCase):
assert latest_version
assert latest_version.channel == amo.RELEASE_CHANNEL_UNLISTED
self.auto_sign_version.assert_called_with(
latest_version, is_beta=False)
latest_version, is_beta=False, use_autograph=False)
def test_addon_does_not_exist_use_autograph(self):
guid = '@create-version'
qs = Addon.unfiltered.filter(guid=guid)
assert not qs.exists()
create_flag('activate-autograph-signing')
response = self.request('PUT', addon=guid, version='1.0')
assert response.status_code == 201
assert qs.exists()
addon = qs.get()
assert addon.guid == guid
assert addon.has_author(self.user)
assert addon.status == amo.STATUS_NULL
latest_version = addon.find_latest_version(
channel=amo.RELEASE_CHANNEL_UNLISTED)
assert latest_version
assert latest_version.channel == amo.RELEASE_CHANNEL_UNLISTED
self.auto_sign_version.assert_called_with(
latest_version, is_beta=False, use_autograph=True)
def test_new_addon_random_slug_unlisted_channel(self):
guid = '@create-webextension'
@ -193,7 +214,8 @@ class TestUploadVersion(BaseUploadVersionCase):
assert version.statuses[0][1] == amo.STATUS_AWAITING_REVIEW
assert version.addon.status == amo.STATUS_PUBLIC
assert version.channel == amo.RELEASE_CHANNEL_LISTED
self.auto_sign_version.assert_called_with(version, is_beta=False)
self.auto_sign_version.assert_called_with(
version, is_beta=False, use_autograph=False)
assert not version.all_files[0].is_mozilla_signed_extension
def test_version_already_uploaded(self):
@ -241,7 +263,8 @@ class TestUploadVersion(BaseUploadVersionCase):
assert latest_version
assert latest_version.channel == amo.RELEASE_CHANNEL_UNLISTED
self.auto_sign_version.assert_called_with(
latest_version, is_beta=False)
latest_version, is_beta=False,
use_autograph=False)
def test_version_added_is_experiment_reject_no_perm(self):
guid = 'experiment@xpi'
@ -276,7 +299,7 @@ class TestUploadVersion(BaseUploadVersionCase):
assert latest_version
assert latest_version.channel == amo.RELEASE_CHANNEL_UNLISTED
self.auto_sign_version.assert_called_with(
latest_version, is_beta=False)
latest_version, is_beta=False, use_autograph=False)
assert latest_version.all_files[0].is_mozilla_signed_extension
def test_mozilla_signed_not_allowed_not_mozilla(self):
@ -313,7 +336,7 @@ class TestUploadVersion(BaseUploadVersionCase):
assert latest_version
assert latest_version.channel == amo.RELEASE_CHANNEL_UNLISTED
self.auto_sign_version.assert_called_with(
latest_version, is_beta=False)
latest_version, is_beta=False, use_autograph=False)
def test_system_addon_not_allowed_not_mozilla(self):
guid = 'systemaddon@mozilla.org'
@ -351,7 +374,7 @@ class TestUploadVersion(BaseUploadVersionCase):
latest_version = addon.find_latest_version(
channel=amo.RELEASE_CHANNEL_UNLISTED)
self.auto_sign_version.assert_called_with(
latest_version, is_beta=False)
latest_version, is_beta=False, use_autograph=False)
def test_version_is_beta_unlisted(self):
addon = Addon.objects.get(guid=self.guid)
@ -375,7 +398,8 @@ class TestUploadVersion(BaseUploadVersionCase):
assert version.addon.status == amo.STATUS_NULL
assert version.channel == amo.RELEASE_CHANNEL_UNLISTED
assert not version.is_beta
self.auto_sign_version.assert_called_with(version, is_beta=False)
self.auto_sign_version.assert_called_with(
version, is_beta=False, use_autograph=False)
def test_version_is_beta(self):
assert Addon.objects.get(guid=self.guid).status == amo.STATUS_PUBLIC
@ -397,7 +421,8 @@ class TestUploadVersion(BaseUploadVersionCase):
assert version.addon.status == amo.STATUS_PUBLIC
assert version.channel == amo.RELEASE_CHANNEL_LISTED
assert version.is_beta
self.auto_sign_version.assert_called_with(version, is_beta=True)
self.auto_sign_version.assert_called_with(
version, is_beta=True, use_autograph=False)
def test_invalid_version_response_code(self):
# This raises an error in parse_addon which is not covered by
@ -533,7 +558,8 @@ class TestUploadVersionWebextension(BaseUploadVersionCase):
assert latest_version
assert latest_version.channel == amo.RELEASE_CHANNEL_UNLISTED
self.auto_sign_version.assert_called_with(
latest_version, is_beta=False)
latest_version, is_beta=False,
use_autograph=False)
def test_addon_does_not_exist_webextension_with_guid_in_url(self):
guid = '@custom-guid-provided'
@ -560,7 +586,8 @@ class TestUploadVersionWebextension(BaseUploadVersionCase):
assert latest_version
assert latest_version.channel == amo.RELEASE_CHANNEL_UNLISTED
self.auto_sign_version.assert_called_with(
latest_version, is_beta=False)
latest_version, is_beta=False,
use_autograph=False)
def test_addon_does_not_exist_webextension_with_invalid_guid_in_url(self):
guid = 'custom-invalid-guid-provided'

Просмотреть файл

@ -224,7 +224,7 @@ class VersionView(APIView):
status.HTTP_400_BAD_REQUEST)
file_upload = handle_upload(
filedata=filedata, user=request.user, addon=addon, submit=True,
filedata=filedata, request=request, addon=addon, submit=True,
channel=channel)
return file_upload, created

Просмотреть файл

@ -249,7 +249,8 @@ def fetch_langpack(url, xpi, **kw):
# Not `version.files.update`, because we need to trigger save
# hooks.
file_.update(status=amo.STATUS_PUBLIC)
sign_file(file_)
sign_file(file_, use_autograph=False)
# Finally, set the addon summary if one wasn't provided in the xpi.
addon.status = amo.STATUS_PUBLIC

Просмотреть файл

@ -134,7 +134,26 @@ class TestLangpackFetcher(TestCase):
# automatically for legacy extensions, that includes langpacks)
assert file_.strict_compatibility is True
mock_sign_file.assert_called_once_with(file_)
mock_sign_file.assert_called_once_with(file_, use_autograph=False)
@mock.patch('olympia.zadmin.tasks.sign_file')
def test_fetch_new_langpack_use_autograph(self, mock_sign_file):
assert self.get_langpacks().count() == 0
self.fetch_langpacks(amo.FIREFOX.latest_version)
langpacks = self.get_langpacks()
assert langpacks.count() == 1
addon = langpacks[0]
file_ = addon.current_version.files.get()
# has_complete_metadata checks license and categories were set.
assert addon.has_complete_metadata(), addon.get_required_metadata()
assert file_.status == amo.STATUS_PUBLIC
assert addon.status == amo.STATUS_PUBLIC
mock_sign_file.assert_called_once_with(file_, use_autograph=False)
@mock.patch('olympia.zadmin.tasks.sign_file')
def test_fetch_updated_langpack(self, mock_sign_file):
@ -164,7 +183,7 @@ class TestLangpackFetcher(TestCase):
# automatically for legacy extensions, that includes langpacks)
assert file_.strict_compatibility is True
mock_sign_file.assert_called_with(file_)
mock_sign_file.assert_called_with(file_, use_autograph=False)
@mock.patch('olympia.zadmin.tasks.sign_file')
def test_fetch_duplicate_langpack(self, mock_sign_file):
@ -186,7 +205,8 @@ class TestLangpackFetcher(TestCase):
amo.FIREFOX.latest_version)
mock_sign_file.assert_called_once_with(
addon.current_version.files.get())
addon.current_version.files.get(),
use_autograph=False)
@mock.patch('olympia.zadmin.tasks.sign_file')
def test_fetch_updated_langpack_beta(self, mock_sign_file):
@ -208,7 +228,8 @@ class TestLangpackFetcher(TestCase):
version = addon.versions.get(version=versions[1])
assert version.files.all()[0].status == amo.STATUS_BETA
mock_sign_file.assert_called_with(version.files.get())
mock_sign_file.assert_called_with(
version.files.get(), use_autograph=False)
@mock.patch('olympia.zadmin.tasks.sign_file')
def test_fetch_new_langpack_beta(self, mock_sign_file):