Dynamically querying EndOfLife.date data for internal packages with Open Policy Agent and Dependency Management Data

Featured image for sharing metadata for article

When working with dependency-management-data, one of the great things it can do is provide insight to how close/far past the end-of-life date of upstream projects your dependencies are.

This data is provided through the excellent EndOfLife.date, and dependency-management-data wires this data in for dependencies it can understand are i.e. Python, Ruby, or Go.

But you're not always going to be working with dependencies that are used in the public world, for instance I've recently been working with some images of the format:

docker.internal.tld/python:3.9
docker.internal.tld/go:1.22-nonroot

Each of these are still bound by the End-of-Life lifecycle of the upstream projects, but right now there's no way for dependency-management-data to be able to surface that information.

I've been looking at a few options for how to surface this better, and fortunately there are a few choices within dependency-management-data, but the one that I was most interested was the excellent Open Policy Agent (OPA) and the inbuilt support that dependency-management-data has for it. I'd recently seen that there's the ability to perform HTTP requests, and thought this would be a good opportunity to see if this would work.

Today I've finished off an example of this policy, alongside a couple of tweaks to DMD to make the process more performant.

This Policy gives us the ability to determine, for each usage of docker.internal.tld/python:

  • is it already End-of-Life?
  • is it soon End-of-Life?
  • is it already out of active support?
  • is it soon out of active support?

Notice that we also explicitly cache the HTTP requests for OPA, as we don't need to retrieve this more than once, and we need to perform some management of the different shapes of the EndOfLife.date API structure.

The policy looks like so:

# NOTE that this was significantly reduced in DMD v0.102.0

package policy

import rego.v1

default the_product := null

default cycle := null

default advisory_type := "DEPRECATED"

days_until_warn := 60

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# below is for the Policy author to determine, as it's dependency specific

version := split(input.dependency.current_version, "-")[0]

versions := split(version, ".")

cycle := sprintf("%s.%s", [versions[0], versions[1]])

# DMD: filter: package_name: docker.internal.tld/python
the_product := "python" if {
	input.dependency.package_name == "docker.internal.tld/python"
}

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# below here is boilerplate

deny contains msg if {
	[is_eol, msg] := endoflifedate_is_eol(the_product, cycle)

	is_eol
}

# we need to override this from the default DEPRECATED
advisory_type := "UNMAINTAINED" if {
	[is_eol, msg] := endoflifedate_is_eol(the_product, cycle)

	is_eol
}

deny contains msg if {
	[approaching_eol, msg] := endoflifedate_approaching_eol(the_product, cycle, days_until_warn)

	approaching_eol
}

deny contains msg if {
	[is_unsupported, msg] := endoflifedate_is_unsupported(the_product, cycle)

	is_unsupported
}

deny contains msg if {
	[approaching_unsupported, msg] := endoflifedate_approaching_unsupported(the_product, cycle, days_until_warn)

	approaching_unsupported
}

As of v0.102.0 of dependency-management-data, this includes builtins that perform a lot of the boilerplate of determining whether our image is End-of-Life/unsupported, or nearing each case, and instead allowing us to focus on what we're actually trying to convey.

Written by Jamie Tanna's profile image Jamie Tanna on , and last updated on .

Content for this article is shared under the terms of the Creative Commons Attribution Non Commercial Share Alike 4.0 International, and code is shared under the Apache License 2.0.

#dependency-management-data #blogumentation #open-policy-agent.

This post was filed under articles.

Interactions with this post

Interactions with this post

Below you can find the interactions that this page has had using WebMention.

Have you written a response to this post? Let me know the URL:

Do you not have a website set up with WebMention capabilities? You can use Comment Parade.