Skip to content

ci: add pytest, ruff, mypy, and Docker build verification to CI#36

Open
LarytheLord wants to merge 1 commit intomainfrom
feature/ci-test-lint-docker
Open

ci: add pytest, ruff, mypy, and Docker build verification to CI#36
LarytheLord wants to merge 1 commit intomainfrom
feature/ci-test-lint-docker

Conversation

@LarytheLord
Copy link
Copy Markdown

@LarytheLord LarytheLord commented May 4, 2026

Summary

  • Add CI workflow that runs all 116 existing pytest tests (previously only runnable locally)
  • Add ruff linting + formatting enforcement
  • Add mypy type checking (advisory/non-blocking for incremental adoption)
  • Add Docker build verification that the container starts successfully
  • Fix all existing ruff violations across the codebase
  • Add pyproject.toml with ruff and mypy configuration

Why this matters

The repo has 116 well-written tests but no CI runs them. A contributor could break everything and the CI would still pass green. This PR fixes that.

Changes

New files

  • .github/workflows/test-lint.yml — 4 CI jobs: tests, ruff, mypy, docker
  • pyproject.toml — ruff and mypy config

Fixed lint violations

  • auth-proxy/admin.py: sorted imports, fixed duplicate imports, replaced nested ifs, contextlib.suppress for ValueError handling, E501 per-file ignore for HTML templates
  • auth-proxy/usage_tracker.py: fixed implicit Optional (str = Nonestr | None = None)
  • auth-proxy/key_manager.py: simplified is_valid() return
  • auth-proxy/server.py: combined nested if statements, fixed unused variable
  • scripts/scrape_docs.py: combined nested ifs, broke long lines
  • tests/: fixed unused variables (key_obj_key_obj, etc.), fixed renamed variables that broke assertions
  • All files: ruff format applied

Test Results

116 passed, 0 failed

Summary by CodeRabbit

  • Chores

    • Added GitHub Actions CI/CD workflow for automated testing and linting on push and pull requests.
    • Introduced code quality tooling configuration (Ruff and Mypy) for consistent code standards and type safety.
    • Modernized codebase to Python 3.12 with updated type annotations for improved code clarity.
  • Tests

    • Enhanced test infrastructure with automated Docker image validation and test execution.

- Add test-lint.yml workflow with 4 jobs:
  - Python Tests: runs all 116 existing pytest tests
  - Ruff Lint & Format: enforces code style
  - Mypy Type Check: advisory type checking (non-blocking)
  - Docker Build Check: builds image and verifies container starts
- Add pyproject.toml with ruff and mypy configuration
- Fix all ruff violations:
  - Sort imports, fix duplicate imports in admin.py
  - Replace nested ifs with combined conditions
  - Fix implicit Optional in usage_tracker.py
  - Use contextlib.suppress for ValueError handling
  - Fix unused variables in tests
  - Apply ruff formatting across all files
- Add E501 and other per-file ignores for admin.py HTML templates
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 4, 2026

📝 Walkthrough

Walkthrough

GitHub Actions workflow added for CI/CD. Separately, Python codebase modernized with PEP 604 union-type annotations (Optional[T] → T | None), normalized string quoting (single to double), updated Ruff/Mypy configuration, and refined logic in server routing, admin dashboard, and rate limiting. Test infrastructure updated with new helpers module and all tests adjusted for type/quoting consistency.

Changes

CI/CD Infrastructure Setup

Layer / File(s) Summary
Workflow Configuration
.github/workflows/test-lint.yml
New GitHub Actions workflow with four jobs: test (pytest), lint (ruff), typecheck (mypy), and docker (build/run container check).

Type System Modernization & Code Quality

Layer / File(s) Summary
Type Annotations
auth-proxy/key_manager.py, auth-proxy/usage_tracker.py
Dataclass and method signatures updated from Optional[T] to T | None union syntax; logic remains equivalent.
Configuration & Tools
pyproject.toml, auth-proxy/config.py
Added [tool.ruff] and [tool.mypy] configuration sections with linting rules and type-checking strictness; normalized string quotes in config constants to double quotes.
Core Server & Admin Logic
auth-proxy/server.py, auth-proxy/admin.py
Refactored middleware routing (auth now skips /health and /admin*), improved rate-limit injection into request context, rewrote admin dashboard key table rendering with better empty states, enhanced session/cookie handling with Secure flag from X-Forwarded-Proto, and tightened exception handling (e.g., OSError vs IOError).
Utilities & Supporting Modules
auth-proxy/utils.py, scripts/manage_keys.py, scripts/scrape_docs.py
Modernized type hints and quoting to double quotes; refactored get_client_ip header access and scraping logic for consistency; added trailing commas in dicts.
Test Infrastructure
tests/conftest.py, tests/helpers.py
New helpers.py module with shared test API-key constants and make_keys_file() fixture helper; conftest.py environment setup now uses double-quoted strings.
Test Updates
tests/test_*.py
All test files updated to match new type signatures, import new helpers, normalize quoting to double quotes, and refactor mocking patterns; test assertions and coverage remain equivalent.

