jmo-security 0.3.0__tar.gz → 0.3.2__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.
- {jmo_security-0.3.0 → jmo_security-0.3.2}/PKG-INFO +85 -2
- {jmo_security-0.3.0 → jmo_security-0.3.2}/README.md +82 -0
- {jmo_security-0.3.0 → jmo_security-0.3.2}/jmo_security.egg-info/PKG-INFO +85 -2
- jmo_security-0.3.2/jmo_security.egg-info/SOURCES.txt +39 -0
- {jmo_security-0.3.0 → jmo_security-0.3.2}/jmo_security.egg-info/entry_points.txt +1 -0
- {jmo_security-0.3.0 → jmo_security-0.3.2}/pyproject.toml +5 -2
- jmo_security-0.3.2/scripts/cli/__init__.py +6 -0
- jmo_security-0.3.2/scripts/cli/clone_from_tsv.py +182 -0
- jmo_security-0.3.2/scripts/cli/jmo.py +801 -0
- jmo_security-0.3.2/scripts/cli/jmotools.py +252 -0
- jmo_security-0.3.2/scripts/core/__init__.py +1 -0
- jmo_security-0.3.2/scripts/core/adapters/__init__.py +1 -0
- jmo_security-0.3.2/scripts/core/adapters/bandit_adapter.py +80 -0
- jmo_security-0.3.2/scripts/core/adapters/checkov_adapter.py +68 -0
- jmo_security-0.3.2/scripts/core/adapters/gitleaks_adapter.py +80 -0
- jmo_security-0.3.2/scripts/core/adapters/hadolint_adapter.py +54 -0
- jmo_security-0.3.2/scripts/core/adapters/noseyparker_adapter.py +62 -0
- jmo_security-0.3.2/scripts/core/adapters/osv_adapter.py +91 -0
- jmo_security-0.3.2/scripts/core/adapters/semgrep_adapter.py +73 -0
- jmo_security-0.3.2/scripts/core/adapters/syft_adapter.py +102 -0
- jmo_security-0.3.2/scripts/core/adapters/tfsec_adapter.py +56 -0
- jmo_security-0.3.2/scripts/core/adapters/trivy_adapter.py +62 -0
- jmo_security-0.3.2/scripts/core/adapters/trufflehog_adapter.py +103 -0
- jmo_security-0.3.2/scripts/core/common_finding.py +41 -0
- jmo_security-0.3.2/scripts/core/config.py +78 -0
- jmo_security-0.3.2/scripts/core/generate_dashboard.py +620 -0
- jmo_security-0.3.2/scripts/core/normalize_and_report.py +236 -0
- jmo_security-0.3.2/scripts/core/reporters/__init__.py +1 -0
- jmo_security-0.3.2/scripts/core/reporters/basic_reporter.py +45 -0
- jmo_security-0.3.2/scripts/core/reporters/html_reporter.py +266 -0
- jmo_security-0.3.2/scripts/core/reporters/sarif_reporter.py +64 -0
- jmo_security-0.3.2/scripts/core/reporters/suppression_reporter.py +27 -0
- jmo_security-0.3.2/scripts/core/reporters/yaml_reporter.py +18 -0
- jmo_security-0.3.2/scripts/core/schema_utils.py +36 -0
- jmo_security-0.3.2/scripts/core/suppress.py +56 -0
- jmo_security-0.3.0/jmo_security.egg-info/SOURCES.txt +0 -10
- {jmo_security-0.3.0 → jmo_security-0.3.2}/LICENSE +0 -0
- {jmo_security-0.3.0 → jmo_security-0.3.2}/jmo_security.egg-info/dependency_links.txt +0 -0
- {jmo_security-0.3.0 → jmo_security-0.3.2}/jmo_security.egg-info/requires.txt +0 -0
- {jmo_security-0.3.0 → jmo_security-0.3.2}/jmo_security.egg-info/top_level.txt +0 -0
- {jmo_security-0.3.0 → jmo_security-0.3.2}/scripts/__init__.py +0 -0
- {jmo_security-0.3.0 → jmo_security-0.3.2}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: jmo-security
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.2
|
|
4
4
|
Summary: JMo Security Audit Suite (terminal-first, multi-tool, unified outputs)
|
|
5
5
|
Author-email: James Moceri <general@jmogaming.com>
|
|
6
6
|
License: MIT
|
|
@@ -13,6 +13,7 @@ License-File: LICENSE
|
|
|
13
13
|
Provides-Extra: reporting
|
|
14
14
|
Requires-Dist: PyYAML>=6.0; extra == "reporting"
|
|
15
15
|
Requires-Dist: jsonschema>=4.0; extra == "reporting"
|
|
16
|
+
Dynamic: license-file
|
|
16
17
|
|
|
17
18
|
# JMo's Security Audit Tool Suite
|
|
18
19
|
|
|
@@ -20,14 +21,77 @@ Requires-Dist: jsonschema>=4.0; extra == "reporting"
|
|
|
20
21
|
<img src="assets/jmo-logo.png" alt="JMo Security Audit Tool Suite" width="220" />
|
|
21
22
|
</p>
|
|
22
23
|
|
|
24
|
+
[](https://github.com/jimmy058910/jmo-security-repo/actions/workflows/tests.yml?query=branch%3Amain)
|
|
25
|
+
[](https://jmotools.com)
|
|
26
|
+
[](LICENSE)
|
|
27
|
+
[](#)
|
|
28
|
+
[](https://github.com/jimmy058910/jmo-security-repo/issues)
|
|
29
|
+
[](https://ko-fi.com/jmogaming)
|
|
30
|
+
|
|
31
|
+
<!-- CI/coverage/package badges (enable once configured)
|
|
32
|
+
[](#)
|
|
33
|
+
<!-- If/when a workflow exists, switch to:
|
|
23
34
|
[](https://github.com/jimmy058910/jmo-security-repo/actions/workflows/tests.yml)
|
|
35
|
+
-->
|
|
36
|
+
<!-- Codecov (enable after uploading coverage):
|
|
24
37
|
[](https://codecov.io/gh/jimmy058910/jmo-security-repo)
|
|
38
|
+
-->
|
|
39
|
+
<!-- PyPI (enable after first release):
|
|
25
40
|
[](https://pypi.org/project/jmo-security/)
|
|
41
|
+
-->
|
|
26
42
|
|
|
27
43
|
A terminal-first, cross-platform security audit toolkit that orchestrates multiple scanners (secrets, SAST, SBOM, IaC, Dockerfile) with a unified Python CLI, normalized outputs, and an HTML dashboard.
|
|
28
44
|
|
|
29
45
|
👉 New here? Read the comprehensive User Guide: [docs/USER_GUIDE.md](docs/USER_GUIDE.md)
|
|
30
46
|
Docs hub: [docs/index.md](docs/index.md)
|
|
47
|
+
Project homepage: [jmotools.com](https://jmotools.com)
|
|
48
|
+
|
|
49
|
+
> Origin story: This started as part of a Cybersecurity Capstone Project. It has since grown into a general-purpose toolkit. I’d love for folks with deeper expertise to jump in—issues and PRs are welcome!
|
|
50
|
+
|
|
51
|
+
Thinking about contributing? See [CONTRIBUTING.md](CONTRIBUTING.md) for setup, coding standards, and release steps.
|
|
52
|
+
|
|
53
|
+
Roadmap & history:
|
|
54
|
+
- Completed steps (summary): see [RELEASE_NOTES.md](RELEASE_NOTES.md) → “Roadmap Summary (Steps 1–13)”
|
|
55
|
+
- Active/planned work: see [ROADMAP.md](ROADMAP.md)
|
|
56
|
+
|
|
57
|
+
For scanning a list of repos from a TSV end-to-end (clone + unshallow + full toolchain), see: [docs/examples/scan_from_tsv.md](docs/examples/scan_from_tsv.md)
|
|
58
|
+
|
|
59
|
+
## 🧪 New: Simple wrapper commands
|
|
60
|
+
|
|
61
|
+
If you're just getting started, use the beginner-friendly wrapper:
|
|
62
|
+
|
|
63
|
+
- `jmotools fast` — quick scan (fast profile)
|
|
64
|
+
- `jmotools balanced` — default balanced scan
|
|
65
|
+
- `jmotools full` — deep scan with more tools
|
|
66
|
+
|
|
67
|
+
Examples:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
# Fast profile over repos listed in a TSV (auto-clone) and open dashboard when done
|
|
71
|
+
jmotools fast --tsv ai-search/candidates.tsv --dest ./repos-tsv
|
|
72
|
+
|
|
73
|
+
# Full (deep) profile targeting an existing directory of repos
|
|
74
|
+
jmotools full --repos-dir ./repos-tsv --allow-missing-tools
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Under the hood, these commands verify your OS/tools, optionally clone from a TSV, run `jmo ci` with the appropriate profile, and open `dashboard.html` and `SUMMARY.md` on completion.
|
|
78
|
+
|
|
79
|
+
Setup tools quickly:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
# Check tools or auto-install on Linux/WSL (where supported)
|
|
83
|
+
jmotools setup --check
|
|
84
|
+
jmotools setup --auto-install # or --print-commands, --force-reinstall
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Makefile shortcuts:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
make setup # jmotools setup --check (installs package if needed)
|
|
91
|
+
make fast DIR=~/repos # jmotools fast --repos-dir ~/repos
|
|
92
|
+
make balanced DIR=~/repos
|
|
93
|
+
make full DIR=~/repos
|
|
94
|
+
```
|
|
31
95
|
|
|
32
96
|
## 🎯 Overview
|
|
33
97
|
|
|
@@ -55,6 +119,12 @@ make verify-env # check OS/WSL/macOS and tool availability
|
|
|
55
119
|
make dev-deps # install Python dev dependencies
|
|
56
120
|
```
|
|
57
121
|
|
|
122
|
+
Optional: install the package locally to get `jmo` and `jmotools` commands on your PATH:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
pip install -e .
|
|
126
|
+
```
|
|
127
|
+
|
|
58
128
|
### Quick Start (Unified CLI)
|
|
59
129
|
|
|
60
130
|
1) Verify your environment (Linux/WSL/macOS) and see install hints for optional tools:
|
|
@@ -76,7 +146,10 @@ make dev-deps
|
|
|
76
146
|
python3 scripts/cli/jmo.py scan --repos-dir ~/repos --profile-name balanced --human-logs
|
|
77
147
|
|
|
78
148
|
# Aggregate and write unified outputs to results/summaries
|
|
149
|
+
# (positional or --results-dir are both accepted)
|
|
79
150
|
python3 scripts/cli/jmo.py report ./results --profile --human-logs
|
|
151
|
+
# or
|
|
152
|
+
python3 scripts/cli/jmo.py report --results-dir ./results --profile --human-logs
|
|
80
153
|
|
|
81
154
|
# Or do both in one step for CI with a failure threshold
|
|
82
155
|
python3 scripts/cli/jmo.py ci --repos-dir ~/repos --profile-name fast --fail-on HIGH --profile --human-logs
|
|
@@ -128,6 +201,8 @@ cat ~/security-results-*/SUMMARY_REPORT.md
|
|
|
128
201
|
# Linux: xdg-open ~/security-results-*/dashboard.html
|
|
129
202
|
```
|
|
130
203
|
|
|
204
|
+
Looking for screenshots and how to capture them? See: [docs/screenshots/README.md](docs/screenshots/README.md)
|
|
205
|
+
|
|
131
206
|
## 📚 Documentation
|
|
132
207
|
|
|
133
208
|
### Workflow (at a glance)
|
|
@@ -559,6 +634,14 @@ The HTML dashboard provides:
|
|
|
559
634
|
|
|
560
635
|
Contributions are welcome! Please feel free to submit pull requests or open issues for bugs and feature requests.
|
|
561
636
|
|
|
637
|
+
## ❤️ Support
|
|
638
|
+
|
|
639
|
+
If this toolkit saves you time, consider fueling development with an energy drink.
|
|
640
|
+
|
|
641
|
+
- Prefer one-time tips? Ko‑fi: https://ko-fi.com/jmogaming
|
|
642
|
+
- When you’re ready, replace the badge target with your preferred platform: GitHub Sponsors (industry standard), Open Collective, Ko-fi, or Stripe Checkout.
|
|
643
|
+
- GitHub Sponsors integrates directly with your GitHub profile and repository sidebar once enabled.
|
|
644
|
+
|
|
562
645
|
## 📝 License
|
|
563
646
|
|
|
564
647
|
MIT License. See LICENSE.
|
|
@@ -4,14 +4,77 @@
|
|
|
4
4
|
<img src="assets/jmo-logo.png" alt="JMo Security Audit Tool Suite" width="220" />
|
|
5
5
|
</p>
|
|
6
6
|
|
|
7
|
+
[](https://github.com/jimmy058910/jmo-security-repo/actions/workflows/tests.yml?query=branch%3Amain)
|
|
8
|
+
[](https://jmotools.com)
|
|
9
|
+
[](LICENSE)
|
|
10
|
+
[](#)
|
|
11
|
+
[](https://github.com/jimmy058910/jmo-security-repo/issues)
|
|
12
|
+
[](https://ko-fi.com/jmogaming)
|
|
13
|
+
|
|
14
|
+
<!-- CI/coverage/package badges (enable once configured)
|
|
15
|
+
[](#)
|
|
16
|
+
<!-- If/when a workflow exists, switch to:
|
|
7
17
|
[](https://github.com/jimmy058910/jmo-security-repo/actions/workflows/tests.yml)
|
|
18
|
+
-->
|
|
19
|
+
<!-- Codecov (enable after uploading coverage):
|
|
8
20
|
[](https://codecov.io/gh/jimmy058910/jmo-security-repo)
|
|
21
|
+
-->
|
|
22
|
+
<!-- PyPI (enable after first release):
|
|
9
23
|
[](https://pypi.org/project/jmo-security/)
|
|
24
|
+
-->
|
|
10
25
|
|
|
11
26
|
A terminal-first, cross-platform security audit toolkit that orchestrates multiple scanners (secrets, SAST, SBOM, IaC, Dockerfile) with a unified Python CLI, normalized outputs, and an HTML dashboard.
|
|
12
27
|
|
|
13
28
|
👉 New here? Read the comprehensive User Guide: [docs/USER_GUIDE.md](docs/USER_GUIDE.md)
|
|
14
29
|
Docs hub: [docs/index.md](docs/index.md)
|
|
30
|
+
Project homepage: [jmotools.com](https://jmotools.com)
|
|
31
|
+
|
|
32
|
+
> Origin story: This started as part of a Cybersecurity Capstone Project. It has since grown into a general-purpose toolkit. I’d love for folks with deeper expertise to jump in—issues and PRs are welcome!
|
|
33
|
+
|
|
34
|
+
Thinking about contributing? See [CONTRIBUTING.md](CONTRIBUTING.md) for setup, coding standards, and release steps.
|
|
35
|
+
|
|
36
|
+
Roadmap & history:
|
|
37
|
+
- Completed steps (summary): see [RELEASE_NOTES.md](RELEASE_NOTES.md) → “Roadmap Summary (Steps 1–13)”
|
|
38
|
+
- Active/planned work: see [ROADMAP.md](ROADMAP.md)
|
|
39
|
+
|
|
40
|
+
For scanning a list of repos from a TSV end-to-end (clone + unshallow + full toolchain), see: [docs/examples/scan_from_tsv.md](docs/examples/scan_from_tsv.md)
|
|
41
|
+
|
|
42
|
+
## 🧪 New: Simple wrapper commands
|
|
43
|
+
|
|
44
|
+
If you're just getting started, use the beginner-friendly wrapper:
|
|
45
|
+
|
|
46
|
+
- `jmotools fast` — quick scan (fast profile)
|
|
47
|
+
- `jmotools balanced` — default balanced scan
|
|
48
|
+
- `jmotools full` — deep scan with more tools
|
|
49
|
+
|
|
50
|
+
Examples:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
# Fast profile over repos listed in a TSV (auto-clone) and open dashboard when done
|
|
54
|
+
jmotools fast --tsv ai-search/candidates.tsv --dest ./repos-tsv
|
|
55
|
+
|
|
56
|
+
# Full (deep) profile targeting an existing directory of repos
|
|
57
|
+
jmotools full --repos-dir ./repos-tsv --allow-missing-tools
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Under the hood, these commands verify your OS/tools, optionally clone from a TSV, run `jmo ci` with the appropriate profile, and open `dashboard.html` and `SUMMARY.md` on completion.
|
|
61
|
+
|
|
62
|
+
Setup tools quickly:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
# Check tools or auto-install on Linux/WSL (where supported)
|
|
66
|
+
jmotools setup --check
|
|
67
|
+
jmotools setup --auto-install # or --print-commands, --force-reinstall
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Makefile shortcuts:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
make setup # jmotools setup --check (installs package if needed)
|
|
74
|
+
make fast DIR=~/repos # jmotools fast --repos-dir ~/repos
|
|
75
|
+
make balanced DIR=~/repos
|
|
76
|
+
make full DIR=~/repos
|
|
77
|
+
```
|
|
15
78
|
|
|
16
79
|
## 🎯 Overview
|
|
17
80
|
|
|
@@ -39,6 +102,12 @@ make verify-env # check OS/WSL/macOS and tool availability
|
|
|
39
102
|
make dev-deps # install Python dev dependencies
|
|
40
103
|
```
|
|
41
104
|
|
|
105
|
+
Optional: install the package locally to get `jmo` and `jmotools` commands on your PATH:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
pip install -e .
|
|
109
|
+
```
|
|
110
|
+
|
|
42
111
|
### Quick Start (Unified CLI)
|
|
43
112
|
|
|
44
113
|
1) Verify your environment (Linux/WSL/macOS) and see install hints for optional tools:
|
|
@@ -60,7 +129,10 @@ make dev-deps
|
|
|
60
129
|
python3 scripts/cli/jmo.py scan --repos-dir ~/repos --profile-name balanced --human-logs
|
|
61
130
|
|
|
62
131
|
# Aggregate and write unified outputs to results/summaries
|
|
132
|
+
# (positional or --results-dir are both accepted)
|
|
63
133
|
python3 scripts/cli/jmo.py report ./results --profile --human-logs
|
|
134
|
+
# or
|
|
135
|
+
python3 scripts/cli/jmo.py report --results-dir ./results --profile --human-logs
|
|
64
136
|
|
|
65
137
|
# Or do both in one step for CI with a failure threshold
|
|
66
138
|
python3 scripts/cli/jmo.py ci --repos-dir ~/repos --profile-name fast --fail-on HIGH --profile --human-logs
|
|
@@ -112,6 +184,8 @@ cat ~/security-results-*/SUMMARY_REPORT.md
|
|
|
112
184
|
# Linux: xdg-open ~/security-results-*/dashboard.html
|
|
113
185
|
```
|
|
114
186
|
|
|
187
|
+
Looking for screenshots and how to capture them? See: [docs/screenshots/README.md](docs/screenshots/README.md)
|
|
188
|
+
|
|
115
189
|
## 📚 Documentation
|
|
116
190
|
|
|
117
191
|
### Workflow (at a glance)
|
|
@@ -543,6 +617,14 @@ The HTML dashboard provides:
|
|
|
543
617
|
|
|
544
618
|
Contributions are welcome! Please feel free to submit pull requests or open issues for bugs and feature requests.
|
|
545
619
|
|
|
620
|
+
## ❤️ Support
|
|
621
|
+
|
|
622
|
+
If this toolkit saves you time, consider fueling development with an energy drink.
|
|
623
|
+
|
|
624
|
+
- Prefer one-time tips? Ko‑fi: https://ko-fi.com/jmogaming
|
|
625
|
+
- When you’re ready, replace the badge target with your preferred platform: GitHub Sponsors (industry standard), Open Collective, Ko-fi, or Stripe Checkout.
|
|
626
|
+
- GitHub Sponsors integrates directly with your GitHub profile and repository sidebar once enabled.
|
|
627
|
+
|
|
546
628
|
## 📝 License
|
|
547
629
|
|
|
548
630
|
MIT License. See LICENSE.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: jmo-security
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.2
|
|
4
4
|
Summary: JMo Security Audit Suite (terminal-first, multi-tool, unified outputs)
|
|
5
5
|
Author-email: James Moceri <general@jmogaming.com>
|
|
6
6
|
License: MIT
|
|
@@ -13,6 +13,7 @@ License-File: LICENSE
|
|
|
13
13
|
Provides-Extra: reporting
|
|
14
14
|
Requires-Dist: PyYAML>=6.0; extra == "reporting"
|
|
15
15
|
Requires-Dist: jsonschema>=4.0; extra == "reporting"
|
|
16
|
+
Dynamic: license-file
|
|
16
17
|
|
|
17
18
|
# JMo's Security Audit Tool Suite
|
|
18
19
|
|
|
@@ -20,14 +21,77 @@ Requires-Dist: jsonschema>=4.0; extra == "reporting"
|
|
|
20
21
|
<img src="assets/jmo-logo.png" alt="JMo Security Audit Tool Suite" width="220" />
|
|
21
22
|
</p>
|
|
22
23
|
|
|
24
|
+
[](https://github.com/jimmy058910/jmo-security-repo/actions/workflows/tests.yml?query=branch%3Amain)
|
|
25
|
+
[](https://jmotools.com)
|
|
26
|
+
[](LICENSE)
|
|
27
|
+
[](#)
|
|
28
|
+
[](https://github.com/jimmy058910/jmo-security-repo/issues)
|
|
29
|
+
[](https://ko-fi.com/jmogaming)
|
|
30
|
+
|
|
31
|
+
<!-- CI/coverage/package badges (enable once configured)
|
|
32
|
+
[](#)
|
|
33
|
+
<!-- If/when a workflow exists, switch to:
|
|
23
34
|
[](https://github.com/jimmy058910/jmo-security-repo/actions/workflows/tests.yml)
|
|
35
|
+
-->
|
|
36
|
+
<!-- Codecov (enable after uploading coverage):
|
|
24
37
|
[](https://codecov.io/gh/jimmy058910/jmo-security-repo)
|
|
38
|
+
-->
|
|
39
|
+
<!-- PyPI (enable after first release):
|
|
25
40
|
[](https://pypi.org/project/jmo-security/)
|
|
41
|
+
-->
|
|
26
42
|
|
|
27
43
|
A terminal-first, cross-platform security audit toolkit that orchestrates multiple scanners (secrets, SAST, SBOM, IaC, Dockerfile) with a unified Python CLI, normalized outputs, and an HTML dashboard.
|
|
28
44
|
|
|
29
45
|
👉 New here? Read the comprehensive User Guide: [docs/USER_GUIDE.md](docs/USER_GUIDE.md)
|
|
30
46
|
Docs hub: [docs/index.md](docs/index.md)
|
|
47
|
+
Project homepage: [jmotools.com](https://jmotools.com)
|
|
48
|
+
|
|
49
|
+
> Origin story: This started as part of a Cybersecurity Capstone Project. It has since grown into a general-purpose toolkit. I’d love for folks with deeper expertise to jump in—issues and PRs are welcome!
|
|
50
|
+
|
|
51
|
+
Thinking about contributing? See [CONTRIBUTING.md](CONTRIBUTING.md) for setup, coding standards, and release steps.
|
|
52
|
+
|
|
53
|
+
Roadmap & history:
|
|
54
|
+
- Completed steps (summary): see [RELEASE_NOTES.md](RELEASE_NOTES.md) → “Roadmap Summary (Steps 1–13)”
|
|
55
|
+
- Active/planned work: see [ROADMAP.md](ROADMAP.md)
|
|
56
|
+
|
|
57
|
+
For scanning a list of repos from a TSV end-to-end (clone + unshallow + full toolchain), see: [docs/examples/scan_from_tsv.md](docs/examples/scan_from_tsv.md)
|
|
58
|
+
|
|
59
|
+
## 🧪 New: Simple wrapper commands
|
|
60
|
+
|
|
61
|
+
If you're just getting started, use the beginner-friendly wrapper:
|
|
62
|
+
|
|
63
|
+
- `jmotools fast` — quick scan (fast profile)
|
|
64
|
+
- `jmotools balanced` — default balanced scan
|
|
65
|
+
- `jmotools full` — deep scan with more tools
|
|
66
|
+
|
|
67
|
+
Examples:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
# Fast profile over repos listed in a TSV (auto-clone) and open dashboard when done
|
|
71
|
+
jmotools fast --tsv ai-search/candidates.tsv --dest ./repos-tsv
|
|
72
|
+
|
|
73
|
+
# Full (deep) profile targeting an existing directory of repos
|
|
74
|
+
jmotools full --repos-dir ./repos-tsv --allow-missing-tools
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Under the hood, these commands verify your OS/tools, optionally clone from a TSV, run `jmo ci` with the appropriate profile, and open `dashboard.html` and `SUMMARY.md` on completion.
|
|
78
|
+
|
|
79
|
+
Setup tools quickly:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
# Check tools or auto-install on Linux/WSL (where supported)
|
|
83
|
+
jmotools setup --check
|
|
84
|
+
jmotools setup --auto-install # or --print-commands, --force-reinstall
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Makefile shortcuts:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
make setup # jmotools setup --check (installs package if needed)
|
|
91
|
+
make fast DIR=~/repos # jmotools fast --repos-dir ~/repos
|
|
92
|
+
make balanced DIR=~/repos
|
|
93
|
+
make full DIR=~/repos
|
|
94
|
+
```
|
|
31
95
|
|
|
32
96
|
## 🎯 Overview
|
|
33
97
|
|
|
@@ -55,6 +119,12 @@ make verify-env # check OS/WSL/macOS and tool availability
|
|
|
55
119
|
make dev-deps # install Python dev dependencies
|
|
56
120
|
```
|
|
57
121
|
|
|
122
|
+
Optional: install the package locally to get `jmo` and `jmotools` commands on your PATH:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
pip install -e .
|
|
126
|
+
```
|
|
127
|
+
|
|
58
128
|
### Quick Start (Unified CLI)
|
|
59
129
|
|
|
60
130
|
1) Verify your environment (Linux/WSL/macOS) and see install hints for optional tools:
|
|
@@ -76,7 +146,10 @@ make dev-deps
|
|
|
76
146
|
python3 scripts/cli/jmo.py scan --repos-dir ~/repos --profile-name balanced --human-logs
|
|
77
147
|
|
|
78
148
|
# Aggregate and write unified outputs to results/summaries
|
|
149
|
+
# (positional or --results-dir are both accepted)
|
|
79
150
|
python3 scripts/cli/jmo.py report ./results --profile --human-logs
|
|
151
|
+
# or
|
|
152
|
+
python3 scripts/cli/jmo.py report --results-dir ./results --profile --human-logs
|
|
80
153
|
|
|
81
154
|
# Or do both in one step for CI with a failure threshold
|
|
82
155
|
python3 scripts/cli/jmo.py ci --repos-dir ~/repos --profile-name fast --fail-on HIGH --profile --human-logs
|
|
@@ -128,6 +201,8 @@ cat ~/security-results-*/SUMMARY_REPORT.md
|
|
|
128
201
|
# Linux: xdg-open ~/security-results-*/dashboard.html
|
|
129
202
|
```
|
|
130
203
|
|
|
204
|
+
Looking for screenshots and how to capture them? See: [docs/screenshots/README.md](docs/screenshots/README.md)
|
|
205
|
+
|
|
131
206
|
## 📚 Documentation
|
|
132
207
|
|
|
133
208
|
### Workflow (at a glance)
|
|
@@ -559,6 +634,14 @@ The HTML dashboard provides:
|
|
|
559
634
|
|
|
560
635
|
Contributions are welcome! Please feel free to submit pull requests or open issues for bugs and feature requests.
|
|
561
636
|
|
|
637
|
+
## ❤️ Support
|
|
638
|
+
|
|
639
|
+
If this toolkit saves you time, consider fueling development with an energy drink.
|
|
640
|
+
|
|
641
|
+
- Prefer one-time tips? Ko‑fi: https://ko-fi.com/jmogaming
|
|
642
|
+
- When you’re ready, replace the badge target with your preferred platform: GitHub Sponsors (industry standard), Open Collective, Ko-fi, or Stripe Checkout.
|
|
643
|
+
- GitHub Sponsors integrates directly with your GitHub profile and repository sidebar once enabled.
|
|
644
|
+
|
|
562
645
|
## 📝 License
|
|
563
646
|
|
|
564
647
|
MIT License. See LICENSE.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
jmo_security.egg-info/PKG-INFO
|
|
5
|
+
jmo_security.egg-info/SOURCES.txt
|
|
6
|
+
jmo_security.egg-info/dependency_links.txt
|
|
7
|
+
jmo_security.egg-info/entry_points.txt
|
|
8
|
+
jmo_security.egg-info/requires.txt
|
|
9
|
+
jmo_security.egg-info/top_level.txt
|
|
10
|
+
scripts/__init__.py
|
|
11
|
+
scripts/cli/__init__.py
|
|
12
|
+
scripts/cli/clone_from_tsv.py
|
|
13
|
+
scripts/cli/jmo.py
|
|
14
|
+
scripts/cli/jmotools.py
|
|
15
|
+
scripts/core/__init__.py
|
|
16
|
+
scripts/core/common_finding.py
|
|
17
|
+
scripts/core/config.py
|
|
18
|
+
scripts/core/generate_dashboard.py
|
|
19
|
+
scripts/core/normalize_and_report.py
|
|
20
|
+
scripts/core/schema_utils.py
|
|
21
|
+
scripts/core/suppress.py
|
|
22
|
+
scripts/core/adapters/__init__.py
|
|
23
|
+
scripts/core/adapters/bandit_adapter.py
|
|
24
|
+
scripts/core/adapters/checkov_adapter.py
|
|
25
|
+
scripts/core/adapters/gitleaks_adapter.py
|
|
26
|
+
scripts/core/adapters/hadolint_adapter.py
|
|
27
|
+
scripts/core/adapters/noseyparker_adapter.py
|
|
28
|
+
scripts/core/adapters/osv_adapter.py
|
|
29
|
+
scripts/core/adapters/semgrep_adapter.py
|
|
30
|
+
scripts/core/adapters/syft_adapter.py
|
|
31
|
+
scripts/core/adapters/tfsec_adapter.py
|
|
32
|
+
scripts/core/adapters/trivy_adapter.py
|
|
33
|
+
scripts/core/adapters/trufflehog_adapter.py
|
|
34
|
+
scripts/core/reporters/__init__.py
|
|
35
|
+
scripts/core/reporters/basic_reporter.py
|
|
36
|
+
scripts/core/reporters/html_reporter.py
|
|
37
|
+
scripts/core/reporters/sarif_reporter.py
|
|
38
|
+
scripts/core/reporters/suppression_reporter.py
|
|
39
|
+
scripts/core/reporters/yaml_reporter.py
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "jmo-security"
|
|
7
|
-
version = "0.3.
|
|
7
|
+
version = "0.3.2"
|
|
8
8
|
description = "JMo Security Audit Suite (terminal-first, multi-tool, unified outputs)"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.8"
|
|
@@ -22,7 +22,10 @@ reporting = ["PyYAML>=6.0", "jsonschema>=4.0"]
|
|
|
22
22
|
|
|
23
23
|
[project.scripts]
|
|
24
24
|
jmo = "scripts.cli.jmo:main"
|
|
25
|
+
jmotools = "scripts.cli.jmotools:main"
|
|
25
26
|
|
|
26
27
|
[tool.setuptools]
|
|
27
|
-
packages = ["scripts"]
|
|
28
28
|
include-package-data = true
|
|
29
|
+
|
|
30
|
+
[tool.setuptools.packages.find]
|
|
31
|
+
include = ["scripts*"]
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Clone repositories listed in a TSV and emit a targets file for jmo scan.
|
|
4
|
+
|
|
5
|
+
Inputs
|
|
6
|
+
- --tsv: Path to a TSV file with a header containing either 'url' or 'full_name' columns.
|
|
7
|
+
Example header: full_name url stars language description created_at updated_at matched_by
|
|
8
|
+
Rows may have blank description; this script only cares about url/full_name.
|
|
9
|
+
|
|
10
|
+
Outputs
|
|
11
|
+
- Clones repos under --dest (default: ./repos-tsv/<owner>/<repo>)
|
|
12
|
+
- Writes a newline-delimited list of absolute repo paths to --targets-out (default: results/targets.tsv.txt)
|
|
13
|
+
|
|
14
|
+
Behavior
|
|
15
|
+
- If a repo already exists, perform a fetch and ensure it is not shallow ("unshallowed")
|
|
16
|
+
- Prefer the 'url' column when present; otherwise construct https://github.com/<full_name>.git
|
|
17
|
+
- Limits cloning to --max (default: all)
|
|
18
|
+
"""
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
import argparse
|
|
22
|
+
import csv
|
|
23
|
+
import subprocess
|
|
24
|
+
import sys
|
|
25
|
+
from pathlib import Path
|
|
26
|
+
from typing import List, Optional, Tuple
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def log(msg: str, level: str = "INFO", human: bool = True) -> None:
|
|
30
|
+
level = level.upper()
|
|
31
|
+
if human:
|
|
32
|
+
color = {"DEBUG": "\x1b[36m", "INFO": "\x1b[32m", "WARN": "\x1b[33m", "ERROR": "\x1b[31m"}.get(level, "")
|
|
33
|
+
reset = "\x1b[0m"
|
|
34
|
+
sys.stderr.write(f"{color}{level:5}{reset} {msg}\n")
|
|
35
|
+
else:
|
|
36
|
+
import json
|
|
37
|
+
import datetime
|
|
38
|
+
rec = {"ts": datetime.datetime.utcnow().isoformat() + "Z", "level": level, "msg": msg}
|
|
39
|
+
sys.stderr.write(json.dumps(rec) + "\n")
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def run(cmd: List[str], cwd: Optional[Path] = None, ok_rcs: Tuple[int, ...] = (0,)) -> Tuple[int, str, str]:
|
|
43
|
+
try:
|
|
44
|
+
cp = subprocess.run(
|
|
45
|
+
cmd,
|
|
46
|
+
cwd=str(cwd) if cwd else None,
|
|
47
|
+
stdout=subprocess.PIPE,
|
|
48
|
+
stderr=subprocess.PIPE,
|
|
49
|
+
text=True,
|
|
50
|
+
check=False,
|
|
51
|
+
)
|
|
52
|
+
rc = cp.returncode
|
|
53
|
+
if rc not in ok_rcs:
|
|
54
|
+
return rc, cp.stdout or "", cp.stderr or ""
|
|
55
|
+
return rc, cp.stdout or "", cp.stderr or ""
|
|
56
|
+
except FileNotFoundError as e:
|
|
57
|
+
return 127, "", str(e)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def ensure_unshallowed(repo_dir: Path) -> None:
|
|
61
|
+
# Determine if shallow and unshallow if needed
|
|
62
|
+
rc, out, err = run(["git", "rev-parse", "--is-shallow-repository"], cwd=repo_dir)
|
|
63
|
+
if rc != 0:
|
|
64
|
+
log(f"git rev-parse failed for {repo_dir.name}: {err.strip()}", "WARN")
|
|
65
|
+
return
|
|
66
|
+
shallow = (out.strip().lower() == "true")
|
|
67
|
+
if shallow:
|
|
68
|
+
# Attempt to unshallow
|
|
69
|
+
rc, _, err = run(["git", "fetch", "--unshallow"], cwd=repo_dir)
|
|
70
|
+
if rc != 0:
|
|
71
|
+
# Some setups require specifying the remote; try origin
|
|
72
|
+
rc2, _, err2 = run(["git", "fetch", "origin", "--unshallow"], cwd=repo_dir)
|
|
73
|
+
if rc2 != 0:
|
|
74
|
+
log(f"Failed to unshallow {repo_dir.name}: {err.strip() or err2.strip()}", "WARN")
|
|
75
|
+
# Also fetch tags/prune to be thorough
|
|
76
|
+
run(["git", "fetch", "--all", "--tags", "--prune"], cwd=repo_dir)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def clone_or_update(url: str, dest_root: Path) -> Optional[Path]:
|
|
80
|
+
# Derive a stable folder path like <dest_root>/<owner>/<repo>
|
|
81
|
+
try:
|
|
82
|
+
# Strip trailing .git for folder naming
|
|
83
|
+
stem = url.split("//", 1)[-1]
|
|
84
|
+
# stem like github.com/owner/repo(.git)
|
|
85
|
+
parts = stem.split("/")
|
|
86
|
+
owner, repo = parts[-2], parts[-1]
|
|
87
|
+
if repo.endswith(".git"):
|
|
88
|
+
repo = repo[:-4]
|
|
89
|
+
except Exception:
|
|
90
|
+
owner, repo = "misc", url.replace("://", "_").replace("/", "-")
|
|
91
|
+
target = dest_root / owner / repo
|
|
92
|
+
target.parent.mkdir(parents=True, exist_ok=True)
|
|
93
|
+
if target.exists():
|
|
94
|
+
log(f"Updating existing repo {owner}/{repo}")
|
|
95
|
+
rc, _, err = run(["git", "remote", "-v"], cwd=target)
|
|
96
|
+
if rc != 0:
|
|
97
|
+
log(f"Not a git repo at {target}: {err.strip()}", "ERROR")
|
|
98
|
+
return None
|
|
99
|
+
run(["git", "fetch", "--all", "--tags", "--prune"], cwd=target)
|
|
100
|
+
ensure_unshallowed(target)
|
|
101
|
+
return target
|
|
102
|
+
log(f"Cloning {owner}/{repo}")
|
|
103
|
+
rc, _, err = run(["git", "clone", url, str(target)])
|
|
104
|
+
if rc != 0:
|
|
105
|
+
log(f"Clone failed for {url}: {err.strip()}", "ERROR")
|
|
106
|
+
return None
|
|
107
|
+
ensure_unshallowed(target)
|
|
108
|
+
return target
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def parse_tsv(tsv_path: Path, max_count: Optional[int]) -> List[str]:
|
|
112
|
+
urls: List[str] = []
|
|
113
|
+
with tsv_path.open("r", encoding="utf-8") as f:
|
|
114
|
+
# Sniff delimiter; default to tab
|
|
115
|
+
sample = f.read(4096)
|
|
116
|
+
f.seek(0)
|
|
117
|
+
dialect = csv.Sniffer().sniff(sample, delimiters="\t,;") if sample else csv.excel_tab
|
|
118
|
+
reader = csv.DictReader(f, dialect=dialect)
|
|
119
|
+
cols = [c.strip().lower() for c in (reader.fieldnames or [])]
|
|
120
|
+
if not cols:
|
|
121
|
+
raise RuntimeError("TSV file has no header row")
|
|
122
|
+
use_url = "url" in cols
|
|
123
|
+
use_full = "full_name" in cols
|
|
124
|
+
if not use_url and not use_full:
|
|
125
|
+
raise RuntimeError("TSV must include either 'url' or 'full_name' columns")
|
|
126
|
+
for row in reader:
|
|
127
|
+
if max_count and len(urls) >= max_count:
|
|
128
|
+
break
|
|
129
|
+
u = (row.get("url") or "").strip() if use_url else ""
|
|
130
|
+
if not u and use_full:
|
|
131
|
+
fn = (row.get("full_name") or "").strip()
|
|
132
|
+
if fn:
|
|
133
|
+
u = f"https://github.com/{fn}.git"
|
|
134
|
+
if u:
|
|
135
|
+
urls.append(u)
|
|
136
|
+
return urls
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def main(argv: Optional[List[str]] = None) -> int:
|
|
140
|
+
ap = argparse.ArgumentParser(description="Clone repos listed in a TSV and emit a jmo targets file")
|
|
141
|
+
ap.add_argument("--tsv", required=True, help="Path to candidates.tsv with 'url' or 'full_name' header")
|
|
142
|
+
ap.add_argument("--dest", default="repos-tsv", help="Destination directory to clone into (default: repos-tsv)")
|
|
143
|
+
ap.add_argument("--targets-out", default=str(Path("results") / "targets.tsv.txt"), help="Path to write newline-delimited repo paths (default: results/targets.tsv.txt)")
|
|
144
|
+
ap.add_argument("--max", type=int, default=None, help="Optional max number of repos to process")
|
|
145
|
+
ap.add_argument("--human-logs", action="store_true", help="Use human-friendly logs")
|
|
146
|
+
args = ap.parse_args(argv)
|
|
147
|
+
|
|
148
|
+
tsv_path = Path(args.tsv).expanduser().resolve()
|
|
149
|
+
dest = Path(args.dest).expanduser().resolve()
|
|
150
|
+
targets_out = Path(args.targets_out).expanduser().resolve()
|
|
151
|
+
targets_out.parent.mkdir(parents=True, exist_ok=True)
|
|
152
|
+
|
|
153
|
+
if not tsv_path.exists():
|
|
154
|
+
log(f"TSV not found: {tsv_path}", "ERROR")
|
|
155
|
+
return 2
|
|
156
|
+
|
|
157
|
+
urls = parse_tsv(tsv_path, args.max)
|
|
158
|
+
if not urls:
|
|
159
|
+
log("No repository URLs found in TSV", "ERROR")
|
|
160
|
+
return 2
|
|
161
|
+
|
|
162
|
+
paths: List[Path] = []
|
|
163
|
+
for url in urls:
|
|
164
|
+
p = clone_or_update(url, dest)
|
|
165
|
+
if p:
|
|
166
|
+
paths.append(p)
|
|
167
|
+
|
|
168
|
+
if not paths:
|
|
169
|
+
log("No repositories cloned/updated successfully", "ERROR")
|
|
170
|
+
return 1
|
|
171
|
+
|
|
172
|
+
# Write absolute paths to targets file
|
|
173
|
+
with targets_out.open("w", encoding="utf-8") as f:
|
|
174
|
+
for p in paths:
|
|
175
|
+
f.write(str(p) + "\n")
|
|
176
|
+
log(f"Wrote targets file: {targets_out}")
|
|
177
|
+
log(f"Cloned/updated {len(paths)} repos into {dest}")
|
|
178
|
+
return 0
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
if __name__ == "__main__":
|
|
182
|
+
raise SystemExit(main())
|