suphm 0.3.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.
Files changed (70) hide show
  1. suphm-0.3.0/.github/dependabot.yml +27 -0
  2. suphm-0.3.0/.github/workflows/ci.yml +46 -0
  3. suphm-0.3.0/.github/workflows/python-publish.yml +72 -0
  4. suphm-0.3.0/.gitignore +218 -0
  5. suphm-0.3.0/AUTHORS.md +9 -0
  6. suphm-0.3.0/CHANGELOG.md +295 -0
  7. suphm-0.3.0/CODE_OF_CONDUCT.md +133 -0
  8. suphm-0.3.0/CONTRIBUTING.md +147 -0
  9. suphm-0.3.0/LICENSE +661 -0
  10. suphm-0.3.0/PKG-INFO +265 -0
  11. suphm-0.3.0/README.md +224 -0
  12. suphm-0.3.0/docs/API_MIGRATION_GUIDE.md +202 -0
  13. suphm-0.3.0/docs/API_REFERENCE.md +304 -0
  14. suphm-0.3.0/docs/HEALTH_SCORE_CALCULATION.md +219 -0
  15. suphm-0.3.0/docs/METRICS_COMPARISON.md +552 -0
  16. suphm-0.3.0/docs/METRICS_SPECIFICATION.md +3986 -0
  17. suphm-0.3.0/docs/api-integrations.md +562 -0
  18. suphm-0.3.0/docs/commands.md +541 -0
  19. suphm-0.3.0/docs/getting-started.md +356 -0
  20. suphm-0.3.0/docs/github-token-setup.md +482 -0
  21. suphm-0.3.0/docs/serpapi-setup.md +466 -0
  22. suphm-0.3.0/pyproject.toml +90 -0
  23. suphm-0.3.0/src/suphm/__init__.py +3 -0
  24. suphm-0.3.0/src/suphm/analysis/__init__.py +5 -0
  25. suphm-0.3.0/src/suphm/analysis/pipeline.py +470 -0
  26. suphm-0.3.0/src/suphm/cache/__init__.py +5 -0
  27. suphm-0.3.0/src/suphm/cache/manager.py +567 -0
  28. suphm-0.3.0/src/suphm/cli.py +1369 -0
  29. suphm-0.3.0/src/suphm/config.py +276 -0
  30. suphm-0.3.0/src/suphm/core/__init__.py +6 -0
  31. suphm-0.3.0/src/suphm/core/git.py +373 -0
  32. suphm-0.3.0/src/suphm/core/http.py +529 -0
  33. suphm-0.3.0/src/suphm/discovery/__init__.py +6 -0
  34. suphm-0.3.0/src/suphm/discovery/purl.py +274 -0
  35. suphm-0.3.0/src/suphm/discovery/resolver.py +677 -0
  36. suphm-0.3.0/src/suphm/enrichment/__init__.py +5 -0
  37. suphm-0.3.0/src/suphm/enrichment/company.py +272 -0
  38. suphm-0.3.0/src/suphm/metrics/__init__.py +11 -0
  39. suphm-0.3.0/src/suphm/metrics/git.py +758 -0
  40. suphm-0.3.0/src/suphm/metrics/github.py +743 -0
  41. suphm-0.3.0/src/suphm/report/__init__.py +5 -0
  42. suphm-0.3.0/src/suphm/report/generator.py +469 -0
  43. suphm-0.3.0/src/suphm/scanner/__init__.py +5 -0
  44. suphm-0.3.0/src/suphm/scanner/tarball.py +636 -0
  45. suphm-0.3.0/src/suphm/scoring/__init__.py +11 -0
  46. suphm-0.3.0/src/suphm/scoring/burnout.py +464 -0
  47. suphm-0.3.0/src/suphm/scoring/health.py +797 -0
  48. suphm-0.3.0/tests/__init__.py +1 -0
  49. suphm-0.3.0/tests/conftest.py +220 -0
  50. suphm-0.3.0/tests/e2e/__init__.py +1 -0
  51. suphm-0.3.0/tests/e2e/test_workflows.py +375 -0
  52. suphm-0.3.0/tests/integration/__init__.py +1 -0
  53. suphm-0.3.0/tests/integration/test_cli.py +328 -0
  54. suphm-0.3.0/tests/unit/__init__.py +1 -0
  55. suphm-0.3.0/tests/unit/test_analysis.py +287 -0
  56. suphm-0.3.0/tests/unit/test_cache.py +310 -0
  57. suphm-0.3.0/tests/unit/test_cache_path_safety.py +79 -0
  58. suphm-0.3.0/tests/unit/test_config.py +251 -0
  59. suphm-0.3.0/tests/unit/test_discovery.py +231 -0
  60. suphm-0.3.0/tests/unit/test_enrichment.py +150 -0
  61. suphm-0.3.0/tests/unit/test_git_clone.py +250 -0
  62. suphm-0.3.0/tests/unit/test_git_metrics.py +274 -0
  63. suphm-0.3.0/tests/unit/test_github_collector_status.py +189 -0
  64. suphm-0.3.0/tests/unit/test_health_normalization.py +168 -0
  65. suphm-0.3.0/tests/unit/test_http.py +324 -0
  66. suphm-0.3.0/tests/unit/test_pipeline_resilience.py +108 -0
  67. suphm-0.3.0/tests/unit/test_report.py +336 -0
  68. suphm-0.3.0/tests/unit/test_scoring.py +221 -0
  69. suphm-0.3.0/tests/unit/test_tarball.py +240 -0
  70. suphm-0.3.0/tests/unit/test_tarball_security.py +214 -0
