Skip to content

Draft: providers: add BellSoft OSV provider#924

Open
i-bs wants to merge 1 commit intoanchore:mainfrom
i-bs:main
Open

Draft: providers: add BellSoft OSV provider#924
i-bs wants to merge 1 commit intoanchore:mainfrom
i-bs:main

Conversation

@i-bs
Copy link

@i-bs i-bs commented Nov 19, 2025

for Alpaquita Linux and BellSoft Hardened Containers

@i-bs
Copy link
Author

i-bs commented Nov 19, 2025

I tried but unfortunately failed to test this locally with https://github.com/i-bs/grype/commits/main/: Grype outputs empty results.

Anybody can help me out with this? Thanks!

@i-bs
Copy link
Author

i-bs commented Nov 19, 2025

File to test with: syft.json.gz

@i-bs
Copy link
Author

i-bs commented Nov 24, 2025

anybody to look at this please?

@i-bs
Copy link
Author

i-bs commented Dec 1, 2025

please??

@i-bs
Copy link
Author

i-bs commented Jan 21, 2026

Data source

OSV Ecosystem "BellSoft SA" providing data for these Linux distros:

  • Alpaquita Linux
  • BellSoft Hardened Containers

Example

Inspected images

Linux distros images:

The images correctly parsed by Syft which determines the distro and packages included.

os-release VENDOR_IDs:

  • alpaquita
  • bellsoft-hardened-containers

Current status and issues

Vunnel patched (this PR).

Grype patched (commit)

Patched Vunnel pulls provider data(provider=bellsoft). But Grype cannot find this data to link it to the found packages:

[0015] DEBUG no OS found in the DB for the given criteria os=alpaquita

Please help with finding the problem and fix it. Thanks.

@willmurphyscode
Copy link
Contributor

Hi @i-bs! Thanks for opening a PR!

We added some new docs pretty recently that you might find helpful, especially https://oss.anchore.com/docs/contributing/vunnel/

There are a couple things to check here:

  1. Does the grype invocation you're running have your new data? You can see which database grype is using with grype db status and you can see what providers grype has available with grype db providers. If grype isn't using your new provider, please see the docs above on setting up a dev environment (make dev provider=<your provider> in vunnel will set up grype config correctly).
  2. If grype does have your data, is there a matcher for it? Grype uses a combination of package type and distro from /etc/os-release in an image to figure out what vuln data to search against. What format of package does bellsoft use? RPM? dpkg?
  3. Does your local checkout of grype-db depend on your branch of grype? If not, your changes in https://github.com/i-bs/grype/commits/main/ may not have any effect. (I suspect this is what's happening to you, since you haven't mentioned grype-db at all.)

Lastly, if none of those are working, please feel free to ping again (make sure you @willmurphyscode so that your message stands out in the ~200 github notifications I get per day) and I'll take a look. Also, we have a community meeting every two weeks: calendar link and I have appointment slots of vulnerability provider office hours: https://calendar.app.google/ws24p3SPhKiL2vjC9

@i-bs
Copy link
Author

i-bs commented Jan 23, 2026

@willmurphyscode , thank you for looking into this.

1st I'm indeed using Vunnel Development Shell (found it myself in docs). Hence I'm quite sure Vunnel, Grype and Grype-DB are custom built with my patches:

((.venv) ) make update-db
task: [update-db] .github/scripts/update-dev-db.sh                                                                                                            
• Updating vunnel providers ...                                                                                                                               
[0000]  INFO grype-db version: 075c3c2183976d045ef5209c96bbb78e85dd3b44-adhoc-build
...
[0000]  INFO aggregating vulnerability data providers=[bellsoft]
[0000]  INFO running vulnerability provider provider=bellsoft
[0000]  INFO bellsoft: running bellsoft provider
...
[0003] DEBUG status eta=4s overall=38.46% provider="bellsoft" 1031/s (38.46%)
[0006] DEBUG status eta=2s overall=72.20% provider="bellsoft" 904/s (72.20%)
[0008] DEBUG wrote all provider state dropped=0 observed=8039 processed=8039

((.venv) ) grype db providers
NAME      VERSION  PROCESSOR                     DATE CAPTURED                         INPUT DIGEST
bellsoft  1        vunnel@0.0.0.post726+f03e887  2026-01-23 17:02:45.975521 +0000 UTC  xxh64:2b2bd1295681c02a

((.venv) ) grype-db list-providers
[0000]  INFO grype-db version: 075c3c2183976d045ef5209c96bbb78e85dd3b44-adhoc-build
bellsoft

2nd, Grype seems not see the relevant data:

((.venv) ) grype "pkg:apk/alpaquita/busybox@1.37.0-r30?arch=x86_64&distro=alpaquita" -vv
[0000]  INFO grype version: [not provided]
...
[0000] DEBUG no CPEs for package: Pkg(name="busybox" version="1.37.0-r30" type="apk" id="d1148f6b9191ae04")
[0000]  INFO using distro: alpaquita
[0000]  INFO gathered packages packages=1 time=14.312547ms
[0000]  INFO loaded DB status=valid time=18.027381ms
[0000] DEBUG ├── schema=v6.1.3
[0000] DEBUG ├── built=2026-01-23T17:02:59Z
[0000] DEBUG ├── from=manual import
[0000] DEBUG └── path=/usr/src/vunnel/.cache/grype/6/vulnerability.db
[0000] DEBUG no OS found in the DB for the given criteria os=alpaquita
...
No vulnerabilities found

I am strongly unsure about how Grype binds the Provider (which is bellsoft) with the distro id (alpaquita). Or maybe I did something wrong on the Vunnel side.

Can you please take another look? Thanks!

@willmurphyscode
Copy link
Contributor

Hi @i-bs !

Does your local checkout of grype-db depend on your branch of grype? If not, your changes in https://github.com/i-bs/grype/commits/main/ may not have any effect. (I suspect this is what's happening to you, since you haven't mentioned grype-db at all.)

I still think this is the problem. Can you confirm that your local build of grype-db links to your local build of grype? (Just having them next to each other won't do that, nor will just using the vunnel dev shell. Maybe that's something we should fix about the dev shell). I usually run go work init ; go work use . ../grype in grype-db, and then run make build-grype-db in vunnel to pick up the changes. The reason this is necessary is that the same data you updated at i-bs/grype@5dc0d87 in grype/db/v6/data.go is needed by grype-db and database build time.

Please let me know whether that helps!

@i-bs
Copy link
Author

i-bs commented Jan 23, 2026

@willmurphyscode ,
I double-did the rebuild after doing go work use ... and even replace .../grype => ../grype in grype-db's go.mod. Same result.

Did you look into the Vunnel and Grype patches? Does those seem ok to you?

Thanks!

@willmurphyscode
Copy link
Contributor

Hi @i-bs ! I think the issue is that the records in the grype database don't line up with your aliases.

So grype-db is going to call toLower() on the ecocstyem name in the OSV, so grype-db today will end up with: alpaquita, bellsoft hardened containers.

This:

		// BellSoft family
		{Alias: "alpaquita", ReplacementName: strRef("bellsoft"), Rolling: true},
		{Alias: "bellsoft-hardened-containers", ReplacementName: strRef("bellsoft"), Rolling: true},

is telling grype, "when you see alpaquita or bellsoft-hardened-containers in /etc/os-release or the distro param, look under "bellsoft" instead.

So that's the mismatch, grype-db is putting either alpaquita or "bellsoft hardened containers" and grype is always searching under "bellsoft".

Does that help? If not maybe we can meet sometime?

https://github.com/anchore/grype-db/blob/075c3c2183976d045ef5209c96bbb78e85dd3b44/pkg/process/v6/transformers/osv/transform.go#L515 does some ecosystem name normalization, might be relevant.

@willmurphyscode
Copy link
Contributor

You can also set GRYPE_DEV_DB_DEBUG=true in the environment and set log level pretty high (debug I think) to make grype log actual sql queries, which can be very useful for troubleshooting stuff like this.

I'm also not sure you want to mark every version of alpaquita "rolling" - that basically tells grype that this distro doesn't confine searches by distro version. I think instead you want to mark stream as rolling? You can see examples for that in the handling of alpine edge and debian unstable.

@i-bs
Copy link
Author

i-bs commented Jan 26, 2026

