Repository navigation
fix: keep files sharing a Python module name as distinct modules - #190
Merged
Merged
Conversation
…ocessor A TEMPLATES bound in a function, called or not, or in a class configures nothing; a function reading, mutating or rebinding the module's TEMPLATES leaves the activation uncertain; a local TEMPLATES beside module settings changes nothing.
request_processor walked every node of every module and counted any assignment to TEMPLATES, so a function-local or class-level assignment activated the request context processor. It now walks the modules with their scope tables: an assignment counts only at module scope, and a mention counts only when the name resolves to the module's binding, or to nothing, as a star import gives. ScopeTable.scope_for accepts a lambda, whose scope the builder already records.
…e flow
A block rendering {{ block.super }} extends the parent's block: its filters stay fed by the render context, with the parent template as the place of the call, however block.super is rendered; a block without it replaces the parent's whole block; other overridden blocks stay excluded; a chain of templates keeps exactly the parents each level renders, once.
A template extending another replaced every block it defined in the parent, so the parent's filter applications dropped out of the render context flow even when the child rendered {{ block.super }}, which Django executes. A template now records the blocks that render block.super, and only the blocks defined without it are passed up as replaced, level by level.
A deployment declaration names its handler as the module binds it, and a module may bind that name as an alias of the function doing the work: main = actual. A model naming the alias's project symbol now applies to the function, or to the class's methods for a class alias. Aliases are module-level assignments of one name to another, followed transitively in source order; a name bound inside a function or class, or to a call, an import or any other value, is no alias.
…-ins A project tag library registering a filter of a built-in's name replaces it in every template loading the library before applying the filter, as Django's parser does; loads are ordered, selective loads honoured, Django's own libraries change nothing. A library the engine cannot find, read or understand, or several apps disagreeing, leaves the filter uncertain: no call is claimed and the load is listed among the unread templates, keeping the advisory under investigation (#183).
Name every module by its file: the import name when unique, otherwise its path from the root as a dotted name. Resolve an import of a shared name within the importer's root only and record the ones no root resolves. Report colliding files with an ambiguous-module note and cover them as ambiguous; key component seeds by import name, registering a shared name only for the file a member imports directly, and the final index by module key (#182).
DjangoGoat, httpie and pygoat each hold files sharing an import name that the engine used to overwrite: the recovered files, their functions and one ambiguous-module note per colliding file are now recorded, files_analysed counts analysed files only, and pygoat's dockerized_labs/insec_des_lab/main.py reports the insecure deserialization it always held (#182).
# Conflicts: # CHANGELOG.md
# Conflicts: # CHANGELOG.md
…rides # Conflicts: # CHANGELOG.md # src/coretrace_python/taint/templates.py
# Conflicts: # CHANGELOG.md
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #182.
Two files with the same Python module name,
a/app.pyandz/app.pyoutside any package, overwrote each other in the module table: the file found last was the only one analysed, so the other's findings never appeared, and which one that was depended on discovery order. The regression corpus shows it: pygoat'sdockerized_labs/insec_des_lab/main.py, hidden behindintroduction/playground/A9/main.py, carries an insecure deserialization (pickle.loadsof a posted form field, line 36) that no run reported.name_modules(root, sources)names each file for the engine: its import name when unique, otherwise its path from the root as a dotted name (a.app,z.app), or the POSIX path when even those coincide; decided over the whole set, so independent of the order.module_name,nodes.Module.nameandproject_symbolare unchanged, so a model or a route namingpython.app.mainapplies to every definition of that symbol.build_module_graphresolves an import of a shared name to the file in the importer's own import root (themodule_name_forwalk) only; without exactly one there it records the name as unresolved, no edge. A unique name resolves as before, from any directory.ambiguous-modulenote and is covered asambiguous; an importer whose import stayed unresolved gets a note too, since calls into it are not followed.files_analysedcounts analysed files only, so a VEX statement over such a project staysunder_investigationrather thannot_affected(vex.pyunchanged: any status butanalysedalready does that; a test pins it)._analyse_managersregisters a name two members of one component share for neither.Regression snapshots re-recorded for DjangoGoat, httpie and pygoat, with the owner's authorization, for exactly these changes: the recovered files (+2, +1, +2), their functions (+14, +2, +8), one
ambiguous-modulenote per colliding file,files_analysedlowered by exactly those files, and the pygoat finding above. Every colliding file is analysed in full (analysed == functions), each with its own findings; no other line changes.Tests:
tests/test_module_identity.py(16 cases, failing before the change: discovery and coverage of both files, findings whatever the discovery order and job count, coinciding dotted paths, root-scoped import resolution, unresolved imports reported and not followed, the seed of a component reaching both files, a package and a script sharing a name, index and cache keys, project plugins, JSON report, VEX status);pytest -m "not regression"1438 passed, 2 skipped; regression corpus 19 passed on the re-recorded snapshots at the pinned revisions;ruff check .andmypyclean.