src2sink 1.0.0__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.
Files changed (124) hide show
  1. src2sink-1.0.0/LICENSE +21 -0
  2. src2sink-1.0.0/PKG-INFO +355 -0
  3. src2sink-1.0.0/README.md +320 -0
  4. src2sink-1.0.0/pyproject.toml +99 -0
  5. src2sink-1.0.0/setup.cfg +4 -0
  6. src2sink-1.0.0/src2sink/__init__.py +1 -0
  7. src2sink-1.0.0/src2sink/aggregators/__init__.py +3 -0
  8. src2sink-1.0.0/src2sink/aggregators/api_client_discovery.py +259 -0
  9. src2sink-1.0.0/src2sink/aggregators/auth_cards.py +116 -0
  10. src2sink-1.0.0/src2sink/aggregators/crypto_cards.py +132 -0
  11. src2sink-1.0.0/src2sink/aggregators/data_stores.py +125 -0
  12. src2sink-1.0.0/src2sink/aggregators/graphs.py +36 -0
  13. src2sink-1.0.0/src2sink/aggregators/index_v2.py +138 -0
  14. src2sink-1.0.0/src2sink/aggregators/library_source_map.py +188 -0
  15. src2sink-1.0.0/src2sink/aggregators/openapi_discovery.py +113 -0
  16. src2sink-1.0.0/src2sink/aggregators/openapi_edges.py +30 -0
  17. src2sink-1.0.0/src2sink/aggregators/openapi_match.py +81 -0
  18. src2sink-1.0.0/src2sink/aggregators/openapi_models.py +25 -0
  19. src2sink-1.0.0/src2sink/aggregators/openapi_report.py +75 -0
  20. src2sink-1.0.0/src2sink/aggregators/payload_producers.py +369 -0
  21. src2sink-1.0.0/src2sink/aggregators/phase3.py +30 -0
  22. src2sink-1.0.0/src2sink/aggregators/pii_cross_repo.py +283 -0
  23. src2sink-1.0.0/src2sink/aggregators/pii_flow_v2.py +118 -0
  24. src2sink-1.0.0/src2sink/aggregators/pii_lifecycle.py +19 -0
  25. src2sink-1.0.0/src2sink/aggregators/pii_lifecycle_report.py +121 -0
  26. src2sink-1.0.0/src2sink/aggregators/pii_touchpoint_collect.py +134 -0
  27. src2sink-1.0.0/src2sink/aggregators/pii_touchpoint_utils.py +96 -0
  28. src2sink-1.0.0/src2sink/aggregators/queues.py +141 -0
  29. src2sink-1.0.0/src2sink/aggregators/ropa.py +190 -0
  30. src2sink-1.0.0/src2sink/aggregators/service_call_collect.py +240 -0
  31. src2sink-1.0.0/src2sink/aggregators/service_call_index.py +31 -0
  32. src2sink-1.0.0/src2sink/aggregators/service_call_models.py +17 -0
  33. src2sink-1.0.0/src2sink/aggregators/service_call_report.py +118 -0
  34. src2sink-1.0.0/src2sink/aggregators/service_calls.py +14 -0
  35. src2sink-1.0.0/src2sink/aggregators/taint_buckets.py +74 -0
  36. src2sink-1.0.0/src2sink/aggregators/taint_catalogs.py +35 -0
  37. src2sink-1.0.0/src2sink/aggregators/taint_writers.py +369 -0
  38. src2sink-1.0.0/src2sink/aggregators/traces_index.py +103 -0
  39. src2sink-1.0.0/src2sink/build_metabase_v2.py +807 -0
  40. src2sink-1.0.0/src2sink/constants.py +44 -0
  41. src2sink-1.0.0/src2sink/curate_internal_libraries.py +135 -0
  42. src2sink-1.0.0/src2sink/extractors/__init__.py +17 -0
  43. src2sink-1.0.0/src2sink/extractors/ast_walk.py +131 -0
  44. src2sink-1.0.0/src2sink/extractors/base.py +59 -0
  45. src2sink-1.0.0/src2sink/extractors/config.py +224 -0
  46. src2sink-1.0.0/src2sink/extractors/file_context.py +35 -0
  47. src2sink-1.0.0/src2sink/extractors/go.py +3 -0
  48. src2sink-1.0.0/src2sink/extractors/http_out.py +108 -0
  49. src2sink-1.0.0/src2sink/extractors/java.py +3 -0
  50. src2sink-1.0.0/src2sink/extractors/javascript.py +3 -0
  51. src2sink-1.0.0/src2sink/extractors/kotlin.py +3 -0
  52. src2sink-1.0.0/src2sink/extractors/node_factory.py +65 -0
  53. src2sink-1.0.0/src2sink/extractors/patterns.py +145 -0
  54. src2sink-1.0.0/src2sink/extractors/python_extractor.py +3 -0
  55. src2sink-1.0.0/src2sink/extractors/regex_extractors.py +378 -0
  56. src2sink-1.0.0/src2sink/extractors/ts_extractors.py +123 -0
  57. src2sink-1.0.0/src2sink/extractors/unified.py +64 -0
  58. src2sink-1.0.0/src2sink/graph_common.py +213 -0
  59. src2sink-1.0.0/src2sink/internal_groups.py +142 -0
  60. src2sink-1.0.0/src2sink/known_api_clients.py +108 -0
  61. src2sink-1.0.0/src2sink/library_taint_java.py +92 -0
  62. src2sink-1.0.0/src2sink/limits.py +171 -0
  63. src2sink-1.0.0/src2sink/models/__init__.py +3 -0
  64. src2sink-1.0.0/src2sink/models/auth_model.py +3 -0
  65. src2sink-1.0.0/src2sink/models/crypto_agility.py +3 -0
  66. src2sink-1.0.0/src2sink/models/pii_lifecycle.py +92 -0
  67. src2sink-1.0.0/src2sink/models/ropa.py +37 -0
  68. src2sink-1.0.0/src2sink/prescreen.py +93 -0
  69. src2sink-1.0.0/src2sink/py.typed +0 -0
  70. src2sink-1.0.0/src2sink/record_fleet_baseline.py +81 -0
  71. src2sink-1.0.0/src2sink/renderers/__init__.py +3 -0
  72. src2sink-1.0.0/src2sink/renderers/markdown.py +149 -0
  73. src2sink-1.0.0/src2sink/renderers/mermaid.py +3 -0
  74. src2sink-1.0.0/src2sink/repo_utils.py +885 -0
  75. src2sink-1.0.0/src2sink/safe_paths.py +54 -0
  76. src2sink-1.0.0/src2sink/sanitize.py +107 -0
  77. src2sink-1.0.0/src2sink/schema.py +57 -0
  78. src2sink-1.0.0/src2sink/trace.py +558 -0
  79. src2sink-1.0.0/src2sink/trace_batch.py +176 -0
  80. src2sink-1.0.0/src2sink/vocabulary.py +152 -0
  81. src2sink-1.0.0/src2sink.egg-info/PKG-INFO +355 -0
  82. src2sink-1.0.0/src2sink.egg-info/SOURCES.txt +122 -0
  83. src2sink-1.0.0/src2sink.egg-info/dependency_links.txt +1 -0
  84. src2sink-1.0.0/src2sink.egg-info/entry_points.txt +6 -0
  85. src2sink-1.0.0/src2sink.egg-info/requires.txt +12 -0
  86. src2sink-1.0.0/src2sink.egg-info/top_level.txt +1 -0
  87. src2sink-1.0.0/tests/test_aggregators_extra.py +130 -0
  88. src2sink-1.0.0/tests/test_api_client_discovery.py +148 -0
  89. src2sink-1.0.0/tests/test_build_internals.py +72 -0
  90. src2sink-1.0.0/tests/test_build_main.py +58 -0
  91. src2sink-1.0.0/tests/test_characterization.py +248 -0
  92. src2sink-1.0.0/tests/test_config_hygiene.py +76 -0
  93. src2sink-1.0.0/tests/test_curate.py +78 -0
  94. src2sink-1.0.0/tests/test_dependency_pinning.py +106 -0
  95. src2sink-1.0.0/tests/test_field_precision.py +83 -0
  96. src2sink-1.0.0/tests/test_graph_common.py +74 -0
  97. src2sink-1.0.0/tests/test_internal_groups.py +51 -0
  98. src2sink-1.0.0/tests/test_limits.py +158 -0
  99. src2sink-1.0.0/tests/test_module_imports.py +23 -0
  100. src2sink-1.0.0/tests/test_openapi.py +72 -0
  101. src2sink-1.0.0/tests/test_output_neutralisation.py +33 -0
  102. src2sink-1.0.0/tests/test_phase0_smoke.py +83 -0
  103. src2sink-1.0.0/tests/test_phase1_config.py +53 -0
  104. src2sink-1.0.0/tests/test_phase1_extractors.py +96 -0
  105. src2sink-1.0.0/tests/test_phase2_graphs.py +184 -0
  106. src2sink-1.0.0/tests/test_phase3_pii.py +161 -0
  107. src2sink-1.0.0/tests/test_phase4_aggregators.py +67 -0
  108. src2sink-1.0.0/tests/test_phase4_extractor_snapshots.py +130 -0
  109. src2sink-1.0.0/tests/test_phase4_fleet_regression.py +66 -0
  110. src2sink-1.0.0/tests/test_phase4_regression.py +111 -0
  111. src2sink-1.0.0/tests/test_phase4_taint_caps.py +90 -0
  112. src2sink-1.0.0/tests/test_post_phase4_backlog.py +107 -0
  113. src2sink-1.0.0/tests/test_prescreen.py +81 -0
  114. src2sink-1.0.0/tests/test_redos_bounds.py +151 -0
  115. src2sink-1.0.0/tests/test_renderers.py +52 -0
  116. src2sink-1.0.0/tests/test_repo_utils_helpers.py +174 -0
  117. src2sink-1.0.0/tests/test_run_manifest.py +68 -0
  118. src2sink-1.0.0/tests/test_sanitize.py +161 -0
  119. src2sink-1.0.0/tests/test_security_input_handling.py +205 -0
  120. src2sink-1.0.0/tests/test_source_map_fix.py +230 -0
  121. src2sink-1.0.0/tests/test_trace_batch.py +70 -0
  122. src2sink-1.0.0/tests/test_trace_render.py +110 -0
  123. src2sink-1.0.0/tests/test_zz_security_coverage_gate.py +57 -0
  124. src2sink-1.0.0/tests/test_zz_untrusted_interpolation_guard.py +84 -0
