PyPI / alembic / 1.20.0

alembic 1.20.0

Source
https://github.com/sqlalchemy/alembic
Tag scanned
rel_1_20_0
Compared with
rel_1_19_2 (0 signals introduced since)
Files
148 scanned, 31 skipped (binary, oversized, or unrecognised)
Signals
2 critical · 0 warn · 6 info
Scan time
8.2 s
LLM review
Reviewed by claude-haiku-5-5 (Anthropic): 8 of 8 warn and critical signals; 6 demoted to info.
Disclude version
4.0.0
Scanned (UTC)
2026-10-14 18:41

Signals

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

  1. critical dynamic-execution tests/conftest.py:34:12

    `compile` at module scope (runs on import) on a non-literal expression (ast pass, confidence 0.80)

    with open(bootstrap_file) as f:
        code = compile(f.read(), "bootstrap.py", "exec")
        to_bootstrap = "pytest"
        exec(code, globals(), locals())
    inconclusive LLM, confidence 0.50 Compiles and execs a bootstrap.py file at import time in the test configuration.
    Reasoning

    Module-level compile and exec of an external bootstrap.py file runs code on every test import. The snippet does not show where bootstrap_file comes from. If it is a local project file, this is an odd but harmless test harness. The unusual `to_bootstrap` variable and import-time execution warrant a closer look at the file's origin.

  2. critical dynamic-execution tests/conftest.py:36:5

    `exec` at module scope (runs on import) on a non-literal expression (ast pass, confidence 0.80)

        to_bootstrap = "pytest"
        exec(code, globals(), locals())
    
        try:
    inconclusive LLM, confidence 0.50 Executes the compiled bootstrap code at module import time in the test conftest.
    Reasoning

    Same module-scope exec of the compiled bootstrap code, with the caller's globals and locals. It is the second half of the same mechanism. Whether it is benign depends on whether bootstrap_file is a trusted local file, which the snippet does not establish.

  3. info warn → info by review dynamic-attribute alembic/autogenerate/render.py:939:18

    reach-by-name through `globals` (ast pass, confidence 0.60)

            if "_render_%s_type" % type_.__visit_name__ in globals():
                fn = globals()["_render_%s_type" % type_.__visit_name__]
                return fn(type_, autogen_context)
            else:
    likely benign LLM, confidence 0.93 Dispatches to a type-specific render function by constructing its name from the type's visit name.
    Reasoning

    Looks up a renderer function by name from a string built from the type's visit name, guarded by an `in globals()` check. This is a common dispatch-by-name pattern for a fixed set of internal `_render_*_type` functions, with no external input or network source.

  4. info warn → info by review dynamic-execution alembic/operations/base.py:185:13

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

    
                exec(func_text, globals_, lcl)
                setattr(cls, name, lcl[name])
                fn.__func__.__doc__ = (
    likely benign LLM, confidence 0.80 Execs generated function source to create a wrapper method that is attached to a class.
    Reasoning

    exec runs generated function text in a controlled namespace to build a wrapper with a matching signature, then sets it on the class. Libraries use this for signature-preserving wrappers. The text is generated internally, not fetched from outside, so this reads as a legitimate code-generation pattern.

  5. info warn → info by review dynamic-execution alembic/util/langhelpers.py:214:9

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

    
            exec(func_text, cast("Dict[str, Any]", globals_), lcl)
            return cast("Callable[..., Any]", lcl[name])
    likely benign LLM, confidence 0.80 Execs generated function source to produce and return a callable with a chosen signature.
    Reasoning

    Same generated-wrapper pattern: exec on internally produced function text to create a callable with a specific signature, returning the named function. No external input is visible in the snippet.

  6. info warn → info by review dynamic-execution tests/test_autogen_render.py:708:9

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

            context = op_fixture()
            eval(py_code)
            context.assert_(
                "CREATE TABLE b (a_id INTEGER, "
    likely benign LLM, confidence 0.85 Evaluates rendered Python code in a test to verify autogenerate output.
    Reasoning

    In a test, eval runs a Python code string produced by the autogenerate renderer so the test can check that the rendered code reproduces the expected operations. This is a standard round-trip test pattern with no external input.

  7. info warn → info by review dynamic-execution tests/test_autogen_render.py:732:9

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

            context = op_fixture()
            eval(py_code)
            context.assert_(
                "CREATE TABLE b (a_id INTEGER, CONSTRAINT "
    likely benign LLM, confidence 0.85 Evaluates rendered Python code in a test to check generated SQL.
    Reasoning

    Same round-trip test pattern: eval of renderer output inside a test function, followed by an assertion on the generated SQL. No attacker-controlled input is visible.

  8. info warn → info by review dynamic-execution tests/test_autogen_render.py:749:9

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

    
            eval(py_code)
            context.assert_(
                "ALTER TABLE b ADD CONSTRAINT fk_a_id "
    likely benign LLM, confidence 0.85 Evaluates rendered Python code in a test to check a generated ALTER TABLE constraint.
    Reasoning

    Same test-only eval of renderer output, asserting on the resulting ALTER TABLE statement. This is a normal way to test code generation.

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/sqlalchemy/alembic alembic && cd alembic
git checkout rel_1_20_0
disclude scan --severity info --diff rel_1_19_2 .