strangelove

package module
v0.0.0-...-d07560f Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 10, 2026 License: MIT Imports: 12 Imported by: 0

README

strangelove mascot

strangelove

How I Learned to Stop Worrying and Love the SBOM.

strangelove is a simple, streaming-first SBOM parsing and identification library for Go. It auto-detects, identifies, and unmarshals both SPDX and CycloneDX documents into a single, predictable Go representation with zero boilerplate.

There is no need to buffer files into memory or deal with incompatible format schemas: just pass any io.Reader and strangelove will extract a unified component inventory for you.

Supported Standards and Formats

Standard Serializations Target Versions
CycloneDX JSON, XML v1.4, v1.5, v1.6
SPDX JSON, Tag-Value, RDF v2.2, v2.3

Usage

Read any SBOM

Pass any SBOM stream (CycloneDX JSON/XML or SPDX JSON/Tag-Value) to Unmarshal. It will automatically detect the format, version, and serialization, then parse it into a unified representation:

package main

import (
	"fmt"
	"log"
	"os"

	"github.com/mcombuechen/strangelove"
)

func main() {
	file, err := os.Open("bom.json")
	if err != nil {
		log.Fatal(err)
	}
	defer file.Close()

	doc, err := strangelove.Unmarshal(file)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("Format: %s (v%s) [%s]\n",
		doc.Format.SBOMStandard,
		doc.Format.SpecVersion,
		doc.Format.Serialization)
	fmt.Printf("Created: %s\n\n", doc.Meta.CreatedAt)

	for _, c := range doc.Components {
		fmt.Printf(" - %s@%s (purl: %s)\n", c.Name, c.Version, c.PackageURL)
	}
}

Documentation

Overview

Package strangelove provides streaming-first SBOM identification and parsing.

It auto-detects and unmarshals SPDX and CycloneDX documents into a unified in-memory representation without buffering the entire input into memory.

Quick Start

The primary entry point is Unmarshaler:

doc, err := strangelove.NewUnmarshaler().Unmarshal(reader)
if err != nil {
    log.Fatal(err)
}
fmt.Println("Format:", doc.Format)

Identification Only

Use Identifier directly when you only need format detection:

result, err := strangelove.NewIdentifier().Identify(reader)
if err != nil {
    log.Fatal(err)
}
fmt.Println(result.Format.SBOMStandard)

Errors

The package returns sentinel errors that can be checked with errors.Is:

Index

Constants

View Source
const SyntheticRootID = "@root"

Variables

View Source
var (
	// ErrUnknownFormat is returned when the input cannot be identified as
	// a supported SBOM format.
	ErrUnknownFormat = errors.New("unknown SBOM format")

	// ErrEmptyInput is returned when the reader contains no data.
	ErrEmptyInput = errors.New("empty input")

	// ErrUnsupportedFormat is returned when the format is recognized but
	// parsing is not yet implemented for that format or serialization.
	ErrUnsupportedFormat = errors.New("unsupported SBOM format")
)

Functions

func WithIdentifier

func WithIdentifier(id *Identifier) unmarshalerOption

WithIdentifier sets a custom Identifier for format detection. Use this to configure peek size or other identification behaviour.

func WithPeekSize

func WithPeekSize(size int) identifierOption

WithPeekSize sets the number of bytes peeked for format detection. The default is 4096 bytes.

Types

type Author

type Author struct {
	Type  AuthorType
	Name  string
	Email string
}

Author represents a person or organization that contributed to or is associated with the SBOM or a component.

type AuthorType

type AuthorType int

AuthorType distinguishes the kind of author or entity.

const (
	AuthorPerson       AuthorType = iota // a natural person
	AuthorOrganization                   // an organization
)

type Component

type Component struct {
	ID      string // bom-ref (CycloneDX) or SPDXRef-* (SPDX)
	Name    string
	Version string
	Type    ComponentType

	Supplier  *Entity
	Authors   []Author
	Publisher string

	Hashes []Hash

	PackageURL       string // package URL (purl)
	CPE              string // Common Platform Enumeration
	FileName         string // SPDX PackageFileName
	DownloadLocation string // SPDX PackageDownloadLocation

	Description string
	Copyright   string
	SourceInfo  string // SPDX PackageSourceInfo
}

Component represents a software component or package extracted from an SBOM.

type ComponentType

type ComponentType int

ComponentType classifies the type of a software component.

const (
	ComponentTypeOther           ComponentType = iota // unrecognized or unspecified
	ComponentTypeApplication                          // an application
	ComponentTypeLibrary                              // a library
	ComponentTypeFramework                            // a framework
	ComponentTypeContainer                            // a container
	ComponentTypeOperatingSystem                      // an operating system
	ComponentTypeDevice                               // a hardware device
	ComponentTypeFirmware                             // firmware
	ComponentTypeFile                                 // a file
	ComponentTypeSource                               // source code (SPDX)
	ComponentTypeArchive                              // an archive (SPDX)
	ComponentTypeInstall                              // an installer (SPDX)
)

