uv-secure


Nameuv-secure JSON
Version 0.12.1 PyPI version JSON
download
home_pageNone
SummaryScan your uv.lock file for dependencies with known vulnerabilities
upload_time2025-07-20 07:37:32
maintainerNone
docs_urlNone
authorOwen Lamont
requires_python>=3.10
licenseNone
keywords uv uv.lock vulnerabilities
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # uv-secure

Scan your uv.lock file for dependencies with known vulnerabilities.

## Scope and Limitations

This tool will scan PyPi dependencies listed in your uv.lock files (or PEP751
pylock.toml files or uv generated requirements.txt files) and check for known
vulnerabilities listed against those packages and versions in the PyPi json API. Since
it is making network requests for each PyPi package this can be a relatively slow tool
to run, and it will only work in test environments with access to the PyPi API.
Currently only packages sourced from PyPi are tested - there's no support for custom
packages or packages stored in private PyPi servers. See roadmap below for my plans for
future enhancements.

I don't intend uv-secure to ever create virtual environments or do dependency
resolution - the plan is to leave that all to uv since it does that so well and just
target lock files and fully pinned and (dependency resolved) requirements.txt files. If
you want a tool that does dependency resolution on requirements.txt files for first
order and unpinned dependencies I recommend using
[pip-audit](https://pypi.org/project/pip-audit/) instead.

## Disclaimer

This tool is still in an alpha phase and although it's unlikely to lose functionality
arguments may get changed with no deprecation warning. I'm still in the process of
refining the command line arguments and configuration behaviour.

## Installation

uv-secure is available on [PyPi](https://pypi.org/project/uv-secure/) and
[conda-forge](https://anaconda.org/conda-forge/uv-secure).

I recommend installing uv-secure as a uv tool, or with pipx, or as a pixi global tool as
it's intended to be used as a CLI tool, and it probably only makes sense to have one
version installed globally.

Installing with uv tool as follows:

```shell
uv tool install uv-secure
```

or with pipx:

```shell
pipx install uv-secure
```

or from conda-forge with pixi:

```shell
pixi global install uv-secure
```

you can optionally install uv-secure as a development dependency in a virtual
environment.

## Optional Dependencies

uv-secure uses highly asynchronous code to request multiple API responses or file opens
concurrently. You can install uvloop on Linux/Mac or winloop on Windows to speed up the
asynchronous event loop (at the expense of debuggability if you want to develop
uv-secure yourself). Also note, winloop is a relatively young package and may give you
some stability issues on particular versions of Python

If you want to install these faster async dependencies with uv do it with the
faster-async extension like this:

```shell
uv tool install uv-secure[faster-async]
```

or with pipx like this:

```shell
pipx install uv-secure[faster-async]
```

With pixi, given conda doesn't support optional dependencies, you can install uv-secure
globally with uvloop or winloop like this:

Mac/Linux:

```shell
pixi global install uv-secure --with uvloop
```

Windows:

```powershell
pixi global install uv-secure --with winloop
```

uv-secure will automatically use uvloop or winloop if it finds them in the same Python
environment as itself.

## Usage

After installation, you can run uv-secure --help to see the options.

```text
>> uv-secure --help

 Usage: run.py [OPTIONS] [FILE_PATHS]...

 Parse uv.lock files, check vulnerabilities, and display summary.

╭─ Arguments ──────────────────────────────────────────────────────────────────────────╮
│   file_paths      [FILE_PATHS]...  Paths to the uv.lock, PEP751 pylock.toml, or uv   │
│                                    generated requirements.txt files or a single      │
│                                    project root level directory (defaults to working │
│                                    directory if not set)                             │
│                                    [default: None]                                   │
╰──────────────────────────────────────────────────────────────────────────────────────╯
╭─ Options ────────────────────────────────────────────────────────────────────────────╮
│ --aliases                                               Flag whether to include      │
│                                                         vulnerability aliases in the │
│                                                         vulnerabilities table        │
│ --desc                                                  Flag whether to include      │
│                                                         vulnerability detailed       │
│                                                         description in the           │
│                                                         vulnerabilities table        │
│ --cache-path                         PATH               Path to the cache directory  │
│                                                         for vulnerability http       │
│                                                         requests                     │
│                                                         [default:                    │
│                                                         (~/.cache/uv-secure)]        │
│ --cache-ttl-seconds                  FLOAT              Time to live in seconds for  │
│                                                         the vulnerability http       │
│                                                         requests cache               │
│                                                         [default: 86400.0]           │
│ --disable-cache                                         Flag whether to disable      │
│                                                         caching for vulnerability    │
│                                                         http requests                │
│ --forbid-yanked                                         Flag whether disallow yanked │
│                                                         package versions from being  │
│                                                         dependencies                 │
│ --max-age-days                       INTEGER            Maximum age threshold for    │
│                                                         packages in days             │
│                                                         [default: None]              │
│ --ignore-vulns                       TEXT               Comma-separated list of      │
│                                                         vulnerability IDs to ignore, │
│                                                         e.g. VULN-123,VULN-456       │
│                                                         [default: None]              │
│ --ignore-pkgs                        PKG:SPEC1|SPEC2|…  Dependency with optional     │
│                                                         version specifiers. Syntax:  │
│                                                         name:spec1|spec2|…  e.g.     │
│                                                         foo:>=1.0,<1.5|==4.5.*       │
│                                                         [default: None]              │
│ --check-direct-dependency-vu…                           Flag whether to only test    │
│                                                         only direct dependencies for │
│                                                         vulnerabilities              │
│ --check-direct-dependency-ma…                           Flag whether to only test    │
│                                                         only direct dependencies for │
│                                                         maintenance issues           │
│ --config                             PATH               Optional path to a           │
│                                                         configuration file           │
│                                                         (uv-secure.toml,             │
│                                                         .uv-secure.toml, or          │
│                                                         pyproject.toml)              │
│                                                         [default: None]              │
│ --version                                               Show the application's       │
│                                                         version                      │
│ --install-completion                                    Install completion for the   │
│                                                         current shell.               │
│ --show-completion                                       Show completion for the      │
│                                                         current shell, to copy it or │
│                                                         customize the installation.  │
│ --help                                                  Show this message and exit.  │
╰──────────────────────────────────────────────────────────────────────────────────────╯
```

```text
>> uv-secure
Checking dependencies for vulnerabilities...
╭────────────────────────────────────────────────────╮
│ No vulnerabilities or maintenance issues detected! │
│ Checked: 160 dependencies                          │
│ All dependencies appear safe!                      │
╰────────────────────────────────────────────────────╯
```

## Configuration

uv-secure can read configuration from a toml file specified with the config option. E.g.

### uv-secure.toml / .uv-secure.toml

```toml
[ignore_packages]
requests = [] # Ignore issues with all versions of the requests package
urllib = [">=1.0, <2.0"] # Ignore issues between version 1.0 and less than 2.0
jinja2 = [">=0.1, <1.0", "~=2.0"] # Ignore issues between version 0.1 and 1.0 or 2.0

[vulnerability_criteria]
ignore_vulnerabilities = ["VULN-123"]
aliases = true # Defaults to false
desc = true # Defaults to false
check_direct_dependencies_only = true # Defaults to false (test transitive dependencies)

[maintainability_criteria]
# max_package_age takes numeric seconds or an ISO8601 duration string
max_package_age = "P1000D" # Defaults to None if not set (no age limit)
forbid_yanked = true # Defaults to false (allow yanked package dependencies) if not set
```

### pyproject.toml

```toml
[tool.uv-secure.ignore_packages]
requests = [] # Ignore issues with all versions of the requests package
urllib = [">=1.0, <2.0"] # Ignore issues between version 1.0 and less than 2.0
jinja2 = [">=0.1, <1.0", "~=2.0"] # Ignore issues between version 0.1 and 1.0 or 2.0

[tool.uv-secure.vulnerability_criteria]
ignore_vulnerabilities = ["VULN-123"]
aliases = true # Defaults to false
desc = true # Defaults to false
check_direct_dependencies_only = true # Defaults to false (test transitive dependencies)

[tool.uv-secure.maintainability_criteria]
# max_package_age takes numeric seconds or an ISO8601 duration string
max_package_age = "P1000D" # Defaults to None (no max age) if not set
forbid_yanked = true # Defaults to false (allow yanked package dependencies) if not set
check_direct_dependencies_only = true # Defaults to false (test transitive dependencies)
```

### File Caching

File caching is enabled by default to speed up subsequent runs of uv-secure. By default,
cache results are saved to:

```shell
~/.cache/uv-secure
```

or on Windows

```powershell
%USERPROFILE%\.cache\uv-secure
```

This can be configured to another location if you wish.

#### Cache Performance on Windows

I'm unsure about other operating systems, but I found on Windows unless I excluded the
cache directory from the _Virus & threat protection settings_ the file caching only made
a minimal performance improvement on subsequent runs (whereas it can speed up subsequent
runs over 50% if you add the cache directory as an exclusion).

### Configuration discovery

If the ignore and config options are left unset uv-secure will search for configuration
files above each uv.lock file and use the deepest found pyproject.toml, uv-secure.toml,
or .uv-secure.toml for the configuration when processing that specific uv.lock file.
uv-secure tries to follow
[Ruff's configuration file discovery strategy](https://docs.astral.sh/ruff/configuration/#config-file-discovery)

Similar to Ruff, pyproject.toml files that don't contain uv-secure configuration are
ignored. Currently, if multiple uv-secure configuration files are defined in the same
directory upstream from a uv.lock file the configurations are used in this precedence
order:

1. .uv-secure.toml
2. uv-secure.toml
3. pyproject.toml (assuming it contains uv-secure configuration)

So .uv-secure.toml files are used first, then uv-secure.toml files, and last
pyproject.toml files with uv-secure config (only if you define all three in the same
directory though - which would be a bit weird - I may make this a warning or error in
future).

Like Ruff, configuration files aren't hierarchically combined, the nearest / highest
precedence configuration is used. If you set a specific configuration file that will
take precedence and hierarchical configuration file discovery is disabled. If you do
specify a configuration options directly, e.g. pass the  --ignore option that will
overwrite the ignore_vulnerabilities setting of all found or manually specified
configuration files.

## Pre-commit Usage

uv-secure can be run as a pre-commit hook by adding this configuration to your
.pre-commit-config.yaml file:

```yaml
  - repo: https://github.com/owenlamont/uv-secure
    rev: 0.12.1
    hooks:
      - id: uv-secure
```

You should run:

```shell
pre-commit autoupdate
```

Or manually check the latest release and update the _rev_ value accordingly.

## Roadmap

Below are some ideas (in no particular order) I have for improving uv-secure:

- Integrate with GitHub / GitLab / BitBucket for additional maintenance metrics
- Add rate limiting on how hard the PyPi json API is hit to query package
  vulnerabilities (this hasn't been a problem yet, but I suspect may be for uv.lock
  files with many dependencies)
- Add support for other lock file formats beyond uv.lock
- Support some of the other output file formats pip-audit does
- Consider adding support for scanning dependencies from the current venv
- Add a severity threshold option for reporting vulnerabilities against
- Add an autofix option for updating package versions with known vulnerabilities if
  there is a more recent fixed version
- Investigate supporting private PyPi repos
- Add translations to support languages beyond English (not sure of the merits of this
  given most vulnerability reports appear to be only in English but happy to take
  feedback on this)

## Running in Development

Running uv-secure as a developer is pretty straight-forward if you have uv installed.
Just check out the repo and from a terminal in the repo root directory run:

```shell
uv sync --dev
```

To create and sync the virtual environment.

You can run the tests with:

```shell
uv run pytest
```

Or run the package entry module directly with:

```shell
uv run src/uv_secure/run.py . --aliases
```

### Debugging

If you want to run and debug uv-secure in an IDE like PyCharm or VSCode select the
virtual environment in the local .venv directory uv would have created after calling
uv sync.

#### PyCharm Warning

With PyCharm debugging relies on pip and setuptools being installed which aren't
installed by default, so I request PyCharm _Install packaging tool_ in the
_Python Interpreter_ settings (I may just add these in future are dev dependencies to
reduce the friction if this causes others too much pain). I have also encountered some
test failures on Windows if you use winloop with setuptools and pip - so you probably do
want to remove winloop if debugging in that environment if you added it.

#### Debugging Async Code

Given uv-secure is often IO bound waiting on API responses or file reads I've tried to
make it as asynchronous as I can. uv-secure also uses uvloop and winloop if installed
which should be more performant than the vanilla asyncio event loop - but they don't
play nice with Python debuggers. If you intend to do debugging I suggest leaving them
out of the virtual environment. By default, winloop or uvloop won't be installed the
repo venv unless you explicitly add them.

## Related Work and Motivation

I created this package as I wanted a dependency vulnerability scanner, but I wasn't
completely happy with the options that were available. I use
[uv](https://docs.astral.sh/uv/) and wanted something that works with uv.lock files but
neither of the main package options I found were as frictionless as I had hoped:

- [pip-audit](https://pypi.org/project/pip-audit/) uv-secure is very much based on doing
  the same vulnerability check that pip-audit does using PyPi's json API. pip-audit
  however only works with requirements.txt so to make it work with uv projects you need
  additional steps to convert your uv.lock file to a requirements.txt then you need to
  run pip-audit with the --no-deps and/or --no-pip options to stop pip-audit trying to
  create a virtual environment from the requirements.txt file. In short, you can use
  pip-audit instead of uv-secure albeit with a bit more friction for uv projects. I hope
  to add extra features beyond what pip-audit does or optimise things better (given the
  more specialised case of only needing to support uv.lock files) in the future.
- [safety](https://pypi.org/project/safety/) also doesn't work with uv.lock file out of
  the box, it does apparently work statically without needing to build a virtual
  environment but it does require you to create an account on the
  [safety site](https://platform.safetycli.com/). They have some limited free account
  but require a paid account to use seriously. If you already have a safety account
  though there is a [uv-audit](https://pypi.org/project/uv-audit/) package that wraps
  safety to support scanning uv.lock files.
- [Python Security PyCharm Plugin](https://plugins.jetbrains.com/plugin/13609-python-security)
  Lastly I was inspired by Anthony Shaw's Python Security plugin - which does CVE
  dependency scanning within PyCharm.

I build uv-secure because I wanted a CLI tool I could run with pre-commit. Statically
analyse the uv.lock file without needing to create a virtual environment, and finally
doesn't require you to create (and pay for) an account with any service.

## Contributing

Please raise issues for any bugs you discover with uv-secure. If practical and not too
sensitive sharing the problem uv.lock file would help me reproduce and fix these issues.

I welcome PRs for minor fixes and documentation tweaks. If you'd like to make more
substantial contributions please reach out by email / social media / or raise an
improvement issue to discuss first to make sure our plans are aligned before creating
any large / time-expensive PRs.

See the [contributing guide](https://github.com/owenlamont/uv-secure/blob/main/CONTRIBUTING.md)
for more details on contributing to uv-secure

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "uv-secure",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.10",
    "maintainer_email": null,
    "keywords": "uv, uv.lock, vulnerabilities",
    "author": "Owen Lamont",
    "author_email": "Owen Lamont <owenrlamont@gmail.com>",
    "download_url": "https://files.pythonhosted.org/packages/e4/da/1550e5722f1917b48695c2308ca5a55ea07a655a0c5c4f9d1e2064ecbec9/uv_secure-0.12.1.tar.gz",
    "platform": null,
    "description": "# uv-secure\n\nScan your uv.lock file for dependencies with known vulnerabilities.\n\n## Scope and Limitations\n\nThis tool will scan PyPi dependencies listed in your uv.lock files (or PEP751\npylock.toml files or uv generated requirements.txt files) and check for known\nvulnerabilities listed against those packages and versions in the PyPi json API. Since\nit is making network requests for each PyPi package this can be a relatively slow tool\nto run, and it will only work in test environments with access to the PyPi API.\nCurrently only packages sourced from PyPi are tested - there's no support for custom\npackages or packages stored in private PyPi servers. See roadmap below for my plans for\nfuture enhancements.\n\nI don't intend uv-secure to ever create virtual environments or do dependency\nresolution - the plan is to leave that all to uv since it does that so well and just\ntarget lock files and fully pinned and (dependency resolved) requirements.txt files. If\nyou want a tool that does dependency resolution on requirements.txt files for first\norder and unpinned dependencies I recommend using\n[pip-audit](https://pypi.org/project/pip-audit/) instead.\n\n## Disclaimer\n\nThis tool is still in an alpha phase and although it's unlikely to lose functionality\narguments may get changed with no deprecation warning. I'm still in the process of\nrefining the command line arguments and configuration behaviour.\n\n## Installation\n\nuv-secure is available on [PyPi](https://pypi.org/project/uv-secure/) and\n[conda-forge](https://anaconda.org/conda-forge/uv-secure).\n\nI recommend installing uv-secure as a uv tool, or with pipx, or as a pixi global tool as\nit's intended to be used as a CLI tool, and it probably only makes sense to have one\nversion installed globally.\n\nInstalling with uv tool as follows:\n\n```shell\nuv tool install uv-secure\n```\n\nor with pipx:\n\n```shell\npipx install uv-secure\n```\n\nor from conda-forge with pixi:\n\n```shell\npixi global install uv-secure\n```\n\nyou can optionally install uv-secure as a development dependency in a virtual\nenvironment.\n\n## Optional Dependencies\n\nuv-secure uses highly asynchronous code to request multiple API responses or file opens\nconcurrently. You can install uvloop on Linux/Mac or winloop on Windows to speed up the\nasynchronous event loop (at the expense of debuggability if you want to develop\nuv-secure yourself). Also note, winloop is a relatively young package and may give you\nsome stability issues on particular versions of Python\n\nIf you want to install these faster async dependencies with uv do it with the\nfaster-async extension like this:\n\n```shell\nuv tool install uv-secure[faster-async]\n```\n\nor with pipx like this:\n\n```shell\npipx install uv-secure[faster-async]\n```\n\nWith pixi, given conda doesn't support optional dependencies, you can install uv-secure\nglobally with uvloop or winloop like this:\n\nMac/Linux:\n\n```shell\npixi global install uv-secure --with uvloop\n```\n\nWindows:\n\n```powershell\npixi global install uv-secure --with winloop\n```\n\nuv-secure will automatically use uvloop or winloop if it finds them in the same Python\nenvironment as itself.\n\n## Usage\n\nAfter installation, you can run uv-secure --help to see the options.\n\n```text\n>> uv-secure --help\n\n Usage: run.py [OPTIONS] [FILE_PATHS]...\n\n Parse uv.lock files, check vulnerabilities, and display summary.\n\n\u256d\u2500 Arguments \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256e\n\u2502   file_paths      [FILE_PATHS]...  Paths to the uv.lock, PEP751 pylock.toml, or uv   \u2502\n\u2502                                    generated requirements.txt files or a single      \u2502\n\u2502                                    project root level directory (defaults to working \u2502\n\u2502                                    directory if not set)                             \u2502\n\u2502                                    [default: None]                                   \u2502\n\u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256f\n\u256d\u2500 Options \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256e\n\u2502 --aliases                                               Flag whether to include      \u2502\n\u2502                                                         vulnerability aliases in the \u2502\n\u2502                                                         vulnerabilities table        \u2502\n\u2502 --desc                                                  Flag whether to include      \u2502\n\u2502                                                         vulnerability detailed       \u2502\n\u2502                                                         description in the           \u2502\n\u2502                                                         vulnerabilities table        \u2502\n\u2502 --cache-path                         PATH               Path to the cache directory  \u2502\n\u2502                                                         for vulnerability http       \u2502\n\u2502                                                         requests                     \u2502\n\u2502                                                         [default:                    \u2502\n\u2502                                                         (~/.cache/uv-secure)]        \u2502\n\u2502 --cache-ttl-seconds                  FLOAT              Time to live in seconds for  \u2502\n\u2502                                                         the vulnerability http       \u2502\n\u2502                                                         requests cache               \u2502\n\u2502                                                         [default: 86400.0]           \u2502\n\u2502 --disable-cache                                         Flag whether to disable      \u2502\n\u2502                                                         caching for vulnerability    \u2502\n\u2502                                                         http requests                \u2502\n\u2502 --forbid-yanked                                         Flag whether disallow yanked \u2502\n\u2502                                                         package versions from being  \u2502\n\u2502                                                         dependencies                 \u2502\n\u2502 --max-age-days                       INTEGER            Maximum age threshold for    \u2502\n\u2502                                                         packages in days             \u2502\n\u2502                                                         [default: None]              \u2502\n\u2502 --ignore-vulns                       TEXT               Comma-separated list of      \u2502\n\u2502                                                         vulnerability IDs to ignore, \u2502\n\u2502                                                         e.g. VULN-123,VULN-456       \u2502\n\u2502                                                         [default: None]              \u2502\n\u2502 --ignore-pkgs                        PKG:SPEC1|SPEC2|\u2026  Dependency with optional     \u2502\n\u2502                                                         version specifiers. Syntax:  \u2502\n\u2502                                                         name:spec1|spec2|\u2026  e.g.     \u2502\n\u2502                                                         foo:>=1.0,<1.5|==4.5.*       \u2502\n\u2502                                                         [default: None]              \u2502\n\u2502 --check-direct-dependency-vu\u2026                           Flag whether to only test    \u2502\n\u2502                                                         only direct dependencies for \u2502\n\u2502                                                         vulnerabilities              \u2502\n\u2502 --check-direct-dependency-ma\u2026                           Flag whether to only test    \u2502\n\u2502                                                         only direct dependencies for \u2502\n\u2502                                                         maintenance issues           \u2502\n\u2502 --config                             PATH               Optional path to a           \u2502\n\u2502                                                         configuration file           \u2502\n\u2502                                                         (uv-secure.toml,             \u2502\n\u2502                                                         .uv-secure.toml, or          \u2502\n\u2502                                                         pyproject.toml)              \u2502\n\u2502                                                         [default: None]              \u2502\n\u2502 --version                                               Show the application's       \u2502\n\u2502                                                         version                      \u2502\n\u2502 --install-completion                                    Install completion for the   \u2502\n\u2502                                                         current shell.               \u2502\n\u2502 --show-completion                                       Show completion for the      \u2502\n\u2502                                                         current shell, to copy it or \u2502\n\u2502                                                         customize the installation.  \u2502\n\u2502 --help                                                  Show this message and exit.  \u2502\n\u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256f\n```\n\n```text\n>> uv-secure\nChecking dependencies for vulnerabilities...\n\u256d\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256e\n\u2502 No vulnerabilities or maintenance issues detected! \u2502\n\u2502 Checked: 160 dependencies                          \u2502\n\u2502 All dependencies appear safe!                      \u2502\n\u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256f\n```\n\n## Configuration\n\nuv-secure can read configuration from a toml file specified with the config option. E.g.\n\n### uv-secure.toml / .uv-secure.toml\n\n```toml\n[ignore_packages]\nrequests = [] # Ignore issues with all versions of the requests package\nurllib = [\">=1.0, <2.0\"] # Ignore issues between version 1.0 and less than 2.0\njinja2 = [\">=0.1, <1.0\", \"~=2.0\"] # Ignore issues between version 0.1 and 1.0 or 2.0\n\n[vulnerability_criteria]\nignore_vulnerabilities = [\"VULN-123\"]\naliases = true # Defaults to false\ndesc = true # Defaults to false\ncheck_direct_dependencies_only = true # Defaults to false (test transitive dependencies)\n\n[maintainability_criteria]\n# max_package_age takes numeric seconds or an ISO8601 duration string\nmax_package_age = \"P1000D\" # Defaults to None if not set (no age limit)\nforbid_yanked = true # Defaults to false (allow yanked package dependencies) if not set\n```\n\n### pyproject.toml\n\n```toml\n[tool.uv-secure.ignore_packages]\nrequests = [] # Ignore issues with all versions of the requests package\nurllib = [\">=1.0, <2.0\"] # Ignore issues between version 1.0 and less than 2.0\njinja2 = [\">=0.1, <1.0\", \"~=2.0\"] # Ignore issues between version 0.1 and 1.0 or 2.0\n\n[tool.uv-secure.vulnerability_criteria]\nignore_vulnerabilities = [\"VULN-123\"]\naliases = true # Defaults to false\ndesc = true # Defaults to false\ncheck_direct_dependencies_only = true # Defaults to false (test transitive dependencies)\n\n[tool.uv-secure.maintainability_criteria]\n# max_package_age takes numeric seconds or an ISO8601 duration string\nmax_package_age = \"P1000D\" # Defaults to None (no max age) if not set\nforbid_yanked = true # Defaults to false (allow yanked package dependencies) if not set\ncheck_direct_dependencies_only = true # Defaults to false (test transitive dependencies)\n```\n\n### File Caching\n\nFile caching is enabled by default to speed up subsequent runs of uv-secure. By default,\ncache results are saved to:\n\n```shell\n~/.cache/uv-secure\n```\n\nor on Windows\n\n```powershell\n%USERPROFILE%\\.cache\\uv-secure\n```\n\nThis can be configured to another location if you wish.\n\n#### Cache Performance on Windows\n\nI'm unsure about other operating systems, but I found on Windows unless I excluded the\ncache directory from the _Virus & threat protection settings_ the file caching only made\na minimal performance improvement on subsequent runs (whereas it can speed up subsequent\nruns over 50% if you add the cache directory as an exclusion).\n\n### Configuration discovery\n\nIf the ignore and config options are left unset uv-secure will search for configuration\nfiles above each uv.lock file and use the deepest found pyproject.toml, uv-secure.toml,\nor .uv-secure.toml for the configuration when processing that specific uv.lock file.\nuv-secure tries to follow\n[Ruff's configuration file discovery strategy](https://docs.astral.sh/ruff/configuration/#config-file-discovery)\n\nSimilar to Ruff, pyproject.toml files that don't contain uv-secure configuration are\nignored. Currently, if multiple uv-secure configuration files are defined in the same\ndirectory upstream from a uv.lock file the configurations are used in this precedence\norder:\n\n1. .uv-secure.toml\n2. uv-secure.toml\n3. pyproject.toml (assuming it contains uv-secure configuration)\n\nSo .uv-secure.toml files are used first, then uv-secure.toml files, and last\npyproject.toml files with uv-secure config (only if you define all three in the same\ndirectory though - which would be a bit weird - I may make this a warning or error in\nfuture).\n\nLike Ruff, configuration files aren't hierarchically combined, the nearest / highest\nprecedence configuration is used. If you set a specific configuration file that will\ntake precedence and hierarchical configuration file discovery is disabled. If you do\nspecify a configuration options directly, e.g. pass the  --ignore option that will\noverwrite the ignore_vulnerabilities setting of all found or manually specified\nconfiguration files.\n\n## Pre-commit Usage\n\nuv-secure can be run as a pre-commit hook by adding this configuration to your\n.pre-commit-config.yaml file:\n\n```yaml\n  - repo: https://github.com/owenlamont/uv-secure\n    rev: 0.12.1\n    hooks:\n      - id: uv-secure\n```\n\nYou should run:\n\n```shell\npre-commit autoupdate\n```\n\nOr manually check the latest release and update the _rev_ value accordingly.\n\n## Roadmap\n\nBelow are some ideas (in no particular order) I have for improving uv-secure:\n\n- Integrate with GitHub / GitLab / BitBucket for additional maintenance metrics\n- Add rate limiting on how hard the PyPi json API is hit to query package\n  vulnerabilities (this hasn't been a problem yet, but I suspect may be for uv.lock\n  files with many dependencies)\n- Add support for other lock file formats beyond uv.lock\n- Support some of the other output file formats pip-audit does\n- Consider adding support for scanning dependencies from the current venv\n- Add a severity threshold option for reporting vulnerabilities against\n- Add an autofix option for updating package versions with known vulnerabilities if\n  there is a more recent fixed version\n- Investigate supporting private PyPi repos\n- Add translations to support languages beyond English (not sure of the merits of this\n  given most vulnerability reports appear to be only in English but happy to take\n  feedback on this)\n\n## Running in Development\n\nRunning uv-secure as a developer is pretty straight-forward if you have uv installed.\nJust check out the repo and from a terminal in the repo root directory run:\n\n```shell\nuv sync --dev\n```\n\nTo create and sync the virtual environment.\n\nYou can run the tests with:\n\n```shell\nuv run pytest\n```\n\nOr run the package entry module directly with:\n\n```shell\nuv run src/uv_secure/run.py . --aliases\n```\n\n### Debugging\n\nIf you want to run and debug uv-secure in an IDE like PyCharm or VSCode select the\nvirtual environment in the local .venv directory uv would have created after calling\nuv sync.\n\n#### PyCharm Warning\n\nWith PyCharm debugging relies on pip and setuptools being installed which aren't\ninstalled by default, so I request PyCharm _Install packaging tool_ in the\n_Python Interpreter_ settings (I may just add these in future are dev dependencies to\nreduce the friction if this causes others too much pain). I have also encountered some\ntest failures on Windows if you use winloop with setuptools and pip - so you probably do\nwant to remove winloop if debugging in that environment if you added it.\n\n#### Debugging Async Code\n\nGiven uv-secure is often IO bound waiting on API responses or file reads I've tried to\nmake it as asynchronous as I can. uv-secure also uses uvloop and winloop if installed\nwhich should be more performant than the vanilla asyncio event loop - but they don't\nplay nice with Python debuggers. If you intend to do debugging I suggest leaving them\nout of the virtual environment. By default, winloop or uvloop won't be installed the\nrepo venv unless you explicitly add them.\n\n## Related Work and Motivation\n\nI created this package as I wanted a dependency vulnerability scanner, but I wasn't\ncompletely happy with the options that were available. I use\n[uv](https://docs.astral.sh/uv/) and wanted something that works with uv.lock files but\nneither of the main package options I found were as frictionless as I had hoped:\n\n- [pip-audit](https://pypi.org/project/pip-audit/) uv-secure is very much based on doing\n  the same vulnerability check that pip-audit does using PyPi's json API. pip-audit\n  however only works with requirements.txt so to make it work with uv projects you need\n  additional steps to convert your uv.lock file to a requirements.txt then you need to\n  run pip-audit with the --no-deps and/or --no-pip options to stop pip-audit trying to\n  create a virtual environment from the requirements.txt file. In short, you can use\n  pip-audit instead of uv-secure albeit with a bit more friction for uv projects. I hope\n  to add extra features beyond what pip-audit does or optimise things better (given the\n  more specialised case of only needing to support uv.lock files) in the future.\n- [safety](https://pypi.org/project/safety/) also doesn't work with uv.lock file out of\n  the box, it does apparently work statically without needing to build a virtual\n  environment but it does require you to create an account on the\n  [safety site](https://platform.safetycli.com/). They have some limited free account\n  but require a paid account to use seriously. If you already have a safety account\n  though there is a [uv-audit](https://pypi.org/project/uv-audit/) package that wraps\n  safety to support scanning uv.lock files.\n- [Python Security PyCharm Plugin](https://plugins.jetbrains.com/plugin/13609-python-security)\n  Lastly I was inspired by Anthony Shaw's Python Security plugin - which does CVE\n  dependency scanning within PyCharm.\n\nI build uv-secure because I wanted a CLI tool I could run with pre-commit. Statically\nanalyse the uv.lock file without needing to create a virtual environment, and finally\ndoesn't require you to create (and pay for) an account with any service.\n\n## Contributing\n\nPlease raise issues for any bugs you discover with uv-secure. If practical and not too\nsensitive sharing the problem uv.lock file would help me reproduce and fix these issues.\n\nI welcome PRs for minor fixes and documentation tweaks. If you'd like to make more\nsubstantial contributions please reach out by email / social media / or raise an\nimprovement issue to discuss first to make sure our plans are aligned before creating\nany large / time-expensive PRs.\n\nSee the [contributing guide](https://github.com/owenlamont/uv-secure/blob/main/CONTRIBUTING.md)\nfor more details on contributing to uv-secure\n",
    "bugtrack_url": null,
    "license": null,
    "summary": "Scan your uv.lock file for dependencies with known vulnerabilities",
    "version": "0.12.1",
    "project_urls": {
        "Releases": "https://github.com/owenlamont/uv-secure/releases",
        "Repository": "https://github.com/owenlamont/uv-secure"
    },
    "split_keywords": [
        "uv",
        " uv.lock",
        " vulnerabilities"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "486f0a10d2c83f134963d219a78fa718db98c3a01e6e630b6c12f7d591d9faf6",
                "md5": "b2880ef5081734cf9af5e2589ac45671",
                "sha256": "5c937a240c1c8e758f2fc81f72a0a4b4519335a3a16f4bd9b040634885dc5088"
            },
            "downloads": -1,
            "filename": "uv_secure-0.12.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "b2880ef5081734cf9af5e2589ac45671",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.10",
            "size": 23451,
            "upload_time": "2025-07-20T07:37:31",
            "upload_time_iso_8601": "2025-07-20T07:37:31.177432Z",
            "url": "https://files.pythonhosted.org/packages/48/6f/0a10d2c83f134963d219a78fa718db98c3a01e6e630b6c12f7d591d9faf6/uv_secure-0.12.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "e4da1550e5722f1917b48695c2308ca5a55ea07a655a0c5c4f9d1e2064ecbec9",
                "md5": "4137ab534e6cecb10e8210dec0c141c4",
                "sha256": "518a83a0aa349944911ea84495a21a66fd37c82b6abd17c40649eca22bfdec7c"
            },
            "downloads": -1,
            "filename": "uv_secure-0.12.1.tar.gz",
            "has_sig": false,
            "md5_digest": "4137ab534e6cecb10e8210dec0c141c4",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.10",
            "size": 19294,
            "upload_time": "2025-07-20T07:37:32",
            "upload_time_iso_8601": "2025-07-20T07:37:32.520929Z",
            "url": "https://files.pythonhosted.org/packages/e4/da/1550e5722f1917b48695c2308ca5a55ea07a655a0c5c4f9d1e2064ecbec9/uv_secure-0.12.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-07-20 07:37:32",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "owenlamont",
    "github_project": "uv-secure",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "uv-secure"
}
        
Elapsed time: 0.46364s