Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-devpi-server for
openSUSE:Factory checked in at 2026-11-09 16:04:34
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-devpi-server (Old)
and /work/SRC/openSUSE:Factory/.python-devpi-server.new.3759290 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-devpi-server"
Mon Nov 9 16:04:34 2026 rev:24 rq:1396187 version:6.21.0
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-devpi-server/python-devpi-server.changes
2026-10-13 17:52:48.145064278 +0200
+++
/work/SRC/openSUSE:Factory/.python-devpi-server.new.3759290/python-devpi-server.changes
2026-11-09 16:05:18.651490862 +0100
@@ -1,0 +2,11 @@
+Sun Nov 8 21:07:38 UTC 2026 - Dirk Müller <[email protected]>
+
+- update to 6.21.0:
+ * Use sha256 for login token signing. Existing tokens will be
+ invalidated, but they are valid for only 10 hours anyway.
+ * Block ``.`` and ``..`` as user and index names.
+ * Reported by Zachariah Mithani [zachariah-mithani] (AploSec)
+ * https://github.com/devpi/devpi/security/advisories/GHSA-w72q-
+ 5vww-p2rh
+
+-------------------------------------------------------------------
Old:
----
devpi_server-6.20.3.tar.gz
New:
----
devpi_server-6.21.0.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-devpi-server.spec ++++++
--- /var/tmp/diff_new_pack.tPwYS4/_old 2026-11-09 16:05:19.385521634 +0100
+++ /var/tmp/diff_new_pack.tPwYS4/_new 2026-11-09 16:05:19.387521718 +0100
@@ -26,7 +26,7 @@
%{?sle15_python_module_pythons}
Name: python-devpi-server
-Version: 6.20.3
+Version: 6.21.0
Release: 0
Summary: Private PyPI caching server
License: MIT
++++++ devpi_server-6.20.3.tar.gz -> devpi_server-6.21.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/devpi_server-6.20.3/AUTHORS
new/devpi_server-6.21.0/AUTHORS
--- old/devpi_server-6.20.3/AUTHORS 1970-01-01 01:00:00.000000000 +0100
+++ new/devpi_server-6.21.0/AUTHORS 2016-09-12 12:26:20.000000000 +0200
@@ -0,0 +1,13 @@
+Authors:
+
+Holger Krekel
+Florian Schulze
+
+Contributors:
+
+Anthon van der Neut
+Marc Abramowitz
+lbrack
+holger
+Edward Easton
+Christian Ullrich
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/devpi_server-6.20.3/CHANGELOG
new/devpi_server-6.21.0/CHANGELOG
--- old/devpi_server-6.20.3/CHANGELOG 2026-06-30 18:36:41.000000000 +0200
+++ new/devpi_server-6.21.0/CHANGELOG 2026-10-26 09:49:31.595840200 +0100
@@ -2,6 +2,24 @@
.. towncrier release notes start
+6.21.0 (2026-10-26)
+===================
+
+Features
+--------
+
+- Use sha256 for login token signing. Existing tokens will be invalidated, but
they are valid for only 10 hours anyway.
+
+Bug Fixes
+---------
+
+- Block ``.`` and ``..`` as user and index names.
+ Reported by Zachariah Mithani [zachariah-mithani] (AploSec)
+ https://github.com/devpi/devpi/security/advisories/GHSA-w72q-5vww-p2rh
+
+- Fix #1130: correctly compare content type header to ignore added parameters
for API v1 JSON responses.
+
+
6.20.3 (2026-06-30)
===================
@@ -20,6 +38,8 @@
---------
- Fix logic error which allowed unauthorized fetching of replication data.
+ CVE-2026-54723 reported by Pavel Revak [pavelrevak]
+ https://github.com/devpi/devpi/security/advisories/GHSA-m5pq-69xg-vcq3
6.20.1 (2026-05-11)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/devpi_server-6.20.3/CHANGELOG.short.rst
new/devpi_server-6.21.0/CHANGELOG.short.rst
--- old/devpi_server-6.20.3/CHANGELOG.short.rst 2026-06-30 18:37:42.000000000
+0200
+++ new/devpi_server-6.21.0/CHANGELOG.short.rst 2026-10-26 09:54:21.120204400
+0100
@@ -9,6 +9,24 @@
.. towncrier release notes start
+6.21.0 (2026-10-26)
+===================
+
+Features
+--------
+
+- Use sha256 for login token signing. Existing tokens will be invalidated, but
they are valid for only 10 hours anyway.
+
+Bug Fixes
+---------
+
+- Block ``.`` and ``..`` as user and index names.
+ Reported by Zachariah Mithani [zachariah-mithani] (AploSec)
+ https://github.com/devpi/devpi/security/advisories/GHSA-w72q-5vww-p2rh
+
+- Fix #1130: correctly compare content type header to ignore added parameters
for API v1 JSON responses.
+
+
6.20.3 (2026-06-30)
===================
@@ -27,6 +45,8 @@
---------
- Fix logic error which allowed unauthorized fetching of replication data.
+ CVE-2026-54723 reported by Pavel Revak [pavelrevak]
+ https://github.com/devpi/devpi/security/advisories/GHSA-m5pq-69xg-vcq3
6.20.1 (2026-05-11)
@@ -51,16 +71,3 @@
- Update replica status when the replica is waiting for new serials using the
streaming changelog endpoint.
-
-6.19.3 (2026-04-13)
-===================
-
-Bug Fixes
----------
-
-- Fix #1112: Parse simple JSON reply even with wrong content-type in reply if
the body seems to contain JSON.
-
-- Return stale project list for mirrors when the lock can't be acquired within
the timeout.
-
-- Fix importing of toxresults from devpi-server 6.5.0 to 6.9.0 where the wrong
hash was stored.
-
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/devpi_server-6.20.3/PKG-INFO
new/devpi_server-6.21.0/PKG-INFO
--- old/devpi_server-6.20.3/PKG-INFO 2026-06-30 18:37:42.541430500 +0200
+++ new/devpi_server-6.21.0/PKG-INFO 2026-10-26 09:54:21.212840600 +0100
@@ -1,6 +1,6 @@
Metadata-Version: 2.4
Name: devpi-server
-Version: 6.20.3
+Version: 6.21.0
Summary: devpi-server: backend for hosting private package indexes and PyPI
on-demand mirrors
Maintainer-email: Florian Schulze <[email protected]>
License-Expression: MIT
@@ -121,6 +121,24 @@
.. towncrier release notes start
+6.21.0 (2026-10-26)
+===================
+
+Features
+--------
+
+- Use sha256 for login token signing. Existing tokens will be invalidated, but
they are valid for only 10 hours anyway.
+
+Bug Fixes
+---------
+
+- Block ``.`` and ``..`` as user and index names.
+ Reported by Zachariah Mithani [zachariah-mithani] (AploSec)
+ https://github.com/devpi/devpi/security/advisories/GHSA-w72q-5vww-p2rh
+
+- Fix #1130: correctly compare content type header to ignore added parameters
for API v1 JSON responses.
+
+
6.20.3 (2026-06-30)
===================
@@ -139,6 +157,8 @@
---------
- Fix logic error which allowed unauthorized fetching of replication data.
+ CVE-2026-54723 reported by Pavel Revak [pavelrevak]
+ https://github.com/devpi/devpi/security/advisories/GHSA-m5pq-69xg-vcq3
6.20.1 (2026-05-11)
@@ -163,16 +183,3 @@
- Update replica status when the replica is waiting for new serials using the
streaming changelog endpoint.
-
-6.19.3 (2026-04-13)
-===================
-
-Bug Fixes
----------
-
-- Fix #1112: Parse simple JSON reply even with wrong content-type in reply if
the body seems to contain JSON.
-
-- Return stale project list for mirrors when the lock can't be acquired within
the timeout.
-
-- Fix importing of toxresults from devpi-server 6.5.0 to 6.9.0 where the wrong
hash was stored.
-
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/devpi_server-6.20.3/devpi_server/__init__.py
new/devpi_server-6.21.0/devpi_server/__init__.py
--- old/devpi_server-6.20.3/devpi_server/__init__.py 2026-06-30
18:36:41.000000000 +0200
+++ new/devpi_server-6.21.0/devpi_server/__init__.py 2026-10-26
09:37:11.732264500 +0100
@@ -1 +1 @@
-__version__ = "6.20.3"
+__version__ = "6.21.0"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/devpi_server-6.20.3/devpi_server/auth.py
new/devpi_server-6.21.0/devpi_server/auth.py
--- old/devpi_server-6.20.3/devpi_server/auth.py 2026-06-30
18:36:41.000000000 +0200
+++ new/devpi_server-6.21.0/devpi_server/auth.py 2026-10-25
08:08:59.759964700 +0100
@@ -2,6 +2,7 @@
from .log import threadlog
from .markers import notset
+from hashlib import sha256
from passlib.context import CryptContext
from typing import TYPE_CHECKING
import itertools
@@ -24,7 +25,9 @@
def __init__(self, xom: XOM, secret: str) -> None:
self.xom = xom
- self.serializer = itsdangerous.TimedSerializer(secret)
+ self.serializer = itsdangerous.TimedSerializer(
+ secret, signer_kwargs={"digest_method": sha256}
+ )
self.hook = xom.config.hook.devpiserver_auth_request
self.legacy_hook = xom.config.hook.devpiserver_auth_user
self.autocreate_users = xom.config.autocreate_users
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/devpi_server-6.20.3/devpi_server/fileutil.py
new/devpi_server-6.21.0/devpi_server/fileutil.py
--- old/devpi_server-6.20.3/devpi_server/fileutil.py 2026-06-30
18:36:41.000000000 +0200
+++ new/devpi_server-6.21.0/devpi_server/fileutil.py 2026-10-25
10:25:17.824929000 +0100
@@ -2,6 +2,7 @@
from . import filestore
from . import readonly
+from .keyfs_types import RelPath
from .markers import nodefault as _nodefault
from .normalized import NormalizedName
from io import BytesIO
@@ -227,6 +228,7 @@
readonly.SetViewReadonly: _dump_set,
complex: _dump_complex,
NormalizedName: _dump_str,
+ RelPath: _dump_str,
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/devpi_server-6.20.3/devpi_server/httpclient.py
new/devpi_server-6.21.0/devpi_server/httpclient.py
--- old/devpi_server-6.20.3/devpi_server/httpclient.py 2026-06-30
18:36:41.000000000 +0200
+++ new/devpi_server-6.21.0/devpi_server/httpclient.py 2026-10-25
08:08:59.761881000 +0100
@@ -88,7 +88,7 @@
@cached_property
def _ssl_context(self) -> ssl.SSLContext:
# create an SSLContext object that uses the same CA certs as requests
- cafile = (
+ cafile: str | None = (
os.environ.get("REQUESTS_CA_BUNDLE")
or os.environ.get("CURL_CA_BUNDLE")
or DEFAULT_CA_BUNDLE_PATH
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/devpi_server-6.20.3/devpi_server/keyfs_types.py
new/devpi_server-6.21.0/devpi_server/keyfs_types.py
--- old/devpi_server-6.20.3/devpi_server/keyfs_types.py 2026-06-30
18:36:41.000000000 +0200
+++ new/devpi_server-6.21.0/devpi_server/keyfs_types.py 2026-10-25
10:40:30.277811300 +0100
@@ -7,12 +7,12 @@
from attrs import frozen
from collections.abc import Hashable
from typing import Generic
-from typing import NewType
from typing import TYPE_CHECKING
from typing import TypeVar
from typing import Union
from typing import overload
import contextlib
+import os.path
import re
import warnings
@@ -28,6 +28,7 @@
from collections.abc import Iterator
from typing import Any
from typing import Literal
+ from typing_extensions import Self
KeyFSTypesRO = Union[
bool,
@@ -66,7 +67,23 @@
raise TypeError(msg)
-RelPath = NewType("RelPath", str)
+class InvalidRelPathError(ValueError):
+ pass
+
+
+class RelPath(str):
+ __slots__ = ()
+
+ def __new__(cls, relpath: Self | str) -> Self:
+ if os.path.isabs(relpath):
+ raise InvalidRelPathError("RelPath must be relative")
+ if {".", ".."}.intersection(os.path.split(relpath)):
+ raise InvalidRelPathError("RelPath must not contain '.' or '..'")
+ return super().__new__(cls, relpath)
+
+ def __repr__(self) -> str:
+ orig = super().__repr__()
+ return f"<{self.__class__.__name__} {orig!r}>"
@define
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/devpi_server-6.20.3/devpi_server/mirror.py
new/devpi_server-6.21.0/devpi_server/mirror.py
--- old/devpi_server-6.20.3/devpi_server/mirror.py 2026-06-30
18:36:41.000000000 +0200
+++ new/devpi_server-6.21.0/devpi_server/mirror.py 2026-10-25
08:08:59.763521000 +0100
@@ -29,6 +29,7 @@
from devpi_common.metadata import parse_version
from devpi_common.types import cached_property
from devpi_common.url import URL
+from email.message import Message
from functools import partial
from html.parser import HTMLParser
from pyramid.authentication import b64encode
@@ -47,6 +48,7 @@
if TYPE_CHECKING:
from .filestore import FileEntry
from .httpclient import AsyncGetResponse
+ from .httpclient import GetResponse
from .httpclient import HTTPClient
from .keyfs_types import PTypedKey
from .main import XOM
@@ -96,6 +98,13 @@
"text/html;q=0.01"))
+def is_json_v1_api(response: GetResponse, text: str) -> bool:
+ m = Message()
+ m["content-type"] = response.headers.get("content-type",
"application/octet-stream")
+ content_type = m.get_content_type()
+ return content_type == SIMPLE_API_V1_JSON or text.startswith("{")
+
+
class Link(URL):
def __init__(self, url="", *args, **kwargs):
self.requires_python = kwargs.pop('requires_python', None)
@@ -666,9 +675,7 @@
)
assert text is not None
parser: ProjectHTMLParser | ProjectJSONv1Parser
- if (
- response.headers.get("content-type") == SIMPLE_API_V1_JSON
- ) or text.startswith("{"):
+ if is_json_v1_api(response, text):
parser = ProjectJSONv1Parser(response.url)
parser.feed(json.loads(text))
else:
@@ -919,7 +926,7 @@
# make sure we don't store credential in the database
response_url = URL(str(response.url)).replace(username=None,
password=None)
# parse simple index's link
- if response.headers.get('content-type') == SIMPLE_API_V1_JSON:
+ if is_json_v1_api(response, text):
releaselinks = parse_index_v1_json(response_url, text)
else:
releaselinks = parse_index(response_url, text).releaselinks
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/devpi_server-6.20.3/devpi_server/model.py
new/devpi_server-6.21.0/devpi_server/model.py
--- old/devpi_server-6.20.3/devpi_server/model.py 2026-06-30
18:36:41.000000000 +0200
+++ new/devpi_server-6.21.0/devpi_server/model.py 2026-10-25
10:41:17.706956600 +0100
@@ -7,6 +7,7 @@
from .filestore import Digests
from .filestore import FileEntry
from .filestore import get_hash_spec
+from .keyfs_types import InvalidRelPathError
from .log import threadlog
from .markers import NotSet
from .markers import notset
@@ -16,6 +17,7 @@
from .readonly import SetViewReadonly
from .readonly import get_mutable_deepcopy
from abc import abstractmethod
+from contextlib import suppress
from devpi_common.metadata import get_latest_version
from devpi_common.metadata import parse_version
from devpi_common.metadata import splitbasename
@@ -241,8 +243,9 @@
def get_user(self, name: str) -> User | None:
user = User(self, name)
- if user.key.exists():
- return user
+ with suppress(InvalidRelPathError):
+ if user.key.exists():
+ return user
return None
def get_userlist(self):
@@ -347,7 +350,7 @@
def is_valid_name(name: str) -> bool:
- return not name_char_blocklist_regexp.search(name)
+ return not (name in {".", ".."} or name_char_blocklist_regexp.search(name))
class InvalidUserconfig(Exception):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/devpi_server-6.20.3/devpi_server/sizeof.py
new/devpi_server-6.21.0/devpi_server/sizeof.py
--- old/devpi_server-6.20.3/devpi_server/sizeof.py 2026-06-30
18:36:41.000000000 +0200
+++ new/devpi_server-6.21.0/devpi_server/sizeof.py 2026-10-25
08:08:59.764773600 +0100
@@ -51,6 +51,4 @@
return result
except TypeError:
# PyPy doesn't implement getsizeof, use dumplen as estimate
- from .fileutil import ( # type: ignore[assignment] # noqa: F401
- dumplen as gettotalsizeof,
- )
+ from .fileutil import dumplen as gettotalsizeof # type:
ignore[assignment] # noqa: F401
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/devpi_server-6.20.3/devpi_server.egg-info/PKG-INFO
new/devpi_server-6.21.0/devpi_server.egg-info/PKG-INFO
--- old/devpi_server-6.20.3/devpi_server.egg-info/PKG-INFO 2026-06-30
18:37:42.000000000 +0200
+++ new/devpi_server-6.21.0/devpi_server.egg-info/PKG-INFO 2026-10-26
09:54:21.134183000 +0100
@@ -1,6 +1,6 @@
Metadata-Version: 2.4
Name: devpi-server
-Version: 6.20.3
+Version: 6.21.0
Summary: devpi-server: backend for hosting private package indexes and PyPI
on-demand mirrors
Maintainer-email: Florian Schulze <[email protected]>
License-Expression: MIT
@@ -121,6 +121,24 @@
.. towncrier release notes start
+6.21.0 (2026-10-26)
+===================
+
+Features
+--------
+
+- Use sha256 for login token signing. Existing tokens will be invalidated, but
they are valid for only 10 hours anyway.
+
+Bug Fixes
+---------
+
+- Block ``.`` and ``..`` as user and index names.
+ Reported by Zachariah Mithani [zachariah-mithani] (AploSec)
+ https://github.com/devpi/devpi/security/advisories/GHSA-w72q-5vww-p2rh
+
+- Fix #1130: correctly compare content type header to ignore added parameters
for API v1 JSON responses.
+
+
6.20.3 (2026-06-30)
===================
@@ -139,6 +157,8 @@
---------
- Fix logic error which allowed unauthorized fetching of replication data.
+ CVE-2026-54723 reported by Pavel Revak [pavelrevak]
+ https://github.com/devpi/devpi/security/advisories/GHSA-m5pq-69xg-vcq3
6.20.1 (2026-05-11)
@@ -163,16 +183,3 @@
- Update replica status when the replica is waiting for new serials using the
streaming changelog endpoint.
-
-6.19.3 (2026-04-13)
-===================
-
-Bug Fixes
----------
-
-- Fix #1112: Parse simple JSON reply even with wrong content-type in reply if
the body seems to contain JSON.
-
-- Return stale project list for mirrors when the lock can't be acquired within
the timeout.
-
-- Fix importing of toxresults from devpi-server 6.5.0 to 6.9.0 where the wrong
hash was stored.
-
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/devpi_server-6.20.3/devpi_server.egg-info/SOURCES.txt
new/devpi_server-6.21.0/devpi_server.egg-info/SOURCES.txt
--- old/devpi_server-6.20.3/devpi_server.egg-info/SOURCES.txt 2026-06-30
18:37:42.000000000 +0200
+++ new/devpi_server-6.21.0/devpi_server.egg-info/SOURCES.txt 2026-10-26
09:54:21.176675600 +0100
@@ -1,4 +1,5 @@
.flake8
+AUTHORS
CHANGELOG
CHANGELOG.short.rst
LICENSE
@@ -87,6 +88,7 @@
test_devpi_server/test_genconfig.py
test_devpi_server/test_importexport.py
test_devpi_server/test_keyfs.py
+test_devpi_server/test_keyfs_types.py
test_devpi_server/test_log.py
test_devpi_server/test_main.py
test_devpi_server/test_mirror.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/devpi_server-6.20.3/pyproject.toml
new/devpi_server-6.21.0/pyproject.toml
--- old/devpi_server-6.20.3/pyproject.toml 2026-06-30 18:36:41.000000000
+0200
+++ new/devpi_server-6.21.0/pyproject.toml 2026-10-25 08:08:59.765459000
+0100
@@ -184,6 +184,7 @@
"FIX003", # cleanup later - xxx
"FLY002", # maybe cleanup later - f-string instead of join
"FURB110", # maybe cleanup later - or instead of ternary
+ "ICN001", # datetime as dt
"PERF401", # maybe cleanup later - list comprehension
"PLR0911", # cleanup later
"PLR0912", # maybe cleanup later
@@ -201,6 +202,7 @@
"RET507", # maybe cleanup later - unnecessary elif after continue
"RUF005", # cleanup later
"RUF012", # cleanup later
+ "RUF036", # cleanup later - None not at the end of the type union
"RUF043", # cleanup later - pytest.raises match regexp
"RUF059", # cleanup later - unpacked variable unused
"RSE102", # maybe cleanup later
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/devpi_server-6.20.3/test_devpi_server/test_importexport.py
new/devpi_server-6.21.0/test_devpi_server/test_importexport.py
--- old/devpi_server-6.20.3/test_devpi_server/test_importexport.py
2026-06-30 18:36:41.000000000 +0200
+++ new/devpi_server-6.21.0/test_devpi_server/test_importexport.py
2026-10-25 08:08:59.767216400 +0100
@@ -272,7 +272,8 @@
*options,
self.exportdir]
pm = get_pluginmanager()
- pm.register(plugin)
+ if plugin is not None:
+ pm.register(plugin)
assert import_(pluginmanager=pm, argv=argv) == 0
mapp2 = makemapp(options=["--serverdir", serverdir])
if plugin is not None:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/devpi_server-6.20.3/test_devpi_server/test_keyfs_types.py
new/devpi_server-6.21.0/test_devpi_server/test_keyfs_types.py
--- old/devpi_server-6.20.3/test_devpi_server/test_keyfs_types.py
1970-01-01 01:00:00.000000000 +0100
+++ new/devpi_server-6.21.0/test_devpi_server/test_keyfs_types.py
2026-10-25 10:20:29.866234800 +0100
@@ -0,0 +1,16 @@
+from __future__ import annotations
+
+from devpi_server.keyfs_types import RelPath
+import pytest
+
+
[email protected](("relpath", "match_str"), [
+ ("../foo", "must not contain"),
+ ("./foo", "must not contain"),
+ ("/absolute", "must be relative"),
+ ("foo/.", "must not contain"),
+ ("foo/..", "must not contain"),
+])
+def test_invalid_relpath(match_str: str, relpath: str) -> None:
+ with pytest.raises(ValueError, match=match_str):
+ RelPath(relpath)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/devpi_server-6.20.3/test_devpi_server/test_mirror.py
new/devpi_server-6.21.0/test_devpi_server/test_mirror.py
--- old/devpi_server-6.20.3/test_devpi_server/test_mirror.py 2026-06-30
18:36:41.000000000 +0200
+++ new/devpi_server-6.21.0/test_devpi_server/test_mirror.py 2026-10-25
08:08:59.767833000 +0100
@@ -268,12 +268,20 @@
class TestExtPYPIDB:
- def test_parse_pep691(self, pypistage):
+ @pytest.mark.parametrize(
+ "content_type",
+ [
+ "application/vnd.pypi.simple.v1+json; api-version=7.2-preview.1",
+ "application/vnd.pypi.simple.v1+json",
+ "application/octet-stream",
+ ],
+ )
+ def test_parse_pep691(self, content_type, pypistage):
pypistage.mock_simple_projects(["devpi"])
pypistage.xom.http.mockresponse(
URL(pypistage.mirror_url).joinpath("devpi").asdir().url,
code=200,
- content_type="application/vnd.pypi.simple.v1+json",
+ content_type=content_type,
text="""{
"meta": {"api-version": "1.0"},
"name": "devpi",
@@ -294,12 +302,20 @@
assert link.yanked is None
assert link.require_python is None
- def test_parse_pep691_data(self, pypistage):
+ @pytest.mark.parametrize(
+ "content_type",
+ [
+ "application/vnd.pypi.simple.v1+json; api-version=7.2-preview.1",
+ "application/vnd.pypi.simple.v1+json",
+ "application/octet-stream",
+ ],
+ )
+ def test_parse_pep691_data(self, content_type, pypistage):
pypistage.mock_simple_projects(["devpi"])
pypistage.xom.http.mockresponse(
URL(pypistage.mirror_url).joinpath("devpi").asdir().url,
code=200,
- content_type="application/vnd.pypi.simple.v1+json",
+ content_type=content_type,
text="""{
"meta": {"api-version": "1.0"},
"name": "devpi",
@@ -321,12 +337,20 @@
assert link.yanked == "brownbag"
assert link.require_python == ">=3.6"
- def test_parse_pep691_md5(self, pypistage):
+ @pytest.mark.parametrize(
+ "content_type",
+ [
+ "application/vnd.pypi.simple.v1+json; api-version=7.2-preview.1",
+ "application/vnd.pypi.simple.v1+json",
+ "application/octet-stream",
+ ],
+ )
+ def test_parse_pep691_md5(self, content_type, pypistage):
pypistage.mock_simple_projects(["devpi"])
pypistage.xom.http.mockresponse(
URL(pypistage.mirror_url).joinpath("devpi").asdir().url,
code=200,
- content_type="application/vnd.pypi.simple.v1+json",
+ content_type=content_type,
text="""{
"meta": {"api-version": "1.0"},
"name": "devpi",
@@ -897,7 +921,11 @@
@pytest.mark.asyncio
@pytest.mark.parametrize(
"content_type",
- ["application/vnd.pypi.simple.v1+json", "application/octet-stream"],
+ [
+ "application/vnd.pypi.simple.v1+json; api-version=7.2-preview.1",
+ "application/vnd.pypi.simple.v1+json",
+ "application/octet-stream",
+ ],
)
async def test_get_remote_projects_pep691_json(self, content_type,
pypistage):
pypistage.xom.http.mockresponse(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/devpi_server-6.20.3/test_devpi_server/test_nginx.py
new/devpi_server-6.21.0/test_devpi_server/test_nginx.py
--- old/devpi_server-6.20.3/test_devpi_server/test_nginx.py 2026-06-30
18:36:41.000000000 +0200
+++ new/devpi_server-6.21.0/test_devpi_server/test_nginx.py 2026-10-25
08:08:59.768721600 +0100
@@ -6,6 +6,7 @@
import json
import pytest
import re
+import sys
class NoRedirect(HTTPRedirectHandler):
@@ -47,8 +48,7 @@
class TestWithOutsideURLHeader:
- @pytest.fixture(scope="class")
- def adjust_nginx_conf_content(self):
+ def adjust_nginx_conf_content(cls):
def adjust_nginx_conf_content(content):
return re.sub(
'proxy_set_header X-outside-url.*$',
@@ -57,6 +57,10 @@
flags=re.IGNORECASE | re.MULTILINE)
return adjust_nginx_conf_content
+ if sys.version_info >= (3, 10):
+ adjust_nginx_conf_content = classmethod(adjust_nginx_conf_content) #
type: ignore[arg-type, assignment]
+ adjust_nginx_conf_content = pytest.fixture(adjust_nginx_conf_content,
scope="class")
+
@pytest.mark.slow
def test_outside_url_nginx(self, nginx_host_port):
(host, port) = nginx_host_port
@@ -69,8 +73,7 @@
class TestWithOutsideURLSubPathHeader:
- @pytest.fixture(scope="class")
- def adjust_nginx_conf_content(self):
+ def adjust_nginx_conf_content(cls):
def adjust_nginx_conf_content(content):
return re.sub(
'proxy_set_header X-outside-url.*$',
@@ -79,6 +82,10 @@
flags=re.IGNORECASE | re.MULTILINE)
return adjust_nginx_conf_content
+ if sys.version_info >= (3, 10):
+ adjust_nginx_conf_content = classmethod(adjust_nginx_conf_content) #
type: ignore[arg-type, assignment]
+ adjust_nginx_conf_content = pytest.fixture(adjust_nginx_conf_content,
scope="class")
+
@pytest.mark.slow
def test_outside_url_nginx(self, nginx_host_port):
(host, port) = nginx_host_port
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/devpi_server-6.20.3/test_devpi_server/test_views.py
new/devpi_server-6.21.0/test_devpi_server/test_views.py
--- old/devpi_server-6.20.3/test_devpi_server/test_views.py 2026-06-30
18:36:41.000000000 +0200
+++ new/devpi_server-6.21.0/test_devpi_server/test_views.py 2026-10-25
10:25:17.803544800 +0100
@@ -59,6 +59,8 @@
("foo~bar42", "fatal"),
(":foobar", "fatal"),
(":foobar:", "fatal"),
+ (".", "fatal"),
+ ("..", "fatal"),
("föö", "ok"),
("\N{GRINNING FACE}", "ok"),
],