Multi-Repository Scenarios
Managing SBOMs across distributed codebases and microservice architectures
Modern software increasingly consists of multiple repositories rather than monolithic codebases. Microservice architectures split functionality across dozens of services, each with own repository, build pipeline, and release cadence. Frontend, backend, mobile apps, infrastructure-as-code—all separate repositories contributing to unified product experience. This distributed architecture creates SBOM challenges: How to represent product composed of many components? How to aggregate SBOMs from multiple sources? How to maintain consistency across repositories?
Multi-repository SBOM management requires coordination mechanisms beyond single-repository practices. Individual service SBOMs are necessary but insufficient—consumers need product-level view showing complete system composition. Organizations must balance granularity (service-level detail) with comprehensibility (product-level aggregation) while avoiding duplication and maintaining consistency as services evolve independently.
Multi-Repository Patterns
Pattern 1: Independent Service SBOMs
Each repository generates and publishes independent SBOM describing single service.
Structure:
product-ecosystem/
├── api-service/ (repo 1)
│ └── generates api-service-sbom.json
├── web-frontend/ (repo 2)
│ └── generates web-frontend-sbom.json
├── mobile-app/ (repo 3)
│ └── generates mobile-app-sbom.json
└── background-workers/ (repo 4)
└── generates workers-sbom.jsonAdvantages:
- Simple—each team owns their SBOM
- Natural boundaries matching organizational structure
- Independent release cadences supported
- Clear ownership and accountability
Challenges:
- Consumers must track multiple SBOMs per product
- Duplicate dependencies across services not visible
- No unified product view
- Difficult to answer "does Product X use Component Y?"
When appropriate: Early SBOM adoption, simple microservice architectures, technically sophisticated consumers comfortable managing multiple SBOMs.
Pattern 2: Aggregated Product SBOM
Central process aggregates service SBOMs into unified product-level SBOM.
Structure:
product-aggregator/ (orchestration repo)
├── collects api-service-sbom.json
├── collects web-frontend-sbom.json
├── collects mobile-app-sbom.json
├── collects workers-sbom.json
└── generates product-complete-sbom.json (aggregated)Aggregation process:
def aggregate_sboms(service_sboms):
"""Combine multiple service SBOMs into product SBOM"""
product_sbom = {
'bomFormat': 'CycloneDX',
'specVersion': '1.6',
'serialNumber': f'urn:uuid:{uuid.uuid4()}',
'version': 1,
'metadata': {
'component': {
'name': 'complete-product',
'version': PRODUCT_VERSION,
'type': 'application',
'description': 'Aggregated SBOM for complete product'
}
},
'components': [],
'dependencies': []
}
# Deduplicate components across services
seen_components = {}
for service_sbom in service_sboms:
service_name = service_sbom['metadata']['component']['name']
# Add service as component
product_sbom['components'].append({
'name': service_name,
'version': service_sbom['metadata']['component']['version'],
'type': 'application',
'description': f'Microservice component',
'bom-ref': f'service-{service_name}'
})
# Add service dependencies
for component in service_sbom.get('components', []):
purl = component.get('purl')
if purl and purl in seen_components:
# Duplicate—mark which services use it
seen_components[purl]['used_by'].append(service_name)
else:
# New component
component['used_by'] = [service_name]
seen_components[purl] = component
product_sbom['components'].append(component)
return product_sbomAdvantages:
- Single SBOM for consumers to manage
- Deduplication reveals shared dependencies
- Product-level vulnerability assessment
- Clear product boundaries
Challenges:
- Requires aggregation infrastructure and coordination
- Version synchronization complexity
- Aggregation pipeline becomes single point of failure
- Update latency between service changes and product SBOM
When appropriate: Mature SBOM programs, consumer preference for unified view, complex multi-service products, compliance requirements for product-level documentation.
Pattern 3: Hierarchical SBOM with References
Root product SBOM references service SBOMs rather than duplicating content.
Structure:
{
"bomFormat": "CycloneDX",
"specVersion": "1.6",
"metadata": {
"component": {
"name": "complete-product",
"version": "2.5.0",
"type": "application"
}
},
"components": [
{
"name": "api-service",
"version": "1.3.2",
"type": "application",
"bom-ref": "api-service-1.3.2",
"externalReferences": [
{
"type": "bom",
"url": "https://sbom.example.com/api-service/v1.3.2/sbom.json",
"comment": "Detailed SBOM for this service"
}
]
},
{
"name": "web-frontend",
"version": "2.1.0",
"type": "application",
"bom-ref": "web-frontend-2.1.0",
"externalReferences": [
{
"type": "bom",
"url": "https://sbom.example.com/web-frontend/v2.1.0/sbom.json",
"comment": "Detailed SBOM for this service"
}
]
}
]
}Advantages:
- Lightweight root SBOM
- No duplication—service SBOMs remain authoritative
- Consumers can traverse references for depth they need
- Clear service boundaries preserved
Challenges:
- Consumers must follow references for complete view
- Requires consumers support SBOM reference resolution
- Network dependencies for complete analysis
- Reference link maintenance as services move
When appropriate: Large-scale microservice architectures, sophisticated consumers with SBOM tooling, need for both high-level and detailed views.
Coordination Challenges
Version Synchronization
Product version 2.5.0 composed of api-service 1.3.2, web-frontend 2.1.0, mobile-app 3.0.1, workers 1.2.7. How to maintain consistent version mapping as services release independently?
Solution: Version manifest
{
"product": "complete-product",
"version": "2.5.0",
"release_date": "2024-01-15",
"services": [
{"name": "api-service", "version": "1.3.2", "sbom_url": "..."},
{"name": "web-frontend", "version": "2.1.0", "sbom_url": "..."},
{"name": "mobile-app", "version": "3.0.1", "sbom_url": "..."},
{"name": "workers", "version": "1.2.7", "sbom_url": "..."}
]
}Centralized version manifest tracks which service versions comprise each product release. Product SBOM aggregation references manifest to collect correct service SBOM versions.
Release Cadence Mismatch
API service releases weekly. Mobile app releases monthly. Frontend releases bi-weekly. Product SBOM aggregation must handle asynchronous updates.
Strategies:
Snapshot approach: Product releases happen on schedule (monthly). Aggregation captures current service versions at release time. Product SBOM reflects snapshot of services as-deployed.
Continuous approach: Product SBOM regenerates whenever any service updates. Always reflects latest service compositions. Consumers receive frequent updates.
Hybrid approach: Major product releases trigger new aggregated SBOM. Minor service updates trigger incremental SBOM updates marked with version increments (product 2.5.0 → 2.5.1 when single service patches).
Build Pipeline Coordination
Each service has own CI/CD pipeline. Aggregation requires coordinating across multiple pipelines.
Centralized collection:
# Product aggregation pipeline (runs on schedule or trigger)
name: Aggregate Product SBOM
on:
schedule:
- cron: '0 2 * * *' # Daily at 2 AM
workflow_dispatch: # Manual trigger
jobs:
aggregate:
runs-on: ubuntu-latest
steps:
- name: Fetch service SBOMs
run: |
# Download from SBOM repository
curl https://sbom.example.com/api-service/latest/sbom.json -o api.json
curl https://sbom.example.com/web-frontend/latest/sbom.json -o web.json
curl https://sbom.example.com/mobile-app/latest/sbom.json -o mobile.json
curl https://sbom.example.com/workers/latest/sbom.json -o workers.json
- name: Aggregate SBOMs
run: python aggregate-sboms.py api.json web.json mobile.json workers.json
- name: Validate aggregated SBOM
run: cyclonedx-cli validate --input-file product-sbom.json
- name: Publish product SBOM
run: |
curl -X POST https://sbom.example.com/api/upload \
-F "product=complete-product" \
-F "sbom=@product-sbom.json"Event-driven collection:
Service pipelines trigger aggregation pipeline on SBOM publication:
# Service pipeline (api-service)
- name: Publish SBOM
run: upload-sbom.sh sbom.json
- name: Trigger product aggregation
run: |
curl -X POST https://api.github.com/repos/org/product-aggregator/dispatches \
-H "Authorization: token €{{ secrets.DISPATCH_TOKEN }}" \
-d '{"event_type": "service-sbom-updated", "client_payload": {"service": "api-service"}}'Deduplication and Consolidation
Multiple services often use same dependencies. Proper deduplication prevents redundant component entries while preserving usage information.
Deduplication Strategy
def deduplicate_components(aggregated_components):
"""Consolidate duplicate components while tracking service usage"""
unique_components = {}
for component in aggregated_components:
# Use PURL as unique identifier
purl = component.get('purl')
if not purl:
# No PURL—cannot deduplicate reliably, keep as-is
unique_components[component['name']] = component
continue
if purl in unique_components:
# Duplicate found—merge usage information
existing = unique_components[purl]
# Combine used_by lists
existing.setdefault('used_by', []).extend(component.get('used_by', []))
existing['used_by'] = list(set(existing['used_by'])) # Deduplicate
# Version conflict check
if existing['version'] != component['version']:
# Same component, different versions across services
existing.setdefault('version_conflicts', []).append({
'version': component['version'],
'services': component.get('used_by', [])
})
else:
# New unique component
unique_components[purl] = component
return list(unique_components.values())Version Conflict Handling
Diamond dependencies at product level: Service A uses Library 1.0, Service B uses Library 2.0. How to represent in product SBOM?
Option 1: Document both versions
{
"components": [
{
"name": "conflicting-lib",
"version": "1.0.0",
"purl": "pkg:npm/conflicting-lib@1.0.0",
"properties": [
{"name": "cdx:used-by-services", "value": "api-service"}
]
},
{
"name": "conflicting-lib",
"version": "2.0.0",
"purl": "pkg:npm/conflicting-lib@2.0.0",
"properties": [
{"name": "cdx:used-by-services", "value": "web-frontend"}
]
}
]
}Both versions listed separately, annotated with which services use each.
Option 2: Document conflict explicitly
{
"components": [
{
"name": "conflicting-lib",
"version": "multiple",
"properties": [
{
"name": "cdx:version-conflict",
"value": "Service api-service uses 1.0.0, web-frontend uses 2.0.0"
}
]
}
]
}Single entry documenting version discrepancy.
Recommendation: Option 1 for accuracy. Vulnerability scanning requires knowing both versions might be deployed.
Shared Component Libraries
Organizations often maintain internal shared libraries used across services. Managing SBOMs for shared components requires coordination.
Internal Component Registry
Publish internal component SBOMs to registry:
internal-component-registry/
├── auth-library/
│ ├── v2.1.0/sbom.json
│ └── v2.1.1/sbom.json
├── logging-framework/
│ ├── v1.3.0/sbom.json
│ └── v1.3.1/sbom.json
└── data-validation/
└── v3.0.0/sbom.jsonService SBOMs reference internal components. Product aggregation includes internal component SBOMs transitively.
Transitive Internal Dependencies
Service depends on internal auth-library, which depends on internal logging-framework. Product SBOM must capture full internal dependency chain.
Solution: Treat internal components like external dependencies. Auth-library SBOM documents logging-framework dependency. Aggregation follows references recursively.
Update Propagation
When service SBOM updates, how quickly does product SBOM reflect changes?
Real-Time Propagation
Service SBOM publication triggers immediate product SBOM regeneration.
Advantages: Product SBOM always current within minutes
Challenges: High update frequency, potential instability from frequent regeneration
Suitable for: Critical systems requiring real-time transparency, mature automation infrastructure
Scheduled Propagation
Product SBOM regenerates on schedule (daily, weekly) regardless of service changes.
Advantages: Predictable update cadence, reduced infrastructure load
Challenges: Product SBOM may lag service changes by hours/days
Suitable for: Most organizations, stable release cadences, balanced freshness vs. operational overhead
Event-Driven Batching
Service updates queue aggregation requests. Aggregation runs when threshold met (5 services changed) or timeout reached (24 hours since last aggregation).
Advantages: Balances freshness with efficiency, reduces unnecessary aggregations
Challenges: More complex logic, potential confusion about update timing
Suitable for: Large-scale microservice architectures with frequent service updates
Governance and Ownership
Multi-repository SBOM requires clear ownership model.
Service-level ownership: Each service team owns their service SBOM. Responsible for quality, accuracy, updates.
Product-level ownership: Product management or architecture team owns product SBOM aggregation. Ensures consistency, coordinates across services, manages product-level distribution.
Platform team support: Platform/DevOps team provides SBOM infrastructure—repositories, aggregation tooling, CI/CD integration, monitoring.
Clear escalation: Service SBOM problems escalate to service team. Aggregation problems escalate to product owners. Infrastructure problems escalate to platform team.
Tools and Automation
SBOM aggregation tools:
- Custom scripts (Python, Go, Bash)
- CycloneDX merge utilities
- Commercial SBOM management platforms with aggregation features
- OSS Review Toolkit for complex scenarios
Repository infrastructure:
- Dependency-Track (multi-project support)
- Artifact registries (Artifactory, Nexus) with SBOM storage
- Custom SBOM repositories with API
CI/CD integration:
- GitHub Actions workflows for aggregation
- GitLab CI multi-project pipelines
- Jenkins orchestration jobs
- Tekton pipelines for Kubernetes environments
Next Steps
- Implement service-level SBOMs via Producer Workflows - Generate SBOMs
- Coordinate across teams using Implementation Guides - Skills and Training
- Manage dependencies through Advanced Topics - Transitive Dependencies
- Automate aggregation with Implementation Guides - Automation Strategies