Tracking Dependencies Beyond the Build Stage
Many developers are familiar with dependency scanning at build time, but can we go further? And why is it worth doing so?
Join the DZone community and get the full member experience.
Join For FreeWhen working on modern software, a developer will often use hundreds or thousands of dependencies. Кeeping an accurate and consistent bill of materials is essential for license compliance and for security.
Motivation
In a large organization, the scope of dependencies review given by build-time scanning has some limitations.
- It's often about a single project — a large organization may have hundreds of applications developed across teams and departments, potentially even using different versions of the same dependency.
- It analyzes dependencies outside the context where they are used. For example, some dependencies and metrics are more critical in production than in testing environments. Additionally, some components built into the application are never used or are used only in some environments.
- Reviewing findings and analyzing the impact of discovered vulnerabilities can be difficult when you don't know where or when a vulnerable component is active.
- Planning future reviews or ad hoc checks when vulnerabilities are discovered takes a lot of time and effort.
Options
Consider an alternative solution: your application serves a standardized API endpoint, where a live list of the active dependencies can be fetched. Of course, dependency information is sensitive, and thus the API must be purely internal to your organization and protected against unauthorized access — but if you have it, automatic monitoring can fetch this information from live instances and store it, e.g., in a centralized database, providing an accurate, up-to-date, actionable overview of the software supply chain and lifecycle.
The ability to review the list of dependencies at runtime is a great opportunity for developers to ask themselves questions and possibly refine their decisions. However, given the sensitivity of the data, the pattern may be reversed, with the application submitting the list to a back-end service at start time. This way, the data would be aggregated and managed in a centralized way across the organization.
Sample Implementation
I've prepared a PoC for providing dedicated API endpoints, alongside a sample scheduling UI which you can find here: https://github.com/olddimplex/dependency-management.
The project uses Maven for building, but nothing stops you from doing the same with another framework.
At build time, the list of dependencies is collected using the Apache Maven Dependency Plugin, with the output type set to graphml. This format is directly readable by the powerful yEd diagram editor if you are interested in rendering dependencies as a graph. If you do so, some manual work would be needed to define the layout, where the editor comes into play.
The resulting XML file is stored on the class path, making it available at runtime.
In terms of configuration, you only need to add the plugin to the pom.xml file as shown below.
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<phase>compile</phase>
<goals>
<goal>tree</goal>
</goals>
</execution>
</executions>
<configuration>
<outputType>graphml</outputType>
<outputFile>src/main/resources/${project.name}-dependency-tree.xml</outputFile>
</configuration>
</plugin>
</plugins>
</build>
This applies to each of the project's modules, if any. The information is aggregated at runtime, so you'll be presented with the list of dependencies across all modules. Since the dependencies have their own dependencies, the resulting graph is a tree in XML format. We are interested in managing dependencies, so only the direct (top-level) nodes are retrieved from the tree and then aggregated.
An API is provided to expose a list of the manageable dependencies to the front-end.
This API is designed for use with DayPilot Pro for JavaScript, but it could be implemented otherwise as well. An example initial screen is shown below.
The size of the visible time window is configurable — in this case, it is 1 year from the current date. You can use the calendar icon to set the start date of the time window.
Apart from the list of dependencies, it is possible to define a list of scheduled events for each of them. You can add events using the mouse, then drag or resize them (change start/end time) the same way. There is a context menu for each event, assigned to the right mouse button.
For the demo, event data is only kept in-memory. If you need persistent data, you can implement the provided interface; otherwise.
Recall, to see the dependencies in the browser, you need to provide your own copy of DayPilot Pro for JavaScript, place and refer to it in the project source tree as shown below. In your case, the version can be different, though you'll get it when downloading the trial.
Use mvn clean package from the root of the project. The executable .jar file is stored in the target sub-directory. Running it starts a local Web server — watch the console for the port — the context path is /demo.
For example, the URL to navigate could be: http://localhost:8080/demo/dependency-management.html.
In addition, you can explore the API at http://localhost:8080/demo/swagger-ui/index.html.
Enjoy!
The same approach could be applied to existing applications of a similar architecture. I'd be glad to hear your thoughts on this topic.
Conclusion
In this article, you have been presented with a concept about improving the visibility and maintenance of dependencies. A sample implementation was provided for a Java application that uses Maven for its life cycle management. Possible future developments were proposed.
Opinions expressed by DZone contributors are their own.


Comments