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 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..4adf27e6f12 --- /dev/null +++ b/osv/ecosystems/opam.py @@ -0,0 +1,50 @@ +"""OPAM ecosystem helper.""" +import requests +import json + +from ..third_party.univers.debian import Version as DebianVersion +from . import config +from .ecosystems_base import EnumerableEcosystem, EnumerateError + +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 and archive_response.status_code == 404: + raise EnumerateError(f'Package {package} not found') + if response.status_code != 200 and 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':