Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-starlette for 
openSUSE:Factory checked in at 2023-05-18 15:18:15
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-starlette (Old)
 and      /work/SRC/openSUSE:Factory/.python-starlette.new.1533 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-starlette"

Thu May 18 15:18:15 2023 rev:19 rq:1087526 version:0.27.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-starlette/python-starlette.changes        
2023-03-15 18:53:47.100152746 +0100
+++ 
/work/SRC/openSUSE:Factory/.python-starlette.new.1533/python-starlette.changes  
    2023-05-18 15:18:19.413548122 +0200
@@ -1,0 +2,12 @@
+Wed May 17 07:42:13 UTC 2023 - David Anes <david.a...@suse.com>
+
+- Update to 0.27.0:
+  * Added
+    - Minify JSON websocket data via send_json #2128
+
+  * Fixed
+    - Replace commonprefix by commonpath on StaticFiles 1797de4.
+    - Convert ImportErrors into ModuleNotFoundError #2135.
+    - Correct the RuntimeError message content in websockets #2141.
+
+-------------------------------------------------------------------

Old:
----
  starlette-0.26.1.tar.gz

New:
----
  starlette-0.27.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-starlette.spec ++++++
--- /var/tmp/diff_new_pack.KvTBez/_old  2023-05-18 15:18:20.197552108 +0200
+++ /var/tmp/diff_new_pack.KvTBez/_new  2023-05-18 15:18:20.205552150 +0200
@@ -27,7 +27,7 @@
 
 %define skip_python2 1
 Name:           python-starlette%{psuffix}
-Version:        0.26.1
+Version:        0.27.0
 Release:        0
 Summary:        Lightweight ASGI framework/toolkit
 License:        BSD-3-Clause

