coretrace-python-analyzer 0.1.0__py3-none-any.whl

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.
Files changed (126) hide show
  1. coretrace_python/__init__.py +4 -0
  2. coretrace_python/__main__.py +4 -0
  3. coretrace_python/abstract/__init__.py +45 -0
  4. coretrace_python/abstract/constants.py +226 -0
  5. coretrace_python/abstract/heap.py +252 -0
  6. coretrace_python/abstract/ranges.py +285 -0
  7. coretrace_python/abstract/values.py +56 -0
  8. coretrace_python/analysis/__init__.py +31 -0
  9. coretrace_python/analysis/manager.py +165 -0
  10. coretrace_python/analysis/provider.py +73 -0
  11. coretrace_python/bundled/dependency/dependency_policy/dependency_policy.py +46 -0
  12. coretrace_python/bundled/dependency/dependency_policy/plugin.toml +9 -0
  13. coretrace_python/bundled/dependency/reachable_vulnerability/plugin.toml +9 -0
  14. coretrace_python/bundled/dependency/reachable_vulnerability/reachable_vulnerability.py +56 -0
  15. coretrace_python/bundled/dependency/sample_advisories/plugin.toml +9 -0
  16. coretrace_python/bundled/dependency/sample_advisories/sample_advisories.py +109 -0
  17. coretrace_python/bundled/dependency/vulnerable_dependency/plugin.toml +9 -0
  18. coretrace_python/bundled/dependency/vulnerable_dependency/vulnerable_dependency.py +43 -0
  19. coretrace_python/bundled/models/cli/cli_models.py +35 -0
  20. coretrace_python/bundled/models/cli/plugin.toml +9 -0
  21. coretrace_python/bundled/models/credentials/credential_models.py +43 -0
  22. coretrace_python/bundled/models/credentials/plugin.toml +9 -0
  23. coretrace_python/bundled/models/django/django_models.py +123 -0
  24. coretrace_python/bundled/models/django/plugin.toml +9 -0
  25. coretrace_python/bundled/models/fastapi/fastapi_models.py +29 -0
  26. coretrace_python/bundled/models/fastapi/plugin.toml +9 -0
  27. coretrace_python/bundled/models/flask/flask_models.py +53 -0
  28. coretrace_python/bundled/models/flask/plugin.toml +9 -0
  29. coretrace_python/bundled/models/http_clients/http_client_models.py +43 -0
  30. coretrace_python/bundled/models/http_clients/plugin.toml +9 -0
  31. coretrace_python/bundled/models/python_stdlib/plugin.toml +9 -0
  32. coretrace_python/bundled/models/python_stdlib/python_stdlib.py +68 -0
  33. coretrace_python/bundled/models/sqlalchemy/plugin.toml +9 -0
  34. coretrace_python/bundled/models/sqlalchemy/sqlalchemy_models.py +47 -0
  35. coretrace_python/bundled/secrets/config_secrets/config_secrets.py +38 -0
  36. coretrace_python/bundled/secrets/config_secrets/plugin.toml +9 -0
  37. coretrace_python/bundled/secrets/hardcoded_secrets/hardcoded_secrets.py +19 -0
  38. coretrace_python/bundled/secrets/hardcoded_secrets/plugin.toml +9 -0
  39. coretrace_python/bundled/security/command_injection/command_injection.py +17 -0
  40. coretrace_python/bundled/security/command_injection/plugin.toml +9 -0
  41. coretrace_python/bundled/security/insecure_deserialization/insecure_deserialization.py +17 -0
  42. coretrace_python/bundled/security/insecure_deserialization/plugin.toml +9 -0
  43. coretrace_python/bundled/security/open_redirect/open_redirect.py +17 -0
  44. coretrace_python/bundled/security/open_redirect/plugin.toml +9 -0
  45. coretrace_python/bundled/security/path_traversal/path_traversal.py +17 -0
  46. coretrace_python/bundled/security/path_traversal/plugin.toml +9 -0
  47. coretrace_python/bundled/security/plaintext_credentials/plaintext_credentials.py +21 -0
  48. coretrace_python/bundled/security/plaintext_credentials/plugin.toml +9 -0
  49. coretrace_python/bundled/security/sql_injection/plugin.toml +9 -0
  50. coretrace_python/bundled/security/sql_injection/sql_injection.py +17 -0
  51. coretrace_python/bundled/security/ssrf/plugin.toml +9 -0
  52. coretrace_python/bundled/security/ssrf/ssrf.py +17 -0
  53. coretrace_python/bundled/security/xss/plugin.toml +9 -0
  54. coretrace_python/bundled/security/xss/xss.py +17 -0
  55. coretrace_python/bundled/syntax/dangerous_eval/dangerous_eval.py +19 -0
  56. coretrace_python/bundled/syntax/dangerous_eval/plugin.toml +9 -0
  57. coretrace_python/bundled/syntax/flask_debug/flask_debug.py +63 -0
  58. coretrace_python/bundled/syntax/flask_debug/plugin.toml +9 -0
  59. coretrace_python/bundled/syntax/missing_timeout/missing_timeout.py +51 -0
  60. coretrace_python/bundled/syntax/missing_timeout/plugin.toml +9 -0
  61. coretrace_python/bundled/syntax/weak_crypto/plugin.toml +9 -0
  62. coretrace_python/bundled/syntax/weak_crypto/weak_crypto.py +19 -0
  63. coretrace_python/cache.py +310 -0
  64. coretrace_python/cfg/__init__.py +46 -0
  65. coretrace_python/cfg/builder.py +589 -0
  66. coretrace_python/cfg/dominance.py +183 -0
  67. coretrace_python/cfg/model.py +166 -0
  68. coretrace_python/cli.py +216 -0
  69. coretrace_python/dataflow/__init__.py +29 -0
  70. coretrace_python/dataflow/lattice.py +78 -0
  71. coretrace_python/dataflow/solver.py +96 -0
  72. coretrace_python/dependency/__init__.py +44 -0
  73. coretrace_python/dependency/advisories.py +168 -0
  74. coretrace_python/dependency/correlation.py +87 -0
  75. coretrace_python/dependency/graph.py +274 -0
  76. coretrace_python/dependency/policy.py +65 -0
  77. coretrace_python/dependency/sbom.py +65 -0
  78. coretrace_python/engine.py +688 -0
  79. coretrace_python/findings/__init__.py +13 -0
  80. coretrace_python/findings/coverage.py +45 -0
  81. coretrace_python/findings/model.py +49 -0
  82. coretrace_python/findings/refutation.py +427 -0
  83. coretrace_python/frontend/__init__.py +18 -0
  84. coretrace_python/frontend/ast_adapter.py +447 -0
  85. coretrace_python/frontend/parser.py +23 -0
  86. coretrace_python/hir/__init__.py +5 -0
  87. coretrace_python/hir/nodes.py +584 -0
  88. coretrace_python/hir/visitors.py +36 -0
  89. coretrace_python/interprocedural/__init__.py +49 -0
  90. coretrace_python/interprocedural/callgraph.py +291 -0
  91. coretrace_python/interprocedural/modulegraph.py +218 -0
  92. coretrace_python/interprocedural/summaries.py +463 -0
  93. coretrace_python/ir/__init__.py +5 -0
  94. coretrace_python/ir/defuse.py +74 -0
  95. coretrace_python/ir/lowering.py +575 -0
  96. coretrace_python/ir/model.py +481 -0
  97. coretrace_python/ir/printer.py +201 -0
  98. coretrace_python/ir/ssa.py +277 -0
  99. coretrace_python/plugins/__init__.py +58 -0
  100. coretrace_python/plugins/api.py +153 -0
  101. coretrace_python/plugins/detectors.py +114 -0
  102. coretrace_python/plugins/loader.py +84 -0
  103. coretrace_python/plugins/manifest.py +112 -0
  104. coretrace_python/plugins/registry.py +34 -0
  105. coretrace_python/plugins/secrets.py +330 -0
  106. coretrace_python/reporters/__init__.py +22 -0
  107. coretrace_python/reporters/json_format.py +48 -0
  108. coretrace_python/reporters/report.py +23 -0
  109. coretrace_python/reporters/sarif.py +70 -0
  110. coretrace_python/reporters/text.py +24 -0
  111. coretrace_python/semantic/__init__.py +9 -0
  112. coretrace_python/semantic/identity.py +39 -0
  113. coretrace_python/semantic/imports.py +131 -0
  114. coretrace_python/semantic/scopes.py +473 -0
  115. coretrace_python/semantic/symbols.py +87 -0
  116. coretrace_python/source/__init__.py +13 -0
  117. coretrace_python/source/manager.py +81 -0
  118. coretrace_python/source/model.py +57 -0
  119. coretrace_python/taint/__init__.py +55 -0
  120. coretrace_python/taint/engine.py +800 -0
  121. coretrace_python/taint/models.py +317 -0
  122. coretrace_python/taint/routes.py +99 -0
  123. coretrace_python_analyzer-0.1.0.dist-info/METADATA +74 -0
  124. coretrace_python_analyzer-0.1.0.dist-info/RECORD +126 -0
  125. coretrace_python_analyzer-0.1.0.dist-info/WHEEL +4 -0
  126. coretrace_python_analyzer-0.1.0.dist-info/entry_points.txt +2 -0
