Skip to content

Commit 93e51ab

Browse files
committed
Call source builder API when source code is provided
1 parent 72a1302 commit 93e51ab

File tree

5 files changed

+76
-0
lines changed

5 files changed

+76
-0
lines changed

src/olympia/lib/settings_base.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -833,6 +833,7 @@ def get_language_url_map():
833833
'olympia.scanners.tasks.run_customs': {'queue': 'devhub'},
834834
'olympia.scanners.tasks.run_narc_on_version': {'queue': 'devhub'},
835835
'olympia.scanners.tasks.run_yara': {'queue': 'devhub'},
836+
'olympia.versions.tasks.call_source_builder': {'queue': 'devhub'},
836837
'olympia.versions.tasks.soft_block_versions': {'queue': 'devhub'},
837838
# Crons.
838839
'olympia.addons.tasks.update_addon_average_daily_users': {'queue': 'cron'},
@@ -1557,3 +1558,8 @@ def read_only_mode(env):
15571558
SWAGGER_SCHEMA_FILE = path('schema.yml')
15581559

15591560
SWAGGER_UI_ENABLED = env('SWAGGER_UI_ENABLED', default=False) or TARGET != 'production'
1561+
1562+
# Source builder settings.
1563+
SOURCE_BUILDER_API_URL = env('SOURCE_BUILDER_API_URL', default=None)
1564+
SOURCE_BUILDER_API_KEY = env('SOURCE_BUILDER_API_KEY', default='this-is-a-dummy-key')
1565+
SOURCE_BUILDER_API_TIMEOUT = 5 # seconds
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Generated by Django 4.2.26 on 2025-11-13 08:55
2+
3+
from django.db import migrations
4+
from olympia.core.db.migrations import CreateWaffleSwitch
5+
6+
7+
class Migration(migrations.Migration):
8+
9+
dependencies = [
10+
('versions', '0050_remove_versionreviewerflags_needs_human_review_by_mad'),
11+
]
12+
13+
operations = [CreateWaffleSwitch('enable-source-builder')]

src/olympia/versions/models.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -826,6 +826,8 @@ def flag_if_sources_were_provided(self, user):
826826
from olympia.activity.utils import log_and_notify
827827
from olympia.reviewers.models import NeedsHumanReview
828828

829+
from .tasks import call_source_builder
830+
829831
if self.source:
830832
# Add Activity Log, notifying staff, relevant reviewers and
831833
# other authors of the add-on.
@@ -835,6 +837,9 @@ def flag_if_sources_were_provided(self, user):
835837
reason = NeedsHumanReview.REASONS.PENDING_REJECTION_SOURCES_PROVIDED
836838
NeedsHumanReview.objects.create(version=self, reason=reason)
837839

840+
if waffle.switch_is_active('enable-source-builder'):
841+
call_source_builder.delay(version_pk=self.pk)
842+
838843
@classmethod
839844
def transformer(cls, versions):
840845
"""Attach all the compatible apps and the file to the versions."""

src/olympia/versions/tasks.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,14 @@
33
import os
44
import tempfile
55
from io import BytesIO
6+
from urllib.parse import urljoin
67

78
from django.conf import settings
89
from django.db import transaction
910
from django.template import loader
11+
from django.urls import reverse
1012

13+
import requests
1114
from django_statsd.clients import statsd
1215
from PIL import Image
1316

@@ -24,6 +27,7 @@
2427
from olympia.files.utils import get_background_images
2528
from olympia.lib.crypto.tasks import duplicate_addon_version
2629
from olympia.reviewers.models import NeedsHumanReview
30+
from olympia.scanners.tasks import make_adapter_with_retry
2731
from olympia.users.models import UserProfile
2832
from olympia.users.utils import get_task_user
2933
from olympia.versions.compare import VersionString
@@ -416,3 +420,35 @@ def soft_block_versions(version_ids, reason=REASON_VERSION_DELETED, **kw):
416420
),
417421
overwrite_block_metadata=False,
418422
)
423+
424+
425+
@task
426+
def call_source_builder(version_pk):
427+
log.info('Calling source builder API for Version %s', version_pk)
428+
429+
try:
430+
version = Version.objects.get(pk=version_pk)
431+
432+
with requests.Session() as http:
433+
adapter = make_adapter_with_retry()
434+
http.mount('http://', adapter)
435+
http.mount('https://', adapter)
436+
437+
json_payload = {
438+
'addon_id': version.addon_id,
439+
'version_id': version.id,
440+
'download_source_url': urljoin(
441+
settings.EXTERNAL_SITE_URL,
442+
reverse('downloads.source', kwargs={'version_id': version.id}),
443+
),
444+
'license_slug': version.license.slug,
445+
}
446+
http.post(
447+
url=settings.SOURCE_BUILDER_API_URL,
448+
json=json_payload,
449+
timeout=settings.SOURCE_BUILDER_API_TIMEOUT,
450+
)
451+
except Exception:
452+
log.exception(
453+
'Error while calling source builder API for Version %s.', version_pk
454+
)

src/olympia/versions/views.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
import os
22

33
from django import http
4+
from django.conf import settings
45
from django.db.transaction import non_atomic_requests
56
from django.shortcuts import get_object_or_404, redirect
67
from django.template.response import TemplateResponse
78
from django.urls import reverse
89
from django.utils.cache import patch_cache_control, patch_vary_headers
10+
from django.utils.crypto import constant_time_compare
11+
12+
import waffle
913

1014
import olympia.core.logger
1115
from olympia import amo
@@ -218,6 +222,18 @@ def download_source(request, version_id):
218222
allow_addons_edit_permission=False,
219223
allow_developer=True,
220224
)
225+
226+
# Source code can also be downloaded using an API key when the source
227+
# builder feature is enabled.
228+
api_key = request.headers.get('x-api-key')
229+
if waffle.switch_is_active('enable-source-builder') and api_key:
230+
has_permission = constant_time_compare(api_key, settings.SOURCE_BUILDER_API_KEY)
231+
if has_permission:
232+
log.info(
233+
'Source code for Version %s was accessed via SOURCE_BUILDER_API_KEY',
234+
version.id,
235+
)
236+
221237
if not (has_permission and getattr(version, 'source', None)):
222238
raise http.Http404()
223239

0 commit comments

Comments
 (0)