++++++ starlette-0.26.1.tar.gz -> starlette-0.27.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/starlette-0.26.1/.github/pull_request_template.md 
new/starlette-0.27.0/.github/pull_request_template.md
--- old/starlette-0.26.1/.github/pull_request_template.md       2023-03-13 
19:08:31.000000000 +0100
+++ new/starlette-0.27.0/.github/pull_request_template.md       2023-05-16 
12:56:45.000000000 +0200
@@ -1,7 +1,12 @@
-The starting point for contributions should usually be [a 
discussion](https://github.com/encode/starlette/discussions)
+<!-- Thanks for contributing to Starlette! 💚
+Given this is a project maintained by volunteers, please read this template to 
not waste your time, or ours! 😁 -->
 
-Simple documentation typos may be raised as stand-alone pull requests, but 
otherwise please ensure you've discussed your proposal prior to issuing a pull 
request.
+# Summary
 
-This will help us direct work appropriately, and ensure that any suggested 
changes have been okayed by the maintainers.
+<!-- Write a small summary about what is happening here. -->
 
-- [ ] Initially raised as discussion #...
+# Checklist
+
+- [ ] I understand that this PR may be closed in case there was no previous 
discussion. (This doesn't apply to typos!)
+- [ ] I've added a test for each change that was introduced, and I tried as 
much as possible to make a single atomic change.
+- [ ] I've updated the documentation accordingly.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/starlette-0.26.1/docs/lifespan.md 
new/starlette-0.27.0/docs/lifespan.md
--- old/starlette-0.26.1/docs/lifespan.md       2023-03-13 19:08:31.000000000 
+0100
+++ new/starlette-0.27.0/docs/lifespan.md       2023-05-16 12:56:45.000000000 
+0200
@@ -43,6 +43,7 @@
 
 import httpx
 from starlette.applications import Starlette
+from starlette.requests import Request
 from starlette.responses import PlainTextResponse
 from starlette.routing import Route
 
@@ -52,12 +53,12 @@
 
 
 @contextlib.asynccontextmanager
-async def lifespan(app: Starlette) -> State:
+async def lifespan(app: Starlette) -> typing.AsyncIterator[State]:
     async with httpx.AsyncClient() as client:
         yield {"http_client": client}
 
 
-async def homepage(request):
+async def homepage(request: Request) -> PlainTextResponse:
     client = request.state.http_client
     response = await client.get("https://www.example.com";)
     return PlainTextResponse(response.text)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/starlette-0.26.1/docs/middleware.md 
new/starlette-0.27.0/docs/middleware.md
--- old/starlette-0.26.1/docs/middleware.md     2023-03-13 19:08:31.000000000 
+0100
+++ new/starlette-0.27.0/docs/middleware.md     2023-05-16 12:56:45.000000000 
+0200
@@ -778,6 +778,11 @@
 A middleware class that emits tracing info to 
[OpenTracing.io](https://opentracing.io/) compatible tracers and
 can be used to profile and monitor distributed applications.
 
+#### 
[SecureCookiesMiddleware](https://github.com/thearchitector/starlette-securecookies)
+
+Customizable middleware for adding automatic cookie encryption and decryption 
to Starlette applications, with
+extra support for existing cookie-based middleware.
+
 #### [TimingMiddleware](https://github.com/steinnes/timing-asgi)
 
 A middleware class to emit timing information (cpu and wall time) for each 
request which
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/starlette-0.26.1/docs/release-notes.md 
new/starlette-0.27.0/docs/release-notes.md
--- old/starlette-0.26.1/docs/release-notes.md  2023-03-13 19:08:31.000000000 
+0100
+++ new/starlette-0.27.0/docs/release-notes.md  2023-05-16 12:56:45.000000000 
+0200
@@ -1,3 +1,18 @@
+## 0.27.0
+
+May 16, 2023
+
+This release fixes a path traversal vulnerability in `StaticFiles`. You can 
view the full security advisory:
+https://github.com/encode/starlette/security/advisories/GHSA-v5gw-mw7f-84px
+
+### Added
+* Minify JSON websocket data via `send_json` 
https://github.com/encode/starlette/pull/2128
+
+### Fixed
+* Replace `commonprefix` by `commonpath` on `StaticFiles` 
[1797de4](https://github.com/encode/starlette/commit/1797de464124b090f10cf570441e8292936d63e3).
+* Convert ImportErrors into ModuleNotFoundError 
[#2135](https://github.com/encode/starlette/pull/2135).
+* Correct the RuntimeError message content in websockets 
[#2141](https://github.com/encode/starlette/pull/2141).
+
 ## 0.26.1
 
 March 13, 2023
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/starlette-0.26.1/docs/staticfiles.md 
new/starlette-0.27.0/docs/staticfiles.md
--- old/starlette-0.26.1/docs/staticfiles.md    2023-03-13 19:08:31.000000000 
+0100
+++ new/starlette-0.27.0/docs/staticfiles.md    2023-05-16 12:56:45.000000000 
+0200
@@ -3,7 +3,7 @@
 
 ### StaticFiles
 
-Signature: `StaticFiles(directory=None, packages=None, check_dir=True, 
follow_symlink=False)`
+Signature: `StaticFiles(directory=None, packages=None, html=False, 
check_dir=True, follow_symlink=False)`
 
 * `directory` - A string or [os.Pathlike][pathlike] denoting a directory path.
 * `packages` - A list of strings or list of tuples of strings of python 
packages.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/starlette-0.26.1/docs/third-party-packages.md 
new/starlette-0.27.0/docs/third-party-packages.md
--- old/starlette-0.26.1/docs/third-party-packages.md   2023-03-13 
19:08:31.000000000 +0100
+++ new/starlette-0.27.0/docs/third-party-packages.md   2023-05-16 
12:56:45.000000000 +0200
@@ -147,6 +147,16 @@
 to quickly generate fully customizable admin interface for your models. You 
can export your data to many formats (*CSV*, *PDF*,
 *Excel*, etc), filter your data with complex query including `AND` and `OR` 
conditions,  upload files, ...
 
+## Starlette Bridge
+
+<a href="https://github.com/tarsil/starlette-bridge"; 
target="_blank">GitHub</a> |
+<a href="https://starlette-bridge.tarsild.io/"; 
target="_blank">Documentation</a>
+
+With the deprecation of `on_startup` and `on_shutdown`, Starlette Bridge makes 
sure you can still
+use the old ways of declaring events with a particularity that internally, in 
fact, creates the
+`lifespan` for you. This way backwards compatibility is assured for the 
existing packages out there
+while maintaining the integrity of the newly `lifespan` events of `Starlette`.
+
 ## Frameworks
 
 ### FastAPI
@@ -160,7 +170,7 @@
 ### Esmerald
 
 <a href="https://github.com/dymmond/esmerald"; target="_blank">GitHub</a> |
-<a href="https://esmerald.dymmond.com/"; target="_blank">Documentation</a>
+<a href="https://www.esmerald.dev"; target="_blank">Documentation</a>
 
 Highly scalable, performant, easy to learn, easy to code and for every 
application web framework.
 Inspired by a lot of frameworks out there, Esmerald provides what every 
application needs, from the
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/starlette-0.26.1/pyproject.toml 
new/starlette-0.27.0/pyproject.toml
--- old/starlette-0.26.1/pyproject.toml 2023-03-13 19:08:31.000000000 +0100
+++ new/starlette-0.27.0/pyproject.toml 2023-05-16 12:56:45.000000000 +0200
@@ -55,3 +55,9 @@
 include = [
     "/starlette",
 ]
+
+[tool.ruff]
+select = ["E", "F", "I"]
+
+[tool.ruff.isort]
+combine-as-imports = true
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/starlette-0.26.1/requirements.txt 
new/starlette-0.27.0/requirements.txt
--- old/starlette-0.26.1/requirements.txt       2023-03-13 19:08:31.000000000 
+0100
+++ new/starlette-0.27.0/requirements.txt       2023-05-16 12:56:45.000000000 
+0200
@@ -2,23 +2,21 @@
 -e .[full]
 
 # Testing
-autoflake==1.5.3
-black==22.12.0
-coverage==7.1.0
-flake8==3.9.2
+black==23.3.0
+coverage==7.2.5
 importlib-metadata==4.13.0
-isort==5.10.1
-mypy==1.0.1
-typing_extensions==4.4.0
-types-contextvars==2.4.7.1
-types-PyYAML==6.0.12.3
+mypy==1.2.0
+ruff==0.0.263
+typing_extensions==4.5.0
+types-contextvars==2.4.7.2
+types-PyYAML==6.0.12.9
 types-dataclasses==0.6.6
-pytest==7.2.1
+pytest==7.3.1
 trio==0.21.0
 
 # Documentation
 mkdocs==1.4.2
-mkdocs-material==9.0.15
+mkdocs-material==9.1.8
 mkautodoc==0.2.0
 
 # Packaging
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/starlette-0.26.1/scripts/check 
new/starlette-0.27.0/scripts/check
--- old/starlette-0.26.1/scripts/check  2023-03-13 19:08:31.000000000 +0100
+++ new/starlette-0.27.0/scripts/check  2023-05-16 12:56:45.000000000 +0200
@@ -9,7 +9,6 @@
 set -x
 
 ./scripts/sync-version
-${PREFIX}isort --check --diff --project=starlette $SOURCE_FILES
 ${PREFIX}black --check --diff $SOURCE_FILES
-${PREFIX}flake8 $SOURCE_FILES
 ${PREFIX}mypy $SOURCE_FILES
+${PREFIX}ruff check $SOURCE_FILES
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/starlette-0.26.1/scripts/lint 
new/starlette-0.27.0/scripts/lint
--- old/starlette-0.26.1/scripts/lint   2023-03-13 19:08:31.000000000 +0100
+++ new/starlette-0.27.0/scripts/lint   2023-05-16 12:56:45.000000000 +0200
@@ -8,6 +8,5 @@
 
 set -x
 
-${PREFIX}autoflake --in-place --recursive $SOURCE_FILES
-${PREFIX}isort --project=starlette $SOURCE_FILES
 ${PREFIX}black $SOURCE_FILES
+${PREFIX}ruff --fix $SOURCE_FILES
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/starlette-0.26.1/setup.cfg 
new/starlette-0.27.0/setup.cfg
--- old/starlette-0.26.1/setup.cfg      2023-03-13 19:08:31.000000000 +0100
+++ new/starlette-0.27.0/setup.cfg      2023-05-16 12:56:45.000000000 +0200
@@ -1,7 +1,3 @@
-[flake8]
-ignore = W503, E203, B305
-max-line-length = 88
-
 [mypy]
 disallow_untyped_defs = True
 ignore_missing_imports = True
@@ -16,10 +12,6 @@
 disallow_untyped_defs = False
 check_untyped_defs = True
 
-[tool:isort]
-profile = black
-combine_as_imports = True
-
 [tool:pytest]
 addopts =
   -rxXs
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/starlette-0.26.1/starlette/__init__.py 
new/starlette-0.27.0/starlette/__init__.py
--- old/starlette-0.26.1/starlette/__init__.py  2023-03-13 19:08:31.000000000 
+0100
+++ new/starlette-0.27.0/starlette/__init__.py  2023-05-16 12:56:45.000000000 
+0200
@@ -1 +1 @@
-__version__ = "0.26.1"
+__version__ = "0.27.0"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/starlette-0.26.1/starlette/_compat.py 
new/starlette-0.27.0/starlette/_compat.py
--- old/starlette-0.26.1/starlette/_compat.py   2023-03-13 19:08:31.000000000 
+0100
+++ new/starlette-0.27.0/starlette/_compat.py   2023-05-16 12:56:45.000000000 
+0200
@@ -10,7 +10,6 @@
 #
 # See issue: https://github.com/encode/starlette/issues/1365
 try:
-
     # check if the Python version supports the parameter
     # using usedforsecurity=False to avoid an exception on FIPS systems
     # that reject usedforsecurity=True
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/starlette-0.26.1/starlette/endpoints.py 
new/starlette-0.27.0/starlette/endpoints.py
--- old/starlette-0.26.1/starlette/endpoints.py 2023-03-13 19:08:31.000000000 
+0100
+++ new/starlette-0.27.0/starlette/endpoints.py 2023-05-16 12:56:45.000000000 
+0200
@@ -55,7 +55,6 @@
 
 
 class WebSocketEndpoint:
-
     encoding: typing.Optional[str] = None  # May be "text", "bytes", or "json".
 
     def __init__(self, scope: Scope, receive: Receive, send: Send) -> None:
@@ -91,7 +90,6 @@
             await self.on_disconnect(websocket, close_code)
 
     async def decode(self, websocket: WebSocket, message: Message) -> 
typing.Any:
-
         if self.encoding == "text":
             if "text" not in message:
                 await websocket.close(code=status.WS_1003_UNSUPPORTED_DATA)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/starlette-0.26.1/starlette/formparsers.py 
new/starlette-0.27.0/starlette/formparsers.py
--- old/starlette-0.26.1/starlette/formparsers.py       2023-03-13 
19:08:31.000000000 +0100
+++ new/starlette-0.27.0/starlette/formparsers.py       2023-05-16 
12:56:45.000000000 +0200
@@ -9,7 +9,7 @@
 try:
     import multipart
     from multipart.multipart import parse_options_header
-except ImportError:  # pragma: nocover
+except ModuleNotFoundError:  # pragma: nocover
     parse_options_header = None
     multipart = None
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/starlette-0.26.1/starlette/middleware/cors.py 
new/starlette-0.27.0/starlette/middleware/cors.py
--- old/starlette-0.26.1/starlette/middleware/cors.py   2023-03-13 
19:08:31.000000000 +0100
+++ new/starlette-0.27.0/starlette/middleware/cors.py   2023-05-16 
12:56:45.000000000 +0200
@@ -22,7 +22,6 @@
         expose_headers: typing.Sequence[str] = (),
         max_age: int = 600,
     ) -> None:
-
         if "*" in allow_methods:
             allow_methods = ALL_METHODS
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/starlette-0.26.1/starlette/requests.py 
new/starlette-0.27.0/starlette/requests.py
--- old/starlette-0.26.1/starlette/requests.py  2023-03-13 19:08:31.000000000 
+0100
+++ new/starlette-0.27.0/starlette/requests.py  2023-05-16 12:56:45.000000000 
+0200
@@ -12,7 +12,7 @@
 
 try:
     from multipart.multipart import parse_options_header
-except ImportError:  # pragma: nocover
+except ModuleNotFoundError:  # pragma: nocover
     parse_options_header = None
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/starlette-0.26.1/starlette/schemas.py 
new/starlette-0.27.0/starlette/schemas.py
--- old/starlette-0.26.1/starlette/schemas.py   2023-03-13 19:08:31.000000000 
+0100
+++ new/starlette-0.27.0/starlette/schemas.py   2023-05-16 12:56:45.000000000 
+0200
@@ -8,7 +8,7 @@
 
 try:
     import yaml
-except ImportError:  # pragma: nocover
+except ModuleNotFoundError:  # pragma: nocover
     yaml = None  # type: ignore[assignment]
 
 
@@ -132,7 +132,6 @@
         endpoints_info = self.get_endpoints(routes)
 
         for endpoint in endpoints_info:
-
             parsed = self.parse_docstring(endpoint.func)
 
             if not parsed:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/starlette-0.26.1/starlette/staticfiles.py 
new/starlette-0.27.0/starlette/staticfiles.py
--- old/starlette-0.26.1/starlette/staticfiles.py       2023-03-13 
19:08:31.000000000 +0100
+++ new/starlette-0.27.0/starlette/staticfiles.py       2023-05-16 
12:56:45.000000000 +0200
@@ -169,7 +169,7 @@
             else:
                 full_path = os.path.realpath(joined_path)
             directory = os.path.realpath(directory)
-            if os.path.commonprefix([full_path, directory]) != directory:
+            if os.path.commonpath([full_path, directory]) != directory:
                 # Don't allow misbehaving clients to break out of the static 
files
                 # directory.
                 continue
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/starlette-0.26.1/starlette/templating.py 
new/starlette-0.27.0/starlette/templating.py
--- old/starlette-0.26.1/starlette/templating.py        2023-03-13 
19:08:31.000000000 +0100
+++ new/starlette-0.27.0/starlette/templating.py        2023-05-16 
12:56:45.000000000 +0200
@@ -18,7 +18,7 @@
         pass_context = jinja2.pass_context
     else:  # pragma: nocover
         pass_context = jinja2.contextfunction  # type: ignore[attr-defined]
-except ImportError:  # pragma: nocover
+except ModuleNotFoundError:  # pragma: nocover
     jinja2 = None  # type: ignore[assignment]
 
 
@@ -68,7 +68,7 @@
         context_processors: typing.Optional[
             typing.List[typing.Callable[[Request], typing.Dict[str, 
typing.Any]]]
         ] = None,
-        **env_options: typing.Any
+        **env_options: typing.Any,
     ) -> None:
         assert jinja2 is not None, "jinja2 must be installed to use 
Jinja2Templates"
         self.env = self._create_env(directory, **env_options)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/starlette-0.26.1/starlette/testclient.py 
new/starlette-0.27.0/starlette/testclient.py
--- old/starlette-0.26.1/starlette/testclient.py        2023-03-13 
19:08:31.000000000 +0100
+++ new/starlette-0.27.0/starlette/testclient.py        2023-05-16 
12:56:45.000000000 +0200
@@ -145,7 +145,7 @@
 
     def send_json(self, data: typing.Any, mode: str = "text") -> None:
         assert mode in ["text", "binary"]
-        text = json.dumps(data)
+        text = json.dumps(data, separators=(",", ":"))
         if mode == "text":
             self.send({"type": "websocket.receive", "text": text})
         else:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/starlette-0.26.1/starlette/websockets.py 
new/starlette-0.27.0/starlette/websockets.py
--- old/starlette-0.26.1/starlette/websockets.py        2023-03-13 
19:08:31.000000000 +0100
+++ new/starlette-0.27.0/starlette/websockets.py        2023-05-16 
12:56:45.000000000 +0200
@@ -65,8 +65,8 @@
             message_type = message["type"]
             if message_type not in {"websocket.accept", "websocket.close"}:
                 raise RuntimeError(
-                    'Expected ASGI message "websocket.connect", '
-                    f"but got {message_type!r}"
+                    'Expected ASGI message "websocket.accept" or '
+                    f'"websocket.close", but got {message_type!r}'
                 )
             if message_type == "websocket.close":
                 self.application_state = WebSocketState.DISCONNECTED
@@ -168,7 +168,7 @@
     async def send_json(self, data: typing.Any, mode: str = "text") -> None:
         if mode not in {"text", "binary"}:
             raise RuntimeError('The "mode" argument should be "text" or 
"binary".')
-        text = json.dumps(data)
+        text = json.dumps(data, separators=(",", ":"))
         if mode == "text":
             await self.send({"type": "websocket.send", "text": text})
         else:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/starlette-0.26.1/tests/test_staticfiles.py 
new/starlette-0.27.0/tests/test_staticfiles.py
--- old/starlette-0.26.1/tests/test_staticfiles.py      2023-03-13 
19:08:31.000000000 +0100
+++ new/starlette-0.27.0/tests/test_staticfiles.py      2023-05-16 
12:56:45.000000000 +0200
@@ -1,8 +1,8 @@
 import os
-import pathlib
 import stat
 import tempfile
 import time
+from pathlib import Path
 
 import anyio
 import pytest
@@ -28,13 +28,12 @@
     assert response.text == "<file content>"
 
 
-def test_staticfiles_with_pathlib(tmpdir, test_client_factory):
-    base_dir = pathlib.Path(tmpdir)
-    path = base_dir / "example.txt"
+def test_staticfiles_with_pathlib(tmp_path: Path, test_client_factory):
+    path = tmp_path / "example.txt"
     with open(path, "w") as file:
         file.write("<file content>")
 
-    app = StaticFiles(directory=base_dir)
+    app = StaticFiles(directory=tmp_path)
     client = test_client_factory(app)
     response = client.get("/example.txt")
     assert response.status_code == 200
@@ -516,3 +515,36 @@
 
     assert exc_info.value.status_code == 404
     assert exc_info.value.detail == "Not Found"
+
+
+def test_staticfiles_avoids_path_traversal(tmp_path: Path):
+    statics_path = tmp_path / "static"
+    statics_disallow_path = tmp_path / "static_disallow"
+
+    statics_path.mkdir()
+    statics_disallow_path.mkdir()
+
+    static_index_file = statics_path / "index.html"
+    statics_disallow_path_index_file = statics_disallow_path / "index.html"
+    static_file = tmp_path / "static1.txt"
+
+    static_index_file.write_text("<h1>Hello</h1>")
+    statics_disallow_path_index_file.write_text("<h1>Private</h1>")
+    static_file.write_text("Private")
+
+    app = StaticFiles(directory=statics_path)
+
+    # We can't test this with 'httpx', so we test the app directly here.
+    path = app.get_path({"path": "/../static1.txt"})
+    with pytest.raises(HTTPException) as exc_info:
+        anyio.run(app.get_response, path, {"method": "GET"})
+
+    assert exc_info.value.status_code == 404
+    assert exc_info.value.detail == "Not Found"
+
+    path = app.get_path({"path": "/../static_disallow/index.html"})
+    with pytest.raises(HTTPException) as exc_info:
+        anyio.run(app.get_response, path, {"method": "GET"})
+
+    assert exc_info.value.status_code == 404
+    assert exc_info.value.detail == "Not Found"

Reply via email to