entrygraph 0.1.8__tar.gz → 0.1.9__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {entrygraph-0.1.8 → entrygraph-0.1.9}/PKG-INFO +1 -1
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/_version.py +2 -2
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/pipeline/scanner.py +3 -1
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/resolve/resolver.py +29 -8
- entrygraph-0.1.9/tests/fixtures/python/fuzzy_sink/app.py +14 -0
- entrygraph-0.1.9/tests/test_fuzzy_sink.py +36 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/test_resolver.py +32 -2
- {entrygraph-0.1.8 → entrygraph-0.1.9}/.github/workflows/ci.yml +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/.github/workflows/release.yml +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/.gitignore +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/LICENSE +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/README.md +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/RELEASING.md +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/pyproject.toml +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/__init__.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/__main__.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/api.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/cli/__init__.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/cli/main.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/cli/render.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/data/sinks/csharp.toml +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/data/sinks/go.toml +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/data/sinks/java.toml +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/data/sinks/javascript.toml +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/data/sinks/lib_javascript.toml +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/data/sinks/lib_python.toml +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/data/sinks/php.toml +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/data/sinks/python.toml +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/data/sinks/ruby.toml +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/data/sinks/rust.toml +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/db/__init__.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/db/engine.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/db/meta.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/db/models.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/db/queries.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/detect/__init__.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/detect/entrypoints/__init__.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/detect/entrypoints/base.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/detect/entrypoints/configs.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/detect/entrypoints/csharp.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/detect/entrypoints/golang.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/detect/entrypoints/java.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/detect/entrypoints/javascript.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/detect/entrypoints/php.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/detect/entrypoints/python.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/detect/entrypoints/ruby.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/detect/entrypoints/rust.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/detect/frameworks.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/detect/manifests.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/detect/taint.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/errors.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/extract/__init__.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/extract/base.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/extract/csharp.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/extract/golang.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/extract/ir.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/extract/java.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/extract/javascript.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/extract/php.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/extract/python.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/extract/registry.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/extract/ruby.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/extract/rust.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/fs/__init__.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/fs/hashing.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/fs/lang.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/fs/walker.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/graph/__init__.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/graph/adjacency.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/graph/cte.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/graph/scoring.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/kinds.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/parsing/__init__.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/parsing/parsers.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/parsing/queries.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/pipeline/__init__.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/pipeline/worker.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/pipeline/writer.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/py.typed +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/queries/csharp/calls.scm +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/queries/csharp/definitions.scm +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/queries/csharp/imports.scm +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/queries/go/calls.scm +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/queries/go/definitions.scm +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/queries/go/imports.scm +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/queries/java/calls.scm +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/queries/java/definitions.scm +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/queries/java/imports.scm +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/queries/javascript/calls.scm +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/queries/javascript/definitions.scm +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/queries/javascript/imports.scm +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/queries/php/calls.scm +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/queries/php/definitions.scm +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/queries/php/imports.scm +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/queries/python/calls.scm +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/queries/python/definitions.scm +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/queries/python/imports.scm +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/queries/ruby/calls.scm +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/queries/ruby/definitions.scm +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/queries/ruby/imports.scm +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/queries/rust/calls.scm +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/queries/rust/definitions.scm +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/queries/rust/imports.scm +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/resolve/__init__.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/resolve/externals.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/resolve/hierarchy.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/resolve/symbol_table.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/src/entrygraph/results.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/conftest.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/fixtures/csharp/aspnet_app/Controllers/ReportsController.cs +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/fixtures/csharp/aspnet_app/Program.cs +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/fixtures/csharp/aspnet_app/Services/ReportService.cs +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/fixtures/csharp/aspnet_app/app.csproj +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/fixtures/go/gin_app/go.mod +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/fixtures/go/gin_app/main.go +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/fixtures/go/gin_app/service.go +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/fixtures/java/spring_app/pom.xml +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/fixtures/java/spring_app/src/main/java/com/example/Application.java +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/fixtures/java/spring_app/src/main/java/com/example/ReportRunner.java +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/fixtures/java/spring_app/src/main/java/com/example/ReportService.java +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/fixtures/java/spring_app/src/main/java/com/example/UserController.java +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/fixtures/javascript/commonjs_app/server.js +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/fixtures/javascript/express_app/package.json +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/fixtures/javascript/express_app/src/routes.js +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/fixtures/javascript/express_app/src/services.js +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/fixtures/php/laravel_app/app/Http/Controllers/ReportController.php +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/fixtures/php/laravel_app/artisan +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/fixtures/php/laravel_app/composer.json +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/fixtures/php/laravel_app/routes/web.php +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/fixtures/python/flask_app/app/__init__.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/fixtures/python/flask_app/app/db.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/fixtures/python/flask_app/app/routes.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/fixtures/python/flask_app/app/services.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/fixtures/python/flask_app/cli.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/fixtures/python/flask_app/requirements.txt +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/fixtures/python/sanitizer/app.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/fixtures/python/taint_source/handler.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/fixtures/ruby/sinatra_app/Gemfile +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/fixtures/ruby/sinatra_app/app.rb +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/fixtures/ruby/sinatra_app/services/runner.rb +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/fixtures/rust/axum_app/Cargo.toml +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/fixtures/rust/axum_app/src/handlers.rs +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/fixtures/rust/axum_app/src/main.rs +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/test_api.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/test_cli.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/test_commonjs.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/test_engine_pragmas.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/test_entrypoint_expansion.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/test_entrypoints.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/test_extract_csharp.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/test_extract_go.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/test_extract_java.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/test_extract_javascript.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/test_extract_php.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/test_extract_python.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/test_extract_ruby.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/test_extract_rust.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/test_frameworks.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/test_hardening.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/test_incremental.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/test_indexer.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/test_lang.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/test_manifests.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/test_models.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/test_pool.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/test_reachability.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/test_render.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/test_scoring.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/test_sink_catalog.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/test_taint.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/test_taint_sanitizers.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/test_taint_sources.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/tests/test_walker.py +0 -0
- {entrygraph-0.1.8 → entrygraph-0.1.9}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: entrygraph
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.9
|
|
4
4
|
Summary: Language-agnostic code graph: query symbols, entrypoints, and source-to-sink call paths from a SQLite index
|
|
5
5
|
Project-URL: Repository, https://github.com/brettbergin/entrygraph
|
|
6
6
|
Author-email: Brett Bergin <brettberginbc@yahoo.com>
|
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '0.1.
|
|
22
|
-
__version_tuple__ = version_tuple = (0, 1,
|
|
21
|
+
__version__ = version = '0.1.9'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 1, 9)
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -432,7 +432,9 @@ def _write_edges_and_entrypoints(
|
|
|
432
432
|
entrypoint_rows: list[dict] = []
|
|
433
433
|
|
|
434
434
|
for path, x, is_package in extractions:
|
|
435
|
-
resolver = FileResolver(
|
|
435
|
+
resolver = FileResolver(
|
|
436
|
+
x, module_ids[path], table, externals, is_package, sink_registry=sink_registry
|
|
437
|
+
)
|
|
436
438
|
file_id = file_id_by_path[path]
|
|
437
439
|
for edge in resolver.resolve():
|
|
438
440
|
is_call = edge.kind is EdgeKind.CALLS
|
|
@@ -17,6 +17,7 @@ incremental re-resolution can heal them when the target appears.
|
|
|
17
17
|
from __future__ import annotations
|
|
18
18
|
|
|
19
19
|
from dataclasses import dataclass
|
|
20
|
+
from typing import TYPE_CHECKING
|
|
20
21
|
|
|
21
22
|
from entrygraph.extract.ir import FileExtraction, RawReference
|
|
22
23
|
from entrygraph.kinds import Confidence, EdgeKind, SymbolKind
|
|
@@ -29,6 +30,9 @@ from entrygraph.resolve.hierarchy import (
|
|
|
29
30
|
)
|
|
30
31
|
from entrygraph.resolve.symbol_table import SymbolTable
|
|
31
32
|
|
|
33
|
+
if TYPE_CHECKING:
|
|
34
|
+
from entrygraph.detect.taint import SinkRegistry
|
|
35
|
+
|
|
32
36
|
# expand_relative re-exported for backward compatibility with callers/tests.
|
|
33
37
|
__all__ = ["FileResolver", "ResolvedEdge", "expand_relative"]
|
|
34
38
|
|
|
@@ -66,12 +70,14 @@ class FileResolver:
|
|
|
66
70
|
table: SymbolTable,
|
|
67
71
|
externals: ExternalRegistry,
|
|
68
72
|
is_package: bool = False,
|
|
73
|
+
sink_registry: SinkRegistry | None = None,
|
|
69
74
|
) -> None:
|
|
70
75
|
self.x = extraction
|
|
71
76
|
self.module_symbol_id = module_symbol_id
|
|
72
77
|
self.table = table
|
|
73
78
|
self.externals = externals
|
|
74
79
|
self.is_package = is_package
|
|
80
|
+
self.sink_registry = sink_registry
|
|
75
81
|
self.prefix = LANG_PREFIX.get(extraction.language, extraction.language)
|
|
76
82
|
self.import_map, self.wildcard_modules = build_import_map(extraction, is_package)
|
|
77
83
|
|
|
@@ -217,6 +223,14 @@ class FileResolver:
|
|
|
217
223
|
return self.table.by_fqn[target]
|
|
218
224
|
return self.table.unique_by_name(name, (SymbolKind.FUNCTION, SymbolKind.METHOD))
|
|
219
225
|
|
|
226
|
+
def _guess_is_sink(self, ref: RawReference) -> bool:
|
|
227
|
+
"""Whether the receiver-agnostic guess for this attribute call matches a
|
|
228
|
+
registered sink — checked with the same call the index-time stamper uses."""
|
|
229
|
+
if self.sink_registry is None:
|
|
230
|
+
return False
|
|
231
|
+
guess = f"{self.prefix}:*.{ref.callee_name}"
|
|
232
|
+
return self.sink_registry.match(guess, ref.arg_preview) is not None
|
|
233
|
+
|
|
220
234
|
def _bind(self, ref: RawReference) -> tuple[int | None, str, Confidence, str | None]:
|
|
221
235
|
# 1. import-map expansion (chase re-export chains for project targets)
|
|
222
236
|
first_seg = ref.callee_text.split(".", 1)[0].split("(", 1)[0]
|
|
@@ -270,14 +284,21 @@ class FileResolver:
|
|
|
270
284
|
# where runner is a local variable) this is the only way to recover the
|
|
271
285
|
# call-graph edge without local type inference — it's the documented
|
|
272
286
|
# FUZZY tradeoff.
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
)
|
|
278
|
-
|
|
279
|
-
if
|
|
280
|
-
|
|
287
|
+
#
|
|
288
|
+
# But if the receiver-agnostic guess (`py:*.execute`) is itself a
|
|
289
|
+
# registered sink, do NOT fuzzy-bind: rewriting dst_qname to a unique
|
|
290
|
+
# project method named `execute` would erase the sink stamp and hide the
|
|
291
|
+
# vulnerability. Prefer the guess so the sink survives (step 5); CHA still
|
|
292
|
+
# adds the project method as a via="cha" candidate, so no edge is lost.
|
|
293
|
+
if not (ref.receiver_text is not None and self._guess_is_sink(ref)):
|
|
294
|
+
kinds = (
|
|
295
|
+
(SymbolKind.METHOD,)
|
|
296
|
+
if ref.receiver_text is not None
|
|
297
|
+
else (SymbolKind.FUNCTION, SymbolKind.CLASS)
|
|
298
|
+
)
|
|
299
|
+
dst_id = self.table.unique_by_name(ref.callee_name, kinds)
|
|
300
|
+
if dst_id is not None:
|
|
301
|
+
return dst_id, self.table.qname_of[dst_id], Confidence.FUZZY, None
|
|
281
302
|
|
|
282
303
|
# 5. unresolved: language-prefixed guess, still a real node for sinks
|
|
283
304
|
if ref.receiver_text is not None:
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import sqlite3
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Runner:
|
|
5
|
+
# the ONLY project method named "execute" — the collision that used to
|
|
6
|
+
# swallow cursor.execute via unique-name fuzzy binding
|
|
7
|
+
def execute(self):
|
|
8
|
+
return 1
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def query(db_path, user_id):
|
|
12
|
+
conn = sqlite3.connect(db_path)
|
|
13
|
+
cur = conn.cursor()
|
|
14
|
+
cur.execute("SELECT * FROM users WHERE id = " + user_id)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""Sink preservation vs unique-name fuzzy binding (Phase 1.4).
|
|
2
|
+
|
|
3
|
+
Regression: an unknown-receiver call like `cursor.execute(sql)` fuzzy-bound to a
|
|
4
|
+
unique project method named `execute`, rewriting dst_qname so the `py:*.execute`
|
|
5
|
+
SQL sink never got stamped — the vulnerability silently vanished from the graph.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
import pytest
|
|
13
|
+
|
|
14
|
+
from entrygraph import CodeGraph
|
|
15
|
+
|
|
16
|
+
FUZZY_SINK_APP = Path(__file__).parent / "fixtures" / "python" / "fuzzy_sink"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@pytest.fixture(scope="module")
|
|
20
|
+
def graph(tmp_path_factory) -> CodeGraph:
|
|
21
|
+
db = tmp_path_factory.mktemp("db") / "graph.db"
|
|
22
|
+
g = CodeGraph.index(FUZZY_SINK_APP, db=db)
|
|
23
|
+
yield g
|
|
24
|
+
g.close()
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def test_sql_sink_survives_unique_name_collision(graph):
|
|
28
|
+
sinks = graph.sql("SELECT dst_qname, sink_id FROM edges WHERE sink_id IS NOT NULL")
|
|
29
|
+
by_qname = {r["dst_qname"]: r["sink_id"] for r in sinks}
|
|
30
|
+
assert by_qname.get("py:*.execute") == "py.sql-execute"
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def test_sql_path_reachable_despite_collision(graph):
|
|
34
|
+
paths = graph.paths(source="app.query", sink_category="sql", include_unresolved=True)
|
|
35
|
+
assert paths
|
|
36
|
+
assert paths[0].symbols[-1].qname == "py:*.execute"
|
|
@@ -20,7 +20,7 @@ def make_table() -> SymbolTable:
|
|
|
20
20
|
return table
|
|
21
21
|
|
|
22
22
|
|
|
23
|
-
def make_resolver(table, refs=(), imports=(), module="app.routes", module_id=2):
|
|
23
|
+
def make_resolver(table, refs=(), imports=(), module="app.routes", module_id=2, sink_registry=None):
|
|
24
24
|
x = FileExtraction(
|
|
25
25
|
path="app/routes.py",
|
|
26
26
|
language="python",
|
|
@@ -31,7 +31,7 @@ def make_resolver(table, refs=(), imports=(), module="app.routes", module_id=2):
|
|
|
31
31
|
references=list(refs),
|
|
32
32
|
)
|
|
33
33
|
externals = ExternalRegistry(iter(range(100, 200)).__next__)
|
|
34
|
-
return FileResolver(x, module_id, table, externals), externals
|
|
34
|
+
return FileResolver(x, module_id, table, externals, sink_registry=sink_registry), externals
|
|
35
35
|
|
|
36
36
|
|
|
37
37
|
def ref(callee_text, callee_name=None, receiver=None, caller=None, kind="call"):
|
|
@@ -180,6 +180,36 @@ def test_unresolved_gets_prefixed_placeholder():
|
|
|
180
180
|
assert by_qname["py:eval"].confidence is Confidence.UNRESOLVED
|
|
181
181
|
|
|
182
182
|
|
|
183
|
+
def test_sink_named_attribute_call_is_not_fuzzy_bound():
|
|
184
|
+
# `cursor.execute(...)` guesses to the sink `py:*.execute`. Even though a
|
|
185
|
+
# unique project method `Runner.execute` (id 12) exists, we must NOT fuzzy-bind
|
|
186
|
+
# to it — that would rewrite dst_qname and erase the SQL sink. Keep the guess.
|
|
187
|
+
from entrygraph.detect.taint import builtin_registry
|
|
188
|
+
|
|
189
|
+
table = make_table()
|
|
190
|
+
resolver, _ = make_resolver(
|
|
191
|
+
table, [ref("cursor.execute", receiver="cursor")], sink_registry=builtin_registry()
|
|
192
|
+
)
|
|
193
|
+
call = next(e for e in resolver.resolve() if e.kind is EdgeKind.CALLS and e.via != "cha")
|
|
194
|
+
assert call.dst_qname == "py:*.execute"
|
|
195
|
+
assert call.confidence is Confidence.UNRESOLVED
|
|
196
|
+
assert call.dst_symbol_id != 12
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def test_non_sink_attribute_call_still_fuzzy_binds_with_registry():
|
|
200
|
+
# `obj.render` is not a sink, so unique-name fuzzy binding still applies even
|
|
201
|
+
# with a sink registry present — the fix is targeted to sink names only.
|
|
202
|
+
from entrygraph.detect.taint import builtin_registry
|
|
203
|
+
|
|
204
|
+
table = make_table()
|
|
205
|
+
resolver, _ = make_resolver(
|
|
206
|
+
table, [ref("obj.render", receiver="obj")], sink_registry=builtin_registry()
|
|
207
|
+
)
|
|
208
|
+
call = next(e for e in resolver.resolve() if e.kind is EdgeKind.CALLS)
|
|
209
|
+
assert call.dst_symbol_id == 13 # Runner.render
|
|
210
|
+
assert call.confidence is Confidence.FUZZY
|
|
211
|
+
|
|
212
|
+
|
|
183
213
|
def test_relative_import_expansion():
|
|
184
214
|
table = make_table()
|
|
185
215
|
table.add_symbol(40, "app.utils", 40 and "utils", SymbolKind.MODULE)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{entrygraph-0.1.8 → entrygraph-0.1.9}/tests/fixtures/csharp/aspnet_app/Services/ReportService.cs
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|