โโโโโโโโโโโโโโโ โโโโโโโ โโโโ โโโโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โโโโโ
โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโ โโโ โโโ
โโโโโโโโโโโโโโโ โโโโโโโ โโโ โโโ
Software Bill of Materials ยท MoonBit
cogna-dev/sbomโ A pure-MoonBit Software Composition Analysis (SCA) library that parses dependency manifests and lock files to produce industry-standard Software Bills of Materials in SPDX 2.3 and CycloneDX 1.5 JSON formats.
| Feature | Details |
|---|---|
| ๐ฆ Cargo / Rust | Parses Cargo.toml (workspace + single-crate) and Cargo.lock |
| ๐๏ธ Terraform / HCL | Parses .tf provider blocks and .terraform.lock.hcl |
| ๐น Go | Parses go.mod (require directives) and go.sum (checksums) |
| ๐ SPDX 2.3 | Full JSON export with packages, relationships, document info |
| ๐ CycloneDX 1.5 | Full JSON export with components, metadata, BOM serial |
| ๐ Auto-discovery | Virtual-FS BFS traversal with glob matching & workspace exclusion |
| ๐ Pure MoonBit | Zero external dependencies โ hand-rolled TOML/HCL parsers |
| ๐งฎ SemVer engine | ^, ~, >=, <=, >, <, =, * constraint matching |
| ๐ชช PURL support | Generates Package URLs for every detected dependency |
| ๐๏ธ Monorepo-aware | Discovers and deduplicates workspace members automatically |
cogna-dev/sbom
โโโ src/
โโโ version/ # SemVer parsing & constraint matching
โโโ types/ # Core domain types (Package, Project, Sbomโฆ)
โโโ formats/
โ โโโ spdx/ # SPDX 2.3 JSON exporter
โ โโโ cyclonedx/ # CycloneDX 1.5 JSON exporter
โโโ packages/
โ โโโ cargo/ # Cargo.toml + Cargo.lock parser
โ โโโ go/ # go.mod + go.sum parser
โ โโโ terraform/ # .tf + .terraform.lock.hcl parser
โโโ discovery/ # VFS-based project discovery engine
โโโ lib/ # Top-level public API
lib
/ | | \
/ | | \
cargo go terra discovery
\ | | /
\ | | /
types version
|
formats
/ \
spdx cyclonedx
{
"deps": {
"cogna-dev/sbom": "0.1.0"
}
}{
"import": [
"cogna-dev/sbom/src/lib"
]
}// Scan a Cargo workspace from a virtual filesystem
let files : Map[String, String] = ... // path -> file content
let result = @lib.scan_cargo(files)
match result {
Ok(project) => {
// Export as SPDX 2.3 JSON
let spdx_json = @lib.export_spdx(project)
// Export as CycloneDX 1.5 JSON
let cdx_json = @lib.export_cyclonedx(project)
}
Err(e) => println("Scan failed: \{e}")
}Parses semantic versions and evaluates version constraints without any external library.
let v = @version.parse_version("1.2.3-alpha.1")!
// Version { major: 1, minor: 2, patch: 3, pre: Some("alpha.1") }
let req = @version.parse_requirement("^1.2")!
let matches = @version.satisfies(v, req) // trueSupported constraint operators:
| Operator | Meaning |
|---|---|
^1.2.3 |
Compatible โ >=1.2.3, <2.0.0 |
~1.2.3 |
Patch-compatible โ >=1.2.3, <1.3.0 |
>=1.0 |
Greater-or-equal |
>1.0 |
Strictly greater |
<=2.0 |
Less-or-equal |
<2.0 |
Strictly less |
=1.2.3 |
Exact match |
* |
Any version |
All core types live here. Every other package imports from types.
// A resolved dependency
pub struct Package {
name : String
version : String
purl : String // e.g. "pkg:cargo/serde@1.0.195"
license : String?
description : String?
source : DependencySource
group : DependencyGroup
}
// A scanned sub-project (e.g. a single Cargo crate)
pub struct SubProject {
name : String
version : String
pkg_type : ProjectType // Cargo | Terraform | Npm | โฆ
manifest : String // path to manifest file
dependencies : Array[Package]
}
// A root project containing sub-projects
pub struct Project {
name : String
version : String
sub_projects : Array[SubProject]
}Parses Cargo.toml (including workspace manifests) and Cargo.lock v3.
// Provide a virtual filesystem: Map[String, String]
let project = @cargo.parse(files)!
// project.sub_projects has one entry per crate discovered
// Each entry contains resolved packages from Cargo.lockHandles:
- Workspace
[workspace.members]glob patterns [package]+[dependencies]/[dev-dependencies]/[build-dependencies]Cargo.lock[[package]]entries with checksum & source- Path, git, and registry dependencies
Parses Terraform .tf files and .terraform.lock.hcl provider lock files.
let project = @terraform.parse(files)!
// Discovers terraform { required_providers { โฆ } } blocks
// Cross-references with .terraform.lock.hcl for resolved versionsHandles:
terraform { required_providers { name = { source = "โฆ", version = "โฆ" } } }.terraform.lock.hclprovider "โฆ" { version = "โฆ" }blocks- Multiple
.tffiles in the same directory
Parses go.mod dependency manifests and go.sum checksum files.
let project = @go.parse_go_project(root_path, go_mod_content, Some(go_sum_content))
// project contains all direct and indirect require entries
// Checksums are taken from go.sum (h1: hash algorithm)Handles:
moduledeclaration (project name)goversion directiverequire (โฆ)blocks with multiple entries- Single-line
require <module> <version> // indirectannotationsgo.sumh1:checksums cross-referenced per module+version
Produces a spec-compliant SPDX 2.3 document as a MoonBit Json value.
let json : Json = @spdx.to_spdx(project)
// Serialise with standard MoonBit JSON utilitiesOutput structure:
{
"spdxVersion": "SPDX-2.3",
"dataLicense": "CC0-1.0",
"SPDXID": "SPDXRef-DOCUMENT",
"name": "my-project-1.0.0",
"documentNamespace": "https://spdx.org/spdxdocs/...",
"packages": [ ... ],
"relationships": [ ... ]
}Produces a spec-compliant CycloneDX 1.5 BOM as a MoonBit Json value.
let json : Json = @cyclonedx.to_cyclonedx(project)Output structure:
{
"bomFormat": "CycloneDX",
"specVersion": "1.5",
"serialNumber": "urn:uuid:...",
"version": 1,
"metadata": { "component": { ... } },
"components": [ ... ]
}Traverses a virtual filesystem (BFS) to locate manifest files and group them into projects.
// VirtualFS is just Map[String, String]
let sub_projects = @discovery.discover(files)
// Returns an Array[DiscoveredProject] with:
// .manifest_path โ path to the root manifest
// .ecosystem โ Cargo | Terraform | โฆ
// .files โ scoped file map for this projectFeatures:
- Glob pattern matching for workspace members
- Skips
.git/,node_modules/,vendor/automatically - Deduplicates paths already claimed by a parent workspace
The single entry point for consumers. Combines discovery + parsing + export.
// โโ Scanning โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// Scan only Cargo projects
let p1 : Result[Project, String] = @lib.scan_cargo(files)
// Scan only Terraform projects
let p2 : Result[Project, String] = @lib.scan_terraform(files)
// Scan everything (auto-detects ecosystem)
let p3 : Result[Project, String] = @lib.scan_all(files)
// โโ Export โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// Produce SPDX 2.3 JSON string
let spdx : String = @lib.export_spdx(project)
// Produce CycloneDX 1.5 JSON string
let cdx : String = @lib.export_cyclonedx(project)| Principle | Implementation |
|---|---|
| No I/O | All functions accept Map[String, String] (virtual FS) โ callers own I/O |
| No external deps | Hand-rolled TOML and HCL parsers; zero moon.mod.json deps |
| Immutable-first | Structs are built once and never mutated |
| Zero type suppression | No as Any, no @ts-ignore equivalent โ strict types throughout |
| Fail-fast errors | Parsers return Result[T, String]! โ errors propagate, never silenced |
| Pure functions | All parsers are deterministic given the same input map |
| Ecosystem | Status |
|---|---|
| ๐ฆ Cargo (Rust) | โ Implemented |
| ๐๏ธ Terraform | โ Implemented |
| ๐น Go / go.mod | โ Implemented |
| ๐ฆ npm / package.json | ๐ Planned |
| ๐ Python / pyproject.toml | ๐ Planned |
| โ Maven / pom.xml | ๐ Planned |
| ๐ Bundler / Gemfile | ๐ Planned |
| ๐งช SBOM merge / diff | ๐ Planned |
- Fork the repository and create a feature branch.
- Run
moon checkโ 0 errors required before opening a PR. - Follow the existing coding style (no
as Any, no empty catches). - Add or update tests with
moon test. - Open a PR with a clear description of what changed and why.
# Clone
git clone https://github.com/cogna-dev/sbom
cd sbom
# Check everything compiles
moon check
# Run tests
moon test
# Build
moon buildMIT ยฉ cogna-dev โ see LICENSE for details.
Built with โค๏ธ in MoonBit