Upgrading packages in squash scope

hello!
i’m trying to validate the behave of syft in squash mode in case of upgrading a package.
assuming I have a package, for example jq in ubuntu image, and after a while I upgrade it, what will appear in the SBOM? both versions? only the latest version?
can you refer me in the code where this filtering is done?

thanks!

(tried to create a Dockerfile to demonstrate it but every time it downloads directly the latest version).

Hi @TimBrown1611! Good question. I think your question illustrates the difference between squashed and all-layers scopes that you can pass to Syft.

Let’s start with a Dockerfile:

FROM fedora:latest

RUN yum install -y jq-1.7.1-4.fc40

RUN yum remove -y jq

RUN yum install -y jq-1.7.1-7.fc40

So now we make an image with two versions of jq in two different layers, and we see what Syft makes of it.

docker build . -t localhost/discourse274
syft -o json=syft.json localhost/discourse274
syft --scope all-layers -o json=all-layers.json localhost/discourse274

Then we can use jq to look at how jq is written down in the two SBOMs:

For squashed scope (cat syft.json| jq '[ .artifacts[] | select(.name == "jq") | {purl: .purl, locations: .locations[]} ]'):

[
  {
    "purl": "pkg:rpm/fedora/jq@1.7.1-7.fc40?arch=aarch64&distro=fedora-40&upstream=jq-1.7.1-7.fc40.src.rpm",
    "locations": {
      "path": "/usr/lib/sysimage/rpm/rpmdb.sqlite",
      "layerID": "sha256:5d1f3baf10a3b56faa51f98890082a9d8523abc4984b77f23264db6b4c1a9261",
      "accessPath": "/usr/lib/sysimage/rpm/rpmdb.sqlite",
      "annotations": {
        "evidence": "primary"
      }
    }
  }
]

Now let’s look at the all-layers scope with the same jq command, but on all-layers.json:

[
  {
    "purl": "pkg:rpm/fedora/jq@1.7.1-4.fc40?arch=aarch64&distro=fedora-40&upstream=jq-1.7.1-4.fc40.src.rpm",
    "locations": {
      "path": "/usr/lib/sysimage/rpm/rpmdb.sqlite",
      "layerID": "sha256:c25c9316928a0f6488c57f9b62347ebc0f4e787e5b6bdcf1512c2f2c69d5db0c",
      "accessPath": "/usr/lib/sysimage/rpm/rpmdb.sqlite",
      "annotations": {
        "evidence": "primary"
      }
    }
  },
  {
    "purl": "pkg:rpm/fedora/jq@1.7.1-7.fc40?arch=aarch64&distro=fedora-40&upstream=jq-1.7.1-7.fc40.src.rpm",
    "locations": {
      "path": "/usr/lib/sysimage/rpm/rpmdb.sqlite",
      "layerID": "sha256:5d1f3baf10a3b56faa51f98890082a9d8523abc4984b77f23264db6b4c1a9261",
      "accessPath": "/usr/lib/sysimage/rpm/rpmdb.sqlite",
      "annotations": {
        "evidence": "primary"
      }
    }
  }
]

As you can see, when scope is “squashed” Syft only reports the jq version that was installed in the last layer of the Dockerfile, because that’s what’s actually present if you run the container, whereas the all-layers scope reports both versions of jq because it considers packages that are present in any layer.

Does this answer your question?

hi @willmurphy
yes, indeed. in case of upgrading a package I expect the same thing right?
only the current version to appear.

thanks!

That’s correct. For squashed scope, you see the version that is present in the final (squashed) image file system.