Skip to content

Malformed installpkg artifact raises an internal error #4230

Closed

Description

@gaborbernat

Malformed installpkg artifact raises an internal error.

Affected code

``VenvCmdBuilder.extract_install_info() in src/tox/tox_env/python/virtual_env/package/cmd_builder.py at report commit 7988418936b730b19981ba934dc8b57186d6b957.

Mechanism

VenvCmdBuilder.extract_install_info parses the selected artifact without handling its parse errors. A malformed artifact propagates an internal exception.

Reproduction

The reproducer returned BUG at the report commit and at main commit d1963d076c78ed4c03c6f8c6e8fbaf9163e21f48 in a disposable container without network access.

Save the Dockerfile below in the finding directory. Build the source image from main commit d1963d076c78ed4c03c6f8c6e8fbaf9163e21f48, then run:

main_checkout=/path/to/tox-main
docker build -f Dockerfile.repro -t tox-sec-head "$main_checkout"

docker run --rm --network=none -u 0 -w /src -v "$PWD/repro:/tmp/repro:ro,z" -v "$PWD/repro.d:/tmp/repro.d:ro,z" tox-sec-head /tmp/repro
a: internal error
  File "/src/src/tox/tox_env/python/virtual_env/package/cmd_builder.py", line 117, in extract_install_info
tarfile.ReadError: not a gzip file
  a: FAIL code 2 (0.08 seconds)
--- tox run -e a --installpkg no_members-1.0.tar.gz  ->  exit code 2
a: internal error
  File "/src/src/tox/tox_env/python/virtual_env/package/cmd_builder.py", line 122, in extract_install_info
StopIteration
  a: FAIL code 2 (0.08 seconds)

reported as tox internal error: ['bad_requires-1.0-py3-none-any.whl', 'no_metadata-1.0-py3-none-any.whl', 'not_a_zip-1.0-py3-none-any.whl', 'not_gzip-1.0.tar.gz', 'no_members-1.0.tar.gz']
BUG

Expected: A malformed selected artifact must produce a configuration error.

repro

#!/usr/bin/env python3
import os
import shutil
import subprocess
import sys
from pathlib import Path

REPRO_D = Path("/tmp/repro.d")
work = Path("/tmp/installpkg-malformed")
shutil.rmtree(work, ignore_errors=True)
artifacts = work / "artifacts"
artifacts.mkdir(parents=True)


def tox_run_installpkg(artifact):
    project = work / f"project-{artifact}"
    project.mkdir()
    shutil.copy(REPRO_D / "tox.toml", project)
    tox = subprocess.run(
        ["/opt/venv/bin/tox", "run", "-e", "a", "--installpkg", artifacts / artifact],
        cwd=project,
        env={**os.environ, "PIP_NO_INDEX": "1"},  # pip is never reached here; if it were, fail instead of going online
        capture_output=True,
        text=True,
        timeout=120,
    )
    print(f"--- tox run -e a --installpkg {artifact}  ->  exit code {tox.returncode}")
    return tox.returncode, (tox.stdout + tox.stderr).splitlines()


# the artifact producer's part
subprocess.run([sys.executable, REPRO_D / "make_malformed_artifacts.py", artifacts], check=True)

# reference: the malformed wheel tox does check for is rejected as "a: failed with <reason>", exit code 1
_, lines = tox_run_installpkg("no_dist_info-1.0-py3-none-any.whl")
print("\n".join(lines))

# trigger: each of these lets a parse error escape from extract_install_info()
escaping_exception = {
    "bad_requires-1.0-py3-none-any.whl": "packaging.requirements.InvalidRequirement",
    "no_metadata-1.0-py3-none-any.whl": "importlib.metadata.MetadataNotFound",
    "not_a_zip-1.0-py3-none-any.whl": "zipfile.BadZipFile",
    "not_gzip-1.0.tar.gz": "tarfile.ReadError",
    "no_members-1.0.tar.gz": "StopIteration",
}
reported_as_internal_error = []
for artifact, exception in escaping_exception.items():
    code, lines = tox_run_installpkg(artifact)
    frame = [line for line in lines if line.endswith("in extract_install_info")]
    raised = [line for line in lines if line.startswith(exception)]
    print("\n".join(line for line in lines if line.lstrip().startswith("a:") or line in frame + raised))
    if code == 2 and "a: internal error" in lines and frame and raised:
        reported_as_internal_error.append(artifact)

# check: a rejected artifact must give "a: failed with <reason>" and exit code 1, not an internal error and a traceback
print()
print("reported as tox internal error:", reported_as_internal_error)
print("BUG" if reported_as_internal_error else "OK")

repro.d/make_malformed_artifacts.py

#!/usr/bin/env python3
import sys
import tarfile
import zipfile
from pathlib import Path

out = Path(sys.argv[1])

with zipfile.ZipFile(out / "bad_requires-1.0-py3-none-any.whl", "w") as wheel:
    wheel.writestr(
        "bad_requires-1.0.dist-info/METADATA",
        "Metadata-Version: 2.1\nName: bad_requires\nVersion: 1.0\nRequires-Dist: requests => 2.0\n",  # "=>" is no operator
    )

with zipfile.ZipFile(out / "no_metadata-1.0-py3-none-any.whl", "w") as wheel:
    wheel.writestr("no_metadata-1.0.dist-info/WHEEL", "Wheel-Version: 1.0\n")

(out / "not_a_zip-1.0-py3-none-any.whl").write_bytes(b"not a zip archive\n")

(out / "not_gzip-1.0.tar.gz").write_bytes(b"not a gzip stream\n")

with tarfile.open(out / "no_members-1.0.tar.gz", "w:gz"):
    pass

# the one malformed wheel tox does check for
with zipfile.ZipFile(out / "no_dist_info-1.0-py3-none-any.whl", "w") as wheel:
    wheel.writestr("no_dist_info/__init__.py", "")

repro.d/tox.toml

[env.a]
commands = [["python", "-c", "print('tests would run here')"]]

Dockerfile.repro (test harness)

FROM python:3.15-bookworm
ENV DEBIAN_FRONTEND=noninteractive \
    PIP_DISABLE_PIP_VERSION_CHECK=1

RUN apt-get update && apt-get install -y --no-install-recommends man-db passwd \
    && rm -rf /var/lib/apt/lists/* \
    && useradd --create-home --shell /bin/bash scanner-test

RUN python -m venv /opt/venv
ENV PATH=/opt/venv/bin:$PATH

COPY . /src
WORKDIR /src

RUN pip install --upgrade pip \
    && { git describe --tags >/dev/null 2>&1 || export SETUPTOOLS_SCM_PRETEND_VERSION=0.0.0; } \
    && pip install -e '.[completion]' --group test \
    && pip wheel --no-deps --wheel-dir /opt/wheels .

RUN chown -R scanner-test:scanner-test /src && git config --global --add safe.directory /src

Impact

A malformed artifact selected by --installpkg raises an internal error instead of a configuration error. Reproducibility is moderate and exposure is niche because the selected installpkg artifact must be malformed.

Credits

Anthropic OSS Scanner, ANT-2026-3BMGTL6L.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bug:normalaffects many people or has quite an impact

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions