From patchwork Sun Oct 25 02:06:45 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tim Orling X-Patchwork-Id: 101901 Received: from mail-pj1-f50.google.com (mail-pj1-f50.google.com [209.85.216.50]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.16903.1792894013208805750 for ; Sat, 24 Oct 2026 19:06:53 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@gmail.com header.s=20251104 header.b=M7+OjRer; spf=pass (domain: gmail.com, ip: 209.85.216.50, mailfrom: ticotimo@gmail.com) Received: by mail-pj1-f50.google.com with SMTP id 98e67ed59e1d1-3a4b3ac8fb7so1031610a91.0 for ; Sat, 24 Oct 2026 19:06:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1792894012; x=1793498812; darn=lists.yoctoproject.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to:content-type; bh=hceSCJt5QvGMleZ6GAdqYk3zJeGbMsTNnmPle+tplQQ=; b=M7+OjRer1nv8dAVnBS52WQdhupOoF/BvU68cSMIec3B/NrIqSFurHHQMYtHWS8Wvkw IP4agpFgSCiD0v4TBIZXgv4EBm0NssB8kOTpLAh6S0byjEz3Rq6/UQNmi301vAFTXStn p4u6uGfl9fobIqmoF2GjT7vJ2brjK15GBaNGeVib91FzGRzeXfyVeg3sDpFaIoyi7jrC /iFts13BHs9rgGeoARmZ7Go0g7lGL89TZlMFP85be4UPR8klWx7CqlDIp5uaGyDNRtem fRSJ0G0xlIbml65YCw+C4sjUU+boO/VTdjiOifKbWnETPmOIwX+VMWFq9YAIn6tqxcsU U5dg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1792894012; x=1793498812; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=hceSCJt5QvGMleZ6GAdqYk3zJeGbMsTNnmPle+tplQQ=; b=wLEJcCC6e3+oU3E4B0x9DEHGXEjMUigGkBZtigKTdOndhR60iPJyTaDJhW18C+YexE yRU5+J3DqseoqfRCjdbbmG+WysW56Qeh3nl/et6wBUP3vdeXvta0SZMNQG59QGHlz+kE 29lxSxdzSba47LkyphWMPPE8s0HIHjAK3ILiQRLBCVvXRNB1c0AdX05mZUpCZXem4kcT YCgz2zaAvE7lL2zFtaPIVv8XDBevDY38sU+xaSgKavcZnWrkftZqkGTkonLOVFYHSVIo YvwtfBHG9roWVKrrUv31muO0tYSglAFGBM3sqeWyy9BRIrnEua7sqv7ynFlWcWob11Be YsrA== X-Gm-Message-State: AFq9FYKjQGaVebde8TyNr6hE2F6xt/m5i+eT8XgER3vM7hjbaVZlKEp+ 2xrULspDKq4T5L9TUeU57eEu8bekJLiLSmTuXh1L+8DGWi/873NQU8P2g6JGoL7g X-Gm-Gg: AYBFou37Zc3ed/X4qU9bkC83vJA9jlniu9Ov1akA4vkokTSpFwfpdiUa7vkjmPkGN/f tAjCKhDiOnIkRaeN3nflNBMa8GefX8D5Kdzsrr8NDLTGafuyHlm9bfm9TQYP+AwethtZ4uog0Ci cZtr4EWDBJKf/dx6La+h6wi29i0rSCYtx5MArs36O3EpBEidHtOomN7cymCXKyG/JFUv4okv7C3 SeZzGoSfYl6CEXeOYy1kCzCZnhNthIDuRmi/mGbPdMXMl2X5fD1/yAcf1dmR2rA8FZ072IWdJ38 AoQ2mkar/bl/66eROIU09bSwbtnCM8rcdS8KyzUGEr7Ub523fxZ2MCba8BpM8e0nf31FgdCzZzN NOB5nVnLOKDoET2wqgEgK83uhw+20zROHfIjBIo1nFCZ5KUpuofIXw8mRLotOPtZRYpoMp0vavl UODkgNANMROKYpk2zDstg+8Va/b5j/z0iF2zwCeYhqvLisdDUpX2suPslW1OuQbZ5UGcNU2hNhn kD3mhL6h26n/qeoXAZUNyLmd8hzWdvMFc274CGaxjB1/j8H3RqutnQxS6IA9Ahd1PV2nxKpWGUL 9Oq6VJ1nvuEu X-Received: by 2002:a17:90b:4985:b0:3ab:413:49b6 with SMTP id 98e67ed59e1d1-3adeae6d3c3mr2718095a91.41.1792894012225; Sat, 24 Oct 2026 19:06:52 -0700 (PDT) Return-Path: Received: from localhost.localdomain ([69.9.132.159]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-3adebb0718esm3966914a91.11.2026.10.24.19.06.49 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Sat, 24 Oct 2026 19:06:51 -0700 (PDT) From: Tim Orling X-Google-Original-From: Tim Orling To: yocto-patches@lists.yoctoproject.org Cc: Tim Orling Subject: [layerindex-web][PATCH 1/2] dockersetup: trust the site's own origin for CSRF Date: Sat, 24 Oct 2026 19:06:45 -0700 Message-ID: <20261025020646.89376-1-tim.orling@konsulko.com> X-Mailer: git-send-email 2.56.0 MIME-Version: 1.0 List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by lin-tor-korg-lkml-alma10-1 with HTTPS for ; Sun, 25 Oct 2026 02:07:03 -0000 X-Groupsio-URL: https://lists.yoctoproject.org/g/yocto-patches/message/5149 A default dockersetup.py install serves the site on https://localhost:8081, but CSRF_TRUSTED_ORIGINS only allowed https://localhost, so logging in failed with "Origin checking failed" (403). Let CSRF_TRUSTED_ORIGINS be set from the environment, and have dockersetup.py write the URL the site is served on, including any non-standard port, to .env.local.app. [YOCTO #15329] AI-Generated: Claude Opus 5.5 Signed-off-by: Tim Orling --- .env.dev.app | 1 + docker/settings.py | 4 +++- dockersetup.py | 30 ++++++++++++++++-------------- tests/test_dockersetup.py | 19 +++++++++++++++++++ 4 files changed, 39 insertions(+), 15 deletions(-) diff --git a/.env.dev.app b/.env.dev.app index 9f8fb5a..a268cdc 100644 --- a/.env.dev.app +++ b/.env.dev.app @@ -11,4 +11,5 @@ RABBITMQ_DEFAULT_PASS=guest #EMAIL_PASSWORD= #EMAIL_USE_SSL= #EMAIL_USE_TLS= +#CSRF_TRUSTED_ORIGINS= DEBUG=1 diff --git a/docker/settings.py b/docker/settings.py index e18a9c2..a610052 100644 --- a/docker/settings.py +++ b/docker/settings.py @@ -314,7 +314,9 @@ TOOLS_LOG_DIR = "" USE_X_FORWARDED_HOST = True ALLOWED_HOSTS = [os.getenv('HOSTNAME', 'layers.test')] -CSRF_TRUSTED_ORIGINS = ['https://' + os.getenv('HOSTNAME', 'layers.test')] +# Comma-separated; set it when the site is not served on https://HOSTNAME, +# e.g. on a non-standard port +CSRF_TRUSTED_ORIGINS = (os.getenv('CSRF_TRUSTED_ORIGINS') or 'https://' + os.getenv('HOSTNAME', 'layers.test')).split(',') SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') SECURE_BROWSER_XSS_FILTER = True SECURE_CONTENT_TYPE_NOSNIFF = True diff --git a/dockersetup.py b/dockersetup.py index eb02f33..406bdf9 100755 --- a/dockersetup.py +++ b/dockersetup.py @@ -582,7 +582,7 @@ def write_env_file(app_dir): # Write the generated secrets and email settings to .env.local., # starting from the tracked .env.dev. defaults. These files hold # secrets and are ignored by git. -def write_service_env_files(dbpassword, dbapassword, secretkey, rmqpassword, email_host, email_port, email_user, email_password, email_ssl, email_tls): +def write_service_env_files(dbpassword, dbapassword, secretkey, rmqpassword, email_host, email_port, email_user, email_password, email_ssl, email_tls, site_origin=None): values = { 'SECRET_KEY': secretkey, 'DATABASE_USER': 'layers', @@ -596,6 +596,7 @@ def write_service_env_files(dbpassword, dbapassword, secretkey, rmqpassword, ema 'EMAIL_PASSWORD': email_password, 'EMAIL_USE_SSL': str(email_ssl) if email_ssl else None, 'EMAIL_USE_TLS': str(email_tls) if email_tls else None, + 'CSRF_TRUSTED_ORIGINS': site_origin, 'DEBUG': '0', } for service in ('app', 'celery', 'db', 'rabbit'): @@ -613,6 +614,17 @@ def write_service_env_files(dbpassword, dbapassword, secretkey, rmqpassword, ema f.write(''.join(newlines)) +# Return the protocol and host[:port] that the site is served on +def site_protocol_host(hostname, http_port, https_port, no_https): + if https_port and not no_https: + protocol, port, defport = 'https', https_port, '443' + else: + protocol, port, defport = 'http', http_port, '80' + if port == defport: + return protocol, hostname + return protocol, '%s:%s' % (hostname, port) + + def check_connectivity(app_dir='/opt'): return_code = subprocess.call(compose('run', '--rm', 'layersapp', app_dir + '/connectivity_check.sh'), shell=False) if return_code != 0: @@ -813,7 +825,8 @@ provide information as needed. edit_dockerfile(args.http_proxy, args.https_proxy, args.no_proxy) write_env_file(args.app_dir) - write_service_env_files(dbpassword, dbapassword, secretkey, rmqpassword, email_host, email_port, args.email_user, args.email_password, args.email_ssl, args.email_tls) + protocol, host = site_protocol_host(args.hostname, http_port, https_port, args.no_https) + write_service_env_files(dbpassword, dbapassword, secretkey, rmqpassword, email_host, email_port, args.email_user, args.email_password, args.email_ssl, args.email_tls, '%s://%s' % (protocol, host)) edit_dockercompose(args.hostname, args.portmapping, args.letsencrypt, args.app_dir) edit_dockerfile_web(args.hostname, args.no_https) @@ -940,18 +953,7 @@ provide information as needed. print("Collecting static files failed") sys.exit(1) - if https_port and not args.no_https: - protocol = 'https' - port = https_port - defport = '443' - else: - protocol = 'http' - port = http_port - defport = '80' - if port == defport: - host = args.hostname - else: - host = '%s:%s' % (args.hostname, port) + protocol, host = site_protocol_host(args.hostname, http_port, https_port, args.no_https) if not args.update: if not args.databasefile: diff --git a/tests/test_dockersetup.py b/tests/test_dockersetup.py index 7958946..0109c80 100644 --- a/tests/test_dockersetup.py +++ b/tests/test_dockersetup.py @@ -77,10 +77,29 @@ def test_env_files_are_private_and_leave_unset_email_commented(workdir): app = read_env(workdir / '.env.local.app') assert 'EMAIL_HOST' not in app assert 'EMAIL_USE_TLS' not in app + assert 'CSRF_TRUSTED_ORIGINS' not in app # The tracked defaults are left alone assert read_env(workdir / '.env.dev.db')['MYSQL_ROOT_PASSWORD'] == 'testingpw' +def test_env_files_get_site_origin(workdir): + # The default port 8081 is not the standard https port, so the browser + # sends it in the Origin header and Django's CSRF check must allow it + dockersetup.write_service_env_files('dbpw', 'rootpw', 'sekrit', 'mqpw', None, None, + None, None, False, False, 'https://localhost:8081') + assert read_env(workdir / '.env.local.app')['CSRF_TRUSTED_ORIGINS'] == 'https://localhost:8081' + + +@pytest.mark.parametrize('http_port, https_port, no_https, expected', [ + ('8080', '8081', False, ('https', 'localhost:8081')), + ('80', '443', False, ('https', 'localhost')), + ('8080', None, True, ('http', 'localhost:8080')), + ('80', '8081', True, ('http', 'localhost')), +]) +def test_site_protocol_host(http_port, https_port, no_https, expected): + assert dockersetup.site_protocol_host('localhost', http_port, https_port, no_https) == expected + + def load_compose(workdir): return yaml.safe_load((workdir / 'docker-compose.yml').read_text()) From patchwork Sun Oct 25 02:06:46 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tim Orling X-Patchwork-Id: 101900 Received: from mail-pj1-f44.google.com (mail-pj1-f44.google.com [209.85.216.44]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.16905.1792894016958512482 for ; Sat, 24 Oct 2026 19:06:57 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@gmail.com header.s=20251104 header.b=AK7f1NiZ; spf=pass (domain: gmail.com, ip: 209.85.216.44, mailfrom: ticotimo@gmail.com) Received: by mail-pj1-f44.google.com with SMTP id 98e67ed59e1d1-398a4dcf289so1058791a91.2 for ; Sat, 24 Oct 2026 19:06:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1792894016; x=1793498816; darn=lists.yoctoproject.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=0fTWnuvX0BR5ApweuBk7769Co0yLukKOXak7JH2wXD8=; b=AK7f1NiZpDmE/NK8z3eRBvTKPGlpdfXbv4voMSC6gUO4nE/HovoRIiYGl4yjtHhx7/ g61jAYxR5xlIBaWfKaZTDdEpaK6t9zEJi94A+W8hT/AU8jyIgxvRg+QoboaZ40a7FC/V HFacLozKled+MV70hQPGcLzcZ9ToW8NB6jpOLZjbWepVJWwcnzIueWfu3ccylp4OTDJc ka0rxXNnWKjmCbRoSXKEfO8mPErmWxFbiIKZh2ArsKCm5oukh7D+jKBfrLeOUfBcVCNN Qgv9IPz/0yJyjsrdQQ2jGji6DNig0kA0kL3CApfcMtXp1aNaAL6f35GIWuInFaT7rZun xzkw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1792894016; x=1793498816; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=0fTWnuvX0BR5ApweuBk7769Co0yLukKOXak7JH2wXD8=; b=OzD2RWdnckp0Uy6twhWfUKMYbYgngwsSAf54ZfYQHUvYpV1lqASm5pJyljcsvtfLyZ 9KHADfZqtXJIgFTb9DyqjplkaleZu/ReDTfCxco48iZtMGoT4eFs5W2gwBEOZFAVMR4V oM/vyC62Aqf5VAf34yAmMI3wleDdvDVUQmhH8bdeup872tLusptJmFrqj0Q1zR4JiVYb KoHMwLHo+GzkZEaJN493B9mBq6Nk8/FKiA7LetlsfNlF1+sB75OZ8NohlxzbHWBsXGb1 vrL0scrjLXaFIg/XFsXM26XXEJ3TnOu72b0dQES+XEnpeu28Hvq/QxCLwwPEcAKFY2fH g0VQ== X-Gm-Message-State: AFq9FYJFGWl5YsmjnqucxnKgFFEkcxkvKGBRywrV0cW01mzNU5ddUiar zAK/GbtQGZBAwpsR8aaGMHLTdXpG1TY0JqE8xcIKK25X5uMhnUKlX4Ga1dGlfw== X-Gm-Gg: AYBFou0E8Hbq59n5FMv8VBM7T+gtmjlj6IkGG3sYpGn9+KsbnCRNK2SLO+7C1jHEEM6 vpu+oclglNcAIzQ74omcqdP5FrODbSBwJWZPjX1OPSn7E9WbmkvJKv3dw8BrWZJmIVLtbEmrYb6 bZ/yL2pQIOoK0ExNIypRrJaecHm/TB8JVgKCA1iImdKEYc3RHouE0HFH8IMkz3lKT8XnxckTVgl 1K37h8muqXHYy8Y2UcemUU+gAYY4c3RHdAjC11OnMNAU6q+drXU0Rp0WUFaeNiit9ALYqUu82ID YiaLGitLumUo+GBoozeSrkPCHviEg2Hb3uK8xXs4f4oAh9FH6Rf0+CxmjDjQQ+8S9+o4ZHMT5+P IuQNrxiFmli5CFyMIujtF6qmpw/VOZDp/npZZujeaXvhQZxQRmJqehtyeylr5h0mU2jBFEuGQGQ HPAMrkNCeCFiauIhDFyxNrOKLqzoLk1lKtmMEzkxDZQ31TpbZVYN5PBVPeKChoiVOaDsNDT0m/T T3ysbqg3C6WpbOp/RH5wJtkSrwghs5278f4SHGu01zJJyrxdFt6b1+McgaDz4s6rnW+kM6X+r34 Ip2rhhe2lI+e X-Received: by 2002:a17:90b:224b:b0:3ac:d19e:85f1 with SMTP id 98e67ed59e1d1-3adeafd6bc7mr2581579a91.53.1792894016212; Sat, 24 Oct 2026 19:06:56 -0700 (PDT) Return-Path: Received: from localhost.localdomain ([69.9.132.159]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-3adebb0718esm3966914a91.11.2026.10.24.19.06.53 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Sat, 24 Oct 2026 19:06:55 -0700 (PDT) From: Tim Orling X-Google-Original-From: Tim Orling To: yocto-patches@lists.yoctoproject.org Cc: Tim Orling Subject: [layerindex-web][PATCH 2/2] templates: link to Bugzilla for reporting bugs Date: Sat, 24 Oct 2026 19:06:46 -0700 Message-ID: <20261025020646.89376-2-tim.orling@konsulko.com> X-Mailer: git-send-email 2.56.0 In-Reply-To: <20261025020646.89376-1-tim.orling@konsulko.com> References: <20261025020646.89376-1-tim.orling@konsulko.com> MIME-Version: 1.0 List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by lin-tor-korg-lkml-alma10-1 with HTTPS for ; Sun, 25 Oct 2026 02:07:03 -0000 X-Groupsio-URL: https://lists.yoctoproject.org/g/yocto-patches/message/5150 The site gave no hint of where to report problems with it. Add a "report a bug" link to the footer and a line on the About page, both pointing to the Layer Index product in the Yocto Project Bugzilla. [YOCTO #15039] AI-Generated: Claude Opus 5.5 Signed-off-by: Tim Orling --- templates/base.html | 1 + templates/layerindex/about.html | 2 ++ tests/test_bug_report_link.py | 23 +++++++++++++++++++++++ 3 files changed, 26 insertions(+) create mode 100644 tests/test_bug_report_link.py diff --git a/templates/base.html b/templates/base.html index e31238c..acf0a9f 100644 --- a/templates/base.html +++ b/templates/base.html @@ -130,6 +130,7 @@ change history • about this site • FAQ + • report a bug {% endblock %} diff --git a/templates/layerindex/about.html b/templates/layerindex/about.html index a2055fb..5acba08 100644 --- a/templates/layerindex/about.html +++ b/templates/layerindex/about.html @@ -57,6 +57,8 @@

The code is Open Source and can be found on git.yoctoproject.org. Patches welcome!

+

If you find a problem with this site, please report it in the Yocto Project Bugzilla under the "Layer Index" product.

+ {% endautoescape %} {% endblock %} diff --git a/tests/test_bug_report_link.py b/tests/test_bug_report_link.py new file mode 100644 index 0000000..d4d1027 --- /dev/null +++ b/tests/test_bug_report_link.py @@ -0,0 +1,23 @@ +# layerindex-web - tests for the bug report link +# +# Licensed under the MIT license, see COPYING.MIT for details +# +# SPDX-License-Identifier: MIT + +import pytest +from django.test import TestCase +from django.urls import reverse + +BUG_URL = 'https://bugzilla.yoctoproject.org/enter_bug.cgi?product=Layer%20Index' + + +@pytest.mark.django_db +class TestBugReportLink(TestCase): + + def test_footer_links_to_bugzilla(self): + response = self.client.get(reverse('history_list')) + self.assertContains(response, 'report a bug' % BUG_URL) + + def test_about_page_links_to_bugzilla(self): + response = self.client.get(reverse('about')) + self.assertContains(response, 'report it' % BUG_URL)