From 4193794a01e0a4e5d728a88e1bf0f12b7d6207fa Mon Sep 17 00:00:00 2001 From: Mehnert Date: Fri, 9 Jan 2026 13:01:34 +0100 Subject: [PATCH 1/4] Add OPAM to osv.dev --- osv/ecosystems/_ecosystems.py | 2 ++ osv/ecosystems/opam.py | 49 +++++++++++++++++++++++++++++++++++ osv/purl_helpers.py | 2 ++ 3 files changed, 53 insertions(+) create mode 100644 osv/ecosystems/opam.py diff --git a/osv/ecosystems/_ecosystems.py b/osv/ecosystems/_ecosystems.py index f7cd436eca4..84dccdacc8f 100644 --- a/osv/ecosystems/_ecosystems.py +++ b/osv/ecosystems/_ecosystems.py @@ -24,6 +24,7 @@ from .hex import Hex from .maven import Maven from .nuget import NuGet +from .opam import Opam from .packagist import Packagist from .pub import Pub from .pypi import PyPI @@ -55,6 +56,7 @@ 'MinimOS': APK, 'npm': SemverEcosystem, 'NuGet': NuGet, + 'opam': Opam, 'openEuler': RPM, 'openSUSE': RPM, 'Packagist': Packagist, diff --git a/osv/ecosystems/opam.py b/osv/ecosystems/opam.py new file mode 100644 index 00000000000..c8db6cd8484 --- /dev/null +++ b/osv/ecosystems/opam.py @@ -0,0 +1,49 @@ +"""OPAM ecosystem helper.""" +import requests +import json + +from ..third_party.univers.debian import Version as DebianVersion +from . import config + +class Opam(EnumerableEcosystem): + """OPAM packages ecosystem""" + def _sort_key(self, version): + # OPAM uses debian versioning + if not DebianVersion.is_valid(version): + # If debian version is not valid, it is most likely an invalid fixed + # version then sort it to the last/largest element + return DebianVersion(9999999999, '9999999999') + return DebianVersion.from_string(version) + + _REPO = 'https://api.github.com/repos/ocaml/opam-repository/contents/packages/' + _REPO_ARCHIVE = 'https://api.github.com/repos/ocaml/opam-repository-archive/contents/packages/' + + def enumerate_versions(self, + package, + introduced, + fixed=None, + last_affected=None, + limits=None): + """Enumerate versions.""" + response = requests.get( + self._REPO + package, timeout=config.timeout) + archive_response = requests.get( + self._REPO_ARCHIVE + package, timeout=config.timeout) + if response.status_code == 404 && archive_response.status_code == 404: + raise EnumerateError(f'Package {package} not found') + if response.status_code != 200 && archive_response.status_code != 200: + raise RuntimeError( + f'Failed to get OPAM versions for {package} with: {response.text}') + + responses = {} + + if response.status_code == 200: + responses.extend(response.json()) + if archive_response.status_code == 200: + responses.extend(archive_response.json()) + + versions = [x["name"] for x in responses] + + self.sort_versions(versions) + return self._get_affected_versions(versions, introduced, fixed, + last_affected, limits) diff --git a/osv/purl_helpers.py b/osv/purl_helpers.py index a44be1b8bb0..02a53a60d6f 100644 --- a/osv/purl_helpers.py +++ b/osv/purl_helpers.py @@ -70,6 +70,8 @@ EcosystemPURL('npm', None), 'NuGet': EcosystemPURL('nuget', None), + 'opam': + EcosystemPURL('opam', None), 'openEuler': EcosystemPURL('rpm', 'openeuler'), 'openSUSE': From c6f9ca7d82a1e90e694a2c74baf3d4e4da4b9914 Mon Sep 17 00:00:00 2001 From: Mehnert Date: Fri, 9 Jan 2026 18:45:32 +0100 Subject: [PATCH 2/4] add OCaml/opam to data.md --- docs/data.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/data.md b/docs/data.md index e74d810cee9..06c4eca585c 100644 --- a/docs/data.md +++ b/docs/data.md @@ -58,6 +58,8 @@ The following ecosystems have vulnerabilities encoded in this format: ([CC0 1.0](https://github.com/haskell/security-advisories/blob/main/LICENSE.txt)) - [Ubuntu](https://github.com/canonical/ubuntu-security-notices) ([CC-BY-SA 4.0](https://github.com/canonical/ubuntu-security-notices/blob/main/LICENSE)) +- [opam (OCaml package manager)](https://github.com/ocaml/security-advisories) + ([CC0 1.0](https://github.com/ocaml/security-advisories/blob/main/LICENSE.txt)) ## Converted data @@ -91,6 +93,7 @@ Between the data served in OSV and the data converted to OSV the following ecosy - Maven - npm - NuGet +- opam (OCaml package manager) - OSS-Fuzz - Packagist - Pub From d187e37c9473ad82be95a18ff84d5cc80c2db7ae Mon Sep 17 00:00:00 2001 From: Mehnert Date: Tue, 13 Jan 2026 12:35:08 +0100 Subject: [PATCH 3/4] fix python code --- osv/ecosystems/opam.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osv/ecosystems/opam.py b/osv/ecosystems/opam.py index c8db6cd8484..dbf4572d30c 100644 --- a/osv/ecosystems/opam.py +++ b/osv/ecosystems/opam.py @@ -29,9 +29,9 @@ def enumerate_versions(self, self._REPO + package, timeout=config.timeout) archive_response = requests.get( self._REPO_ARCHIVE + package, timeout=config.timeout) - if response.status_code == 404 && archive_response.status_code == 404: + if response.status_code == 404 and archive_response.status_code == 404: raise EnumerateError(f'Package {package} not found') - if response.status_code != 200 && archive_response.status_code != 200: + if response.status_code != 200 and archive_response.status_code != 200: raise RuntimeError( f'Failed to get OPAM versions for {package} with: {response.text}') From 624fe665325668a9da6c9c602375c890d424425b Mon Sep 17 00:00:00 2001 From: Rex P <106129829+another-rex@users.noreply.github.com> Date: Wed, 14 Jan 2026 10:16:47 +1100 Subject: [PATCH 4/4] Update osv/ecosystems/opam.py --- osv/ecosystems/opam.py | 1 + 1 file changed, 1 insertion(+) diff --git a/osv/ecosystems/opam.py b/osv/ecosystems/opam.py index dbf4572d30c..4adf27e6f12 100644 --- a/osv/ecosystems/opam.py +++ b/osv/ecosystems/opam.py @@ -4,6 +4,7 @@ from ..third_party.univers.debian import Version as DebianVersion from . import config +from .ecosystems_base import EnumerableEcosystem, EnumerateError class Opam(EnumerableEcosystem): """OPAM packages ecosystem"""