Sequence Diagram

sequenceDiagram
    participant Client
    participant Auth as Auth Middleware
    participant RateLimit as Rate Limiting
    participant Proxy as Proxy Handler
    participant Upstream
    participant Usage as Usage Tracker

    Client->>Auth: Request (with API Key or IP)
    
    rect rgba(0, 150, 200, 0.5)
    Note over Auth: Skip if /health<br/>or /admin*
    Auth-->>Client: Health/Admin response
    end
    
    rect rgba(200, 100, 0, 0.5)
    Auth->>RateLimit: Check global IP rate limit
    RateLimit-->>Auth: Allowed + remaining headers
    end
    
    rect rgba(0, 150, 100, 0.5)
    alt API Key present
        Auth->>Auth: Validate API key
        Auth->>RateLimit: Check per-key rate limit
        RateLimit-->>Auth: Allowed + limit headers
        Auth->>Auth: Store key_id in request
    else No API Key
        Auth->>Client: 403 Forbidden
    end
    end
    
    rect rgba(100, 150, 200, 0.5)
    Auth->>Proxy: Forward to proxy_request
    Proxy->>Upstream: Forward request (inject PrivateMode key)
    Upstream-->>Proxy: Response
    Proxy->>Proxy: Extract usage data
    end
    
    rect rgba(150, 100, 150, 0.5)
    alt Status 200 and key_id present
        Proxy->>Usage: Record usage
        Usage-->>Proxy: Cost calculated
    end
    end
    
    Proxy->>Client: Add RateLimit headers + response
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 52.05% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately and specifically describes the main changes: adding CI workflows for pytest, ruff, mypy testing and Docker build verification, which aligns with the comprehensive changes across workflow configuration, code formatting, and type annotations throughout the codebase.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/ci-test-lint-docker

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 0/1 reviews remaining, refill in 60 minutes.

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
auth-proxy/usage_tracker.py (1)

255-286: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Return type annotation is incorrect — can return (None, None).

The function signature declares tuple[float, float] but returns (None, None) for the "all" and unknown periods (lines 281, 284). This will cause mypy type errors.

🐛 Proposed fix
-def get_time_range(period: str) -> tuple[float, float]:
+def get_time_range(period: str) -> tuple[float | None, float | None]:
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@auth-proxy/usage_tracker.py` around lines 255 - 286, The return type of
get_time_range is wrong because it can return (None, None); update the function
signature to return tuple[Optional[float], Optional[float]] (or
Optional[tuple[float, float]]), add the required typing import (from typing
import Optional), and keep the existing return logic in get_time_range unchanged
so callers and type checkers accept None for the "all" and default cases.
🧹 Nitpick comments (2)
.github/workflows/test-lint.yml (1)

52-53: ⚡ Quick win

Pin ruff and mypy versions to prevent non-deterministic CI failures.

pip install ruff and pip install mypy without version pins will silently pick up new releases. A new ruff version that introduces or modifies rules can break the lint job unexpectedly on an otherwise-clean commit.

🔧 Proposed fix
-      - name: Install ruff
-        run: pip install ruff
+      - name: Install ruff
+        run: pip install ruff==0.11.9  # pin to known-good version
-          pip install mypy
+          pip install mypy==1.15.0  # pin to known-good version

Also applies to: 76-81

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/test-lint.yml around lines 52 - 53, Update the GitHub
Actions workflow steps that install linters so they pin versions instead of
installing latest: modify the "Install ruff" step (and the "Install mypy" step)
to use explicit version pins (e.g., ruff==<version>, mypy==<version>) or a
shared pinned requirements file/constraint to ensure deterministic CI; change
the pip install commands referenced by the "Install ruff" and "Install mypy"
steps to include those exact version specifiers or a requirements file.
scripts/scrape_docs.py (1)

159-163: 💤 Low value

link not in visited is always True — dead check.

visited stores absolute URLs (added via visited.add(full_url) in get_page), while link is always a relative path such as "/getting-started". A relative path can never equal an absolute URL, so link not in visited is unconditionally True and adds no guard. The real deduplication is full_url not in visited.

🔧 Proposed fix
         for link in extract_nav_links(soup):
             full_url = urljoin(BASE_URL, link)
-            if link not in visited and full_url not in visited and link.startswith("/") and not link.startswith("//"):
+            if full_url not in visited and link.startswith("/") and not link.startswith("//"):
                 to_visit.append(link)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/scrape_docs.py` around lines 159 - 163, The loop that discovers links
