Skip to content

feat: give project plugins each module's functions with their span and entry point - #117

Closed
SizzleUnrlsd wants to merge 2 commits into
release/0.4.0from
feat/project-functions
Closed

SizzleUnrlsd wants to merge 2 commits into
release/0.4.0from
feat/project-functions

Conversation

@SizzleUnrlsd

Copy link
Copy Markdown
Contributor

Closes #116. Stacked on #115 (release 0.4.0): merge #115 first; GitHub then retargets this PR to main, and its changelog entry sits under a new Unreleased above 0.4.0.

Why

Needed by the enterprise exposure-prioritization plugin (CoreTrace-Entreprise/coretrace-python-analyzer-plugins#4). A project plugin could not place a finding in the call graph: findings carry bare function names (get, not Admin.get), the context's call graphs are rebuilt from call sites without definitions (no spans), and nothing said which functions are entry points. The engine now provides those facts; the ranking policy stays in the plugin.

What

  • ModuleFunction(name, span, entry_point) in coretrace_python.interprocedural: the call graph's name, the span, the entry point's label (http, argv, ...) or None.
  • function_entry_point(...) extracted from parameter_sources (decorator or base matching an EntryPoint model, or a registration elsewhere); parameter_sources now calls it, behaviour unchanged.
  • EntryPointAnalysis (taint.entry_points) applies it to every function of the module, with the factory instances and registered routes the taint engine uses. It reads the project summaries, so it joins the analyses ProjectSummariesUpdated invalidates.
  • CachedModule.functions holds the records (cache format 5 → 6); ProjectContext.functions(module) serves them, falling back to the module's manager like call_graph() does.

Tests

tests/test_project.py: names, spans and labels of a Flask module (<module>, index = http, helper, Admin.get); a Django view registered in urls.py is http, an unregistered function is not; the route of an app built by create_app() in another module is http; a module served from the cache gives the same records. The two cache codec tests build CachedModule from records (the heap one only checks summaries, so it passes none).

932 passed; ruff and mypy clean. Plugin guide documents ctx.functions(module) (and fixes ctx.modules() → ctx.modules, a property).

Every function as the call graph names it, with its span and the label
of the entry point it is: a Flask route, a Django view registered in
another module, a route of an app made by a factory in another module,
and the same answer from a module served from the cache. The cache codec
tests build CachedModule from the new function records.
…d entry point

A finding names its function by its bare name and the project context's
call graphs carry no definitions, so a project plugin could not place a
finding in the call graph, nor tell a route from a helper.

ModuleFunction(name, span, entry_point) records each function as the call
graph names it. EntryPointAnalysis decides the entry point with the taint
engine's own rule, extracted from parameter_sources as
function_entry_point, and is invalidated with the project summaries it
reads. The records are cached with the module (format 6) and served by
ProjectContext.functions(module).

Closes #116
@SizzleUnrlsd

Copy link
Copy Markdown
Contributor Author

Closed by GitHub when its base branch release/0.4.0 was deleted on merging #115. Replaced by #118, same commits, against main.

@SizzleUnrlsd
SizzleUnrlsd deleted the feat/project-functions branch September 24, 2026 11:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant