feat(ci): send a released version's documents to Dependency-Track - #82
Open
nikzen wants to merge 6 commits into
Open
feat(ci): send a released version's documents to Dependency-Track#82nikzen wants to merge 6 commits into
nikzen wants to merge 6 commits into
Conversation
syft names the image it read and stops there, which leaves the document without the one name for an artefact that cannot drift. The digest is known only once the registry holds the image, so it is written in between the push and the signature: the attestation, the release asset and anything reading them later then agree on what the document is about. The repository and the run go in beside it, because a document that names a digest still does not say where the thing came from.
A document attached to a release answers what a version shipped, to whoever thinks to look. It cannot answer the other direction: a component became a problem today, and which of the versions still in use holds it. That question arrives without warning and is asked of every release at once, so the documents go somewhere that keeps them. Only released versions are sent. Nobody asks that of a nightly, and a portfolio filled with them buries the versions that are actually out there. Each platform image gets a line of its own, because it is a separate artefact holding different bytes, and a line keeps a history: the analysis recorded against the version before is carried over, or a release would start its triage from nothing. The key that does this needs no right to change or remove what is already there. Repositories with no tracker to tell leave `DEPENDENCY_TRACK_URL` unset, and the step is skipped.
`PUT /v1/project/clone` is deprecated as of 5.0.0, the release that introduced the replacement, and it answers with a token that is a fresh random UUID rather than a handle on any work: the clone is already done when it returns. Waiting on that token waited on nothing. The v2 endpoint answers 201 with the UUID of the clone, so what happened is visible from the answer. Its list of what to include takes the access list as well, which the old call had no way to ask for — a clone without one is a clone nobody can see, should this instance ever restrict who may read what.
The address comes from a settings page, where a pasted URL commonly keeps its trailing slash, and every request would then carry a doubled one.
A rerun, or a retry after the clone but before the upload, finds this tag as latest. Cloning it into itself is a conflict, and the upload that would refresh the documents never runs.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit e4f98bc. Configure here.
pkg:oci names only the last fragment of the repository. Where to fetch it from is repository_url, which is the whole path — debian lives at docker.io/library/debian, not docker.io/library. Stripping the name left Dependency-Track identifying the digest under the namespace. Signed-off-by: Niklas Zender <n.zender@famedly.com>
yash-garg
approved these changes
Aug 27, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Why
A document attached to a release answers what a version shipped, to whoever thinks to look for it. It cannot answer the other direction: a component became a problem today, and which of the versions still out there holds it. That
question arrives without warning, is asked of every release at once, and is the one a regulator asks. Answering it needs the documents somewhere that keeps them, which is what Dependency-Track is for.
Stacked on #81, which switches these documents to CycloneDX — the only format Dependency-Track reads.
What changed
Each document is told what it describes. syft names the image it read and stops there, so the document carries no identity for the artefact it is about. A digest is the one name for an image that cannot drift, and it exists only once
the registry holds the image, so it is written in between the push and the signature: the attestation, the release asset and the tracker then all agree. The repository and the run go in beside it, because a digest still does not say where the thing came from. The lockfile document has no image of its own to point at and names the commit its packages were read at instead.
Dependency-Track reads
purl,cpe, the supplier and the external references straight out ofmetadata.componenton upload — verified against a live instance — so this needs no second call and no right to modify anything.A released version's documents are sent to the tracker. Only released versions: nobody asks that question of a nightly.
Each platform image gets a line of its own, under a node for the index, under one for the product:
A platform image is a separate artefact holding different bytes, so a single document over the index could only ever describe one of them, and each line keeps a history of its own. The analysis recorded against the previous version
is carried over by cloning it, or every release would start its triage from nothing — Dependency-Track offers no other way to inherit it.
Names are the short ones, because the registry reference is now in the document.
What a repository needs
DEPENDENCY_TRACK_URLas a variable anddependency_track_api_keyas a secret. Where the variable is unset the step is skipped, so nothing is required of a repository with no tracker to tell.Verification
Both workflows generated in
famedly-controlagainst this branch, then the generated scripts run verbatim against a live Dependency-Track 5.0.5 instance across two releases of a throwaway image:CONTAINERand the lockfile document asAPPLICATION, with the supplier, thepurlcarrying digest, registry, architecture and tag, and both external references.isLatestmoved by itself, both recorded verdicts were inherited, and a dependency bump planted for the purpose surfaced as 16 open findings.Made with Cursor