github-license-scanner 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.
- github_license_scanner-0.1.0/.gitignore +38 -0
- github_license_scanner-0.1.0/LICENSE +21 -0
- github_license_scanner-0.1.0/PKG-INFO +307 -0
- github_license_scanner-0.1.0/README.md +281 -0
- github_license_scanner-0.1.0/gls/__init__.py +1 -0
- github_license_scanner-0.1.0/gls/auth.py +229 -0
- github_license_scanner-0.1.0/gls/cli.py +358 -0
- github_license_scanner-0.1.0/gls/config.py +161 -0
- github_license_scanner-0.1.0/gls/dependency_scanner.py +621 -0
- github_license_scanner-0.1.0/gls/deploy_advisor.py +286 -0
- github_license_scanner-0.1.0/gls/docs/LEGAL_DISCLAIMER.md +57 -0
- github_license_scanner-0.1.0/gls/docs/PRIVACY.md +69 -0
- github_license_scanner-0.1.0/gls/docs/TERMS.md +52 -0
- github_license_scanner-0.1.0/gls/github_api.py +514 -0
- github_license_scanner-0.1.0/gls/history_store.py +177 -0
- github_license_scanner-0.1.0/gls/i18n.py +530 -0
- github_license_scanner-0.1.0/gls/license_analyzer.py +855 -0
- github_license_scanner-0.1.0/gls/models.py +148 -0
- github_license_scanner-0.1.0/gls/rate_limit.py +64 -0
- github_license_scanner-0.1.0/gls/report.py +150 -0
- github_license_scanner-0.1.0/gls/sbom_export.py +312 -0
- github_license_scanner-0.1.0/gls/spdx_engine.py +441 -0
- github_license_scanner-0.1.0/gls/webui.py +1828 -0
- github_license_scanner-0.1.0/pyproject.toml +49 -0
- github_license_scanner-0.1.0/requirements.txt +9 -0
- github_license_scanner-0.1.0/scripts/generate_audit_pdf.py +479 -0
- github_license_scanner-0.1.0/scripts/smoke_features.py +59 -0
- github_license_scanner-0.1.0/scripts/verify_app.py +346 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
.Python
|
|
7
|
+
.venv/
|
|
8
|
+
venv/
|
|
9
|
+
ENV/
|
|
10
|
+
env/
|
|
11
|
+
*.egg-info/
|
|
12
|
+
.eggs/
|
|
13
|
+
dist/
|
|
14
|
+
build/
|
|
15
|
+
|
|
16
|
+
# NiceGUI
|
|
17
|
+
.nicegui/
|
|
18
|
+
|
|
19
|
+
# Local data / secrets
|
|
20
|
+
.env
|
|
21
|
+
.env.*
|
|
22
|
+
!.env.example
|
|
23
|
+
data/history.json
|
|
24
|
+
data/history/
|
|
25
|
+
data/users.json
|
|
26
|
+
|
|
27
|
+
# IDE / OS
|
|
28
|
+
.idea/
|
|
29
|
+
.vscode/
|
|
30
|
+
*.swp
|
|
31
|
+
.DS_Store
|
|
32
|
+
Thumbs.db
|
|
33
|
+
|
|
34
|
+
# Logs / temp
|
|
35
|
+
*.log
|
|
36
|
+
.pytest_cache/
|
|
37
|
+
.mypy_cache/
|
|
38
|
+
.ruff_cache/
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 NezbiT
|
|
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,307 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: github-license-scanner
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Analyze GitHub repo and dependency licenses, copyleft risk, and closed-source sellability.
|
|
5
|
+
Project-URL: Homepage, https://github.com/NezbiT/github-license-scanner
|
|
6
|
+
Project-URL: Issues, https://github.com/NezbiT/github-license-scanner/issues
|
|
7
|
+
Author: Mario Alvarez
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Keywords: agpl,compliance,copyleft,dependencies,gpl,license,sbom
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
18
|
+
Requires-Python: >=3.11
|
|
19
|
+
Requires-Dist: httpx>=0.27.0
|
|
20
|
+
Requires-Dist: packaging>=24.0
|
|
21
|
+
Requires-Dist: platformdirs>=4.0
|
|
22
|
+
Requires-Dist: python-dotenv>=1.0.0
|
|
23
|
+
Provides-Extra: ui
|
|
24
|
+
Requires-Dist: nicegui>=2.0.0; extra == 'ui'
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
|
|
27
|
+
# GitHub License Scanner
|
|
28
|
+
|
|
29
|
+
<p align="center">
|
|
30
|
+
<img src="docs/images/hero.jpg" alt="GitHub License Scanner hero banner" width="100%" />
|
|
31
|
+
</p>
|
|
32
|
+
|
|
33
|
+
<p align="center">
|
|
34
|
+
<strong>Analyze GitHub repo licenses + dependencies</strong><br/>
|
|
35
|
+
Know if you can sell closed-source — or if copyleft (GPL / AGPL) forces open source.<br/>
|
|
36
|
+
<em>NiceGUI web UI · CLI · bilingual ES/EN · light & dark mode</em>
|
|
37
|
+
</p>
|
|
38
|
+
|
|
39
|
+
<p align="center">
|
|
40
|
+
<a href="#quick-start"><img src="https://img.shields.io/badge/Python-3.11%2B-2c3e50?style=flat-square" alt="Python" /></a>
|
|
41
|
+
<a href="#web-ui"><img src="https://img.shields.io/badge/UI-NiceGUI-8b5e3c?style=flat-square" alt="NiceGUI" /></a>
|
|
42
|
+
<a href="#cli"><img src="https://img.shields.io/badge/CLI-supported-3f6f4e?style=flat-square" alt="CLI" /></a>
|
|
43
|
+
<a href="#disclaimer"><img src="https://img.shields.io/badge/Not-legal%20advice-9b2c2c?style=flat-square" alt="Disclaimer" /></a>
|
|
44
|
+
<a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-2c3e50?style=flat-square" alt="MIT License" /></a>
|
|
45
|
+
</p>
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Screenshots
|
|
50
|
+
|
|
51
|
+
### Light workspace (full-width layout)
|
|
52
|
+
|
|
53
|
+
<p align="center">
|
|
54
|
+
<img src="docs/images/ui-light.jpg" alt="Light mode UI — scan workspace and results" width="100%" />
|
|
55
|
+
</p>
|
|
56
|
+
|
|
57
|
+
### Dark mode
|
|
58
|
+
|
|
59
|
+
<p align="center">
|
|
60
|
+
<img src="docs/images/ui-dark.jpg" alt="Dark mode UI — copyleft warning and package groups" width="100%" />
|
|
61
|
+
</p>
|
|
62
|
+
|
|
63
|
+
### How it works
|
|
64
|
+
|
|
65
|
+
<p align="center">
|
|
66
|
+
<img src="docs/images/flow.jpg" alt="Flow: URL → fetch → registries → verdict → deploy" width="100%" />
|
|
67
|
+
</p>
|
|
68
|
+
|
|
69
|
+
| Step | What happens |
|
|
70
|
+
|------|----------------|
|
|
71
|
+
| 1 | Paste a GitHub URL (`owner/repo`) |
|
|
72
|
+
| 2 | Read repo license + dependency manifests |
|
|
73
|
+
| 3 | Look up package licenses on npm, PyPI, crates.io, … |
|
|
74
|
+
| 4 | Verdict: closed sale OK vs strong copyleft |
|
|
75
|
+
| 5 | Deploy tips + copyright notice to copy |
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Features
|
|
80
|
+
|
|
81
|
+
- **Repo license** via GitHub REST API
|
|
82
|
+
- **Dependency scan** for `package.json`, `requirements.txt`, `pyproject.toml`, `Cargo.toml`, `go.mod`, `Gemfile`, `composer.json`, Maven/Gradle (best-effort)
|
|
83
|
+
- **Registry license lookup** (npm, PyPI, crates.io, RubyGems, Packagist)
|
|
84
|
+
- **Risk colors**: green (permissive) · orange (weak/unknown) · red (strong copyleft)
|
|
85
|
+
- **Closed-source sellability** signal + GPL/AGPL force-open flag
|
|
86
|
+
- **Permissive replacement** suggestions for problematic packages
|
|
87
|
+
- **Batch mode** (many URLs) + **scan history**
|
|
88
|
+
- **Copy copyright notice** button
|
|
89
|
+
- **Deploy advisor** (Vercel, Railway, Render, Fly.io, …)
|
|
90
|
+
- **ES / EN** UI · **light / dark** theme · **full-width** responsive layout
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## Quick start
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
pipx install github-license-scanner
|
|
98
|
+
gls scan psf/requests
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
The web interface is an optional extra, so the CLI stays light:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
pipx install 'github-license-scanner[ui]'
|
|
105
|
+
gls ui
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Optional configuration (recommended):
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
# PowerShell example
|
|
112
|
+
$env:GITHUB_TOKEN = "ghp_..."
|
|
113
|
+
$env:GLS_STORAGE_SECRET = "long-random-string"
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Environment variables are the source of truth. A `.env` file is only a local
|
|
117
|
+
convenience: one is read from the current directory or from your user config
|
|
118
|
+
directory if present, and real environment variables always win.
|
|
119
|
+
|
|
120
|
+
| Variable | Purpose |
|
|
121
|
+
|----------|---------|
|
|
122
|
+
| `GITHUB_TOKEN` | Higher GitHub API rate limits / private repos |
|
|
123
|
+
| `GLS_STORAGE_SECRET` | Signs session cookies (**required** for public deploys) |
|
|
124
|
+
| `GLS_HOST` / `GLS_PORT` | Bind address (default `127.0.0.1:8080`) |
|
|
125
|
+
| `GLS_MAX_BATCH_URLS` | Cap batch scans (default 15) |
|
|
126
|
+
| `GLS_RATE_LIMIT_SCANS` | Scans per window per client (default 20/hour) |
|
|
127
|
+
| `GLS_AUTH_ENABLED` | Require web login (`1` / `true`) |
|
|
128
|
+
| `GLS_USERS_FILE` | JSON users DB (default: `users.json` in the data dir) |
|
|
129
|
+
| `GLS_DATA_DIR` | Override where history and users are stored |
|
|
130
|
+
|
|
131
|
+
See [`.env.example`](.env.example) for the full list.
|
|
132
|
+
|
|
133
|
+
History and users live in your per-user data directory, never inside the
|
|
134
|
+
installed package:
|
|
135
|
+
|
|
136
|
+
| OS | Path |
|
|
137
|
+
|----|------|
|
|
138
|
+
| Windows | `%LOCALAPPDATA%\NezbiT\github-license-scanner` |
|
|
139
|
+
| macOS | `~/Library/Application Support/github-license-scanner` |
|
|
140
|
+
| Linux | `~/.local/share/github-license-scanner` |
|
|
141
|
+
|
|
142
|
+
### Multi-user auth + private history
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
gls user-add alice # interactive password (≥8 chars)
|
|
146
|
+
|
|
147
|
+
export GLS_AUTH_ENABLED=1
|
|
148
|
+
export GLS_STORAGE_SECRET=long-random-string
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Each user gets `history/<username>.json` in that data directory. Without auth,
|
|
152
|
+
history stays in a single `history.json`.
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## Web UI
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
pipx install 'github-license-scanner[ui]'
|
|
160
|
+
gls ui # or: gls ui --host 0.0.0.0 --port 9000
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Open **[http://127.0.0.1:8080](http://127.0.0.1:8080)** (binds to localhost by default)
|
|
164
|
+
|
|
165
|
+
- Switch **ES | EN** in the top bar
|
|
166
|
+
- Toggle **light / dark** with the sun/moon button
|
|
167
|
+
- Try example chips (`psf/requests`, `encode/httpx`, …)
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## CLI
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
# Single repository
|
|
175
|
+
gls scan https://github.com/psf/requests
|
|
176
|
+
|
|
177
|
+
# Shorthand
|
|
178
|
+
gls scan psf/requests
|
|
179
|
+
|
|
180
|
+
# Batch (one URL per line)
|
|
181
|
+
gls batch urls.example.txt
|
|
182
|
+
|
|
183
|
+
# History
|
|
184
|
+
gls history
|
|
185
|
+
|
|
186
|
+
# Markdown + SBOM export
|
|
187
|
+
gls scan psf/requests --markdown report.md --sbom bom.cdx.json
|
|
188
|
+
gls scan psf/requests --sbom bom.spdx.json --sbom-format spdx
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
`github-license-scanner` is available as a longer alias for `gls`.
|
|
192
|
+
|
|
193
|
+
| Exit code | Meaning |
|
|
194
|
+
|-----------|---------|
|
|
195
|
+
| `0` | No strong copyleft force-open signal |
|
|
196
|
+
| `1` | Strong copyleft detected |
|
|
197
|
+
| `2` | Hard failure (bad URL, API error, …) |
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## Project layout
|
|
202
|
+
|
|
203
|
+
```text
|
|
204
|
+
github-license-scanner/
|
|
205
|
+
├── pyproject.toml # Packaging (hatchling)
|
|
206
|
+
├── gls/
|
|
207
|
+
│ ├── __init__.py # __version__
|
|
208
|
+
│ ├── cli.py # Command-line mode + entry point
|
|
209
|
+
│ ├── webui.py # NiceGUI interface (optional [ui] extra)
|
|
210
|
+
│ ├── config.py # Env-based configuration + data paths
|
|
211
|
+
│ ├── rate_limit.py # Scan rate limiter
|
|
212
|
+
│ ├── auth.py # Optional multi-user auth (PBKDF2)
|
|
213
|
+
│ ├── spdx_engine.py # SPDX expression parser + risk
|
|
214
|
+
│ ├── sbom_export.py # CycloneDX 1.5 + SPDX 2.3 JSON
|
|
215
|
+
│ ├── github_api.py # URL parse + GitHub REST
|
|
216
|
+
│ ├── dependency_scanner.py # Manifest parsers
|
|
217
|
+
│ ├── license_analyzer.py # Registry licenses + verdict
|
|
218
|
+
│ ├── deploy_advisor.py # Deploy recommendations
|
|
219
|
+
│ ├── history_store.py # JSON history (shared or per-user)
|
|
220
|
+
│ ├── models.py # Dataclasses
|
|
221
|
+
│ ├── i18n.py # ES/EN strings
|
|
222
|
+
│ ├── report.py # Markdown export
|
|
223
|
+
│ └── docs/ # Legal pages served by the web UI
|
|
224
|
+
│ ├── LEGAL_DISCLAIMER.md
|
|
225
|
+
│ ├── PRIVACY.md
|
|
226
|
+
│ └── TERMS.md
|
|
227
|
+
├── scripts/ # Dev smoke tests / audit tooling
|
|
228
|
+
├── .env.example
|
|
229
|
+
├── urls.example.txt
|
|
230
|
+
└── docs/
|
|
231
|
+
├── AUDIT_REPORT.pdf
|
|
232
|
+
└── images/ # README screenshots
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
## License risk legend
|
|
238
|
+
|
|
239
|
+
| Color | Risk | Examples |
|
|
240
|
+
|-------|------|----------|
|
|
241
|
+
| Green | Permissive | MIT, Apache-2.0, BSD, ISC |
|
|
242
|
+
| Orange | Weak copyleft / unknown | LGPL, MPL, EUPL, missing metadata |
|
|
243
|
+
| Red | Strong copyleft | GPL, AGPL, SSPL |
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
## Security & privacy notes
|
|
248
|
+
|
|
249
|
+
- Default bind is **localhost only** (`GLS_HOST=127.0.0.1`).
|
|
250
|
+
- Set a strong **`GLS_STORAGE_SECRET`** before exposing the UI.
|
|
251
|
+
- Scan history is **instance-local** and shared if multi-user — use **Clear history** or prune via config.
|
|
252
|
+
- Rate limits and batch caps reduce GitHub API abuse.
|
|
253
|
+
- Docs: [Privacy](gls/docs/PRIVACY.md) · [Terms](gls/docs/TERMS.md) · [Legal disclaimer](gls/docs/LEGAL_DISCLAIMER.md)
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
## Disclaimer
|
|
258
|
+
|
|
259
|
+
This tool provides **automated heuristics only**. It is **not legal advice** and not a
|
|
260
|
+
license-compatibility opinion. Dual-licensing, linking models, SaaS (AGPL/SSPL),
|
|
261
|
+
attribution duties, and contracts can change obligations.
|
|
262
|
+
Always review with a qualified attorney before commercial closed-source distribution.
|
|
263
|
+
See [gls/docs/LEGAL_DISCLAIMER.md](gls/docs/LEGAL_DISCLAIMER.md).
|
|
264
|
+
|
|
265
|
+
---
|
|
266
|
+
|
|
267
|
+
## Development
|
|
268
|
+
|
|
269
|
+
```bash
|
|
270
|
+
git clone https://github.com/NezbiT/github-license-scanner.git
|
|
271
|
+
cd github-license-scanner
|
|
272
|
+
|
|
273
|
+
python -m venv .venv
|
|
274
|
+
.venv\Scripts\activate # macOS / Linux: source .venv/bin/activate
|
|
275
|
+
|
|
276
|
+
pip install -e '.[ui]'
|
|
277
|
+
python -m gls.cli scan psf/requests
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
Build and check a release locally before tagging:
|
|
281
|
+
|
|
282
|
+
```bash
|
|
283
|
+
pip install build twine
|
|
284
|
+
python -m build
|
|
285
|
+
twine check dist/*
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
Releases are published to PyPI by [`.github/workflows/publish.yml`](.github/workflows/publish.yml)
|
|
289
|
+
using Trusted Publishing (OIDC) — no API tokens are stored anywhere.
|
|
290
|
+
|
|
291
|
+
---
|
|
292
|
+
|
|
293
|
+
## License
|
|
294
|
+
|
|
295
|
+
Released under the **[MIT License](LICENSE)**.
|
|
296
|
+
|
|
297
|
+
You may use, modify, and redistribute this project commercially or privately,
|
|
298
|
+
as long as you keep the copyright and license notice. See `LICENSE` for full text.
|
|
299
|
+
|
|
300
|
+
> The MIT license applies to **this tool’s source code**.
|
|
301
|
+
> It does **not** change the licenses of the GitHub repositories or packages you scan.
|
|
302
|
+
|
|
303
|
+
---
|
|
304
|
+
|
|
305
|
+
<p align="center">
|
|
306
|
+
Made with NiceGUI · httpx · packaging
|
|
307
|
+
</p>
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
# GitHub License Scanner
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<img src="docs/images/hero.jpg" alt="GitHub License Scanner hero banner" width="100%" />
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
<strong>Analyze GitHub repo licenses + dependencies</strong><br/>
|
|
9
|
+
Know if you can sell closed-source — or if copyleft (GPL / AGPL) forces open source.<br/>
|
|
10
|
+
<em>NiceGUI web UI · CLI · bilingual ES/EN · light & dark mode</em>
|
|
11
|
+
</p>
|
|
12
|
+
|
|
13
|
+
<p align="center">
|
|
14
|
+
<a href="#quick-start"><img src="https://img.shields.io/badge/Python-3.11%2B-2c3e50?style=flat-square" alt="Python" /></a>
|
|
15
|
+
<a href="#web-ui"><img src="https://img.shields.io/badge/UI-NiceGUI-8b5e3c?style=flat-square" alt="NiceGUI" /></a>
|
|
16
|
+
<a href="#cli"><img src="https://img.shields.io/badge/CLI-supported-3f6f4e?style=flat-square" alt="CLI" /></a>
|
|
17
|
+
<a href="#disclaimer"><img src="https://img.shields.io/badge/Not-legal%20advice-9b2c2c?style=flat-square" alt="Disclaimer" /></a>
|
|
18
|
+
<a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-2c3e50?style=flat-square" alt="MIT License" /></a>
|
|
19
|
+
</p>
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Screenshots
|
|
24
|
+
|
|
25
|
+
### Light workspace (full-width layout)
|
|
26
|
+
|
|
27
|
+
<p align="center">
|
|
28
|
+
<img src="docs/images/ui-light.jpg" alt="Light mode UI — scan workspace and results" width="100%" />
|
|
29
|
+
</p>
|
|
30
|
+
|
|
31
|
+
### Dark mode
|
|
32
|
+
|
|
33
|
+
<p align="center">
|
|
34
|
+
<img src="docs/images/ui-dark.jpg" alt="Dark mode UI — copyleft warning and package groups" width="100%" />
|
|
35
|
+
</p>
|
|
36
|
+
|
|
37
|
+
### How it works
|
|
38
|
+
|
|
39
|
+
<p align="center">
|
|
40
|
+
<img src="docs/images/flow.jpg" alt="Flow: URL → fetch → registries → verdict → deploy" width="100%" />
|
|
41
|
+
</p>
|
|
42
|
+
|
|
43
|
+
| Step | What happens |
|
|
44
|
+
|------|----------------|
|
|
45
|
+
| 1 | Paste a GitHub URL (`owner/repo`) |
|
|
46
|
+
| 2 | Read repo license + dependency manifests |
|
|
47
|
+
| 3 | Look up package licenses on npm, PyPI, crates.io, … |
|
|
48
|
+
| 4 | Verdict: closed sale OK vs strong copyleft |
|
|
49
|
+
| 5 | Deploy tips + copyright notice to copy |
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Features
|
|
54
|
+
|
|
55
|
+
- **Repo license** via GitHub REST API
|
|
56
|
+
- **Dependency scan** for `package.json`, `requirements.txt`, `pyproject.toml`, `Cargo.toml`, `go.mod`, `Gemfile`, `composer.json`, Maven/Gradle (best-effort)
|
|
57
|
+
- **Registry license lookup** (npm, PyPI, crates.io, RubyGems, Packagist)
|
|
58
|
+
- **Risk colors**: green (permissive) · orange (weak/unknown) · red (strong copyleft)
|
|
59
|
+
- **Closed-source sellability** signal + GPL/AGPL force-open flag
|
|
60
|
+
- **Permissive replacement** suggestions for problematic packages
|
|
61
|
+
- **Batch mode** (many URLs) + **scan history**
|
|
62
|
+
- **Copy copyright notice** button
|
|
63
|
+
- **Deploy advisor** (Vercel, Railway, Render, Fly.io, …)
|
|
64
|
+
- **ES / EN** UI · **light / dark** theme · **full-width** responsive layout
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Quick start
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
pipx install github-license-scanner
|
|
72
|
+
gls scan psf/requests
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
The web interface is an optional extra, so the CLI stays light:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
pipx install 'github-license-scanner[ui]'
|
|
79
|
+
gls ui
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Optional configuration (recommended):
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
# PowerShell example
|
|
86
|
+
$env:GITHUB_TOKEN = "ghp_..."
|
|
87
|
+
$env:GLS_STORAGE_SECRET = "long-random-string"
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Environment variables are the source of truth. A `.env` file is only a local
|
|
91
|
+
convenience: one is read from the current directory or from your user config
|
|
92
|
+
directory if present, and real environment variables always win.
|
|
93
|
+
|
|
94
|
+
| Variable | Purpose |
|
|
95
|
+
|----------|---------|
|
|
96
|
+
| `GITHUB_TOKEN` | Higher GitHub API rate limits / private repos |
|
|
97
|
+
| `GLS_STORAGE_SECRET` | Signs session cookies (**required** for public deploys) |
|
|
98
|
+
| `GLS_HOST` / `GLS_PORT` | Bind address (default `127.0.0.1:8080`) |
|
|
99
|
+
| `GLS_MAX_BATCH_URLS` | Cap batch scans (default 15) |
|
|
100
|
+
| `GLS_RATE_LIMIT_SCANS` | Scans per window per client (default 20/hour) |
|
|
101
|
+
| `GLS_AUTH_ENABLED` | Require web login (`1` / `true`) |
|
|
102
|
+
| `GLS_USERS_FILE` | JSON users DB (default: `users.json` in the data dir) |
|
|
103
|
+
| `GLS_DATA_DIR` | Override where history and users are stored |
|
|
104
|
+
|
|
105
|
+
See [`.env.example`](.env.example) for the full list.
|
|
106
|
+
|
|
107
|
+
History and users live in your per-user data directory, never inside the
|
|
108
|
+
installed package:
|
|
109
|
+
|
|
110
|
+
| OS | Path |
|
|
111
|
+
|----|------|
|
|
112
|
+
| Windows | `%LOCALAPPDATA%\NezbiT\github-license-scanner` |
|
|
113
|
+
| macOS | `~/Library/Application Support/github-license-scanner` |
|
|
114
|
+
| Linux | `~/.local/share/github-license-scanner` |
|
|
115
|
+
|
|
116
|
+
### Multi-user auth + private history
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
gls user-add alice # interactive password (≥8 chars)
|
|
120
|
+
|
|
121
|
+
export GLS_AUTH_ENABLED=1
|
|
122
|
+
export GLS_STORAGE_SECRET=long-random-string
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Each user gets `history/<username>.json` in that data directory. Without auth,
|
|
126
|
+
history stays in a single `history.json`.
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## Web UI
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
pipx install 'github-license-scanner[ui]'
|
|
134
|
+
gls ui # or: gls ui --host 0.0.0.0 --port 9000
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Open **[http://127.0.0.1:8080](http://127.0.0.1:8080)** (binds to localhost by default)
|
|
138
|
+
|
|
139
|
+
- Switch **ES | EN** in the top bar
|
|
140
|
+
- Toggle **light / dark** with the sun/moon button
|
|
141
|
+
- Try example chips (`psf/requests`, `encode/httpx`, …)
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## CLI
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
# Single repository
|
|
149
|
+
gls scan https://github.com/psf/requests
|
|
150
|
+
|
|
151
|
+
# Shorthand
|
|
152
|
+
gls scan psf/requests
|
|
153
|
+
|
|
154
|
+
# Batch (one URL per line)
|
|
155
|
+
gls batch urls.example.txt
|
|
156
|
+
|
|
157
|
+
# History
|
|
158
|
+
gls history
|
|
159
|
+
|
|
160
|
+
# Markdown + SBOM export
|
|
161
|
+
gls scan psf/requests --markdown report.md --sbom bom.cdx.json
|
|
162
|
+
gls scan psf/requests --sbom bom.spdx.json --sbom-format spdx
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
`github-license-scanner` is available as a longer alias for `gls`.
|
|
166
|
+
|
|
167
|
+
| Exit code | Meaning |
|
|
168
|
+
|-----------|---------|
|
|
169
|
+
| `0` | No strong copyleft force-open signal |
|
|
170
|
+
| `1` | Strong copyleft detected |
|
|
171
|
+
| `2` | Hard failure (bad URL, API error, …) |
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## Project layout
|
|
176
|
+
|
|
177
|
+
```text
|
|
178
|
+
github-license-scanner/
|
|
179
|
+
├── pyproject.toml # Packaging (hatchling)
|
|
180
|
+
├── gls/
|
|
181
|
+
│ ├── __init__.py # __version__
|
|
182
|
+
│ ├── cli.py # Command-line mode + entry point
|
|
183
|
+
│ ├── webui.py # NiceGUI interface (optional [ui] extra)
|
|
184
|
+
│ ├── config.py # Env-based configuration + data paths
|
|
185
|
+
│ ├── rate_limit.py # Scan rate limiter
|
|
186
|
+
│ ├── auth.py # Optional multi-user auth (PBKDF2)
|
|
187
|
+
│ ├── spdx_engine.py # SPDX expression parser + risk
|
|
188
|
+
│ ├── sbom_export.py # CycloneDX 1.5 + SPDX 2.3 JSON
|
|
189
|
+
│ ├── github_api.py # URL parse + GitHub REST
|
|
190
|
+
│ ├── dependency_scanner.py # Manifest parsers
|
|
191
|
+
│ ├── license_analyzer.py # Registry licenses + verdict
|
|
192
|
+
│ ├── deploy_advisor.py # Deploy recommendations
|
|
193
|
+
│ ├── history_store.py # JSON history (shared or per-user)
|
|
194
|
+
│ ├── models.py # Dataclasses
|
|
195
|
+
│ ├── i18n.py # ES/EN strings
|
|
196
|
+
│ ├── report.py # Markdown export
|
|
197
|
+
│ └── docs/ # Legal pages served by the web UI
|
|
198
|
+
│ ├── LEGAL_DISCLAIMER.md
|
|
199
|
+
│ ├── PRIVACY.md
|
|
200
|
+
│ └── TERMS.md
|
|
201
|
+
├── scripts/ # Dev smoke tests / audit tooling
|
|
202
|
+
├── .env.example
|
|
203
|
+
├── urls.example.txt
|
|
204
|
+
└── docs/
|
|
205
|
+
├── AUDIT_REPORT.pdf
|
|
206
|
+
└── images/ # README screenshots
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## License risk legend
|
|
212
|
+
|
|
213
|
+
| Color | Risk | Examples |
|
|
214
|
+
|-------|------|----------|
|
|
215
|
+
| Green | Permissive | MIT, Apache-2.0, BSD, ISC |
|
|
216
|
+
| Orange | Weak copyleft / unknown | LGPL, MPL, EUPL, missing metadata |
|
|
217
|
+
| Red | Strong copyleft | GPL, AGPL, SSPL |
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## Security & privacy notes
|
|
222
|
+
|
|
223
|
+
- Default bind is **localhost only** (`GLS_HOST=127.0.0.1`).
|
|
224
|
+
- Set a strong **`GLS_STORAGE_SECRET`** before exposing the UI.
|
|
225
|
+
- Scan history is **instance-local** and shared if multi-user — use **Clear history** or prune via config.
|
|
226
|
+
- Rate limits and batch caps reduce GitHub API abuse.
|
|
227
|
+
- Docs: [Privacy](gls/docs/PRIVACY.md) · [Terms](gls/docs/TERMS.md) · [Legal disclaimer](gls/docs/LEGAL_DISCLAIMER.md)
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
## Disclaimer
|
|
232
|
+
|
|
233
|
+
This tool provides **automated heuristics only**. It is **not legal advice** and not a
|
|
234
|
+
license-compatibility opinion. Dual-licensing, linking models, SaaS (AGPL/SSPL),
|
|
235
|
+
attribution duties, and contracts can change obligations.
|
|
236
|
+
Always review with a qualified attorney before commercial closed-source distribution.
|
|
237
|
+
See [gls/docs/LEGAL_DISCLAIMER.md](gls/docs/LEGAL_DISCLAIMER.md).
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
## Development
|
|
242
|
+
|
|
243
|
+
```bash
|
|
244
|
+
git clone https://github.com/NezbiT/github-license-scanner.git
|
|
245
|
+
cd github-license-scanner
|
|
246
|
+
|
|
247
|
+
python -m venv .venv
|
|
248
|
+
.venv\Scripts\activate # macOS / Linux: source .venv/bin/activate
|
|
249
|
+
|
|
250
|
+
pip install -e '.[ui]'
|
|
251
|
+
python -m gls.cli scan psf/requests
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
Build and check a release locally before tagging:
|
|
255
|
+
|
|
256
|
+
```bash
|
|
257
|
+
pip install build twine
|
|
258
|
+
python -m build
|
|
259
|
+
twine check dist/*
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
Releases are published to PyPI by [`.github/workflows/publish.yml`](.github/workflows/publish.yml)
|
|
263
|
+
using Trusted Publishing (OIDC) — no API tokens are stored anywhere.
|
|
264
|
+
|
|
265
|
+
---
|
|
266
|
+
|
|
267
|
+
## License
|
|
268
|
+
|
|
269
|
+
Released under the **[MIT License](LICENSE)**.
|
|
270
|
+
|
|
271
|
+
You may use, modify, and redistribute this project commercially or privately,
|
|
272
|
+
as long as you keep the copyright and license notice. See `LICENSE` for full text.
|
|
273
|
+
|
|
274
|
+
> The MIT license applies to **this tool’s source code**.
|
|
275
|
+
> It does **not** change the licenses of the GitHub repositories or packages you scan.
|
|
276
|
+
|
|
277
|
+
---
|
|
278
|
+
|
|
279
|
+
<p align="center">
|
|
280
|
+
Made with NiceGUI · httpx · packaging
|
|
281
|
+
</p>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.1.0"
|