Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-Werkzeug for openSUSE:Factory
checked in at 2026-03-18 16:49:25
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-Werkzeug (Old)
and /work/SRC/openSUSE:Factory/.python-Werkzeug.new.8177 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-Werkzeug"
Wed Mar 18 16:49:25 2026 rev:53 rq:1340735 version:3.1.6
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-Werkzeug/python-Werkzeug.changes
2026-01-28 15:07:03.109765675 +0100
+++
/work/SRC/openSUSE:Factory/.python-Werkzeug.new.8177/python-Werkzeug.changes
2026-03-18 16:50:33.033142739 +0100
@@ -1,0 +2,7 @@
+Tue Mar 17 16:20:02 UTC 2026 - John Paul Adrian Glaubitz
<[email protected]>
+
+- Update to 3.1.6
+ * ``safe_join`` on Windows does not allow special devices names
+ in multi-segment paths. :ghsa:`29vq-49wr-vm6x`
+
+-------------------------------------------------------------------
Old:
----
werkzeug-3.1.5.tar.gz
New:
----
werkzeug-3.1.6.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-Werkzeug.spec ++++++
--- /var/tmp/diff_new_pack.k8zox6/_old 2026-03-18 16:50:33.941180776 +0100
+++ /var/tmp/diff_new_pack.k8zox6/_new 2026-03-18 16:50:33.945180943 +0100
@@ -27,7 +27,7 @@
%{?sle15_python_module_pythons}
Name: python-Werkzeug%{psuffix}
-Version: 3.1.5
+Version: 3.1.6
Release: 0
Summary: The Swiss Army knife of Python web development
License: BSD-3-Clause
++++++ werkzeug-3.1.5.tar.gz -> werkzeug-3.1.6.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/werkzeug-3.1.5/CHANGES.rst
new/werkzeug-3.1.6/CHANGES.rst
--- old/werkzeug-3.1.5/CHANGES.rst 2026-01-08 18:37:08.000000000 +0100
+++ new/werkzeug-3.1.6/CHANGES.rst 2026-02-19 16:12:36.000000000 +0100
@@ -1,5 +1,14 @@
.. currentmodule:: werkzeug
+Version 3.1.6
+-------------
+
+Released 2026-02-19
+
+- ``safe_join`` on Windows does not allow special devices names in
+ multi-segment paths. :ghsa:`29vq-49wr-vm6x`
+
+
Version 3.1.5
-------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/werkzeug-3.1.5/PKG-INFO new/werkzeug-3.1.6/PKG-INFO
--- old/werkzeug-3.1.5/PKG-INFO 1970-01-01 01:00:00.000000000 +0100
+++ new/werkzeug-3.1.6/PKG-INFO 1970-01-01 01:00:00.000000000 +0100
@@ -1,6 +1,6 @@
Metadata-Version: 2.4
Name: Werkzeug
-Version: 3.1.5
+Version: 3.1.6
Summary: The comprehensive WSGI web application library.
Maintainer-email: Pallets <[email protected]>
Requires-Python: >=3.9
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/werkzeug-3.1.5/docs/routing.rst
new/werkzeug-3.1.6/docs/routing.rst
--- old/werkzeug-3.1.5/docs/routing.rst 2026-01-08 18:37:08.000000000 +0100
+++ new/werkzeug-3.1.6/docs/routing.rst 2026-02-19 16:12:36.000000000 +0100
@@ -87,6 +87,28 @@
appropriately.
+Rule Priority
+=============
+
+In general, the map matches more specific rules first. Rules are made up of
+static and variable parts, separated by slash ``/``. For a given segment, rules
+with a static part in that position take priority, and longer static values
take
+priority over shorter. Variable parts are weighted based on the type of data
+they match.
+
+If you're using subdomain or host matching, the domain part can use converters
+as well. The domain part is matched before the path parts. Like the path parts,
+a static domain part take priority over a variable part.
+
+Rules may end up with the same priority, by having static parts with the same
+length, and dynamic parts with the same weight, in the same positions. In this
+case, sorting is stable, so rules added earlier take priority.
+
+The exact way that rules are sorted internally is pretty complicated, but the
+result should be that you can rely on more specific rules matching before more
+general ones.
+
+
Built-in Converters
===================
@@ -127,13 +149,6 @@
:members: empty
-Matchers
-========
-
-.. autoclass:: StateMachineMatcher
- :members:
-
-
Rule Factories
==============
@@ -274,34 +289,3 @@
url = adapter.build("comm")
assert url == "ws://example.org/ws"
-
-
-State Machine Matching
-======================
-
-The default matching algorithm uses a state machine that transitions
-between parts of the request path to find a match. To understand how
-this works consider this rule::
-
- /resource/<id>
-
-Firstly this rule is decomposed into two ``RulePart``. The first is a
-static part with a content equal to ``resource``, the second is
-dynamic and requires a regex match to ``[^/]+``.
-
-A state machine is then created with an initial state that represents
-the rule's first ``/``. This initial state has a single, static
-transition to the next state which represents the rule's second
-``/``. This second state has a single dynamic transition to the final
-state which includes the rule.
-
-To match a path the matcher starts and the initial state and follows
-transitions that work. Clearly a trial path of ``/resource/2`` has the
-parts ``""``, ``resource``, and ``2`` which match the transitions and
-hence a rule will match. Whereas ``/other/2`` will not match as there
-is no transition for the ``other`` part from the initial state.
-
-The only diversion from this rule is if a ``RulePart`` is not
-part-isolating i.e. it will match ``/``. In this case the ``RulePart``
-is considered final and represents a transition that must include all
-the subsequent parts of the trial path.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/werkzeug-3.1.5/pyproject.toml
new/werkzeug-3.1.6/pyproject.toml
--- old/werkzeug-3.1.5/pyproject.toml 2026-01-08 18:37:08.000000000 +0100
+++ new/werkzeug-3.1.6/pyproject.toml 2026-02-19 16:12:36.000000000 +0100
@@ -1,6 +1,6 @@
[project]
name = "Werkzeug"
-version = "3.1.5"
+version = "3.1.6"
description = "The comprehensive WSGI web application library."
readme = "README.md"
license = "BSD-3-Clause"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/werkzeug-3.1.5/src/werkzeug/routing/map.py
new/werkzeug-3.1.6/src/werkzeug/routing/map.py
--- old/werkzeug-3.1.5/src/werkzeug/routing/map.py 2026-01-08
18:37:08.000000000 +0100
+++ new/werkzeug-3.1.6/src/werkzeug/routing/map.py 2026-02-19
16:12:36.000000000 +0100
@@ -834,69 +834,46 @@
append_unknown: bool = True,
url_scheme: str | None = None,
) -> str:
- """Building URLs works pretty much the other way round. Instead of
- `match` you call `build` and pass it the endpoint and a dict of
- arguments for the placeholders.
-
- The `build` function also accepts an argument called `force_external`
- which, if you set it to `True` will force external URLs. Per default
- external URLs (include the server name) will only be used if the
- target URL is on a different subdomain.
-
- >>> m = Map([
- ... Rule('/', endpoint='index'),
- ... Rule('/downloads/', endpoint='downloads/index'),
- ... Rule('/downloads/<int:id>', endpoint='downloads/show')
- ... ])
- >>> urls = m.bind("example.com", "/")
- >>> urls.build("index", {})
- '/'
- >>> urls.build("downloads/show", {'id': 42})
- '/downloads/42'
- >>> urls.build("downloads/show", {'id': 42}, force_external=True)
- 'http://example.com/downloads/42'
-
- Because URLs cannot contain non ASCII data you will always get
- bytes back. Non ASCII characters are urlencoded with the
- charset defined on the map instance.
-
- Additional values are converted to strings and appended to the URL as
- URL querystring parameters:
-
- >>> urls.build("index", {'q': 'My Searchstring'})
- '/?q=My+Searchstring'
-
- When processing those additional values, lists are furthermore
- interpreted as multiple values (as per
- :py:class:`werkzeug.datastructures.MultiDict`):
-
- >>> urls.build("index", {'q': ['a', 'b', 'c']})
- '/?q=a&q=b&q=c'
-
- Passing a ``MultiDict`` will also add multiple values:
-
- >>> urls.build("index", MultiDict((('p', 'z'), ('q', 'a'), ('q',
'b'))))
- '/?p=z&q=a&q=b'
-
- If a rule does not exist when building a `BuildError` exception is
- raised.
-
- The build method accepts an argument called `method` which allows you
- to specify the method you want to have an URL built for if you have
- different methods for the same endpoint specified.
-
- :param endpoint: the endpoint of the URL to build.
- :param values: the values for the URL to build. Unhandled values are
- appended to the URL as query parameters.
- :param method: the HTTP method for the rule if there are different
- URLs for different methods on the same endpoint.
- :param force_external: enforce full canonical external URLs. If the URL
- scheme is not provided, this will generate
- a protocol-relative URL.
- :param append_unknown: unknown parameters are appended to the generated
- URL as query string argument. Disable this
- if you want the builder to ignore those.
- :param url_scheme: Scheme to use in place of the bound
+ """Build a URL by filling in any variable slots in the endpoint's rule
+ with the provided values.
+
+ This produces relative URLs (path only, no host) by default, which is
+ appropriate for most use cases. When using subdomain or host matching,
+ the URL will be absolute if the endpoint is not on the same host as the
+ current request. If you need an absolute URL no matter what, such as
+ when adding a link to an email, pass ``force_external=True``.
+
+ Characters that are not allowed directly in URLs will be
percent-encoded
+ using UTF-8.
+
+ Additional values that don't match any rule parts are added to the
query
+ (``?key=value``) part of the URL.
+
+ If a rule is not found, an :exc:`.BuildError` is raised. Converters may
+ also raise exceptions when preparing a value.
+
+ Unlike matching, building does not perform comprehensive validation of
+ the values, it's assumed that they are trusted and correct. It's also
+ possible to build a URL for one endpoint that will be matched by
+ another, or will not match. This is very unlikely to happen or to
matter
+ in most applications, especially with testing. If you need a
+ stronger guarantee, you can use a helper to verify that
+ ``match(build(endpoint)) == endpoint``.
+
+ :param endpoint: The endpoint for the rule to build.
+ :param values: Values for the variable parts of the rule, which will be
+ converted using the part's converter's
+ :meth:`~.BaseConverter.to_url` method. Keys that don't match
+ variable parts will be converted to a query string unless
+ ``append_unknown`` is disabled.
+ :param method: Further match the rule to build by this HTTP method, for
+ when there are multiple rules for the same endpoint that vary based
+ on method.
+ :param force_external: Always produce an absolute URL, for external
use.
+ If ``scheme`` is not set, this produces a protocol-relative URL.
+ :param append_unknown: Convert values that don't match any rule parts
+ to a query string. Disable to ignore such values.
+ :param url_scheme: Scheme to use for absolute URLs. Defaults to
:attr:`url_scheme`.
.. versionchanged:: 2.0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/werkzeug-3.1.5/src/werkzeug/security.py
new/werkzeug-3.1.6/src/werkzeug/security.py
--- old/werkzeug-3.1.5/src/werkzeug/security.py 2026-01-08 18:37:08.000000000
+0100
+++ new/werkzeug-3.1.6/src/werkzeug/security.py 2026-02-19 16:12:36.000000000
+0100
@@ -10,7 +10,7 @@
DEFAULT_PBKDF2_ITERATIONS = 1_000_000
_os_alt_seps: list[str] = list(
- sep for sep in [os.sep, os.path.altsep] if sep is not None and sep != "/"
+ sep for sep in [os.sep, os.altsep] if sep is not None and sep != "/"
)
# https://chrisdenton.github.io/omnipath/Special%20Dos%20Device%20Names.html
_windows_device_files = {
@@ -142,15 +142,23 @@
return hmac.compare_digest(_hash_internal(method, salt, password)[0],
hashval)
-def safe_join(directory: str, *pathnames: str) -> str | None:
- """Safely join zero or more untrusted path components to a base
+def safe_join(directory: str, *untrusted: str) -> str | None:
+ """Safely join zero or more untrusted path components to a trusted base
directory to avoid escaping the base directory.
+ The untrusted path is assumed to be from/for a URL, such as for serving
+ files. Therefore, it should only use the forward slash ``/`` path
separator,
+ and will be joined using that separator. On Windows, the backslash ``\\``
+ separator is not allowed.
+
:param directory: The trusted base directory.
- :param pathnames: The untrusted path components relative to the
+ :param untrusted: The untrusted path components relative to the
base directory.
:return: A safe path, otherwise ``None``.
+ .. versionchanged:: 3.1.6
+ Special device names in multi-segment paths are not allowed on Windows.
+
.. versionchanged:: 3.1.5
More special device names, regardless of extension or trailing spaces,
are not allowed on Windows.
@@ -165,24 +173,29 @@
parts = [directory]
- for filename in pathnames:
- if filename != "":
- filename = posixpath.normpath(filename)
+ for part in untrusted:
+ if not part:
+ continue
+
+ part = posixpath.normpath(part)
if (
- any(sep in filename for sep in _os_alt_seps)
+ os.path.isabs(part)
+ # ntpath.isabs doesn't catch this
+ or part.startswith("/")
+ or part == ".."
+ or part.startswith("../")
+ or any(sep in part for sep in _os_alt_seps)
or (
os.name == "nt"
- and filename.partition(".")[0].strip().upper() in
_windows_device_files
+ and any(
+ p.partition(".")[0].strip().upper() in
_windows_device_files
+ for p in part.split("/")
+ )
)
- or os.path.isabs(filename)
- # ntpath.isabs doesn't catch this on Python < 3.11
- or filename.startswith("/")
- or filename == ".."
- or filename.startswith("../")
):
return None
- parts.append(filename)
+ parts.append(part)
return posixpath.join(*parts)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/werkzeug-3.1.5/tests/test_security.py
new/werkzeug-3.1.6/tests/test_security.py
--- old/werkzeug-3.1.5/tests/test_security.py 2026-01-08 18:37:08.000000000
+0100
+++ new/werkzeug-3.1.6/tests/test_security.py 2026-02-19 16:12:36.000000000
+0100
@@ -73,7 +73,7 @@
@pytest.mark.parametrize(
- "name", ["CON", "CON.txt", "CON.txt.html", "CON ", "CON . txt"]
+ "name", ["CON", "CON.txt", "CON.txt.html", "CON ", "CON . txt", "b/CON"]
)
def test_safe_join_windows_special(monkeypatch: pytest.MonkeyPatch, name: str)
-> None:
"""Windows special device name is not allowed on Windows."""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/werkzeug-3.1.5/uv.lock new/werkzeug-3.1.6/uv.lock
--- old/werkzeug-3.1.5/uv.lock 2026-01-08 18:37:08.000000000 +0100
+++ new/werkzeug-3.1.6/uv.lock 2026-02-19 16:12:36.000000000 +0100
@@ -1938,7 +1938,7 @@
[[package]]
name = "werkzeug"
-version = "3.1.5"
+version = "3.1.6"
source = { editable = "." }
dependencies = [
{ name = "markupsafe" },