@@ -0,0 +1,317 @@
1
+ """Security model registry (architecture §16, §17).
2
+
3
+ Taint kinds form a bitset joined with ``|``. Plugins register sources, sinks and
4
+ sanitizers keyed by canonical symbol; the engine freezes them into an immutable
5
+ ``ModelTable`` and provides it to the Analysis Manager as the ``taint.models`` input,
6
+ so every detector consumes the same models and the same taint result.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import hashlib
12
+ import re
13
+ from dataclasses import dataclass, field
14
+ from enum import Flag, auto
15
+ from types import MappingProxyType
16
+ from typing import ClassVar
17
+
18
+ from coretrace_python.analysis import Analysis, AnalysisContext, MissingInputError
19
+ from coretrace_python.semantic.symbols import SymbolId
20
+
21
+
22
+ class TaintKind(Flag):
23
+ NONE = 0
24
+ SQL = auto()
25
+ COMMAND = auto()
26
+ HTML = auto()
27
+ PATH = auto()
28
+ SSRF = auto()
29
+ CODE = auto()
30
+ ADVISORY = auto()
31
+ DESERIALIZATION = auto()
32
+ REDIRECT = auto()
33
+ ALL = SQL | COMMAND | HTML | PATH | SSRF | CODE | ADVISORY | DESERIALIZATION | REDIRECT
34
+ # Outside ALL on purpose: only credential-named parameters carry it, so a database
35
+ # write reached by ordinary input is not a plaintext credential.
36
+ CREDENTIAL = auto()
37
+
38
+
39
+ class ModelError(Exception):
40
+ """Two models of the same kind claim the same symbol."""
41
+
42
+
43
+ @dataclass(frozen=True)
44
+ class Source:
45
+ """A symbol whose value, or call result, is attacker-controlled."""
46
+
47
+ symbol: SymbolId
48
+ label: str
49
+ kinds: TaintKind = TaintKind.ALL
50
+
51
+
52
+ @dataclass(frozen=True)
53
+ class Sink:
54
+ """A callable whose arguments must not carry the given taint kinds. ``positions``
55
+ restricts some kinds to argument positions: a SQL statement is the first argument
56
+ of ``execute``, its parameter tuple is not a statement."""
57
+
58
+ symbol: SymbolId
59
+ kinds: TaintKind
60
+ positions: tuple[tuple[TaintKind, tuple[int, ...]], ...] = ()
61
+
62
+ def kinds_at(self, position: int | None) -> TaintKind:
63
+ """The kinds that must not reach the argument at ``position`` (``None`` for a
64
+ keyword or starred argument)."""
65
+
66
+ kinds = self.kinds
67
+ for restricted, allowed in self.positions:
68
+ if position is None or position not in allowed:
69
+ kinds &= ~restricted
70
+ return kinds
71
+
72
+
73
+ @dataclass(frozen=True)
74
+ class Sanitizer:
75
+ """A callable whose result no longer carries the given taint kinds."""
76
+
77
+ symbol: SymbolId
78
+ kinds: TaintKind
79
+
80
+
81
+ @dataclass(frozen=True)
82
+ class EntryPoint:
83
+ """Functions decorated by ``symbol``, and methods of classes deriving from it,
84
+ receive attacker-controlled parameters."""
85
+
86
+ symbol: SymbolId
87
+ label: str
88
+ kinds: TaintKind = TaintKind.ALL
89
+
90
+
91
+ @dataclass(frozen=True)
92
+ class TypedParameter:
93
+ """A parameter annotated with ``symbol`` is attacker-controlled."""
94
+
95
+ symbol: SymbolId
96
+ label: str
97
+ kinds: TaintKind = TaintKind.ALL
98
+
99
+
100
+ @dataclass(frozen=True)
101
+ class NamedParameter:
102
+ """Parameters whose name matches ``pattern`` carry ``kinds`` (``password`` is a
103
+ credential wherever it is a parameter)."""
104
+
105
+ pattern: str
106
+ label: str
107
+ kinds: TaintKind
108
+
109
+ @property
110
+ def symbol(self) -> SymbolId:
111
+ digest = hashlib.sha1(self.pattern.encode("utf-8")).hexdigest()[:12]
112
+ return SymbolId(f"python.parameter.p{digest}")
113
+
114
+ def matches(self, name: str) -> bool:
115
+ return re.search(self.pattern, name) is not None
116
+
117
+
118
+ @dataclass(frozen=True)
119
+ class RouteRegistrar:
120
+ """A call registering a handler elsewhere (``path('login/', views.log_in)``): the
121
+ function or class referenced by ``argument`` (or ``keyword``) is an entry point."""
122
+
123
+ symbol: SymbolId
124
+ argument: int
125
+ label: str
126
+ kinds: TaintKind = TaintKind.ALL
127
+ keyword: str | None = None
128
+
129
+
130
+ @dataclass(frozen=True)
131
+ class SuffixSink:
132
+ """A sink matched by the tail of a call's symbol (``objects.raw`` for any model)."""
133
+
134
+ suffix: str
135
+ kinds: TaintKind
136
+ positions: tuple[tuple[TaintKind, tuple[int, ...]], ...] = ()
137
+
138
+ @property
139
+ def symbol(self) -> SymbolId:
140
+ return SymbolId(f"python.suffix.{self.suffix.replace('.', '_')}")
141
+
142
+
143
+ @dataclass(frozen=True)
144
+ class Validator:
145
+ """A callable whose truth proves its ``argument`` safe (refutation evidence, §24)."""
146
+
147
+ symbol: SymbolId
148
+ kinds: TaintKind = TaintKind.ALL
149
+ argument: int = 0
150
+
151
+
152
+ @dataclass(frozen=True)
153
+ class AuthorizationGuard:
154
+ """A decorator, or a condition, that restricts who reaches the code behind it; a
155
+ flow behind one is a hotspot rather than a vulnerability (§24)."""
156
+
157
+ symbol: SymbolId
158
+ label: str
159
+
160
+
161
+ Model = (
162
+ Source
163
+ | Sink
164
+ | Sanitizer
165
+ | EntryPoint
166
+ | TypedParameter
167
+ | Validator
168
+ | AuthorizationGuard
169
+ | NamedParameter
170
+ | RouteRegistrar
171
+ | SuffixSink
172
+ )
173
+
174
+
175
+ @dataclass(frozen=True)
176
+ class ModelTable:
177
+ sources: tuple[Source, ...]
178
+ sinks: tuple[Sink, ...]
179
+ sanitizers: tuple[Sanitizer, ...]
180
+ entry_points: tuple[EntryPoint, ...] = ()
181
+ typed_parameters: tuple[TypedParameter, ...] = ()
182
+ validators: tuple[Validator, ...] = ()
183
+ authorizations: tuple[AuthorizationGuard, ...] = ()
184
+ named_parameters: tuple[NamedParameter, ...] = ()
185
+ route_registrars: tuple[RouteRegistrar, ...] = ()
186
+ suffix_sinks: tuple[SuffixSink, ...] = ()
187
+ _by_symbol: dict[type[Model], dict[SymbolId, Model]] = field(
188
+ init=False, repr=False, compare=False
189
+ )
190
+
191
+ def __post_init__(self) -> None:
192
+ index: dict[type[Model], dict[SymbolId, Model]] = {
193
+ Source: {m.symbol: m for m in self.sources},
194
+ Sink: {m.symbol: m for m in self.sinks},
195
+ Sanitizer: {m.symbol: m for m in self.sanitizers},
196
+ EntryPoint: {m.symbol: m for m in self.entry_points},
197
+ TypedParameter: {m.symbol: m for m in self.typed_parameters},
198
+ Validator: {m.symbol: m for m in self.validators},
199
+ AuthorizationGuard: {m.symbol: m for m in self.authorizations},
200
+ RouteRegistrar: {m.symbol: m for m in self.route_registrars},
201
+ }
202
+ object.__setattr__(self, "_by_symbol", MappingProxyType(index))
203
+
204
+ def entry_point(self, symbol: SymbolId) -> EntryPoint | None:
205
+ found = self._by_symbol[EntryPoint].get(symbol)
206
+ return found if isinstance(found, EntryPoint) else None
207
+
208
+ def typed_parameter(self, symbol: SymbolId) -> TypedParameter | None:
209
+ found = self._by_symbol[TypedParameter].get(symbol)
210
+ return found if isinstance(found, TypedParameter) else None
211
+
212
+ def validator(self, symbol: SymbolId) -> Validator | None:
213
+ found = self._by_symbol[Validator].get(symbol)
214
+ return found if isinstance(found, Validator) else None
215
+
216
+ def authorization(self, symbol: SymbolId) -> AuthorizationGuard | None:
217
+ found = self._by_symbol[AuthorizationGuard].get(symbol)
218
+ return found if isinstance(found, AuthorizationGuard) else None
219
+
220
+ def source(self, symbol: SymbolId) -> Source | None:
221
+ found = self._by_symbol[Source].get(symbol)
222
+ return found if isinstance(found, Source) else None
223
+
224
+ def source_covering(self, symbol: SymbolId) -> Source | None:
225
+ """The source registered for ``symbol`` or for the closest symbol above it, so a
226
+ source on ``flask.request.args`` also covers ``flask.request.args.get``."""
227
+
228
+ parts = symbol.canonical_name.split(".")
229
+ for length in range(len(parts), 1, -1):
230
+ found = self.source(SymbolId(".".join(parts[:length])))
231
+ if found is not None:
232
+ return found
233
+ return None
234
+
235
+ def sink(self, symbol: SymbolId) -> Sink | None:
236
+ found = self._by_symbol[Sink].get(symbol)
237
+ if isinstance(found, Sink):
238
+ return found
239
+ for suffix in self.suffix_sinks:
240
+ if symbol.canonical_name.endswith(f".{suffix.suffix}"):
241
+ return Sink(symbol, suffix.kinds, suffix.positions)
242
+ return None
243
+
244
+ def route_registrar(self, symbol: SymbolId) -> RouteRegistrar | None:
245
+ found = self._by_symbol[RouteRegistrar].get(symbol)
246
+ return found if isinstance(found, RouteRegistrar) else None
247
+
248
+ def extended(self, *sinks: Sink) -> ModelTable:
249
+ """A table with extra sinks; a sink already present gains the new kinds."""
250
+
251
+ merged = {sink.symbol: sink for sink in self.sinks}
252
+ for sink in sinks:
253
+ current = merged.get(sink.symbol)
254
+ merged[sink.symbol] = (
255
+ Sink(sink.symbol, current.kinds | sink.kinds, current.positions + sink.positions)
256
+ if current is not None
257
+ else sink
258
+ )
259
+ return ModelTable(
260
+ self.sources,
261
+ tuple(merged.values()),
262
+ self.sanitizers,
263
+ self.entry_points,
264
+ self.typed_parameters,
265
+ self.validators,
266
+ self.authorizations,
267
+ self.named_parameters,
268
+ self.route_registrars,
269
+ self.suffix_sinks,
270
+ )
271
+
272
+ def sanitizer(self, symbol: SymbolId) -> Sanitizer | None:
273
+ found = self._by_symbol[Sanitizer].get(symbol)
274
+ return found if isinstance(found, Sanitizer) else None
275
+
276
+
277
+ class SecurityModelRegistry:
278
+ """Mutable collection point for the models plugins register."""
279
+
280
+ def __init__(self) -> None:
281
+ self._models: dict[tuple[type[Model], SymbolId], Model] = {}
282
+
283
+ def register(self, *models: Model) -> None:
284
+ for model in models:
285
+ key = (type(model), model.symbol)
286
+ if key in self._models:
287
+ raise ModelError(
288
+ f"{type(model).__name__.lower()} model for {model.symbol} is already registered"
289
+ )
290
+ self._models[key] = model
291
+
292
+ def freeze(self) -> ModelTable:
293
+ models = list(self._models.values())
294
+ return ModelTable(
295
+ sources=tuple(m for m in models if isinstance(m, Source)),
296
+ sinks=tuple(m for m in models if isinstance(m, Sink)),
297
+ sanitizers=tuple(m for m in models if isinstance(m, Sanitizer)),
298
+ entry_points=tuple(m for m in models if isinstance(m, EntryPoint)),
299
+ typed_parameters=tuple(m for m in models if isinstance(m, TypedParameter)),
300
+ validators=tuple(m for m in models if isinstance(m, Validator)),
301
+ authorizations=tuple(m for m in models if isinstance(m, AuthorizationGuard)),
302
+ named_parameters=tuple(m for m in models if isinstance(m, NamedParameter)),
303
+ route_registrars=tuple(m for m in models if isinstance(m, RouteRegistrar)),
304
+ suffix_sinks=tuple(m for m in models if isinstance(m, SuffixSink)),
305
+ )
306
+
307
+
308
+ class SecurityModelAnalysis(Analysis[ModelTable]):
309
+ """The frozen model table, provided by the engine rather than computed."""
310
+
311
+ name: ClassVar[str] = "taint.models"
312
+
313
+ @classmethod
314
+ def compute(cls, ctx: AnalysisContext) -> ModelTable:
315
+ raise MissingInputError(
316
+ f"{cls.name} must be provided to the analysis manager before it is requested"
317
+ )
@@ -0,0 +1,99 @@
1
+ """Entry points registered away from their definition (architecture §16, §25).
2
+
3
+ Django views are plain functions listed in ``urls.py``; Flask and FastAPI applications
4
+ can register handlers programmatically too. A ``RouteRegistrar`` model names the
5
+ registering call and the argument that references the handler. The engine scans every
6
+ module of a project for such calls before analysing and provides the result as the
7
+ ``taint.routes`` input, so a registered function, or the methods of a registered class,
8
+ receive attacker-controlled parameters wherever they are defined.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ from collections.abc import Iterator, Mapping
14
+ from typing import ClassVar
15
+
16
+ from coretrace_python.analysis import Analysis, AnalysisContext
17
+ from coretrace_python.hir import nodes
18
+ from coretrace_python.hir.visitors import Node, children
19
+ from coretrace_python.interprocedural import project_symbol
20
+ from coretrace_python.semantic.scopes import ScopeTable
21
+ from coretrace_python.semantic.symbols import SymbolId, SymbolTable
22
+ from coretrace_python.taint.models import EntryPoint, ModelTable
23
+
24
+ Routes = Mapping[SymbolId, EntryPoint]
25
+
26
+
27
+ class RegisteredRoutes(Analysis[Routes]):
28
+ """Project symbols registered as handlers, provided by the engine; empty on its own."""
29
+
30
+ name: ClassVar[str] = "taint.routes"
31
+
32
+ @classmethod
33
+ def compute(cls, ctx: AnalysisContext) -> Routes:
34
+ return {}
35
+
36
+
37
+ def registered_routes(
38
+ module: nodes.Module, scopes: ScopeTable, symbols: SymbolTable, models: ModelTable
39
+ ) -> dict[SymbolId, EntryPoint]:
40
+ """The handlers this module registers, as project symbols, with the entry point the
41
+ registrar grants them."""
42
+
43
+ scope = scopes.module_scope.id
44
+ defined = {
45
+ s.name for s in module.body if isinstance(s, nodes.Function | nodes.Class)
46
+ }
47
+ found: dict[SymbolId, EntryPoint] = {}
48
+ for call in _calls(module.body):
49
+ callee = symbols.resolve_expression(scope, call.callee)
50
+ registrar = models.route_registrar(callee) if callee is not None else None
51
+ if registrar is None:
52
+ continue
53
+ handler: nodes.Expression | None = None
54
+ if registrar.argument < len(call.arguments):
55
+ handler = call.arguments[registrar.argument]
56
+ elif registrar.keyword is not None:
57
+ handler = next((k.value for k in call.keywords if k.name == registrar.keyword), None)
58
+ if handler is None:
59
+ continue
60
+ target = _handler_symbol(handler, module, symbols, scope, defined)
61
+ if target is not None:
62
+ found.setdefault(target, EntryPoint(registrar.symbol, registrar.label, registrar.kinds))
63
+ return found
64
+
65
+
66
+ def _handler_symbol(
67
+ handler: nodes.Expression,
68
+ module: nodes.Module,
69
+ symbols: SymbolTable,
70
+ scope: object,
71
+ defined: set[str],
72
+ ) -> SymbolId | None:
73
+ if isinstance(handler, nodes.Call):
74
+ # ``NoteView.as_view()``: the class is the handler.
75
+ handler = handler.callee
76
+ if isinstance(handler, nodes.Attribute) and handler.name == "as_view":
77
+ handler = handler.value
78
+ symbol = symbols.resolve_expression(scope, handler) # type: ignore[arg-type]
79
+ if symbol is not None:
80
+ return symbol
81
+ if isinstance(handler, nodes.Name) and handler.identifier in defined:
82
+ return project_symbol(module.name, handler.identifier)
83
+ return None
84
+
85
+
86
+ def _calls(body: tuple[nodes.Statement, ...]) -> Iterator[nodes.Call]:
87
+ for statement in body:
88
+ if isinstance(statement, nodes.Function | nodes.Class):
89
+ continue
90
+ yield from _calls_in(statement)
91
+
92
+
93
+ def _calls_in(node: Node) -> Iterator[nodes.Call]:
94
+ if isinstance(node, nodes.Function | nodes.Class | nodes.Lambda | nodes.Comprehension):
95
+ return
96
+ if isinstance(node, nodes.Call):
97
+ yield node
98
+ for child in children(node):
99
+ yield from _calls_in(child)
@@ -0,0 +1,74 @@
1
+ Metadata-Version: 2.5
2
+ Name: coretrace-python-analyzer
3
+ Version: 0.1.0
4
+ Summary: Static security analysis infrastructure for Python code
5
+ Project-URL: Homepage, https://github.com/CoreTrace/coretrace-python-analyzer
6
+ Project-URL: Repository, https://github.com/CoreTrace/coretrace-python-analyzer
7
+ Project-URL: Issues, https://github.com/CoreTrace/coretrace-python-analyzer/issues
8
+ Author: CoreTrace
9
+ License: Apache-2.0
10
+ Keywords: python,sast,security,static-analysis,taint
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: Apache Software License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Security
20
+ Classifier: Topic :: Software Development :: Quality Assurance
21
+ Requires-Python: >=3.11
22
+ Provides-Extra: dev
23
+ Requires-Dist: build>=1.2; extra == 'dev'
24
+ Requires-Dist: mypy>=1.15; extra == 'dev'
25
+ Requires-Dist: pytest>=8.0; extra == 'dev'
26
+ Requires-Dist: ruff>=0.9; extra == 'dev'
27
+ Requires-Dist: twine>=5.0; extra == 'dev'
28
+ Description-Content-Type: text/markdown
29
+
30
+ # CoreTrace Python Analyzer
31
+
32
+ A standalone static security analyzer for Python. It finds injection vulnerabilities by
33
+ following attacker-controlled data through the program, across functions, files, objects
34
+ and closures, and judges each flow against the guards on its path; it reports dangerous
35
+ API usage, secrets committed in sources and configuration, and vulnerable or forbidden
36
+ dependencies, correlated with the code that reaches them. It runs offline, on a file or a
37
+ whole project, with no runtime dependency.
38
+
39
+ ```bash
40
+ pip install coretrace-python-analyzer
41
+ coretrace-python-analyzer --check src/ --format sarif > report.sarif
42
+ ```
43
+
44
+ - [Usage guide](docs/usage.md): command line, rules, report formats, dependencies and
45
+ advisories, cache and parallelism, continuous integration.
46
+ - [Writing a plugin](docs/plugins.md): models for another framework, detectors for
47
+ another rule, secret patterns and project-wide checks.
48
+ - [Architecture](docs/architecture.md): the engine's design and its migration plan.
49
+
50
+ The pipeline: source manager, parser-independent high-level representation (PyHIR),
51
+ semantic resolution of imports and scopes, lowering to a small intermediate
52
+ representation (PyIR), control-flow graphs, SSA, data-flow and abstract interpretation,
53
+ interprocedural summaries, taint and refutation, then plugins and reporters.
54
+
55
+ ## Development
56
+
57
+ ```bash
58
+ python -m venv .venv
59
+ python -m pip install -e ".[dev]"
60
+ python -m mypy
61
+ python -m pytest
62
+ python -m ruff check .
63
+ ```
64
+
65
+ The non-regression suite analyses the public repositories pinned in
66
+ [`tests/regression/repositories.toml`](tests/regression/repositories.toml) and compares
67
+ findings and coverage with the snapshots in `tests/regression/expected/`. It clones on
68
+ first use, needs the network and runs in its own CI job:
69
+
70
+ ```bash
71
+ python -m pytest -m regression
72
+ CORETRACE_REGRESSION_UPDATE=1 python -m pytest -m regression # record an intended change
73
+ ```
74
+
@@ -0,0 +1,126 @@
1
+ coretrace_python/__init__.py,sha256=eutxN_wsAP00U-4iZdzViOyOKyUlbDgVeatEdvXDSQ4,75
2
+ coretrace_python/__main__.py,sha256=V8DnYtRboISK2VCKm7DGHLREKvqLbqApyWlKBOs26wU,65
3
+ coretrace_python/cache.py,sha256=CGA-5IpBF60rZc8StfhMRwzGxbG_PSluMyAIRi2AatI,10674
4
+ coretrace_python/cli.py,sha256=jgZMY7-HjZDiN4i2d4qvG_2ryZzUYzM2aEuS_XVm6r4,7966
5
+ coretrace_python/engine.py,sha256=1BYreAq6urpxefoBaQkto8SvaFXQB9EaKpTafttRBEw,25748
6
+ coretrace_python/abstract/__init__.py,sha256=n5FNkV8Z4LmwG0r06KWdLj4N2CPSgAKwY3896tdmRgM,999
7
+ coretrace_python/abstract/constants.py,sha256=z4-e7IzysxzGi58wFFff1MlEoV8l7AZsB9EL-q6b7vY,9071
8
+ coretrace_python/abstract/heap.py,sha256=OaESXFGC0qzyhAr76xrCu4skeDVzZM4wlenQqfMTkdk,9642
9
+ coretrace_python/abstract/ranges.py,sha256=zEl9ee55u3E02tkYzzIvCCud5mYRKIUgZd9h_0-crCM,11547
10
+ coretrace_python/abstract/values.py,sha256=SQmgR8jo7cd8KJFDokejg-cFTjJU1CTBUPYyEvbMg-4,1739
11
+ coretrace_python/analysis/__init__.py,sha256=hE7lDwXOdA05_aSZaERRgMv0C2ev8jjJbz4xvrja4Og,728
12
+ coretrace_python/analysis/manager.py,sha256=suoIrPwimyu1AjF6BJwpqAkJBwe6XxzQu9JwV2TN2aQ,5843
13
+ coretrace_python/analysis/provider.py,sha256=Q_OlEcoLzBAsNdAGWijbj_n3E2Ep5UQ4Z8_skqA5Ui8,2211
14
+ coretrace_python/bundled/dependency/dependency_policy/dependency_policy.py,sha256=_CJYHijv4DTgfdumcCqAVV5_MPWjfZOadxeM5pQdw_k,1845
15
+ coretrace_python/bundled/dependency/dependency_policy/plugin.toml,sha256=4w1TA-UKsa82WTnd1xy4bJuU3_G2RNCAWNICLPcZLMk,210
16
+ coretrace_python/bundled/dependency/reachable_vulnerability/plugin.toml,sha256=LuF9jQqZfplN_GBky69Xjq2pksaX1Fs8PYEir-7-vY8,275
17
+ coretrace_python/bundled/dependency/reachable_vulnerability/reachable_vulnerability.py,sha256=jMNw7-ly4Bhjh3gaUDW7z43HOoQPH9f17M3sZ8HtK2M,2507
18
+ coretrace_python/bundled/dependency/sample_advisories/plugin.toml,sha256=cME4pSFzkFsxmIJGGBSrmXqynAd0dg34X-rgEoZ_u6E,184
19
+ coretrace_python/bundled/dependency/sample_advisories/sample_advisories.py,sha256=uViz4fvg2-u7jFKPtPY2G0yPhr_8Ba09exZc-fcZ2w8,3649
20
+ coretrace_python/bundled/dependency/vulnerable_dependency/plugin.toml,sha256=FbmiXLEqtPUZEsDc5q_UqCzn6AecL5HCSdGVy7_2dy0,238
21
+ coretrace_python/bundled/dependency/vulnerable_dependency/vulnerable_dependency.py,sha256=Mu4pOhNrfxds-qsFr9_DZOAQHaW2QAKxwelQEpm41vU,1871
22
+ coretrace_python/bundled/models/cli/cli_models.py,sha256=BfeXGLbS-3EnzYrJMhZeViQO9ZUZB-EFtxobWj-oW8M,977
23
+ coretrace_python/bundled/models/cli/plugin.toml,sha256=D2gkrL1lWc6b4ME_C0hjzwZHJX1l_OChRs3_oapam_s,163
24
+ coretrace_python/bundled/models/credentials/credential_models.py,sha256=Mw9ty8PDDyLNPtbPTTm-sIY9XE8gBsi02dPmLeum2kE,1423
25
+ coretrace_python/bundled/models/credentials/plugin.toml,sha256=0ut7Jc7IdcvbsZKPu6ty-z3DBlMg2CUT7JX4y4nMybo,217
26
+ coretrace_python/bundled/models/django/django_models.py,sha256=87NCkJ5BKWgF_kXnKLJC_tfsQAjqbhkE4o022_bkrok,5339
27
+ coretrace_python/bundled/models/django/plugin.toml,sha256=_Qa2X_4IViORQkcLvLsAC5vI-2P5CxgG8VvnuNIWcFQ,214
28
+ coretrace_python/bundled/models/fastapi/fastapi_models.py,sha256=K2Edlo1RzYKmAJAIChNVUDc8gorAS48MGEMKNlCIGrI,1251
29
+ coretrace_python/bundled/models/fastapi/plugin.toml,sha256=V_R2WcEc-qkST0tTpL-cRf2FEbjK6Mk727WbJmVpWJM,200
30
+ coretrace_python/bundled/models/flask/flask_models.py,sha256=CVspfwmn56fMg8LlhgZUm351_Zw8d8InNv_UZcoIusg,2171
31
+ coretrace_python/bundled/models/flask/plugin.toml,sha256=kI53Xwf5aZKd2n3fEQEbBzNnOXRvuonqEazTOIXPJP4,192
32
+ coretrace_python/bundled/models/http_clients/http_client_models.py,sha256=TmVIg66zRRQxx3C9RT2XX6xLhemm037hIIBFRSyKzU0,1273
33
+ coretrace_python/bundled/models/http_clients/plugin.toml,sha256=vq9tWHgy8-m8LiU1StGhm9Lsy7vnj3w90P4AKDaKfc0,216
34
+ coretrace_python/bundled/models/python_stdlib/plugin.toml,sha256=DWqjG68rx91HCJi_VEp6tUs4ujkzlR7Lq7saMvtK2HM,187
35
+ coretrace_python/bundled/models/python_stdlib/python_stdlib.py,sha256=y88cIJ5Jfw7qCAgvHsXYu7BmVhhCBv66qk4FN0Moh84,3234
36
+ coretrace_python/bundled/models/sqlalchemy/plugin.toml,sha256=2gRbglnMK5U2QWnzs2U2pDvmTeWmrlW7XpJ_8dRmIoY,182
37
+ coretrace_python/bundled/models/sqlalchemy/sqlalchemy_models.py,sha256=Gm2qjyXUrjzALy-MigUhPQyyDxYdfWlQKDZLp1C6Jqk,1697
38
+ coretrace_python/bundled/secrets/config_secrets/config_secrets.py,sha256=JfhWSyVbjlYD9pQYJN6qAc4Rp4IA8PP222akM4KTPU8,1283
39
+ coretrace_python/bundled/secrets/config_secrets/plugin.toml,sha256=dRkA3zQ9wtT2EJyqZ5zGqJ5KYdyIQtQcSvesqrb4M0Q,177
40
+ coretrace_python/bundled/secrets/hardcoded_secrets/hardcoded_secrets.py,sha256=7TD-Nf5S4yfoRBRmJ6Ab6v4Q2zIC2n79FRfNS3I4xos,544
41
+ coretrace_python/bundled/secrets/hardcoded_secrets/plugin.toml,sha256=bkhRJFUrTFP2LiggDP3PkQpC0REtTq8aWrqlkYzxVHc,231
42
+ coretrace_python/bundled/security/command_injection/command_injection.py,sha256=d8CgmU0tWyhuLk_GTaUQHQaWlKIxC5TDY-K370tdyhE,573
43
+ coretrace_python/bundled/security/command_injection/plugin.toml,sha256=x9NUpwdVZsTQpaPNX3HoYcrZWk4sOGN-aSp9Bc8jvCA,240
44
+ coretrace_python/bundled/security/insecure_deserialization/insecure_deserialization.py,sha256=-4KIQDaYo-09gSceuNEs3eutmBn2OBuYBTqiUEYOatk,637
45
+ coretrace_python/bundled/security/insecure_deserialization/plugin.toml,sha256=5OTVO9jZN-HBid8v__jYkxU-RnKX974Qqu7JQMFdj54,268
46
+ coretrace_python/bundled/security/open_redirect/open_redirect.py,sha256=nUjVIgYhVh_2xBs8_1LOfcLDgQ3g3z1E7APqg2sBdpo,562
47
+ coretrace_python/bundled/security/open_redirect/plugin.toml,sha256=8t4KLNG1DIpjjen6TuKxMjz2jv6GDcwVJDm_hJUalCg,224
48
+ coretrace_python/bundled/security/path_traversal/path_traversal.py,sha256=MiTDZBNU6i3WWua1qaxg1swqDy3wlWwBwG6G4ClyDgw,552
49
+ coretrace_python/bundled/security/path_traversal/plugin.toml,sha256=f0ADZimUvQatOffltF5Ihu1mkzf5rNrsaIpKBg2v39c,228
50
+ coretrace_python/bundled/security/plaintext_credentials/plaintext_credentials.py,sha256=QaE2CXAdl0bi4dE5d2d8KnLJrsAcxUDjR76ghfsnXXo,900
51
+ coretrace_python/bundled/security/plaintext_credentials/plugin.toml,sha256=W56wUdAdf7NNirfQhTdKrn-cCwebqmvkRJg9OVFJUyM,263
52
+ coretrace_python/bundled/security/sql_injection/plugin.toml,sha256=U35h6YdbbM93Ar_msWrwY98_bb6rN-qaa1e7XOtPeSo,224
53
+ coretrace_python/bundled/security/sql_injection/sql_injection.py,sha256=W-ppZngb9mLwRjJPGkh__8kaDqYdSrVbciv0mPdYFNE,545
54
+ coretrace_python/bundled/security/ssrf/plugin.toml,sha256=OySYgL9rGh1f4UuVpEOWdgcyp0vAmaP1m2IJ8Al6Ddc,189
55
+ coretrace_python/bundled/security/ssrf/ssrf.py,sha256=bshcPZMjuQtTR4203CUTxFGZuwIYfsi58rnE5XdqKXc,549
56
+ coretrace_python/bundled/security/xss/plugin.toml,sha256=o6aZWoDNCG6CJ11JDa5lVR0v6NHh-Jg5QpNRxoGSJaw,185
57
+ coretrace_python/bundled/security/xss/xss.py,sha256=hzhoblPMivtwoWZ4v7YyAb15GGisX_imGWgxFzCDeqA,532
58
+ coretrace_python/bundled/syntax/dangerous_eval/dangerous_eval.py,sha256=_ktrigLDf-XTKjWtYX-_wZ9-Gb3G4bCzRhpU0Xj-c1g,723
59
+ coretrace_python/bundled/syntax/dangerous_eval/plugin.toml,sha256=97Eyrcet1jcewAIPa78IKYz9XgiOVsZSJ4vWYdMer2I,200
60
+ coretrace_python/bundled/syntax/flask_debug/flask_debug.py,sha256=28OH3_Im_c_xsMxrjpXmCoBHvLOHQ4DT77dFBAwafbs,2596
61
+ coretrace_python/bundled/syntax/flask_debug/plugin.toml,sha256=bz_6Njz6PAgK-o-yFBWB3U2g2vX6_5cFTfwrkkyQmGA,210
62
+ coretrace_python/bundled/syntax/missing_timeout/missing_timeout.py,sha256=fp_IZDhCdaXR6A5tqvWUA-7jCUxqPpB5zRJH_jnaJQQ,2359
63
+ coretrace_python/bundled/syntax/missing_timeout/plugin.toml,sha256=ZsoxXj_a1RxyhIt8FjwnaWDKvX0xpe8eGEof0WP_BwY,226
64
+ coretrace_python/bundled/syntax/weak_crypto/plugin.toml,sha256=fTAnNZZ7N8-2WVJbmtQ3gJzKfBV5eTUkPfiPzj7R-aM,188
65
+ coretrace_python/bundled/syntax/weak_crypto/weak_crypto.py,sha256=OAOuYR1f4Lc_JxdiHs1wxRRKC4K1kayg5REFIlHK71k,671
66
+ coretrace_python/cfg/__init__.py,sha256=2bJEVjyyVwwciPvxiZuNAOpSVO36yutNRGc-7R54EXw,836
67
+ coretrace_python/cfg/builder.py,sha256=bZdSz2LNDOz-DyQ4wu05s1yxpUCSrgOJZ8hpmcA2YgM,27859
68
+ coretrace_python/cfg/dominance.py,sha256=QpM4-mKVMxe75ZLyqx2_1x-4v5WJd9iDqIdi4C7S7rQ,6602
69
+ coretrace_python/cfg/model.py,sha256=6EJiXFAGrsMgCdyxMJ6TClY8tQhJF6Hq2bX802Gc0yg,5308
70
+ coretrace_python/dataflow/__init__.py,sha256=N5uY8VTNjEk6-ARCgDkxr6uGqQIz2NbF-U9sC_v_lfA,547
71
+ coretrace_python/dataflow/lattice.py,sha256=HgYGVcKVUlexvEc0yT47aQCudLxU_SWLpHhr17igkiE,1929
72
+ coretrace_python/dataflow/solver.py,sha256=iDsW0wujhM2DXplu2JMKC46BRsroXlNETHPEoikPeG4,3475
73
+ coretrace_python/dependency/__init__.py,sha256=JOa2OupSyMe6COiSF9Cah6kcdqYJewFprWi9-E1Je6Q,983
74
+ coretrace_python/dependency/advisories.py,sha256=BDZatgUvxeW8vOLLnGax49gSPBO3yiRlUHcPpaZKeMc,6333
75
+ coretrace_python/dependency/correlation.py,sha256=psRKsca9W8Mr790VfFHIjGiblE0k4onKIW-Y2nlt8I0,3562
76
+ coretrace_python/dependency/graph.py,sha256=LIH8PdBBzpqNsic8tQHQmO8LuTJXEHSDHDGnW0mKjwc,10812
77
+ coretrace_python/dependency/policy.py,sha256=u6nUw2nX-kTuqmw_vooxN8eXZoC31ZMoMaxC9pCcwec,2317
78
+ coretrace_python/dependency/sbom.py,sha256=h4K3Gb9O_D6uZyfpwpC5rPcNjH_Ib-3uvFxix6OKlfs,2520
79
+ coretrace_python/findings/__init__.py,sha256=gnJI-uB2CkgZ8I5aFYP_N5yZb7FGNIy7LirVDh4NLwo,372
80
+ coretrace_python/findings/coverage.py,sha256=U8URLEz6EN4B_TTQlLFCOtEmUbINt7a0Bexb-6OUFlI,1203
81
+ coretrace_python/findings/model.py,sha256=lUfefeq3tyYrTu8lA11JbYcHi_JleqWBL3vh7R89E1c,1147
82
+ coretrace_python/findings/refutation.py,sha256=wL26drcy0JB-qHlRpb4jaYWej209GxTi2tt5SWnfCFw,17465
83
+ coretrace_python/frontend/__init__.py,sha256=ULI2tf_IRTMboaKM6uzTkGGh4Agy3cFjtw2H1IPrz4g,627
84
+ coretrace_python/frontend/ast_adapter.py,sha256=oFILfv3NElabtqA-v4xskb0ztz4_ya_dgErDB3s2Yx4,21661
85
+ coretrace_python/frontend/parser.py,sha256=6-CG7rWxUYeOGeDP206SJWy4BMQUP9Mr6Jf-thaFm0s,669
86
+ coretrace_python/hir/__init__.py,sha256=xMpvj-RSp6bd78a_hhkqbe99-snjERkH-_Lv5o9ASbw,180
87
+ coretrace_python/hir/nodes.py,sha256=xvVJq1QmdjKsrS3nuSO8Uf1nX_1aZAyE6ZdCudi-_KY,11843
88
+ coretrace_python/hir/visitors.py,sha256=JFnX09hK6trLyRcWgZ5ehOG2ywX3VvkqQ1h82nahYNg,885
89
+ coretrace_python/interprocedural/__init__.py,sha256=uWnJK9v_ZCXiA-2Z64nkLuyUg1EOAhnVkJ3WxHZhsVM,1014
90
+ coretrace_python/interprocedural/callgraph.py,sha256=ZtOip87-TgQ_DYLhDiR5Z03VsU0jxUVNgMkEkDuNZ4Q,12380
91
+ coretrace_python/interprocedural/modulegraph.py,sha256=0UIKtxxAfTV7WW4B0xcJgVnD-Z6KRS3hpOTMshj1E_U,8595
92
+ coretrace_python/interprocedural/summaries.py,sha256=BLB6nbWZFIHe54Cj1p64jhOLYm9xc1qvJmpoWQi-clw,17657
93
+ coretrace_python/ir/__init__.py,sha256=ShBPYYqoQFePP-mgBjGezQ2acel0-ReOHF9vCC-G_4Q,232
94
+ coretrace_python/ir/defuse.py,sha256=CZEPnlgntRp4MqwR7kLldd2ZlIlBnr-V9VJAxXxwm0c,2616
95
+ coretrace_python/ir/lowering.py,sha256=1Ctuiq_TWzSuNg5eJe438wQ-bve6toKI4VNQJPLlGXE,25739
96
+ coretrace_python/ir/model.py,sha256=cugasB1E05jLAoQyWkGQHvPMsyDEcyL5tbagKqYqRgU,10520
97
+ coretrace_python/ir/printer.py,sha256=iMwFitjwFIM0gelpZelmzTWefwLdxOc37DlPkywI7is,8800
98
+ coretrace_python/ir/ssa.py,sha256=cIYbcv90PI6AOeMrw2ZWp88fy7E2ZO4P3tqjtPHra7g,11116
99
+ coretrace_python/plugins/__init__.py,sha256=Jh5oLVI_Rc7ZzibsMjJzg69LGeNcRRjLcY5XaVOhjgA,1308
100
+ coretrace_python/plugins/api.py,sha256=y1bicTdPypstWs7aJ4JDIOSVKX-MwFq5NSjGntTZhDw,5309
101
+ coretrace_python/plugins/detectors.py,sha256=RcCSsPpFiq4CTrC0IzXTXEAAWoMQXMAhAARgp182f7g,4781
102
+ coretrace_python/plugins/loader.py,sha256=e7S6l3VhMpku0HpnAl5qbBRFiOlsSf66P7low7RsRvU,3174
103
+ coretrace_python/plugins/manifest.py,sha256=F24pgQSwApRUL6ZihRSLv9wL_M03A_pZjrj9Zi4Ku3Q,3438
104
+ coretrace_python/plugins/registry.py,sha256=ixKcT2YDky96TWCFckdzKnGRmFn1dbBVMSZLPvdxvY8,1177
105
+ coretrace_python/plugins/secrets.py,sha256=SqoejVzHHRKn0vSiWBlmN-VEGXX3QgbcgBQ0zG_hkMk,12494
106
+ coretrace_python/reporters/__init__.py,sha256=MHTEfIj5q1KvFeIm6aAzt4mwL8oCZMkpYlaAGaq_cdo,764
107
+ coretrace_python/reporters/json_format.py,sha256=IvtyN2u3w-fYEtrTZtAJu_7L2NRr29B8IIVJBny9L88,1633
108
+ coretrace_python/reporters/report.py,sha256=V2_MQwtChhU65vyiVSBFi4tXs9YKdEMWD5MxQ3470UY,654
109
+ coretrace_python/reporters/sarif.py,sha256=FOmNX2_QzcEGRFMRwPHMt5ckJKp6UTKEwioOTTdD5tU,2125
110
+ coretrace_python/reporters/text.py,sha256=0X6PZYjYdpNlXnAovkH6g4kWZkcIUcT5-5tycM3RF7I,854
111
+ coretrace_python/semantic/__init__.py,sha256=_tjT9CgXfPbOMs8EFguhWrLeSmpyrqOHU_OSoQPiWYs,411
112
+ coretrace_python/semantic/identity.py,sha256=uQBdqEXrOtYmGIiR9hZu0Pimv52iW1rOOOvIdG0InNY,1472
113
+ coretrace_python/semantic/imports.py,sha256=389MZs8iTUc3CyUHG0VAgWFsypd7VPFKkLHmFz9L-N0,5673
114
+ coretrace_python/semantic/scopes.py,sha256=ZCSu2XRo042BC8Ksj-drMUDIQfpBgcM83x368H2M2kI,19526
115
+ coretrace_python/semantic/symbols.py,sha256=3JptnnX5_KBlSd00L_wcGlYZQdnmBvSBAhfivBF6DLo,3513
116
+ coretrace_python/source/__init__.py,sha256=0Y8fvtbkETnNCJR9Zq7RS5TSgF9c22pz3SSk1KdAXF0,301
117
+ coretrace_python/source/manager.py,sha256=JRmMOcWfS1nocbVrdcvfQTqEfIkmnb5JP857TpGywN4,2736
118
+ coretrace_python/source/model.py,sha256=FZnN5mlir3tzbIpWoxnn6YtRi9UcJ_y0sZM60tKr8U4,1727
119
+ coretrace_python/taint/__init__.py,sha256=D-NH3kx9wKTNeWASewawGAx7ChOkGMGhmjf-E4crHl0,1111
120
+ coretrace_python/taint/engine.py,sha256=NEDJryXqCgc0l8STZ3fSMx-aD-8BO5z8YZLnAgaC7Pw,32452
121
+ coretrace_python/taint/models.py,sha256=s7luO5vMaowxPcWoThkLTEdYuyw0JZZVkaKYW5o_xOI,10930
122
+ coretrace_python/taint/routes.py,sha256=0ICYweRBktlXC0nZYIPi9rxHYEddJXAg_sAc7f_8Ie4,3865
123
+ coretrace_python_analyzer-0.1.0.dist-info/METADATA,sha256=CI39rQWDZ48ltOrKGltLAkYRR-LFzz13stLxCBnP3Nk,3148
124
+ coretrace_python_analyzer-0.1.0.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
125
+ coretrace_python_analyzer-0.1.0.dist-info/entry_points.txt,sha256=wdozemiraOkbt65g_Y_zgspuZpoLxJdaCVMJt1Ft3c0,72
126
+ coretrace_python_analyzer-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.32.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ coretrace-python-analyzer = coretrace_python.cli:main