From ec7c7b3701315955c74202c3f78ca33a330aa80e Mon Sep 17 00:00:00 2001
From: Jennifer Richards <jennifer@painless-security.com>
Date: Mon, 23 Jan 2023 15:29:45 -0400
Subject: [PATCH 1/9] chore: Upgrade to bleach v6 (#5021)

* build: Bump bleach requirement to 6.0.0

* fix: Update bleach configuration for compatibility with v6 changes
---
 ietf/utils/text.py | 8 ++++----
 requirements.txt   | 2 +-
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/ietf/utils/text.py b/ietf/utils/text.py
index d5463c9f4..48f5538cb 100644
--- a/ietf/utils/text.py
+++ b/ietf/utils/text.py
@@ -20,11 +20,11 @@ import debug                            # pyflakes:ignore
 from .texescape import init as texescape_init, tex_escape_map
 
 tlds_sorted = sorted(tlds.tld_set, key=len, reverse=True)
-protocols = copy.copy(bleach.sanitizer.ALLOWED_PROTOCOLS)
-protocols.append("ftp")  # we still have some ftp links
-protocols.append("xmpp")  # we still have some xmpp links
+protocols = set(bleach.sanitizer.ALLOWED_PROTOCOLS)
+protocols.add("ftp")  # we still have some ftp links
+protocols.add("xmpp")  # we still have some xmpp links
 
-tags = set(copy.copy(bleach.sanitizer.ALLOWED_TAGS)).union(
+tags = set(bleach.sanitizer.ALLOWED_TAGS).union(
     {
         # fmt: off
         'a', 'abbr', 'acronym', 'address', 'b', 'big',
diff --git a/requirements.txt b/requirements.txt
index a0e7953d1..7a5662ffa 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -4,7 +4,7 @@ setuptools>=51.1.0    # Require this first, to prevent later errors
 argon2-cffi>=21.3.0    # For the Argon2 password hasher option
 beautifulsoup4>=4.11.1    # Only used in tests
 bibtexparser>=1.2.0    # Only used in tests
-bleach>=5.0.0
+bleach>=6
 celery>=5.2.6
 coverage>=4.5.4,<5.0    # Coverage 5.x moves from a json database to SQLite.  Moving to 5.x will require substantial rewrites in ietf.utils.test_runner and ietf.release.views
 decorator>=5.1.1

From 43c7e92d9d3550927097e4a5340d14853a13b5c9 Mon Sep 17 00:00:00 2001
From: Robert Sparks <rjsparks@nostrum.com>
Date: Mon, 23 Jan 2023 18:03:19 -0600
Subject: [PATCH 2/9] feat: remove the format element from the bibxml-id source
 of truth (#5017)

---
 ietf/templates/doc/bibxml.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ietf/templates/doc/bibxml.xml b/ietf/templates/doc/bibxml.xml
index d9d534bf3..a7513df47 100644
--- a/ietf/templates/doc/bibxml.xml
+++ b/ietf/templates/doc/bibxml.xml
@@ -13,5 +13,5 @@
    </front>
    <seriesInfo name="Internet-Draft" value="{{name}}-{{doc.rev}}" />
    {% if doi %}<seriesInfo name="DOI" value="{{doi}}" />
-   {% endif %}<format type="TXT" target="https://www.ietf.org/archive/id/{{name}}-{{doc.rev}}.txt" />
+   {% endif %}
 </reference>

From c35afca5073eabe16c0d451cd6122c88e5b3ea14 Mon Sep 17 00:00:00 2001
From: Jennifer Richards <jennifer@painless-security.com>
Date: Mon, 23 Jan 2023 20:05:53 -0400
Subject: [PATCH 3/9] test: Use DEADLINE_TZINFO to validate reminder due date
 calculation (#5019)

---
 ietf/doc/tests_draft.py | 16 +++++++++++-----
 1 file changed, 11 insertions(+), 5 deletions(-)

diff --git a/ietf/doc/tests_draft.py b/ietf/doc/tests_draft.py
index c038b27b2..dda6453de 100644
--- a/ietf/doc/tests_draft.py
+++ b/ietf/doc/tests_draft.py
@@ -34,7 +34,7 @@ from ietf.iesg.models import TelechatDate
 from ietf.utils.test_utils import login_testing_unauthorized
 from ietf.utils.mail import outbox, empty_outbox, get_payload_text
 from ietf.utils.test_utils import TestCase
-from ietf.utils.timezone import date_today, datetime_from_date
+from ietf.utils.timezone import date_today, datetime_from_date, DEADLINE_TZINFO
 
 
 class ChangeStateTests(TestCase):
@@ -1749,8 +1749,11 @@ class ChangeStreamStateTests(TestCase):
         self.assertEqual(draft.docevent_set.count() - events_before, 2)
         reminder = DocReminder.objects.filter(event__doc=draft, type="stream-s")
         self.assertEqual(len(reminder), 1)
-        due = timezone.now() + datetime.timedelta(weeks=10)
-        self.assertTrue(due - datetime.timedelta(days=1) <= reminder[0].due <= due + datetime.timedelta(days=1))
+        due = timezone.now().astimezone(DEADLINE_TZINFO) + datetime.timedelta(weeks=10)
+        self.assertTrue(
+            due - datetime.timedelta(days=1) <= reminder[0].due <= due + datetime.timedelta(days=1),
+            f'Due date {reminder[0].due} should be {due} +/- 1 day'
+        )
         self.assertEqual(len(outbox), 1)
         self.assertTrue("state changed" in outbox[0]["Subject"].lower())
         self.assertTrue("mars-chairs@ietf.org" in outbox[0].as_string())
@@ -1794,8 +1797,11 @@ class ChangeStreamStateTests(TestCase):
         self.assertEqual(draft.docevent_set.count() - events_before, 2)
         reminder = DocReminder.objects.filter(event__doc=draft, type="stream-s")
         self.assertEqual(len(reminder), 1)
-        due = timezone.now() + datetime.timedelta(weeks=10)
-        self.assertTrue(due - datetime.timedelta(days=1) <= reminder[0].due <= due + datetime.timedelta(days=1))
+        due = timezone.now().astimezone(DEADLINE_TZINFO) + datetime.timedelta(weeks=10)
+        self.assertTrue(
+            due - datetime.timedelta(days=1) <= reminder[0].due <= due + datetime.timedelta(days=1),
+            f'Due date {reminder[0].due} should be {due} +/- 1 day'
+        )
         self.assertEqual(len(outbox), 1)
         self.assertTrue("state changed" in outbox[0]["Subject"].lower())
         self.assertTrue("mars-chairs@ietf.org" in outbox[0].as_string())

From db3506e8c7a143eee4b7543ae20d094e1f50cc03 Mon Sep 17 00:00:00 2001
From: Jennifer Richards <jennifer@painless-security.com>
Date: Mon, 23 Jan 2023 20:06:51 -0400
Subject: [PATCH 4/9] fix: Use settings.TIME_ZONE when looking up telechat
 agenda_date() (#5020)

---
 ietf/iesg/agenda.py | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/ietf/iesg/agenda.py b/ietf/iesg/agenda.py
index 113c3c5d1..b4ac47abf 100644
--- a/ietf/iesg/agenda.py
+++ b/ietf/iesg/agenda.py
@@ -17,7 +17,7 @@ from ietf.doc.models import Document, LastCallDocEvent, ConsensusDocEvent
 from ietf.doc.utils_search import fill_in_telechat_date
 from ietf.iesg.models import TelechatDate, TelechatAgendaItem
 from ietf.review.utils import review_assignments_to_list_for_docs
-from ietf.utils.timezone import date_today
+from ietf.utils.timezone import date_today, make_aware
 
 def get_agenda_date(date=None):
     if not date:
@@ -26,8 +26,9 @@ def get_agenda_date(date=None):
         except IndexError:
             return date_today()
     else:
+        parsed_date = make_aware(datetime.datetime.strptime(date, "%Y-%m-%d"), settings.TIME_ZONE).date()
         try:
-            return TelechatDate.objects.active().get(date=datetime.datetime.strptime(date, "%Y-%m-%d").date()).date
+            return TelechatDate.objects.active().get(date=parsed_date).date
         except (ValueError, TelechatDate.DoesNotExist):
             raise Http404
 

From 61f7984d5c3b98de4d57113c14255eaef9180b7f Mon Sep 17 00:00:00 2001
From: Lars Eggert <lars@eggert.org>
Date: Tue, 24 Jan 2023 17:02:21 +0200
Subject: [PATCH 5/9] fix: Handle unset cookies correctly (#5023)

Fixes #5015
---
 ietf/static/js/document_html.js       | 10 +++++++++-
 ietf/templates/doc/document_html.html |  2 +-
 2 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/ietf/static/js/document_html.js b/ietf/static/js/document_html.js
index 9da32a0a7..53ca6bf54 100644
--- a/ietf/static/js/document_html.js
+++ b/ietf/static/js/document_html.js
@@ -49,13 +49,21 @@ document.addEventListener("DOMContentLoaded", function (event) {
 
     // activate pref buttons selected by pref cookies or localStorage
     const in_localStorage = ["deftab", "reflinks"];
+    const btn_pref = {
+        "sidebar": "on",
+        "deftab": "docinfo",
+        "htmlconf": "html",
+        "pagedeps": "reference",
+        "reflinks": "refsection"
+    };
     document.querySelectorAll("#pref-tab-pane .btn-check")
         .forEach(btn => {
             const id = btn.id.replace("-radio", "");
 
             const val = in_localStorage.includes(btn.name) ?
                 localStorage.getItem(btn.name) : cookies.get(btn.name);
-            if (val == id) {
+            if (val == id || ((val == undefined || val == null) &&
+                    btn_pref[btn.name] == id)) {
                 btn.checked = true;
             }
 
diff --git a/ietf/templates/doc/document_html.html b/ietf/templates/doc/document_html.html
index 1edeec944..84a921532 100644
--- a/ietf/templates/doc/document_html.html
+++ b/ietf/templates/doc/document_html.html
@@ -167,7 +167,7 @@
                                 </span>
 
                         </p>
-                        {% if request.COOKIES.htmlconf != 'html' and html %}
+                        {% if request.COOKIES.htmlconf and request.COOKIES.htmlconf != 'html' and html %}
                         <div class="alert alert-info small">
                             You are viewing the legacy <code><a class="text-decoration-none text-reset" href="https://github.com/ietf-tools/rfc2html">rfc2html</a></code>
                             rendering of this document. Change the

From 040af97c114adc9426a3db427aff31c3fa38c464 Mon Sep 17 00:00:00 2001
From: Jennifer Richards <jennifer@painless-security.com>
Date: Wed, 25 Jan 2023 17:09:13 -0400
Subject: [PATCH 6/9] refactor: Simplify tests and comply with StandardJS style
 (#5026)

* refactor: Simplify tests and comply with StandardJS style

Use === instead of ==, except where it's used to match both null and
undefined.

* style: further tweaks
---
 ietf/static/js/document_html.js | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/ietf/static/js/document_html.js b/ietf/static/js/document_html.js
index 53ca6bf54..7de6660c2 100644
--- a/ietf/static/js/document_html.js
+++ b/ietf/static/js/document_html.js
@@ -62,8 +62,7 @@ document.addEventListener("DOMContentLoaded", function (event) {
 
             const val = in_localStorage.includes(btn.name) ?
                 localStorage.getItem(btn.name) : cookies.get(btn.name);
-            if (val == id || ((val == undefined || val == null) &&
-                    btn_pref[btn.name] == id)) {
+            if (val === id || (val === null && btn_pref[btn.name] === id)) {
                 btn.checked = true;
             }
 

From 742fc4ead2cf3019e84873730f6c2c46a93dc432 Mon Sep 17 00:00:00 2001
From: Robert Sparks <rjsparks@nostrum.com>
Date: Wed, 25 Jan 2023 15:09:55 -0600
Subject: [PATCH 7/9] feat: show session purposes on the meeting request page
 (#5034)

---
 ietf/templates/meeting/requests.html | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/ietf/templates/meeting/requests.html b/ietf/templates/meeting/requests.html
index a80b083c1..b88efa892 100644
--- a/ietf/templates/meeting/requests.html
+++ b/ietf/templates/meeting/requests.html
@@ -36,6 +36,7 @@
                     <th scope="col" data-sort="group">Group</th>
                     <th scope="col" class="d-none d-lg-table-cell" data-sort="count">Length</th>
                     <th scope="col" class="d-none d-lg-table-cell" data-sort="num">Size</th>
+                    <th scope="col" class="d-none d-lg-table-cell" data-sort="num">Purpose</th>
                     <th scope="col" class="d-none d-lg-table-cell" data-sort="requester">Requester</th>
                     <th scope="col" class="d-none d-lg-table-cell" data-sort="ad">AD</th>
                     <th scope="col" data-sort="constraints">Constraints</th>
@@ -76,6 +77,7 @@
                             {% if session.requested_duration %}{{ session.requested_duration|stringformat:"s"|slice:"0:4" }}{% endif %}
                         </td>
                         <td class="d-none d-lg-table-cell">{{ session.attendees|default:"" }}</td>
+                        <td class="d-none d-lg-table-cell">{% if session.purpose_id != "regular" %}{{session.purpose}}{% endif %}</td>
                         <td class="d-none d-lg-table-cell">{% person_link session.requested_by_person with_email=False %}</td>
                         <td class="d-none d-lg-table-cell">
                             {% if session.group.ad_role %}

From 5560c28c825ea6c570d44f30002b04c22ac11bac Mon Sep 17 00:00:00 2001
From: Robert Sparks <rjsparks@nostrum.com>
Date: Wed, 25 Jan 2023 15:10:31 -0600
Subject: [PATCH 8/9] fix: only show irtf stream ballot and publication buttons
 to the IRTF chair (#5036)

---
 ietf/doc/views_doc.py   | 8 ++++----
 ietf/doc/views_draft.py | 5 ++++-
 2 files changed, 8 insertions(+), 5 deletions(-)

diff --git a/ietf/doc/views_doc.py b/ietf/doc/views_doc.py
index 3b7ccb4f2..29d0f0f03 100644
--- a/ietf/doc/views_doc.py
+++ b/ietf/doc/views_doc.py
@@ -390,22 +390,22 @@ def document_main(request, name, rev=None, document_html=False):
         if doc.get_state_slug() == "expired" and has_role(request.user, ("Secretariat",)) and not snapshot:
             actions.append(("Resurrect", urlreverse('ietf.doc.views_draft.resurrect', kwargs=dict(name=doc.name))))
         
-        if (doc.get_state_slug() not in ["rfc", "expired"] and doc.stream_id in ("irtf",) and not snapshot and not doc.ballot_open('irsg-approve') and can_edit_stream_info):
+        if (doc.get_state_slug() not in ["rfc", "expired"] and doc.stream_id in ("irtf",) and not snapshot and not doc.ballot_open('irsg-approve') and has_role(request.user, ("Secretariat", "IRTF Chair"))):
             label = "Issue IRSG Ballot"
             actions.append((label, urlreverse('ietf.doc.views_ballot.issue_irsg_ballot', kwargs=dict(name=doc.name))))
-        if (doc.get_state_slug() not in ["rfc", "expired"] and doc.stream_id in ("irtf",) and not snapshot and doc.ballot_open('irsg-approve') and can_edit_stream_info):
+        if (doc.get_state_slug() not in ["rfc", "expired"] and doc.stream_id in ("irtf",) and not snapshot and doc.ballot_open('irsg-approve') and has_role(request.user, ("Secretariat", "IRTF Chair"))):
             label = "Close IRSG Ballot"
             actions.append((label, urlreverse('ietf.doc.views_ballot.close_irsg_ballot', kwargs=dict(name=doc.name))))
 
         if (doc.get_state_slug() not in ["rfc", "expired"] and doc.stream_id in ("ise", "irtf")
-            and can_edit_stream_info and not conflict_reviews and not snapshot):
+            and has_role(request.user, ("Secretariat", "IRTF Chair")) and not conflict_reviews and not snapshot):
             label = "Begin IETF Conflict Review"
             if not doc.intended_std_level:
                 label += " (note that intended status is not set)"
             actions.append((label, urlreverse('ietf.doc.views_conflict_review.start_review', kwargs=dict(name=doc.name))))
 
         if (doc.get_state_slug() not in ["rfc", "expired"] and doc.stream_id in ("iab", "ise", "irtf")
-            and can_edit_stream_info and not snapshot):
+            and (has_role(request.user, ("Secretariat", "IRTF Chair")) if doc.stream_id=="irtf" else can_edit_stream_info) and not snapshot):
             if doc.get_state_slug('draft-stream-%s' % doc.stream_id) not in ('rfc-edit', 'pub', 'dead'):
                 label = "Request Publication"
                 if not doc.intended_std_level:
diff --git a/ietf/doc/views_draft.py b/ietf/doc/views_draft.py
index 63cdbe9ea..f22ad3548 100644
--- a/ietf/doc/views_draft.py
+++ b/ietf/doc/views_draft.py
@@ -1292,7 +1292,10 @@ def request_publication(request, name):
 
     doc = get_object_or_404(Document, type="draft", name=name, stream__in=("iab", "ise", "irtf"))
 
-    if not is_authorized_in_doc_stream(request.user, doc):
+    if doc.stream_id == "irtf":
+        if not has_role(request.user, ("Secretariat", "IRTF Chair")):
+            permission_denied(request, "You do not have the necessary permissions to view this page.")
+    elif not is_authorized_in_doc_stream(request.user, doc):
         permission_denied(request, "You do not have the necessary permissions to view this page.")
 
     consensus_event = doc.latest_event(ConsensusDocEvent, type="changed_consensus")

From e7c206399252b51c07b3fc4b08ea23bac61e102b Mon Sep 17 00:00:00 2001
From: Nicolas Giard <github@ngpixel.com>
Date: Wed, 25 Jan 2023 22:44:27 -0500
Subject: [PATCH 9/9] ci: disable buildx provenance on dev db nightly builds

---
 .github/workflows/dev-db-nightly.yml | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/.github/workflows/dev-db-nightly.yml b/.github/workflows/dev-db-nightly.yml
index 128780544..9a2284d4d 100644
--- a/.github/workflows/dev-db-nightly.yml
+++ b/.github/workflows/dev-db-nightly.yml
@@ -63,6 +63,7 @@ jobs:
           platforms: ${{ matrix.platform }}
           push: true
           tags: ghcr.io/ietf-tools/datatracker-db:latest-${{ matrix.docker }}
+          provenance: false
           
   combine-mariadb:
     name: Create MariaDB Docker Manifests
@@ -184,3 +185,4 @@ jobs:
         platforms: linux/amd64,linux/arm64
         push: true
         tags: ghcr.io/ietf-tools/datatracker-db-pg:latest,ghcr.io/ietf-tools/datatracker-db-pg:nightly-${{ steps.date.outputs.date }}
+        provenance: false