cmmc2-toolkit 0.2.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 (59) hide show
  1. cmmc2_toolkit-0.2.0/PKG-INFO +109 -0
  2. cmmc2_toolkit-0.2.0/README.md +80 -0
  3. cmmc2_toolkit-0.2.0/cmmc2_toolkit.egg-info/PKG-INFO +109 -0
  4. cmmc2_toolkit-0.2.0/cmmc2_toolkit.egg-info/SOURCES.txt +57 -0
  5. cmmc2_toolkit-0.2.0/cmmc2_toolkit.egg-info/dependency_links.txt +1 -0
  6. cmmc2_toolkit-0.2.0/cmmc2_toolkit.egg-info/entry_points.txt +3 -0
  7. cmmc2_toolkit-0.2.0/cmmc2_toolkit.egg-info/requires.txt +17 -0
  8. cmmc2_toolkit-0.2.0/cmmc2_toolkit.egg-info/top_level.txt +2 -0
  9. cmmc2_toolkit-0.2.0/cmmc2agent/__init__.py +2 -0
  10. cmmc2_toolkit-0.2.0/cmmc2agent/cli.py +94 -0
  11. cmmc2_toolkit-0.2.0/cmmc2agent/config.py +64 -0
  12. cmmc2_toolkit-0.2.0/cmmc2agent/poster.py +43 -0
  13. cmmc2_toolkit-0.2.0/cmmc2toolkit/__init__.py +2 -0
  14. cmmc2_toolkit-0.2.0/cmmc2toolkit/adapters/__init__.py +3 -0
  15. cmmc2_toolkit-0.2.0/cmmc2toolkit/adapters/adapter_django.py +129 -0
  16. cmmc2_toolkit-0.2.0/cmmc2toolkit/adapters/adapter_express.py +173 -0
  17. cmmc2_toolkit-0.2.0/cmmc2toolkit/adapters/adapter_fastapi.py +156 -0
  18. cmmc2_toolkit-0.2.0/cmmc2toolkit/adapters/adapter_flask.py +54 -0
  19. cmmc2_toolkit-0.2.0/cmmc2toolkit/adapters/adapter_spring.py +181 -0
  20. cmmc2_toolkit-0.2.0/cmmc2toolkit/adapters/base.py +48 -0
  21. cmmc2_toolkit-0.2.0/cmmc2toolkit/auth/__init__.py +12 -0
  22. cmmc2_toolkit-0.2.0/cmmc2toolkit/auth/models.py +28 -0
  23. cmmc2_toolkit-0.2.0/cmmc2toolkit/auth/passwords.py +48 -0
  24. cmmc2_toolkit-0.2.0/cmmc2toolkit/auth/store.py +189 -0
  25. cmmc2_toolkit-0.2.0/cmmc2toolkit/auth/totp.py +26 -0
  26. cmmc2_toolkit-0.2.0/cmmc2toolkit/checks/__init__.py +0 -0
  27. cmmc2_toolkit-0.2.0/cmmc2toolkit/checks/access.py +33 -0
  28. cmmc2_toolkit-0.2.0/cmmc2toolkit/checks/audit.py +11 -0
  29. cmmc2_toolkit-0.2.0/cmmc2toolkit/checks/auth.py +51 -0
  30. cmmc2_toolkit-0.2.0/cmmc2toolkit/checks/config.py +48 -0
  31. cmmc2_toolkit-0.2.0/cmmc2toolkit/checks/integrity.py +93 -0
  32. cmmc2_toolkit-0.2.0/cmmc2toolkit/checks/transport.py +16 -0
  33. cmmc2_toolkit-0.2.0/cmmc2toolkit/cli.py +94 -0
  34. cmmc2_toolkit-0.2.0/cmmc2toolkit/controls.py +352 -0
  35. cmmc2_toolkit-0.2.0/cmmc2toolkit/dashboard/__init__.py +0 -0
  36. cmmc2_toolkit-0.2.0/cmmc2toolkit/dashboard/app.py +543 -0
  37. cmmc2_toolkit-0.2.0/cmmc2toolkit/dashboard/templates/audit_log.html +77 -0
  38. cmmc2_toolkit-0.2.0/cmmc2toolkit/dashboard/templates/dashboard.html +454 -0
  39. cmmc2_toolkit-0.2.0/cmmc2toolkit/dashboard/templates/home.html +218 -0
  40. cmmc2_toolkit-0.2.0/cmmc2toolkit/dashboard/templates/login.html +67 -0
  41. cmmc2_toolkit-0.2.0/cmmc2toolkit/dashboard/templates/mfa.html +55 -0
  42. cmmc2_toolkit-0.2.0/cmmc2toolkit/dashboard/templates/poam.html +81 -0
  43. cmmc2_toolkit-0.2.0/cmmc2toolkit/dashboard/templates/register.html +83 -0
  44. cmmc2_toolkit-0.2.0/cmmc2toolkit/dashboard/templates/setup_mfa.html +49 -0
  45. cmmc2_toolkit-0.2.0/cmmc2toolkit/detector/__init__.py +4 -0
  46. cmmc2_toolkit-0.2.0/cmmc2toolkit/detector/base.py +79 -0
  47. cmmc2_toolkit-0.2.0/cmmc2toolkit/detector/fingerprints.py +36 -0
  48. cmmc2_toolkit-0.2.0/cmmc2toolkit/detector/profile.py +14 -0
  49. cmmc2_toolkit-0.2.0/cmmc2toolkit/export.py +111 -0
  50. cmmc2_toolkit-0.2.0/cmmc2toolkit/models.py +50 -0
  51. cmmc2_toolkit-0.2.0/cmmc2toolkit/store/__init__.py +5 -0
  52. cmmc2_toolkit-0.2.0/cmmc2toolkit/store/base.py +25 -0
  53. cmmc2_toolkit-0.2.0/cmmc2toolkit/store/registry.py +180 -0
  54. cmmc2_toolkit-0.2.0/cmmc2toolkit/store/store_sqlite.py +206 -0
  55. cmmc2_toolkit-0.2.0/pyproject.toml +46 -0
  56. cmmc2_toolkit-0.2.0/setup.cfg +4 -0
  57. cmmc2_toolkit-0.2.0/tests/test_adapter_flask.py +62 -0
  58. cmmc2_toolkit-0.2.0/tests/test_detector.py +41 -0
  59. cmmc2_toolkit-0.2.0/tests/test_store_sqlite.py +35 -0
@@ -0,0 +1,109 @@
1
+ Metadata-Version: 2.4
2
+ Name: cmmc2-toolkit
3
+ Version: 0.2.0
4
+ Summary: CMMC 2.0 Level 2 compliance scanner and admin dashboard for web application teams
5
+ Author-email: David Moorhead <david.moorhead37@gmail.com>
6
+ License-Expression: MIT
7
+ Keywords: cmmc,compliance,nist,800-171,security
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: Topic :: Security
11
+ Classifier: Programming Language :: Python :: 3
12
+ Requires-Python: >=3.10
13
+ Description-Content-Type: text/markdown
14
+ Requires-Dist: flask>=3.0
15
+ Requires-Dist: click>=8.0
16
+ Requires-Dist: openpyxl>=3.1
17
+ Requires-Dist: bcrypt>=4.0
18
+ Requires-Dist: flask-login>=0.6
19
+ Requires-Dist: flask-wtf>=1.2
20
+ Requires-Dist: pyotp>=2.9
21
+ Requires-Dist: qrcode[pil]>=7.4
22
+ Requires-Dist: flask-limiter>=3.5
23
+ Requires-Dist: waitress>=3.0
24
+ Provides-Extra: mongo
25
+ Requires-Dist: pymongo>=4.0; extra == "mongo"
26
+ Provides-Extra: dev
27
+ Requires-Dist: pytest>=8.0; extra == "dev"
28
+ Requires-Dist: pytest-cov; extra == "dev"
29
+
30
+ # cmmc2-toolkit
31
+
32
+ A self-contained Python package that gives any web application team a **CMMC 2.0 Level 2** compliance scanner and admin dashboard — installable via pip, zero infrastructure required.
33
+
34
+ ## Features
35
+
36
+ - **62 controls** — all CMMC Level 1 (17), Level 2 practices, and optional Level 3 (24) controls
37
+ - **Auto-scan** for 5 platforms: Flask, Django, FastAPI, Express/Node.js, Spring Boot
38
+ - **Dashboard** — per-project compliance tracker with status, progress, target dates, and audit log
39
+ - **POA&M** — Plan of Action & Milestones view for Gap / Partial / Manual controls
40
+ - **Excel export** — one-click 3-tab workbook (Dashboard, POA&M, Audit Log)
41
+ - **Audit log** — every status change timestamped and attributed to a user
42
+ - **REST API** — agent ingest endpoint for CI/CD pipeline integration
43
+
44
+ ## Quickstart
45
+
46
+ ```bash
47
+ pip install cmmc2-toolkit
48
+
49
+ cmmc2 serve # launch dashboard at http://localhost:5050
50
+ cmmc2 scan --path /path/to/project # run programmatic checks (CLI mode)
51
+ cmmc2 export --out poam.xlsx # export POA&M to Excel
52
+ ```
53
+
54
+ On first launch the dashboard creates an admin account automatically (`admin` / `BWIadmin!2026` — change it immediately).
55
+
56
+ ## Supported platforms
57
+
58
+ | Platform | Auto-detected by | Auto-checks |
59
+ |---|---|---|
60
+ | Flask | `flask` in requirements / `app.py` | 25 controls |
61
+ | Django | `django` in requirements / `manage.py` | 25 controls |
62
+ | FastAPI | `fastapi` in requirements / `main.py` | 25 controls |
63
+ | Express / Next.js | `express` or `next` in `package.json` | 25 controls |
64
+ | Spring Boot / WildFly | `spring-boot` in `pom.xml` / `WEB-INF` | 25 controls |
65
+
66
+ Unsupported platforms fall back to full manual tracking mode.
67
+
68
+ ## Dashboard
69
+
70
+ ```
71
+ cmmc2 serve --port 5050
72
+ ```
73
+
74
+ - Create projects by URL or local path
75
+ - Run a live scan against a local codebase
76
+ - Track status (Pass / Gap / Partial / Manual) per control
77
+ - Every status change requires a note — written to the immutable audit log
78
+ - Level 3 controls (NIST SP 800-172) are opt-in per project
79
+ - Export the full workbook (Dashboard + POA&M + Audit Log tabs) with one click
80
+
81
+ On Windows, use the included `serve.ps1` launcher if `cmmc2` is not yet on your PATH.
82
+
83
+ ## Architecture
84
+
85
+ ```
86
+ cmmc2toolkit/
87
+ ├── controls.py # 62 CMMC control definitions (L1 + L2 + L3)
88
+ ├── models.py # Control, Finding dataclasses
89
+ ├── cli.py # click CLI (scan | serve | export | init)
90
+ ├── detector/ # auto-detect platform from project files
91
+ ├── adapters/ # platform-specific check runners
92
+ ├── checks/ # atomic grep-based check functions
93
+ ├── store/ # SQLiteStore + StoreBase ABC
94
+ ├── auth/ # password hashing, TOTP, session management
95
+ ├── dashboard/ # Flask micro-app (routes + Jinja2 templates)
96
+ └── export.py # openpyxl 3-tab Excel export
97
+ ```
98
+
99
+ ## Contributing an adapter
100
+
101
+ 1. Subclass `AdapterBase` in `cmmc2toolkit/adapters/adapter_<platform>.py`
102
+ 2. Implement `check_all() -> list[Finding]`
103
+ 3. Register it in `adapters/base.py` → `get_adapter()` registry
104
+ 4. Add fingerprint rules in `detector/fingerprints.py`
105
+ 5. Open a PR
106
+
107
+ ## License
108
+
109
+ MIT
@@ -0,0 +1,80 @@
1
+ # cmmc2-toolkit
2
+
3
+ A self-contained Python package that gives any web application team a **CMMC 2.0 Level 2** compliance scanner and admin dashboard — installable via pip, zero infrastructure required.
4
+
5
+ ## Features
6
+
7
+ - **62 controls** — all CMMC Level 1 (17), Level 2 practices, and optional Level 3 (24) controls
8
+ - **Auto-scan** for 5 platforms: Flask, Django, FastAPI, Express/Node.js, Spring Boot
9
+ - **Dashboard** — per-project compliance tracker with status, progress, target dates, and audit log
10
+ - **POA&M** — Plan of Action & Milestones view for Gap / Partial / Manual controls
11
+ - **Excel export** — one-click 3-tab workbook (Dashboard, POA&M, Audit Log)
12
+ - **Audit log** — every status change timestamped and attributed to a user
13
+ - **REST API** — agent ingest endpoint for CI/CD pipeline integration
14
+
15
+ ## Quickstart
16
+
17
+ ```bash
18
+ pip install cmmc2-toolkit
19
+
20
+ cmmc2 serve # launch dashboard at http://localhost:5050
21
+ cmmc2 scan --path /path/to/project # run programmatic checks (CLI mode)
22
+ cmmc2 export --out poam.xlsx # export POA&M to Excel
23
+ ```
24
+
25
+ On first launch the dashboard creates an admin account automatically (`admin` / `BWIadmin!2026` — change it immediately).
26
+
27
+ ## Supported platforms
28
+
29
+ | Platform | Auto-detected by | Auto-checks |
30
+ |---|---|---|
31
+ | Flask | `flask` in requirements / `app.py` | 25 controls |
32
+ | Django | `django` in requirements / `manage.py` | 25 controls |
33
+ | FastAPI | `fastapi` in requirements / `main.py` | 25 controls |
34
+ | Express / Next.js | `express` or `next` in `package.json` | 25 controls |
35
+ | Spring Boot / WildFly | `spring-boot` in `pom.xml` / `WEB-INF` | 25 controls |
36
+
37
+ Unsupported platforms fall back to full manual tracking mode.
38
+
39
+ ## Dashboard
40
+
41
+ ```
42
+ cmmc2 serve --port 5050
43
+ ```
44
+
45
+ - Create projects by URL or local path
46
+ - Run a live scan against a local codebase
47
+ - Track status (Pass / Gap / Partial / Manual) per control
48
+ - Every status change requires a note — written to the immutable audit log
49
+ - Level 3 controls (NIST SP 800-172) are opt-in per project
50
+ - Export the full workbook (Dashboard + POA&M + Audit Log tabs) with one click
51
+
52
+ On Windows, use the included `serve.ps1` launcher if `cmmc2` is not yet on your PATH.
53
+
54
+ ## Architecture
55
+
56
+ ```
57
+ cmmc2toolkit/
58
+ ├── controls.py # 62 CMMC control definitions (L1 + L2 + L3)
59
+ ├── models.py # Control, Finding dataclasses
60
+ ├── cli.py # click CLI (scan | serve | export | init)
61
+ ├── detector/ # auto-detect platform from project files
62
+ ├── adapters/ # platform-specific check runners
63
+ ├── checks/ # atomic grep-based check functions
64
+ ├── store/ # SQLiteStore + StoreBase ABC
65
+ ├── auth/ # password hashing, TOTP, session management
66
+ ├── dashboard/ # Flask micro-app (routes + Jinja2 templates)
67
+ └── export.py # openpyxl 3-tab Excel export
68
+ ```
69
+
70
+ ## Contributing an adapter
71
+
72
+ 1. Subclass `AdapterBase` in `cmmc2toolkit/adapters/adapter_<platform>.py`
73
+ 2. Implement `check_all() -> list[Finding]`
74
+ 3. Register it in `adapters/base.py` → `get_adapter()` registry
75
+ 4. Add fingerprint rules in `detector/fingerprints.py`
76
+ 5. Open a PR
77
+
78
+ ## License
79
+
80
+ MIT
@@ -0,0 +1,109 @@
1
+ Metadata-Version: 2.4
2
+ Name: cmmc2-toolkit
3
+ Version: 0.2.0
4
+ Summary: CMMC 2.0 Level 2 compliance scanner and admin dashboard for web application teams
5
+ Author-email: David Moorhead <david.moorhead37@gmail.com>
6
+ License-Expression: MIT
7
+ Keywords: cmmc,compliance,nist,800-171,security
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: Topic :: Security
11
+ Classifier: Programming Language :: Python :: 3
12
+ Requires-Python: >=3.10
13
+ Description-Content-Type: text/markdown
14
+ Requires-Dist: flask>=3.0
15
+ Requires-Dist: click>=8.0
16
+ Requires-Dist: openpyxl>=3.1
17
+ Requires-Dist: bcrypt>=4.0
18
+ Requires-Dist: flask-login>=0.6
19
+ Requires-Dist: flask-wtf>=1.2
20
+ Requires-Dist: pyotp>=2.9
21
+ Requires-Dist: qrcode[pil]>=7.4
22
+ Requires-Dist: flask-limiter>=3.5
23
+ Requires-Dist: waitress>=3.0
24
+ Provides-Extra: mongo
25
+ Requires-Dist: pymongo>=4.0; extra == "mongo"
26
+ Provides-Extra: dev
27
+ Requires-Dist: pytest>=8.0; extra == "dev"
28
+ Requires-Dist: pytest-cov; extra == "dev"
29
+
30
+ # cmmc2-toolkit
31
+
32
+ A self-contained Python package that gives any web application team a **CMMC 2.0 Level 2** compliance scanner and admin dashboard — installable via pip, zero infrastructure required.
33
+
34
+ ## Features
35
+
36
+ - **62 controls** — all CMMC Level 1 (17), Level 2 practices, and optional Level 3 (24) controls
37
+ - **Auto-scan** for 5 platforms: Flask, Django, FastAPI, Express/Node.js, Spring Boot
38
+ - **Dashboard** — per-project compliance tracker with status, progress, target dates, and audit log
39
+ - **POA&M** — Plan of Action & Milestones view for Gap / Partial / Manual controls
40
+ - **Excel export** — one-click 3-tab workbook (Dashboard, POA&M, Audit Log)
41
+ - **Audit log** — every status change timestamped and attributed to a user
42
+ - **REST API** — agent ingest endpoint for CI/CD pipeline integration
43
+
44
+ ## Quickstart
45
+
46
+ ```bash
47
+ pip install cmmc2-toolkit
48
+
49
+ cmmc2 serve # launch dashboard at http://localhost:5050
50
+ cmmc2 scan --path /path/to/project # run programmatic checks (CLI mode)
51
+ cmmc2 export --out poam.xlsx # export POA&M to Excel
52
+ ```
53
+
54
+ On first launch the dashboard creates an admin account automatically (`admin` / `BWIadmin!2026` — change it immediately).
55
+
56
+ ## Supported platforms
57
+
58
+ | Platform | Auto-detected by | Auto-checks |
59
+ |---|---|---|
60
+ | Flask | `flask` in requirements / `app.py` | 25 controls |
61
+ | Django | `django` in requirements / `manage.py` | 25 controls |
62
+ | FastAPI | `fastapi` in requirements / `main.py` | 25 controls |
63
+ | Express / Next.js | `express` or `next` in `package.json` | 25 controls |
64
+ | Spring Boot / WildFly | `spring-boot` in `pom.xml` / `WEB-INF` | 25 controls |
65
+
66
+ Unsupported platforms fall back to full manual tracking mode.
67
+
68
+ ## Dashboard
69
+
70
+ ```
71
+ cmmc2 serve --port 5050
72
+ ```
73
+
74
+ - Create projects by URL or local path
75
+ - Run a live scan against a local codebase
76
+ - Track status (Pass / Gap / Partial / Manual) per control
77
+ - Every status change requires a note — written to the immutable audit log
78
+ - Level 3 controls (NIST SP 800-172) are opt-in per project
79
+ - Export the full workbook (Dashboard + POA&M + Audit Log tabs) with one click
80
+
81
+ On Windows, use the included `serve.ps1` launcher if `cmmc2` is not yet on your PATH.
82
+
83
+ ## Architecture
84
+
85
+ ```
86
+ cmmc2toolkit/
87
+ ├── controls.py # 62 CMMC control definitions (L1 + L2 + L3)
88
+ ├── models.py # Control, Finding dataclasses
89
+ ├── cli.py # click CLI (scan | serve | export | init)
90
+ ├── detector/ # auto-detect platform from project files
91
+ ├── adapters/ # platform-specific check runners
92
+ ├── checks/ # atomic grep-based check functions
93
+ ├── store/ # SQLiteStore + StoreBase ABC
94
+ ├── auth/ # password hashing, TOTP, session management
95
+ ├── dashboard/ # Flask micro-app (routes + Jinja2 templates)
96
+ └── export.py # openpyxl 3-tab Excel export
97
+ ```
98
+
99
+ ## Contributing an adapter
100
+
101
+ 1. Subclass `AdapterBase` in `cmmc2toolkit/adapters/adapter_<platform>.py`
102
+ 2. Implement `check_all() -> list[Finding]`
103
+ 3. Register it in `adapters/base.py` → `get_adapter()` registry
104
+ 4. Add fingerprint rules in `detector/fingerprints.py`
105
+ 5. Open a PR
106
+
107
+ ## License
108
+
109
+ MIT
@@ -0,0 +1,57 @@
1
+ README.md
2
+ pyproject.toml
3
+ cmmc2_toolkit.egg-info/PKG-INFO
4
+ cmmc2_toolkit.egg-info/SOURCES.txt
5
+ cmmc2_toolkit.egg-info/dependency_links.txt
6
+ cmmc2_toolkit.egg-info/entry_points.txt
7
+ cmmc2_toolkit.egg-info/requires.txt
8
+ cmmc2_toolkit.egg-info/top_level.txt
9
+ cmmc2agent/__init__.py
10
+ cmmc2agent/cli.py
11
+ cmmc2agent/config.py
12
+ cmmc2agent/poster.py
13
+ cmmc2toolkit/__init__.py
14
+ cmmc2toolkit/cli.py
15
+ cmmc2toolkit/controls.py
16
+ cmmc2toolkit/export.py
17
+ cmmc2toolkit/models.py
18
+ cmmc2toolkit/adapters/__init__.py
19
+ cmmc2toolkit/adapters/adapter_django.py
20
+ cmmc2toolkit/adapters/adapter_express.py
21
+ cmmc2toolkit/adapters/adapter_fastapi.py
22
+ cmmc2toolkit/adapters/adapter_flask.py
23
+ cmmc2toolkit/adapters/adapter_spring.py
24
+ cmmc2toolkit/adapters/base.py
25
+ cmmc2toolkit/auth/__init__.py
26
+ cmmc2toolkit/auth/models.py
27
+ cmmc2toolkit/auth/passwords.py
28
+ cmmc2toolkit/auth/store.py
29
+ cmmc2toolkit/auth/totp.py
30
+ cmmc2toolkit/checks/__init__.py
31
+ cmmc2toolkit/checks/access.py
32
+ cmmc2toolkit/checks/audit.py
33
+ cmmc2toolkit/checks/auth.py
34
+ cmmc2toolkit/checks/config.py
35
+ cmmc2toolkit/checks/integrity.py
36
+ cmmc2toolkit/checks/transport.py
37
+ cmmc2toolkit/dashboard/__init__.py
38
+ cmmc2toolkit/dashboard/app.py
39
+ cmmc2toolkit/dashboard/templates/audit_log.html
40
+ cmmc2toolkit/dashboard/templates/dashboard.html
41
+ cmmc2toolkit/dashboard/templates/home.html
42
+ cmmc2toolkit/dashboard/templates/login.html
43
+ cmmc2toolkit/dashboard/templates/mfa.html
44
+ cmmc2toolkit/dashboard/templates/poam.html
45
+ cmmc2toolkit/dashboard/templates/register.html
46
+ cmmc2toolkit/dashboard/templates/setup_mfa.html
47
+ cmmc2toolkit/detector/__init__.py
48
+ cmmc2toolkit/detector/base.py
49
+ cmmc2toolkit/detector/fingerprints.py
50
+ cmmc2toolkit/detector/profile.py
51
+ cmmc2toolkit/store/__init__.py
52
+ cmmc2toolkit/store/base.py
53
+ cmmc2toolkit/store/registry.py
54
+ cmmc2toolkit/store/store_sqlite.py
55
+ tests/test_adapter_flask.py
56
+ tests/test_detector.py
57
+ tests/test_store_sqlite.py
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ cmmc2 = cmmc2toolkit.cli:main
3
+ cmmc2agent = cmmc2agent.cli:main
@@ -0,0 +1,17 @@
1
+ flask>=3.0
2
+ click>=8.0
3
+ openpyxl>=3.1
4
+ bcrypt>=4.0
5
+ flask-login>=0.6
6
+ flask-wtf>=1.2
7
+ pyotp>=2.9
8
+ qrcode[pil]>=7.4
9
+ flask-limiter>=3.5
10
+ waitress>=3.0
11
+
12
+ [dev]
13
+ pytest>=8.0
14
+ pytest-cov
15
+
16
+ [mongo]
17
+ pymongo>=4.0
@@ -0,0 +1,2 @@
1
+ cmmc2agent
2
+ cmmc2toolkit
@@ -0,0 +1,2 @@
1
+ """cmmc2-agent — lightweight scanner agent for cmmc2-toolkit."""
2
+ __version__ = "0.1.0"
@@ -0,0 +1,94 @@
1
+ """cmmc2agent CLI entry point."""
2
+ import click
3
+ from cmmc2agent.config import load_config, TOML_TEMPLATE
4
+
5
+
6
+ @click.group()
7
+ def main():
8
+ """CMMC 2.0 scanner agent — posts results to a central dashboard."""
9
+
10
+
11
+ @main.command()
12
+ @click.option("--config", default=None, help="Path to cmmc2agent.toml")
13
+ @click.option("--dry-run", is_flag=True, help="Run checks but do not post results.")
14
+ def scan(config, dry_run):
15
+ """Run compliance checks and POST results to the dashboard."""
16
+ from cmmc2toolkit.detector import detect_platform
17
+ from cmmc2toolkit.adapters import get_adapter
18
+ from cmmc2agent.poster import post_findings
19
+
20
+ try:
21
+ cfg = load_config(config)
22
+ except (FileNotFoundError, RuntimeError) as e:
23
+ click.secho(str(e), fg="red")
24
+ raise SystemExit(1)
25
+
26
+ click.echo(f"Scanning: {cfg.scan_path}")
27
+ profile = detect_platform(cfg.scan_path)
28
+ click.echo(f"Platform: {profile.platform} Language: {profile.language}")
29
+
30
+ try:
31
+ adapter = get_adapter(profile)
32
+ findings = adapter.check_all()
33
+ except NotImplementedError as e:
34
+ click.secho(str(e), fg="yellow")
35
+ raise SystemExit(1)
36
+
37
+ passed = [f for f in findings if f.passed]
38
+ failed = [f for f in findings if not f.passed]
39
+ click.echo(f"Results : {len(passed)} passed / {len(failed)} failed")
40
+
41
+ for f in failed:
42
+ click.secho(f" ✗ {f.practice_id} {f.detail[:80]}", fg="red")
43
+ for f in passed:
44
+ click.secho(f" ✓ {f.practice_id} {f.detail[:80]}", fg="green")
45
+
46
+ if dry_run:
47
+ click.secho("\nDry run — results not posted.", fg="yellow")
48
+ return
49
+
50
+ click.echo(f"\nPosting to: {cfg.ingest_url}")
51
+ try:
52
+ result = post_findings(
53
+ ingest_url=cfg.ingest_url,
54
+ api_key=cfg.api_key,
55
+ project_id=cfg.project_id,
56
+ platform=profile.platform,
57
+ scan_path=cfg.scan_path,
58
+ findings=findings,
59
+ )
60
+ click.secho(
61
+ f"Dashboard updated — "
62
+ f"{result.get('passed',0)} passed, "
63
+ f"{result.get('failed',0)} failed, "
64
+ f"{result.get('skipped',0)} skipped.",
65
+ fg="green", bold=True,
66
+ )
67
+ except RuntimeError as e:
68
+ click.secho(f"Post failed: {e}", fg="red")
69
+ raise SystemExit(1)
70
+
71
+
72
+ @main.command("init")
73
+ @click.option("--dashboard-url", prompt="Central dashboard URL",
74
+ help="e.g. http://cmmc2.mycompany.com:5050")
75
+ @click.option("--api-key", prompt="API key",
76
+ help="Issued when you created the project on the dashboard.")
77
+ @click.option("--project-id", prompt="Project ID",
78
+ help="Shown on the dashboard home page after project creation.")
79
+ @click.option("--scan-path", prompt="Local scan path",
80
+ default=".", show_default=True,
81
+ help="Directory containing the app source code.")
82
+ @click.option("--output", default="cmmc2agent.toml", show_default=True)
83
+ def init_cmd(dashboard_url, api_key, project_id, scan_path, output):
84
+ """Interactively create a cmmc2agent.toml config file."""
85
+ from pathlib import Path
86
+ content = TOML_TEMPLATE.format(
87
+ dashboard_url=dashboard_url,
88
+ api_key=api_key,
89
+ project_id=project_id,
90
+ scan_path=scan_path,
91
+ )
92
+ Path(output).write_text(content)
93
+ click.secho(f"Config written to {output}", fg="green")
94
+ click.echo("Run `cmmc2agent scan` to send your first results to the dashboard.")
@@ -0,0 +1,64 @@
1
+ """Load and validate cmmc2agent.toml config."""
2
+ from dataclasses import dataclass
3
+ from pathlib import Path
4
+
5
+ try:
6
+ import tomllib
7
+ except ImportError:
8
+ try:
9
+ import tomli as tomllib # pip install tomli on Python < 3.11
10
+ except ImportError:
11
+ tomllib = None
12
+
13
+
14
+ DEFAULT_CONFIG_PATHS = [
15
+ Path("cmmc2agent.toml"),
16
+ Path.home() / ".cmmc2" / "agent.toml",
17
+ ]
18
+
19
+
20
+ @dataclass
21
+ class AgentConfig:
22
+ dashboard_url: str
23
+ api_key: str
24
+ project_id: str
25
+ scan_path: str
26
+
27
+ @property
28
+ def ingest_url(self) -> str:
29
+ return self.dashboard_url.rstrip("/") + "/api/v1/ingest"
30
+
31
+
32
+ def load_config(path: str | Path | None = None) -> AgentConfig:
33
+ if tomllib is None:
34
+ raise RuntimeError(
35
+ "TOML support not available. On Python < 3.11, run: pip install tomli"
36
+ )
37
+
38
+ candidates = [Path(path)] if path else DEFAULT_CONFIG_PATHS
39
+ for candidate in candidates:
40
+ if candidate.exists():
41
+ with open(candidate, "rb") as f:
42
+ data = tomllib.load(f)
43
+ return AgentConfig(
44
+ dashboard_url=data["dashboard_url"],
45
+ api_key=data["api_key"],
46
+ project_id=data["project_id"],
47
+ scan_path=data["scan_path"],
48
+ )
49
+
50
+ raise FileNotFoundError(
51
+ "No cmmc2agent.toml found. Run `cmmc2agent init` to create one, "
52
+ "or specify --config <path>."
53
+ )
54
+
55
+
56
+ TOML_TEMPLATE = """\
57
+ # cmmc2agent.toml — Scanner agent configuration
58
+ # Generated by `cmmc2agent init`
59
+
60
+ dashboard_url = "{dashboard_url}"
61
+ api_key = "{api_key}"
62
+ project_id = "{project_id}"
63
+ scan_path = "{scan_path}"
64
+ """
@@ -0,0 +1,43 @@
1
+ """HTTP poster — sends scan results to the central dashboard."""
2
+ import json
3
+ import urllib.request
4
+ import urllib.error
5
+ from cmmc2toolkit.models import Finding
6
+
7
+
8
+ def post_findings(ingest_url: str, api_key: str, project_id: str,
9
+ platform: str, scan_path: str,
10
+ findings: list[Finding]) -> dict:
11
+ payload = json.dumps({
12
+ "project_id": project_id,
13
+ "platform": platform,
14
+ "path": scan_path,
15
+ "findings": [
16
+ {
17
+ "practice_id": f.practice_id,
18
+ "passed": f.passed,
19
+ "detail": f.detail,
20
+ "evidence": f.evidence,
21
+ }
22
+ for f in findings
23
+ ],
24
+ }).encode()
25
+
26
+ req = urllib.request.Request(
27
+ ingest_url,
28
+ data=payload,
29
+ headers={
30
+ "Content-Type": "application/json",
31
+ "X-CMMC2-Key": api_key,
32
+ },
33
+ method="POST",
34
+ )
35
+
36
+ try:
37
+ with urllib.request.urlopen(req, timeout=30) as resp:
38
+ return json.loads(resp.read())
39
+ except urllib.error.HTTPError as e:
40
+ body = e.read().decode(errors="replace")
41
+ raise RuntimeError(f"Dashboard returned {e.code}: {body}") from e
42
+ except urllib.error.URLError as e:
43
+ raise RuntimeError(f"Could not reach dashboard at {ingest_url}: {e.reason}") from e
@@ -0,0 +1,2 @@
1
+ """cmmc2-toolkit — CMMC 2.0 Level 2 compliance scanner and dashboard."""
2
+ __version__ = "0.1.0"
@@ -0,0 +1,3 @@
1
+ from cmmc2toolkit.adapters.base import AdapterBase, get_adapter
2
+
3
+ __all__ = ["AdapterBase", "get_adapter"]