Skip to content

src2sink 1.0.0

Choose a tag to compare

@BrettCrawley BrettCrawley released this 28 Jul 17:34
· 194 commits to main since this release
4bbc23a

Yanked on PyPI, 2026-07-29 — "Superseded by 1.0.1". Not a defect: 1.0.1 is
functionally identical, and this release is sound. Existing == 1.0.0 pins
keep resolving as before; new installs resolve to 1.0.1 regardless.

First public release. src2sink builds a source-to-sink metabase: a structured,
human-readable knowledge base of an entire source-code estate, designed to be
loaded as context for LLM-assisted SAST so taint can be followed across
repositories — a SQL fragment built in one service and executed in another, an
internal library that silently forwards to a JDBC sink, PII entering at an
ingress and surfacing in a log three repos away.

Extraction

  • Tree-sitter extractors for Java, Kotlin, Python, Go, JavaScript, and
    TypeScript
    , plus configuration-file extraction (Spring application.yml /
    .properties, and friends) for facts that never appear in code.
  • Output schema v2 (SCHEMA_VERSION = 2): a flow graph of FlowNode
    (source / propagator / sink / store, with a family, a
    pii_classification, a data_class, and a confidence rating) joined by
    FlowEdge at intra-file, intra-repo, and cross-repo scope.
  • Build-system and framework detection across Maven, Gradle, npm/yarn/pnpm, pip,
    Poetry, Pipenv, Go modules, and Cargo. Declared dependencies are parsed from
    pom.xml, build.gradle*, and package.json; component identity (which
    repo publishes a given coordinate) additionally resolves pyproject.toml,
    setup.cfg, Cargo.toml, composer.json, go.mod, *.csproj/*.fsproj/
    *.vbproj, and *.gemspec. An internal-vs-external coordinate classifier
    runs off your own namespace patterns.

Cross-repo analysis

  • Taint catalogues — SQL sources and execution sinks, file sinks, outbound
    HTTP sinks, PII sources and sinks, crypto operations, raw-code-payload
    endpoints, and security-relevant configuration.
  • Graphs — service-call graph (HTTP out ↔ HTTP in), queue producer/consumer
    graph, data-store graph, payload-endpoint producers, PII lifecycle, and
    cross-repo phone-number flows.
  • OpenAPI discovery — specs found in the estate are matched to services and
    folded into the service-call edges.
  • Phase 3 models — per-repo auth cards, crypto-agility cards, a PII lifecycle
    model, and a GDPR Article 30 ROPA projection.
  • Bidirectional tracing — src2sink-trace follows a target repo or endpoint
    upstream to its producers and downstream to its sinks; src2sink-trace-batch
    does it for every raw-payload endpoint discovered.

Command-line tools

src2sink-build (extract + aggregate), src2sink-trace, src2sink-trace-batch,
src2sink-curate (internal-library taint tables), and src2sink-baseline
(fleet baseline). Builds are incremental by git SHA — unchanged repos are
skipped, cross-repo aggregation always re-runs so the estate stays consistent.

Built to scan hostile input

Scanned repositories are treated as untrusted, and the outputs are treated as
prompt material for an LLM. Every control below is traced to a test through the
SRTM:

  • Execution bulkhead — each repo is analysed in its own process with a
    wall-clock budget, so a pathological parse or catastrophic regex kills one
    repo, not the run.
  • Path containment — crafted .git/HEAD symrefs and escaping symlinks cannot
    read outside the repo.
  • Hardened XML — manifests are parsed with defusedxml; entity-expansion
    payloads do not expand.
  • Size, file-count, and line-length caps, plus a content pre-screen that
    skips binary and minified/obfuscated files before a parser sees them. Every
    skip is recorded, never silent.
  • Untrusted-output neutralisation — extracted content is escaped and fenced
    in Markdown and JSONL so a comment in a scanned repo cannot issue instructions
    to a downstream LLM.
  • Literal-PII redaction in code snippets, and log hygiene that reports the
    exception type and repo id rather than paths or content.
  • Run provenance — every build writes a secret-free run-manifest.json
    (tool version, per-repo SHAs, counts, UTC timestamps) for reproducibility and
    Article 30 records.

Operational guidance — data classification, least-privilege CI, retention and
erasure — is in docs/operations-security.md;
the risk register is in docs/threat-model.md.

Quality gates

CI runs six gates on every push and pull request, and weekly:

Gate Enforces
test 302 tests, 84% coverage overall, 90% on the security-critical modules
srtm every requirement in the SRTM still has an implementing test or a documented audit
mypy (strict) mypy --strict, clean across the package and scripts
bandit Python SAST, clean
pip-audit no known advisories against the locked dependency set
opengrep pattern SAST with a pinned ruleset, clean at ERROR severity

Dependencies are hash-pinned in a committed uv.lock and installed with
uv sync --locked. Known false positives are annotated inline with a stated
reason rather than suppressed wholesale.

Fixed before release

  • SKIP_DIRS was matched against each manifest's absolute path, so a repos
    root under any colliding path segment — /tmp/repos, ~/build/repos — indexed
    nothing at all. Silently: no error, no note, every coordinate resolving to "not
    found" and every source-map lookup coming back empty. The first CI run caught
    it, because GitHub runners put pytest's temporary directories under /tmp;
    reproducible locally with TMPDIR=/tmp. SKIP_DIRS now applies only to
    segments below the scan root — the absolute prefix is the operator's
    filesystem layout, not part of the scanned tree. No published version is
    affected: the fix predates this release.

Requirements

Python 3.14+. Install with pip install src2sink or uv add src2sink.

Known limitations

  • Detection is heuristic and rated (high / medium / low); treat low as
    investigate, not confirmed.
  • Scala files are counted in the language breakdown and get the language-agnostic
    regex passes, but there is no tree-sitter grammar for them yet, so no AST-level
    extraction.
  • The metabase is a concentrated map of weaknesses and personal-data locations.
    Store it access-controlled and encrypted at rest — see the operations guide.