From a9e50573753fcc7fcd86c5baba86588a1de86155 Mon Sep 17 00:00:00 2001
From: Jennifer Richards <jennifer@staff.ietf.org>
Date: Thu, 21 Nov 2024 18:57:58 -0400
Subject: [PATCH 1/4] chore: crlf -> lf (#8255)

---
 .github/workflows/build-base-app.yml | 132 +++++-----
 .github/workflows/tests.yml          | 374 +++++++++++++--------------
 2 files changed, 253 insertions(+), 253 deletions(-)

diff --git a/.github/workflows/build-base-app.yml b/.github/workflows/build-base-app.yml
index 609b641ef..c8f66a22b 100644
--- a/.github/workflows/build-base-app.yml
+++ b/.github/workflows/build-base-app.yml
@@ -1,66 +1,66 @@
-name: Build Base App Docker Image
-
-on:
-  push:
-    branches:
-      - 'main'
-    paths:
-      - 'docker/base.Dockerfile'
-      - 'requirements.txt'
-
-  workflow_dispatch:
-
-jobs:
-  publish:
-    runs-on: ubuntu-latest
-    permissions:
-      contents: write
-      packages: write
-
-    steps:
-    - uses: actions/checkout@v4
-      with:
-        token: ${{ secrets.GH_COMMON_TOKEN }}
-
-    - name: Set Version
-      run: |
-        printf -v CURDATE '%(%Y%m%dT%H%M)T' -1
-        echo "IMGVERSION=$CURDATE" >> $GITHUB_ENV
-
-    - name: Set up QEMU
-      uses: docker/setup-qemu-action@v3
-    
-    - name: Set up Docker Buildx
-      uses: docker/setup-buildx-action@v3
-
-    - name: Login to GitHub Container Registry
-      uses: docker/login-action@v3
-      with:
-        registry: ghcr.io
-        username: ${{ github.actor }}
-        password: ${{ secrets.GITHUB_TOKEN }}
-
-    - name: Docker Build & Push
-      uses: docker/build-push-action@v6
-      env:
-        DOCKER_BUILD_NO_SUMMARY: true
-      with:
-        context: .
-        file: docker/base.Dockerfile
-        platforms: linux/amd64,linux/arm64
-        push: true
-        tags: |
-          ghcr.io/ietf-tools/datatracker-app-base:${{ env.IMGVERSION }}
-          ghcr.io/ietf-tools/datatracker-app-base:latest
-
-    - name: Update version references
-      run: |
-        sed -i "1s/.*/FROM ghcr.io\/ietf-tools\/datatracker-app-base:${{ env.IMGVERSION }}/" dev/build/Dockerfile
-        echo "${{ env.IMGVERSION }}" > dev/build/TARGET_BASE
-
-    - name: Commit CHANGELOG.md
-      uses: stefanzweifel/git-auto-commit-action@v5
-      with:
-        branch: main
-        commit_message: 'ci: update base image target version to ${{ env.IMGVERSION }}'
-        file_pattern: dev/build/Dockerfile dev/build/TARGET_BASE
+name: Build Base App Docker Image
+
+on:
+  push:
+    branches:
+      - 'main'
+    paths:
+      - 'docker/base.Dockerfile'
+      - 'requirements.txt'
+
+  workflow_dispatch:
+
+jobs:
+  publish:
+    runs-on: ubuntu-latest
+    permissions:
+      contents: write
+      packages: write
+
+    steps:
+    - uses: actions/checkout@v4
+      with:
+        token: ${{ secrets.GH_COMMON_TOKEN }}
+
+    - name: Set Version
+      run: |
+        printf -v CURDATE '%(%Y%m%dT%H%M)T' -1
+        echo "IMGVERSION=$CURDATE" >> $GITHUB_ENV
+
+    - name: Set up QEMU
+      uses: docker/setup-qemu-action@v3
+    
+    - name: Set up Docker Buildx
+      uses: docker/setup-buildx-action@v3
+
+    - name: Login to GitHub Container Registry
+      uses: docker/login-action@v3
+      with:
+        registry: ghcr.io
+        username: ${{ github.actor }}
+        password: ${{ secrets.GITHUB_TOKEN }}
+
+    - name: Docker Build & Push
+      uses: docker/build-push-action@v6
+      env:
+        DOCKER_BUILD_NO_SUMMARY: true
+      with:
+        context: .
+        file: docker/base.Dockerfile
+        platforms: linux/amd64,linux/arm64
+        push: true
+        tags: |
+          ghcr.io/ietf-tools/datatracker-app-base:${{ env.IMGVERSION }}
+          ghcr.io/ietf-tools/datatracker-app-base:latest
+
+    - name: Update version references
+      run: |
+        sed -i "1s/.*/FROM ghcr.io\/ietf-tools\/datatracker-app-base:${{ env.IMGVERSION }}/" dev/build/Dockerfile
+        echo "${{ env.IMGVERSION }}" > dev/build/TARGET_BASE
+
+    - name: Commit CHANGELOG.md
+      uses: stefanzweifel/git-auto-commit-action@v5
+      with:
+        branch: main
+        commit_message: 'ci: update base image target version to ${{ env.IMGVERSION }}'
+        file_pattern: dev/build/Dockerfile dev/build/TARGET_BASE
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 8eb6adc95..5457415f5 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -1,187 +1,187 @@
-name: Reusable Tests Workflow
-
-on:
-  workflow_call:
-    inputs:
-      ignoreLowerCoverage:
-        description: 'Ignore Lower Coverage'
-        default: false
-        required: true
-        type: boolean
-      skipSelenium:
-        description: 'Skip Selenium Tests'
-        default: false
-        required: false
-        type: boolean
-      targetBaseVersion:
-        description: 'Target Base Image Version'
-        default: latest
-        required: false
-        type: string
-
-jobs:
-  tests-python:
-    name: Python Tests
-    runs-on: ubuntu-latest
-    container: ghcr.io/ietf-tools/datatracker-app-base:${{ inputs.targetBaseVersion }}
-    
-    services:
-      db:
-        image: ghcr.io/ietf-tools/datatracker-db:latest
-    
-    steps:
-    - uses: actions/checkout@v4
-    
-    - name: Prepare for tests
-      run: |
-        chmod +x ./dev/tests/prepare.sh
-        sh ./dev/tests/prepare.sh
-        
-    - name: Ensure DB is ready
-      run: |
-        /usr/local/bin/wait-for db:5432 -- echo "DB ready"
-        
-    - name: Run all tests
-      shell: bash
-      run: |
-        echo "Running checks..."
-        ./ietf/manage.py check
-        ./ietf/manage.py migrate --fake-initial
-        echo "Validating migrations..."
-        if ! ( ietf/manage.py makemigrations --dry-run --check --verbosity 3 ) ; then
-          echo "Model changes without migrations found."
-          exit 1
-        fi
-        if [[ "x${{ inputs.skipSelenium }}" == "xtrue" ]]; then
-          echo "Disable selenium tests..."
-          rm /usr/bin/geckodriver
-        fi
-        echo "Running tests..."
-        if [[ "x${{ inputs.ignoreLowerCoverage }}" == "xtrue" ]]; then
-          echo "Lower coverage failures will be ignored."
-          HOME=/root ./ietf/manage.py test -v2 --validate-html-harder --settings=settings_test --ignore-lower-coverage
-        else
-          HOME=/root ./ietf/manage.py test -v2 --validate-html-harder --settings=settings_test
-        fi
-        coverage xml
-
-    - name: Upload geckodriver.log
-      uses: actions/upload-artifact@v4
-      if: ${{ failure() }}
-      with:
-        name: geckodriverlog
-        path: geckodriver.log
-
-    - name: Upload Coverage Results to Codecov
-      uses: codecov/codecov-action@v5
-      with:
-        disable_search: true
-        files: coverage.xml
-        token: ${{ secrets.CODECOV_TOKEN }}
-        
-    - name: Convert Coverage Results
-      if: ${{ always() }}
-      run: |
-        mv latest-coverage.json coverage.json
-        
-    - name: Upload Coverage Results as Build Artifact
-      uses: actions/upload-artifact@v4
-      if: ${{ always() }}
-      with:
-        name: coverage
-        path: coverage.json
-
-  tests-playwright:
-    name: Playwright Tests
-    runs-on: macos-latest
-    strategy:
-      fail-fast: false
-      matrix:
-        project: [chromium, firefox]
-    
-    steps:
-    - uses: actions/checkout@v4
-
-    - uses: actions/setup-node@v4
-      with:
-        node-version: '18'
-
-    - name: Run all tests
-      run: |
-        echo "Installing dependencies..."
-        yarn
-        echo "Installing Playwright..."
-        cd playwright
-        mkdir test-results
-        npm ci
-        npx playwright install --with-deps ${{ matrix.project }}
-        echo "Running tests..."
-        npx playwright test --project=${{ matrix.project }}
-        
-    - name: Upload Report
-      uses: actions/upload-artifact@v4
-      if: ${{ always() }}
-      continue-on-error: true
-      with:
-        name: playwright-results-${{ matrix.project }}
-        path: playwright/test-results/
-        if-no-files-found: ignore
-
-  tests-playwright-legacy:
-    name: Playwright Legacy Tests
-    runs-on: ubuntu-latest
-    container: ghcr.io/ietf-tools/datatracker-app-base:${{ inputs.targetBaseVersion }}
-    strategy:
-      fail-fast: false
-      matrix:
-        project: [chromium, firefox]
-    
-    services:
-      db:
-        image: ghcr.io/ietf-tools/datatracker-db:latest
-    
-    steps:
-    - uses: actions/checkout@v4
-    
-    - name: Prepare for tests
-      run: |
-        chmod +x ./dev/tests/prepare.sh
-        sh ./dev/tests/prepare.sh
-        
-    - name: Ensure DB is ready
-      run: |
-        /usr/local/bin/wait-for db:5432 -- echo "DB ready"
-        
-    - name: Start Datatracker
-      run: |
-        echo "Running checks..."
-        ./ietf/manage.py check
-        ./ietf/manage.py migrate --fake-initial
-        echo "Starting datatracker..."
-        ./ietf/manage.py runserver 0.0.0.0:8000 --settings=settings_local &
-        echo "Waiting for datatracker to be ready..."
-        /usr/local/bin/wait-for localhost:8000 -- echo "Datatracker ready"
-
-    - name: Run all tests
-      env:
-        # Required to get firefox to run as root:
-        HOME: ""
-      run: |
-        echo "Installing dependencies..."
-        yarn
-        echo "Installing Playwright..."
-        cd playwright
-        mkdir test-results
-        npm ci
-        npx playwright install --with-deps ${{ matrix.project }}
-        echo "Running tests..."
-        npx playwright test --project=${{ matrix.project }} -c playwright-legacy.config.js
-        
-    - name: Upload Report
-      uses: actions/upload-artifact@v4
-      if: ${{ always() }}
-      continue-on-error: true
-      with:
-        name: playwright-legacy-results-${{ matrix.project }}
-        path: playwright/test-results/
-        if-no-files-found: ignore
+name: Reusable Tests Workflow
+
+on:
+  workflow_call:
+    inputs:
+      ignoreLowerCoverage:
+        description: 'Ignore Lower Coverage'
+        default: false
+        required: true
+        type: boolean
+      skipSelenium:
+        description: 'Skip Selenium Tests'
+        default: false
+        required: false
+        type: boolean
+      targetBaseVersion:
+        description: 'Target Base Image Version'
+        default: latest
+        required: false
+        type: string
+
+jobs:
+  tests-python:
+    name: Python Tests
+    runs-on: ubuntu-latest
+    container: ghcr.io/ietf-tools/datatracker-app-base:${{ inputs.targetBaseVersion }}
+    
+    services:
+      db:
+        image: ghcr.io/ietf-tools/datatracker-db:latest
+    
+    steps:
+    - uses: actions/checkout@v4
+    
+    - name: Prepare for tests
+      run: |
+        chmod +x ./dev/tests/prepare.sh
+        sh ./dev/tests/prepare.sh
+        
+    - name: Ensure DB is ready
+      run: |
+        /usr/local/bin/wait-for db:5432 -- echo "DB ready"
+        
+    - name: Run all tests
+      shell: bash
+      run: |
+        echo "Running checks..."
+        ./ietf/manage.py check
+        ./ietf/manage.py migrate --fake-initial
+        echo "Validating migrations..."
+        if ! ( ietf/manage.py makemigrations --dry-run --check --verbosity 3 ) ; then
+          echo "Model changes without migrations found."
+          exit 1
+        fi
+        if [[ "x${{ inputs.skipSelenium }}" == "xtrue" ]]; then
+          echo "Disable selenium tests..."
+          rm /usr/bin/geckodriver
+        fi
+        echo "Running tests..."
+        if [[ "x${{ inputs.ignoreLowerCoverage }}" == "xtrue" ]]; then
+          echo "Lower coverage failures will be ignored."
+          HOME=/root ./ietf/manage.py test -v2 --validate-html-harder --settings=settings_test --ignore-lower-coverage
+        else
+          HOME=/root ./ietf/manage.py test -v2 --validate-html-harder --settings=settings_test
+        fi
+        coverage xml
+
+    - name: Upload geckodriver.log
+      uses: actions/upload-artifact@v4
+      if: ${{ failure() }}
+      with:
+        name: geckodriverlog
+        path: geckodriver.log
+
+    - name: Upload Coverage Results to Codecov
+      uses: codecov/codecov-action@v5
+      with:
+        disable_search: true
+        files: coverage.xml
+        token: ${{ secrets.CODECOV_TOKEN }}
+        
+    - name: Convert Coverage Results
+      if: ${{ always() }}
+      run: |
+        mv latest-coverage.json coverage.json
+        
+    - name: Upload Coverage Results as Build Artifact
+      uses: actions/upload-artifact@v4
+      if: ${{ always() }}
+      with:
+        name: coverage
+        path: coverage.json
+
+  tests-playwright:
+    name: Playwright Tests
+    runs-on: macos-latest
+    strategy:
+      fail-fast: false
+      matrix:
+        project: [chromium, firefox]
+    
+    steps:
+    - uses: actions/checkout@v4
+
+    - uses: actions/setup-node@v4
+      with:
+        node-version: '18'
+
+    - name: Run all tests
+      run: |
+        echo "Installing dependencies..."
+        yarn
+        echo "Installing Playwright..."
+        cd playwright
+        mkdir test-results
+        npm ci
+        npx playwright install --with-deps ${{ matrix.project }}
+        echo "Running tests..."
+        npx playwright test --project=${{ matrix.project }}
+        
+    - name: Upload Report
+      uses: actions/upload-artifact@v4
+      if: ${{ always() }}
+      continue-on-error: true
+      with:
+        name: playwright-results-${{ matrix.project }}
+        path: playwright/test-results/
+        if-no-files-found: ignore
+
+  tests-playwright-legacy:
+    name: Playwright Legacy Tests
+    runs-on: ubuntu-latest
+    container: ghcr.io/ietf-tools/datatracker-app-base:${{ inputs.targetBaseVersion }}
+    strategy:
+      fail-fast: false
+      matrix:
+        project: [chromium, firefox]
+    
+    services:
+      db:
+        image: ghcr.io/ietf-tools/datatracker-db:latest
+    
+    steps:
+    - uses: actions/checkout@v4
+    
+    - name: Prepare for tests
+      run: |
+        chmod +x ./dev/tests/prepare.sh
+        sh ./dev/tests/prepare.sh
+        
+    - name: Ensure DB is ready
+      run: |
+        /usr/local/bin/wait-for db:5432 -- echo "DB ready"
+        
+    - name: Start Datatracker
+      run: |
+        echo "Running checks..."
+        ./ietf/manage.py check
+        ./ietf/manage.py migrate --fake-initial
+        echo "Starting datatracker..."
+        ./ietf/manage.py runserver 0.0.0.0:8000 --settings=settings_local &
+        echo "Waiting for datatracker to be ready..."
+        /usr/local/bin/wait-for localhost:8000 -- echo "Datatracker ready"
+
+    - name: Run all tests
+      env:
+        # Required to get firefox to run as root:
+        HOME: ""
+      run: |
+        echo "Installing dependencies..."
+        yarn
+        echo "Installing Playwright..."
+        cd playwright
+        mkdir test-results
+        npm ci
+        npx playwright install --with-deps ${{ matrix.project }}
+        echo "Running tests..."
+        npx playwright test --project=${{ matrix.project }} -c playwright-legacy.config.js
+        
+    - name: Upload Report
+      uses: actions/upload-artifact@v4
+      if: ${{ always() }}
+      continue-on-error: true
+      with:
+        name: playwright-legacy-results-${{ matrix.project }}
+        path: playwright/test-results/
+        if-no-files-found: ignore

From 3074be8ccf634af7690615a684dad3cc4501759c Mon Sep 17 00:00:00 2001
From: Jennifer Richards <jennifer@staff.ietf.org>
Date: Thu, 21 Nov 2024 18:06:37 -0400
Subject: [PATCH 2/4] ci: tag feature branch release images

---
 .github/workflows/build.yml | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index f1044223d..46cb150e0 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -256,6 +256,10 @@ jobs:
         username: ${{ github.actor }}
         password: ${{ secrets.GITHUB_TOKEN }}
 
+    - name: Add feature-latest tag
+      if: ${{ startsWith(github.ref_name, 'feat/') }}
+      run: echo "FEATURE_LATEST_TAG=$(echo $GITHUB_REF_NAME | tr / -)" >> $GITHUB_ENV
+
     - name: Build Images
       uses: docker/build-push-action@v6
       env:
@@ -265,7 +269,9 @@ jobs:
         file: dev/build/Dockerfile
         platforms: ${{ github.event.inputs.skiparm == 'true' && 'linux/amd64' || 'linux/amd64,linux/arm64' }}
         push: true
-        tags: ghcr.io/ietf-tools/datatracker:${{ env.PKG_VERSION }}
+        tags: |
+          ghcr.io/ietf-tools/datatracker:${{ env.PKG_VERSION }}
+          ${{ env.FEATURE_LATEST_TAG && format('ghcr.io/ietf-tools/datatracker:{0}-latest', env.FEATURE_LATEST_TAG) || null }}
         cache-from: type=gha
         cache-to: type=gha,mode=max
 

From 394e32e022aa99e07c93823f7ad53679815a6124 Mon Sep 17 00:00:00 2001
From: Jennifer Richards <jennifer@staff.ietf.org>
Date: Fri, 22 Nov 2024 10:13:53 -0400
Subject: [PATCH 3/4] fix: lock session requests for new meetings (#8251)

* fix: lock session requests for new meetings

* fix: lint
---
 ietf/secr/meetings/tests.py | 4 ++++
 ietf/secr/meetings/views.py | 7 +++----
 2 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/ietf/secr/meetings/tests.py b/ietf/secr/meetings/tests.py
index a241d2b5e..08c792ce1 100644
--- a/ietf/secr/meetings/tests.py
+++ b/ietf/secr/meetings/tests.py
@@ -82,6 +82,10 @@ class SecrMeetingTestCase(TestCase):
             [cn.slug for cn in new_meeting.group_conflict_types.all()],
             post_data['group_conflict_types'],
         )
+        self.assertEqual(
+            new_meeting.session_request_lock_message, 
+            "Session requests for this meeting have not yet opened.",
+        )
 
     def test_add_meeting_default_conflict_types(self):
         """Add meeting should default to same conflict types as previous meeting"""
diff --git a/ietf/secr/meetings/views.py b/ietf/secr/meetings/views.py
index 8afcf5a11..47f7b7ffa 100644
--- a/ietf/secr/meetings/views.py
+++ b/ietf/secr/meetings/views.py
@@ -17,7 +17,7 @@ import debug                            # pyflakes:ignore
 from ietf.ietfauth.utils import role_required
 from ietf.utils.mail import send_mail
 from ietf.meeting.forms import duration_string
-from ietf.meeting.helpers import get_meeting, make_materials_directories, populate_important_dates
+from ietf.meeting.helpers import make_materials_directories, populate_important_dates
 from ietf.meeting.models import Meeting, Session, Room, TimeSlot, SchedTimeSessAssignment, Schedule, SchedulingEvent
 from ietf.meeting.utils import add_event_info_to_session_qs
 from ietf.name.models import SessionStatusName
@@ -223,9 +223,8 @@ def add(request):
             )
             meeting.schedule = schedule
 