compares the relative `link` against `visited` (which contains absolute URLs),
so `link not in visited` is always true; change the dedupe to use `full_url` and
enqueue the absolute URL to keep checks consistent: in the loop that calls
`extract_nav_links(soup)` compute `full_url = urljoin(BASE_URL, link)`, replace
the condition with `if full_url not in visited and link.startswith("/") and not
link.startswith("//"):` and append `full_url` to `to_visit` (and adjust any
downstream code that expects paths so it consumes absolute URLs), referencing
`extract_nav_links`, the `visited` set, and the loop currently adding to
`to_visit`.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/test-lint.yml:
- Around line 109-120: The workflow's docker run smoke test must supply the env
vars required by auth-proxy/admin.py and avoid auto-removal so startup crashes
aren't hidden; update the docker run in the Verify container starts step to set
PBKDF2_SALT and ADMIN_PASSWORD (use the same safe defaults as
tests/conftest.py), remove the --rm flag and keep the container name, wait, then
explicitly inspect container status and run docker logs test-container before
stopping and removing it so crash logs are preserved for debugging.

In `@auth-proxy/admin.py`:
- Around line 680-690: The code unconditionally trusts X-Forwarded-Proto when
computing is_https for setting the "admin_session" cookie; instead read the
TRUST_PROXY configuration (same flag used in server.py) and only honor
X-Forwarded-Proto when TRUST_PROXY is true, otherwise determine HTTPS from the
actual request (e.g., request.secure or request.scheme == "https"); update the
is_https logic in admin.py where the response.set_cookie call is made so
secure=True is set when the real connection is HTTPS or when TRUST_PROXY allows
the forwarded header to be trusted.

In `@tests/test_endpoints.py`:
- Line 228: The assertion allows any Set-Cookie header to satisfy the test;
instead ensure the fallback specifically checks for "admin_session". Update the
assertion that currently examines resp.cookies and resp.headers so that if the
cookie key set does not contain "admin_session" you explicitly check that
resp.headers.get("Set-Cookie", "") contains "admin_session" (e.g.,
"admin_session=") rather than just testing header truthiness; reference the resp
variable and the "admin_session" cookie name in tests/test_endpoints.py to
locate and fix the failing assertion.

---

Outside diff comments:
In `@auth-proxy/usage_tracker.py`:
- Around line 255-286: The return type of get_time_range is wrong because it can
return (None, None); update the function signature to return
tuple[Optional[float], Optional[float]] (or Optional[tuple[float, float]]), add
the required typing import (from typing import Optional), and keep the existing
return logic in get_time_range unchanged so callers and type checkers accept
None for the "all" and default cases.

---

Nitpick comments:
In @.github/workflows/test-lint.yml:
- Around line 52-53: Update the GitHub Actions workflow steps that install
linters so they pin versions instead of installing latest: modify the "Install
ruff" step (and the "Install mypy" step) to use explicit version pins (e.g.,
ruff==<version>, mypy==<version>) or a shared pinned requirements
file/constraint to ensure deterministic CI; change the pip install commands
referenced by the "Install ruff" and "Install mypy" steps to include those exact
version specifiers or a requirements file.

In `@scripts/scrape_docs.py`:
- Around line 159-163: The loop that discovers links compares the relative
`link` against `visited` (which contains absolute URLs), so `link not in
visited` is always true; change the dedupe to use `full_url` and enqueue the
absolute URL to keep checks consistent: in the loop that calls
`extract_nav_links(soup)` compute `full_url = urljoin(BASE_URL, link)`, replace
the condition with `if full_url not in visited and link.startswith("/") and not
link.startswith("//"):` and append `full_url` to `to_visit` (and adjust any
downstream code that expects paths so it consumes absolute URLs), referencing
`extract_nav_links`, the `visited` set, and the loop currently adding to
`to_visit`.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 13e687c8-d947-4f38-8b18-c8b0ed7d1ae6

📥 Commits

Reviewing files that changed from the base of the PR and between 9cb986e and 35ba74b.

📒 Files selected for processing (19)
  • .github/workflows/test-lint.yml
  • auth-proxy/admin.py
  • auth-proxy/config.py
  • auth-proxy/key_manager.py
  • auth-proxy/server.py
  • auth-proxy/usage_tracker.py
  • auth-proxy/utils.py
  • pyproject.toml
  • scripts/manage_keys.py
  • scripts/scrape_docs.py
  • tests/conftest.py
  • tests/helpers.py
  • tests/test_admin.py
  • tests/test_auth.py
  • tests/test_endpoints.py
  • tests/test_proxy.py
  • tests/test_rate_limiting.py
  • tests/test_usage_tracker.py
  • tests/test_utils.py
💤 Files with no reviewable changes (1)
  • tests/helpers.py

Comment on lines +109 to +120
- name: Verify container starts
run: |
docker run --rm -d --name test-container \
-e API_KEYS_FILE=/app/secrets/keys.json \
-e UPSTREAM_URL=http://localhost:8081 \
-e PORT=8080 \
-e PRIVATEMODE_API_KEY=test-key \
-e FORCE_HTTPS=false \
privatemode-proxy:test
sleep 5
docker logs test-container
docker stop test-container
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for PBKDF2_SALT usage and the ValueError it raises
rg -n "PBKDF2_SALT" --type py -A 5 -B 2

Repository: Open-Paws/privatemode-proxy

Length of output: 2536


Docker smoke test may silently mask container startup failures.

Two compounding issues:

  1. Missing PBKDF2_SALT and ADMIN_PASSWORD: auth-proxy/admin.py raises ValueError at import time if PBKDF2_SALT is shorter than 16 bytes. The docker run command doesn't set these variables, so the container will crash immediately on startup. The test configuration in tests/conftest.py properly sets both to valid defaults.

  2. --rm + crash = misleading failure: With --rm -d, if the container exits within the 5-second window due to the startup error above, it is automatically removed. Subsequent docker logs test-container and docker stop test-container commands then fail with "no such container" — the CI step exits non-zero for the wrong reason and the actual crash logs are lost.

🔧 Proposed fix
       - name: Verify container starts
         run: |
-          docker run --rm -d --name test-container \
+          docker run -d --name test-container \
             -e API_KEYS_FILE=/app/secrets/keys.json \
             -e UPSTREAM_URL=http://localhost:8081 \
             -e PORT=8080 \
             -e PRIVATEMODE_API_KEY=test-key \
             -e FORCE_HTTPS=false \
+            -e PBKDF2_SALT=test-salt-value-1234567890 \
+            -e ADMIN_PASSWORD=test-admin-password \
             privatemode-proxy:test
           sleep 5
           docker logs test-container
-          docker stop test-container
+          docker stop test-container || true
+          docker rm -f test-container || true
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- name: Verify container starts
run: |
docker run --rm -d --name test-container \
-e API_KEYS_FILE=/app/secrets/keys.json \
-e UPSTREAM_URL=http://localhost:8081 \
-e PORT=8080 \
-e PRIVATEMODE_API_KEY=test-key \
-e FORCE_HTTPS=false \
privatemode-proxy:test
sleep 5
docker logs test-container
docker stop test-container
- name: Verify container starts
run: |
docker run -d --name test-container \
-e API_KEYS_FILE=/app/secrets/keys.json \
-e UPSTREAM_URL=http://localhost:8081 \
-e PORT=8080 \
-e PRIVATEMODE_API_KEY=test-key \
-e FORCE_HTTPS=false \
-e PBKDF2_SALT=test-salt-value-1234567890 \
-e ADMIN_PASSWORD=test-admin-password \
privatemode-proxy:test
sleep 5
docker logs test-container
docker stop test-container || true
docker rm -f test-container || true
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/test-lint.yml around lines 109 - 120, The workflow's
docker run smoke test must supply the env vars required by auth-proxy/admin.py
and avoid auto-removal so startup crashes aren't hidden; update the docker run
in the Verify container starts step to set PBKDF2_SALT and ADMIN_PASSWORD (use
the same safe defaults as tests/conftest.py), remove the --rm flag and keep the
container name, wait, then explicitly inspect container status and run docker
logs test-container before stopping and removing it so crash logs are preserved
for debugging.

