depsdev 0.0.3__tar.gz → 0.0.5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {depsdev-0.0.3 → depsdev-0.0.5}/.pre-commit-config.yaml +3 -3
- depsdev-0.0.5/PKG-INFO +143 -0
- depsdev-0.0.5/README.md +98 -0
- {depsdev-0.0.3 → depsdev-0.0.5}/pyproject.toml +1 -0
- {depsdev-0.0.3 → depsdev-0.0.5}/src/depsdev/__main__.py +64 -16
- {depsdev-0.0.3 → depsdev-0.0.5}/src/depsdev/_version.py +16 -3
- depsdev-0.0.5/src/depsdev/base.py +47 -0
- depsdev-0.0.5/src/depsdev/cli/purl.py +143 -0
- depsdev-0.0.5/src/depsdev/cli/vuln.py +71 -0
- depsdev-0.0.5/src/depsdev/osv.py +195 -0
- depsdev-0.0.5/tests/__init__.py +0 -0
- {depsdev-0.0.3 → depsdev-0.0.5}/tests/scripts_test.py +1 -1
- depsdev-0.0.3/PKG-INFO +0 -72
- depsdev-0.0.3/README.md +0 -28
- {depsdev-0.0.3 → depsdev-0.0.5}/.github/copilot-instructions.md +0 -0
- {depsdev-0.0.3 → depsdev-0.0.5}/.github/workflows/main.yaml +0 -0
- {depsdev-0.0.3 → depsdev-0.0.5}/.gitignore +0 -0
- {depsdev-0.0.3 → depsdev-0.0.5}/.python-version +0 -0
- {depsdev-0.0.3 → depsdev-0.0.5}/LICENSE.txt +0 -0
- {depsdev-0.0.3 → depsdev-0.0.5}/src/depsdev/__init__.py +0 -0
- {depsdev-0.0.3/tests → depsdev-0.0.5/src/depsdev/cli}/__init__.py +0 -0
- {depsdev-0.0.3 → depsdev-0.0.5}/src/depsdev/py.typed +0 -0
- {depsdev-0.0.3 → depsdev-0.0.5}/src/depsdev/v3.py +0 -0
- {depsdev-0.0.3 → depsdev-0.0.5}/src/depsdev/v3alpha.py +0 -0
- {depsdev-0.0.3 → depsdev-0.0.5}/taplo.toml +0 -0
- {depsdev-0.0.3 → depsdev-0.0.5}/tests/main_test.py +0 -0
- {depsdev-0.0.3 → depsdev-0.0.5}/tests/v3_test.py +0 -0
- {depsdev-0.0.3 → depsdev-0.0.5}/tests/v3alpha_test.py +0 -0
@@ -9,7 +9,7 @@ ci:
|
|
9
9
|
- uv-test
|
10
10
|
repos:
|
11
11
|
- repo: https://github.com/astral-sh/uv-pre-commit
|
12
|
-
rev: 0.
|
12
|
+
rev: 0.9.5
|
13
13
|
hooks:
|
14
14
|
- id: uv-lock
|
15
15
|
- id: uv-export
|
@@ -19,7 +19,7 @@ repos:
|
|
19
19
|
- id: taplo-format
|
20
20
|
- id: taplo-lint
|
21
21
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
22
|
-
rev: v0.
|
22
|
+
rev: v0.14.1
|
23
23
|
hooks:
|
24
24
|
- id: ruff-check
|
25
25
|
types_or: [python, pyi, jupyter]
|
@@ -36,7 +36,7 @@ repos:
|
|
36
36
|
- id: name-tests-test
|
37
37
|
- id: requirements-txt-fixer
|
38
38
|
- repo: https://github.com/pre-commit/mirrors-mypy
|
39
|
-
rev: v1.
|
39
|
+
rev: v1.18.2
|
40
40
|
hooks:
|
41
41
|
- id: mypy
|
42
42
|
- repo: local
|
depsdev-0.0.5/PKG-INFO
ADDED
@@ -0,0 +1,143 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: depsdev
|
3
|
+
Version: 0.0.5
|
4
|
+
Summary: Python wrapper for https://deps.dev/ API
|
5
|
+
Project-URL: Documentation, https://github.com/FlavioAmurrioCS/depsdev#readme
|
6
|
+
Project-URL: Issues, https://github.com/FlavioAmurrioCS/depsdev/issues
|
7
|
+
Project-URL: Source, https://github.com/FlavioAmurrioCS/depsdev
|
8
|
+
Author-email: Flavio Amurrio <25621374+FlavioAmurrioCS@users.noreply.github.com>
|
9
|
+
License-Expression: MIT
|
10
|
+
License-File: LICENSE.txt
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
12
|
+
Classifier: Programming Language :: Python
|
13
|
+
Classifier: Programming Language :: Python :: 3.9
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
18
|
+
Classifier: Programming Language :: Python :: 3.14
|
19
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
20
|
+
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
21
|
+
Requires-Python: >=3.9
|
22
|
+
Requires-Dist: httpx
|
23
|
+
Requires-Dist: packageurl-python
|
24
|
+
Provides-Extra: cli
|
25
|
+
Requires-Dist: rich; extra == 'cli'
|
26
|
+
Requires-Dist: typer-slim; extra == 'cli'
|
27
|
+
Provides-Extra: tests
|
28
|
+
Requires-Dist: pytest; extra == 'tests'
|
29
|
+
Requires-Dist: pytest-asyncio; extra == 'tests'
|
30
|
+
Requires-Dist: rich; extra == 'tests'
|
31
|
+
Requires-Dist: tomli; (python_version < '3.11') and extra == 'tests'
|
32
|
+
Requires-Dist: typer-slim; extra == 'tests'
|
33
|
+
Provides-Extra: types
|
34
|
+
Requires-Dist: mypy; extra == 'types'
|
35
|
+
Requires-Dist: pyrefly; extra == 'types'
|
36
|
+
Requires-Dist: pyright[nodejs]; extra == 'types'
|
37
|
+
Requires-Dist: pytest; extra == 'types'
|
38
|
+
Requires-Dist: pytest-asyncio; extra == 'types'
|
39
|
+
Requires-Dist: rich; extra == 'types'
|
40
|
+
Requires-Dist: tomli; (python_version < '3.11') and extra == 'types'
|
41
|
+
Requires-Dist: ty; extra == 'types'
|
42
|
+
Requires-Dist: typer-slim; extra == 'types'
|
43
|
+
Requires-Dist: typing-extensions; extra == 'types'
|
44
|
+
Description-Content-Type: text/markdown
|
45
|
+
|
46
|
+
# depsdev
|
47
|
+
|
48
|
+
[](https://pypi.org/project/depsdev)
|
49
|
+
[](https://pypi.org/project/depsdev)
|
50
|
+
[](https://results.pre-commit.ci/latest/github/FlavioAmurrioCS/depsdev/main)
|
51
|
+
|
52
|
+
-----
|
53
|
+
|
54
|
+
## Table of Contents
|
55
|
+
|
56
|
+
- [depsdev](#depsdev)
|
57
|
+
- [Table of Contents](#table-of-contents)
|
58
|
+
- [Overview](#overview)
|
59
|
+
- [Installation](#installation)
|
60
|
+
- [CLI Usage](#cli-usage)
|
61
|
+
- [Report mode](#report-mode)
|
62
|
+
- [License](#license)
|
63
|
+
|
64
|
+
## Overview
|
65
|
+
|
66
|
+
Thin Python wrapper (async-first) around the public [deps.dev REST API](https://deps.dev) plus an optional Typer-based CLI. Provides straightforward methods mapping closely to the documented endpoints; responses are returned as decoded JSON (dict / list). Alpha endpoints can be enabled via `DEPSDEV_V3_ALPHA=true` and may change without notice.
|
67
|
+
|
68
|
+
## Installation
|
69
|
+
|
70
|
+
```bash
|
71
|
+
pip install depsdev # library only
|
72
|
+
pipx install depsdev[cli] # CLI
|
73
|
+
uv tool install depsdev[cli] # CLI
|
74
|
+
```
|
75
|
+
|
76
|
+
## CLI Usage
|
77
|
+
|
78
|
+
```bash
|
79
|
+
[flavio@Mac ~/dev/github.com/FlavioAmurrioCS/depsdev][main ✗]
|
80
|
+
$ depsdev --help
|
81
|
+
|
82
|
+
Usage: depsdev [OPTIONS] COMMAND [ARGS]...
|
83
|
+
|
84
|
+
╭─ Options ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
|
85
|
+
│ --install-completion [bash|zsh|fish|powershell|pwsh] Install completion for the specified shell. │
|
86
|
+
│ --show-completion [bash|zsh|fish|powershell|pwsh] Show completion for the specified shell, to copy it or customize the installation. │
|
87
|
+
│ --help Show this message and exit. │
|
88
|
+
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
|
89
|
+
╭─ Commands ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
|
90
|
+
│ report Show vulnerabilities for packages in a file. │
|
91
|
+
│ api A CLI tool to interact with the https://docs.deps.dev/api/ │
|
92
|
+
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
|
93
|
+
╭─ Utils ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
|
94
|
+
│ purl Extract package URLs from various formats. │
|
95
|
+
│ vuln Main function to analyze packages for vulnerabilities. │
|
96
|
+
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
|
97
|
+
|
98
|
+
```
|
99
|
+
|
100
|
+
### Report mode
|
101
|
+
|
102
|
+
Parses depedency file and reports the vulnerabilities and the version where it was fixed.
|
103
|
+
|
104
|
+
```bash
|
105
|
+
[flavio@Mac ~/dev/github.com/FlavioAmurrioCS/depsdev][main ✗]
|
106
|
+
$ depsdev report --help
|
107
|
+
|
108
|
+
Usage: depsdev report [OPTIONS] FILENAME
|
109
|
+
|
110
|
+
Show vulnerabilities for packages in a file.
|
111
|
+
|
112
|
+
Example usage:
|
113
|
+
depsdev report requirements.txt
|
114
|
+
depsdev report pom.xml
|
115
|
+
depsdev report Pipfile.lock
|
116
|
+
|
117
|
+
╭─ Arguments ────────────────────────────────────────────────╮
|
118
|
+
│ * filename TEXT [required] │
|
119
|
+
╰────────────────────────────────────────────────────────────╯
|
120
|
+
╭─ Options ──────────────────────────────────────────────────╮
|
121
|
+
│ --help Show this message and exit. │
|
122
|
+
╰────────────────────────────────────────────────────────────╯
|
123
|
+
|
124
|
+
[flavio@Mac ~/dev/github.com/FlavioAmurrioCS/depsdev][main ✗]
|
125
|
+
$ uv export > requirements.txt
|
126
|
+
Resolved 34 packages in 6ms
|
127
|
+
|
128
|
+
[flavio@Mac ~/dev/github.com/FlavioAmurrioCS/depsdev][main ✗]
|
129
|
+
$ depsdev report requirements.txt
|
130
|
+
Analysing 10 packages...
|
131
|
+
Found 1 packages with advisories.
|
132
|
+
pkg:pypi/idna@3.6
|
133
|
+
┏━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
134
|
+
┃ Id ┃ Summary ┃ Fixed ┃
|
135
|
+
┡━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
|
136
|
+
│ GHSA-jjg7-2v4v-x38h │ Internationalized Domain Names in Applications (IDNA) vulnerable to denial of service from specially crafted inputs to idna.encode │ 3.7 │
|
137
|
+
│ PYSEC-2024-60 │ │ 1d365e17e10d72d0b7876316fc7b9… │
|
138
|
+
└─────────────────────┴────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┴────────────────────────────────┘
|
139
|
+
```
|
140
|
+
|
141
|
+
## License
|
142
|
+
|
143
|
+
`depsdev` is distributed under the terms of the [MIT](https://spdx.org/licenses/MIT.html) license.
|
depsdev-0.0.5/README.md
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
# depsdev
|
2
|
+
|
3
|
+
[](https://pypi.org/project/depsdev)
|
4
|
+
[](https://pypi.org/project/depsdev)
|
5
|
+
[](https://results.pre-commit.ci/latest/github/FlavioAmurrioCS/depsdev/main)
|
6
|
+
|
7
|
+
-----
|
8
|
+
|
9
|
+
## Table of Contents
|
10
|
+
|
11
|
+
- [depsdev](#depsdev)
|
12
|
+
- [Table of Contents](#table-of-contents)
|
13
|
+
- [Overview](#overview)
|
14
|
+
- [Installation](#installation)
|
15
|
+
- [CLI Usage](#cli-usage)
|
16
|
+
- [Report mode](#report-mode)
|
17
|
+
- [License](#license)
|
18
|
+
|
19
|
+
## Overview
|
20
|
+
|
21
|
+
Thin Python wrapper (async-first) around the public [deps.dev REST API](https://deps.dev) plus an optional Typer-based CLI. Provides straightforward methods mapping closely to the documented endpoints; responses are returned as decoded JSON (dict / list). Alpha endpoints can be enabled via `DEPSDEV_V3_ALPHA=true` and may change without notice.
|
22
|
+
|
23
|
+
## Installation
|
24
|
+
|
25
|
+
```bash
|
26
|
+
pip install depsdev # library only
|
27
|
+
pipx install depsdev[cli] # CLI
|
28
|
+
uv tool install depsdev[cli] # CLI
|
29
|
+
```
|
30
|
+
|
31
|
+
## CLI Usage
|
32
|
+
|
33
|
+
```bash
|
34
|
+
[flavio@Mac ~/dev/github.com/FlavioAmurrioCS/depsdev][main ✗]
|
35
|
+
$ depsdev --help
|
36
|
+
|
37
|
+
Usage: depsdev [OPTIONS] COMMAND [ARGS]...
|
38
|
+
|
39
|
+
╭─ Options ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
|
40
|
+
│ --install-completion [bash|zsh|fish|powershell|pwsh] Install completion for the specified shell. │
|
41
|
+
│ --show-completion [bash|zsh|fish|powershell|pwsh] Show completion for the specified shell, to copy it or customize the installation. │
|
42
|
+
│ --help Show this message and exit. │
|
43
|
+
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
|
44
|
+
╭─ Commands ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
|
45
|
+
│ report Show vulnerabilities for packages in a file. │
|
46
|
+
│ api A CLI tool to interact with the https://docs.deps.dev/api/ │
|
47
|
+
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
|
48
|
+
╭─ Utils ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
|
49
|
+
│ purl Extract package URLs from various formats. │
|
50
|
+
│ vuln Main function to analyze packages for vulnerabilities. │
|
51
|
+
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
|
52
|
+
|
53
|
+
```
|
54
|
+
|
55
|
+
### Report mode
|
56
|
+
|
57
|
+
Parses depedency file and reports the vulnerabilities and the version where it was fixed.
|
58
|
+
|
59
|
+
```bash
|
60
|
+
[flavio@Mac ~/dev/github.com/FlavioAmurrioCS/depsdev][main ✗]
|
61
|
+
$ depsdev report --help
|
62
|
+
|
63
|
+
Usage: depsdev report [OPTIONS] FILENAME
|
64
|
+
|
65
|
+
Show vulnerabilities for packages in a file.
|
66
|
+
|
67
|
+
Example usage:
|
68
|
+
depsdev report requirements.txt
|
69
|
+
depsdev report pom.xml
|
70
|
+
depsdev report Pipfile.lock
|
71
|
+
|
72
|
+
╭─ Arguments ────────────────────────────────────────────────╮
|
73
|
+
│ * filename TEXT [required] │
|
74
|
+
╰────────────────────────────────────────────────────────────╯
|
75
|
+
╭─ Options ──────────────────────────────────────────────────╮
|
76
|
+
│ --help Show this message and exit. │
|
77
|
+
╰────────────────────────────────────────────────────────────╯
|
78
|
+
|
79
|
+
[flavio@Mac ~/dev/github.com/FlavioAmurrioCS/depsdev][main ✗]
|
80
|
+
$ uv export > requirements.txt
|
81
|
+
Resolved 34 packages in 6ms
|
82
|
+
|
83
|
+
[flavio@Mac ~/dev/github.com/FlavioAmurrioCS/depsdev][main ✗]
|
84
|
+
$ depsdev report requirements.txt
|
85
|
+
Analysing 10 packages...
|
86
|
+
Found 1 packages with advisories.
|
87
|
+
pkg:pypi/idna@3.6
|
88
|
+
┏━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
89
|
+
┃ Id ┃ Summary ┃ Fixed ┃
|
90
|
+
┡━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
|
91
|
+
│ GHSA-jjg7-2v4v-x38h │ Internationalized Domain Names in Applications (IDNA) vulnerable to denial of service from specially crafted inputs to idna.encode │ 3.7 │
|
92
|
+
│ PYSEC-2024-60 │ │ 1d365e17e10d72d0b7876316fc7b9… │
|
93
|
+
└─────────────────────┴────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┴────────────────────────────────┘
|
94
|
+
```
|
95
|
+
|
96
|
+
## License
|
97
|
+
|
98
|
+
`depsdev` is distributed under the terms of the [MIT](https://spdx.org/licenses/MIT.html) license.
|
@@ -1,6 +1,21 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
import logging
|
4
|
+
import sys
|
5
|
+
|
6
|
+
from depsdev.cli.purl import get_extractor
|
7
|
+
from depsdev.cli.vuln import main_helper
|
8
|
+
|
9
|
+
try:
|
10
|
+
import typer
|
11
|
+
except ImportError:
|
12
|
+
msg = (
|
13
|
+
"The 'cli' optional dependency is not installed. "
|
14
|
+
"Please install it with 'pip install depsdev[cli]'."
|
15
|
+
)
|
16
|
+
print(msg, file=sys.stderr)
|
17
|
+
raise SystemExit(1) from None
|
18
|
+
|
4
19
|
import os
|
5
20
|
from textwrap import dedent
|
6
21
|
from typing import TYPE_CHECKING
|
@@ -14,7 +29,6 @@ if TYPE_CHECKING:
|
|
14
29
|
P = ParamSpec("P")
|
15
30
|
R = TypeVar("R")
|
16
31
|
|
17
|
-
|
18
32
|
logging.basicConfig(
|
19
33
|
level=logging.ERROR,
|
20
34
|
format="[%(asctime)s] [%(levelname)-7s] [%(name)s] %(message)s",
|
@@ -38,7 +52,9 @@ def to_sync() -> Callable[[Callable[P, R]], Callable[P, R]]:
|
|
38
52
|
|
39
53
|
from rich import print_json
|
40
54
|
|
41
|
-
|
55
|
+
result: object = asyncio.run(func(*args, **kwargs)) # type: ignore[arg-type]
|
56
|
+
if result is not None:
|
57
|
+
print_json(data=result)
|
42
58
|
except Exception:
|
43
59
|
logger.exception("An error occurred while executing the command.")
|
44
60
|
raise SystemExit(1) from None
|
@@ -50,25 +66,14 @@ def to_sync() -> Callable[[Callable[P, R]], Callable[P, R]]:
|
|
50
66
|
return decorator
|
51
67
|
|
52
68
|
|
53
|
-
def
|
69
|
+
def create_app() -> typer.Typer:
|
54
70
|
"""
|
55
71
|
Main entry point for the CLI.
|
56
72
|
"""
|
57
|
-
|
58
|
-
try:
|
59
|
-
import typer
|
60
|
-
except ImportError:
|
61
|
-
msg = (
|
62
|
-
"The 'cli' optional dependency is not installed. "
|
63
|
-
"Please install it with 'pip install depsdev[cli]'."
|
64
|
-
)
|
65
|
-
logger.error(msg) # noqa: TRY400
|
66
|
-
raise SystemExit(1) from None
|
67
|
-
|
68
73
|
alpha = os.environ.get("DEPSDEV_V3_ALPHA", "false").lower() in ("true", "1", "yes")
|
69
74
|
|
70
75
|
app = typer.Typer(
|
71
|
-
name="
|
76
|
+
name="api",
|
72
77
|
no_args_is_help=True,
|
73
78
|
rich_markup_mode="rich",
|
74
79
|
help=dedent(
|
@@ -125,7 +130,50 @@ def main() -> None:
|
|
125
130
|
app.command(rich_help_panel="v3alpha")(to_sync()(client_v3_alpha.purl_lookup_batch))
|
126
131
|
app.command(rich_help_panel="v3alpha")(to_sync()(client_v3_alpha.query_container_images))
|
127
132
|
|
128
|
-
return app
|
133
|
+
return app
|
134
|
+
|
135
|
+
|
136
|
+
main = typer.Typer(
|
137
|
+
name="depsdev",
|
138
|
+
no_args_is_help=True,
|
139
|
+
rich_markup_mode="rich",
|
140
|
+
)
|
141
|
+
|
142
|
+
main.add_typer(
|
143
|
+
create_app(),
|
144
|
+
name="api",
|
145
|
+
)
|
146
|
+
|
147
|
+
|
148
|
+
@main.command(name="purl", rich_help_panel="Utils")
|
149
|
+
def purl(filename: str) -> None:
|
150
|
+
"""
|
151
|
+
Extract package URLs from various formats.
|
152
|
+
"""
|
153
|
+
extractor = get_extractor(filename)
|
154
|
+
|
155
|
+
for purl in extractor.extract(filename):
|
156
|
+
print(purl)
|
157
|
+
|
158
|
+
|
159
|
+
main.command(name="vuln", rich_help_panel="Utils")(to_sync()(main_helper))
|
160
|
+
|
161
|
+
|
162
|
+
@main.command()
|
163
|
+
@to_sync()
|
164
|
+
async def report(filename: str) -> None:
|
165
|
+
"""
|
166
|
+
Show vulnerabilities for packages in a file.
|
167
|
+
|
168
|
+
Example usage:
|
169
|
+
depsdev report requirements.txt
|
170
|
+
depsdev report pom.xml
|
171
|
+
depsdev report Pipfile.lock
|
172
|
+
"""
|
173
|
+
filename = os.path.abspath(filename)
|
174
|
+
extractor = get_extractor(filename)
|
175
|
+
packages = extractor.extract(filename)
|
176
|
+
await main_helper([x.to_string() for x in packages])
|
129
177
|
|
130
178
|
|
131
179
|
if __name__ == "__main__":
|
@@ -1,7 +1,14 @@
|
|
1
1
|
# file generated by setuptools-scm
|
2
2
|
# don't change, don't track in version control
|
3
3
|
|
4
|
-
__all__ = [
|
4
|
+
__all__ = [
|
5
|
+
"__version__",
|
6
|
+
"__version_tuple__",
|
7
|
+
"version",
|
8
|
+
"version_tuple",
|
9
|
+
"__commit_id__",
|
10
|
+
"commit_id",
|
11
|
+
]
|
5
12
|
|
6
13
|
TYPE_CHECKING = False
|
7
14
|
if TYPE_CHECKING:
|
@@ -9,13 +16,19 @@ if TYPE_CHECKING:
|
|
9
16
|
from typing import Union
|
10
17
|
|
11
18
|
VERSION_TUPLE = Tuple[Union[int, str], ...]
|
19
|
+
COMMIT_ID = Union[str, None]
|
12
20
|
else:
|
13
21
|
VERSION_TUPLE = object
|
22
|
+
COMMIT_ID = object
|
14
23
|
|
15
24
|
version: str
|
16
25
|
__version__: str
|
17
26
|
__version_tuple__: VERSION_TUPLE
|
18
27
|
version_tuple: VERSION_TUPLE
|
28
|
+
commit_id: COMMIT_ID
|
29
|
+
__commit_id__: COMMIT_ID
|
19
30
|
|
20
|
-
__version__ = version = '0.0.
|
21
|
-
__version_tuple__ = version_tuple = (0, 0,
|
31
|
+
__version__ = version = '0.0.5'
|
32
|
+
__version_tuple__ = version_tuple = (0, 0, 5)
|
33
|
+
|
34
|
+
__commit_id__ = commit_id = None
|
@@ -0,0 +1,47 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
import logging
|
4
|
+
from dataclasses import dataclass
|
5
|
+
from dataclasses import field
|
6
|
+
from typing import TYPE_CHECKING
|
7
|
+
from urllib.parse import quote
|
8
|
+
|
9
|
+
import httpx
|
10
|
+
|
11
|
+
if TYPE_CHECKING:
|
12
|
+
from httpx._types import QueryParamTypes
|
13
|
+
from typing_extensions import Literal
|
14
|
+
|
15
|
+
from depsdev.v3 import Incomplete
|
16
|
+
|
17
|
+
logger = logging.getLogger(__name__)
|
18
|
+
|
19
|
+
|
20
|
+
@dataclass
|
21
|
+
class BaseClient:
|
22
|
+
base_url: str
|
23
|
+
timeout: float = 5.0
|
24
|
+
client: httpx.AsyncClient = field(init=False, repr=False)
|
25
|
+
|
26
|
+
def __post_init__(self) -> None:
|
27
|
+
self.client = httpx.AsyncClient(base_url=self.base_url, timeout=self.timeout)
|
28
|
+
|
29
|
+
async def _requests(
|
30
|
+
self,
|
31
|
+
url: str = "",
|
32
|
+
method: Literal["GET", "POST"] = "GET",
|
33
|
+
params: QueryParamTypes | None = None,
|
34
|
+
json: object | None = None,
|
35
|
+
) -> Incomplete:
|
36
|
+
logger.info(locals())
|
37
|
+
response = await self.client.request(method=method, url=url, params=params, json=json)
|
38
|
+
if not response.is_success:
|
39
|
+
logger.error(
|
40
|
+
"Request failed with status code %s: %s", response.status_code, response.text
|
41
|
+
)
|
42
|
+
response.raise_for_status()
|
43
|
+
return response.json()
|
44
|
+
|
45
|
+
@staticmethod
|
46
|
+
def url_escape(string: str) -> str:
|
47
|
+
return quote(string, safe="")
|
@@ -0,0 +1,143 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
import itertools
|
4
|
+
import json
|
5
|
+
import logging
|
6
|
+
import os
|
7
|
+
import subprocess
|
8
|
+
import sys
|
9
|
+
from typing import TYPE_CHECKING
|
10
|
+
|
11
|
+
from packageurl import PackageURL
|
12
|
+
|
13
|
+
if TYPE_CHECKING:
|
14
|
+
from collections.abc import Iterable
|
15
|
+
|
16
|
+
logger = logging.getLogger(__name__)
|
17
|
+
|
18
|
+
|
19
|
+
class MavenExtractor:
|
20
|
+
@classmethod
|
21
|
+
def extract(cls, filename: str) -> Iterable[PackageURL]:
|
22
|
+
yield from (cls.parse_single_line(x) for x in cls._clean(cls._get_source(filename)))
|
23
|
+
|
24
|
+
@staticmethod
|
25
|
+
def _get_source(filename: str) -> Iterable[str]:
|
26
|
+
"""
|
27
|
+
Read lines from stdin or a file.
|
28
|
+
"""
|
29
|
+
if not filename.endswith("pom.xml"):
|
30
|
+
logger.error("Invalid POM file: %s. It should end with 'pom.xml'.", filename)
|
31
|
+
raise SystemExit(1)
|
32
|
+
result = subprocess.run(
|
33
|
+
["mvn", "dependency:tree"], # noqa: S607
|
34
|
+
check=False,
|
35
|
+
capture_output=True,
|
36
|
+
text=True,
|
37
|
+
cwd=os.path.dirname(os.path.abspath(filename)),
|
38
|
+
)
|
39
|
+
if result.returncode != 0:
|
40
|
+
print(result.stderr, file=sys.stderr)
|
41
|
+
raise SystemExit(1)
|
42
|
+
yield from result.stdout.splitlines()
|
43
|
+
|
44
|
+
@staticmethod
|
45
|
+
def parse_single_line(line: str) -> PackageURL:
|
46
|
+
"""
|
47
|
+
Parse a single line of Maven dependency output and return a PackageURL object.
|
48
|
+
"""
|
49
|
+
package, *rest = line.split()
|
50
|
+
_is_optional = bool(rest)
|
51
|
+
group, artifact, _type, version, *_classifier = package.split(":")
|
52
|
+
return PackageURL(
|
53
|
+
type="maven",
|
54
|
+
namespace=group,
|
55
|
+
name=artifact,
|
56
|
+
version=version,
|
57
|
+
qualifiers=None,
|
58
|
+
subpath=None,
|
59
|
+
)
|
60
|
+
|
61
|
+
@staticmethod
|
62
|
+
def _clean(lines: Iterable[str]) -> Iterable[str]:
|
63
|
+
stage1 = (x.rstrip() for x in lines if x.strip())
|
64
|
+
stage2 = itertools.dropwhile(lambda x: not x.startswith("[INFO] --- "), stage1)
|
65
|
+
stage3 = itertools.takewhile(
|
66
|
+
lambda x: not x.startswith(
|
67
|
+
"[INFO] ------------------------------------------------------------------------"
|
68
|
+
),
|
69
|
+
stage2,
|
70
|
+
)
|
71
|
+
stage4 = itertools.islice(stage3, 1, None) # Skip the first line
|
72
|
+
stage5 = (x[7:] for x in stage4)
|
73
|
+
yield from (x.split("- ", maxsplit=1)[-1] for x in stage5)
|
74
|
+
|
75
|
+
|
76
|
+
class PipfileLockExtractor:
|
77
|
+
@classmethod
|
78
|
+
def extract(cls, filename: str) -> Iterable[PackageURL]:
|
79
|
+
"""
|
80
|
+
Extracts package URLs from a Pipfile.lock.
|
81
|
+
"""
|
82
|
+
if not filename.endswith("Pipfile.lock"):
|
83
|
+
logger.error("Invalid Pipfile.lock: %s. It should end with 'Pipfile.lock'.", filename)
|
84
|
+
raise SystemExit(1)
|
85
|
+
with open(filename) as f:
|
86
|
+
data = json.load(f)
|
87
|
+
for package_name, package_info in data.get("default", {}).items():
|
88
|
+
version: str | None = package_info.get("version")
|
89
|
+
if version:
|
90
|
+
yield PackageURL(
|
91
|
+
type="pypi",
|
92
|
+
namespace=None,
|
93
|
+
name=package_name,
|
94
|
+
version=version[2:],
|
95
|
+
qualifiers=None,
|
96
|
+
subpath=None,
|
97
|
+
)
|
98
|
+
else:
|
99
|
+
logger.warning("Package %s has no version specified.", package_name)
|
100
|
+
|
101
|
+
|
102
|
+
class RequirementsExtractor:
|
103
|
+
@classmethod
|
104
|
+
def extract(cls, filename: str) -> Iterable[PackageURL]:
|
105
|
+
"""
|
106
|
+
Extracts package URLs from a requirements.txt file.
|
107
|
+
"""
|
108
|
+
if not filename.endswith("requirements.txt"):
|
109
|
+
logger.error(
|
110
|
+
"Invalid requirements file: %s. It should end with 'requirements.txt'.", filename
|
111
|
+
)
|
112
|
+
raise SystemExit(1)
|
113
|
+
with open(filename) as f:
|
114
|
+
for line in f:
|
115
|
+
_line = line.strip()
|
116
|
+
if not _line or _line.startswith(("#", "-r ", "-i ")):
|
117
|
+
continue
|
118
|
+
parts = _line.split(";")[0].split("==")
|
119
|
+
if len(parts) == 2: # noqa: PLR2004
|
120
|
+
name, version = parts
|
121
|
+
version = version.strip(" \\")
|
122
|
+
yield PackageURL(
|
123
|
+
type="pypi",
|
124
|
+
namespace=None,
|
125
|
+
name=name,
|
126
|
+
version=version,
|
127
|
+
qualifiers=None,
|
128
|
+
subpath=None,
|
129
|
+
)
|
130
|
+
|
131
|
+
|
132
|
+
def get_extractor(filename: str) -> MavenExtractor | PipfileLockExtractor | RequirementsExtractor:
|
133
|
+
"""
|
134
|
+
Returns the appropriate extractor based on the file extension.
|
135
|
+
"""
|
136
|
+
if filename.endswith("pom.xml"):
|
137
|
+
return MavenExtractor()
|
138
|
+
if filename.endswith("Pipfile.lock"):
|
139
|
+
return PipfileLockExtractor()
|
140
|
+
if filename.endswith("requirements.txt"):
|
141
|
+
return RequirementsExtractor()
|
142
|
+
logger.error("Unsupported file format: %s", filename)
|
143
|
+
raise SystemExit(1)
|
@@ -0,0 +1,71 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
import asyncio
|
4
|
+
import itertools
|
5
|
+
import logging
|
6
|
+
from typing import TYPE_CHECKING
|
7
|
+
|
8
|
+
from rich.console import Console
|
9
|
+
from rich.table import Table
|
10
|
+
|
11
|
+
from depsdev.osv import OSVClientV1
|
12
|
+
|
13
|
+
if TYPE_CHECKING:
|
14
|
+
from depsdev.osv import OSVVulnerability
|
15
|
+
from depsdev.osv import V1Query
|
16
|
+
|
17
|
+
logger = logging.getLogger(__name__)
|
18
|
+
|
19
|
+
|
20
|
+
def get_version_fix(vuln: OSVVulnerability) -> str | None:
|
21
|
+
for affected in vuln.get("affected", []):
|
22
|
+
for _range in affected.get("ranges", []):
|
23
|
+
for event in _range.get("events", []):
|
24
|
+
if "fixed" in event:
|
25
|
+
return event["fixed"]
|
26
|
+
return None
|
27
|
+
|
28
|
+
|
29
|
+
async def get_vulns(purls: list[str], osv_client: OSVClientV1) -> dict[str, list[OSVVulnerability]]:
|
30
|
+
queries: list[V1Query] = [
|
31
|
+
{
|
32
|
+
"package": {"purl": purl},
|
33
|
+
}
|
34
|
+
for purl in purls
|
35
|
+
]
|
36
|
+
result = await osv_client.querybatch({"queries": queries})
|
37
|
+
r = {k: [x["id"] for x in v["vulns"]] for k, v in zip(purls, result["results"]) if v}
|
38
|
+
all_result = await asyncio.gather(
|
39
|
+
*[osv_client.get_vuln(vuln_id) for vuln_id in itertools.chain.from_iterable(r.values())]
|
40
|
+
)
|
41
|
+
look_up = {vuln["id"]: vuln for vuln in all_result}
|
42
|
+
return {purl: [look_up[vuln_id] for vuln_id in vuln_ids] for purl, vuln_ids in r.items()}
|
43
|
+
|
44
|
+
|
45
|
+
async def main_helper(packages: list[str]) -> int:
|
46
|
+
"""Main function to analyze packages for vulnerabilities."""
|
47
|
+
|
48
|
+
console = Console()
|
49
|
+
|
50
|
+
console.print(f"Analysing {len(packages)} packages...")
|
51
|
+
|
52
|
+
osv_client = OSVClientV1()
|
53
|
+
|
54
|
+
results = await get_vulns(packages, osv_client)
|
55
|
+
console.print(f"Found {len(results)} packages with advisories.")
|
56
|
+
|
57
|
+
for purl, advisories in results.items():
|
58
|
+
table = Table(title=purl)
|
59
|
+
|
60
|
+
table.add_column("Id")
|
61
|
+
table.add_column("Summary", style="cyan", no_wrap=True)
|
62
|
+
table.add_column("Fixed", style="magenta")
|
63
|
+
|
64
|
+
for vuln in advisories:
|
65
|
+
table.add_row(
|
66
|
+
f"[link=https://github.com/advisories/{vuln['id']}]{vuln['id']}[/link]",
|
67
|
+
vuln.get("summary"),
|
68
|
+
get_version_fix(vuln) or "unknown",
|
69
|
+
)
|
70
|
+
console.print(table)
|
71
|
+
return 0
|
@@ -0,0 +1,195 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
import logging
|
4
|
+
from dataclasses import dataclass
|
5
|
+
from typing import TYPE_CHECKING
|
6
|
+
|
7
|
+
from depsdev.base import BaseClient
|
8
|
+
|
9
|
+
if TYPE_CHECKING:
|
10
|
+
from typing import Any
|
11
|
+
from typing import Literal
|
12
|
+
|
13
|
+
from typing_extensions import NotRequired
|
14
|
+
from typing_extensions import TypedDict
|
15
|
+
|
16
|
+
class OSVEvent(TypedDict):
|
17
|
+
introduced: NotRequired[str]
|
18
|
+
fixed: NotRequired[str]
|
19
|
+
limit: NotRequired[str]
|
20
|
+
lastAffected: NotRequired[str]
|
21
|
+
|
22
|
+
class OSVRange(TypedDict):
|
23
|
+
type: NotRequired[
|
24
|
+
Literal[
|
25
|
+
"UNSPECIFIED",
|
26
|
+
"GIT",
|
27
|
+
"SEMVER",
|
28
|
+
"ECOSYSTEM",
|
29
|
+
]
|
30
|
+
]
|
31
|
+
repo: NotRequired[str]
|
32
|
+
events: NotRequired[list[OSVEvent]]
|
33
|
+
|
34
|
+
class OSVPackage(TypedDict):
|
35
|
+
name: NotRequired[str]
|
36
|
+
ecosystem: NotRequired[str]
|
37
|
+
purl: NotRequired[str]
|
38
|
+
|
39
|
+
class OSVCredit(TypedDict):
|
40
|
+
name: NotRequired[str]
|
41
|
+
contact: NotRequired[list[str]]
|
42
|
+
type: NotRequired[
|
43
|
+
Literal[
|
44
|
+
"UNSPECIFIED",
|
45
|
+
"OTHER",
|
46
|
+
"FINDER",
|
47
|
+
"REPORTER",
|
48
|
+
"ANALYST",
|
49
|
+
"COORDINATOR",
|
50
|
+
"REMEDIATION_DEVELOPER",
|
51
|
+
"REMEDIATION_REVIEWER",
|
52
|
+
"REMEDIATION_VERIFIER",
|
53
|
+
"TOOL",
|
54
|
+
"SPONSOR",
|
55
|
+
]
|
56
|
+
]
|
57
|
+
|
58
|
+
class OSVSeverity(TypedDict):
|
59
|
+
type: NotRequired[
|
60
|
+
Literal[
|
61
|
+
"UNSPECIFIED",
|
62
|
+
"CVSS_V4",
|
63
|
+
"CVSS_V3",
|
64
|
+
"CVSS_V2",
|
65
|
+
]
|
66
|
+
]
|
67
|
+
score: NotRequired[str]
|
68
|
+
|
69
|
+
class OSVReference(TypedDict):
|
70
|
+
type: NotRequired[
|
71
|
+
Literal[
|
72
|
+
"NONE",
|
73
|
+
"WEB",
|
74
|
+
"ADVISORY",
|
75
|
+
"REPORT",
|
76
|
+
"FIX",
|
77
|
+
"PACKAGE",
|
78
|
+
"ARTICLE",
|
79
|
+
"EVIDENCE",
|
80
|
+
]
|
81
|
+
]
|
82
|
+
url: NotRequired[str]
|
83
|
+
|
84
|
+
class OSVAffected(TypedDict):
|
85
|
+
package: NotRequired[OSVPackage]
|
86
|
+
ranges: NotRequired[list[OSVRange]]
|
87
|
+
versions: NotRequired[list[str]]
|
88
|
+
ecosystemSpecific: NotRequired[dict[str, Any]]
|
89
|
+
databaseSpecific: NotRequired[dict[str, Any]]
|
90
|
+
severity: NotRequired[list[OSVSeverity]]
|
91
|
+
|
92
|
+
class OSVVulnerability(TypedDict):
|
93
|
+
id: str
|
94
|
+
summary: str
|
95
|
+
schemaVersion: NotRequired[str]
|
96
|
+
published: NotRequired[str]
|
97
|
+
modified: NotRequired[str]
|
98
|
+
withdrawn: NotRequired[str]
|
99
|
+
aliases: NotRequired[list[str]]
|
100
|
+
related: NotRequired[list[str]]
|
101
|
+
details: NotRequired[str]
|
102
|
+
affected: NotRequired[list[OSVAffected]]
|
103
|
+
references: NotRequired[list[OSVReference]]
|
104
|
+
databaseSpecific: NotRequired[dict[str, Any]]
|
105
|
+
severity: NotRequired[list[OSVSeverity]]
|
106
|
+
credits: NotRequired[list[OSVCredit]]
|
107
|
+
|
108
|
+
class V1VulnerabilityList(TypedDict):
|
109
|
+
vulns: NotRequired[list[OSVVulnerability]]
|
110
|
+
nextPageToken: NotRequired[str]
|
111
|
+
|
112
|
+
class V1Query(TypedDict):
|
113
|
+
commit: NotRequired[str]
|
114
|
+
version: NotRequired[str]
|
115
|
+
package: NotRequired[OSVPackage]
|
116
|
+
page_token: NotRequired[str]
|
117
|
+
|
118
|
+
#########################################
|
119
|
+
|
120
|
+
class V1Batchquery(TypedDict):
|
121
|
+
queries: list[V1Query]
|
122
|
+
|
123
|
+
class QueryBatchResult(TypedDict):
|
124
|
+
vulns: list[dict[Literal["id", "modified"], str]]
|
125
|
+
next_page_token: NotRequired[str]
|
126
|
+
|
127
|
+
class QueryBatchResponse(TypedDict):
|
128
|
+
results: list[QueryBatchResult]
|
129
|
+
|
130
|
+
|
131
|
+
logger = logging.getLogger(__name__)
|
132
|
+
|
133
|
+
|
134
|
+
@dataclass
|
135
|
+
class OSVClientV1(BaseClient):
|
136
|
+
base_url: str = "https://api.osv.dev"
|
137
|
+
|
138
|
+
async def query(self, query: V1Query) -> V1VulnerabilityList:
|
139
|
+
"""
|
140
|
+
Lists vulnerabilities for given package and version. May also be queried by commit hash.
|
141
|
+
|
142
|
+
POST /v1/query
|
143
|
+
"""
|
144
|
+
return await self._requests(method="POST", url="/v1/query", json=query) # type:ignore[return-value]
|
145
|
+
|
146
|
+
async def querybatch(self, query: V1Batchquery) -> QueryBatchResponse:
|
147
|
+
"""
|
148
|
+
Query for multiple packages (by either package and version or git commit hash) at once. Returns vulnerability ids and modified field only. The response ordering will be guaranteed to match the input.
|
149
|
+
|
150
|
+
POST /v1/querybatc
|
151
|
+
""" # noqa: E501
|
152
|
+
return await self._requests(method="POST", url="/v1/querybatch", json=query) # type:ignore[return-value]
|
153
|
+
|
154
|
+
async def get_vuln(self, vuln_id: str) -> OSVVulnerability:
|
155
|
+
"""
|
156
|
+
Returns vulnerability information for a given vulnerability id.
|
157
|
+
|
158
|
+
GET /v1/vulns/{id}
|
159
|
+
"""
|
160
|
+
return await self._requests(method="GET", url=f"/v1/vulns/{self.url_escape(vuln_id)}") # type:ignore[return-value]
|
161
|
+
|
162
|
+
# async def import_findings(self) -> Incomplete:
|
163
|
+
# """
|
164
|
+
# Something like this:
|
165
|
+
# """
|
166
|
+
# return await self._requests(method="GET", url="/v1experimental/importfindings")
|
167
|
+
|
168
|
+
# async def determine_version(self) -> Incomplete:
|
169
|
+
# """
|
170
|
+
# Something like this:
|
171
|
+
# """
|
172
|
+
# return await self._requests(method="POST", url="/v1experimental/determineversion")
|
173
|
+
|
174
|
+
|
175
|
+
if __name__ == "__main__":
|
176
|
+
logging.basicConfig(level=logging.INFO)
|
177
|
+
client = OSVClientV1()
|
178
|
+
import asyncio
|
179
|
+
import json
|
180
|
+
|
181
|
+
query: V1Query = {
|
182
|
+
"package": {"name": "jinja2", "ecosystem": "PyPI"},
|
183
|
+
"version": "2.4.1",
|
184
|
+
}
|
185
|
+
loop = asyncio.get_event_loop()
|
186
|
+
a = client.query(query)
|
187
|
+
# a = client.get_vuln("GHSA-3mc7-4q67-w48m")
|
188
|
+
# # {"name": "org.yaml:snakeyaml", "version": "1.19", "system": "MAVEN"}
|
189
|
+
# a = client.query(
|
190
|
+
# {"package": {"name": "org.yaml:snakeyaml", "ecosystem": "MAVEN"}, "version": "1.19"}
|
191
|
+
# )
|
192
|
+
a = client.query({"package": {"purl": "pkg:maven/org.yaml/snakeyaml@1.19"}})
|
193
|
+
|
194
|
+
result = loop.run_until_complete(a)
|
195
|
+
print(json.dumps(result)) # For demonstration purposes, print the result
|
File without changes
|
@@ -26,7 +26,7 @@ def entrypoints() -> Generator[tuple[str, str], None, None]:
|
|
26
26
|
|
27
27
|
@pytest.mark.parametrize("pair", entrypoints())
|
28
28
|
def test_help(pair: tuple[str, str]) -> None:
|
29
|
-
k,
|
29
|
+
k, _v = pair
|
30
30
|
result = subprocess.run([k, "--help"], check=False, capture_output=True, text=True) # noqa: S603
|
31
31
|
if result.returncode != 0:
|
32
32
|
logger.error(result.stderr)
|
depsdev-0.0.3/PKG-INFO
DELETED
@@ -1,72 +0,0 @@
|
|
1
|
-
Metadata-Version: 2.4
|
2
|
-
Name: depsdev
|
3
|
-
Version: 0.0.3
|
4
|
-
Summary: Python wrapper for https://deps.dev/ API
|
5
|
-
Project-URL: Documentation, https://github.com/FlavioAmurrioCS/depsdev#readme
|
6
|
-
Project-URL: Issues, https://github.com/FlavioAmurrioCS/depsdev/issues
|
7
|
-
Project-URL: Source, https://github.com/FlavioAmurrioCS/depsdev
|
8
|
-
Author-email: Flavio Amurrio <25621374+FlavioAmurrioCS@users.noreply.github.com>
|
9
|
-
License-Expression: MIT
|
10
|
-
License-File: LICENSE.txt
|
11
|
-
Classifier: Development Status :: 4 - Beta
|
12
|
-
Classifier: Programming Language :: Python
|
13
|
-
Classifier: Programming Language :: Python :: 3.9
|
14
|
-
Classifier: Programming Language :: Python :: 3.10
|
15
|
-
Classifier: Programming Language :: Python :: 3.11
|
16
|
-
Classifier: Programming Language :: Python :: 3.12
|
17
|
-
Classifier: Programming Language :: Python :: 3.13
|
18
|
-
Classifier: Programming Language :: Python :: 3.14
|
19
|
-
Classifier: Programming Language :: Python :: Implementation :: CPython
|
20
|
-
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
21
|
-
Requires-Python: >=3.9
|
22
|
-
Requires-Dist: httpx
|
23
|
-
Provides-Extra: cli
|
24
|
-
Requires-Dist: rich; extra == 'cli'
|
25
|
-
Requires-Dist: typer-slim; extra == 'cli'
|
26
|
-
Provides-Extra: tests
|
27
|
-
Requires-Dist: pytest; extra == 'tests'
|
28
|
-
Requires-Dist: pytest-asyncio; extra == 'tests'
|
29
|
-
Requires-Dist: rich; extra == 'tests'
|
30
|
-
Requires-Dist: tomli; (python_version < '3.11') and extra == 'tests'
|
31
|
-
Requires-Dist: typer-slim; extra == 'tests'
|
32
|
-
Provides-Extra: types
|
33
|
-
Requires-Dist: mypy; extra == 'types'
|
34
|
-
Requires-Dist: pyrefly; extra == 'types'
|
35
|
-
Requires-Dist: pyright[nodejs]; extra == 'types'
|
36
|
-
Requires-Dist: pytest; extra == 'types'
|
37
|
-
Requires-Dist: pytest-asyncio; extra == 'types'
|
38
|
-
Requires-Dist: rich; extra == 'types'
|
39
|
-
Requires-Dist: tomli; (python_version < '3.11') and extra == 'types'
|
40
|
-
Requires-Dist: ty; extra == 'types'
|
41
|
-
Requires-Dist: typer-slim; extra == 'types'
|
42
|
-
Requires-Dist: typing-extensions; extra == 'types'
|
43
|
-
Description-Content-Type: text/markdown
|
44
|
-
|
45
|
-
# depsdev
|
46
|
-
|
47
|
-
[](https://pypi.org/project/depsdev)
|
48
|
-
[](https://pypi.org/project/depsdev)
|
49
|
-
[](https://results.pre-commit.ci/latest/github/FlavioAmurrioCS/depsdev/main)
|
50
|
-
|
51
|
-
-----
|
52
|
-
|
53
|
-
## Table of Contents
|
54
|
-
|
55
|
-
- [Overview](#overview)
|
56
|
-
- [Installation](#installation)
|
57
|
-
- [License](#license)
|
58
|
-
|
59
|
-
## Overview
|
60
|
-
|
61
|
-
Thin Python wrapper (async-first) around the public [deps.dev REST API](https://deps.dev) plus an optional Typer-based CLI. Provides straightforward methods mapping closely to the documented endpoints; responses are returned as decoded JSON (dict / list). Alpha endpoints can be enabled via `DEPSDEV_V3_ALPHA=true` and may change without notice.
|
62
|
-
|
63
|
-
## Installation
|
64
|
-
|
65
|
-
```bash
|
66
|
-
pip install depsdev # library only
|
67
|
-
pip install depsdev[cli] # library + CLI
|
68
|
-
```
|
69
|
-
|
70
|
-
## License
|
71
|
-
|
72
|
-
`depsdev` is distributed under the terms of the [MIT](https://spdx.org/licenses/MIT.html) license.
|
depsdev-0.0.3/README.md
DELETED
@@ -1,28 +0,0 @@
|
|
1
|
-
# depsdev
|
2
|
-
|
3
|
-
[](https://pypi.org/project/depsdev)
|
4
|
-
[](https://pypi.org/project/depsdev)
|
5
|
-
[](https://results.pre-commit.ci/latest/github/FlavioAmurrioCS/depsdev/main)
|
6
|
-
|
7
|
-
-----
|
8
|
-
|
9
|
-
## Table of Contents
|
10
|
-
|
11
|
-
- [Overview](#overview)
|
12
|
-
- [Installation](#installation)
|
13
|
-
- [License](#license)
|
14
|
-
|
15
|
-
## Overview
|
16
|
-
|
17
|
-
Thin Python wrapper (async-first) around the public [deps.dev REST API](https://deps.dev) plus an optional Typer-based CLI. Provides straightforward methods mapping closely to the documented endpoints; responses are returned as decoded JSON (dict / list). Alpha endpoints can be enabled via `DEPSDEV_V3_ALPHA=true` and may change without notice.
|
18
|
-
|
19
|
-
## Installation
|
20
|
-
|
21
|
-
```bash
|
22
|
-
pip install depsdev # library only
|
23
|
-
pip install depsdev[cli] # library + CLI
|
24
|
-
```
|
25
|
-
|
26
|
-
## License
|
27
|
-
|
28
|
-
`depsdev` is distributed under the terms of the [MIT](https://spdx.org/licenses/MIT.html) license.
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|