# sbomasm

sbomasm is a comprehensive SBOM management toolkit for assembling, editing, enriching, viewing, and cryptographically signing SBOMs. It supports both SPDX and CycloneDX formats and handles operations that span multiple SBOMs — merging microservice SBOMs into a platform-wide view, enriching components with license data, editing metadata for compliance, and signing SBOMs for integrity verification.

**Repository:** [github.com/interlynk-io/sbomasm](https://github.com/interlynk-io/sbomasm)

***

## Use Cases

| Operation        | When to Use                                                           |
| ---------------- | --------------------------------------------------------------------- |
| Assemble (merge) | Combine SBOMs from multiple services, containers, or modules into one |
| Edit             | Update metadata (supplier, author, version) before distribution       |
| Enrich           | Fill missing license information from ClearlyDefined                  |
| Remove           | Strip components or fields before sharing externally                  |
| View             | Inspect SBOM structure and dependencies                               |
| Sign / Verify    | Establish authenticity and detect tampering                           |

***

## Installation

### Homebrew (macOS/Linux)

```bash
brew tap interlynk-io/interlynk
brew install sbomasm
```

### Go Install

```bash
go install github.com/interlynk-io/sbomasm@latest
```

### Pre-Built Binaries

Download from the [GitHub releases page](https://github.com/interlynk-io/sbomasm/releases) for Linux (amd64, arm64), macOS (amd64, arm64), and Windows (amd64).

### Docker

```bash
docker run -v $(pwd):/data ghcr.io/interlynk-io/sbomasm:latest assemble \
  -n 'my-app' -v '1.0.0' -o /data/merged.json /data/sbom1.json /data/sbom2.json
```

### Build from Source

```bash
git clone https://github.com/interlynk-io/sbomasm.git
cd sbomasm
make build
```

### Verify Installation

```bash
sbomasm version
```

***

## Core Operations

### Assemble (Merge SBOMs)

Combine multiple SBOMs into a single document. Four merge strategies are available:

| Strategy     | Flag                    | Behavior                                                           |
| ------------ | ----------------------- | ------------------------------------------------------------------ |
| Hierarchical | `--hierMerge` (default) | Preserves component structure; nests input SBOMs under a new root  |
| Flat         | `--flatMerge`           | Removes relationships; flattens all components to the same level   |
| Assembly     | `--assemblyMerge`       | Treats each SBOM independently without linking to primary          |
| Augment      | `--augmentMerge`        | Enriches a primary SBOM with data from others; no new root created |

#### Hierarchical Merge (Default)

```bash
sbomasm assemble \
  -n 'platform-sbom' \
  -v '2.0.0' \
  -o merged.cdx.json \
  service-a.cdx.json service-b.cdx.json service-c.cdx.json
```

#### Flat Merge

```bash
sbomasm assemble \
  --flatMerge \
  -n 'platform-sbom' \
  -v '2.0.0' \
  -o merged.cdx.json \
  service-a.cdx.json service-b.cdx.json
```

#### Assembly Merge

```bash
sbomasm assemble \
  --assemblyMerge \
  -n 'platform-sbom' \
  -v '2.0.0' \
  -o merged.cdx.json \
  service-a.cdx.json service-b.cdx.json
```

#### Augment Merge

Enrich an existing SBOM with components from other SBOMs without changing the root structure:

```bash
sbomasm assemble \
  --augmentMerge \
  --primary base-sbom.cdx.json \
  --merge-mode if-missing-or-empty \
  -o enriched.cdx.json \
  additional-data.cdx.json
```

Merge modes for augment:

* `if-missing-or-empty` (default) — only fills in empty or missing fields
* `overwrite` — replaces existing values

#### Output Format Control

```bash
# CycloneDX JSON (default)
sbomasm assemble -n 'app' -v '1.0' -o out.cdx.json sbom1.json sbom2.json

# CycloneDX XML
sbomasm assemble -n 'app' -v '1.0' --xml -o out.cdx.xml sbom1.json sbom2.json

# SPDX JSON
sbomasm assemble -n 'app' -v '1.0' --outputSpecSpdx -o out.spdx.json sbom1.json sbom2.json

# Specific spec version
sbomasm assemble -n 'app' -v '1.0' --outputSpecVersion 1.5 -o out.json sbom1.json sbom2.json
```

#### Configuration-Driven Assembly

Generate a configuration template:

```bash
sbomasm generate
```

Example configuration file (`assemble-config.yaml`):

```yaml
app:
  name: 'platform-sbom'
  version: '2.0.0'
  type: 'application'
  description: 'Combined platform SBOM'
  supplier:
    name: 'Acme Corp'
    email: 'security@acme.com'
  author:
    - name: 'Security Team'
      email: 'security@acme.com'
  licenses:
    - id: 'Apache-2.0'
  purl: 'pkg:generic/acme/platform@2.0.0'
  cpe: 'cpe:2.3:a:acme:platform:2.0.0:*:*:*:*:*:*:*'

output:
  spec: cyclonedx
  file_format: json
  file: 'platform-sbom.cdx.json'

assemble:
  hierarchical_merge: true
  include_components: true
  include_dependency_graph: true
```

Run with configuration:

```bash
sbomasm assemble --configPath assemble-config.yaml service-a.cdx.json service-b.cdx.json
```

#### Assemble Parameters

| Parameter             | Short | Required          | Default               | Description                |
| --------------------- | ----- | ----------------- | --------------------- | -------------------------- |
| `--name`              | `-n`  | Yes (non-augment) | —                     | Name for assembled SBOM    |
| `--version`           | `-v`  | Yes (non-augment) | —                     | Version for assembled SBOM |
| `--output`            | `-o`  | No                | stdout                | Output file path           |
| `--type`              | `-t`  | No                | `application`         | Component type             |
| `--configPath`        | `-c`  | No                | —                     | YAML configuration file    |
| `--hierMerge`         | `-m`  | No                | Default               | Hierarchical merge         |
| `--flatMerge`         | `-f`  | No                | —                     | Flat merge                 |
| `--assemblyMerge`     | `-a`  | No                | —                     | Assembly merge             |
| `--augmentMerge`      | —     | No                | —                     | Augment merge              |
| `--primary`           | `-p`  | Augment only      | —                     | Primary SBOM file          |
| `--merge-mode`        | —     | No                | `if-missing-or-empty` | Merge mode for augment     |
| `--outputSpecCdx`     | `-g`  | No                | Default               | CycloneDX output           |
| `--outputSpecSpdx`    | `-s`  | No                | —                     | SPDX output                |
| `--outputSpecVersion` | `-e`  | No                | Latest                | Spec version               |
| `--xml`               | `-x`  | No                | —                     | XML output                 |
| `--json`              | `-j`  | No                | Default               | JSON output                |

**Component type values:** `application`, `framework`, `library`, `container`, `device`, `firmware`

***

### Edit SBOM Metadata

Modify metadata on the SBOM document, primary component, or specific components.

#### Edit Document Metadata

```bash
sbomasm edit \
  --subject document \
  --supplier "Acme Corp (https://acme.com)" \
  --author "Security Team" \
  --tool "sbomasm (v2.0)" \
  --timestamp \
  -o updated.cdx.json \
  original.cdx.json
```

#### Edit Primary Component

```bash
sbomasm edit \
  --subject primary-component \
  --name "my-application" \
  --version "2.1.0" \
  --purl "pkg:generic/acme/my-application@2.1.0" \
  --license "Apache-2.0" \
  --description "Main application component" \
  -o updated.cdx.json \
  original.cdx.json
```

#### Edit a Specific Component

```bash
sbomasm edit \
  --subject component-name-version \
  --search "log4j-core:2.17.0" \
  --license "Apache-2.0" \
  --supplier "Apache Foundation (https://apache.org)" \
  -o updated.cdx.json \
  original.cdx.json
```

#### Edit Modes

| Flag        | Behavior                                           |
| ----------- | -------------------------------------------------- |
| (default)   | Overwrite existing values                          |
| `--append`  | Add to existing values (e.g., additional licenses) |
| `--missing` | Only set if the field is currently empty           |

#### Editable Fields

| Field       | Flag            | Format                             |
| ----------- | --------------- | ---------------------------------- |
| Name        | `--name`        | String                             |
| Version     | `--version`     | String                             |
| Type        | `--type`        | Component type value               |
| Supplier    | `--supplier`    | `"Name (url)"`                     |
| Author      | `--author`      | String (repeatable)                |
| PURL        | `--purl`        | Package URL                        |
| CPE         | `--cpe`         | CPE identifier                     |
| License     | `--license`     | SPDX expression (repeatable)       |
| Hash        | `--hash`        | `"Algorithm (value)"` (repeatable) |
| Tool        | `--tool`        | `"Name (version)"` (repeatable)    |
| Copyright   | `--copyright`   | String                             |
| Lifecycle   | `--lifecycle`   | Phase name (repeatable)            |
| Description | `--description` | String                             |
| Repository  | `--repository`  | URL                                |
| Timestamp   | `--timestamp`   | Flag — adds current time           |

***

### Enrich SBOMs

Fill missing license information using the ClearlyDefined API.

```bash
# Enrich missing licenses
sbomasm enrich --fields license -o enriched.cdx.json sbom.cdx.json

# Force-replace existing licenses
sbomasm enrich --fields license --force -o enriched.cdx.json sbom.cdx.json

# Custom license joining operator
sbomasm enrich --fields license --license-exp-join AND -o enriched.cdx.json sbom.cdx.json

# Adjust batch size and retry behavior
sbomasm enrich --fields license --chunk-size 50 --max-retries 3 --max-wait 10 -o enriched.cdx.json sbom.cdx.json
```

| Parameter            | Short | Default | Description                                      |
| -------------------- | ----- | ------- | ------------------------------------------------ |
| `--fields`           | —     | —       | Fields to enrich (currently: `license`)          |
| `--output`           | `-o`  | stdout  | Output file                                      |
| `--force`            | `-f`  | Off     | Replace existing values                          |
| `--max-retries`      | `-r`  | `2`     | API retry attempts                               |
| `--max-wait`         | `-w`  | `5`     | Max wait time (seconds)                          |
| `--license-exp-join` | `-j`  | `OR`    | License expression operator: `OR`, `AND`, `WITH` |
| `--chunk-size`       | `-c`  | `100`   | Batch size for API requests                      |

The enrichment process reports:

* Total components
* Components selected for enrichment
* Successfully enriched count
* Skipped count
* Failed count

***

### Remove Components or Fields

Strip components or metadata before external distribution.

```bash
# Remove a specific component
sbomasm rm --components --name "internal-lib" -o cleaned.cdx.json sbom.cdx.json

# Remove a field from all components
sbomasm rm --field author --scope component --all -o cleaned.cdx.json sbom.cdx.json

# Remove dependencies
sbomasm rm --dependency --id "pkg:npm/internal@1.0.0" -o cleaned.cdx.json sbom.cdx.json

# Dry run — preview changes
sbomasm rm --components --name "internal-*" --dry-run sbom.cdx.json

# Summary of changes
sbomasm rm --components --name "internal-lib" --summary -o cleaned.cdx.json sbom.cdx.json
```

***

### View SBOM Structure

Inspect SBOM contents without modifying the file.

```bash
# Default tree view
sbomasm view sbom.cdx.json

# Verbose — show all fields
sbomasm view --verbose sbom.cdx.json

# Show only licenses
sbomasm view --only-licenses sbom.cdx.json

# Filter by component type
sbomasm view --filter-type "library,framework" sbom.cdx.json

# Show vulnerabilities with severity filter
sbomasm view --vulnerabilities --min-severity high sbom.cdx.json

# Limit tree depth
sbomasm view --max-depth 2 sbom.cdx.json

# Flat list format
sbomasm view --format flat sbom.cdx.json

# JSON output
sbomasm view --format json -o structure.json sbom.cdx.json

# Hide disconnected components
sbomasm view --hide-islands sbom.cdx.json
```

***

### Sign and Verify SBOMs

Cryptographically sign SBOMs for integrity verification using the SecureSBOM service.

#### Sign

```bash
sbomasm sign \
  --key-id "your-key-id" \
  --api-key "$SECURE_SBOM_API_KEY" \
  --output signed.cdx.json \
  sbom.cdx.json
```

For SPDX (detached signature):

```bash
sbomasm sign \
  --key-id "your-key-id" \
  --api-key "$SECURE_SBOM_API_KEY" \
  --detached \
  --output signature.b64 \
  sbom.spdx.json
```

#### Verify

```bash
# CycloneDX (embedded signature)
sbomasm verify \
  --key-id "your-key-id" \
  --api-key "$SECURE_SBOM_API_KEY" \
  signed.cdx.json

# SPDX (detached signature)
sbomasm verify \
  --key-id "your-key-id" \
  --api-key "$SECURE_SBOM_API_KEY" \
  --signature "$(cat signature.b64)" \
  sbom.spdx.json
```

| Parameter    | Default                | Description                      |
| ------------ | ---------------------- | -------------------------------- |
| `--key-id`   | —                      | Signing key ID (required)        |
| `--api-key`  | `$SECURE_SBOM_API_KEY` | API key for SecureSBOM service   |
| `--base-url` | Default service URL    | Custom SecureSBOM endpoint       |
| `--output`   | stdout                 | Output file                      |
| `--detached` | Off                    | Return detached signature (SPDX) |
| `--timeout`  | `30s`                  | Request timeout                  |
| `--retry`    | `3`                    | Retry attempts                   |

***

## Supported Formats

### Input

| Spec      | Versions      | File Formats         |
| --------- | ------------- | -------------------- |
| SPDX      | 2.1, 2.2, 2.3 | JSON, XML, Tag-Value |
| CycloneDX | 1.0 – 1.6     | JSON, XML            |

### Output

| Spec      | Default Version | File Formats |
| --------- | --------------- | ------------ |
| SPDX      | 2.3             | JSON         |
| CycloneDX | 1.6             | JSON, XML    |

Formats are auto-detected on input. Cross-format assembly (mixing SPDX and CycloneDX inputs) is supported — the output format is determined by flags.

***

## Advanced Usage

### Multi-Module Builds

For projects with multiple build modules (e.g., microservices, monorepos):

```bash
# Step 1: Generate per-module SBOMs during build
cd service-a && syft . -o cyclonedx-json > ../sboms/service-a.cdx.json
cd service-b && syft . -o cyclonedx-json > ../sboms/service-b.cdx.json
cd service-c && syft . -o cyclonedx-json > ../sboms/service-c.cdx.json

# Step 2: Assemble into platform SBOM
sbomasm assemble \
  -n 'platform' \
  -v '$(git describe --tags)' \
  -t application \
  -o platform-sbom.cdx.json \
  sboms/*.cdx.json

# Step 3: Enrich with license data
sbomasm enrich --fields license -o platform-sbom-enriched.cdx.json platform-sbom.cdx.json

# Step 4: Score quality
sbomqs score platform-sbom-enriched.cdx.json

# Step 5: Upload to Interlynk
pylynk upload --prod 'platform' --sbom platform-sbom-enriched.cdx.json
```

### Large SBOM Handling

For SBOMs with thousands of components:

* **Batch assembly:** Assemble in stages — merge groups of SBOMs first, then merge the results.
* **Enrichment chunking:** Use `--chunk-size 50` to reduce memory usage during license enrichment.
* **View depth limiting:** Use `--max-depth 2` and `--hide-islands` for readable output.
* **JSON output:** Use `--format json` for machine processing rather than tree rendering.

```bash
# Stage 1: Merge groups
sbomasm assemble -n 'batch-1' -v '1.0' -o batch1.json group1/*.json
sbomasm assemble -n 'batch-2' -v '1.0' -o batch2.json group2/*.json

# Stage 2: Final assembly
sbomasm assemble -n 'complete' -v '1.0' -o final.json batch1.json batch2.json
```

### Dependency-Track Integration

Fetch SBOMs directly from Dependency-Track, assemble, and optionally upload back:

```bash
sbomasm assemble dt \
  --url https://dtrack.example.com \
  --api-key "$DT_API_KEY" \
  -n 'combined' \
  -v '1.0.0' \
  -o combined.cdx.json \
  <project-uuid-1> <project-uuid-2>
```

### CI/CD Pipeline Example

```yaml
# GitHub Actions: Full SBOM pipeline
name: SBOM Pipeline
on:
  release:
    types: [published]

jobs:
  sbom:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Generate SBOMs
        run: |
          syft ./service-a -o cyclonedx-json > service-a.cdx.json
          syft ./service-b -o cyclonedx-json > service-b.cdx.json

      - name: Assemble Platform SBOM
        run: |
          sbomasm assemble \
            -n '${{ github.event.repository.name }}' \
            -v '${{ github.event.release.tag_name }}' \
            -o platform.cdx.json \
            service-a.cdx.json service-b.cdx.json

      - name: Enrich Licenses
        run: sbomasm enrich --fields license -o platform-enriched.cdx.json platform.cdx.json

      - name: Quality Gate
        run: |
          SCORE=$(sbomqs score --json platform-enriched.cdx.json | jq -r '.files[0].sbom_quality_score')
          if (( $(echo "$SCORE < 7.0" | bc -l) )); then
            echo "::error::SBOM quality $SCORE below threshold 7.0"
            exit 1
          fi

      - name: Upload to Interlynk
        env:
          INTERLYNK_SECURITY_TOKEN: ${{ secrets.INTERLYNK_SERVICE_TOKEN }}
        run: pylynk upload --prod '${{ github.event.repository.name }}' --sbom platform-enriched.cdx.json
```

***

## Error Handling

### Common Errors

| Error                       | Cause                                       | Resolution                                                  |
| --------------------------- | ------------------------------------------- | ----------------------------------------------------------- |
| `file not found`            | Invalid input path                          | Verify file path; use absolute paths in Docker              |
| `unsupported format`        | Unrecognized SBOM format                    | Ensure input is valid CycloneDX or SPDX                     |
| `name and version required` | Missing `--name` or `--version`             | Provide both for non-augment assembly                       |
| `primary file required`     | Augment merge without `--primary`           | Specify `--primary` with augment merge                      |
| `invalid reference`         | Dependency references nonexistent component | Fix the source SBOM; ensure all referenced components exist |
| ClearlyDefined API timeout  | Network or rate limiting                    | Increase `--max-wait` and `--max-retries`                   |
| Signing service unavailable | SecureSBOM API down                         | Check service status; increase `--timeout`                  |

### Debug Mode

Enable debug logging globally:

```bash
sbomasm --debug assemble -n 'app' -v '1.0' -o out.json input.json
```

Debug output includes processing flow details, component matching decisions, deduplication results, and API request/response information.

***

## Best Practices

### Assembly

* Use **hierarchical merge** for platform-level SBOMs where component provenance matters.
* Use **flat merge** when downstream consumers need a simple component list.
* Use **augment merge** to enrich vendor-provided SBOMs without altering their structure.
* Include `--type` to set the correct component type (`application`, `container`, `library`).
* Store assembly configuration in version control alongside your build scripts.

### Editing

* Use `--missing` mode to fill gaps without overwriting vendor-provided metadata.
* Use `--append` to add supplementary licenses or authors without removing existing ones.
* Edit the `document` subject to set creation tool and timestamp metadata before distribution.

### Enrichment

* Run enrichment after assembly to process all components in one pass.
* Use `--license-exp-join AND` for conservative license interpretation in regulated environments.
* Review enrichment reports — failed components may need manual attention.

### Security

* Sign SBOMs before distributing to external parties.
* Verify received SBOMs before importing into your supply chain management system.
* Store signing API keys in a secrets manager; never commit to source control.
* Strip internal components (`sbomasm rm`) before sharing SBOMs externally.

***

## Common Misconfigurations

| Issue                                        | Symptom                       | Fix                                                     |
| -------------------------------------------- | ----------------------------- | ------------------------------------------------------- |
| Missing `--name` and `--version` on assemble | Error at startup              | Always provide both unless using augment merge          |
| Mixing formats without output spec flag      | Unexpected output format      | Explicitly set `--outputSpecCdx` or `--outputSpecSpdx`  |
| Augment without `--primary`                  | Error requiring primary file  | Specify the base SBOM with `--primary`                  |
| Large enrichment without `--chunk-size`      | Timeouts or high memory usage | Set `--chunk-size 50` for SBOMs with 1000+ components   |
| Signing without `SECURE_SBOM_API_KEY`        | Authentication error          | Set the environment variable or use `--api-key`         |
| Editing with default overwrite mode          | Vendor metadata lost          | Use `--missing` or `--append` to preserve existing data |