Comment thread auth-proxy/admin.py
Comment on lines +680 to 690
response = web.HTTPFound("/admin")
# Detect if running behind HTTPS (Fly.io, nginx, etc.)
is_https = request.headers.get('X-Forwarded-Proto', '').lower() == 'https'
is_https = request.headers.get("X-Forwarded-Proto", "").lower() == "https"
response.set_cookie(
'admin_session',
"admin_session",
token,
max_age=86400, # 24 hours
httponly=True,
samesite='Strict',
secure=is_https # Only send cookie over HTTPS in production
samesite="Strict",
secure=is_https, # Only send cookie over HTTPS in production
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Inconsistent X-Forwarded-Proto handling — should check TRUST_PROXY.

This code unconditionally trusts the X-Forwarded-Proto header to determine HTTPS status for setting the Secure cookie flag. However, server.py (lines 290-310) only trusts this header when the TRUST_PROXY config flag is enabled.

When TRUST_PROXY=false (the default), an attacker could:

  1. Send a spoofed X-Forwarded-Proto: https header on an HTTP connection
  2. The cookie would be set with secure=True, but won't be sent over the HTTP connection
  3. This could cause authentication to fail unexpectedly

More critically, if the app is accessed directly (not behind a proxy) but X-Forwarded-Proto is missing, the cookie may incorrectly be set without secure=True even on HTTPS connections.

🔒 Proposed fix to align with server.py behavior
+from config import TRUST_PROXY

# Then in admin_login_post:
-        is_https = request.headers.get("X-Forwarded-Proto", "").lower() == "https"
+        is_https = request.secure  # True if connection is TLS
+        if not is_https and TRUST_PROXY:
+            is_https = request.headers.get("X-Forwarded-Proto", "").lower() == "https"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
response = web.HTTPFound("/admin")
# Detect if running behind HTTPS (Fly.io, nginx, etc.)
is_https = request.headers.get('X-Forwarded-Proto', '').lower() == 'https'
is_https = request.headers.get("X-Forwarded-Proto", "").lower() == "https"
response.set_cookie(
'admin_session',
"admin_session",
token,
max_age=86400, # 24 hours
httponly=True,
samesite='Strict',
secure=is_https # Only send cookie over HTTPS in production
samesite="Strict",
secure=is_https, # Only send cookie over HTTPS in production
)
response = web.HTTPFound("/admin")
# Detect if running behind HTTPS (Fly.io, nginx, etc.)
is_https = request.secure # True if connection is TLS
if not is_https and TRUST_PROXY:
is_https = request.headers.get("X-Forwarded-Proto", "").lower() == "https"
response.set_cookie(
"admin_session",
token,
max_age=86400, # 24 hours
httponly=True,
samesite="Strict",
secure=is_https, # Only send cookie over HTTPS in production
)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@auth-proxy/admin.py` around lines 680 - 690, The code unconditionally trusts
X-Forwarded-Proto when computing is_https for setting the "admin_session"
cookie; instead read the TRUST_PROXY configuration (same flag used in server.py)
and only honor X-Forwarded-Proto when TRUST_PROXY is true, otherwise determine
HTTPS from the actual request (e.g., request.secure or request.scheme ==
"https"); update the is_https logic in admin.py where the response.set_cookie
call is made so secure=True is set when the real connection is HTTPS or when
TRUST_PROXY allows the forwarded header to be trusted.

Comment thread tests/test_endpoints.py
cookies = resp.cookies
assert 'admin_session' in {c.key for c in resp.cookies.values()} or resp.headers.get('Set-Cookie', '')

assert "admin_session" in {c.key for c in resp.cookies.values()} or resp.headers.get("Set-Cookie", "")
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

or fallback accepts any Set-Cookie header, not just admin_session.

The assertion:

assert "admin_session" in {c.key for c in resp.cookies.values()} or resp.headers.get("Set-Cookie", "")

is logically broken. If admin_session is absent but any other Set-Cookie header is present (e.g. a CSRF cookie set on the same response), resp.headers.get("Set-Cookie", "") is truthy and the assertion silently passes — masking a missing session cookie.

The fallback should also check for "admin_session" specifically:

🐛 Proposed fix
-        assert "admin_session" in {c.key for c in resp.cookies.values()} or resp.headers.get("Set-Cookie", "")
+        assert "admin_session" in resp.cookies or "admin_session" in resp.headers.get("Set-Cookie", "")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/test_endpoints.py` at line 228, The assertion allows any Set-Cookie
header to satisfy the test; instead ensure the fallback specifically checks for
"admin_session". Update the assertion that currently examines resp.cookies and
resp.headers so that if the cookie key set does not contain "admin_session" you
explicitly check that resp.headers.get("Set-Cookie", "") contains
"admin_session" (e.g., "admin_session=") rather than just testing header
truthiness; reference the resp variable and the "admin_session" cookie name in
tests/test_endpoints.py to locate and fix the failing assertion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant