Two things are missing from the "get manifests" example. First, if you include the http headers, you'll likely get the digest field, or you can skip the jq and pipe the result into a sha256sum to get the digest. But you also need to add an "Accept" header for the various media types of a manifest, otherwise the registry will convert it to an older schema v1 syntax which will not have the same digest. Here's an example that does the two v2 docker media types:
api="application/vnd.docker.distribution.manifest.v2+json"
apil="application/vnd.docker.distribution.manifest.list.v2+json"
curl -H "Accept: ${api}" -H "Accept: ${apil}" \
-u admin:adminPass \
-I -s "nexus.example.com/v2/abc-web-service-stage-2/manifests/5.2.6_1"
The next issue you'll run into with your policy is the 30 day requirement. You can get the creation time on many images by pulling their image config blob (it's listed in the manifest), but that date will be when the image was created, not when it was pushed or last pulled. There have been suggestions to add API's to OCI to handle more metadata, but we're still a ways off from that, and further still to get registry providers to implement them. So you'd end up deleting things that are likely being used. Even the 5 tag rule can be problematic if several new tags are created working through bugs in CI and you age out the image currently deployed in production.
With that all said, some tooling that I work on called regclient may help. The regctl
command gives you a way to script this in a shell, e.g.:
#!/bin/sh
registry="nexus.example.com"
cutoff="$(date -d -30days '+%s')"
for repo in $(regctl repo ls "$registry"); do
# The "head -n -5" ignores the last 5 tags, but you may want to sort that list first.
for tag in $(regctl tag ls "$registry/$repo" | head -n -5); do
# This is the most likely command to fail since the created timestamp is optional, may be set to 0,
# and the string format might vary.
# The cut is to remove the "+0000" that breaks the "date" command.
created="$(regctl image config "$registry/$repo:$tag" --format '{{.Created}}' | cut -f1,2,4 -d' ')"
createdSec="$(date -d "$created" '+%s')"
# both timestamps are converted to seconds since epoc, allowing numeric comparison
if [ "$createdSec" -lt "$cutoff" ]; then
# next line is prefixed with echo for debugging, delete the echo to run the tag delete command
echo regctl tag rm "$registry/$repo:$tag"
fi
done
done
Note that I'm using "regctl tag rm" above, which is different from an image manifest delete you're seeing in the API. This will attempt to do an OCI tag delete API first, which likely isn't supported by your registry. It falls back to pushing a dummy manifest and deleting that. The alternative of deleting the current manifest the tag points to is you may delete more tags than intended (you could have 5 tags all pointing to the same manifest).
If you want to further automate this, regbot
in that same repo lets you build a policy and run it on a schedule to constantly cleanup old images according to your rules.
In addition to regclient, there's also crane and skopeo that may also help in this space, but the features of each of these will vary.