Skip to content

fix(cyclonedx): write the authors list instead of the deprecated author field for 1.6 and later - #5199

Open
hamodywe wants to merge 1 commit into
anchore:mainfrom
hamodywe:fix/cyclonedx-deprecated-author
Open

fix(cyclonedx): write the authors list instead of the deprecated author field for 1.6 and later#5199
hamodywe wants to merge 1 commit into
anchore:mainfrom
hamodywe:fix/cyclonedx-deprecated-author

Conversation

@hamodywe

Copy link
Copy Markdown
Contributor

Description

CycloneDX 1.6 deprecated component.author in favour of component.authors, and syft still writes the deprecated one. It shows up in every document syft produces at the default spec version, since metadata.tools.components names anchore there:

$ syft scan alpine:latest -o cyclonedx-json | jq .metadata.tools

# before
{ "components": [ { "type": "application", "author": "anchore", "name": "syft", "version": "1.x" } ] }

# after
{ "components": [ { "type": "application", "authors": [ { "name": "anchore" } ], "name": "syft", "version": "1.x" } ] }

Taking the approach suggested in #4580: the format model is built once and then encoded to whichever version was asked for, so it has to keep the field that every version has. The translation belongs where the target version is known — the encoder — and that is where this puts it, alongside where the library already decides which fields survive a given spec version. For 1.5 and earlier nothing changes; there is no list to write there, and the library strips authors on the way out anyway.

It applies to every component, not only the tools entry. Package components carry the same deprecated field (author from npm/python/ruby metadata), and a document that used the current shape in one place and the deprecated one in another would be a stranger thing than either alone. Nested components are covered too.

Decoding reads whichever of the two fields a document states. Without that half, syft could no longer read an author back from its own output at the default version — and nothing would have said so: TestSupportedVersions does the encode/decode round trip against a fixture that has no author at all. It also means syft now reads authors from 1.6 documents produced by other tools, which it previously dropped.

On splitting: an author is carried across whole, as a single entry. Where syft has more than one author to describe, encodeAuthor joins them with a separator of the ecosystem's own choosing (, for ruby, whatever npm's author string contains), so splitting that back apart here would mean guessing at a convention that differs per ecosystem — and guessing wrong changes what the document claims. Only the name <email> form that encodeAuthor itself produces is split, into a name and an email. componentAuthor returns exactly what went in.

Type of change

  • Bug fix (non-breaking change which fixes an issue)

Checklist

  • I have added unit tests that cover changed behavior
  • I have tested my code in common scenarios and confirmed there are no regressions
  • I have added comments to my code, particularly in hard-to-understand sections

Verification

  • Test_ComponentAuthorByVersion runs the encode/decode round trip over every supported version with a fixture that has an author, and asserts which field the document uses: "author" through 1.5, "authors" from 1.6, never both. Each half of the change was reverted independently — dropping the encoder half or the decoder half makes 1.6 and 1.7 fail while 1.2–1.5 stay green.
  • Test_ConvertComponentAuthors covers each place a component can appear (tools, metadata.component, top-level and nested components), the name <email> form, authors that are already stated, components with no author, and a nil document; a round-trip case asserts componentAuthor reads back exactly what the conversion wrote.
  • Ran ./syft/format/... on the branch and on a pristine tree and compared the failure sets — identical, so nothing here newly fails.
  • golangci-lint run reports nothing on any changed file.

On the goldens: the two directory goldens were regenerated with -update-cyclonedx-json / -update-cyclonedx-xml. The two image goldens need Docker to regenerate, which I do not have here, so the same one-field replacement was applied to them by hand — byte-identical to what regeneration produced in the directory goldens beside them. Each of the four changes by exactly that one field and nothing else, which the diff shows.

Issue references

Fixes #4580


Disclosure: written with AI assistance (the commit carries a Co-Authored-By trailer). Behaviour was checked against the encoder for every supported spec version, before and after, rather than reasoned about from the spec alone.

…or field for 1.6 and later

CycloneDX 1.6 deprecated the author field on a component in favour of a
list of authors, and syft still writes the deprecated one -- including at
metadata.tools.components, where it names anchore in every document syft
produces at the default spec version.

The format model is built once and then encoded to whichever version was
asked for, so it has to carry the field every version has. This adds the
translation on the way out, where the target version is known and the
library has already decided which fields survive: the deprecated field is
rewritten into the list for 1.6 and later, and left exactly as it was for
earlier versions, which have no list to write.

It applies to every component, not only the tools entry. Package authors
carry the same deprecated field, and a document that used the current
shape in one place and the deprecated one in another would be a stranger
thing than either alone.

Decoding reads whichever of the two fields a document states. Without
that, syft could no longer read back an author from its own output at the
default version -- and nothing would have said so, since the round trip
covered by TestSupportedVersions runs against a fixture with no author.

An author is carried across whole, as a single entry. Where syft has more
than one author to describe it joins them with a separator of the
ecosystem's own choosing, so splitting that string apart here would mean
guessing at a convention that differs per ecosystem; only the "name
<email>" form that encodeAuthor produces is split, into a name and an
email. What comes back out of componentAuthor is exactly what went in.

The snapshot goldens change by one field each. The image goldens were
edited to match rather than regenerated, since regenerating them needs
Docker; the replacement is byte-identical to what regeneration produced
in the directory goldens beside them.

Fixes anchore#4580

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: hamodywe <iosapk.org@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Eliminate deprecated field metadata.tools.components.author on cyclonedx 1.6 format

1 participant