PyPI / setuptools / 84.2.0

setuptools 84.2.0

Source
https://github.com/pypa/setuptools
Tag scanned
v84.2.0
Compared with
v84.1.0 (0 signals introduced since)
Files
415 scanned, 127 skipped (binary, oversized, or unrecognised)
Signals
1 critical · 0 warn · 58 info
Scan time
17.4 s
LLM review
Reviewed by claude-haiku-5-5 (Anthropic): 22 of 22 warn and critical signals; 21 demoted to info.
Disclude version
4.0.0
Scanned (UTC)
2026-10-20 00:56

Signals

Ordered by severity, then signals introduced in this release. Hidden characters are shown as ⟨U+…⟩.

  1. critical dynamic-execution launcher.c:328:9

    `execv` called with a non-literal path (ast pass, confidence 0.90)

            /* Use exec, we don't need to wait for the GUI to finish */
            execv(ptr, (const char * const *)(newargs));
            return fail("Could not exec %s", ptr);   /* shouldn't get here! */
        }
    likely benign LLM, confidence 0.60 A C launcher calls execv on a computed path to start the GUI binary.
    Reasoning

    execv with a runtime-determined path in a GUI launcher is a common legitimate pattern for launching a bundled binary; the path source is not shown, so it cannot be fully confirmed benign, but nothing in the snippet is obfuscated.

  2. info critical → info by review dynamic-execution setuptools/_distutils/command/bdist_rpm.py:369:15

    `os.popen` called on a non-literal command — runtime-determined shell invocation (ast pass, confidence 0.85)

    
            out = os.popen(q_cmd)
            try:
                binary_rpms = []
    likely benign LLM, confidence 0.85 Runs an rpm query command via os.popen during RPM packaging.
    Reasoning

    os.popen on a constructed rpm query command is standard distutils behavior for querying rpm; the command is built from the build configuration, not from untrusted input in this snippet.

  3. info warn → info by review dynamic-execution setuptools/_distutils/command/bdist_rpm.py:436:23

    `subprocess.getoutput` called with a literal shell command (ast pass, confidence 0.70)

            # RHEL6 (and probably derivatives)
            vendor_hook = subprocess.getoutput('rpm --eval %{__os_install_post}')
            # Generate a potential replacement value for __os_install_post (whilst
            # normalizing the whitespace to simplify the test for whether the
    likely benign LLM, confidence 0.92 Fetches the RPM __os_install_post macro using a literal shell command.
    Reasoning

    A fixed literal rpm --eval command via subprocess.getoutput is an ordinary, documented RPM-vendor detection step.

  4. info warn → info by review dynamic-execution setuptools/_distutils/compilers/C/base.py:1130:28

    `eval` called on a non-literal expression (ast pass, confidence 0.70)

            expected = '"static", "shared", "dylib", "xcode_stub"'
            if lib_type not in eval(expected):
                raise ValueError(f"'lib_type' must be {expected}")
            fmt = getattr(self, lib_type + "_lib_format")
    likely benign LLM, confidence 0.85 Evaluates a hardcoded string of library type names to validate lib_type.
    Reasoning

    eval is applied to a constant string literal defined in the same function, a known idiom for parsing a fixed list; no external input reaches it.

  5. info warn → info by review dynamic-execution setuptools/_distutils/core.py:250:17

    `exec` called on a non-literal expression (ast pass, confidence 0.70)

                    code = f.read().replace(r'\r\n', r'\n')
                    exec(code, g)  # noqa: S102 # executing the setup script is the point
            finally:
                sys.argv = save_argv
    likely benign LLM, confidence 0.85 Executes the user's setup.py script inside run_setup.
    Reasoning

    Executing the setup script is the documented purpose of distutils run_setup; the exec is intentional and annotated as such.

  6. info critical → info by review dynamic-import setuptools/_distutils/dist.py:873:17

    `__import__` called on a non-literal expression (ast pass, confidence 0.70)

                try:
                    __import__(module_name)
                    module = sys.modules[module_name]
                except ImportError:
    likely benign LLM, confidence 0.85 Dynamically imports a command module by name.
    Reasoning

    __import__ of a module name for command loading is standard plugin/command resolution in distutils, wrapped in ImportError handling.

  7. identifier `Dεbug` mixes scripts: Latin + Greek (in string/comment) (raw pass, confidence 0.40)

            caplog.set_level(logging.DEBUG)
            log.debug('Dεbug\tMėssãge')
            log.fatal('Fαtal\tÈrrōr')
            assert caplog.messages == ['Dεbug\tMėssãge', 'Fαtal\tÈrrōr']
  8. identifier `Fαtal` contains homoglyph candidates: α (03B1)→a (in string/comment) (raw pass, confidence 0.35)

            log.debug('Dεbug\tMėssãge')
            log.fatal('Fαtal\tÈrrōr')
            assert caplog.messages == ['Dεbug\tMėssãge', 'Fαtal\tÈrrōr']
  9. identifier `Fαtal` mixes scripts: Latin + Greek (in string/comment) (raw pass, confidence 0.40)

            log.debug('Dεbug\tMėssãge')
            log.fatal('Fαtal\tÈrrōr')
            assert caplog.messages == ['Dεbug\tMėssãge', 'Fαtal\tÈrrōr']
  10. identifier `Dεbug` mixes scripts: Latin + Greek (in string/comment) (raw pass, confidence 0.40)

            log.fatal('Fαtal\tÈrrōr')
            assert caplog.messages == ['Dεbug\tMėssãge', 'Fαtal\tÈrrōr']
  11. identifier `Fαtal` contains homoglyph candidates: α (03B1)→a (in string/comment) (raw pass, confidence 0.35)

            log.fatal('Fαtal\tÈrrōr')
            assert caplog.messages == ['Dεbug\tMėssãge', 'Fαtal\tÈrrōr']
  12. identifier `Fαtal` mixes scripts: Latin + Greek (in string/comment) (raw pass, confidence 0.40)

            log.fatal('Fαtal\tÈrrōr')
            assert caplog.messages == ['Dεbug\tMėssãge', 'Fαtal\tÈrrōr']
  13. info warn → info by review dynamic-execution setuptools/_distutils/util.py:397:21

    `compile` called on a non-literal expression (ast pass, confidence 0.70)

                        log.info("byte-compiling %s to %s", file, cfile_base)
                        compile(file, cfile, dfile)
                    else:
                        log.debug("skipping byte-compilation of %s to %s", file, cfile_base)
    likely benign LLM, confidence 0.85 Byte-compiles Python source files during install.
    Reasoning

    compile() is used to byte-compile library source files during installation, a normal distutils operation.

  14. info warn → info by review decoder-decompress-payload setuptools/_vendor/backports/tarfile/__init__.py:479:20

    file imports decoder module(s) zlib, bz2, lzma, gzip and calls `.decompress()` — embedded payload decompressed at runtime (ast pass, confidence 0.75)

            """
            self.cmp = self.zlib.decompressobj(-self.zlib.MAX_WBITS)
            self.dbuf = b""
    likely benign LLM, confidence 0.85 Creates a zlib decompressor for reading compressed tar streams.
    Reasoning

    Streaming decompression via decompressobj is the core of tarfile's compressed stream handling; it decompresses the archive being read, not an embedded payload.

  15. info warn → info by review dynamic-execution setuptools/_vendor/jaraco/functools/__init__.py:563:28

    `eval` called on a non-literal expression (ast pass, confidence 0.70)

                    try:
                        return eval(use)
                    except TypeError:
                        return replace
    likely benign LLM, confidence 0.80 Evaluates an expression string in a utility wrapper.
    Reasoning

    eval of a 'use' expression in a retry/replace helper is a legacy pattern that is unsafe only if the expression is attacker-controlled; the snippet shows no such source, so it is a code-quality concern rather than clear malice.

  16. info warn → info by review dynamic-execution setuptools/_vendor/packaging/licenses/__init__.py:144:9

    `compile` called on a non-literal expression (ast pass, confidence 0.70)

        try:
            compile(python_expression, "", "eval")
        except SyntaxError:
            message = f"Invalid license expression: {raw_license_expression!r}"
    likely benign LLM, confidence 0.90 Syntax-checks a license expression by compiling it without running it.
    Reasoning

    compile with mode 'eval' is used purely to validate syntax of a license expression and discards the result; it does not execute the code.

  17. info warn → info by review dynamic-execution setuptools/build_meta.py:317:13

    `exec` called on a non-literal expression (ast pass, confidence 0.70)

            try:
                exec(code, locals())  # noqa: S102 # exec is intentional here
            except SystemExit as e:
                if e.code:
    likely benign LLM, confidence 0.85 Runs setup.py code during the PEP 517 build.
    Reasoning

    build_meta executes the project's setup.py as part of the PEP 517 build backend; exec is the intended, documented behavior and is annotated.

  18. info warn → info by review dynamic-execution setuptools/command/bdist_egg.py:396:12

    `marshal.load` deserializes Python bytecode from bytes — code-object sink (ast pass, confidence 0.75)

        f.read(skip)
        code = marshal.load(f)
        f.close()
        safe = True
    likely benign LLM, confidence 0.80 Reads a compiled module's code object while building an egg.
    Reasoning

    marshal.load reads bytecode from a module file during egg-building to detect whether it is safe, a known legitimate use with no hidden payload shown.

  19. info warn → info by review frame-introspection setuptools/command/install.py:114:18

    `inspect.getouterframes` — call-stack frame introspection (ast pass, confidence 0.70)

    
            frames = inspect.getouterframes(run_frame)
            for frame in frames[2:4]:
                (caller,) = frame[:1]
    likely benign LLM, confidence 0.90 Inspects the call stack to locate the calling frame.
    Reasoning

    Call-stack introspection to find the caller of run_setup for install-command handling is a benign use of inspect in setuptools.

  20. line length 1035 characters (raw pass, confidence 0.50)

                    raise JsonSchemaValueException("" + (name_prefix or "data") + ".build-system must be object", value=data__buildsystem, name="" + (name_prefix or "data") + ".build-system", definition={'type': 'object', 'description': 'Table used to store build-related data', 'additionalProperties': False, 'properties': 
  21. line length 792 characters (raw pass, confidence 0.50)

                    raise JsonSchemaValueException("" + (name_prefix or "data") + ".dependency-groups must be object", value=data__dependencygroups, name="" + (name_prefix or "data") + ".dependency-groups", definition={'type': 'object', 'description': 'Dependency groups following PEP 735', 'additionalProperties': False, 'p
  22. line length 891 characters (raw pass, confidence 0.50)

                    raise JsonSchemaValueException("" + (name_prefix or "data") + ".package-dir must be object", value=data__packagedir, name="" + (name_prefix or "data") + ".package-dir", definition={'$$description': [':class:`dict`-like structure mapping from package names to directories where their', 'code can be found.
  23. line length 968 characters (raw pass, confidence 0.50)

                    raise JsonSchemaValueException("" + (name_prefix or "data") + ".package-data must be object", value=data__packagedata, name="" + (name_prefix or "data") + ".package-data", definition={'$$description': ['Mapping from package names to lists of glob patterns.', 'Usually this option is not needed when using
  24. line length 934 characters (raw pass, confidence 0.50)

                    raise JsonSchemaValueException("" + (name_prefix or "data") + ".exclude-package-data must be object", value=data__excludepackagedata, name="" + (name_prefix or "data") + ".exclude-package-data", definition={'$$description': ['Mapping from package names to lists of glob patterns that should be excluded',
  25. line length 1720 characters (raw pass, confidence 0.50)

                    raise JsonSchemaValueException("" + (name_prefix or "data") + ".ext-modules must be array", value=data__extmodules, name="" + (name_prefix or "data") + ".ext-modules", definition={'description': 'Extension modules to be compiled by setuptools', 'type': 'array', 'items': {'$id': '#/definitions/ext-module
  26. line length 791 characters (raw pass, confidence 0.50)

                    raise JsonSchemaValueException("" + (name_prefix or "data") + ".data-files must be object", value=data__datafiles, name="" + (name_prefix or "data") + ".data-files", definition={'$$description': ['``dict``-like structure where each key represents a directory and', 'the value is a list of glob patterns t
  27. line length 1584 characters (raw pass, confidence 0.50)

            raise JsonSchemaValueException("" + (name_prefix or "data") + " must be object", value=data, name="" + (name_prefix or "data") + "", definition={'$id': '#/definitions/ext-module', 'title': 'Extension module', 'description': 'Parameters to construct a :class:`setuptools.Extension` object', 'type': 'object', 'req
  28. line length 1643 characters (raw pass, confidence 0.50)

                raise JsonSchemaValueException("" + (name_prefix or "data") + " must contain " + (str(sorted(data__missing_keys)) + " properties"), value=data, name="" + (name_prefix or "data") + "", definition={'$id': '#/definitions/ext-module', 'title': 'Extension module', 'description': 'Parameters to construct a :class
  29. line length 1636 characters (raw pass, confidence 0.50)

                raise JsonSchemaValueException("" + (name_prefix or "data") + " must not contain "+str(data_keys)+" properties", value=data, name="" + (name_prefix or "data") + "", definition={'$id': '#/definitions/ext-module', 'title': 'Extension module', 'description': 'Parameters to construct a :class:`setuptools.Extens
  30. line length 1230 characters (raw pass, confidence 0.50)

            raise JsonSchemaValueException("" + (name_prefix or "data") + " must be object", value=data, name="" + (name_prefix or "data") + "", definition={'$id': '#/definitions/find-directive', 'title': "'find:' directive", 'type': 'object', 'additionalProperties': False, 'properties': {'find': {'type': 'object', '$$desc
  31. line length 1110 characters (raw pass, confidence 0.50)

                    raise JsonSchemaValueException("" + (name_prefix or "data") + ".find must be object", value=data__find, name="" + (name_prefix or "data") + ".find", definition={'type': 'object', '$$description': ['Dynamic `package discovery', '<https://setuptools.pypa.io/en/latest/userguide/package_discovery.html>`_.']
  32. line length 1282 characters (raw pass, confidence 0.50)

                raise JsonSchemaValueException("" + (name_prefix or "data") + " must not contain "+str(data_keys)+" properties", value=data, name="" + (name_prefix or "data") + "", definition={'$id': '#/definitions/find-directive', 'title': "'find:' directive", 'type': 'object', 'additionalProperties': False, 'properties':
  33. line length 1502 characters (raw pass, confidence 0.50)

                    raise JsonSchemaValueException("" + (name_prefix or "data") + ".readme must be valid exactly by one definition" + (" (" + str(data__readme_one_of_count12) + " matches found)"), value=data__readme, name="" + (name_prefix or "data") + ".readme", definition={'$$description': ['`Full/detailed description of
  34. line length 935 characters (raw pass, confidence 0.50)

                    raise JsonSchemaValueException("" + (name_prefix or "data") + ".license must be valid exactly by one definition" + (" (" + str(data__license_one_of_count14) + " matches found)"), value=data__license, name="" + (name_prefix or "data") + ".license", definition={'description': '`Project license <https://pe
  35. line length 963 characters (raw pass, confidence 0.50)

                    raise JsonSchemaValueException("" + (name_prefix or "data") + ".authors must be array", value=data__authors, name="" + (name_prefix or "data") + ".authors", definition={'type': 'array', 'items': {'$id': '#/definitions/author', 'title': 'Author or Maintainer', '$comment': 'https://peps.python.org/pep-062
  36. line length 920 characters (raw pass, confidence 0.50)

                    raise JsonSchemaValueException("" + (name_prefix or "data") + ".maintainers must be array", value=data__maintainers, name="" + (name_prefix or "data") + ".maintainers", definition={'type': 'array', 'items': {'$id': '#/definitions/author', 'title': 'Author or Maintainer', '$comment': 'https://peps.python
  37. line length 837 characters (raw pass, confidence 0.50)

                            raise JsonSchemaValueException("" + (name_prefix or "data") + ".dynamic[{data__dynamic_x}]".format(**locals()) + " must be one of ['version', 'description', 'readme', 'requires-python', 'license', 'license-files', 'authors', 'maintainers', 'keywords', 'classifiers', 'urls', 'scripts', 'gui-scrip
  38. line length 968 characters (raw pass, confidence 0.50)

            raise JsonSchemaValueException("" + (name_prefix or "data") + " must be object", value=data, name="" + (name_prefix or "data") + "", definition={'$id': '#/definitions/entry-point-group', 'title': 'Entry-points', 'type': 'object', '$$description': ['Entry-points are grouped together to indicate what sort of capa
  39. line length 1020 characters (raw pass, confidence 0.50)

                raise JsonSchemaValueException("" + (name_prefix or "data") + " must not contain "+str(data_keys)+" properties", value=data, name="" + (name_prefix or "data") + "", definition={'$id': '#/definitions/entry-point-group', 'title': 'Entry-points', 'type': 'object', '$$description': ['Entry-points are grouped to
  40. line length 1011 characters (raw pass, confidence 0.50)

                    raise JsonSchemaValueException("" + (name_prefix or "data") + " must be named by propertyName definition", value=data, name="" + (name_prefix or "data") + "", definition={'$id': '#/definitions/entry-point-group', 'title': 'Entry-points', 'type': 'object', '$$description': ['Entry-points are grouped toge
  41. info warn → info by review dynamic-execution setuptools/depends.py:132:24

    `marshal.load` deserializes Python bytecode from bytes — code-object sink (ast pass, confidence 0.75)

                    f.read(8)  # skip magic & date
                    code = marshal.load(f)
                elif kind == PY_FROZEN:
                    code = _imp.get_frozen_object(module, paths)
    likely benign LLM, confidence 0.80 Reads bytecode from a module file to inspect its constants.
    Reasoning

    marshal.load is used to read a module's bytecode to extract its version constant, a standard operation in setuptools' dependency detection on local files.

  42. info warn → info by review decoder-import-with-exec setuptools/depends.py:136:24

    file imports decoder module(s) marshal and calls `exec`/`eval`/`compile` — multi-stage payload shape (ast pass, confidence 0.80)

                elif kind == PY_SOURCE:
                    code = compile(f.read(), path, 'exec')
                else:
                    # Not something we can parse; we'll have to import it.  :(
    likely benign LLM, confidence 0.90 Compiles Python source files read from disk while inspecting module metadata in setuptools' dependency checker.
    Reasoning

    The snippet shows compile() of source read from a file on the PY_SOURCE branch, which is how setuptools inspects module constants. The marshal import is consistent with handling bytecode for the same feature. This is a legitimate introspection pattern, and the multi-stage label is a heuristic false positive on a generic import helper.

  43. info warn → info by review dynamic-execution setuptools/depends.py:136:24

    `compile` called on a non-literal expression (ast pass, confidence 0.70)

                elif kind == PY_SOURCE:
                    code = compile(f.read(), path, 'exec')
                else:
                    # Not something we can parse; we'll have to import it.  :(
    likely benign LLM, confidence 0.90 compile() on source text read from a local module file during dependency introspection.
    Reasoning

    compile() receives the contents of a file it just opened, along with its path and mode 'exec'. This is the normal way to load source for inspection. Nothing in the snippet is encoded, hidden, or fetched remotely.

  44. info critical → info by review dynamic-import setuptools/extension.py:24:9

    `__import__` called on a non-literal expression (ast pass, confidence 0.70)

            # from (cython_impl) import build_ext
            __import__(cython_impl, fromlist=['build_ext']).build_ext  # noqa: B018 # evaluated to trigger validation/side effect
        except Exception:  # noqa: BLE001 # intentional broad fallback
            return False
    likely benign LLM, confidence 0.85 Dynamic __import__ of the Cython build_ext module to test whether Cython support is available.
    Reasoning

    The import is a deliberate feature check for the optional Cython build_ext. The comment explains that it is evaluated to trigger validation, and the broad except returns False when the import fails. The module name is internal to setuptools, and the critical severity comes from the dynamic-import pattern alone.

  45. info warn → info by review dynamic-execution setuptools/launch.py:31:12

    `compile` called on a non-literal expression (ast pass, confidence 0.70)

        norm_script = script.replace('\\r\\n', '\\n')
        code = compile(norm_script, script_name, 'exec')
        exec(code, namespace)  # noqa: S102 # exec is intentional here
    likely benign LLM, confidence 0.90 Compiles and executes a script inside a namespace in setuptools' launch helper, which is its intended purpose.
    Reasoning

    This is the setuptools launcher, which runs a script it was given. The compile and exec are intentional, as the noqa comment says, and the script comes from the caller. Newline normalization is ordinary preparation before compiling.

  46. info warn → info by review dynamic-execution setuptools/launch.py:32:5

    `exec` called on a non-literal expression (ast pass, confidence 0.70)

        code = compile(norm_script, script_name, 'exec')
        exec(code, namespace)  # noqa: S102 # exec is intentional here
    likely benign LLM, confidence 0.90 exec of the compiled script code inside setuptools' launch helper.
    Reasoning

    exec runs the code object compiled on the previous line, with an explicit namespace and a noqa comment marking it as intentional. This is the expected behavior of a script launcher.

  47. identifier `Γαμα` contains homoglyph candidates: α (03B1)→a, α (03B1)→a (in string/comment) (raw pass, confidence 0.35)

      {name = "John X. Ãørçeč", email = "john@utf8.org"},
      {name = "Γαμα קּ 東", email = "gama@utf8.org"},
    ]
    classifiers = [
  48. identifier `Γαμα` mixes scripts: Greek + Latin (in string/comment) (raw pass, confidence 0.40)

      {name = "John X. Ãørçeč", email = "john@utf8.org"},
      {name = "Γαμα קּ 東", email = "gama@utf8.org"},
    ]
    classifiers = [
  49. identifier `Γαμα` contains homoglyph candidates: α (03B1)→a, α (03B1)→a (in string/comment) (raw pass, confidence 0.35)

                    'Brett Cannon <brett@python.org>, "John X. Ãørçeč" <john@utf8.org>, '
                    'Γαμα קּ 東 <gama@utf8.org>'
                ),
                id='non-international-emails',
  50. identifier `Γαμα` mixes scripts: Greek + Latin (in string/comment) (raw pass, confidence 0.40)

                    'Brett Cannon <brett@python.org>, "John X. Ãørçeč" <john@utf8.org>, '
                    'Γαμα קּ 東 <gama@utf8.org>'
                ),
                id='non-international-emails',
  51. identifier `Γαμα` contains homoglyph candidates: α (03B1)→a, α (03B1)→a (in string/comment) (raw pass, confidence 0.35)

                version = 42
                author_email = "John X. Ãørçeč" <john@utf8.org>, Γαμα קּ 東 <gama@utf8.org>
                long_description = file: README.rst
                """
  52. identifier `Γαμα` mixes scripts: Greek + Latin (in string/comment) (raw pass, confidence 0.40)

                version = 42
                author_email = "John X. Ãørçeč" <john@utf8.org>, Γαμα קּ 東 <gama@utf8.org>
                long_description = file: README.rst
                """
  53. identifier `Γαμα` contains homoglyph candidates: α (03B1)→a, α (03B1)→a (in string/comment) (raw pass, confidence 0.35)

    Version: 42
    Author-email: "John X. Ãørçeč" <john@utf8.org>, Γαμα קּ 東 <gama@utf8.org>
  54. identifier `Γαμα` mixes scripts: Greek + Latin (in string/comment) (raw pass, confidence 0.40)

    Version: 42
    Author-email: "John X. Ãørçeč" <john@utf8.org>, Γαμα קּ 東 <gama@utf8.org>
  55. identifier `Γαμα` contains homoglyph candidates: α (03B1)→a, α (03B1)→a (in string/comment) (raw pass, confidence 0.35)

        assert 'Author-email: "John X. Ãørçeč"' in metadata
        assert "Γαμα קּ 東 " in metadata
        assert "UTF-8 描述 説明" in metadata
  56. identifier `Γαμα` mixes scripts: Greek + Latin (in string/comment) (raw pass, confidence 0.40)

        assert 'Author-email: "John X. Ãørçeč"' in metadata
        assert "Γαμα קּ 東 " in metadata
        assert "UTF-8 描述 説明" in metadata
  57. info critical → info by review dynamic-import setuptools/tests/test_bdist_wheel.py:760:16

    `__import__` called on a non-literal expression (ast pass, confidence 0.70)

    
            return importlib.__import__(name, *args, **kwargs)
    
        with suppress(KeyError):
    likely benign LLM, confidence 0.90 Test helper that forwards import calls to importlib.__import__ so the test can observe or patch them.
    Reasoning

    The function is a test helper that forwards to importlib.__import__ with the same arguments, probably to mock or observe imports. It sits inside a with-suppress block in a test file. The critical rating is a false positive driven by the dynamic-import signal.

  58. info warn → info by review dynamic-execution setuptools/tests/test_editable_install.py:448:9

    `exec` called on a non-literal expression (ast pass, confidence 0.70)

            loc = {}
            exec(finder, loc, loc)  # noqa: S102 # exec is intentional here
            loc["install"]()
    likely benign LLM, confidence 0.90 Test that execs the generated editable-install finder code in a local namespace and calls its install function.
    Reasoning

    This is a test for editable installs. It executes a generated finder script in a local dict and then calls its install function, which is a standard way to test the generated code. The code is not obfuscated and is limited to test scope.

  59. info warn → info by review dynamic-execution setuptools/wheel.py:250:64

    `eval` called on a non-literal expression (ast pass, confidence 0.70)

                        raw_req,
                        (req for req in reqs if for_extra(req) and eval(req, extra=extra)),
                    )
                )
    likely benign LLM, confidence 0.80 Evaluates requirement environment markers with an extra name while filtering wheel dependencies.
    Reasoning

    The eval is applied to requirement marker strings during wheel metadata processing, with an extra keyword that carries the extra name. This is the marker-evaluation path, and the eval target is a requirement string from package metadata. It is a known pattern in setuptools, but eval on metadata strings is worth noting, so confidence is moderate.

Reproduce This Scan

Run disclude locally to verify. Add --format sarif for SARIF output. Add --llm (with an API key in the environment) to include the LLM review.

cargo install disclude --version 4.0.0
git clone https://github.com/pypa/setuptools setuptools && cd setuptools
git checkout v84.2.0
disclude scan --severity info --diff v84.1.0 .