osvpy
Scan container images for vulnerabilities and license incompatibilities.
Built with osvscanner. In-process, no external dependencies.
Supports Python 3.13+ on Linux, WSL, or macOS 13+.
Installation
python -m pip install osvpy
# or
uv add osvpy
Scan images
import asyncio
import osvpy
batch = await osvpy.scan("ubuntu:latest", "python:3.12-slim", workers=2)
for image in batch.images:
if not image.complete:
for diagnostic in image.diagnostics:
print(image.requested, diagnostic.code, diagnostic.message)
continue
for finding in image.findings:
package = finding.occurrence.package
print(
image.requested,
package.name,
package.version,
finding.vulnerability.id,
tuple(finding.fix_evidence.versions),
finding.fix_evidence.status,
)
scan() returns a BatchResult with one image result per input, in input order.
Repeated inputs have separate image results. Calling scan() without images
raises ValueError. The examples below use await inside an async function
or notebook.
Scan options
Keyword options apply to every image in the call.
| Option | Default | Purpose |
|---|---|---|
workers |
None (auto) |
Maximum number of images scanned concurrently; a positive integer or None for automatic selection. |
all_packages |
False |
Include packages without vulnerability or license findings. |
languages |
None |
Select language families or individual package formats. |
allowed_licenses |
None |
Evaluate packages against an SPDX license allowlist. |
auth |
None |
Supply registry credentials with RegistryAuth. |
platform |
None (linux/amd64) |
Select the image platform, such as "linux/arm64". |
Private registries and platforms
batch = await osvpy.scan(
"registry.example.com/team/app:latest",
auth=osvpy.RegistryAuth("reader", "password"),
platform="linux/arm64",
all_packages=True,
)
print(batch.images[0].status)
Registry references accept tags or digests. Supply credentials through
RegistryAuth; Docker credential helpers are not used.
Concurrency and cancellation
Use workers to limit concurrency within a batch. Separate calls can run
concurrently, and completed results can be read from multiple threads.
Concurrency limits apply to each call separately. None selects the usable CPU
count bounded between two and four, then capped at the number of input images.
If the CPU count is unavailable, the automatic limit is two before the image
count cap. Set workers=1 for serial scanning; zero and negative values raise
ValueError.
Set a deadline with asyncio.timeout() or asyncio.wait_for():
import asyncio
async with asyncio.timeout(30):
batch = await osvpy.scan("debian:12-slim")
Cancel an active scan with task.cancel(). Cancellation raises
asyncio.CancelledError after the scan stops; it does not return a partial batch.
Timeouts raise TimeoutError and may take longer than the requested deadline
while the scan stops. Repeated cancellation and asyncio.TaskGroup are supported.
Language coverage
Combine families with |, or select individual formats such as PYTHON_UV:
batch = await osvpy.scan(
"python:3.12-slim",
languages=osvpy.LanguageSelection.PYTHON | osvpy.LanguageSelection.JAVA,
)
Family selections include supported manifests and lockfiles. Individual format
names combine the family and suffix, such as JAVA_MAVEN.
| Family | Format suffixes |
|---|---|
| CPP | CONAN |
| DART | PUBSPEC |
| DOTNET | PROJECT, DEPS, CENTRAL_PACKAGES, PACKAGES_CONFIG, PACKAGES_LOCK |
| ELIXIR | MIX |
| GO | BINARY, MODULES |
| HASKELL | CABAL, STACK |
| JAVA | ARCHIVE, GRADLE_LOCK, GRADLE_VERIFICATION, MAVEN |
| JAVASCRIPT | INSTALLED, NPM, PNPM, YARN, BUN |
| PHP | COMPOSER |
| PYTHON | INSTALLED, REQUIREMENTS, POETRY, PIPFILE, PDM, PYLOCK, UV |
| R | RENV |
| RUBY | GEMFILE |
| RUST | BINARY, CARGO |
| SWIFT | PACKAGE_RESOLVED |
NoneorLanguageSelection.INSTALLED: installed Python and JavaScript packages, Java archives, and Go and Rust binaries.LanguageSelection.ALL: every format listed above.LanguageSelection.NONE: OS packages only.
OS package scanning remains enabled with every language selection. Standalone source directories, lockfiles, and SBOM files are not accepted as scan inputs.
Read results
Access fields directly, such as package.name or image.status.
| Object | Data and relationships |
|---|---|
batch |
images, packages, vulnerabilities, advisory_sources, findings, complete, errors |
image |
requested, os, status, diagnostics, complete, packages, occurrences, vulnerable_packages, noncompliant_packages, vulnerabilities, findings |
package |
name, version, ecosystem, commit, os_package_name, purl, present_images, vulnerable_images, noncompliant_images, affected_images, findings |
vulnerability |
id, aliases, affected_images, findings |
advisory_source |
id, aliases, summary, severities, references, modified, published, withdrawn, affected_images, findings |
occurrence |
image, package, context, license_assessment, findings |
finding |
occurrence, vulnerability, advisory_source, assessment, fix_evidence |
An occurrence describes a package in a particular image and location. Its
context includes the path, source type, layer digest, and dependency groups.
Package affected_images combines vulnerability-affected and license-noncompliant
images; present_images includes every image reporting that package.
Vulnerabilities group related advisory identifiers, preferring a CVE identifier when available. Individual advisories provide their own summaries, severity information, references, and dates.
Fix evidence
finding.fix_evidence.versions contains reported package-specific, non-Git fix
versions. When version ordering is supported, fixes at or below the installed
version are excluded.
finding.fix_evidence.status |
Meaning |
|---|---|
reported |
Applicable fix versions were reported. |
no_reported_fix |
No applicable explicit fix version was reported. |
unknown |
Fix applicability or version ordering could not be determined. |
Unknown ordering preserves reported version strings. An empty collection does not establish that no fix exists. Reported fixes are not upgrade recommendations or a guarantee that later versions are unaffected.
Collections and equality
Collections support iteration, len(), negative indexing, and slicing. Slices
return tuples. Use tuple(values) to collect all items into a tuple.
Results are read-only and cannot be pickled. References to the same record within a batch compare equal and have the same hash. Records from separate scans compare unequal; compare their fields when checking for matching contents. A package, finding, or collection remains usable after its original batch variable is deleted.
License policies
batch = await osvpy.scan("python:3.12-slim", allowed_licenses={"MIT", "Apache-2.0"})
for occurrence in batch.images[0].occurrences:
assessment = occurrence.license_assessment
print(occurrence.package.name, assessment.status, tuple(assessment.violations))
allowed_licenses=None disables license evaluation. An empty collection allows
no licenses. Policies support SPDX expressions. assessment.policy is None
when evaluation was not requested, or an empty sequence for an empty allowlist.
License assessment statuses are not_evaluated, compliant, noncompliant,
and unknown. Packages can have license violations without vulnerabilities.
Failures and diagnostics
An image download or scan failure produces a failed image result; remaining
inputs are still scanned. batch.complete is false if any image failed.
for image_index, diagnostic in batch.errors:
print(batch.images[image_index].requested)
print(diagnostic.code, diagnostic.message)
Error codes include registry_authentication, image_not_found, invalid_image,
and scan_error. Failed images represent unknown results.
Successful images may also contain diagnostics in image.diagnostics.
Batch-level failures raise osvpy.NativeLibraryError and abort the batch.
Library exceptions derive from osvpy.OSVError.
Comparison
Features available out of the box when integrating with Python:
| Feature | osvpy | OSV-Scanner CLI |
|---|---|---|
| Container vulnerability and license scanning | ✅ | ✅ |
| Source directory, lockfile, and SBOM inputs | ❌ | ✅ |
| Typed Python results | ✅ | ❌ Parse JSON yourself |
| Cross-image result relationships | ✅ | ❌ Build relationships yourself |
| HTML and SARIF reports | ❌ | ✅ |
| In-process scanning, no separate executable | ✅ | ❌ Install scanner separately |
| Async Python API with cancellation | ✅ | ❌ Write subprocess handling |
| Batch scanning | ✅ | ❌ Write batch orchestration |
Building distributions
Source builds require Go (see go/go.mod), Git, and a C compiler. uv build
builds a source archive and then a wheel from that archive.
Linux wheels need repairing for PyPI:
uv build
uvx --with patchelf auditwheel repair dist/*.whl --wheel-dir wheelhouse
uv publish --dry-run dist/*.tar.gz wheelhouse/*.whl
uv publish dist/*.tar.gz wheelhouse/*.whl
Publish the repaired wheel from wheelhouse. Its minimum glibc version depends
on the build environment; use a manylinux container to target older Linux
systems. On macOS, publish the wheel in dist directly.
Metadata
Release files for osvpy 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| osvpy-0.3.0.tar.gz | 335.5 kB | Without provenance | Details for osvpy-0.3.0.tar.gz |
Built distributions (wheels)
| File | Actions Reset | |||
|---|---|---|---|---|
| osvpy-0.3.0-cp315-cp315-manylinux_2_34_x86_64.whl | CPython 3.15 | CPython 3.15 | Linux glibc 2.34+ x86-64 | Details for osvpy-0.3.0-cp315-cp315-manylinux_2_34_x86_64.whl |
| osvpy-0.3.0-cp314-cp314t-manylinux_2_34_x86_64.whl | CPython 3.14 | CPython 3.14 free-threading | Linux glibc 2.34+ x86-64 | Details for osvpy-0.3.0-cp314-cp314t-manylinux_2_34_x86_64.whl |
| osvpy-0.3.0-cp314-cp314-manylinux_2_34_x86_64.whl | CPython 3.14 | CPython 3.14 | Linux glibc 2.34+ x86-64 | Details for osvpy-0.3.0-cp314-cp314-manylinux_2_34_x86_64.whl |
| osvpy-0.3.0-cp313-cp313-manylinux_2_34_x86_64.whl | CPython 3.13 | CPython 3.13 | Linux glibc 2.34+ x86-64 | Details for osvpy-0.3.0-cp313-cp313-manylinux_2_34_x86_64.whl |
Total release size: 73.9 MB
Release files / osvpy-0.3.0.tar.gz
| Download URL | osvpy-0.3.0.tar.gz |
|---|---|
| Size | 335.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
48f55316d7343968d3d18d01851198bfc609cc1c84fdd0dcd489f0204597fc26
|
|
BLAKE2b-256 checksum How to use checksums |
d07de760388f5927eaf5f4472a3f1f8f5b483b31a8519fc89eb78e2cfa21cf9f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.13.5 {"installer":{"name":"uv","version":"0.13.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / osvpy-0.3.0-cp315-cp315-manylinux_2_34_x86_64.whl
| Download URL | osvpy-0.3.0-cp315-cp315-manylinux_2_34_x86_64.whl |
|---|---|
| Size | 18.4 MB |
| Tags | CPython 3.15 Linux glibc 2.34+ x86-64 |
|
SHA-256 checksum How to use checksums |
e49db0bfa0a3e6085df24f39b034e97780de09908018baead8538d707bd8c7fc
|
|
BLAKE2b-256 checksum How to use checksums |
b5792bd4664c46f35f2240cba5cb67c3d67fb1d62d23a4e2b67e0de3bc6a0f1e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.13.5 {"installer":{"name":"uv","version":"0.13.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / osvpy-0.3.0-cp314-cp314t-manylinux_2_34_x86_64.whl
| Download URL | osvpy-0.3.0-cp314-cp314t-manylinux_2_34_x86_64.whl |
|---|---|
| Size | 18.4 MB |
| Tags | CPython 3.14 CPython 3.14 free-threading Linux glibc 2.34+ x86-64 |
|
SHA-256 checksum How to use checksums |
814d06902cb57252dea66e76bad9a1b2c6fa471095b8bae9b33b9174308c69f8
|
|
BLAKE2b-256 checksum How to use checksums |
052678d3fb13af235f555d336d7500996af0d34ca9500e175c30a881d7ac467f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.13.5 {"installer":{"name":"uv","version":"0.13.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / osvpy-0.3.0-cp314-cp314-manylinux_2_34_x86_64.whl
| Download URL | osvpy-0.3.0-cp314-cp314-manylinux_2_34_x86_64.whl |
|---|---|
| Size | 18.4 MB |
| Tags | CPython 3.14 Linux glibc 2.34+ x86-64 |
|
SHA-256 checksum How to use checksums |
5d1392a8a374fda0dcc44b7c3e2d696e4ad151847f18db476c1df3a33c9dc51f
|
|
BLAKE2b-256 checksum How to use checksums |
87cc46bf8b90bc6937a6189aac894a4e86ec507a768d03e0efa8869f8fbaff72
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.13.5 {"installer":{"name":"uv","version":"0.13.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / osvpy-0.3.0-cp313-cp313-manylinux_2_34_x86_64.whl
| Download URL | osvpy-0.3.0-cp313-cp313-manylinux_2_34_x86_64.whl |
|---|---|
| Size | 18.4 MB |
| Tags | CPython 3.13 Linux glibc 2.34+ x86-64 |
|
SHA-256 checksum How to use checksums |
d9c010ea601d3adccef3d56ffcf12888dd3cd7f04b4ebd8537dfde89237adfb8
|
|
BLAKE2b-256 checksum How to use checksums |
35b2b68be82807d63890fbc00b4ab944911244400fd01e0df0e57355f1298a13
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.13.5 {"installer":{"name":"uv","version":"0.13.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Security for osvpy 0.3.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.