forceupdate 0.1.0__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.
- forceupdate-0.1.0/.gitignore +12 -0
- forceupdate-0.1.0/LICENSE +21 -0
- forceupdate-0.1.0/PKG-INFO +79 -0
- forceupdate-0.1.0/README.md +43 -0
- forceupdate-0.1.0/pyproject.toml +80 -0
- forceupdate-0.1.0/src/forceupdate/__init__.py +9 -0
- forceupdate-0.1.0/src/forceupdate/__main__.py +5 -0
- forceupdate-0.1.0/src/forceupdate/advisories/__init__.py +30 -0
- forceupdate-0.1.0/src/forceupdate/advisories/cvss.py +95 -0
- forceupdate-0.1.0/src/forceupdate/advisories/osv.py +584 -0
- forceupdate-0.1.0/src/forceupdate/checks/__init__.py +49 -0
- forceupdate-0.1.0/src/forceupdate/checks/base.py +98 -0
- forceupdate-0.1.0/src/forceupdate/checks/deprecated.py +115 -0
- forceupdate-0.1.0/src/forceupdate/checks/outdated.py +183 -0
- forceupdate-0.1.0/src/forceupdate/checks/priority.py +82 -0
- forceupdate-0.1.0/src/forceupdate/checks/vulns.py +201 -0
- forceupdate-0.1.0/src/forceupdate/cli.py +309 -0
- forceupdate-0.1.0/src/forceupdate/detect/__init__.py +5 -0
- forceupdate-0.1.0/src/forceupdate/detect/languages.py +266 -0
- forceupdate-0.1.0/src/forceupdate/detect/manifests.py +478 -0
- forceupdate-0.1.0/src/forceupdate/engine.py +313 -0
- forceupdate-0.1.0/src/forceupdate/models.py +510 -0
- forceupdate-0.1.0/src/forceupdate/net/__init__.py +20 -0
- forceupdate-0.1.0/src/forceupdate/net/cache.py +217 -0
- forceupdate-0.1.0/src/forceupdate/net/http.py +270 -0
- forceupdate-0.1.0/src/forceupdate/parsers/__init__.py +43 -0
- forceupdate-0.1.0/src/forceupdate/parsers/base.py +22 -0
- forceupdate-0.1.0/src/forceupdate/parsers/json_spans.py +123 -0
- forceupdate-0.1.0/src/forceupdate/parsers/lockfiles.py +231 -0
- forceupdate-0.1.0/src/forceupdate/parsers/npm.py +1257 -0
- forceupdate-0.1.0/src/forceupdate/parsers/python.py +1421 -0
- forceupdate-0.1.0/src/forceupdate/parsers/toml_spans.py +297 -0
- forceupdate-0.1.0/src/forceupdate/registries/__init__.py +52 -0
- forceupdate-0.1.0/src/forceupdate/registries/base.py +294 -0
- forceupdate-0.1.0/src/forceupdate/registries/npm.py +153 -0
- forceupdate-0.1.0/src/forceupdate/registries/pypi.py +242 -0
- forceupdate-0.1.0/src/forceupdate/report/__init__.py +359 -0
- forceupdate-0.1.0/src/forceupdate/report/json.py +34 -0
- forceupdate-0.1.0/src/forceupdate/report/markdown.py +169 -0
- forceupdate-0.1.0/src/forceupdate/report/terminal.py +376 -0
- forceupdate-0.1.0/src/forceupdate/sources/__init__.py +1 -0
- forceupdate-0.1.0/src/forceupdate/sources/base.py +45 -0
- forceupdate-0.1.0/src/forceupdate/sources/local.py +183 -0
- forceupdate-0.1.0/src/forceupdate/update/__init__.py +8 -0
- forceupdate-0.1.0/src/forceupdate/update/constraints.py +317 -0
- forceupdate-0.1.0/src/forceupdate/update/planner.py +531 -0
- forceupdate-0.1.0/src/forceupdate/versions/__init__.py +40 -0
- forceupdate-0.1.0/src/forceupdate/versions/base.py +229 -0
- forceupdate-0.1.0/src/forceupdate/versions/npm.py +432 -0
- forceupdate-0.1.0/src/forceupdate/versions/pypi.py +220 -0
- forceupdate-0.1.0/tests/conftest.py +187 -0
- forceupdate-0.1.0/tests/fixtures/npm/@hapi__joi.json +1 -0
- forceupdate-0.1.0/tests/fixtures/npm/colors.json +1 -0
- forceupdate-0.1.0/tests/fixtures/npm/crossenv.json +1 -0
- forceupdate-0.1.0/tests/fixtures/npm/left-pad.json +1 -0
- forceupdate-0.1.0/tests/fixtures/npm/lodash.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/queries.json +321 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/GHSA-29mw-wpgm-hmr9.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/GHSA-29vq-49wr-vm6x.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/GHSA-2g68-c3qc-8985.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/GHSA-35jh-r3h4-6jhm.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/GHSA-462w-v97r-4m45.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/GHSA-562c-5r94-xh97.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/GHSA-5wv5-4vpf-pj6m.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/GHSA-652x-xj99-gmcc.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/GHSA-68rp-wp8r-4726.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/GHSA-87hc-h4r5-73f7.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/GHSA-9hjg-9r4m-mvj7.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/GHSA-9wx4-h78v-vm56.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/GHSA-9x64-5r7x-2q53.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/GHSA-c2m4-w5hm-vqjw.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/GHSA-cfj3-7x9c-4p3h.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/GHSA-cpwx-vrp4-4pq7.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/GHSA-f23m-r3pf-42rh.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/GHSA-f9vj-2wh5-fj8j.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/GHSA-g3rq-g295-4j3m.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/GHSA-g6x2-hccm-hh4m.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/GHSA-gc5v-m9x4-r6x2.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/GHSA-gq9m-qvpx-68hc.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/GHSA-h5c8-rqwp-cp95.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/GHSA-h75v-3vvj-5mfj.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/GHSA-hgf8-39gv-g3f2.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/GHSA-j544-7q9p-6xp8.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/GHSA-m2qf-hxjv-5gpq.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/GHSA-mh6f-8j2x-4483.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/GHSA-p6mc-m468-83gw.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/GHSA-pjwm-rvh2-c87w.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/GHSA-px8h-6qxv-m22q.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/GHSA-q2x7-8rv6-6q7h.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/GHSA-r5fr-rjxr-66jc.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/GHSA-x84v-xcm2-53pg.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/GHSA-xg9f-g7g7-2323.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/GHSA-xxjr-mmjv-4gpg.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/MAL-2025-20690.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/PYSEC-2014-13.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/PYSEC-2014-14.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/PYSEC-2015-17.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/PYSEC-2018-28.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/PYSEC-2018-66.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/PYSEC-2019-140.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/PYSEC-2019-179.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/PYSEC-2019-217.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/PYSEC-2021-66.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/PYSEC-2022-203.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/PYSEC-2023-221.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/PYSEC-2023-57.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/PYSEC-2023-58.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/PYSEC-2023-62.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/PYSEC-2026-1065.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/PYSEC-2026-1471.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/PYSEC-2026-1473.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/PYSEC-2026-1474.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/PYSEC-2026-1475.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/PYSEC-2026-1872.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/PYSEC-2026-1873.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/PYSEC-2026-2043.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/PYSEC-2026-2044.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/PYSEC-2026-2045.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/PYSEC-2026-2046.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/PYSEC-2026-2151.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/PYSEC-2026-2275.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/PYSEC-2026-2320.json +1 -0
- forceupdate-0.1.0/tests/fixtures/osv/vulns/PYSEC-2026-4312.json +1 -0
- forceupdate-0.1.0/tests/fixtures/pypi/aioredis.json +1 -0
- forceupdate-0.1.0/tests/fixtures/pypi/flask.json +1 -0
- forceupdate-0.1.0/tests/fixtures/pypi/jinja2.json +1 -0
- forceupdate-0.1.0/tests/fixtures/pypi/requests.json +1 -0
- forceupdate-0.1.0/tests/fixtures/pypi/werkzeug.json +1 -0
- forceupdate-0.1.0/tests/fixtures/record.py +160 -0
- forceupdate-0.1.0/tests/projects/README.md +29 -0
- forceupdate-0.1.0/tests/projects/npm/package-lock.json +264 -0
- forceupdate-0.1.0/tests/projects/npm/package.json +25 -0
- forceupdate-0.1.0/tests/projects/npm/vendor/local-lib/package.json +7 -0
- forceupdate-0.1.0/tests/projects/npm-workspace/package-lock.json +165 -0
- forceupdate-0.1.0/tests/projects/npm-workspace/package.json +13 -0
- forceupdate-0.1.0/tests/projects/npm-workspace/packages/a/package.json +8 -0
- forceupdate-0.1.0/tests/projects/npm-workspace/packages/b/package.json +8 -0
- forceupdate-0.1.0/tests/projects/npm-workspace/tools/script/package.json +7 -0
- forceupdate-0.1.0/tests/projects/pip/constraints.txt +2 -0
- forceupdate-0.1.0/tests/projects/pip/requirements-dev.txt +4 -0
- forceupdate-0.1.0/tests/projects/pip/requirements.txt +11 -0
- forceupdate-0.1.0/tests/projects/pip-tools/requirements-dev.in +2 -0
- forceupdate-0.1.0/tests/projects/pip-tools/requirements-dev.txt +18 -0
- forceupdate-0.1.0/tests/projects/pip-tools/requirements.in +3 -0
- forceupdate-0.1.0/tests/projects/pip-tools/requirements.txt +33 -0
- forceupdate-0.1.0/tests/projects/pipenv/Pipfile +14 -0
- forceupdate-0.1.0/tests/projects/pipenv/Pipfile.lock +490 -0
- forceupdate-0.1.0/tests/projects/pnpm-catalog/package.json +8 -0
- forceupdate-0.1.0/tests/projects/pnpm-catalog/packages/app/package.json +8 -0
- forceupdate-0.1.0/tests/projects/pnpm-catalog/pnpm-lock.yaml +67 -0
- forceupdate-0.1.0/tests/projects/pnpm-catalog/pnpm-workspace.yaml +10 -0
- forceupdate-0.1.0/tests/projects/pnpm9/package.json +16 -0
- forceupdate-0.1.0/tests/projects/pnpm9/packages/app/package.json +9 -0
- forceupdate-0.1.0/tests/projects/pnpm9/packages/excluded/package.json +7 -0
- forceupdate-0.1.0/tests/projects/pnpm9/packages/lib/package.json +10 -0
- forceupdate-0.1.0/tests/projects/pnpm9/pnpm-lock.yaml +175 -0
- forceupdate-0.1.0/tests/projects/pnpm9/pnpm-workspace.yaml +3 -0
- forceupdate-0.1.0/tests/projects/poetry/poetry.lock +405 -0
- forceupdate-0.1.0/tests/projects/poetry/pyproject.toml +21 -0
- forceupdate-0.1.0/tests/projects/setuptools/pyproject.toml +3 -0
- forceupdate-0.1.0/tests/projects/setuptools/setup.cfg +16 -0
- forceupdate-0.1.0/tests/projects/setuptools/setup.py +3 -0
- forceupdate-0.1.0/tests/projects/uv/packages/legacy/pyproject.toml +5 -0
- forceupdate-0.1.0/tests/projects/uv/packages/lib/pyproject.toml +9 -0
- forceupdate-0.1.0/tests/projects/uv/pyproject.toml +25 -0
- forceupdate-0.1.0/tests/projects/uv/tools/script/pyproject.toml +5 -0
- forceupdate-0.1.0/tests/projects/uv/uv.lock +222 -0
- forceupdate-0.1.0/tests/projects/vulnerable/package-lock.json +21 -0
- forceupdate-0.1.0/tests/projects/vulnerable/package.json +8 -0
- forceupdate-0.1.0/tests/projects/vulnerable/requirements.in +2 -0
- forceupdate-0.1.0/tests/projects/vulnerable/requirements.txt +14 -0
- forceupdate-0.1.0/tests/projects/yarn1/package.json +25 -0
- forceupdate-0.1.0/tests/projects/yarn1/vendor/local-lib/package.json +7 -0
- forceupdate-0.1.0/tests/projects/yarn1/yarn.lock +106 -0
- forceupdate-0.1.0/tests/projects/yarn4/package.json +19 -0
- forceupdate-0.1.0/tests/projects/yarn4/packages/lib/package.json +11 -0
- forceupdate-0.1.0/tests/projects/yarn4/yarn.lock +353 -0
- forceupdate-0.1.0/tests/test_checks.py +542 -0
- forceupdate-0.1.0/tests/test_checks_vulns.py +246 -0
- forceupdate-0.1.0/tests/test_cli.py +299 -0
- forceupdate-0.1.0/tests/test_conftest.py +35 -0
- forceupdate-0.1.0/tests/test_cvss.py +77 -0
- forceupdate-0.1.0/tests/test_engine.py +157 -0
- forceupdate-0.1.0/tests/test_engine_check.py +491 -0
- forceupdate-0.1.0/tests/test_json_spans.py +90 -0
- forceupdate-0.1.0/tests/test_languages.py +161 -0
- forceupdate-0.1.0/tests/test_manifests.py +352 -0
- forceupdate-0.1.0/tests/test_models.py +169 -0
- forceupdate-0.1.0/tests/test_net_cache.py +187 -0
- forceupdate-0.1.0/tests/test_net_http.py +278 -0
- forceupdate-0.1.0/tests/test_npm_projects.py +282 -0
- forceupdate-0.1.0/tests/test_osv.py +497 -0
- forceupdate-0.1.0/tests/test_parsers_npm.py +1065 -0
- forceupdate-0.1.0/tests/test_parsers_python.py +1172 -0
- forceupdate-0.1.0/tests/test_planner.py +763 -0
- forceupdate-0.1.0/tests/test_python_projects.py +251 -0
- forceupdate-0.1.0/tests/test_registries.py +229 -0
- forceupdate-0.1.0/tests/test_registries_npm.py +269 -0
- forceupdate-0.1.0/tests/test_registries_pypi.py +378 -0
- forceupdate-0.1.0/tests/test_report.py +384 -0
- forceupdate-0.1.0/tests/test_sources.py +169 -0
- forceupdate-0.1.0/tests/test_toml_spans.py +143 -0
- forceupdate-0.1.0/tests/test_update_constraints.py +184 -0
- forceupdate-0.1.0/tests/test_versions.py +213 -0
- forceupdate-0.1.0/tests/test_versions_npm.py +483 -0
- forceupdate-0.1.0/tests/test_versions_pypi.py +245 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Pauzzle
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: forceupdate
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Trouve les dépendances à mettre à jour (versions, failles, fins de vie) et fait les mises à jour : en local, ou par pull request sur GitHub, GitLab et Bitbucket.
|
|
5
|
+
Project-URL: Homepage, https://github.com/Pauzzle-ozz/forceupdate
|
|
6
|
+
Project-URL: Repository, https://github.com/Pauzzle-ozz/forceupdate
|
|
7
|
+
Project-URL: Issues, https://github.com/Pauzzle-ozz/forceupdate/issues
|
|
8
|
+
Author: Pauzzle
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: dependencies,end-of-life,osv,outdated,pull-request,update,vulnerabilities
|
|
12
|
+
Classifier: Development Status :: 2 - Pre-Alpha
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Environment :: Web Environment
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Natural Language :: French
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
24
|
+
Classifier: Topic :: Security
|
|
25
|
+
Classifier: Topic :: Software Development
|
|
26
|
+
Classifier: Topic :: System :: Software Distribution
|
|
27
|
+
Classifier: Topic :: Utilities
|
|
28
|
+
Requires-Python: >=3.11
|
|
29
|
+
Requires-Dist: httpx>=0.28.1
|
|
30
|
+
Requires-Dist: packaging>=26.3
|
|
31
|
+
Requires-Dist: platformdirs>=4.13.6
|
|
32
|
+
Requires-Dist: pyyaml>=6.0.3
|
|
33
|
+
Requires-Dist: rich>=15.0.0
|
|
34
|
+
Requires-Dist: typer>=0.27.3
|
|
35
|
+
Description-Content-Type: text/markdown
|
|
36
|
+
|
|
37
|
+
# forceupdate
|
|
38
|
+
|
|
39
|
+
On donne du code à l'outil : un dossier, un fichier, ou tous ses dépôts GitHub,
|
|
40
|
+
GitLab et Bitbucket. Dans une interface web qui tourne sur son ordinateur, il
|
|
41
|
+
montre les langages et les dépendances, et dit ce qui doit être mis à jour :
|
|
42
|
+
versions en retard, failles, fins de vie, paquets dépréciés. On coche les mises à
|
|
43
|
+
jour voulues, puis il les fait : en local il réécrit les fichiers, sur une forge il
|
|
44
|
+
ouvre une pull request par dépôt.
|
|
45
|
+
|
|
46
|
+
En construction. L'outil sera publié gratuitement sur PyPI
|
|
47
|
+
(`uv tool install forceupdate`), sous licence MIT.
|
|
48
|
+
|
|
49
|
+
Déjà là, en ligne de commande, pour Python et npm : `forceupdate scan <dossier>`
|
|
50
|
+
dit quelles dépendances ont une faille connue (d'après [OSV](https://osv.dev),
|
|
51
|
+
indirectes comprises, avec la version qui la corrige), une version plus récente,
|
|
52
|
+
une version retirée, ou sont dépréciées.
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
forceupdate scan . # rapport dans le terminal
|
|
56
|
+
forceupdate scan . --format json -o rapport.json # ou md ; toujours en UTF-8
|
|
57
|
+
forceupdate scan . --fail-on vuln # code 1 si une faille est connue
|
|
58
|
+
forceupdate scan . --fail-on major # code 1 si une majeure (ou pire) attend
|
|
59
|
+
forceupdate scan . --offline # seulement le cache, sans réseau
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Autres options : `--no-dev`, `--transitive`, `--no-cache` (`forceupdate scan --help`).
|
|
63
|
+
|
|
64
|
+
`forceupdate update <dossier>` montre, pour l'instant sans rien écrire, les mises à
|
|
65
|
+
jour qu'il ferait : vers quelle version, quelle contrainte réécrire (dans son style :
|
|
66
|
+
`^4.17.0` devient `^4.21.2`), quel lockfile régénérer. Correctifs, mineures et
|
|
67
|
+
corrections de failles sont choisis ; les majeures sont proposées à part.
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
forceupdate update . # correctifs et mineures (--level minor)
|
|
71
|
+
forceupdate update . --level major # majeures comprises
|
|
72
|
+
forceupdate update . --security-only # seulement les corrections de failles
|
|
73
|
+
forceupdate update . --exclude "eslint*" --ecosystem npm
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
- [docs/BRIEF.md](docs/BRIEF.md) : l'idée, les décisions prises, les pièges
|
|
77
|
+
- [docs/JSON_FORMAT.md](docs/JSON_FORMAT.md) : le format du rapport JSON
|
|
78
|
+
- [PLAN.md](PLAN.md) : le plan étape par étape, et l'avancement
|
|
79
|
+
- [reference/README.md](reference/README.md) : le code déjà disponible, repris d'Argos
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# forceupdate
|
|
2
|
+
|
|
3
|
+
On donne du code à l'outil : un dossier, un fichier, ou tous ses dépôts GitHub,
|
|
4
|
+
GitLab et Bitbucket. Dans une interface web qui tourne sur son ordinateur, il
|
|
5
|
+
montre les langages et les dépendances, et dit ce qui doit être mis à jour :
|
|
6
|
+
versions en retard, failles, fins de vie, paquets dépréciés. On coche les mises à
|
|
7
|
+
jour voulues, puis il les fait : en local il réécrit les fichiers, sur une forge il
|
|
8
|
+
ouvre une pull request par dépôt.
|
|
9
|
+
|
|
10
|
+
En construction. L'outil sera publié gratuitement sur PyPI
|
|
11
|
+
(`uv tool install forceupdate`), sous licence MIT.
|
|
12
|
+
|
|
13
|
+
Déjà là, en ligne de commande, pour Python et npm : `forceupdate scan <dossier>`
|
|
14
|
+
dit quelles dépendances ont une faille connue (d'après [OSV](https://osv.dev),
|
|
15
|
+
indirectes comprises, avec la version qui la corrige), une version plus récente,
|
|
16
|
+
une version retirée, ou sont dépréciées.
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
forceupdate scan . # rapport dans le terminal
|
|
20
|
+
forceupdate scan . --format json -o rapport.json # ou md ; toujours en UTF-8
|
|
21
|
+
forceupdate scan . --fail-on vuln # code 1 si une faille est connue
|
|
22
|
+
forceupdate scan . --fail-on major # code 1 si une majeure (ou pire) attend
|
|
23
|
+
forceupdate scan . --offline # seulement le cache, sans réseau
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Autres options : `--no-dev`, `--transitive`, `--no-cache` (`forceupdate scan --help`).
|
|
27
|
+
|
|
28
|
+
`forceupdate update <dossier>` montre, pour l'instant sans rien écrire, les mises à
|
|
29
|
+
jour qu'il ferait : vers quelle version, quelle contrainte réécrire (dans son style :
|
|
30
|
+
`^4.17.0` devient `^4.21.2`), quel lockfile régénérer. Correctifs, mineures et
|
|
31
|
+
corrections de failles sont choisis ; les majeures sont proposées à part.
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
forceupdate update . # correctifs et mineures (--level minor)
|
|
35
|
+
forceupdate update . --level major # majeures comprises
|
|
36
|
+
forceupdate update . --security-only # seulement les corrections de failles
|
|
37
|
+
forceupdate update . --exclude "eslint*" --ecosystem npm
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
- [docs/BRIEF.md](docs/BRIEF.md) : l'idée, les décisions prises, les pièges
|
|
41
|
+
- [docs/JSON_FORMAT.md](docs/JSON_FORMAT.md) : le format du rapport JSON
|
|
42
|
+
- [PLAN.md](PLAN.md) : le plan étape par étape, et l'avancement
|
|
43
|
+
- [reference/README.md](reference/README.md) : le code déjà disponible, repris d'Argos
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "forceupdate"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Trouve les dépendances à mettre à jour (versions, failles, fins de vie) et fait les mises à jour : en local, ou par pull request sur GitHub, GitLab et Bitbucket."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
license-files = ["LICENSE"]
|
|
8
|
+
requires-python = ">=3.11"
|
|
9
|
+
authors = [{ name = "Pauzzle" }]
|
|
10
|
+
keywords = [
|
|
11
|
+
"dependencies",
|
|
12
|
+
"update",
|
|
13
|
+
"outdated",
|
|
14
|
+
"vulnerabilities",
|
|
15
|
+
"osv",
|
|
16
|
+
"end-of-life",
|
|
17
|
+
"pull-request",
|
|
18
|
+
]
|
|
19
|
+
classifiers = [
|
|
20
|
+
"Development Status :: 2 - Pre-Alpha",
|
|
21
|
+
"Environment :: Console",
|
|
22
|
+
"Environment :: Web Environment",
|
|
23
|
+
"Intended Audience :: Developers",
|
|
24
|
+
"Natural Language :: French",
|
|
25
|
+
"Operating System :: OS Independent",
|
|
26
|
+
"Programming Language :: Python :: 3",
|
|
27
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
28
|
+
"Programming Language :: Python :: 3.11",
|
|
29
|
+
"Programming Language :: Python :: 3.12",
|
|
30
|
+
"Programming Language :: Python :: 3.13",
|
|
31
|
+
"Programming Language :: Python :: 3.14",
|
|
32
|
+
"Topic :: Security",
|
|
33
|
+
"Topic :: Software Development",
|
|
34
|
+
"Topic :: System :: Software Distribution",
|
|
35
|
+
"Topic :: Utilities",
|
|
36
|
+
]
|
|
37
|
+
dependencies = [
|
|
38
|
+
"httpx>=0.28.1",
|
|
39
|
+
"packaging>=26.3",
|
|
40
|
+
"platformdirs>=4.13.6",
|
|
41
|
+
"pyyaml>=6.0.3",
|
|
42
|
+
"rich>=15.0.0",
|
|
43
|
+
"typer>=0.27.3",
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
[project.urls]
|
|
47
|
+
Homepage = "https://github.com/Pauzzle-ozz/forceupdate"
|
|
48
|
+
Repository = "https://github.com/Pauzzle-ozz/forceupdate"
|
|
49
|
+
Issues = "https://github.com/Pauzzle-ozz/forceupdate/issues"
|
|
50
|
+
|
|
51
|
+
[project.scripts]
|
|
52
|
+
forceupdate = "forceupdate.cli:app"
|
|
53
|
+
|
|
54
|
+
[dependency-groups]
|
|
55
|
+
dev = [
|
|
56
|
+
"pytest>=9.1.1",
|
|
57
|
+
"respx>=0.23.1",
|
|
58
|
+
"ruff>=0.17.3",
|
|
59
|
+
]
|
|
60
|
+
|
|
61
|
+
[build-system]
|
|
62
|
+
requires = ["hatchling>=1.27"]
|
|
63
|
+
build-backend = "hatchling.build"
|
|
64
|
+
|
|
65
|
+
[tool.hatch.build.targets.wheel]
|
|
66
|
+
packages = ["src/forceupdate"]
|
|
67
|
+
|
|
68
|
+
[tool.hatch.build.targets.sdist]
|
|
69
|
+
include = ["/src", "/tests"]
|
|
70
|
+
|
|
71
|
+
[tool.ruff]
|
|
72
|
+
line-length = 100
|
|
73
|
+
extend-exclude = ["reference"]
|
|
74
|
+
|
|
75
|
+
[tool.ruff.lint]
|
|
76
|
+
select = ["E", "W", "F", "I", "UP", "B", "SIM", "RUF"]
|
|
77
|
+
|
|
78
|
+
[tool.pytest.ini_options]
|
|
79
|
+
testpaths = ["tests"]
|
|
80
|
+
addopts = ["-ra", "-p", "pytester"]
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"""forceupdate : trouve les dépendances à mettre à jour, et fait les mises à jour.
|
|
2
|
+
|
|
3
|
+
La version vient des métadonnées du paquet installé : elle n'est écrite qu'à un
|
|
4
|
+
seul endroit, dans ``pyproject.toml``.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from importlib.metadata import version
|
|
8
|
+
|
|
9
|
+
__version__ = version("forceupdate")
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"""Les avis de sécurité : les failles connues d'une version de paquet (type 2 du brief).
|
|
2
|
+
|
|
3
|
+
- ``osv.py`` : le client d'OSV (``Osv``), et ``Advisory``, un avis réduit à ce qui sert,
|
|
4
|
+
avec la version qui corrige la faille (``Advisory.fixed_in``) ;
|
|
5
|
+
- ``cvss.py`` : le score CVSS 3 d'un vecteur, et la gravité qui va avec.
|
|
6
|
+
|
|
7
|
+
Les constats qu'on en tire sont dans ``checks/vulns.py``, qui ne parle pas au réseau.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from forceupdate.advisories.osv import (
|
|
11
|
+
Advisory,
|
|
12
|
+
Affected,
|
|
13
|
+
AffectedRange,
|
|
14
|
+
Osv,
|
|
15
|
+
OsvError,
|
|
16
|
+
Query,
|
|
17
|
+
Vulnerabilities,
|
|
18
|
+
parse_vuln,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
__all__ = [
|
|
22
|
+
"Advisory",
|
|
23
|
+
"Affected",
|
|
24
|
+
"AffectedRange",
|
|
25
|
+
"Osv",
|
|
26
|
+
"OsvError",
|
|
27
|
+
"Query",
|
|
28
|
+
"Vulnerabilities",
|
|
29
|
+
"parse_vuln",
|
|
30
|
+
]
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"""Le score CVSS d'une faille, calculé depuis son vecteur, sans dépendance.
|
|
2
|
+
|
|
3
|
+
OSV donne la gravité d'une faille sous forme de vecteur (``CVSS:3.1/AV:N/AC:L/…``), pas de
|
|
4
|
+
score. Le calcul suit la spécification de FIRST (CVSS 3.1, section 7.1), y compris son
|
|
5
|
+
arrondi (annexe A), qui évite les erreurs de calcul en virgule flottante : un arrondi naïf
|
|
6
|
+
(``ceil(x * 10) / 10``) donne parfois un dixième de trop. Les vecteurs CVSS 3.0 ont les mêmes
|
|
7
|
+
formules ; seul leur arrondi diffère, et ne change le score que dans ces cas d'erreur.
|
|
8
|
+
|
|
9
|
+
CVSS 4.0 n'est pas calculé (il faut les tables de la spécification) : OSV le donne rarement
|
|
10
|
+
seul, et GitHub ajoute alors sa propre gravité, que lit ``advisories.osv``.
|
|
11
|
+
|
|
12
|
+
Repris de ``reference/argos_sca_parsers.py`` (``_cvss_base_score_from_vector``,
|
|
13
|
+
``_cvss_to_severity``), puis adapté : ``Severity`` de ``models`` (``ARGOS (1)``), métriques
|
|
14
|
+
lues dans n'importe quel ordre, arrondi de la spécification, ``None`` pour un vecteur
|
|
15
|
+
illisible au lieu de 0.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
import re
|
|
19
|
+
|
|
20
|
+
from forceupdate.models import Severity
|
|
21
|
+
|
|
22
|
+
_PREFIX = re.compile(r"^CVSS:3\.[01]/")
|
|
23
|
+
_LEADING_SCORE = re.compile(r"^(\d{1,2}\.\d)/")
|
|
24
|
+
"""Un score écrit devant le vecteur (``9.8/CVSS:3.1/…``), comme certaines bases le font."""
|
|
25
|
+
|
|
26
|
+
_WEIGHTS: dict[str, dict[str, float]] = {
|
|
27
|
+
"AV": {"N": 0.85, "A": 0.62, "L": 0.55, "P": 0.2},
|
|
28
|
+
"AC": {"L": 0.77, "H": 0.44},
|
|
29
|
+
"UI": {"N": 0.85, "R": 0.62},
|
|
30
|
+
"C": {"H": 0.56, "L": 0.22, "N": 0.0},
|
|
31
|
+
"I": {"H": 0.56, "L": 0.22, "N": 0.0},
|
|
32
|
+
"A": {"H": 0.56, "L": 0.22, "N": 0.0},
|
|
33
|
+
}
|
|
34
|
+
_PRIVILEGES = {"N": 0.85, "L": 0.62, "H": 0.27}
|
|
35
|
+
_PRIVILEGES_CHANGED = {"N": 0.85, "L": 0.68, "H": 0.5}
|
|
36
|
+
"""PR pèse plus quand la faille sort de son périmètre (``S:C``)."""
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def base_score(vector: str) -> float | None:
|
|
40
|
+
"""Le score de base (0 à 10) d'un vecteur CVSS 3.0 ou 3.1 ; ``None`` s'il est illisible.
|
|
41
|
+
|
|
42
|
+
Les métriques temporelles et environnementales (``E:``, ``RL:``…) sont ignorées : le
|
|
43
|
+
score de base est celui que publient les avis.
|
|
44
|
+
"""
|
|
45
|
+
vector = vector.strip()
|
|
46
|
+
leading = _LEADING_SCORE.match(vector)
|
|
47
|
+
if leading:
|
|
48
|
+
return float(leading.group(1))
|
|
49
|
+
if not _PREFIX.match(vector):
|
|
50
|
+
return None
|
|
51
|
+
metrics: dict[str, str] = {}
|
|
52
|
+
for part in vector.split("/")[1:]:
|
|
53
|
+
name, _, value = part.partition(":")
|
|
54
|
+
metrics.setdefault(name, value)
|
|
55
|
+
try:
|
|
56
|
+
scope_changed = {"U": False, "C": True}[metrics["S"]]
|
|
57
|
+
privileges = (_PRIVILEGES_CHANGED if scope_changed else _PRIVILEGES)[metrics["PR"]]
|
|
58
|
+
weights = {name: _WEIGHTS[name][metrics[name]] for name in _WEIGHTS}
|
|
59
|
+
except KeyError:
|
|
60
|
+
return None
|
|
61
|
+
iss = 1 - (1 - weights["C"]) * (1 - weights["I"]) * (1 - weights["A"])
|
|
62
|
+
impact = (7.52 * (iss - 0.029) - 3.25 * (iss - 0.02) ** 15) if scope_changed else 6.42 * iss
|
|
63
|
+
if impact <= 0:
|
|
64
|
+
return 0.0
|
|
65
|
+
exploitability = 8.22 * weights["AV"] * weights["AC"] * privileges * weights["UI"]
|
|
66
|
+
total = impact + exploitability
|
|
67
|
+
if scope_changed:
|
|
68
|
+
total *= 1.08
|
|
69
|
+
return _roundup(min(total, 10.0))
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def _roundup(value: float) -> float:
|
|
73
|
+
"""Le plus petit nombre à une décimale qui est au moins ``value`` (CVSS 3.1, annexe A).
|
|
74
|
+
|
|
75
|
+
Calculé en entiers : ``ceil(4.000000000000001 * 10) / 10`` donnerait 4.1 au lieu de 4.0.
|
|
76
|
+
"""
|
|
77
|
+
integer = round(value * 100_000)
|
|
78
|
+
if integer % 10_000 == 0:
|
|
79
|
+
return integer / 100_000
|
|
80
|
+
return (integer // 10_000 + 1) / 10
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def severity(score: float) -> Severity:
|
|
84
|
+
"""La gravité d'un score CVSS, selon l'échelle de la spécification : critique à partir de
|
|
85
|
+
9, élevée à partir de 7, moyenne à partir de 4, faible au-dessus de 0. Un score nul
|
|
86
|
+
(aucun impact) donne ``INFO``."""
|
|
87
|
+
if score >= 9.0:
|
|
88
|
+
return Severity.CRITICAL
|
|
89
|
+
if score >= 7.0:
|
|
90
|
+
return Severity.HIGH
|
|
91
|
+
if score >= 4.0:
|
|
92
|
+
return Severity.MEDIUM
|
|
93
|
+
if score > 0.0:
|
|
94
|
+
return Severity.LOW
|
|
95
|
+
return Severity.INFO
|