-            # we want to carry session request lock status over from previous meeting
-            previous_meeting = get_meeting( int(meeting.number) - 1 )
-            meeting.session_request_lock_message = previous_meeting.session_request_lock_message
+            # Create meeting with session requests locked
+            meeting.session_request_lock_message = "Session requests for this meeting have not yet opened."
             meeting.save()
 
             populate_important_dates(meeting)

From 622ded5d2b4db9d4bf948af0e1d0890edaa8bb33 Mon Sep 17 00:00:00 2001
From: Jennifer Richards <jennifer@staff.ietf.org>
Date: Fri, 22 Nov 2024 12:38:36 -0400
Subject: [PATCH 4/4] fix: ensure csrf cookie for searches (#8260)

Needed on views that include search_form.html in their responses.
---
 ietf/doc/views_search.py | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/ietf/doc/views_search.py b/ietf/doc/views_search.py
index 0f1937efb..f4ad247ff 100644
--- a/ietf/doc/views_search.py
+++ b/ietf/doc/views_search.py
@@ -56,6 +56,7 @@ from django.utils import timezone
 from django.utils.html import strip_tags
 from django.utils.cache import _generate_cache_key # type: ignore
 from django.utils.text import slugify
+from django.views.decorators.csrf import ensure_csrf_cookie
 from django_stubs_ext import QuerySetAny
 
 import debug                            # pyflakes:ignore
@@ -283,6 +284,7 @@ def retrieve_search_results(form, all_types=False):
     return docs
 
 
+@ensure_csrf_cookie
 def search(request):
     """Search for a draft"""
     # defaults for results / meta
@@ -335,6 +337,7 @@ def search(request):
     )
 
 
+@ensure_csrf_cookie
 def frontpage(request):
     form = SearchForm()
     return render(request, 'doc/frontpage.html', {'form':form})