skip to Main Content

The following json is extracted from a json file in CycloneDX format produced by Syft tool over a debian:bulleye-slim docker image.

{
    "bomFormat": "CycloneDX",
    "components": [{
            "name": "bsdutils",
            "version": "1:2.36.1-8+deb11u1",
            "purl": "pkg:deb/debian/bsdutils@1:2.36.1-8+deb11u1?arch=amd64&upstream=util-linux%402.36.1-8+deb11u1&distro=debian-11",
            "properties": [{
                    "name": "syft:metadata:source",
                    "value": "util-linux"
                }, {
                    "name": "syft:metadata:sourceVersion",
                    "value": "2.36.1-8+deb11u1"
                }
            ]
        }, {
            "name": "curl",
            "version": "7.74.0-1.3+deb11u7",
            "purl": "pkg:deb/debian/[email protected]+deb11u7?arch=amd64&distro=debian-11"
        }, {
            "name": "libaudit-common",
            "version": "1:3.0-2",
            "purl": "pkg:deb/debian/libaudit-common@1:3.0-2?arch=all&upstream=audit&distro=debian-11",
            "properties": [{
                    "name": "syft:metadata:source",
                    "value": "audit"
                }
            ]
        }
    ]
}

I would like to transform it as the following, using linux script (on a yaml pipeline):

{
    "bomFormat": "CycloneDX",
    "components": [{
            "name": "util-linux",
            "version": "2.36.1-8+deb11u1",
            "purl": "pkg:deb/debian/[email protected]+deb11u1?arch=source",
            "properties": [{
                    "name": "syft:metadata:source",
                    "value": "util-linux"
                }, {
                    "name": "syft:metadata:sourceVersion",
                    "value": "2.36.1-8+deb11u1"
                }
            ]
        }, {
            "name": "curl",
            "version": "7.74.0-1.3+deb11u7",
            "purl": "pkg:deb/debian/[email protected]+deb11u7?arch=amd64&distro=debian-11"
        }, {
            "name": "audit",
            "version": "1:3.0-2",
            "purl": "pkg:deb/debian/audit@1:3.0-2?arch=source",
            "properties": [{
                    "name": "syft:metadata:source",
                    "value": "audit"
                }
            ]
        }
    ]
}

The pseudo algorithm to make the transformation is:

for each component where component.purl.startwith(pkg:deb/debian/) and component.properties.syft:metadata:source is set
   component.name = properties.where(name=="syft:metadata:source").value
   if (properties.syft:metadata:sourceVersion)
       component.version = properties.where(name=="syft:metadata:sourceVersion").value
   component.purl=pkg:deb/debian/{component.name}@{component.version}?arch=source
take any other component not matching the where/select "as is" 

I thought jq may be the best tool to do the job, but I once again struggle to use it properly.

After some tries with jqplay.org
the fist line (the select part) is given by

.components[]|select((.properties[].name=="syft:metadata:source") and (.purl | startswith("pkg:deb/debian")))

I now need to combine all to be able to edit the 3 fields I want: name, version and purl from the edited name and version.

Any help is welcome!

2

Answers


  1. Chosen as BEST ANSWER

    current working solution

    .components[]|select((.properties[].name=="syft:metadata:source") and (.purl | startswith("pkg:deb/debian")) ) as $comps 
    | .name=(.properties[] | select(.name == "syft:metadata:source").value)
    | .version=(.properties[] | select(.name == "syft:metadata:sourceVersion").value)
    | .purl="pkg:deb/debian/"+(.name)+"@"+(.version)+"?arch=source"
    

    It is not yet fully covering my need, but partially...


  2. It sounds like you want to interpret your "properties" array as an object and then merge it into the parent while renaming some keys. The following jq program should do that:

    (.components[] | select(.properties|from_entries?|has("syft:metadata:source")))
    |= . + (
        .properties // []
        | from_entries
        | {
            name: ."syft:metadata:source",
            version: ."syft:metadata:sourceVersion"
        }
        | . + { purl: "pkg:deb/debian/(.name)@(.version)?arch=source" }
    )
    

    or the equivalent:

    "syft:metadata:source" as $source
    | "syft:metadata:sourceVersion" as $version
    | (.components[] | select(.properties|from_entries?|has($source)))
    |= . + (
        .properties // []
        | from_entries
        | {
            name: .[$source],
            version: .[$version],
            purl: "pkg:deb/debian/(.[$source])@(.[$version])?arch=source"
        }
    )
    

    The output for either program will be:

    {
      "bomFormat": "CycloneDX",
      "components": [
        {
          "name": "util-linux",
          "version": "2.36.1-8+deb11u1",
          "purl": "pkg:deb/debian/[email protected]+deb11u1?arch=source",
          "properties": [
            {
              "name": "syft:metadata:source",
              "value": "util-linux"
            },
            {
              "name": "syft:metadata:sourceVersion",
              "value": "2.36.1-8+deb11u1"
            }
          ]
        },
        {
          "name": "curl",
          "version": "7.74.0-1.3+deb11u7",
          "purl": "pkg:deb/debian/[email protected]+deb11u7?arch=amd64&distro=debian-11"
        }
      ]
    }
    

    If you are like me and feel uneasy about the repeated check for the source, then a little restructuring helps to get rid of the repetition:

    "syft:metadata:source" as $source
    | "syft:metadata:sourceVersion" as $version
    | .components[]
    |= . + (
        (
            .properties//[]
            | from_entries
            | select(has($source))
            | {
                name: .[$source],
                version: .[$version],
                purl: "pkg:deb/debian/(.[$source])@(.[$version])?arch=source"
            }
        ) // {}
    )
    

    To only update the source/name, but skip the version if it is not contained in the properties, use the updated version:

    "syft:metadata:source" as $syftSource
    | "syft:metadata:sourceVersion" as $syftVersion
    | .components[]
    |= . + (
         (
            .version as $componentVersion
            | .properties//[]
            | from_entries
            | select(has($syftSource))
            | (.[$syftVersion]//$componentVersion) as $version
            | .[$syftSource] as $name
            | {
                $name,
                $version,
                purl: "pkg:deb/debian/($name)@($version)?arch=source"
            }
        ) // {}
    )
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search