@willmurphyscode , thanks a lot, but..
Running the same command:

GRYPE_DEV_DB_DEBUG=true grype "pkg:apk/alpaquita/busybox@1.37.0-r30?arch=x86_64&distro=alpaquita" -vv

unfortunately gives no extra debug info (log below). I suggest it doesn't correctly merge config values because I see two dev: sections. I guess it processes only the 1st of them.

Also thanks for pointing to the transform.go in grype-db. I'll try to inject code there to tie the bellsoft ecosystem to alpaquita OS.

Details
[0000]  INFO grype version: [not provided]
[0000] DEBUG config:
�[35m  log:
      quiet: false
      level: debug
      file: ""
  dev:
      profile: none
  output: []
  file: ""
  pretty: false
  distro: ""
  add-cpes-if-none: false
  output-template-file: ""
  check-for-app-update: false
  only-fixed: false
  only-notfixed: false
  ignore-states: ""
  platform: ""
  search:
      scope: squashed
      unindexed-archives: false
      indexed-archives: true
  ignore: []
  exclude: []
  external-sources:
      enable: false
      maven:
          search-upstream: true
          base-url: https://search.maven.org/solrsearch/select
          rate-limit: 300ms
  match:
      java:
          using-cpes: false
      jvm:
          using-cpes: true
      dotnet:
          using-cpes: false
      golang:
          using-cpes: false
          always-use-cpe-for-stdlib: true
          allow-main-module-pseudo-version-comparison: false
      javascript:
          using-cpes: false
      python:
          using-cpes: false
      ruby:
          using-cpes: false
      rust:
          using-cpes: false
      stock:
          using-cpes: true
  fail-on-severity: ""
  registry:
      insecure-skip-tls-verify: false
      insecure-use-http: false
      auth: []
      ca-cert: ""
  show-suppressed: false
  by-cve: false
  sort-by: risk
  name: ""
  default-image-pull-source: ""
  from: []
  vex-documents: []
  vex-add: []
  match-upstream-kernel-headers: false
  fix-channel:
      redhat-eus:
          apply: auto
          versions: '>= 8.0'
  timestamp: true
  db:
      cache-dir: /usr/src/vunnel/.cache/grype
      update-url: https://grype.anchore.io/databases
      ca-cert: ""
      auto-update: false
      validate-by-hash-on-start: true
      validate-age: false
      max-allowed-built-age: 120h0m0s
      require-update-check: false
      update-available-timeout: 30s
      update-download-timeout: 5m0s
      max-update-check-frequency: 2h0m0s
  exp: {}
  dev:
      db:
          debug: true�[0m
[0000] DEBUG gathering packages
[0000] DEBUG loading DB
[0000] DEBUG skipping db update
[0000] DEBUG no CPEs for package: Pkg(name="busybox" version="1.37.0-r30" type="apk" id="d1148f6b9191ae04")
[0000]  INFO using distro: alpaquita 
[0000]  INFO gathered packages packages=1 time=14.384273ms
[0000]  INFO loaded DB status=valid time=19.394129ms
[0000] DEBUG ├── schema=v6.1.3
[0000] DEBUG ├── built=2026-01-24T12:31:46Z
[0000] DEBUG ├── from=manual import
[0000] DEBUG └── path=/usr/src/vunnel/.cache/grype/6/vulnerability.db
[0000] DEBUG no OS found in the DB for the given criteria os=alpaquita
[0000] DEBUG failed to find CPE matches for package error=attempted CPE match against package with no CPEs package=busybox
[0000] DEBUG no OS found in the DB for the given criteria os=alpaquita
[0000] DEBUG no OS found in the DB for the given criteria os=alpaquita
[0000]  INFO found 0 vulnerability matches across 1 packages
[0000] DEBUG   ├── fixed: 0
[0000] DEBUG   ├── ignored: 0 (due to user-provided rule)
[0000] DEBUG   ├── dropped: 0 (due to hard-coded correction)
[0000] DEBUG   └── matched: 0
[0000] DEBUG       ├── unknown: 0
[0000] DEBUG       ├── negligible: 0
[0000] DEBUG       ├── low: 0
[0000] DEBUG       ├── medium: 0
[0000] DEBUG       ├── high: 0
[0000] DEBUG       └── critical: 0
[0000]  INFO found vulnerability matches time=1.656074ms
No vulnerabilities found

BTW, if osName == almaLinux { junction in https://github.com/anchore/grype-db/blob/075c3c2183976d045ef5209c96bbb78e85dd3b44/pkg/process/v6/transformers/osv/transform.go#L518 seems useless returning the same result in the end of the function.

@willmurphyscode
Copy link
Contributor

Hi @i-bs ! Thanks for taking this so far. I am happy to help get it in, but I need a test image that is publicly pullable for our quality gate. Is there a place I can pull an image? What many providers have done if the images are normally paid is push an old tag of a small image to some other registry and made it publicly pullable. If you can provide a test image, I can try to get this provider in. (You're also welcome to keep working on it - we need a test image either way.)

Please let me know:

  1. Would you like me to take over, or would you like to keep working on this?
  2. Either way, what public image can I use as a test case?

In case you want to keep working on this, here's what I've learned:

SQL only shows up at trace level logging. I oven find it useful to set GRYPE_LOG_FILE and grep the resulting file for TRACE sql: so that I can sort of see just the sql in one printout.

[0000] TRACE sql: SELECT * FROM `operating_systems` WHERE (name = "alpaquita" collate nocase OR release_id = "alpaquita" collate nocase) AND (channel IS NULL OR channel = '') duration=24.667µs rows=3
[0000] TRACE sql: SELECT `affected_package_handles`.`id`,`affected_package_handles`.`vulnerability_id`,`affected_package_handles`.`operating_system_id`,`affected_package_handles`.`package_id`,`affected_package_handles`.`blob_id` FROM `affected_package_handles` JOIN packages ON affected_package_handles.package_id = packages.id WHERE packages.name = "busybox" collate nocase AND affected_package_handles.operating_system_id IN (1,2,3) ORDER BY `affected_package_handles`.`id` LIMIT 300 duration=102.25µs rows=22

When I run GRYPE_DEV_DB_DEBUG=true grype "pkg:apk/alpaquita/busybox@1.37.0-r30?arch=x86_64&distro=alpaquita" -vv I see a lot of this:

[0000] DEBUG unable to parse constraint constraint=[>= 1.36.1-r1 < 1.37.0-r28] error=could not create fuzzy constraint: version "1.36.1-r1<1.37.0-r28" potentially is a version constraint expression (should not contain '><=' outside of quotes)
[0000] DEBUG unable to parse constraint constraint=[>= 1.35.0-r29 < 1.35.0-r35] error=could not create fuzzy constraint: version "1.35.0-r29<1.35.0-r35" potentially is a version constraint expression (should not contain '><=' outside of quotes)
[0000] DEBUG unable to parse constraint constraint=[>= 1.37.0-r20 < 1.37.0-r23] error=could not create fuzzy constraint: version "1.37.0-r20<1.37.0-r23" potentially is a version constraint expression (should not contain '><=' outside of quotes)
[0000] DEBUG unable to parse constraint constraint=[>= 1.36.1-r1 < 1.37.0-r27] error=could not create fuzzy constraint: version "1.36.1-r1<1.37.0-r27" potentially is a version constraint expression (should not contain '><=' outside of quotes)
[0000] DEBUG unable to parse constraint constraint=[>= 1.35.0-r29 < 1.35.0-r38] error=could not create fuzzy constraint: version "1.35.0-r29<1.35.0-r38" potentially is a version constraint expression (should not contain '><=' outside of quotes)
[0000] DEBUG unable to parse constraint constraint=[>= 1.37.0-r20 < 1.37.0-r26] error=could not create fuzzy constraint: version "1.37.0-r20<1.37.0-r26" potentially is a version constraint expression (should not contain '><=' outside of quotes)
[0000] DEBUG unable to parse constraint constraint=[>= 1.36.1-r1 < 1.37.0-r31] error=could not create fuzzy constraint: version "1.36.1-r1<1.37.0-r31" potentially is a version constraint expression (should not contain '><=' outside of quotes)

Which means Grype is dropping vulnerabilities because there are bad version constraints in the database. I think maybe the grype-db osv transformer doesn't know how handle a the combination of introduced and fixed correctly for the new provider.

Looking a grype db search -o json --pkg busybox

I see in the json:

     "ranges": [
      {
       "version": {
        "type": "ecosystem",
        "constraint": ">= 1.36.1-r1 < 1.37.0-r31"
       },
       "fix": {
        "version": "1.37.0-r31",
        "state": "fixed"
       }
      }
     ]

which I don't think is the correct way of making one. I think this is a grype-db bug that pre-exists your changes in the OSV transformer.

Let me know how you'd like to proceed and what test image we can use for this! Thanks for sticking with it so far!

@willmurphyscode willmurphyscode self-assigned this Jan 26, 2026
@i-bs
Copy link
Author

i-bs commented Jan 27, 2026

Dear @willmurphyscode ,
thank you for caring. Actually I don't mind you or Anchore team working on adapting Grype for Alpaquita Linux and Hardened Containers. My main priority is that our users (BellSoft and Anchore) get the best experience with Linux OS and security scanners. So either way I'm here to get the work done (though fairly my Go knowledge is close to zero).
Regarding the images for test:

(links are the same as above).

Your findings are very good. Thanks.
The imported OSV data corresponds the specs (see examples in https://ossf.github.io/osv-schema/#fixed-vulnerability-example). And this:

"constraint": ">= 1.36.1-r1 < 1.37.0-r31"

looks quite right from a human POV. But not from the Constraint Parser's.

So if the OSV transformer needs to be fixed, maybe the missing peace is the APK (Linux package) version parser. Indeed the scanner needs to know how to compare versions which is generally distro-specific. One advantage here is that Alpaquita versions obey the same rules as Alpine Linux APKs and it probably can be reused.

I'll keep looking deeper here. If you have something please share or add your commits.
Thanks a lot!

@willmurphyscode
Copy link
Contributor

"constraint": ">= 1.36.1-r1 < 1.37.0-r31"

That's fine OSV, but I believe grype, which does not use OSV internally, is expecting a comma. The log line

[0000] DEBUG unable to parse constraint constraint=[>= 1.35.0-r29 < 1.35.0-r35] error=could not create fuzzy constraint: version "1.35.0-r29<1.35.0-r35" potentially is a version constraint expression (should not contain '><=' outside of quotes)

is Grype saying, "someone put >= 1.35.0-r29 < 1.35.0-r35 as a single clause in an affected package record's version constraint and I don't know what to do about that." Grype expects >= 1.35.0-r29,< 1.35.0-r35 I believe.

I think the issue is that at https://github.com/anchore/grype-db/blob/main/pkg/process/v6/transformers/osv/transform.go#L302-L307

only semver and bitnami type versions are being normalized.

@i-bs
Copy link
Author

i-bs commented Jan 29, 2026

The change like this one?
https://github.com/i-bs/grype-db/commits/main/

@i-bs i-bs force-pushed the main branch 2 times, most recently from 94b56cf to b3bfcd4 Compare February 4, 2026 17:33
for Alpaquita Linux and BellSoft Hardened Containers

Signed-off-by: Ildar Mulyukov <ildar.mulyukov@bell-sw.com>
@i-bs
Copy link
Author

i-bs commented Feb 8, 2026

"constraint": ">= 1.36.1-r1 < 1.37.0-r31"

That's fine OSV, but I believe grype, which does not use OSV internally, is expecting a comma.

@willmurphyscode

I believe I fixed this fault in anchore/grype-db#869 . Please take a look, it is short.

I also enabled my desired Ecosystems in that PR. With that Grype sees vuln. info for the requested pkg.

But I suspect that the package version ranges are not determined correctly. Will check it tomorrow. Thanks.

@willmurphyscode
Copy link
Contributor

Hi @i-bs ! Thanks for your patience. I am working to get this in, but I have one question: Typically, other APK / Apline based distros we scan use Alpine SecDB, which has basically the semantics: use NVD CPEs to do the initial search, and then use entries from Alpine SecDB to rule out findings that are fixed in distro packages. Is that the semantics we have here? To ask another way, do you publish vulnerabilities in your OSV feed or only fixes?

@i-bs
Copy link
Author

i-bs commented Feb 13, 2026

@willmurphyscode , thanks for the feedback.

Let me clarify:

  1. Alpaquita is not Alpine-based in this perspective. And Alpaquita APK artifacts are not the same as Alpine's. Hence Alpine SecDB is not applicable to Alpaquita packages
  2. CPE/Severity/CVSS vector may differ from Alpine's as well as from any other sources
  3. As you may know OSV DB prohibits using CVE-____-____ ids for vendors DB entries. This is why BellSoft uses BELL-CVE-____-____ ids
  4. Regarding the last question: BellSoft publishes fixes as well as the unfixed entries.

@willmurphyscode
Copy link
Contributor

@i-bs sorry, I wasn't trying to ask if we should literally use Alpine SecDB for matching. But most Alpine based distros we've seen have some variant of SecDB semantics, that is, they expect us to match against NVD CPEs and then filter out fixes they have published. It sounds like for Bellsoft / Alpaquita we should just assume that the OSV feed is complete for APK packages on that distro. Is that right?

@i-bs
Copy link
Author

i-bs commented Feb 19, 2026

@willmurphyscode , sorry for the delay.

BellSoft OSV feed is complete regarding the package set, applicable CVEs as well as severity data and needs no additional source of information(*). Moreover the feed is limited only to the packages/CVEs relevant to BellSoft Linux ecosystem and doesn't contain any info relevant to Alpine/Windows/etc.

So, yes, BellSoft OSV feed should be enough to process vulnerability data in BellSoft Alpaquita Linux / Hardened Containers.

(*) The feed is almost complete but it has Summary and Description fields empty. See google/osv-scanner#2476 for details.

@willmurphyscode
Copy link
Contributor

@i-bs thanks! One additional question. What's the relationship between "bellsoft-hardened-containers" and "alpaquita linux"? Are there two sets of vulnerability data here or just one?

@i-bs
Copy link
Author

i-bs commented Feb 24, 2026

While in theory the two products share the same artifacts, those are built slightly differently and should be treated differently. Internally the APK comparison rules are the same.

I see that Grype "ecosystems" and OSV ecosystems are a little different. BellSoft ecosystem in OSV has two Linux distros: Alpaquita and Hardened Containers. In Grype source code it seems to be hard having both in one "ecosystem". Is that right?

@willmurphyscode
Copy link
Contributor

@i-bs I'm just trying to understand what the matching behavior should be; implementation difficulty in Grype is something I think about after I know what I'm trying to accomplish.

Here are some very concrete questions that may help:

  1. If we encounter an image, can we tell by inspecting /etc/os-release or similar whether the image is Bellsoft Hardened Containers or is Alpaquita? Can we tell these distros apart?
  2. Can you point to a match that depends on this distinction? For example, an APK at a specific version that should be considered vulnerable on Alpaquita and fixed on Bellsoft or vice versa? Do you expect that such matches do or don't exist?

@i-bs
Copy link
Author

i-bs commented Feb 24, 2026

@willmurphyscode , thanks for working on this.

  1. If we encounter an image, can we tell by inspecting /etc/os-release or similar whether the image is Bellsoft Hardened Containers or is Alpaquita? Can we tell these distros apart?

Sure. It is ID=alpaquita and ID=bellsoft-hardened-containers in /etc/os-release

  1. Can you point to a match that depends on this distinction? For example, an APK at a specific version that should be considered vulnerable on Alpaquita and fixed on Bellsoft or vice versa? Do you expect that such matches do or don't exist?

OSV data contains vulnerability data for both of the distros in the same records. So normally no guessing here. The match may and may not be, we cannot tell a-priory.

I.e. if a BellSoft record has entries for Alpaquita packages and does not have entries for Bellsoft Hardened Containers this means that the vulnerability is not applicable to Bellsoft Hardened Containers.

I hope this clarifies a bit.

Also reminding the live images links:

@i-bs
Copy link
Author

i-bs commented Mar 4, 2026

@willmurphyscode ,
FYI I opened a DRAFT PR: anchore/grype#3264
It is definitely neither ready nor complete. But at least with it Grype sees some vuln(s) already.
Work In Progress.

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.

2 participants