src2sink-1.0.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Mimecast Services Limited
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,355 @@
1
+ Metadata-Version: 2.4
2
+ Name: src2sink
3
+ Version: 1.0.0
4
+ Summary: Cross-repository source-to-sink metabase for LLM-assisted SAST
5
+ Author: Brett Crawley
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/mimecast/src2sink
8
+ Project-URL: Repository, https://github.com/mimecast/src2sink
9
+ Project-URL: Issues, https://github.com/mimecast/src2sink/issues
10
+ Keywords: sast,static-analysis,taint-analysis,security,tree-sitter,llm
11
+ Classifier: Development Status :: 5 - Production/Stable
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Intended Audience :: Information Technology
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.14
16
+ Classifier: Topic :: Security
17
+ Classifier: Topic :: Software Development :: Quality Assurance
18
+ Classifier: Typing :: Typed
19
+ Requires-Python: >=3.14
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Requires-Dist: defusedxml>=0.7.1
23
+ Requires-Dist: ipykernel>=7.2.0
24
+ Requires-Dist: jupyterlab>=4.5.7
25
+ Requires-Dist: openpyxl>=3.1.5
26
+ Requires-Dist: pandas>=3.0.2
27
+ Requires-Dist: tree-sitter>=0.25.2
28
+ Requires-Dist: tree-sitter-go>=0.25.0
29
+ Requires-Dist: tree-sitter-java>=0.23.5
30
+ Requires-Dist: tree-sitter-javascript>=0.25.0
31
+ Requires-Dist: tree-sitter-kotlin>=1.1.0
32
+ Requires-Dist: tree-sitter-python>=0.25.0
33
+ Requires-Dist: tree-sitter-typescript>=0.23.2
34
+ Dynamic: license-file
35
+
36
+ ![src2sink logo](https://raw.githubusercontent.com/mimecast/src2sink/main/images/src2sink-logo-light.png)
37
+ # Source-Code Metabase
38
+
39
+ [![CI](https://github.com/mimecast/src2sink/actions/workflows/ci.yml/badge.svg)](https://github.com/mimecast/src2sink/actions/workflows/ci.yml)
40
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/mimecast/src2sink/blob/main/LICENSE)
41
+
42
+ A structured, human-readable knowledge base of the analysed source-code
43
+ ecosystem. Designed to be loaded as **context for LLM SAST** so that
44
+ cross-repository taint analysis becomes possible — sources in one repo,
45
+ sinks in another, internal libraries that act as transparent pass-
46
+ throughs to dangerous APIs.
47
+
48
+ **Canonical field definitions:** [`SCHEMA.md`](https://github.com/mimecast/src2sink/blob/main/SCHEMA.md)
49
+ **Roadmap / gaps:** [`NEXT_STEPS.md`](https://github.com/mimecast/src2sink/blob/main/NEXT_STEPS.md)
50
+
51
+ ---
52
+
53
+ ## Why this exists
54
+
55
+ Conventional SAST tools work one repository at a time and cannot
56
+ follow:
57
+
58
+ 1. **Cross-repo SQL injection** — service A constructs a SQL fragment
59
+ and forwards it as a payload to service B which executes it.
60
+ 2. **Internal-library black boxes** — shared wrappers hide JDBC/JPA sinks.
61
+ 3. **Cross-repo PII flow** — ingress → queue → store → log → third party.
62
+ 4. **Crypto agility** — algorithms and keys decided in config or shared libs.
63
+ 5. **Dangerous request payloads** — e.g. raw SQL accepted on an HTTP
64
+ endpoint (`acme/sql-runner-api` `/query`).
65
+
66
+ The metabase captures cross-repo facts so an LLM (or human) can reason
67
+ about the full path, not a single repo in isolation.
68
+
69
+ ---
70
+
71
+ ## Contents at a glance
72
+
73
+ ### Per-repo (gitignored after generation)
74
+
75
+ | Path | Content |
76
+ |------|---------|
77
+ | `repos/<group>/<repo>.md` | Flow-node summary |
78
+ | `repos/<group>/<repo>.json` | Flow graph (`schema_version: 2`, `nodes[]`, `edges[]`) |
79
+
80
+ ### Cross-repo catalogues (mostly gitignored)
81
+
82
+ | Folder / file | Purpose |
83
+ |---------------|---------|
84
+ | `taint/sql-sources.md` + `.jsonl` | SQL string construction (concat / template) |
85
+ | `taint/sql-execution-sinks.md` + `.jsonl` | JDBC/JPA/native execution sinks |
86
+ | `taint/file-sinks.md` + `.jsonl` | File-write / archive extract |
87
+ | `taint/http-sinks.md` + `.jsonl` | Outbound HTTP client calls |
88
+ | `taint/pii-sources.md` + `.jsonl` | PII field declarations (bounded MD + full jsonl) |
89
+ | `taint/pii-sinks.md` + `.jsonl` | PII in logs / storage (`field_name` null = generic `.save` etc. without nearby PII token — see `SCHEMA.md`) |
90
+ | `taint/crypto-operations.md` + `.jsonl` | Crypto algorithm use |
91
+ | `taint/raw-code-payload-endpoints.md` + `.jsonl` | HTTP handlers that accept `sql`/… and reach SQL execution in-file |
92
+ | `taint/config-data-stores.md` + `.jsonl` | JDBC/Mongo/Redis/S3 from config |
93
+ | `taint/config-security.md` + `.jsonl` | Security-sensitive config keys |
94
+ | `taint/config-crypto.md` + `.jsonl` | Cipher suites / signing algorithms from config |
95
+ | `graphs/service-call-graph.md` + `service-call-edges.jsonl` | Cross-repo HTTP edges (`http-in` ↔ enriched `http-out`) |
96
+ | `graphs/queue-graph.md` + `.jsonl` | Topic producers / consumers |
97
+ | `graphs/data-store-graph.md` + `.jsonl` | Config-discovered stores ↔ repos |
98
+ | `graphs/payload-endpoint-producers.md` + `.jsonl` | Registered API clients → target services |
99
+ | `graphs/pii-lifecycle.md` + `.jsonl` | PII lifecycle stages (Phase 3) |
100
+ | `graphs/pii-phone-cross-repo.md` + `.jsonl` | Cross-repo phone hops (queue + HTTP) |
101
+ | `ropa/categories-of-personal-data.md` | ROPA Article 30 projection (Phase 3) |
102
+ | `conventions/auth-models.md` + `.jsonl` | Per-repo auth cards (Phase 3) |
103
+ | `conventions/crypto-agility.md` + `.jsonl` | Per-repo crypto cards (Phase 3) |
104
+ | `graphs/traces/<target>.md` | Endpoint traces (`trace.py` / `trace_batch.py`) |
105
+
106
+ ### Hand-authored (committed)
107
+
108
+ | Path | Purpose |
109
+ |------|---------|
110
+ | `SCHEMA.md` | Field and node-family definitions |
111
+ | `README.md` | This file |
112
+ | `NEXT_STEPS.md` | Gaps and follow-ups |
113
+ | `internal-libraries/<coord>.md` | Per-library taint tables (hand-curated) |
114
+ | `conventions/*.md` | Auth, crypto agility, PII naming (mixed) |
115
+
116
+ ### Scripts (committed)
117
+
118
+ | Script | Role |
119
+ |--------|------|
120
+ | `src2sink/build_metabase_v2.py` | Extractor + taint + graph aggregation |
121
+ | `src2sink/trace.py` | Bidirectional trace for a target repo/endpoint |
122
+ | `src2sink/trace_batch.py` | Batch traces from `raw-code-payload-endpoints.jsonl` |
123
+ | `src2sink/known_api_clients.py` | Registry: client library → target service |
124
+ | `src2sink/schema.py` | v2 `FlowNode` / `FlowEdge` dataclasses |
125
+ | `src2sink/extractors/` | unified, config, http_out, tree-sitter helpers |
126
+ | `src2sink/aggregators/` | taint catalogues, graphs, payload producers |
127
+
128
+ ---
129
+
130
+ ## Building the metabase
131
+
132
+ Prerequisites: source repos cloned to your `--repos-root` path, `uv sync`, corp network.
133
+
134
+ ```sh
135
+ # Incremental update — skips repos whose git SHA hasn't changed (~fast after first run)
136
+ uv run src2sink-build \
137
+ --repos-root repos --metabase-root metabase \
138
+ --internal-groups-file internal-groups.json --api-clients api-clients.json
139
+
140
+ # Force full re-extract of all repos (use after downloading new repo snapshots
141
+ # that are not git checkouts, or after changing internal-groups/api-clients config)
142
+ uv run src2sink-build \
143
+ --repos-root repos --metabase-root metabase --force \
144
+ --internal-groups-file internal-groups.json --api-clients api-clients.json
145
+
146
+ # Single repo — re-extracts only that repo, but re-aggregates taint/graphs/phase3
147
+ # from all existing JSONs so cross-repo outputs stay consistent
148
+ uv run src2sink-build \
149
+ --repos-root repos --metabase-root metabase \
150
+ --repo acme/sql-runner-api \
151
+ --internal-groups-file internal-groups.json --api-clients api-clients.json
152
+
153
+ # Re-aggregate taint + graphs from existing v2 JSONs only (fast, no re-extraction)
154
+ uv run src2sink-build \
155
+ --repos-root repos --metabase-root metabase --graphs-only \
156
+ --internal-groups-file internal-groups.json --api-clients api-clients.json
157
+
158
+ # Phase 3 only (PII lifecycle, ROPA, auth/crypto, cross-repo phone flows)
159
+ uv run src2sink-build \
160
+ --repos-root repos --metabase-root metabase --phase3-only \
161
+ --internal-groups-file internal-groups.json --api-clients api-clients.json
162
+
163
+ # Resolve flagged library-source-map entries from on-disk pom.xml only
164
+ # (fast, no re-extraction). Walks every pom.xml under --repos-root, reads each
165
+ # groupId/artifactId, and for any mapping still flagged (status pending/ambiguous
166
+ # or with an empty clone_path) whose coordinate matches a pom, fills in clone_path
167
+ # and sets status: cloned. excluded and already-cloned entries are left alone.
168
+ uv run src2sink-build \
169
+ --repos-root repos --metabase-root metabase --fix-source-map
170
+
171
+ # Tests (Phase 4 regression suite)
172
+ uv run pytest tests/ -q
173
+ uv run pytest tests/ -q -m fleet # needs metabase/repos v2 JSONs
174
+ ```
175
+
176
+ ### Build gates
177
+
178
+ [`.github/workflows/ci.yml`](https://github.com/mimecast/src2sink/blob/main/.github/workflows/ci.yml) runs six gates on every push,
179
+ pull request, and weekly (advisories move even when the code does not):
180
+
181
+ | Gate | What it enforces | Locally |
182
+ |---|---|---|
183
+ | `test` | pytest + coverage floors (80% overall, 90% on the security modules) | `make test` |
184
+ | `srtm` | every requirement in the [SRTM](https://github.com/mimecast/src2sink/blob/main/docs/security-privacy-gap-analysis.md) still has a test or a documented audit | `make srtm` |
185
+ | `mypy (strict)` | `mypy --strict` over `src2sink/` and `scripts/` | `make typecheck` |
186
+ | `bandit` | Python SAST on first-party code | `make bandit` |
187
+ | `pip-audit` | dependency vulnerability audit (`TA-011` / `SC-1`) | `make audit` |
188
+ | `opengrep` | pattern SAST, pinned ruleset, gated at ERROR severity | `make opengrep` |
189
+
190
+ `make ci` runs everything except `opengrep`, which needs the external ruleset
191
+ checkout. Known false positives carry inline `# nosec` / `# nosemgrep`
192
+ annotations with a stated reason rather than blanket rule exclusions.
193
+
194
+ Publishing a version to PyPI: [`docs/releasing.md`](https://github.com/mimecast/src2sink/blob/main/docs/releasing.md).
195
+ Known small gaps: [`docs/todo.md`](https://github.com/mimecast/src2sink/blob/main/docs/todo.md).
196
+
197
+ > **Incremental behaviour:** each re-run compares the repo's current `git HEAD` SHA
198
+ > against the SHA stored in the existing per-repo JSON. Repos that haven't changed are
199
+ > skipped (`skip group/name (unchanged)`); only changed repos are re-extracted.
200
+ > Repos without a `.git/` directory (bare downloads) are always re-extracted.
201
+ > Cross-repo graphs and taint catalogues are always re-aggregated at the end regardless
202
+ > of how many repos were skipped, so the metabase stays consistent.
203
+ > Use `--force` to bypass the SHA check and re-extract everything.
204
+
205
+ > **Traces are not run automatically.** `src2sink-build` produces a
206
+ > `graphs/traces/INDEX.md` that lists existing trace files and shows
207
+ > which endpoints still lack one, but it does not generate traces itself.
208
+ > Run `src2sink-trace-batch` (or `src2sink-trace`) as a separate step
209
+ > after the build completes.
210
+
211
+ ### Generating traces (separate step)
212
+
213
+ Traces give a full bidirectional view of a dangerous-payload endpoint:
214
+ inbound routes, `raw-code-payload` nodes, SQL sinks, config stores, and
215
+ upstream callers. They are written to `graphs/traces/<name>.md`.
216
+
217
+ **Batch — trace all raw-code-payload endpoints at once (recommended):**
218
+
219
+ ```sh
220
+ # First run: generates a report for every endpoint in
221
+ # taint/raw-code-payload-endpoints.jsonl
222
+ uv run src2sink-trace-batch --metabase-root metabase \
223
+ --internal-groups-file internal-groups.json --api-clients api-clients.json
224
+
225
+ # Subsequent runs: skip endpoints that already have a report
226
+ uv run src2sink-trace-batch --metabase-root metabase \
227
+ --internal-groups-file internal-groups.json --api-clients api-clients.json --skip-existing
228
+ ```
229
+
230
+ **Single endpoint:**
231
+
232
+ ```sh
233
+ uv run src2sink-trace \
234
+ --metabase-root metabase \
235
+ --target acme/sql-runner-api \
236
+ --path /query \
237
+ --scan-repos repos \
238
+ --internal-groups-file internal-groups.json \
239
+ --api-clients api-clients.json \
240
+ --output metabase/graphs/traces/sql-runner-api-query.md
241
+ ```
242
+
243
+ `--scan-repos` is optional; it adds a literal import/URL scan of the
244
+ cloned source trees to find callers that are not yet in the graph.
245
+
246
+ After adding new traces, refresh the index:
247
+
248
+ ```sh
249
+ uv run src2sink-build --repos-root repos --metabase-root metabase --graphs-only \
250
+ --internal-groups-file internal-groups.json --api-clients api-clients.json
251
+ ```
252
+
253
+ ### Fixing flagged internal-library mappings
254
+
255
+ After the initial scan, `library-source-map.json` may contain entries the
256
+ build couldn't resolve — coordinates with `status: pending`/`ambiguous` or an
257
+ empty `clone_path` (an internal dependency whose source repo it couldn't
258
+ locate). Every normal build already tries to repair these automatically at the
259
+ end, but if you clone the missing repos *after* a scan you can re-run just the
260
+ fix without re-extracting anything:
261
+
262
+ ```sh
263
+ uv run src2sink-build --repos-root repos --metabase-root metabase --fix-source-map
264
+ ```
265
+
266
+ This walks every `pom.xml` under `--repos-root`, reads each `groupId` /
267
+ `artifactId`, and for any still-flagged mapping whose coordinate matches a pom
268
+ it sets `clone_path` to that repo's path (relative to the repos root) and flips
269
+ `status` to `cloned`. Matching is by exact `groupId:artifactId`, falling back to
270
+ a unique `artifactId`-only match. Entries marked `excluded`, and those already
271
+ `cloned` with a `clone_path`, are left untouched. It prints how many entries it
272
+ resolved; anything still flagged afterwards has no matching `pom.xml` on disk
273
+ (clone the repo, or set `clone_path`/`status` by hand). Once resolved,
274
+ `curate_internal_libraries.py` can seed taint tables from that source.
275
+
276
+ ### Register another API client library
277
+
278
+ Edit `src2sink/known_api_clients.py` (`ApiClientBinding`), then re-run
279
+ `src2sink-build` (or `--graphs-only`).
280
+
281
+ ---
282
+
283
+ ## How to use this metabase as LLM context
284
+
285
+ ### Minimum pack for SAST on one repo
286
+
287
+ 1. `repos/<group>/<repo>.md` and `.json` (check `schema_version`).
288
+ 2. For each **internal dependency**, `internal-libraries/<coord>.md`.
289
+ 3. Relevant **taint** rows (filter jsonl by `repo` column).
290
+ 4. **graphs** edges involving that repo (`service-call-edges.jsonl`,
291
+ `payload-endpoint-producers.jsonl`, `queue-graph.jsonl`).
292
+
293
+ ### Dangerous-payload / raw SQL in HTTP body
294
+
295
+ 1. `taint/raw-code-payload-endpoints.md` (sample) + `.jsonl` (full).
296
+ 2. `graphs/payload-endpoint-producers.md` for known client libraries.
297
+ 3. `graphs/traces/<service>-<path>.md` if generated (see `graphs/traces/INDEX.md`).
298
+ 4. Target repo v2 JSON: `family=raw-code-payload`, `http-in`, `sql` sinks.
299
+
300
+ Use **phone numbers** (not email) as the canonical PII lifecycle example
301
+ when illustrating field flow — email is ambient in an email-security
302
+ company (`conventions/pii-classification.md`).
303
+
304
+ ### PII and crypto
305
+
306
+ - PII lifecycle: `graphs/pii-lifecycle.md`, `graphs/pii-phone-cross-repo.md`.
307
+ - ROPA draft: `ropa/categories-of-personal-data.md`.
308
+ - Field catalogues: `taint/pii-sources.md`, `taint/pii-sinks.md`.
309
+ - Crypto: `taint/crypto-operations.md`, `conventions/crypto-agility.md`.
310
+
311
+ ---
312
+
313
+ ## Updating and hand-curation
314
+
315
+ Per-repo files are regenerated wholesale by `build_metabase_v2.py`.
316
+ Put durable notes in `internal-libraries/` or conventions files, not
317
+ inside generated output.
318
+
319
+ ---
320
+
321
+ ## Confidence levels
322
+
323
+ | Level | Meaning |
324
+ |-------|---------|
325
+ | **high** | Strong pattern (e.g. tree-sitter JDBC sink, explicit import of registered client) |
326
+ | **medium** | Heuristic (field name, regex HTTP client) |
327
+ | **low** | Weak signal (host-only match, path suffix overlap) |
328
+
329
+ Service-call and producer-index edges label confidence explicitly.
330
+ Treat **low** as “investigate”, not “confirmed”.
331
+
332
+ ---
333
+
334
+ ## Dependencies
335
+
336
+ v2 requires **tree-sitter** and per-language grammars (via
337
+ `uv sync`). See `metabase/docs/phase0-probe.md` if resolution fails.
338
+ Do not add public PyPI fallbacks.
339
+
340
+ ---
341
+
342
+ ## See also
343
+
344
+ - [`SCHEMA.md`](https://github.com/mimecast/src2sink/blob/main/SCHEMA.md) — complete v2 node/edge vocabulary.
345
+ - [`docs/implementation-plan.md`](https://github.com/mimecast/src2sink/blob/main/docs/implementation-plan.md) — **phased plan and progress record**.
346
+ - [`docs/architecture.md`](https://github.com/mimecast/src2sink/blob/main/docs/architecture.md) — components, data flow, trust boundaries.
347
+ - [`docs/threat-model.md`](https://github.com/mimecast/src2sink/blob/main/docs/threat-model.md) — STRIDE risk register.
348
+ - [`docs/security-privacy-gap-analysis.md`](https://github.com/mimecast/src2sink/blob/main/docs/security-privacy-gap-analysis.md) — requirements, abuse cases, SRTM.
349
+ - [`docs/operations-security.md`](https://github.com/mimecast/src2sink/blob/main/docs/operations-security.md) — running it safely; data classification and retention.
350
+ - [`docs/sast-report.md`](https://github.com/mimecast/src2sink/blob/main/docs/sast-report.md) — self-review of this tool's own code.
351
+ - [`docs/api-clients-json.md`](https://github.com/mimecast/src2sink/blob/main/docs/api-clients-json.md) — the internal-service binding file.
352
+ - [`metabase-usage.md`](https://github.com/mimecast/src2sink/blob/main/metabase-usage.md) — using the output as LLM context.
353
+ - [`docs/releasing.md`](https://github.com/mimecast/src2sink/blob/main/docs/releasing.md) — publishing a version to PyPI.
354
+ - [`NEXT_STEPS.md`](https://github.com/mimecast/src2sink/blob/main/NEXT_STEPS.md) — roadmap · [`docs/todo.md`](https://github.com/mimecast/src2sink/blob/main/docs/todo.md) — known small gaps.
355
+ - `/ai-sast-scanner` skill — SAST prompt this metabase feeds.