type DependencyGraph

type DependencyGraph struct {
	Root  string           // component ID of the root ("@root" if synthetic)
	Nodes map[string]*Node // component ID → Node
}

DependencyGraph represents the dependency relationships between components as a directed graph. Each node corresponds to a component (referenced by ID), with outgoing edges (DependsOn) and incoming edges (DependedBy).

type Document

type Document struct {
	Format     SBOMFormat
	Meta       Meta
	Components []Component
	Graph      *DependencyGraph
	// contains filtered or unexported fields
}

Document is the result of unmarshaling an SBOM. It contains the detected format, parsed metadata, a unified component inventory, and the dependency graph.

func Unmarshal

func Unmarshal(r io.Reader) (*Document, error)

Unmarshal identifies and parses an SBOM document from r using a default Unmarshaler. It is a convenience wrapper around NewUnmarshaler().Unmarshal.

func (*Document) SBOM

func (d *Document) SBOM() any

SBOM returns the underlying library-specific parsed document. Use type assertion to access standard-specific fields:

if cdxDoc, ok := doc.SBOM().(*cyclonedx.BOM); ok { ... }

type Entity

type Entity struct {
	Name  string
	Email string
	URL   []string
}

Entity represents a named organization or person with contact information.

type Hash

type Hash struct {
	Algorithm string // e.g. "SHA-256", "SHA1", "MD5"
	Value     string
}

Hash represents a cryptographic checksum of a component.

type IdentificationResult

type IdentificationResult struct {
	Format SBOMFormat
	Reader *bufio.Reader
}

IdentificationResult contains the detected format and a buffered reader that preserves the stream position past the peeked bytes.

type Identifier

type Identifier struct {
	// contains filtered or unexported fields
}

Identifier peeks at the beginning of an SBOM stream to detect its format, standard, serialization, and specification version.

func NewIdentifier

func NewIdentifier(opts ...identifierOption) *Identifier

NewIdentifier creates an Identifier with the given options.

func (*Identifier) Identify

func (id *Identifier) Identify(r io.Reader) (IdentificationResult, error)

Identify reads the peek buffer, detects the SBOM format, and returns the result along with a buffered reader ready to consume the full stream.

type Meta

type Meta struct {
	CreatedAt time.Time
	Authors   []Author
	Tools     []Tool
}

Meta contains SBOM-level metadata.

type Node

type Node struct {
	ID         string
	Component  *Component       // nil for synthetic/stub nodes (e.g. @root, broken refs)
	DependsOn  map[string]*Node // targets of outgoing edges (this → dependency)
	DependedBy map[string]*Node // sources of incoming edges (dependant → this)
}

Node represents a single vertex in the dependency graph.

type SBOMFormat

type SBOMFormat struct {
	SBOMStandard  SBOMStandard
	Serialization Serialization
	SpecVersion   string
}

SBOMFormat describes the complete format of an SBOM document.

func (SBOMFormat) String

func (f SBOMFormat) String() string

type SBOMStandard

type SBOMStandard int

SBOMStandard identifies the SBOM specification standard.

const (
	SBOMStandardUnknown   SBOMStandard = iota
	SBOMStandardCycloneDX              // CycloneDX
	SBOMStandardSPDX                   // SPDX
)

func (SBOMStandard) String

func (s SBOMStandard) String() string

type Serialization

type Serialization int

Serialization identifies the serialization format of the SBOM document.

const (
	SerializationUnknown      Serialization = iota
	SerializationJSON                       // JSON
	SerializationXML                        // XML
	SerializationSPDXTagValue               // SPDX Tag-Value
	SerializationRDF                        // RDF/XML (SPDX)
)

func (Serialization) String

func (s Serialization) String() string

type Tool

type Tool struct {
	Type    ToolType
	Name    string
	Version string
	Vendor  string
}

Tool represents a tool used in the creation of the SBOM.

type ToolType

type ToolType int

ToolType distinguishes the origin of a tool entry.

const (
	ToolTypeTool      ToolType = iota // a general tool
	ToolTypeComponent                 // a component used as a tool (CycloneDX)
	ToolTypeService                   // a service used as a tool (CycloneDX)
)

type Unmarshaler

type Unmarshaler struct {
	// contains filtered or unexported fields
}

Unmarshaler parses SBOM documents from any io.Reader. It uses an internal Identifier to auto-detect the format before parsing.

func NewUnmarshaler

func NewUnmarshaler(opts ...unmarshalerOption) *Unmarshaler

NewUnmarshaler creates an Unmarshaler with the given options. By default it uses a new Identifier with default settings.

func (*Unmarshaler) Unmarshal

func (u *Unmarshaler) Unmarshal(r io.Reader) (*Document, error)

Unmarshal reads from r, identifies the SBOM format, and parses the document into a Document. It returns ErrUnknownFormat if the input is not a recognized SBOM, ErrEmptyInput if the reader is empty, and ErrUnsupportedFormat for recognized but unsupported formats.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL