Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-poetry for openSUSE:Factory 
checked in at 2026-03-31 15:23:11
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-poetry (Old)
 and      /work/SRC/openSUSE:Factory/.python-poetry.new.1999 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-poetry"

Tue Mar 31 15:23:11 2026 rev:41 rq:1343788 version:2.3.3

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-poetry/python-poetry.changes      
2026-02-12 17:29:44.825347730 +0100
+++ /work/SRC/openSUSE:Factory/.python-poetry.new.1999/python-poetry.changes    
2026-03-31 15:24:24.517617841 +0200
@@ -1,0 +2,33 @@
+Mon Mar 30 20:35:42 UTC 2026 - Dirk Müller <[email protected]>
+
+- update to 2.3.3:
+  * **Fix a path traversal vulnerability in the wheel installer
+    that could allow malicious wheel files to write files outside
+    the intended installation directory** (#10792).
+  * Fix an issue where `git` dependencies from annotated tags
+    could not be updated (#10719).
+  * Fix an issue where empty `VIRTUAL_ENV` or `CONDA_PREFIX`
+    environment variables (e.g., after `conda deactivate`) would
+    cause Poetry to incorrectly detect an active virtualenv
+    (#10784).
+  * Fix an issue where an incomprehensible error message was
+    printed when `.venv` was a file instead of a directory
+    (#10777).
+  * Fix an issue where HTTP Basic Authentication credentials
+    could be corrupted during request preparation, causing
+    authentication failures with long tokens (#10748).
+  * Fix an issue where `poetry publish --no-interaction --build`
+    requested user interaction (#10769).
+  * Fix an issue where `poetry init` and `poetry new` created a
+    deprecated `project.license` format (#10787).
+  * Clarify the differences between `poetry install` and `poetry
+    update` (#10713).
+  * Clarify the section of fields in the `pyproject.toml`
+    examples (#10753).
+  * Add a note about the different installation location when
+    Python from the Microsoft Store is used (#10759).
+  * Fix the system requirements for Poetry (#10739).
+  * Fix the `poetry cache clear` example (#10749).
+  * Fix the link to `pipx` installation instructions (#10783).
+
+-------------------------------------------------------------------

Old:
----
  poetry-2.3.2.tar.gz

New:
----
  poetry-2.3.3.tar.gz

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

Other differences:
------------------
++++++ python-poetry.spec ++++++
--- /var/tmp/diff_new_pack.FeR4M6/_old  2026-03-31 15:24:25.109642504 +0200
+++ /var/tmp/diff_new_pack.FeR4M6/_new  2026-03-31 15:24:25.113642671 +0200
@@ -27,7 +27,7 @@
 
 %{?sle15_python_module_pythons}
 Name:           python-poetry%{psuffix}
-Version:        2.3.2
+Version:        2.3.3
 Release:        0
 Summary:        Python dependency management and packaging
 License:        MIT
@@ -39,14 +39,14 @@
 BuildRequires:  %{python_module poetry-core >= 2}
 BuildRequires:  fdupes
 BuildRequires:  python-rpm-macros
-Requires:       python-poetry-core = 2.3.1
+Requires:       python-poetry-core = 2.3.2
 Requires:       (python-build >= 1.2.1 with python-build < 2.0.0)
 Requires:       (python-cachecontrol >= 0.14.0 with python-cachecontrol < 
0.15.0)
 # from cachecontrol[filecache]
 Requires:       python-filelock >= 3.8.0
 # /cachecontrol[filecache]
 Requires:       (python-cleo >= 2.1.0 with python-cleo < 3.0.0)
-Requires:       python-packaging >= 24
+Requires:       python-packaging >= 24.2
 Requires:       python-pbs-installer >= 2025.6.10
 Requires:       python-trove-classifiers >= 2022.5.19
 Requires:       python-virtualenv >= 20.26.6

++++++ poetry-2.3.2.tar.gz -> poetry-2.3.3.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/poetry-2.3.2/CHANGELOG.md 
new/poetry-2.3.3/CHANGELOG.md
--- old/poetry-2.3.2/CHANGELOG.md       2026-02-01 16:31:39.000000000 +0100
+++ new/poetry-2.3.3/CHANGELOG.md       2026-03-29 14:13:27.000000000 +0200
@@ -1,5 +1,40 @@
 # Change Log
 
+## [2.3.3] - 2026-03-29
+
+### Fixed
+
+- **Fix a path traversal vulnerability in the wheel installer that could allow 
malicious wheel files to write files outside the intended installation 
directory** ([#10792](https://github.com/python-poetry/poetry/pull/10792)).
+- Fix an issue where `git` dependencies from annotated tags could not be 
updated ([#10719](https://github.com/python-poetry/poetry/pull/10719)).
+- Fix an issue where empty `VIRTUAL_ENV` or `CONDA_PREFIX` environment 
variables (e.g., after `conda deactivate`) would cause Poetry to incorrectly 
detect an active virtualenv 
([#10784](https://github.com/python-poetry/poetry/pull/10784)).
+- Fix an issue where an incomprehensible error message was printed when 
`.venv` was a file instead of a directory 
([#10777](https://github.com/python-poetry/poetry/pull/10777)).
+- Fix an issue where HTTP Basic Authentication credentials could be corrupted 
during request preparation, causing authentication failures with long tokens 
([#10748](https://github.com/python-poetry/poetry/pull/10748)).
+- Fix an issue where `poetry publish --no-interaction --build` requested user 
interaction ([#10769](https://github.com/python-poetry/poetry/pull/10769)).
+- Fix an issue where `poetry init` and `poetry new` created a deprecated 
`project.license` format 
([#10787](https://github.com/python-poetry/poetry/pull/10787)).
+
+### Docs
+
+- Clarify the differences between `poetry install` and `poetry update` 
([#10713](https://github.com/python-poetry/poetry/pull/10713)).
+- Clarify the section of fields in the `pyproject.toml` examples 
([#10753](https://github.com/python-poetry/poetry/pull/10753)).
+- Add a note about the different installation location when Python from the 
Microsoft Store is used 
([#10759](https://github.com/python-poetry/poetry/pull/10759)).
+- Fix the system requirements for Poetry 
([#10739](https://github.com/python-poetry/poetry/pull/10739)).
+- Fix the `poetry cache clear` example 
([#10749](https://github.com/python-poetry/poetry/pull/10749)).
+- Fix the link to `pipx` installation instructions 
([#10783](https://github.com/python-poetry/poetry/pull/10783)).
+
+### poetry-core 
([`2.3.2`](https://github.com/python-poetry/poetry-core/releases/tag/2.3.2))
+
+- Fix an issue where `platform_release` could not be parsed on Debian Trixie 
([#930](https://github.com/python-poetry/poetry-core/pull/930)).
+- Fix an issue where using `project.readme.text` in the `pyproject.toml` file 
resulted in broken metadata 
([#914](https://github.com/python-poetry/poetry-core/pull/914)).
+- Fix an issue where dependency groups were considered equal when their 
resolved dependencies were equal, even if the groups themselves were not 
([#919](https://github.com/python-poetry/poetry-core/pull/919)).
+- Fix an issue where removing a dependency from a group that included another 
group resulted in other dependencies being added to the included group 
([#922](https://github.com/python-poetry/poetry-core/pull/922)).
+- Fix an issue where PEP 735 `include-group` entries were lost when 
`[tool.poetry.group]` also defined `include-groups` for the same group 
([#924](https://github.com/python-poetry/poetry-core/pull/924)).
+- Fix an issue where the union of `<value> not in <marker>` constraints was 
wrongly treated as always satisfied 
([#925](https://github.com/python-poetry/poetry-core/pull/925)).
+- Fix an issue where a post release with a local version identifier was 
wrongly allowed by a `>` version constraint 
([#921](https://github.com/python-poetry/poetry-core/pull/921)).
+- Fix an issue where a version with the local version identifier `0` was 
treated as equal to the corresponding public version 
([#920](https://github.com/python-poetry/poetry-core/pull/920)).
+- Fix an issue where a `!= <version>` constraint wrongly disallowed pre 
releases and post releases of the specified version 
([#929](https://github.com/python-poetry/poetry-core/pull/929)).
+- Fix an issue where `in` and `not in` constraints were wrongly not allowed by 
specific compound constraints 
([#927](https://github.com/python-poetry/poetry-core/pull/927)).
+
+
 ## [2.3.2] - 2026-02-01
 
 ### Changed
@@ -2658,7 +2693,8 @@
 
 
 
-[Unreleased]: https://github.com/python-poetry/poetry/compare/2.3.2...main
+[Unreleased]: https://github.com/python-poetry/poetry/compare/2.3.3...main
+[2.3.3]: https://github.com/python-poetry/poetry/releases/tag/2.3.3
 [2.3.2]: https://github.com/python-poetry/poetry/releases/tag/2.3.2
 [2.3.1]: https://github.com/python-poetry/poetry/releases/tag/2.3.1
 [2.3.0]: https://github.com/python-poetry/poetry/releases/tag/2.3.0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/poetry-2.3.2/docs/_index.md 
new/poetry-2.3.3/docs/_index.md
--- old/poetry-2.3.2/docs/_index.md     2026-02-01 16:31:39.000000000 +0100
+++ new/poetry-2.3.3/docs/_index.md     2026-03-29 14:13:27.000000000 +0200
@@ -18,7 +18,7 @@
 
 ## System requirements
 
-Poetry requires **Python 3.9+**. It is multi-platform and the goal is to make 
it work equally well
+Poetry requires **Python 3.10+**. It is multi-platform and the goal is to make 
it work equally well
 on Linux, macOS and Windows.
 
 ## Installation
@@ -40,7 +40,7 @@
 **Install pipx**
 
 If `pipx` is not already installed, you can follow any of the options in the
-[official pipx installation 
instructions](https://pipx.pypa.io/stable/installation/).
+[official pipx installation 
instructions](https://pipx.pypa.io/stable/how-to/install-pipx/).
 Any non-ancient version of `pipx` will do.
 
 {{< /step >}}
@@ -190,6 +190,18 @@
 - `%APPDATA%\Python\Scripts` on Windows.
 - `$POETRY_HOME/bin` if `$POETRY_HOME` is set.
 
+{{% note %}}
+If you have installed Python through the Microsoft Store, the `poetry` binary
+will be installed to a different location, for example:
+
+```
+%LOCALAPPDATA%\Packages\PythonSoftwareFoundation.Python.3.12_qbz5n2kfra8p0
+\LocalCache\Roaming\Python\Scripts
+```
+
+Replace `3.12` with your installed Python version and `qbz5n2kfra8p0` with 
your suffix.
+{{% /note %}}
+
 If this directory is not present in your `$PATH`, you can add it in order to 
invoke Poetry
 as `poetry`.
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/poetry-2.3.2/docs/cli.md new/poetry-2.3.3/docs/cli.md
--- old/poetry-2.3.2/docs/cli.md        2026-02-01 16:31:39.000000000 +0100
+++ new/poetry-2.3.3/docs/cli.md        2026-03-29 14:13:27.000000000 +0200
@@ -263,7 +263,7 @@
 To only remove a specific package from a cache, you have to specify the cache 
entry in the following form `cache:package:version`:
 
 ```bash
-poetry cache clear pypi:requests:2.24.0
+poetry cache clear PyPI:requests:2.24.0
 ```
 
 ### cache list
@@ -475,14 +475,6 @@
 The `install` command reads the `pyproject.toml` file from the current project,
 resolves the dependencies, and installs them.
 
-{{% note %}}
-Normally, you should prefer `poetry sync` to `poetry install` to avoid 
untracked outdated packages.
-However, if you have set `virtualenvs.create = false` to install dependencies 
into your system environment,
-which is discouraged, or `virtualenvs.options.system-site-packages = true` to 
make
-system site-packages available in your virtual environment, you should use 
`poetry install`
-because `poetry sync` will normally not work well in these cases.
-{{% /note %}}
-
 ```bash
 poetry install
 ```
@@ -493,6 +485,23 @@
 
 If there is no `poetry.lock` file, Poetry will create one after dependency 
resolution.
 
+{{% note %}}
+**When to use `install` vs `update`:**
+- Use `poetry install` to install dependencies as specified in `poetry.lock` 
(or resolve dependencies and create the lock file if it is missing).
+  This is what you run after cloning a project. For reproducible installs, 
prefer `poetry sync`,
+  which also removes packages that are not in the lock file.
+- Use `poetry update` when you want to update dependencies to their latest 
versions (within the constraints from the `pyproject.toml`)
+  and refresh `poetry.lock`.
+{{% /note %}}
+
+{{% note %}}
+Normally, you should prefer `poetry sync` to `poetry install` to avoid 
untracked outdated packages.
+However, if you have set `virtualenvs.create = false` to install dependencies 
into your system environment,
+which is discouraged, or `virtualenvs.options.system-site-packages = true` to 
make
+system site-packages available in your virtual environment, you should use 
`poetry install`
+because `poetry sync` will normally not work well in these cases.
+{{% /note %}}
+
 If you want to exclude one or more dependency groups for the installation, you 
can use
 the `--without` option.
 
@@ -1276,7 +1285,14 @@
 poetry update
 ```
 
-This will resolve all dependencies of the project and write the exact versions 
into `poetry.lock`.
+This will resolve all dependencies of the project, write the exact versions 
into `poetry.lock`,
+and install them into your environment.
+
+{{% note %}}
+The `update` command **does not** modify your `pyproject.toml` file. It only 
updates the
+`poetry.lock` file with the latest compatible versions based on the 
constraints already
+defined in `pyproject.toml`. To change version constraints, use the `add` 
command instead.
+{{% /note %}}
 
 If you just want to update a few packages and not all, you can list them as 
such:
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/poetry-2.3.2/docs/pyproject.md 
new/poetry-2.3.3/docs/pyproject.md
--- old/poetry-2.3.2/docs/pyproject.md  2026-02-01 16:31:39.000000000 +0100
+++ new/poetry-2.3.3/docs/pyproject.md  2026-03-29 14:13:27.000000000 +0200
@@ -35,6 +35,7 @@
 
 
 ```toml
+[project]
 name = "my-package"
 ```
 
@@ -45,6 +46,8 @@
 This should be a valid [PEP 440](https://peps.python.org/pep-0440/) string.
 
 ```toml
+[project]
+# ...
 version = "0.1.0"
 ```
 
@@ -66,6 +69,8 @@
 A short description of the package.
 
 ```toml
+[project]
+# ...
 description = "A short description of the package."
 ```
 
@@ -94,6 +99,8 @@
 More identifiers are listed at the [SPDX Open Source License 
Registry](https://spdx.org/licenses/).
 
 ```toml
+[project]
+# ...
 license = "MIT"
 ```
 
@@ -136,6 +143,8 @@
 A path to the README file or the content.
 
 ```toml
+[project]
+# ...
 readme = "README.md"
 ```
 
@@ -159,6 +168,8 @@
 The Python version requirements of the project.
 
 ```toml
+[project]
+# ...
 requires-python = ">=3.8"
 ```
 
@@ -184,6 +195,8 @@
 This is a list of authors and should contain at least one author.
 
 ```toml
+[project]
+# ...
 authors = [
     { name = "Sébastien Eustace", email = "[email protected]" },
 ]
@@ -196,6 +209,8 @@
 This is a list of maintainers and should be distinct from authors.
 
 ```toml
+[project]
+# ...
 maintainers = [
     { name = "John Smith", email = "[email protected]" },
     { name = "Jane Smith", email = "[email protected]" },
@@ -207,6 +222,8 @@
 A list of keywords that the package is related to.
 
 ```toml
+[project]
+# ...
 keywords = [ "packaging", "poetry" ]
 ```
 
@@ -215,6 +232,8 @@
 A list of PyPI [trove classifiers](https://pypi.org/classifiers/) that 
describe the project.
 
 ```toml
+[project]
+# ...
 classifiers = [
     "Topic :: Software Development :: Build Tools",
     "Topic :: Software Development :: Libraries :: Python Modules"
@@ -326,6 +345,8 @@
 The `dependencies` of the project.
 
 ```toml
+[project]
+# ...
 dependencies = [
     "requests>=2.13.0",
 ]
@@ -366,6 +387,8 @@
 See [basic usage]({{< relref "basic-usage#operating-modes" >}}) for more 
information.
 
 ```toml
+[tool.poetry]
+# ...
 package-mode = false
 ```
 
@@ -379,6 +402,7 @@
 
 
 ```toml
+[tool.poetry]
 name = "my-package"
 ```
 
@@ -395,6 +419,8 @@
 This should be a valid [PEP 440](https://peps.python.org/pep-0440/) string.
 
 ```toml
+[tool.poetry]
+# ...
 version = "0.1.0"
 ```
 
@@ -412,6 +438,8 @@
 A short description of the package.
 
 ```toml
+[tool.poetry]
+# ...
 description = "A short description of the package."
 ```
 
@@ -441,6 +469,8 @@
 More identifiers are listed at the [SPDX Open Source License 
Registry](https://spdx.org/licenses/).
 
 ```toml
+[tool.poetry]
+# ...
 license = "MIT"
 ```
 
@@ -453,6 +483,8 @@
 This is a list of authors and should contain at least one author. Authors must 
be in the form `name <email>`.
 
 ```toml
+[tool.poetry]
+# ...
 authors = [
     "Sébastien Eustace <[email protected]>",
 ]
@@ -467,6 +499,8 @@
 This is a list of maintainers and should be distinct from authors. Maintainers 
may contain an email and be in the form `name <email>`.
 
 ```toml
+[tool.poetry]
+# ...
 maintainers = [
     "John Smith <[email protected]>",
     "Jane Smith <[email protected]>",
@@ -513,9 +547,11 @@
 
 **Deprecated**: Use `project.urls` instead.
 
-An URL to the website of the project.
+A URL to the website of the project.
 
 ```toml
+[tool.poetry]
+# ...
 homepage = "https://python-poetry.org/";
 ```
 
@@ -523,9 +559,11 @@
 
 **Deprecated**: Use `project.urls` instead.
 
-An URL to the repository of the project.
+A URL to the repository of the project.
 
 ```toml
+[tool.poetry]
+# ...
 repository = "https://github.com/python-poetry/poetry";
 ```
 
@@ -533,9 +571,11 @@
 
 **Deprecated**: Use `project.urls` instead.
 
-An URL to the documentation of the project.
+A URL to the documentation of the project.
 
 ```toml
+[tool.poetry]
+# ...
 documentation = "https://python-poetry.org/docs/";
 ```
 
@@ -546,6 +586,8 @@
 A list of keywords that the package is related to.
 
 ```toml
+[tool.poetry]
+# ...
 keywords = ["packaging", "poetry"]
 ```
 
@@ -642,6 +684,8 @@
 another package named `extra_package`, you will need to specify `my_package` 
explicitly:
 
 ```toml
+[tool.poetry]
+# ...
 packages = [
     { include = "my_package" },
     { include = "extra_package" },
@@ -921,6 +965,7 @@
 
 ```toml
 [tool.poetry]
+# ...
 requires-poetry = ">=2.0"
 ```
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/poetry-2.3.2/poetry.lock new/poetry-2.3.3/poetry.lock
--- old/poetry-2.3.2/poetry.lock        2026-02-01 16:31:39.000000000 +0100
+++ new/poetry-2.3.3/poetry.lock        2026-03-29 14:13:27.000000000 +0200
@@ -1,4 +1,4 @@
-# This file is automatically @generated by Poetry 2.3.1 and should not be 
changed by hand.
+# This file is automatically @generated by Poetry 2.3.2 and should not be 
changed by hand.
 
 [[package]]
 name = "anyio"
@@ -1347,14 +1347,14 @@
 
 [[package]]
 name = "poetry-core"
-version = "2.3.1"
+version = "2.3.2"
 description = "Poetry PEP 517 Build Backend"
 optional = false
 python-versions = "<4.0,>=3.10"
 groups = ["main"]
 files = [
-    {file = "poetry_core-2.3.1-py3-none-any.whl", hash = 
"sha256:db1cf63b782570deb38bfba61e2304a553eef0740dc17959a50cc0f5115ee634"},
-    {file = "poetry_core-2.3.1.tar.gz", hash = 
"sha256:96f791d5d7d4e040f3983d76779425cf9532690e2756a24fd5ca0f86af19ef82"},
+    {file = "poetry_core-2.3.2-py3-none-any.whl", hash = 
"sha256:23df641b64f87fbb4ce1873c1915a4d4bb1b7d808c596e4307edc073e68d7234"},
+    {file = "poetry_core-2.3.2.tar.gz", hash = 
"sha256:20cb71be27b774628da9f384effd9183dfceb53bcef84063248a8672aa47031f"},
 ]
 
 [[package]]
@@ -2196,4 +2196,4 @@
 [metadata]
 lock-version = "2.1"
 python-versions = ">=3.10,<4.0"
-content-hash = 
"9ce6acbe11341f1c5fc0a8df9bfe5fe9237fedb54c90a756baf344b1c2b62e43"
+content-hash = 
"69cddd52ffdedc12c4b7445a9f359d67a4a1dc4b5d139d261a2c228a832bf39a"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/poetry-2.3.2/pyproject.toml 
new/poetry-2.3.3/pyproject.toml
--- old/poetry-2.3.2/pyproject.toml     2026-02-01 16:31:39.000000000 +0100
+++ new/poetry-2.3.3/pyproject.toml     2026-03-29 14:13:27.000000000 +0200
@@ -1,10 +1,10 @@
 [project]
 name = "poetry"
-version = "2.3.2"
+version = "2.3.3"
 description = "Python dependency management and packaging made easy."
 requires-python = ">=3.10,<4.0"
 dependencies = [
-    "poetry-core (==2.3.1)",
+    "poetry-core (==2.3.2)",
     "build (>=1.2.1,<2.0.0)",
     "cachecontrol[filecache] (>=0.14.0,<0.15.0)",
     "cleo (>=2.1.0,<3.0.0)",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/poetry-2.3.2/src/poetry/console/commands/env/remove.py 
new/poetry-2.3.3/src/poetry/console/commands/env/remove.py
--- old/poetry-2.3.2/src/poetry/console/commands/env/remove.py  2026-02-01 
16:31:39.000000000 +0100
+++ new/poetry-2.3.3/src/poetry/console/commands/env/remove.py  2026-03-29 
14:13:27.000000000 +0200
@@ -7,6 +7,7 @@
 from cleo.helpers import option
 
 from poetry.console.commands.command import Command
+from poetry.utils._compat import is_relative_to
 
 
 if TYPE_CHECKING:
@@ -54,8 +55,8 @@
             self.line(f"Deleted virtualenv: <comment>{venv.path}</comment>")
         if remove_all_envs or is_in_project:
             for venv in manager.list():
-                if not is_in_project or venv.path.is_relative_to(
-                    self.poetry.pyproject_path.parent
+                if not is_in_project or is_relative_to(
+                    venv.path, self.poetry.pyproject_path.parent
                 ):
                     manager.remove_venv(venv.path)
                     self.line(f"Deleted virtualenv: 
<comment>{venv.path}</comment>")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/poetry-2.3.2/src/poetry/console/commands/publish.py 
new/poetry-2.3.3/src/poetry/console/commands/publish.py
--- old/poetry-2.3.2/src/poetry/console/commands/publish.py     2026-02-01 
16:31:39.000000000 +0100
+++ new/poetry-2.3.3/src/poetry/console/commands/publish.py     2026-03-29 
14:13:27.000000000 +0200
@@ -72,13 +72,21 @@
 
         # Building package first, if told
         if self.option("build"):
-            if publisher.files and not self.confirm(
-                f"There are <info>{len(publisher.files)}</info> files ready 
for"
-                " publishing. Build anyway?"
-            ):
-                self.line_error("<error>Aborted!</error>")
+            if publisher.files:
+                if self.io.is_interactive():
+                    if not self.confirm(
+                        f"There are <info>{len(publisher.files)}</info> files 
ready for"
+                        f" publishing in {dist_dir}. Build anyway?"
+                    ):
+                        self.line_error("<error>Aborted!</error>")
 
-                return 1
+                        return 1
+
+                else:
+                    self.line(
+                        f"<warning>Warning: There are 
<info>{len(publisher.files)}</info> files "
+                        f"ready for publishing in {dist_dir}. Build 
anyway!</warning>"
+                    )
 
             self.call("build", args=f"--output {dist_dir}")
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/poetry-2.3.2/src/poetry/console/commands/python/list.py 
new/poetry-2.3.3/src/poetry/console/commands/python/list.py
--- old/poetry-2.3.2/src/poetry/console/commands/python/list.py 2026-02-01 
16:31:39.000000000 +0100
+++ new/poetry-2.3.3/src/poetry/console/commands/python/list.py 2026-03-29 
14:13:27.000000000 +0200
@@ -10,6 +10,7 @@
 
 from poetry.config.config import Config
 from poetry.console.commands.command import Command
+from poetry.utils._compat import is_relative_to
 from poetry.utils.env.python import Python
 
 
@@ -107,9 +108,8 @@
             implementation = implementations.get(
                 pv.implementation.lower(), pv.implementation
             )
-            is_poetry_managed = (
-                pv.executable is None
-                or 
pv.executable.resolve().is_relative_to(python_installation_path)
+            is_poetry_managed = pv.executable is None or is_relative_to(
+                pv.executable.resolve(), python_installation_path
             )
 
             if self.option("managed") and not is_poetry_managed:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/poetry-2.3.2/src/poetry/installation/wheel_installer.py 
new/poetry-2.3.3/src/poetry/installation/wheel_installer.py
--- old/poetry-2.3.2/src/poetry/installation/wheel_installer.py 2026-02-01 
16:31:39.000000000 +0100
+++ new/poetry-2.3.3/src/poetry/installation/wheel_installer.py 2026-03-29 
14:13:27.000000000 +0200
@@ -14,6 +14,7 @@
 
 from poetry.__version__ import __version__
 from poetry.utils._compat import WINDOWS
+from poetry.utils._compat import is_relative_to
 
 
 logger = logging.getLogger(__name__)
@@ -44,7 +45,20 @@
         from installer.utils import copyfileobj_with_hashing
         from installer.utils import make_file_executable
 
-        target_path = Path(self.scheme_dict[scheme]) / path
+        target_dir = Path(self.scheme_dict[scheme]).resolve()
+        target_path = (target_dir / path).resolve()
+
+        # Use is_relative_to() instead of Path.is_relative_to()
+        # because the latter does not work if one of both paths
+        # has a Windows long path prefix and the other path has not.
+        # (A long path prefix may be added when calling resolve().)
+        if not is_relative_to(target_path, target_dir):
+            raise ValueError(
+                f"Attempting to write {path} outside of the target directory\n"
+                f"Target directory: {target_dir}\n"
+                f"Target path: {target_path}"
+            )
+
         if target_path.exists():
             # Contrary to the base library we don't raise an error here since 
it can
             # break pkgutil-style and pkg_resource-style namespace packages.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/poetry-2.3.2/src/poetry/layouts/layout.py 
new/poetry-2.3.3/src/poetry/layouts/layout.py
--- old/poetry-2.3.2/src/poetry/layouts/layout.py       2026-02-01 
16:31:39.000000000 +0100
+++ new/poetry-2.3.3/src/poetry/layouts/layout.py       2026-03-29 
14:13:27.000000000 +0200
@@ -32,7 +32,7 @@
 description = ""
 authors = [
 ]
-license = {}
+license = ""
 readme = ""
 requires-python = ""
 dependencies = [
@@ -158,7 +158,7 @@
             project_content["authors"].append(author)
 
         if self._license:
-            project_content["license"]["text"] = self._license
+            project_content["license"] = self._license
         else:
             project_content.remove("license")
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/poetry-2.3.2/src/poetry/utils/_compat.py 
new/poetry-2.3.3/src/poetry/utils/_compat.py
--- old/poetry-2.3.2/src/poetry/utils/_compat.py        2026-02-01 
16:31:39.000000000 +0100
+++ new/poetry-2.3.3/src/poetry/utils/_compat.py        2026-03-29 
14:13:27.000000000 +0200
@@ -5,6 +5,7 @@
 import warnings
 
 from contextlib import suppress
+from pathlib import Path
 
 
 if sys.version_info < (3, 11):
@@ -52,6 +53,33 @@
         return locale.getencoding()
 
 
+def is_relative_to(path1: Path, path2: Path) -> bool:
+    """
+    Checks if path1 is relative to path2.
+
+    Works also if one of both paths has a Windows long path prefix.
+    A long path prefix may be added when calling Path.resolve().
+    """
+    if WINDOWS:
+        # Work around an issue that is_relative_to() does not work if
+        # one of both paths has a long path prefix and the other path has not.
+        long_path_prefix = "\\\\?\\"
+        long_path_unc_prefix = f"{long_path_prefix}UNC\\"
+
+        def remove_long_path_prefix(path: Path) -> Path:
+            if (path_str := str(path)).startswith(long_path_prefix):
+                if path_str.startswith(long_path_unc_prefix):
+                    path = Path("\\\\" + 
path_str.removeprefix(long_path_unc_prefix))
+                else:
+                    path = Path(path_str.removeprefix(long_path_prefix))
+            return path
+
+        path1 = remove_long_path_prefix(path1)
+        path2 = remove_long_path_prefix(path2)
+
+    return path1.is_relative_to(path2)
+
+
 def __getattr__(name: str) -> object:
     if name == "metadata":
         warnings.warn(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/poetry-2.3.2/src/poetry/utils/authenticator.py 
new/poetry-2.3.3/src/poetry/utils/authenticator.py
--- old/poetry-2.3.2/src/poetry/utils/authenticator.py  2026-02-01 
16:31:39.000000000 +0100
+++ new/poetry-2.3.3/src/poetry/utils/authenticator.py  2026-03-29 
14:13:27.000000000 +0200
@@ -189,13 +189,15 @@
         self, method: str, url: str, raise_for_status: bool = True, **kwargs: 
Any
     ) -> requests.Response:
         headers = kwargs.get("headers")
-        request = requests.Request(method, url, headers=headers)
         credential = self.get_credentials_for_url(url)
 
+        auth = None
         if credential.username is not None or credential.password is not None:
-            request = requests.auth.HTTPBasicAuth(
+            auth = requests.auth.HTTPBasicAuth(
                 credential.username or "", credential.password or ""
-            )(request)
+            )
+
+        request = requests.Request(method, url, headers=headers, auth=auth)
 
         session = self.get_session(url=url)
         prepared_request = session.prepare_request(request)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/poetry-2.3.2/src/poetry/utils/env/env_manager.py 
new/poetry-2.3.3/src/poetry/utils/env/env_manager.py
--- old/poetry-2.3.2/src/poetry/utils/env/env_manager.py        2026-02-01 
16:31:39.000000000 +0100
+++ new/poetry-2.3.3/src/poetry/utils/env/env_manager.py        2026-03-29 
14:13:27.000000000 +0200
@@ -125,7 +125,7 @@
         if self.use_in_project_venv():
             create = False
             venv = self.in_project_venv
-            if venv.exists():
+            if venv.is_dir():
                 # We need to check if the patch version is correct
                 _venv = VirtualEnv(venv)
                 current_patch = ".".join(str(v) for v in 
_venv.version_info[:3])
@@ -159,7 +159,7 @@
 
         # Create if needed
         if not venv.exists() or create:
-            in_venv = os.environ.get("VIRTUAL_ENV") is not None
+            in_venv = bool(os.environ.get("VIRTUAL_ENV"))
             if in_venv or not venv.exists():
                 create = True
 
@@ -214,7 +214,9 @@
         conda_env_name = os.environ.get("CONDA_DEFAULT_ENV")
         # It's probably not a good idea to pollute Conda's global "base" env, 
since
         # most users have it activated all the time.
-        in_venv = env_prefix is not None and conda_env_name != "base"
+        # Treat an empty env_prefix as if no virtualenv is active, since conda
+        # can leave CONDA_PREFIX set to an empty string after deactivation.
+        in_venv = bool(env_prefix) and conda_env_name != "base"
 
         if not in_venv or env is not None:
             # Checking if a local virtualenv exists
@@ -249,14 +251,8 @@
 
             return VirtualEnv(venv)
 
-        if env_prefix is not None:
-            prefix = Path(env_prefix)
-            base_prefix = None
-        else:
-            prefix = Path(sys.prefix)
-            base_prefix = self.get_base_prefix()
-
-        return VirtualEnv(prefix, base_prefix)
+        assert env_prefix
+        return VirtualEnv(Path(env_prefix))
 
     def list(self, name: str | None = None) -> list[VirtualEnv]:
         if name is None:
@@ -456,7 +452,7 @@
                     f"Invalid template string in 'virtualenvs.prompt' setting: 
{e}"
                 ) from e
 
-        if not venv.exists():
+        if not venv.is_dir():
             if create_venv is False:
                 self._io.write_error_line(
                     "<fg=black;bg=yellow>"
@@ -467,6 +463,12 @@
 
                 return self.get_system_env()
 
+            if venv.is_file():
+                self._io.write_error_line(
+                    f"<warning>{venv} is not a virtual environment but a file. 
Removing it.</warning>"
+                )
+                venv.unlink()
+
             self._io.write_error_line(
                 f"Creating virtualenv <c1>{name}</> in"
                 f" {venv_path if not WINDOWS else 
get_real_windows_path(venv_path)!s}"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/poetry-2.3.2/src/poetry/utils/env/python/manager.py 
new/poetry-2.3.3/src/poetry/utils/env/python/manager.py
--- old/poetry-2.3.2/src/poetry/utils/env/python/manager.py     2026-02-01 
16:31:39.000000000 +0100
+++ new/poetry-2.3.3/src/poetry/utils/env/python/manager.py     2026-03-29 
14:13:27.000000000 +0200
@@ -23,6 +23,7 @@
 from poetry.core.constraints.version import VersionConstraint
 from poetry.core.constraints.version import parse_constraint
 
+from poetry.utils._compat import is_relative_to
 from poetry.utils.env.python.exceptions import 
NoCompatiblePythonVersionFoundError
 from poetry.utils.env.python.providers import PoetryPythonPathProvider
 from poetry.utils.env.python.providers import ShutilWhichPythonProvider
@@ -84,10 +85,10 @@
     @classmethod
     def find_all(cls) -> Iterator[Python]:
         venv_path: Path | None = (
-            Path(os.environ["VIRTUAL_ENV"]) if "VIRTUAL_ENV" in os.environ 
else None
+            Path(venv) if (venv := os.environ.get("VIRTUAL_ENV")) else None
         )
         for python in findpython.find_all():
-            if venv_path and python.executable.is_relative_to(venv_path):
+            if venv_path and is_relative_to(python.executable, venv_path):
                 continue
             yield cls(python=python)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/poetry-2.3.2/src/poetry/vcs/git/backend.py 
new/poetry-2.3.3/src/poetry/vcs/git/backend.py
--- old/poetry-2.3.2/src/poetry/vcs/git/backend.py      2026-02-01 
16:31:39.000000000 +0100
+++ new/poetry-2.3.3/src/poetry/vcs/git/backend.py      2026-03-29 
14:13:27.000000000 +0200
@@ -1,5 +1,6 @@
 from __future__ import annotations
 
+import contextlib
 import dataclasses
 import logging
 import os
@@ -20,6 +21,7 @@
 from dulwich.errors import NotGitRepository
 from dulwich.file import FileLocked
 from dulwich.index import IndexEntry
+from dulwich.object_store import peel_sha
 from dulwich.objects import ObjectID
 from dulwich.protocol import PEELED_TAG_SUFFIX
 from dulwich.refs import Ref
@@ -63,8 +65,9 @@
     "- the remote ({remote}) you have specified\n"
     "    - was misspelled\n"
     "    - does not exist\n"
-    "    - requires credentials that were either not configured or is 
incorrect\n"
-    "    - is in accessible due to network issues"
+    "    - requires credentials that were either not configured or are 
incorrect\n"
+    "    - contains Git submodules that require credentials that were either 
not configured or are incorrect\n"
+    "    - is inaccessible due to network issues"
 )
 ERROR_MESSAGE_FILE_LOCK = (
     "- another process is holding the file lock\n"
@@ -96,7 +99,7 @@
         Resolve the ref using the provided remote refs.
         """
         self._normalise(remote_refs=remote_refs, repo=repo)
-        self._set_head(remote_refs=remote_refs)
+        self._set_head(remote_refs=remote_refs, repo=repo)
 
     def _normalise(self, remote_refs: FetchPackResult, repo: Repo) -> None:
         """
@@ -142,7 +145,7 @@
                 self.revision = sha.decode("utf-8")
                 return
 
-    def _set_head(self, remote_refs: FetchPackResult) -> None:
+    def _set_head(self, remote_refs: FetchPackResult, repo: Repo) -> None:
         """
         Internal helper method to populate ref and set it's sha as the 
remote's head
         and default ref.
@@ -165,6 +168,15 @@
                 )
             head = remote_refs.refs[self.ref]
 
+            # Peel tag objects to get the underlying commit SHA.
+            # Annotated tags are Tag objects, not Commit objects. Operations 
like
+            # reset_index() expect HEAD to point to a Commit, so we must peel 
tags
+            # to extract the commit SHA they reference.
+            # Object not in store yet will be handled during fetch
+            if head is not None:
+                with contextlib.suppress(KeyError):
+                    head = peel_sha(repo.object_store, head)[1].id
+
         remote_refs.refs[self.ref] = remote_refs.refs[Ref(b"HEAD")] = head
 
     @property
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/poetry-2.3.2/tests/console/commands/conftest.py 
new/poetry-2.3.3/tests/console/commands/conftest.py
--- old/poetry-2.3.2/tests/console/commands/conftest.py 2026-02-01 
16:31:39.000000000 +0100
+++ new/poetry-2.3.3/tests/console/commands/conftest.py 2026-03-29 
14:13:27.000000000 +0200
@@ -30,7 +30,7 @@
 authors = [
     {name = "Your Name",email = "[email protected]"}
 ]
-license = {text = "MIT"}
+license = "MIT"
 readme = "README.md"
 requires-python = ">=3.6"
 """
@@ -55,7 +55,7 @@
 authors = [
     {name = "Your Name",email = "[email protected]"}
 ]
-license = {text = "MIT"}
+license = "MIT"
 readme = "README.md"
 requires-python = ">=3.6"
 dependencies = [
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/poetry-2.3.2/tests/console/commands/test_init.py 
new/poetry-2.3.3/tests/console/commands/test_init.py
--- old/poetry-2.3.2/tests/console/commands/test_init.py        2026-02-01 
16:31:39.000000000 +0100
+++ new/poetry-2.3.3/tests/console/commands/test_init.py        2026-03-29 
14:13:27.000000000 +0200
@@ -145,7 +145,7 @@
 authors = [
     {name = "Your Name",email = "[email protected]"}
 ]
-license = {text = "MIT"}
+license = "MIT"
 requires-python = ">=3.6"
 dependencies = [
     "pendulum (>=2.0.0,<3.0.0)",
@@ -201,7 +201,7 @@
 authors = [
     {name = "Your Name",email = "[email protected]"}
 ]
-license = {text = "MIT"}
+license = "MIT"
 requires-python = ">=3.6"
 """
 
@@ -269,7 +269,7 @@
 authors = [
     {name = "Your Name",email = "[email protected]"}
 ]
-license = {text = "MIT"}
+license = "MIT"
 requires-python = ">=3.6"
 dependencies = [
     "demo @ git+https://github.com/demo/demo.git";
@@ -364,7 +364,7 @@
 authors = [
     {name = "Your Name",email = "[email protected]"}
 ]
-license = {text = "MIT"}
+license = "MIT"
 requires-python = ">=3.6"
 dependencies = [
     "demo @ git+https://github.com/demo/demo.git@develop";
@@ -412,7 +412,7 @@
 authors = [
     {name = "Your Name",email = "[email protected]"}
 ]
-license = {text = "MIT"}
+license = "MIT"
 requires-python = ">=3.6"
 dependencies = [
     "demo @ git+https://github.com/demo/pyproject-demo.git";
@@ -467,7 +467,7 @@
 authors = [
     {{name = "Your Name",email = "[email protected]"}}
 ]
-license = {{text = "MIT"}}
+license = "MIT"
 requires-python = ">=3.6"
 dependencies = [
     "demo @ {demo_uri}"
@@ -521,7 +521,7 @@
 authors = [
     {{name = "Your Name",email = "[email protected]"}}
 ]
-license = {{text = "MIT"}}
+license = "MIT"
 requires-python = ">=3.6"
 dependencies = [
     "demo @ {demo_uri}"
@@ -576,7 +576,7 @@
 authors = [
     {{name = "Your Name",email = "[email protected]"}}
 ]
-license = {{text = "MIT"}}
+license = "MIT"
 requires-python = ">=3.6"
 dependencies = [
     "demo @ {demo_uri}"
@@ -623,7 +623,7 @@
 authors = [
     {name = "Your Name",email = "[email protected]"}
 ]
-license = {text = "MIT"}
+license = "MIT"
 requires-python = ">=3.8"
 dependencies = [
     "foo (==1.19.2)",
@@ -660,7 +660,7 @@
 authors = [
     {name = "Your Name",email = "[email protected]"}
 ]
-license = {text = "MIT"}
+license = "MIT"
 requires-python = ">=3.6"
 """
 
@@ -691,7 +691,7 @@
 authors = [
     {name = "Your Name",email = "[email protected]"}
 ]
-license = {text = "MIT"}
+license = "MIT"
 requires-python = ">=3.6"
 dependencies = [
     "pendulum (>=2.0.0,<3.0.0)"
@@ -733,7 +733,7 @@
 authors = [
     {name = "Your Name",email = "[email protected]"}
 ]
-license = {text = "MIT"}
+license = "MIT"
 requires-python = ">=3.6"
 dependencies = [
     "pendulum (>=2.0.0,<3.0.0)",
@@ -768,7 +768,7 @@
 authors = [
     {name = "Your Name",email = "[email protected]"}
 ]
-license = {text = "MIT"}
+license = "MIT"
 requires-python = ">=3.6"
 dependencies = [
 ]
@@ -814,7 +814,7 @@
 authors = [
     {name = "Your Name",email = "[email protected]"}
 ]
-license = {text = "MIT"}
+license = "MIT"
 requires-python = ">=3.6"
 dependencies = [
 ]
@@ -861,7 +861,7 @@
 authors = [
     {name = "Foo Bar",email = "[email protected]"}
 ]
-license = {text = "MIT"}
+license = "MIT"
 requires-python = ">=3.8"
 dependencies = [
     "pendulum (>=2.0.0,<3.0.0)"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/poetry-2.3.2/tests/console/commands/test_publish.py 
new/poetry-2.3.3/tests/console/commands/test_publish.py
--- old/poetry-2.3.2/tests/console/commands/test_publish.py     2026-02-01 
16:31:39.000000000 +0100
+++ new/poetry-2.3.3/tests/console/commands/test_publish.py     2026-03-29 
14:13:27.000000000 +0200
@@ -5,6 +5,7 @@
 from pathlib import Path
 from typing import TYPE_CHECKING
 from typing import NoReturn
+from unittest.mock import PropertyMock
 
 import pytest
 import requests
@@ -215,3 +216,31 @@
     assert "Publishing simple-project (1.2.3) to PyPI" in output
     assert "- Uploading simple_project-1.2.3.tar.gz" in error
     assert "- Uploading simple_project-1.2.3-py2.py3-none-any.whl" in error
+
+
+def test_publish_build_no_interaction_skips_confirmation(
+    app_tester: ApplicationTester, mocker: MockerFixture
+) -> None:
+    mocker.patch(
+        "poetry.publishing.publisher.Publisher.files",
+        new_callable=PropertyMock,
+        return_value=[Path("dist/simple_project-1.2.3-py2.py3-none-any.whl")],
+    )
+    confirm = 
mocker.patch("poetry.console.commands.publish.PublishCommand.confirm")
+    command_call = 
mocker.patch("poetry.console.commands.publish.PublishCommand.call")
+    publisher_publish = mocker.patch("poetry.publishing.Publisher.publish")
+
+    exit_code = app_tester.execute("publish --build --no-interaction 
--dry-run")
+
+    assert exit_code == 0
+    output = app_tester.io.fetch_output()
+    error = app_tester.io.fetch_error()
+
+    confirm.assert_not_called()
+    assert "Build anyway?" not in output
+    assert "Build anyway?" not in error
+    assert (
+        "Warning: There are 1 files ready for publishing in dist. Build 
anyway!"
+    ) in output
+    command_call.assert_called_once_with("build", args="--output dist")
+    assert publisher_publish.call_count == 1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/poetry-2.3.2/tests/installation/test_wheel_installer.py 
new/poetry-2.3.3/tests/installation/test_wheel_installer.py
--- old/poetry-2.3.2/tests/installation/test_wheel_installer.py 2026-02-01 
16:31:39.000000000 +0100
+++ new/poetry-2.3.3/tests/installation/test_wheel_installer.py 2026-03-29 
14:13:27.000000000 +0200
@@ -81,3 +81,51 @@
         assert not list(cache_dir.glob("*.opt-2.pyc"))
     else:
         assert not cache_dir.exists()
+
+
+def test_install_dir_is_symlink(tmp_path: Path, demo_wheel: Path) -> None:
+    target_dir = tmp_path / "target"
+    target_dir.mkdir()
+    symlink_dir = tmp_path / "symlink"
+    symlink_dir.symlink_to(target_dir, target_is_directory=True)
+
+    env = MockEnv(path=symlink_dir)
+
+    installer = WheelInstaller(env)
+    installer.install(demo_wheel)
+
+    assert (Path(env.paths["purelib"]) / "demo").exists()
+
+
[email protected]
+def wheel_with_path_traversal(tmp_path: Path) -> Path:
+    import zipfile
+
+    wheel = tmp_path / "traversal-0.1-py3-none-any.whl"
+    files = {
+        "traversal/__init__.py": b"",
+        "../../traversal.txt": b"",
+        "traversal-0.1.dist-info/WHEEL": (
+            b"Wheel-Version: 1.0\nRoot-Is-Purelib: true\nTag: py3-none-any\n"
+        ),
+        "traversal-0.1.dist-info/METADATA": (
+            b"Metadata-Version: 2.1\nName: traversal\nVersion: 0.1\n"
+        ),
+    }
+    files["traversal-0.1.dist-info/RECORD"] = (
+        "\n".join([f"{k},," for k in files] + 
["traversal-0.1.dist-info/RECORD,,"])
+        + "\n"
+    ).encode()
+
+    with zipfile.ZipFile(wheel, "w") as z:
+        for k, v in files.items():
+            z.writestr(k, v)
+
+    return wheel
+
+
+def test_path_traversal(env: MockEnv, wheel_with_path_traversal: Path) -> None:
+    installer = WheelInstaller(env)
+    with pytest.raises(ValueError):
+        installer.install(wheel_with_path_traversal)
+    assert not (env.path.parent / "traversal.txt").exists()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/poetry-2.3.2/tests/utils/env/conftest.py 
new/poetry-2.3.3/tests/utils/env/conftest.py
--- old/poetry-2.3.2/tests/utils/env/conftest.py        2026-02-01 
16:31:39.000000000 +0100
+++ new/poetry-2.3.3/tests/utils/env/conftest.py        2026-03-29 
14:13:27.000000000 +0200
@@ -4,6 +4,8 @@
 
 import pytest
 
+from cleo.io.buffered_io import BufferedIO
+
 from poetry.utils.env import EnvManager
 
 
@@ -19,5 +21,10 @@
 
 
 @pytest.fixture
-def manager(poetry: Poetry) -> EnvManager:
-    return EnvManager(poetry)
+def io() -> BufferedIO:
+    return BufferedIO()
+
+
[email protected]
+def manager(poetry: Poetry, io: BufferedIO) -> EnvManager:
+    return EnvManager(poetry, io)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/poetry-2.3.2/tests/utils/env/test_env_manager.py 
new/poetry-2.3.3/tests/utils/env/test_env_manager.py
--- old/poetry-2.3.2/tests/utils/env/test_env_manager.py        2026-02-01 
16:31:39.000000000 +0100
+++ new/poetry-2.3.3/tests/utils/env/test_env_manager.py        2026-03-29 
14:13:27.000000000 +0200
@@ -32,6 +32,7 @@
     from collections.abc import Iterator
     from unittest.mock import MagicMock
 
+    from cleo.io.buffered_io import BufferedIO
     from pytest import LogCaptureFixture
     from pytest_mock import MockerFixture
 
@@ -470,6 +471,56 @@
     assert not envs_file.exists()
 
 
+def test_activate_with_in_project_setting_if_venv_is_file(
+    manager: EnvManager,
+    poetry: Poetry,
+    io: BufferedIO,
+    config: Config,
+    tmp_path: Path,
+    mocker: MockerFixture,
+    venv_flags_default: dict[str, bool],
+    mocked_python_register: MockedPythonRegister,
+) -> None:
+    if "VIRTUAL_ENV" in os.environ:
+        del os.environ["VIRTUAL_ENV"]
+
+    config.merge(
+        {
+            "virtualenvs": {
+                "path": str(tmp_path / "virtualenvs"),
+                "in-project": True,
+            }
+        }
+    )
+
+    mocked_python_register("3.7.1")
+    m = mocker.patch("poetry.utils.env.EnvManager.build_venv")
+
+    venv_path = poetry.file.path.parent / ".venv"
+    assert not venv_path.exists()
+    venv_path.touch()
+    assert venv_path.is_file()
+
+    manager.activate("python3.7")
+
+    m.assert_called_with(
+        poetry.file.path.parent / ".venv",
+        executable=Path("/usr/bin/python3.7"),
+        flags=venv_flags_default,
+        prompt="simple-project-py3.7",
+    )
+
+    envs_file = TOMLFile(tmp_path / "virtualenvs" / "envs.toml")
+    assert not envs_file.exists()
+
+    # The .venv file is removed, but no .venv is created because we mocked 
build_venv.
+    assert not venv_path.exists()
+    assert (
+        f"{venv_path} is not a virtual environment but a file. Removing it."
+        in io.fetch_error()
+    )
+
+
 def test_deactivate_non_activated_but_existing(
     tmp_path: Path,
     manager: EnvManager,
@@ -577,6 +628,33 @@
     assert env.base == Path(sys.base_prefix)
 
 
[email protected]("env_var", ["VIRTUAL_ENV", "CONDA_PREFIX"])
+def test_get_ignores_empty_env_prefix(
+    manager: EnvManager,
+    poetry: Poetry,
+    in_project_venv_dir: Path,
+    env_var: str,
+    mocker: MockerFixture,
+) -> None:
+    """An empty VIRTUAL_ENV or CONDA_PREFIX should be treated as unset.
+
+    After ``conda deactivate``, conda can leave CONDA_PREFIX set to an
+    empty string.  Poetry should not consider that as an active
+    virtualenv and should fall back to the in-project .venv instead.
+
+    See: https://github.com/python-poetry/poetry/issues/10770
+    """
+    os.environ.pop("VIRTUAL_ENV", None)
+    os.environ.pop("CONDA_PREFIX", None)
+    os.environ[env_var] = ""
+    mocker.patch(
+        "poetry.utils.env.virtual_env.VirtualEnv.__init__",
+        lambda self, *args, **kwargs: setattr(self, "_path", args[0]),
+    )
+    venv = manager.get()
+    assert venv.path == in_project_venv_dir
+
+
 def test_list(
     tmp_path: Path,
     manager: EnvManager,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/poetry-2.3.2/tests/utils/test_compat.py 
new/poetry-2.3.3/tests/utils/test_compat.py
--- old/poetry-2.3.2/tests/utils/test_compat.py 1970-01-01 01:00:00.000000000 
+0100
+++ new/poetry-2.3.3/tests/utils/test_compat.py 2026-03-29 14:13:27.000000000 
+0200
@@ -0,0 +1,71 @@
+from __future__ import annotations
+
+import sys
+
+from pathlib import Path
+
+import pytest
+
+from poetry.utils._compat import is_relative_to
+
+
[email protected](
+    ("path1", "path2", "expected"),
+    [
+        ("a", "a", True),
+        ("a/b", "a/b", True),
+        ("a/b", "a", True),
+        ("a", "a/b", False),
+        ("a/b/c/d", "a/b", True),
+        ("a/b", "a/b/c/d", False),
+    ],
+)
+def test_is_relative_to(path1: str, path2: str, expected: bool) -> None:
+    assert is_relative_to(Path(path1), Path(path2)) is expected
+
+
[email protected](
+    ("path1", "path2", "expected"),
+    [
+        ("/", "/", True),
+        ("/a/b", "/a/b", True),
+        ("/a/b", "/a", True),
+        ("/a", "/a/b", False),
+        ("/a/b/c/d", "/a/b", True),
+        ("/a/b", "/a/b/c/d", False),
+    ],
+)
[email protected](sys.platform == "win32", reason="non-Windows paths")
+def test_is_relative_to_non_win32(path1: str, path2: str, expected: bool) -> 
None:
+    assert is_relative_to(Path(path1), Path(path2)) is expected
+
+
[email protected](
+    ("path1", "path2", "expected"),
+    [
+        ("C:\\", "C:\\", True),
+        (r"C:\a\b", r"C:\a\b", True),
+        (r"C:\a\b", r"C:\a", True),
+        (r"C:\a", r"C:\a\b", False),
+        (r"C:\a\b\c\d", r"C:\a\b", True),
+        (r"C:\a\b", r"C:\a\b\c\d", False),
+        (r"C:\a\b", r"D:\a", False),
+        (r"C:\a\b", "D:\\", False),
+        (r"\\server\a\b", r"\\server\a", True),
+        (r"\\server\a", r"\\server\a\b", False),
+        (r"\\server2\a\b", r"\\server\a", False),
+        # long path prefix
+        (r"\\?\C:\a\b", r"\\?\C:\a", True),
+        (r"\\?\C:\a\b", r"C:\a", True),
+        (r"C:\a\b", r"\\?\C:\a", True),
+        (r"\\?\C:\a", r"\\?\C:\a\b", False),
+        # long path UNC prefix
+        (r"\\?\UNC\server\a\b", r"\\?\UNC\server\a", True),
+        (r"\\?\UNC\server\a\b", r"\\server\a", True),
+        (r"\\server\a\b", r"\\?\UNC\server\a", True),
+        (r"\\?\UNC\server\a", r"\\?\UNC\server\a\b", False),
+    ],
+)
[email protected](sys.platform != "win32", reason="Windows paths")
+def test_is_relative_to_win32(path1: str, path2: str, expected: bool) -> None:
+    assert is_relative_to(Path(path1), Path(path2)) is expected
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/poetry-2.3.2/tests/vcs/git/test_backend.py 
new/poetry-2.3.3/tests/vcs/git/test_backend.py
--- old/poetry-2.3.2/tests/vcs/git/test_backend.py      2026-02-01 
16:31:39.000000000 +0100
+++ new/poetry-2.3.3/tests/vcs/git/test_backend.py      2026-03-29 
14:13:27.000000000 +0200
@@ -8,6 +8,8 @@
 import pytest
 
 from dulwich.client import FetchPackResult
+from dulwich.refs import HEADREF
+from dulwich.refs import Ref
 from dulwich.repo import Repo
 
 from poetry.console.exceptions import PoetryRuntimeError
@@ -290,3 +292,135 @@
         f"Try again later or remove the {tag_ref_lock} manually"
         " if you are sure no other process is holding it."
     )
+
+
[email protected]_git_mock
+def test_clone_annotated_tag(tmp_path: Path) -> None:
+    """Test cloning at an annotated tag (issue #10658)."""
+    from dulwich import porcelain
+    from dulwich.objects import Commit
+
+    # Create a source repository with an annotated tag
+    source_path = tmp_path / "source-repo"
+    source_path.mkdir()
+    repo = Repo.init(str(source_path))
+
+    # Create initial commit
+    test_file = source_path / "test.txt"
+    test_file.write_text("test content", encoding="utf-8")
+    porcelain.add(repo, str(test_file))
+    expected_commit_sha = porcelain.commit(
+        repo,
+        message=b"Initial commit",
+        author=b"Test <[email protected]>",
+        committer=b"Test <[email protected]>",
+    )
+
+    # Create an annotated tag
+    porcelain.tag_create(
+        repo,
+        tag=b"v1.0.0",
+        message=b"Release 1.0.0",
+        author=b"Test <[email protected]>",
+        annotated=True,
+    )
+
+    # Clone at the annotated tag
+    source_root_dir = tmp_path / "clone-root"
+    source_root_dir.mkdir()
+    cloned_repo = Git.clone(
+        url=source_path.as_uri(),
+        source_root=source_root_dir,
+        name="clone-test",
+        tag="v1.0.0",
+    )
+
+    # Verify HEAD points to a commit, not a tag object
+    head_sha = cloned_repo.refs[HEADREF]
+    head_obj = cloned_repo.object_store[head_sha]
+    assert isinstance(head_obj, Commit), (
+        f"HEAD should point to a Commit, got {type(head_obj).__name__}"
+    )
+    # Verify it's the correct commit
+    assert head_sha == expected_commit_sha, (
+        f"HEAD should point to the expected commit 
{expected_commit_sha.hex()}, "
+        f"got {head_sha.hex()}"
+    )
+
+    # Verify the clone succeeded and files are present
+    clone_dir = source_root_dir / "clone-test"
+    assert (clone_dir / ".git").is_dir()
+    assert (clone_dir / "test.txt").exists()
+    assert (clone_dir / "test.txt").read_text(encoding="utf-8") == "test 
content"
+
+
[email protected]_git_mock
+def test_clone_nested_annotated_tags(tmp_path: Path) -> None:
+    """Test cloning at a tag that points to another tag (nested tags)."""
+    from dulwich import porcelain
+    from dulwich.objects import Commit
+    from dulwich.objects import Tag
+
+    # Create a source repository with nested annotated tags
+    source_path = tmp_path / "source-repo"
+    source_path.mkdir()
+    repo = Repo.init(str(source_path))
+
+    # Create initial commit
+    test_file = source_path / "test.txt"
+    test_file.write_text("nested tag test", encoding="utf-8")
+    porcelain.add(repo, paths=[b"test.txt"])
+    commit_sha = porcelain.commit(
+        repo,
+        message=b"Initial commit",
+        committer=b"Test <[email protected]>",
+        author=b"Test <[email protected]>",
+    )
+
+    # Create first annotated tag pointing to the commit
+    tag1 = Tag()
+    tag1.name = b"v1.0.0"
+    tag1.object = (Commit, commit_sha)
+    tag1.message = b"First tag"
+    tag1.tag_time = 1234567890
+    tag1.tag_timezone = 0
+    tag1.tagger = b"Test <[email protected]>"
+    repo.object_store.add_object(tag1)
+    repo.refs[Ref(b"refs/tags/v1.0.0")] = tag1.id
+
+    # Create second annotated tag pointing to the first tag
+    tag2 = Tag()
+    tag2.name = b"v1.0.0-release"
+    tag2.object = (Tag, tag1.id)
+    tag2.message = b"Second tag (points to first tag)"
+    tag2.tag_time = 1234567891
+    tag2.tag_timezone = 0
+    tag2.tagger = b"Test <[email protected]>"
+    repo.object_store.add_object(tag2)
+    repo.refs[Ref(b"refs/tags/v1.0.0-release")] = tag2.id
+
+    # Clone at the nested tag
+    source_root_dir = tmp_path / "clone-root"
+    source_root_dir.mkdir()
+    cloned_repo = Git.clone(
+        url=source_path.as_uri(),
+        source_root=source_root_dir,
+        name="clone-test",
+        tag="v1.0.0-release",
+    )
+
+    # Verify HEAD points to a commit, not a tag object
+    head_sha = cloned_repo.refs[HEADREF]
+    head_obj = cloned_repo.object_store[head_sha]
+    assert isinstance(head_obj, Commit), (
+        f"HEAD should point to a Commit (peeling nested tags), got 
{type(head_obj).__name__}"
+    )
+
+    # Verify it's the correct commit
+    assert head_sha == commit_sha
+
+    # Verify the clone succeeded and files are present
+    clone_dir = source_root_dir / "clone-test"
+    assert (clone_dir / ".git").is_dir()
+    assert (clone_dir / "test.txt").exists()
+    assert (clone_dir / "test.txt").read_text(encoding="utf-8") == "nested tag 
test"

Reply via email to