Skip to content

Support partitioned in Response.delete_cookie#3376

Open
sungbin1015 wants to merge 3 commits into
Kludex:mainfrom
sungbin1015:feature/delete-cookie-partitioned
Open

Support partitioned in Response.delete_cookie#3376
sungbin1015 wants to merge 3 commits into
Kludex:mainfrom
sungbin1015:feature/delete-cookie-partitioned

Conversation

@sungbin1015

@sungbin1015 sungbin1015 commented Jul 13, 2026

Copy link
Copy Markdown

Summary

Response.set_cookie accepts a partitioned flag, but its sibling delete_cookie does not. Deleting a partitioned (CHIPS) cookie requires the clearing Set-Cookie to also carry the Partitioned attribute — otherwise the browser will not match and remove the cookie.

This adds partitioned: bool = False to delete_cookie, forwarding it to set_cookie alongside the other attributes so the two methods stay in parity. The existing Python 3.14+ gating lives in set_cookie, so no new gating is needed here.

Changes

  • starlette/responses.py — add partitioned param to delete_cookie, forward to set_cookie.
  • tests/test_responses.py — add test_delete_cookie_partitioned (version-safe: asserts Partitioned on 3.14+, absent otherwise, mirroring test_set_cookie).
  • docs/responses.md — update the delete_cookie signature (it was stale, also missing secure/httponly/samesite).

Testing

$ pytest tests/test_responses.py -k cookie
18 passed

$ ruff format --check starlette tests   # already formatted
$ ruff check starlette tests            # All checks passed
$ mypy starlette                        # no issues

Local interpreter is Python 3.13, so the < 3.14 path is exercised locally; the >= 3.14 path is covered by the CI matrix.


This PR was prepared with AI assistance (Claude); every changed line was reviewed and the tests above were run locally.

Review in cubic

`Response.set_cookie` accepts a `partitioned` flag, but its sibling
`delete_cookie` does not. Deleting a partitioned (CHIPS) cookie requires
the clearing `Set-Cookie` to also carry the `Partitioned` attribute,
otherwise the browser will not match and remove it.

Add `partitioned: bool = False` to `delete_cookie`, forwarding it to
`set_cookie` alongside the other attributes so the two methods stay in
parity. Add a version-safe test covering the delete path.

Co-authored-by: Claude <noreply@anthropic.com>
Signed-off-by: sungbin1015 <sbin@solbox.com>

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

1 issue found across 3 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="starlette/responses.py">

<violation number="1" location="starlette/responses.py:153">
P1: `delete_cookie("key", partitioned=True)` uses the default `secure=False`, so browsers reject the `Partitioned` expiry header and the cookie remains. Forward `secure=secure or partitioned` (or reject that invalid combination) when `partitioned` is requested.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread starlette/responses.py
secure=secure,
httponly=httponly,
samesite=samesite,
partitioned=partitioned,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1: delete_cookie("key", partitioned=True) uses the default secure=False, so browsers reject the Partitioned expiry header and the cookie remains. Forward secure=secure or partitioned (or reject that invalid combination) when partitioned is requested.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At starlette/responses.py, line 153:

<comment>`delete_cookie("key", partitioned=True)` uses the default `secure=False`, so browsers reject the `Partitioned` expiry header and the cookie remains. Forward `secure=secure or partitioned` (or reject that invalid combination) when `partitioned` is requested.</comment>

<file context>
@@ -149,6 +150,7 @@ def delete_cookie(
             secure=secure,
             httponly=httponly,
             samesite=samesite,
+            partitioned=partitioned,
         )
 
</file context>

Comment thread docs/responses.md
Add the partitioned description (including the Python 3.14+ constraint)
to the delete_cookie signature docs, mirroring set_cookie. Addresses
review feedback on PR Kludex#3376.

Co-authored-by: Claude <noreply@anthropic.com>
Signed-off-by: sungbin1015 <sbin@solbox.com>
@sungbin1015

Copy link
Copy Markdown
Author

Thanks for the review!

P3 (docs): Fixed in 6beb4d9 — added the partitioned description (including the Python 3.14+ constraint) to the delete_cookie docs, mirroring set_cookie.

P1 (coerce secure when partitioned=True): I would prefer to leave this as-is. delete_cookie intentionally forwards every argument straight to set_cookie, and set_cookie(partitioned=True) does not coerce secure either — the whole purpose of this PR is behavioral parity between the two sibling methods. Starlette also already follows this "pass the attributes through faithfully" convention elsewhere (e.g. it does not force secure for samesite=\"none\", which browsers likewise require). Auto-setting secure in delete_cookie only would make the two methods diverge. If forcing secure for partitioned cookies is desired, I think that belongs in a separate change that applies to set_cookie too — happy to open a follow-up if you would like.

🤖 This PR was prepared with AI assistance (Claude Code); all changes were reviewed by me.

The previous version-gated if/else left the 3.14+ assertion line
uncovered on Python <3.14, failing the repo's 100% coverage gate.
Mirror the set_cookie partitioned test: derive the expected
`Partitioned` marker via a ternary and assert with a single
branchless statement, so every Python version reaches 100% coverage.

Co-authored-by: Claude <noreply@anthropic.com>
Signed-off-by: sungbin1015 <sbin@solbox.com>

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

1 issue found across 1 file (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="tests/test_responses.py">

<violation number="1" location="tests/test_responses.py:528">
P2: The branchless refactoring loses negative coverage for Python < 3.14. When `partitioned_text` is `""`, `assert "" in response.headers["set-cookie"]` is always true, so the test never actually verifies that "Partitioned" is absent from the header. Compare with the `set_cookie` test where a full `==` equality makes the branchless pattern safe — here the `in` operator and empty string make it vacuous. Consider restoring the explicit `assert "Partitioned" not in response.headers["set-cookie"]` path for Python < 3.14, or switching to a full equality check similar to the set_cookie test.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread tests/test_responses.py

client = test_client_factory(app)
response = client.get("/")
assert partitioned_text in response.headers["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.

P2: The branchless refactoring loses negative coverage for Python < 3.14. When partitioned_text is "", assert "" in response.headers["set-cookie"] is always true, so the test never actually verifies that "Partitioned" is absent from the header. Compare with the set_cookie test where a full == equality makes the branchless pattern safe — here the in operator and empty string make it vacuous. Consider restoring the explicit assert "Partitioned" not in response.headers["set-cookie"] path for Python < 3.14, or switching to a full equality check similar to the set_cookie test.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At tests/test_responses.py, line 528:

<comment>The branchless refactoring loses negative coverage for Python < 3.14. When `partitioned_text` is `""`, `assert "" in response.headers["set-cookie"]` is always true, so the test never actually verifies that "Partitioned" is absent from the header. Compare with the `set_cookie` test where a full `==` equality makes the branchless pattern safe — here the `in` operator and empty string make it vacuous. Consider restoring the explicit `assert "Partitioned" not in response.headers["set-cookie"]` path for Python < 3.14, or switching to a full equality check similar to the set_cookie test.</comment>

<file context>
@@ -521,13 +521,11 @@ async def app(scope: Scope, receive: Receive, send: Send) -> None:
-        assert "Partitioned" in set_cookie
-    else:
-        assert "Partitioned" not in set_cookie
+    assert partitioned_text in response.headers["set-cookie"]
 
 
</file context>

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