ADR-003: Minimal Dependencies¶
TL;DR
gouvernante keeps external dependencies minimal and carefully weighed. The scanning engine uses only the Go standard library. Format parsers may use vetted libraries where robustness justifies the trust surface.
Who is this for?
Audience: Contributors who want to add a dependency, and security reviewers. Reading time: ~5 minutes.
Status¶
| Status | Accepted |
| Date | 2025-01 |
| Deciders | Core team |
Context¶
gouvernante is a supply chain scanner. Its entire purpose is to detect compromised dependencies in other projects. If the scanner itself has a sprawling dependency tree, it becomes vulnerable to the same attack class it is designed to detect.
This is not a theoretical concern:
- The
event-streamincident (2018) showed that a single transitive dependency can inject malicious code. - The
ua-parser-js,coa, andrccompromises (2021) hit widely-used packages. - Go modules are not immune — the
ctxtyposquat demonstrated this in the Go ecosystem.
At the same time, dogmatic purity has costs. Writing a custom YAML parser to avoid a dependency creates maintenance burden and fragility that outweighs the risk of a well-vetted library.
The policy must balance: minimal trust surface against robust, maintainable code.
Options Considered¶
| Criterion | Zero dependencies | Minimal, vetted dependencies | Unconstrained dependencies |
|---|---|---|---|
| Supply chain risk | None | Low — small, auditable set | High — transitive deps are opaque |
| Audit surface | Only this repository | This repo + 2-3 vetted modules | Large — go.sum can be hundreds of lines |
| Robustness | Lower — bespoke parsers break on format changes | Higher — libraries handle edge cases | Highest |
| Maintenance | Higher — must maintain custom parsers | Moderate | Lower |
| Build reproducibility | No network needed | Vendored — no network needed | Depends on module proxy |
Decision¶
Keep dependencies minimal and carefully weighed. Each dependency must justify its trust surface expansion with a concrete robustness or correctness benefit.
The dependency policy is scoped:
| Scope | Policy | Current dependencies |
|---|---|---|
| Scanning & matching engine | Go standard library only | None |
| Format parsers | Vetted libraries allowed | goccy/go-yaml for pnpm lockfile parsing |
| Test infrastructure | Test-only deps allowed | santhosh-tekuri/jsonschema for schema validation |
| CLI framework | Standard library | flag package |
Reasoning:
-
The scanning engine must be above suspicion. The package matching, host indicator checking, and report generation code uses only the Go standard library. This is the code that makes security decisions.
-
Format parsers benefit from real libraries. A pnpm lockfile YAML change should not require a new binary release.
goccy/go-yamlis well-maintained, hosted ongithub.com(nogopkg.innetwork issues), and handles edge cases that a custom parser would miss. -
Test-only dependencies don't ship in the binary.
santhosh-tekuri/jsonschemavalidates rules against the JSON Schema during testing but is not compiled into the production binary. -
The core invariant is: gouvernante never depends on the npm ecosystem it scans. No JavaScript, no Node.js modules, no npm packages. This is non-negotiable.
Consequences¶
Positive¶
- The scanning engine's attack surface is limited to the Go standard library.
- The full dependency set is small enough to audit by hand.
- Format parsers are robust against upstream format changes.
- Test-only dependencies provide strong schema fidelity guarantees without bloating the production binary.
Negative¶
- Contributors must evaluate whether a new dependency falls in the "parser" or "engine" scope before adding it.
- Each new dependency requires justification — this intentionally slows down dependency growth.
Vendoring¶
All dependencies are vendored in vendor/ and committed to the repository.
This provides:
- Offline builds — no network access to
github.comrequired at build time. - Reproducibility — builds are not affected by upstream module proxy outages or deletions.
- Auditability — the exact source code of every dependency is visible in the repository and can be reviewed in pull requests.
After modifying go.mod, run make vendor to update the vendor directory. CI
verifies vendor consistency via make vendor-check.
License compliance¶
A third-party license report is generated automatically during make all and
attached to every release. The report is produced by scripts/licenses.sh,
which scans vendor/ for LICENSE files and identifies each dependency's license
type. All current dependencies use permissive licenses (MIT, Apache-2.0,
BSD-3-Clause).
Next Steps¶
- See the YAML parser decision --> YAML Parser
- Understand the language choice --> Go over Node.js
- Back to decision log --> Decision Log