Building a Polyglot Dependency Scanner in Haskell: Inside FOSSA CLI
Hook
With 5.8 million downloads, one of the most-used dependency analysis tools in enterprise environments is written in Haskell—a language most developers have never touched. Here’s why that architectural choice matters for correctness in compliance scanning.
Context
License compliance and vulnerability scanning used to be manual processes: developers maintaining spreadsheets of dependencies, legal teams reviewing licenses one-by-one, security teams scrambling when CVEs dropped. For polyglot projects with multiple languages and build systems, this became exponentially worse. A typical modern application might use npm for frontend code, Maven for Java services, pip for Python scripts, and Go modules for infrastructure tools. Traditional dependency scanners forced you to configure each build system separately, maintain multiple tools, or write custom scripts to bridge gaps.
FOSSA CLI emerged to solve this fragmentation. Rather than asking developers to configure YAML files mapping out their build systems, it takes a zero-configuration approach: point it at a codebase and it automatically detects what you’re using. The tool examines project structure, parses build files and lock files across multiple ecosystems, extracts dependency graphs, and uploads results to the FOSSA cloud platform for license compliance analysis, vulnerability scanning, and attribution reporting. The choice of Haskell as the implementation language isn’t accidental—when you’re parsing dozens of different build file formats and constructing dependency graphs that legal teams will rely on, type safety and correctness aren’t optional.
Technical Insight
FOSSA CLI’s architecture centers on a strategy-based discovery system. When you run fossa analyze, the tool doesn’t require you to declare what languages you’re using. Instead, it walks your project directory tree, identifies build files and dependency manifests, and selects appropriate analysis strategies. Each strategy is a self-contained module that knows how to extract dependencies for a specific build system.
Here’s what a basic analysis looks like in practice:
# Set your API key from the FOSSA web application
export FOSSA_API_KEY=your-key-here
# Navigate to your project
cd /path/to/your/project
# Run analysis - no configuration needed
fossa analyze
# The CLI automatically detects build systems and reports findings:
# [ INFO] Found project: npm in package.json
# [ INFO] Found project: maven in pom.xml
# [ INFO] Found project: go in go.mod
# [ INFO] Running npm analysis...
# [ INFO] Running maven analysis...
# [ INFO] Running go analysis...
# [OK ] Uploaded scan results to FOSSA
Under the hood, each strategy implements a common interface for dependency extraction. For example, the npm strategy reads package.json and package-lock.json to build a complete dependency tree including transitive dependencies. The Maven strategy invokes mvn dependency:tree to get accurate resolution order respecting your build configuration. The Go modules strategy parses go.mod and can optionally run go list to capture build-time dependencies.
Haskell’s type system shines here because each build system has different semantics for dependency resolution. Npm uses nested dependencies with potential duplicates at different versions. Maven has a complex inheritance and dependency management system. Go modules use minimal version selection. Representing these different graph structures with shared interfaces while maintaining type safety prevents entire classes of bugs. A dependency graph node in the npm strategy can’t accidentally be treated as a Maven node—the compiler prevents it.
The tool also implements fallback strategies for edge cases. If it can’t invoke build tools directly (maybe you’re running in a locked-down CI environment), it falls back to parsing lock files statically. If no lock files exist, it can attempt to parse build files directly, though this provides less accurate dependency resolution. The documentation explicitly notes that vendored dependency detection and container scanning are “work in progress” features with limited support—an honest acknowledgment that complete accuracy across all scenarios is still being refined.
Integration with the FOSSA cloud service is fundamental to the architecture. The CLI doesn’t perform license analysis or vulnerability scanning locally. Instead, it extracts dependency information and uploads it via API. The FOSSA platform then matches dependencies against its database of known packages, licenses, and vulnerabilities. This separation means the CLI stays fast and focused on accurate dependency extraction, while the heavy lifting of compliance analysis happens server-side where databases can be continuously updated.
For CI/CD pipelines, FOSSA CLI supports a test mode that enforces policy:
# Analyze dependencies
fossa analyze
# Test against your organization's license policies
fossa test
# Returns non-zero exit code if policy violations found
# [ ERROR] License policy violated: GPL-3.0 detected
# [ ERROR] Build failed due to policy violations
This workflow enables automated compliance gates in pull requests and deployment pipelines, blocking builds that introduce dependencies with incompatible licenses or known vulnerabilities.
Gotcha
The most significant limitation is that FOSSA CLI isn’t a standalone tool—it requires a FOSSA cloud service account and API key. You can’t use it for offline dependency analysis or run it in air-gapped environments. This is a fundamental architectural decision: the CLI is a data collection tool for a commercial SaaS platform. While the CLI itself is open source, the value proposition depends entirely on the FOSSA service. Teams wanting self-hosted compliance scanning or those with strict data residency requirements will hit a wall immediately.
Vendored dependencies and container scanning are explicitly marked as work-in-progress with limited support in the README. If your project vendors dependencies (copying third-party code directly into your repository rather than using a package manager), FOSSA CLI’s ability to detect and analyze those dependencies is incomplete. Similarly, if you’re primarily scanning container images for dependencies, this tool isn’t mature in that space yet. The Haskell implementation also creates a contribution barrier—while the language choice benefits correctness and reliability, it means the pool of developers who can easily contribute fixes or add new build system support is smaller than it would be for a Go or TypeScript project.
Verdict
Use FOSSA CLI if you’re working in an enterprise environment where license compliance and vulnerability management are regulatory requirements, especially if you have polyglot monorepos with multiple build systems. The zero-configuration approach and support for 20+ build systems make it the fastest path to automated compliance scanning in CI/CD pipelines. The tight FOSSA platform integration provides attribution reports and policy enforcement that legal and security teams actually need. Skip it if you need a standalone tool without cloud dependencies, if your compliance requirements mandate self-hosted solutions, if you’re primarily scanning containers or vendored dependencies, or if you want an open-source solution without vendor lock-in. For those scenarios, consider Syft/Grype for container-focused SBOM generation, OSS Review Toolkit (ORT) for fully self-hostable compliance scanning, or Trivy for simpler offline vulnerability scanning.