depenemy 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.
- depenemy-0.1.0/.depenemy.yml +43 -0
- depenemy-0.1.0/.github/workflows/ci.yml +75 -0
- depenemy-0.1.0/.github/workflows/publish.yml +30 -0
- depenemy-0.1.0/.gitignore +58 -0
- depenemy-0.1.0/.pre-commit-config.yaml +11 -0
- depenemy-0.1.0/CHANGELOG.md +26 -0
- depenemy-0.1.0/LICENSE +21 -0
- depenemy-0.1.0/PKG-INFO +268 -0
- depenemy-0.1.0/README.md +210 -0
- depenemy-0.1.0/action.yml +82 -0
- depenemy-0.1.0/assets/logos/logo.svg +26 -0
- depenemy-0.1.0/depenemy/__init__.py +4 -0
- depenemy-0.1.0/depenemy/__main__.py +3 -0
- depenemy-0.1.0/depenemy/advisories/__init__.py +5 -0
- depenemy-0.1.0/depenemy/advisories/osv.py +184 -0
- depenemy-0.1.0/depenemy/cache.py +57 -0
- depenemy-0.1.0/depenemy/cli.py +187 -0
- depenemy-0.1.0/depenemy/config.py +152 -0
- depenemy-0.1.0/depenemy/data/top_npm_packages.json +15 -0
- depenemy-0.1.0/depenemy/data/top_pypi_packages.json +14 -0
- depenemy-0.1.0/depenemy/fetchers/__init__.py +8 -0
- depenemy-0.1.0/depenemy/fetchers/base.py +27 -0
- depenemy-0.1.0/depenemy/fetchers/crates.py +97 -0
- depenemy-0.1.0/depenemy/fetchers/github.py +126 -0
- depenemy-0.1.0/depenemy/fetchers/npm.py +176 -0
- depenemy-0.1.0/depenemy/fetchers/pypi.py +158 -0
- depenemy-0.1.0/depenemy/parsers/__init__.py +7 -0
- depenemy-0.1.0/depenemy/parsers/base.py +35 -0
- depenemy-0.1.0/depenemy/parsers/npm.py +98 -0
- depenemy-0.1.0/depenemy/parsers/python.py +153 -0
- depenemy-0.1.0/depenemy/parsers/rust.py +69 -0
- depenemy-0.1.0/depenemy/reporters/__init__.py +7 -0
- depenemy-0.1.0/depenemy/reporters/json_reporter.py +43 -0
- depenemy-0.1.0/depenemy/reporters/sarif.py +91 -0
- depenemy-0.1.0/depenemy/reporters/table.py +146 -0
- depenemy-0.1.0/depenemy/rules/__init__.py +44 -0
- depenemy-0.1.0/depenemy/rules/base.py +65 -0
- depenemy-0.1.0/depenemy/rules/behavioral/__init__.py +5 -0
- depenemy-0.1.0/depenemy/rules/behavioral/b001_range_specifier.py +45 -0
- depenemy-0.1.0/depenemy/rules/behavioral/b002_unpinned.py +33 -0
- depenemy-0.1.0/depenemy/rules/behavioral/b003_lagging_version.py +59 -0
- depenemy-0.1.0/depenemy/rules/reputation/__init__.py +21 -0
- depenemy-0.1.0/depenemy/rules/reputation/r001_young_author.py +49 -0
- depenemy-0.1.0/depenemy/rules/reputation/r002_young_package.py +49 -0
- depenemy-0.1.0/depenemy/rules/reputation/r003_low_weekly_downloads.py +38 -0
- depenemy-0.1.0/depenemy/rules/reputation/r004_low_total_downloads.py +38 -0
- depenemy-0.1.0/depenemy/rules/reputation/r005_stale_package.py +50 -0
- depenemy-0.1.0/depenemy/rules/reputation/r006_few_contributors.py +41 -0
- depenemy-0.1.0/depenemy/rules/reputation/r007_below_security_patch.py +48 -0
- depenemy-0.1.0/depenemy/rules/reputation/r008_deprecated.py +33 -0
- depenemy-0.1.0/depenemy/rules/reputation/r009_typosquatting.py +82 -0
- depenemy-0.1.0/depenemy/rules/supply_chain/__init__.py +13 -0
- depenemy-0.1.0/depenemy/rules/supply_chain/s001_install_scripts.py +36 -0
- depenemy-0.1.0/depenemy/rules/supply_chain/s002_no_source_repo.py +35 -0
- depenemy-0.1.0/depenemy/rules/supply_chain/s003_archived_repo.py +35 -0
- depenemy-0.1.0/depenemy/rules/supply_chain/s004_dependency_confusion.py +73 -0
- depenemy-0.1.0/depenemy/rules/supply_chain/s005_malicious_package.py +36 -0
- depenemy-0.1.0/depenemy/scanner.py +152 -0
- depenemy-0.1.0/depenemy/types.py +114 -0
- depenemy-0.1.0/pyproject.toml +80 -0
- depenemy-0.1.0/tests/__init__.py +0 -0
- depenemy-0.1.0/tests/conftest.py +83 -0
- depenemy-0.1.0/tests/fixtures/npm/b001_caret_ranges.json +14 -0
- depenemy-0.1.0/tests/fixtures/npm/b001_gte_range.json +12 -0
- depenemy-0.1.0/tests/fixtures/npm/b001_latest_tag.json +13 -0
- depenemy-0.1.0/tests/fixtures/npm/b001_or_range.json +11 -0
- depenemy-0.1.0/tests/fixtures/npm/b001_star_wildcard.json +13 -0
- depenemy-0.1.0/tests/fixtures/npm/b001_tilde_ranges.json +13 -0
- depenemy-0.1.0/tests/fixtures/npm/b001_x_range.json +14 -0
- depenemy-0.1.0/tests/fixtures/npm/b002_empty_version.json +10 -0
- depenemy-0.1.0/tests/fixtures/npm/b002_x_version.json +10 -0
- depenemy-0.1.0/tests/fixtures/npm/clean_exact_pins.json +15 -0
- depenemy-0.1.0/tests/fixtures/npm/future_file_dep.json +12 -0
- depenemy-0.1.0/tests/fixtures/npm/future_git_dep.json +13 -0
- depenemy-0.1.0/tests/fixtures/npm/future_http_dep.json +10 -0
- depenemy-0.1.0/tests/fixtures/npm/future_install_scripts.json +14 -0
- depenemy-0.1.0/tests/fixtures/npm/future_no_license.json +9 -0
- depenemy-0.1.0/tests/fixtures/npm/mixed_bad_patterns.json +23 -0
- depenemy-0.1.0/tests/test_parsers/__init__.py +0 -0
- depenemy-0.1.0/tests/test_parsers/test_npm.py +67 -0
- depenemy-0.1.0/tests/test_parsers/test_npm_parser.py +134 -0
- depenemy-0.1.0/tests/test_parsers/test_python.py +57 -0
- depenemy-0.1.0/tests/test_reporters/__init__.py +0 -0
- depenemy-0.1.0/tests/test_reporters/test_json_reporter.py +125 -0
- depenemy-0.1.0/tests/test_reporters/test_sarif.py +70 -0
- depenemy-0.1.0/tests/test_reporters/test_table.py +189 -0
- depenemy-0.1.0/tests/test_rules/__init__.py +0 -0
- depenemy-0.1.0/tests/test_rules/test_b001_range_specifier.py +128 -0
- depenemy-0.1.0/tests/test_rules/test_b002_unpinned.py +95 -0
- depenemy-0.1.0/tests/test_rules/test_behavioral.py +92 -0
- depenemy-0.1.0/tests/test_rules/test_detection_coverage.py +276 -0
- depenemy-0.1.0/tests/test_rules/test_r009_typosquatting.py +106 -0
- depenemy-0.1.0/tests/test_rules/test_reputation.py +160 -0
- depenemy-0.1.0/tests/test_rules/test_s004_s005.py +227 -0
- depenemy-0.1.0/tests/test_rules/test_supply_chain.py +55 -0
- depenemy-0.1.0/tests/test_scanner.py +98 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# depenemy configuration
|
|
2
|
+
# All thresholds are configurable. Set a rule to false to disable it.
|
|
3
|
+
|
|
4
|
+
thresholds:
|
|
5
|
+
min_weekly_downloads: 1000
|
|
6
|
+
min_total_downloads: 10000
|
|
7
|
+
min_author_account_age_days: 365
|
|
8
|
+
min_package_age_days: 180
|
|
9
|
+
max_stale_days: 730
|
|
10
|
+
min_contributors: 5
|
|
11
|
+
max_version_lag: 10 # how many minor versions behind is too old
|
|
12
|
+
typosquatting_distance: 1 # max edit distance to flag as typosquatting
|
|
13
|
+
|
|
14
|
+
rules:
|
|
15
|
+
B001: warning # range specifier (^, ~, >=, *) - hygiene
|
|
16
|
+
B002: error # no version pinned - active risk
|
|
17
|
+
B003: warning # lagging version - hygiene, CVEs caught by R007
|
|
18
|
+
R001: warning # young author account - signal, not proof
|
|
19
|
+
R002: warning # young package - signal, not proof
|
|
20
|
+
R003: warning # low weekly downloads - signal
|
|
21
|
+
R004: warning # low total downloads - signal
|
|
22
|
+
R005: warning # stale package - maintenance issue, not active threat
|
|
23
|
+
R006: warning # few contributors - signal
|
|
24
|
+
R007: error # target version below known security patch - active threat
|
|
25
|
+
R008: warning # deprecated - should migrate, not urgent
|
|
26
|
+
R009: warning # typosquatting suspected - signal
|
|
27
|
+
S001: error # install scripts present - executes code on install
|
|
28
|
+
S002: warning # no source repository linked - hygiene
|
|
29
|
+
S003: warning # source repository archived - maintenance issue
|
|
30
|
+
S004: warning # dependency confusion - signal
|
|
31
|
+
S005: error # known malicious package history in OSV - active threat
|
|
32
|
+
|
|
33
|
+
# Packages to ignore (with reason)
|
|
34
|
+
ignore: []
|
|
35
|
+
# ignore:
|
|
36
|
+
# - name: my-internal-package
|
|
37
|
+
# ecosystem: npm
|
|
38
|
+
# reason: "internal fork, not on public registry"
|
|
39
|
+
|
|
40
|
+
# Ecosystems to scan (default: all detected)
|
|
41
|
+
# ecosystems:
|
|
42
|
+
# - npm
|
|
43
|
+
# - pypi
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main, develop]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
name: Test (Python ${{ matrix.python-version }})
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
strategy:
|
|
14
|
+
matrix:
|
|
15
|
+
python-version: ["3.11", "3.12"]
|
|
16
|
+
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
|
|
20
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
21
|
+
uses: actions/setup-python@v5
|
|
22
|
+
with:
|
|
23
|
+
python-version: ${{ matrix.python-version }}
|
|
24
|
+
|
|
25
|
+
- name: Install dependencies
|
|
26
|
+
run: |
|
|
27
|
+
pip install -e ".[dev]"
|
|
28
|
+
|
|
29
|
+
- name: Lint with ruff
|
|
30
|
+
run: ruff check .
|
|
31
|
+
|
|
32
|
+
- name: Type check with mypy
|
|
33
|
+
run: mypy depenemy
|
|
34
|
+
|
|
35
|
+
- name: Run tests
|
|
36
|
+
run: pytest --cov=depenemy --cov-report=xml
|
|
37
|
+
|
|
38
|
+
- name: Upload coverage
|
|
39
|
+
uses: codecov/codecov-action@v4
|
|
40
|
+
if: matrix.python-version == '3.11'
|
|
41
|
+
with:
|
|
42
|
+
file: ./coverage.xml
|
|
43
|
+
|
|
44
|
+
self-scan:
|
|
45
|
+
name: Self-scan (depenemy scans itself)
|
|
46
|
+
runs-on: ubuntu-latest
|
|
47
|
+
needs: test
|
|
48
|
+
permissions:
|
|
49
|
+
contents: read
|
|
50
|
+
security-events: write
|
|
51
|
+
|
|
52
|
+
steps:
|
|
53
|
+
- uses: actions/checkout@v4
|
|
54
|
+
|
|
55
|
+
- name: Set up Python
|
|
56
|
+
uses: actions/setup-python@v5
|
|
57
|
+
with:
|
|
58
|
+
python-version: "3.11"
|
|
59
|
+
|
|
60
|
+
- name: Install depenemy
|
|
61
|
+
run: pip install -e .
|
|
62
|
+
|
|
63
|
+
- name: Run depenemy on this repo
|
|
64
|
+
env:
|
|
65
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
66
|
+
run: |
|
|
67
|
+
depenemy scan . --output sarif --output-file depenemy.sarif --fail-on error || true
|
|
68
|
+
|
|
69
|
+
- name: Upload SARIF
|
|
70
|
+
uses: github/codeql-action/upload-sarif@v4
|
|
71
|
+
if: always()
|
|
72
|
+
continue-on-error: true
|
|
73
|
+
with:
|
|
74
|
+
sarif_file: depenemy.sarif
|
|
75
|
+
category: depenemy-self-scan
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
publish:
|
|
9
|
+
name: Publish to PyPI
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
environment: pypi
|
|
12
|
+
permissions:
|
|
13
|
+
id-token: write # Required for trusted publishing
|
|
14
|
+
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
|
|
18
|
+
- name: Set up Python
|
|
19
|
+
uses: actions/setup-python@v5
|
|
20
|
+
with:
|
|
21
|
+
python-version: "3.11"
|
|
22
|
+
|
|
23
|
+
- name: Install build tools
|
|
24
|
+
run: pip install hatchling build
|
|
25
|
+
|
|
26
|
+
- name: Build package
|
|
27
|
+
run: python -m build
|
|
28
|
+
|
|
29
|
+
- name: Publish to PyPI
|
|
30
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
.Python
|
|
7
|
+
build/
|
|
8
|
+
dist/
|
|
9
|
+
eggs/
|
|
10
|
+
.eggs/
|
|
11
|
+
lib/
|
|
12
|
+
lib64/
|
|
13
|
+
parts/
|
|
14
|
+
sdist/
|
|
15
|
+
var/
|
|
16
|
+
wheels/
|
|
17
|
+
*.egg-info/
|
|
18
|
+
.installed.cfg
|
|
19
|
+
*.egg
|
|
20
|
+
MANIFEST
|
|
21
|
+
.venv/
|
|
22
|
+
venv/
|
|
23
|
+
ENV/
|
|
24
|
+
env/
|
|
25
|
+
|
|
26
|
+
# Testing
|
|
27
|
+
.tox/
|
|
28
|
+
.nox/
|
|
29
|
+
.coverage
|
|
30
|
+
.coverage.*
|
|
31
|
+
coverage.xml
|
|
32
|
+
htmlcov/
|
|
33
|
+
.pytest_cache/
|
|
34
|
+
.mypy_cache/
|
|
35
|
+
|
|
36
|
+
# IDEs
|
|
37
|
+
.idea/
|
|
38
|
+
.vscode/
|
|
39
|
+
*.swp
|
|
40
|
+
*.swo
|
|
41
|
+
|
|
42
|
+
# OS
|
|
43
|
+
.DS_Store
|
|
44
|
+
Thumbs.db
|
|
45
|
+
|
|
46
|
+
# depenemy output
|
|
47
|
+
.depenemy_cache/
|
|
48
|
+
depenemy-results.json
|
|
49
|
+
|
|
50
|
+
# local demo
|
|
51
|
+
demo/
|
|
52
|
+
|
|
53
|
+
# Team coordination
|
|
54
|
+
TODO.md
|
|
55
|
+
|
|
56
|
+
# Secrets
|
|
57
|
+
.env
|
|
58
|
+
*.key
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.1.0] - 2026-04-09
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- Initial release
|
|
14
|
+
- npm and PyPI ecosystem support
|
|
15
|
+
- Behavioral checks: range specifiers, unpinned versions, lagging versions
|
|
16
|
+
- Reputation checks: author age, package age, download counts, contributors, staleness, known CVEs, deprecated packages, typosquatting
|
|
17
|
+
- Supply chain checks: install scripts, missing source repo, archived repo, dependency confusion, known malicious packages
|
|
18
|
+
- Deprecated package detection
|
|
19
|
+
- OSV.dev integration for security advisories
|
|
20
|
+
- SARIF 2.1.0 output (GitHub Code Scanning compatible)
|
|
21
|
+
- Rich terminal table output
|
|
22
|
+
- JSON output
|
|
23
|
+
- Disk-backed caching
|
|
24
|
+
- GitHub Action support
|
|
25
|
+
- Pre-commit hook support
|
|
26
|
+
- Configurable thresholds via `.depenemy.yml`
|
depenemy-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 W3OSC
|
|
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.
|
depenemy-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: depenemy
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Dependency scanner that finds your enemies in the supply chain
|
|
5
|
+
Project-URL: Homepage, https://github.com/W3OSC/depenemy
|
|
6
|
+
Project-URL: Repository, https://github.com/W3OSC/depenemy
|
|
7
|
+
Project-URL: Issues, https://github.com/W3OSC/depenemy/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/W3OSC/depenemy/blob/main/CHANGELOG.md
|
|
9
|
+
Author-email: W3OSC <contact@w3osc.com>
|
|
10
|
+
License: MIT License
|
|
11
|
+
|
|
12
|
+
Copyright (c) 2026 W3OSC
|
|
13
|
+
|
|
14
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
15
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
16
|
+
in the Software without restriction, including without limitation the rights
|
|
17
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
18
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
19
|
+
furnished to do so, subject to the following conditions:
|
|
20
|
+
|
|
21
|
+
The above copyright notice and this permission notice shall be included in all
|
|
22
|
+
copies or substantial portions of the Software.
|
|
23
|
+
|
|
24
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
25
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
26
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
27
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
28
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
29
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
30
|
+
SOFTWARE.
|
|
31
|
+
License-File: LICENSE
|
|
32
|
+
Keywords: dependencies,sarif,sbom,scanner,security,supply-chain
|
|
33
|
+
Classifier: Development Status :: 3 - Alpha
|
|
34
|
+
Classifier: Environment :: Console
|
|
35
|
+
Classifier: Intended Audience :: Developers
|
|
36
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
37
|
+
Classifier: Programming Language :: Python :: 3
|
|
38
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
39
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
40
|
+
Classifier: Topic :: Security
|
|
41
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
42
|
+
Requires-Python: >=3.9
|
|
43
|
+
Requires-Dist: anyio>=4.4.0
|
|
44
|
+
Requires-Dist: httpx>=0.27.0
|
|
45
|
+
Requires-Dist: pyyaml>=6.0
|
|
46
|
+
Requires-Dist: rich>=13.7.0
|
|
47
|
+
Requires-Dist: tomli>=2.0.0; python_version < '3.11'
|
|
48
|
+
Requires-Dist: typer>=0.12.0
|
|
49
|
+
Provides-Extra: dev
|
|
50
|
+
Requires-Dist: mypy>=1.10.0; extra == 'dev'
|
|
51
|
+
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
|
|
52
|
+
Requires-Dist: pytest-cov>=5.0.0; extra == 'dev'
|
|
53
|
+
Requires-Dist: pytest>=8.0.0; extra == 'dev'
|
|
54
|
+
Requires-Dist: respx>=0.21.0; extra == 'dev'
|
|
55
|
+
Requires-Dist: ruff>=0.4.0; extra == 'dev'
|
|
56
|
+
Requires-Dist: types-pyyaml>=6.0.0; extra == 'dev'
|
|
57
|
+
Description-Content-Type: text/markdown
|
|
58
|
+
|
|
59
|
+
<div align="center">
|
|
60
|
+
|
|
61
|
+
<img src="assets/logos/logo.svg" alt="depenemy" width="380"/>
|
|
62
|
+
|
|
63
|
+
**Your dependencies could be your enemy.**
|
|
64
|
+
|
|
65
|
+
Depenemy scans your project for supply chain risks, behavioral issues, and reputation red flags - before they can do damage.
|
|
66
|
+
|
|
67
|
+
[](https://github.com/W3OSC/depenemy/actions/workflows/ci.yml)
|
|
68
|
+
[](https://pypi.org/project/depenemy/)
|
|
69
|
+
[](https://www.python.org/)
|
|
70
|
+
[](LICENSE)
|
|
71
|
+
|
|
72
|
+
</div>
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Why depenemy?
|
|
77
|
+
|
|
78
|
+
Modern projects pull in hundreds of dependencies. Each one is a potential entry point for a supply chain attack - a compromised maintainer account, a typosquatted package, an old version with a known CVE, or a package that runs arbitrary code on install.
|
|
79
|
+
|
|
80
|
+
Depenemy gives you **a single command** that audits all your dependencies across npm, Python, Rust, and Solidity - and tells you exactly what looks suspicious and why.
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## What it detects
|
|
85
|
+
|
|
86
|
+
### Behavioral risks
|
|
87
|
+
|
|
88
|
+
| ID | Name | Description | Severity |
|
|
89
|
+
|----|------|-------------|----------|
|
|
90
|
+
| B001 | Range specifier | Version uses `^`, `~`, `>=`, `*` - allows unexpected updates | Warning |
|
|
91
|
+
| B002 | No version pinned | No version specified at all | Error |
|
|
92
|
+
| B003 | Lagging version | Pinned version is significantly behind latest | Warning |
|
|
93
|
+
|
|
94
|
+
### Reputation signals
|
|
95
|
+
|
|
96
|
+
| ID | Name | Description | Severity |
|
|
97
|
+
|----|------|-------------|----------|
|
|
98
|
+
| R001 | Young author account | Package author's GitHub account is < 12 months old | Warning |
|
|
99
|
+
| R002 | New package | Package was first published < 6 months ago | Warning |
|
|
100
|
+
| R003 | Low weekly downloads | < 1,000 weekly downloads | Warning |
|
|
101
|
+
| R004 | Low total downloads | < 10,000 total downloads | Warning |
|
|
102
|
+
| R005 | No updates in 2+ years | Last publish was over 2 years ago | Warning |
|
|
103
|
+
| R006 | Few contributors | Fewer than 5 contributors on GitHub | Warning |
|
|
104
|
+
| R007 | Known vulnerable version | Your version is below a known security patch (OSV/CVE) | Error |
|
|
105
|
+
| R008 | Deprecated package | Package is officially marked as deprecated | Warning |
|
|
106
|
+
| R009 | Typosquatting suspected | Name is suspiciously close to a popular package | Warning |
|
|
107
|
+
|
|
108
|
+
### Supply chain risks
|
|
109
|
+
|
|
110
|
+
| ID | Name | Description | Severity |
|
|
111
|
+
|----|------|-------------|----------|
|
|
112
|
+
| S001 | Install scripts | Package runs code at install time (`postinstall`, `preinstall`) | Error |
|
|
113
|
+
| S002 | No source repository | No GitHub/GitLab link in package metadata | Warning |
|
|
114
|
+
| S003 | Archived repository | Source repo has been archived or deleted | Warning |
|
|
115
|
+
| S004 | Dependency confusion | Private package name found on public registry | Warning |
|
|
116
|
+
| S005 | Known malicious package | Package has a recorded history of malicious activity (OSV) | Error |
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## Supported ecosystems
|
|
121
|
+
|
|
122
|
+
| Ecosystem | Manifest files |
|
|
123
|
+
|-----------|----------------|
|
|
124
|
+
| **npm / Node.js** | `package.json`, `package-lock.json`, `yarn.lock` |
|
|
125
|
+
| **Python** | `requirements*.txt`, `pyproject.toml`, `Pipfile` |
|
|
126
|
+
| **Rust** | `Cargo.toml` |
|
|
127
|
+
| **Solidity** | Foundry / Hardhat (delegates to npm) |
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## Installation
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
pip install depenemy
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## Usage
|
|
140
|
+
|
|
141
|
+
### CLI
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
# Scan your project
|
|
145
|
+
depenemy scan .
|
|
146
|
+
|
|
147
|
+
# Scan a specific file
|
|
148
|
+
depenemy scan pyproject.toml
|
|
149
|
+
|
|
150
|
+
# Output as SARIF (for GitHub Code Scanning)
|
|
151
|
+
depenemy scan . --output sarif --output-file results.sarif
|
|
152
|
+
|
|
153
|
+
# Output as JSON to a custom filename (table scan always writes depenemy-results.json automatically)
|
|
154
|
+
depenemy scan . --output json --output-file my-results.json
|
|
155
|
+
|
|
156
|
+
# Pipe JSON output to another tool
|
|
157
|
+
depenemy scan . --output json | jq '.findings'
|
|
158
|
+
|
|
159
|
+
# Fail the command if any warnings exist (useful in CI)
|
|
160
|
+
depenemy scan . --fail-on warning
|
|
161
|
+
|
|
162
|
+
# List all available rules
|
|
163
|
+
depenemy rules
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
**Example output:**
|
|
167
|
+
<img width="1070" height="711" alt="image" src="https://github.com/user-attachments/assets/96d22774-9649-4b2e-ba09-c3311df8ae3c" />
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
### GitHub Action
|
|
173
|
+
|
|
174
|
+
Add to your workflow and results appear automatically as [Code Scanning alerts](https://docs.github.com/en/code-security/code-scanning) on every pull request:
|
|
175
|
+
|
|
176
|
+
```yaml
|
|
177
|
+
- name: Scan dependencies
|
|
178
|
+
uses: W3OSC/depenemy@v0.1.0
|
|
179
|
+
with:
|
|
180
|
+
token: ${{ secrets.GITHUB_TOKEN }}
|
|
181
|
+
fail-on: error
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
### Pre-commit hook
|
|
187
|
+
|
|
188
|
+
Block pushes that introduce risky dependencies. Add to `.pre-commit-config.yaml`:
|
|
189
|
+
|
|
190
|
+
```yaml
|
|
191
|
+
repos:
|
|
192
|
+
- repo: https://github.com/W3OSC/depenemy
|
|
193
|
+
rev: v0.1.0
|
|
194
|
+
hooks:
|
|
195
|
+
- id: depenemy
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## Configuration
|
|
201
|
+
|
|
202
|
+
Create `.depenemy.yml` in your repository root to customize thresholds, severities, and ignore specific packages:
|
|
203
|
+
|
|
204
|
+
```yaml
|
|
205
|
+
thresholds:
|
|
206
|
+
min_weekly_downloads: 1000 # R003 threshold
|
|
207
|
+
min_total_downloads: 10000 # R004 threshold
|
|
208
|
+
min_author_account_age_days: 365 # R001 threshold
|
|
209
|
+
min_package_age_days: 180 # R002 threshold
|
|
210
|
+
max_stale_days: 730 # R005 threshold
|
|
211
|
+
min_contributors: 5 # R006 threshold
|
|
212
|
+
max_version_lag: 10 # B003 threshold (minor versions)
|
|
213
|
+
typosquatting_distance: 1 # R009 threshold (edit distance)
|
|
214
|
+
|
|
215
|
+
rules:
|
|
216
|
+
B001: warning # downgrade range specifier to warning
|
|
217
|
+
R003: false # disable low downloads check entirely
|
|
218
|
+
|
|
219
|
+
ignore:
|
|
220
|
+
- name: my-internal-package
|
|
221
|
+
ecosystem: npm
|
|
222
|
+
reason: "Internal fork, not on public registry"
|
|
223
|
+
- name: legacy-tool
|
|
224
|
+
ecosystem: pypi
|
|
225
|
+
reason: "Approved exception, tracked in JIRA-1234"
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
Set a rule to `false` to disable it entirely. All other rules accept `warning` or `error`.
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
## Output formats
|
|
233
|
+
|
|
234
|
+
| Format | Flag | Best for |
|
|
235
|
+
|--------|------|----------|
|
|
236
|
+
| Table (default) | `--output table` | Terminal / CI logs |
|
|
237
|
+
| SARIF | `--output sarif` | GitHub Code Scanning |
|
|
238
|
+
| JSON | `--output json` | Custom integrations, dashboards |
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
## How it works
|
|
243
|
+
|
|
244
|
+
<img width="619" height="813" alt="image" src="https://github.com/user-attachments/assets/07a028e4-5c1f-402e-804e-c9e63148d0aa" />
|
|
245
|
+
|
|
246
|
+
API responses are cached for **6 hours** in `.depenemy_cache/` to avoid rate limits on repeated runs. Use `--no-cache` to force fresh data.
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
## GitHub Token
|
|
251
|
+
|
|
252
|
+
A GitHub token unlocks author account age (R001) and contributor count (R006) checks. Without it, those rules are skipped.
|
|
253
|
+
|
|
254
|
+
```bash
|
|
255
|
+
# CLI
|
|
256
|
+
depenemy scan . --github-token ghp_xxxx
|
|
257
|
+
|
|
258
|
+
# Or via environment variable
|
|
259
|
+
GITHUB_TOKEN=ghp_xxxx depenemy scan .
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
In GitHub Actions, `${{ secrets.GITHUB_TOKEN }}` is available automatically.
|
|
263
|
+
|
|
264
|
+
---
|
|
265
|
+
|
|
266
|
+
## License
|
|
267
|
+
|
|
268
|
+
MIT - see [LICENSE](LICENSE)
|