@@ -0,0 +1,27 @@
1
+ version: 2
2
+ updates:
3
+ # Keep GitHub Actions up to date so security patches in the actions
4
+ # themselves don't sit waiting for a human bump.
5
+ - package-ecosystem: github-actions
6
+ directory: /
7
+ schedule:
8
+ interval: weekly
9
+ commit-message:
10
+ prefix: "ci"
11
+ groups:
12
+ actions:
13
+ patterns: ["*"]
14
+
15
+ # Python dependencies in pyproject.toml. Grouped to avoid PR sprawl;
16
+ # weekly cadence so noise stays manageable.
17
+ - package-ecosystem: pip
18
+ directory: /
19
+ schedule:
20
+ interval: weekly
21
+ commit-message:
22
+ prefix: "deps"
23
+ groups:
24
+ production:
25
+ dependency-type: production
26
+ development:
27
+ dependency-type: development
@@ -0,0 +1,46 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ # Allow python-publish.yml to reuse this workflow as the pre-publish test gate.
8
+ workflow_call:
9
+
10
+ # Cancel in-progress runs when a new push lands on the same branch/PR.
11
+ concurrency:
12
+ group: ${{ github.workflow }}-${{ github.ref }}
13
+ cancel-in-progress: true
14
+
15
+ permissions:
16
+ contents: read
17
+
18
+ jobs:
19
+ test:
20
+ name: test (py${{ matrix.python-version }})
21
+ runs-on: ubuntu-latest
22
+ strategy:
23
+ fail-fast: false
24
+ matrix:
25
+ python-version: ["3.10", "3.11", "3.12"]
26
+
27
+ steps:
28
+ - uses: actions/checkout@v4
29
+
30
+ - name: Set up Python ${{ matrix.python-version }}
31
+ uses: actions/setup-python@v5
32
+ with:
33
+ python-version: ${{ matrix.python-version }}
34
+ cache: pip
35
+
36
+ - name: Install dev dependencies
37
+ run: pip install -e ".[dev]"
38
+
39
+ - name: Lint (ruff)
40
+ run: ruff check src/ tests/
41
+
42
+ - name: Type-check (mypy)
43
+ run: mypy src/
44
+
45
+ - name: Tests (pytest)
46
+ run: pytest -q
@@ -0,0 +1,72 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ # Two simultaneous releases would race on the same PyPI version.
8
+ concurrency:
9
+ group: ${{ github.workflow }}-${{ github.event.release.tag_name }}
10
+ cancel-in-progress: false
11
+
12
+ permissions:
13
+ contents: read
14
+
15
+ jobs:
16
+ test:
17
+ name: pre-publish tests
18
+ uses: ./.github/workflows/ci.yml
19
+
20
+ build:
21
+ name: build sdist + wheel
22
+ needs: test
23
+ runs-on: ubuntu-latest
24
+
25
+ steps:
26
+ - uses: actions/checkout@v4
27
+
28
+ - name: Set up Python
29
+ uses: actions/setup-python@v5
30
+ with:
31
+ # Pinned to a single supported version for reproducible builds.
32
+ # Bump intentionally; do not use "3.x" (would silently follow
33
+ # whatever the runner ships and could miss our 3.10 floor).
34
+ python-version: "3.12"
35
+
36
+ - name: Build distributions
37
+ run: |
38
+ python -m pip install --upgrade pip
39
+ python -m pip install build
40
+ python -m build
41
+
42
+ - name: Upload dist artifacts
43
+ uses: actions/upload-artifact@v4
44
+ with:
45
+ name: release-dists
46
+ path: dist/
47
+
48
+ publish:
49
+ name: publish to PyPI
50
+ needs: build
51
+ runs-on: ubuntu-latest
52
+ permissions:
53
+ # Trusted Publishing (OIDC) - no PyPI token required in repo secrets.
54
+ # PyPI side: configure a publisher pointing at SemClone/suphm with
55
+ # workflow=python-publish.yml and environment=pypi.
56
+ id-token: write
57
+
58
+ environment:
59
+ name: pypi
60
+ url: https://pypi.org/p/suphm
61
+
62
+ steps:
63
+ - name: Download dist artifacts
64
+ uses: actions/download-artifact@v4
65
+ with:
66
+ name: release-dists
67
+ path: dist/
68
+
69
+ - name: Publish to PyPI
70
+ uses: pypa/gh-action-pypi-publish@release/v1
71
+ with:
72
+ packages-dir: dist/
suphm-0.3.0/.gitignore ADDED
@@ -0,0 +1,218 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[codz]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py.cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ cover/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ .pybuilder/
76
+ target/
77
+
78
+ # Jupyter Notebook
79
+ .ipynb_checkpoints
80
+
81
+ # IPython
82
+ profile_default/
83
+ ipython_config.py
84
+
85
+ # pyenv
86
+ # For a library or package, you might want to ignore these files since the code is
87
+ # intended to run in multiple environments; otherwise, check them in:
88
+ # .python-version
89
+
90
+ # pipenv
91
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
+ # install all needed dependencies.
95
+ #Pipfile.lock
96
+
97
+ # UV
98
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
99
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
100
+ # commonly ignored for libraries.
101
+ #uv.lock
102
+
103
+ # poetry
104
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
105
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
106
+ # commonly ignored for libraries.
107
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
108
+ #poetry.lock
109
+ #poetry.toml
110
+
111
+ # pdm
112
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
113
+ # pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
114
+ # https://pdm-project.org/en/latest/usage/project/#working-with-version-control
115
+ #pdm.lock
116
+ #pdm.toml
117
+ .pdm-python
118
+ .pdm-build/
119
+
120
+ # pixi
121
+ # Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
122
+ #pixi.lock
123
+ # Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
124
+ # in the .venv directory. It is recommended not to include this directory in version control.
125
+ .pixi
126
+
127
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
128
+ __pypackages__/
129
+
130
+ # Celery stuff
131
+ celerybeat-schedule
132
+ celerybeat.pid
133
+
134
+ # SageMath parsed files
135
+ *.sage.py
136
+
137
+ # Environments
138
+ .env
139
+ .envrc
140
+ .venv
141
+ env/
142
+ venv/
143
+ ENV/
144
+ env.bak/
145
+ venv.bak/
146
+
147
+ # Spyder project settings
148
+ .spyderproject
149
+ .spyproject
150
+
151
+ # Rope project settings
152
+ .ropeproject
153
+
154
+ # mkdocs documentation
155
+ /site
156
+
157
+ # mypy
158
+ .mypy_cache/
159
+ .dmypy.json
160
+ dmypy.json
161
+
162
+ # Pyre type checker
163
+ .pyre/
164
+
165
+ # pytype static type analyzer
166
+ .pytype/
167
+
168
+ # Cython debug symbols
169
+ cython_debug/
170
+
171
+ # PyCharm
172
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
173
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
174
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
175
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
176
+ #.idea/
177
+
178
+ # Abstra
179
+ # Abstra is an AI-powered process automation framework.
180
+ # Ignore directories containing user credentials, local state, and settings.
181
+ # Learn more at https://abstra.io/docs
182
+ .abstra/
183
+
184
+ # Visual Studio Code
185
+ # Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
186
+ # that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
187
+ # and can be added to the global gitignore or merged into this file. However, if you prefer,
188
+ # you could uncomment the following to ignore the entire vscode folder
189
+ # .vscode/
190
+
191
+ # Ruff stuff:
192
+ .ruff_cache/
193
+
194
+ # PyPI configuration file
195
+ .pypirc
196
+
197
+ # Cursor
198
+ # Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to
199
+ # exclude from AI features like autocomplete and code analysis. Recommended for sensitive data
200
+ # refer to https://docs.cursor.com/context/ignore-files
201
+ .cursorignore
202
+ .cursorindexingignore
203
+
204
+ # Marimo
205
+ marimo/_static/
206
+ marimo/_lsp/
207
+ __marimo__/
208
+
209
+ # suphm-specific
210
+ # Local analysis output (regenerated on demand; not part of the source).
211
+ analysis_results/
212
+ # Local on-disk cache (default ~/.suphm/, but allow per-repo overrides).
213
+ .suphm/
214
+ # MagicMock paths created if a test accidentally treats a MagicMock as a Path.
215
+ MagicMock/
216
+ # Per-PURL output saved during ad-hoc testing.
217
+ *-result.json
218
+ *-analysis.json
suphm-0.3.0/AUTHORS.md ADDED
@@ -0,0 +1,9 @@
1
+ # Authors
2
+
3
+ ## Project Lead
4
+
5
+ * Oscar Valenzuela B. - Project creator and maintainer
6
+
7
+ ---
8
+
9
+ For a complete list of all contributors, please see the [GitHub contributors page](https://github.com/SemClone/suphm/graphs/contributors).
@@ -0,0 +1,295 @@
1
+ # Changelog
2
+
3
+ ## [Unreleased]
4
+
5
+ ## [0.3.0] - 2026-04-29
6
+
7
+ ### Changed (BREAKING)
8
+
9
+ - **Project renamed** from `ccda-cli` to `suphm` (Supply Chain Health Metrics).
10
+ The repo also moved from `SemClone/ccda-cli` to `SemClone/suphm`.
11
+ - Python package: `ccda_cli` → `suphm`. All imports change.
12
+ ```python
13
+ # before
14
+ from ccda_cli.metrics.git import GitMetricsAnalyzer
15
+ # after
16
+ from suphm.metrics.git import GitMetricsAnalyzer
17
+ ```
18
+ - CLI entry point: `ccda-cli` → `suphm`. Update any scripts.
19
+ - Distribution name on PyPI: `ccda-cli` → `suphm` (new package; the old one
20
+ will not be updated further).
21
+ - Cache directory: `~/.ccda/` → `~/.suphm/`. Existing caches are not migrated;
22
+ delete the old directory or copy contents over manually.
23
+ - Project config file: `./ccda-config.yaml` → `./suphm-config.yaml`.
24
+ - Environment variables:
25
+ - `CCDA_GITHUB_TOKEN` → `SUPHM_GITHUB_TOKEN`
26
+ - `CCDA_SERPAPI_KEY` → `SUPHM_SERPAPI_KEY`
27
+ - `CCDA_CACHE_DIR` → `SUPHM_CACHE_DIR`
28
+ - `GITHUB_TOKEN` continues to work as a fallback.
29
+ - Repo-clone metadata file in cache: `.ccda-metadata.json` → `.suphm-metadata.json`.
30
+ Repos cloned by older versions will be re-cloned on first use.
31
+
32
+ ## [0.2.2] - 2026-01-14
33
+
34
+ ### Fixed
35
+
36
+ - **Critical**: Fixed malformed GitHub URLs with `git+` prefix causing clone failures
37
+ - Discovery stage now properly normalizes GitHub URLs by stripping `git+` prefix
38
+ - Removes `.git` suffix and trailing paths (`/issues`, `/pulls`, `/wiki`, etc.)
39
+ - Replaces `git://` protocol with `https://`
40
+ - Affects all npm packages and potentially other ecosystems
41
+ - Missing metrics restored: Bus Factor, Pony Factor, Elephant Factor, Commit Activity, Contributor Retention, License Stability
42
+ - Now collecting all 10 health metrics instead of only 4 for affected packages
43
+ - Added `_normalize_github_url()` helper function in `discovery/resolver.py`
44
+ - Applied normalization to all repository URL assignments across all discovery sources
45
+
46
+ ## [0.2.1] - 2026-01-13
47
+
48
+ ### Fixed
49
+
50
+ - **Critical**: Fixed pkg:github package analysis failure with 'ecosystem' parameter error
51
+ - Fixed `_github_discovery_step` in `pipeline.py` passing invalid parameters to `DiscoveryResult`
52
+ - Removed non-existent `ecosystem` parameter
53
+ - Changed `github_url` to correct `repository_url` parameter
54
+ - Removed non-existent `success` parameter
55
+ - Changed `metadata` to correct `registry_data` parameter
56
+ - Added required `version` parameter
57
+ - GitHub packages like `pkg:github/hashicorp/terraform` now analyze successfully
58
+
59
+ ## [0.2.0] - 2026-01-13
60
+
61
+ ### Added
62
+
63
+ - **Phase 4 Metric A.6: Review Turnaround Time**
64
+ - New `avg_review_turnaround_hours` metric in pull request data
65
+ - New `median_review_turnaround_hours` metric in pull request data
66
+ - Track `prs_with_reviews` and `prs_without_reviews` counts
67
+ - Samples up to 50 recent PRs to calculate time from PR creation to first review
68
+ - Handles APPROVED, CHANGES_REQUESTED, and COMMENTED review states
69
+
70
+ - **Phase 4 Metric A.8: New Contributor Rate**
71
+ - New `new_contributors_count` metric in time window data (90d, 180d, 365d)
72
+ - New `new_contributors_per_month` metric showing monthly rate
73
+ - New `contributor_growth_rate` showing percentage of contributors who are new
74
+ - Tracks contributors whose first commit falls within each time window
75
+
76
+ ### Changed
77
+
78
+ - Enhanced `PullRequestMetrics` dataclass with review turnaround fields
79
+ - Added `get_pull_reviews()` method to `GitHubClient` for fetching PR reviews
80
+ - Enhanced `TimeWindowMetrics` dataclass with new contributor rate fields
81
+
82
+ ## [0.1.10] - 2026-01-12
83
+
84
+ ### Fixed
85
+
86
+ - **Critical**: Fixed golang package GitHub metrics discovery
87
+ - Fixed `depsdev_ecosystem` property to handle "golang" vs "go" type mismatch
88
+ - Fixed `_discover_from_depsdev` to support both "go" and "golang" types
89
+ - Golang packages now correctly infer GitHub URL from package namespace
90
+ - Example: `pkg:golang/github.com/gin-gonic/gin` now discovers `https://github.com/gin-gonic/gin`
91
+ - Root cause: packageurl library returns `type="golang"` but code only checked for `"go"`
92
+
93
+ ## [0.1.9] - 2026-01-12
94
+
95
+ ### Changed
96
+
97
+ - Version bump to publish GitHub PURL support to PyPI
98
+ - No code changes from 0.1.8 (which included the GitHub PURL feature but was not published with it)
99
+
100
+ ## [0.1.8] - 2026-01-12
101
+
102
+ ### Added
103
+
104
+ - **Native pkg:github/* PURL support** for direct GitHub package analysis
105
+ - Early PURL detection in `AnalysisPipeline.analyze()` to identify GitHub packages
106
+ - New `_analyze_github_package()` method for specialized GitHub package analysis
107
+ - New `_github_discovery_step()` helper for minimal discovery without external API calls
108
+ - Direct GitHub API access for metrics collection (no tarball download required)
109
+ - Simplified 3-step pipeline for GitHub packages: Discovery → GitHub Metrics → Health Score
110
+
111
+ ### Changed
112
+
113
+ - GitHub packages now skip package registry discovery (not needed for pkg:github/*)
114
+ - GitHub packages no longer require tarball download or git cloning
115
+ - Analysis time for GitHub packages reduced from ~80s to ~10s
116
+
117
+ ### Fixed
118
+
119
+ - Analysis failures for GitHub PURLs like `pkg:github/hashicorp/terraform` and `pkg:github/actions/checkout`
120
+ - Unnecessary package registry lookups for GitHub-native packages
121
+
122
+ ## [0.1.7] - 2026-01-05
123
+
124
+ ### Fixed
125
+
126
+ - **Critical**: Fixed company affiliation enrichment silently failing
127
+ - Company enrichment was not working due to async/await execution context issue
128
+ - `_enrich_contributors()` was calling async code from within an executor thread
129
+ - Added proper event loop detection and thread-safe async execution
130
+ - Now correctly handles both standalone and executor-based execution contexts
131
+ - Company data now properly populates in metrics output
132
+
133
+ ## [0.1.6] - 2026-01-05
134
+
135
+ ### Added
136
+
137
+ - **Company affiliation enrichment** via GitHub API (optional, requires GitHub token)
138
+ - Automatically enriches contributor data with company information from GitHub user profiles
139
+ - Extracts GitHub usernames from commit emails (e.g., `username@users.noreply.github.com`)
140
+ - Fetches user profiles from GitHub API in batch to minimize API calls
141
+ - Caches user profiles for 30 days to avoid duplicate requests
142
+ - Normalizes company names using configurable mappings (e.g., "@google" → "Google")
143
+ - Respects GitHub API rate limits and degrades gracefully
144
+ - Falls back to email domain detection when API unavailable or rate limited
145
+ - Provides more accurate elephant factor and company distribution metrics
146
+ - New `CompanyEnricher` class in `ccda_cli.enrichment.company` module
147
+ - Configuration option `github.enrich_company_affiliation` (default: true when token provided)
148
+ - Comprehensive test suite for company enrichment (16 unit tests)
149
+ - Enhanced documentation in `docs/github-token-setup.md` with company enrichment examples
150
+
151
+ ### Changed
152
+
153
+ - `GitMetricsAnalyzer` now accepts optional `github_token` parameter for enrichment
154
+ - Company detection now prioritizes GitHub API data over email domain mapping (when token available)
155
+ - Updated README.md to highlight company affiliation enrichment feature
156
+
157
+ ## [0.1.5] - 2026-01-05
158
+
159
+ ### Added
160
+
161
+ - **osslili as required dependency** for professional license detection
162
+ - Replaced brittle pattern-matching with osslili's Python API
163
+ - Accurate SPDX license identification with confidence scores
164
+ - Copyright statement extraction
165
+ - Support for all osslili detection methods (metadata, file analysis, keyword matching)
166
+
167
+ ### Fixed
168
+
169
+ - **Critical**: Cargo package tarball scanning now works correctly
170
+ - Fixed `.crate` file download from crates.io (was downloading as `download` with no extension)
171
+ - Added `.crate` extension support to archive extraction
172
+ - Enhanced download URL detection to handle redirects properly (checks Content-Disposition header and final redirect URL)
173
+ - License file detection now works for all ecosystems
174
+ - Removed incomplete `LICENSE_PATTERNS` that missed common patterns like `LICENSE-MIT`, `LICENSE-APACHE`
175
+ - Now uses osslili for comprehensive license file discovery
176
+ - Relative path display in scan results (shows `serde-1.0.228/LICENSE-MIT` instead of full temp paths)
177
+
178
+ ### Changed
179
+
180
+ - **Breaking**: osslili is now a required dependency (previously optional)
181
+ - **Breaking**: purl2src is now a required dependency (previously optional)
182
+ - Removed optional dependency groups `scanner` and `all`
183
+ - Tarball scanner completely refactored to use osslili Python API
184
+ - Deleted 200+ lines of brittle pattern-matching code
185
+ - Removed fallback license detection methods
186
+ - Scan method now always reports `osslili`
187
+ - Cleaned up unused code and imports from tarball scanner
188
+
189
+ ### Removed
190
+
191
+ - Removed obsolete methods: `_check_tool`, `_resolve_command`, `_build_command`, `_run_external_tool`, `_run_osslili`, `_run_upmex`, `_apply_osslili_results`, `_apply_upmex_results`, `_analyze_license_file`
192
+ - Removed `LICENSE_PATTERNS` and `COPYRIGHT_PATTERNS` constants
193
+ - Removed support for external tool command-line integration (now uses Python APIs directly)
194
+
195
+ ## [0.1.4] - 2026-01-04
196
+
197
+ ### Added
198
+
199
+ - **purl2src integration** for automatic download URL discovery
200
+ - Integrated purl2src library as optional dependency
201
+ - Tarball scanner now auto-discovers download URLs from PURLs
202
+ - Fallback to PackageResolver if purl2src unavailable
203
+ - New optional dependency group: `scanner` and `all`
204
+ - Crates.io (Rust Cargo) package discovery integration
205
+ - Full metadata extraction from crates.io API
206
+ - Registry data snapshot including downloads, keywords, and categories
207
+ - Tarball URL resolution for package scanning
208
+ - Enhanced tarball scanner with external tool integration support
209
+ - Support for osslili and upmex external scanning tools
210
+ - Dynamic scan method tracking (builtin, osslili, upmex, or combined)
211
+ - Improved license detection and binary file analysis
212
+
213
+ ### Fixed
214
+
215
+ - Test suite compatibility with Python 3.14
216
+ - Virtual environment setup and package installation workflow
217
+
218
+ ## [0.1.3] - 2026-01-04
219
+
220
+ ### Added
221
+
222
+ - Dynamic API sampling based on GitHub token authentication status
223
+ - Authenticated (5000 calls/hr): Fetches up to 5000 issues, 5000 PRs, 2000 closed issues
224
+ - Unauthenticated (60 calls/hr): Conservative limits of 300 items per category
225
+ - Sampling metadata in JSON output for transparency
226
+ - `_sampling` field in `IssueMetrics` showing sample size vs total count
227
+ - `_sampling` field in `PullRequestMetrics` with coverage information
228
+ - Coverage percentage indicator for quality assessment
229
+
230
+ ### Fixed
231
+
232
+ - **Critical**: Metrics severely underreported due to hard-coded 300-item limit regardless of token
233
+ - Issue sample size increased from 300 to 5000 when authenticated (16x improvement)
234
+ - PR sample size increased from 300 to 5000 when authenticated (16x improvement)
235
+ - Unlabeled rate now calculated from proper sample size
236
+ - Unresponded rate now reflects larger sample for better accuracy
237
+ - Burnout score `issue_backlog` now uses adjusted full count instead of sampled count
238
+ - PR counts (open/merged/closed) now reflect comprehensive data instead of first 300 items
239
+
240
+ ### Changed
241
+
242
+ - `IssueMetrics` dataclass now includes `sampled_open_count` and `sampled_closed_count` fields
243
+ - `PullRequestMetrics` dataclass now includes `sampled_count` field
244
+ - GitHub API collector now adapts page limits based on token availability
245
+
246
+ ## [0.1.2] - 2026-01-04
247
+
248
+ ### Fixed
249
+
250
+ - Use actual `open_issues_count` from GitHub repo API instead of sampled count (max 300)
251
+ - Subtract open PRs from issue count for accurate totals
252
+ - Fixes incorrect burnout score `issue_backlog` calculation
253
+
254
+ ## [0.1.1] - 2026-01-04
255
+
256
+ ### Added
257
+
258
+ - `chaoss_metrics` field to `HealthScoreResult` containing bus_factor, pony_factor, elephant_factor, and contributor_count
259
+ - `extended_metrics` field to `HealthScoreResult` containing commit_frequency, commits_per_day, pr_velocity, median_pr_merge_hours, branch_protected, and has_signed_releases
260
+ - Helper methods `_classify_frequency()` and `_classify_velocity()` for categorizing activity levels
261
+
262
+ ### Fixed
263
+
264
+ - Dashboard template compatibility by exposing CHAOSS and extended metrics in health score output (#1)
265
+
266
+ ## [0.1.0] - 2026-01-03
267
+
268
+ ### Initial Release
269
+
270
+ First public release of ccda-cli - Supply Chain Security Metrics tool.
271
+
272
+ ### Features
273
+
274
+ - Multi-ecosystem package analysis (npm, PyPI, Cargo, Maven, Go)
275
+ - Health score calculation (0-100) based on commit activity, contributor diversity, and community health
276
+ - Burnout score detection for maintainer sustainability risk assessment
277
+ - CHAOSS metrics computation (bus factor, pony factor, elephant factor)
278
+ - GitHub API integration for community health indicators (stars, forks, issues, PRs)
279
+ - Package tarball scanning for license compliance and binary detection
280
+ - Multiple discovery sources (deps.dev, ecosyste.ms, package registries, SerpAPI fallback)
281
+ - CLI commands: analyze, discover, cache management
282
+ - JSON output format for integration with other tools
283
+ - Comprehensive documentation and usage examples
284
+
285
+ ### Documentation
286
+
287
+ - Complete README with installation and usage instructions
288
+ - Contribution guidelines (CONTRIBUTING.md)
289
+ - Code of Conduct (CODE_OF_CONDUCT.md)
290
+ - Authors and credits (AUTHORS.md)
291
+ - Detailed documentation for API integrations and configuration
292
+
293
+ ### License
294
+
295
+ GNU Affero General Public License v3.0