I promised yesterday that it would be my last post about how we are using Dependency Track. But turns out that there is some confusion and a few people asked me the following question:
"How should I organize all these projects?"
This is a good question because a well-structured project hierarchy makes the difference between a dashboard that provides clarity and one that creates confusion. In this post, I'll share the project organization strategies we've explored and practical examples you can adapt to your organization.
Understanding Dependency-Track's model
Dependency-Track organizes work around several key concepts:
- Projects: The fundamental unit representing a software component. Each project has a name and version.
- Remark: A project can also be flagged as current.
- Versions: Projects can have multiple versions representing different releases or deployments.
- Classifiers: Indicates if the project type is a library, framework, application,… .
- Tags: Flexible labels you can attach to projects for categorization and filtering.
- Parent-Child Relationships: Projects can have hierarchical relationships
- Teams: Groups of users with specific permissions that can be assigned to projects.
- Properties: Custom metadata you can attach to projects.
The parent-child relationship deserves some extra explanation. The parent in in the parent-child can be setup as a “collection Project”, which allows to define that a parent itself does not host any components, but instead aggregates metrics of vulnerabilities and policy violations of its children with one of three possible calculation methods:
- Aggregate all direct children
- Aggregate all direct children which have a tag of your choice
- Aggregate all direct children which are marked as latest version
Common Structuring Strategies
There's no one-size-fits-all approach, but here are the most common strategies and when to use each:
Strategy 1: Application-Centric
In this approach, each deployable application or service is a project, with versions representing different releases or environments. You can optionally aggregate them using a collection project under one parent project.
Structure:
Project Name: myapp-api
Versions: 1.0.0, 1.1.0, 1.2.0, dev, staging, production
Project Name: myapp-frontend
Versions: 1.0.0, 1.1.0, 1.2.0, dev, staging, production
Project Name: myapp-worker
Versions: 1.0.0, 1.1.0, 1.2.0, dev, staging, production
Tags: team:platform, product:myapp, tier:critical
When to use:
- You have clear application boundaries
- Each application has its own release cycle
- You need to track what's deployed in each environment
Advantages:
- Clear ownership per application
- Easy to track deployment status across environments
- Natural fit for microservices architectures
- Aligns with how developers think about their work
Disadvantages:
- Can result in many projects for large organizations
- Version management requires discipline
Strategy 2: Product-Centric with Component Hierarchy
Group related applications under a product umbrella using a project collection, tags or naming conventions.
Structure:
Project Name: ecommerce-api
Tags: product:ecommerce, component:api, team:backend
Project Name: ecommerce-web
Tags: product:ecommerce, component:frontend, team:frontend
Project Name: ecommerce-mobile-android
Tags: product:ecommerce, component:mobile, platform:android, team:mobile
Project Name: ecommerce-mobile-ios
Tags: product:ecommerce, component:mobile, platform:ios, team:mobile
Project Name: ecommerce-recommendation-engine
Tags: product:ecommerce, component:ml, team:datascience
When to use:
- You have multiple products with several components each
- Cross-product reporting is important
- Different teams contribute to the same product
Advantages:
- Easy to get product-level vulnerability overview
- Supports complex organizational structures
- Flexible tagging enables multiple reporting views
Disadvantages:
- Requires consistent tagging discipline
- Tags aren't hierarchical (can't nest products)
Strategy 3: Environment-First
Create separate projects for each environment, useful when environments have significantly different configurations.
Structure:
Project Name: myapp-production
Version: 2024.12.15 (date-based versioning)
Project Name: myapp-staging
Version: 2024.12.16
Project Name: myapp-development
Version: 2024.12.18
Tags: application:myapp, tier:critical
When to use:
- Different environments have significantly different dependencies
- You need strict separation between environment security postures
- Compliance requires environment-specific tracking
Advantages:
- Crystal clear view of what's in each environment
- Easy to apply environment-specific policies
- Simple to understand for operations teams
Disadvantages:
- Harder to track component history across environments
- Can create confusion during releases
- Doesn't scale well with many applications
Our approach
After experimenting with different strategies, we've settled on a hybrid approach depending on if its a library or an application:
For applications we settled on one project for a complete system per environment grouped in a collection project using the ‘Aggregate all direct children’ aggregation strategy:
For our internal framework and libraries, we use one project per library version (using a combination of project name and version) and aggregate it in a collection project using the ‘Aggregate all direct children which are marked as latest version’ aggregation strategy:
Wrap up
A well-thought-out project structure in Dependency-Track is foundational to getting value from the platform. The key principles to remember:
- Be consistent: Establish conventions and stick to them
- Be pragmatic: Don't over-engineer your structure
- Be descriptive: Use tags liberally to add context
- Be maintainable: Automate cleanup and updates
- Be flexible: Your structure will evolve with your organization
Start simple, document your decisions, and iterate based on feedback from your teams. The structure that works best is the one that helps your organization understand and manage security risks effectively.
Happy secure coding!