ecdat 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.
- ecdat-0.2.0/CHANGELOG.md +60 -0
- ecdat-0.2.0/LICENSE +21 -0
- ecdat-0.2.0/MANIFEST.in +29 -0
- ecdat-0.2.0/PKG-INFO +142 -0
- ecdat-0.2.0/PYPI_README.md +104 -0
- ecdat-0.2.0/README.md +200 -0
- ecdat-0.2.0/ecdat/__init__.py +10 -0
- ecdat-0.2.0/ecdat/__main__.py +5 -0
- ecdat-0.2.0/ecdat/cli/__init__.py +203 -0
- ecdat-0.2.0/ecdat/cli/commands/__init__.py +0 -0
- ecdat-0.2.0/ecdat/cli/commands/about.py +130 -0
- ecdat-0.2.0/ecdat/cli/commands/demo.py +116 -0
- ecdat-0.2.0/ecdat/cli/commands/doctor.py +296 -0
- ecdat-0.2.0/ecdat/cli/commands/help_cmd.py +205 -0
- ecdat-0.2.0/ecdat/cli/commands/scan.py +228 -0
- ecdat-0.2.0/ecdat/cli/commands/version_cmd.py +48 -0
- ecdat-0.2.0/ecdat/cli/parser.py +87 -0
- ecdat-0.2.0/ecdat/demo_project/auth/login.py +75 -0
- ecdat-0.2.0/ecdat/demo_project/certs/cert_verify.go +81 -0
- ecdat-0.2.0/ecdat/demo_project/keyexchange/channel.go +48 -0
- ecdat-0.2.0/ecdat/demo_project/legacy/LegacyCrypto.java +78 -0
- ecdat-0.2.0/ecdat/demo_project/payments/payment.py +64 -0
- ecdat-0.2.0/ecdat/demo_project/quantum/pqc_utils.py +67 -0
- ecdat-0.2.0/ecdat/demo_project/quantum/slh_signer.py +40 -0
- ecdat-0.2.0/ecdat/demo_project/tokens/signing.js +54 -0
- ecdat-0.2.0/ecdat/py.typed +0 -0
- ecdat-0.2.0/ecdat/services/__init__.py +1 -0
- ecdat-0.2.0/ecdat/services/crashlog.py +109 -0
- ecdat-0.2.0/ecdat/services/demo.py +85 -0
- ecdat-0.2.0/ecdat/services/paths.py +52 -0
- ecdat-0.2.0/ecdat/services/scanner.py +248 -0
- ecdat-0.2.0/ecdat/services/viewmodel.py +326 -0
- ecdat-0.2.0/ecdat/tests/__init__.py +0 -0
- ecdat-0.2.0/ecdat/tests/conftest.py +17 -0
- ecdat-0.2.0/ecdat/tests/test_app_art.py +314 -0
- ecdat-0.2.0/ecdat/tests/test_app_cli_meta.py +126 -0
- ecdat-0.2.0/ecdat/tests/test_app_cli_scan.py +257 -0
- ecdat-0.2.0/ecdat/tests/test_app_crashlog.py +127 -0
- ecdat-0.2.0/ecdat/tests/test_app_demo.py +106 -0
- ecdat-0.2.0/ecdat/tests/test_app_e2e_cli.py +311 -0
- ecdat-0.2.0/ecdat/tests/test_app_packaging.py +593 -0
- ecdat-0.2.0/ecdat/tests/test_app_render.py +483 -0
- ecdat-0.2.0/ecdat/tests/test_app_scanner.py +238 -0
- ecdat-0.2.0/ecdat/tests/test_app_skeleton.py +44 -0
- ecdat-0.2.0/ecdat/tests/test_app_ui.py +298 -0
- ecdat-0.2.0/ecdat/tests/test_app_viewmodel.py +169 -0
- ecdat-0.2.0/ecdat/ui/__init__.py +1 -0
- ecdat-0.2.0/ecdat/ui/art3d.py +136 -0
- ecdat-0.2.0/ecdat/ui/art_static.py +65 -0
- ecdat-0.2.0/ecdat/ui/art_text.py +81 -0
- ecdat-0.2.0/ecdat/ui/banner.py +148 -0
- ecdat-0.2.0/ecdat/ui/console.py +119 -0
- ecdat-0.2.0/ecdat/ui/motion.py +64 -0
- ecdat-0.2.0/ecdat/ui/render.py +486 -0
- ecdat-0.2.0/ecdat/ui/theme.py +173 -0
- ecdat-0.2.0/ecdat.egg-info/PKG-INFO +142 -0
- ecdat-0.2.0/ecdat.egg-info/SOURCES.txt +97 -0
- ecdat-0.2.0/ecdat.egg-info/dependency_links.txt +1 -0
- ecdat-0.2.0/ecdat.egg-info/entry_points.txt +2 -0
- ecdat-0.2.0/ecdat.egg-info/requires.txt +9 -0
- ecdat-0.2.0/ecdat.egg-info/top_level.txt +2 -0
- ecdat-0.2.0/ecdat_core/__init__.py +6 -0
- ecdat-0.2.0/ecdat_core/cbom_export.py +287 -0
- ecdat-0.2.0/ecdat_core/cli.py +202 -0
- ecdat-0.2.0/ecdat_core/detector.py +273 -0
- ecdat-0.2.0/ecdat_core/ingestion.py +581 -0
- ecdat-0.2.0/ecdat_core/models.py +145 -0
- ecdat-0.2.0/ecdat_core/recommender.py +74 -0
- ecdat-0.2.0/ecdat_core/risk_engine.py +264 -0
- ecdat-0.2.0/ecdat_core/signature_loader.py +204 -0
- ecdat-0.2.0/ecdat_core/signatures.json +692 -0
- ecdat-0.2.0/ecdat_core/tests/fixtures/cyclonedx/bom-1.6.schema.json +5699 -0
- ecdat-0.2.0/ecdat_core/tests/fixtures/cyclonedx/jsf-0.82.schema.json +240 -0
- ecdat-0.2.0/ecdat_core/tests/fixtures/cyclonedx/spdx.schema.json +1632 -0
- ecdat-0.2.0/ecdat_core/tests/fixtures/demo_repo/auth/login.py +37 -0
- ecdat-0.2.0/ecdat_core/tests/fixtures/demo_repo/legacy/cipher.java +28 -0
- ecdat-0.2.0/ecdat_core/tests/fixtures/demo_repo/modern/crypto.py +31 -0
- ecdat-0.2.0/ecdat_core/tests/fixtures/demo_repo/requirements.txt +5 -0
- ecdat-0.2.0/ecdat_core/tests/fixtures/demo_repo/utils/hasher.py +15 -0
- ecdat-0.2.0/ecdat_core/tests/fixtures/showcase_repo/auth/login.py +75 -0
- ecdat-0.2.0/ecdat_core/tests/fixtures/showcase_repo/certs/cert_verify.go +81 -0
- ecdat-0.2.0/ecdat_core/tests/fixtures/showcase_repo/keyexchange/channel.go +48 -0
- ecdat-0.2.0/ecdat_core/tests/fixtures/showcase_repo/legacy/LegacyCrypto.java +78 -0
- ecdat-0.2.0/ecdat_core/tests/fixtures/showcase_repo/payments/payment.py +64 -0
- ecdat-0.2.0/ecdat_core/tests/fixtures/showcase_repo/quantum/pqc_utils.py +67 -0
- ecdat-0.2.0/ecdat_core/tests/fixtures/showcase_repo/quantum/slh_signer.py +40 -0
- ecdat-0.2.0/ecdat_core/tests/fixtures/showcase_repo/tokens/signing.js +54 -0
- ecdat-0.2.0/ecdat_core/tests/test_cbom_export.py +419 -0
- ecdat-0.2.0/ecdat_core/tests/test_cbom_schema.py +163 -0
- ecdat-0.2.0/ecdat_core/tests/test_detector.py +267 -0
- ecdat-0.2.0/ecdat_core/tests/test_end_to_end.py +84 -0
- ecdat-0.2.0/ecdat_core/tests/test_ingestion.py +625 -0
- ecdat-0.2.0/ecdat_core/tests/test_models.py +239 -0
- ecdat-0.2.0/ecdat_core/tests/test_recommender.py +151 -0
- ecdat-0.2.0/ecdat_core/tests/test_risk_engine.py +250 -0
- ecdat-0.2.0/ecdat_core/tests/test_run_scan_sandbox.py +59 -0
- ecdat-0.2.0/ecdat_core/tests/test_signature_loader.py +210 -0
- ecdat-0.2.0/pyproject.toml +82 -0
- ecdat-0.2.0/setup.cfg +4 -0
ecdat-0.2.0/CHANGELOG.md
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to
|
|
7
|
+
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
8
|
+
|
|
9
|
+
## [0.2.0] - 2026-09-21
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **New `ecdat` command-line interface.** A pip-installable, terminal-native
|
|
15
|
+
front end for the scanner, with subcommands:
|
|
16
|
+
- `ecdat scan <path-or-url>` — scan a local directory or an `https://` Git
|
|
17
|
+
repository, with `--format pretty|json|cbom|summary`, `--output DIR`,
|
|
18
|
+
`--fail-on critical|high|medium|low`, `--limit N`, `--no-progress`,
|
|
19
|
+
`--quiet`, and `--git-url`.
|
|
20
|
+
- `ecdat demo` — scan the bundled, deliberately-insecure sample project with
|
|
21
|
+
zero setup (and `--path` to materialise a persistent copy).
|
|
22
|
+
- `ecdat doctor` — environment self-check (Python, platform, install
|
|
23
|
+
location, git, terminal, signatures, `ECDAT_HOME`) with a one-line fix per
|
|
24
|
+
failing check.
|
|
25
|
+
- `ecdat about` — credits, project links, and an animated 3D globe.
|
|
26
|
+
- `ecdat help [command]` — command overview and per-command help.
|
|
27
|
+
- `ecdat version` — version, engine, signature count, Python, and OS.
|
|
28
|
+
- Global flags `--version`, `--no-color`, and `--debug`.
|
|
29
|
+
- **Gradient ASCII banner** shown on interactive runs.
|
|
30
|
+
- **Animated 3D globe** in `ecdat about` (opt-out with `--no-anim`, duration
|
|
31
|
+
controlled by `--spin`).
|
|
32
|
+
- **Padlock verdict emblem** in the pretty scan report.
|
|
33
|
+
- **Bundled demo project** (`ecdat/demo_project/`) shipped inside the wheel, so
|
|
34
|
+
`ecdat demo` works with no repository checkout.
|
|
35
|
+
- **Crash-safe error handling.** Expected errors print a friendly message and a
|
|
36
|
+
documented exit code; unexpected errors are written to a local crash log
|
|
37
|
+
under `ECDAT_HOME/logs` with a pointer for bug reports, instead of a raw
|
|
38
|
+
traceback.
|
|
39
|
+
- **Documented exit codes** for scripting and CI: `0` success, `1` findings at
|
|
40
|
+
or above `--fail-on`, `2` usage/validation error, `3` scan/runtime/unexpected
|
|
41
|
+
error, `130` interrupted (`Ctrl-C`).
|
|
42
|
+
- `CHANGELOG.md` and `PYPI_README.md`, and a `[project.scripts]` console entry
|
|
43
|
+
point (`ecdat = "ecdat.cli:main"`).
|
|
44
|
+
|
|
45
|
+
### Changed
|
|
46
|
+
|
|
47
|
+
- **Distribution renamed to `ecdat`** (previously `ecdat-cbom`). A single wheel
|
|
48
|
+
now ships both import packages: the new app layer (`ecdat`) and the scanner
|
|
49
|
+
engine (`ecdat_core`). `python -m ecdat` behaves identically to the console
|
|
50
|
+
script; the legacy `python -m ecdat_core.cli` entry point is unchanged.
|
|
51
|
+
- **Engine: `run_scan()` gained a `sandboxed=` parameter.** Callers can opt a
|
|
52
|
+
trusted local scan out of the workspace sandbox (the CLI and TUI do this — the
|
|
53
|
+
user is the trust boundary), while the HTTP API keeps the sandbox enabled.
|
|
54
|
+
- Runtime dependency on `rich` added for the CLI/TUI renderers.
|
|
55
|
+
|
|
56
|
+
### Security
|
|
57
|
+
|
|
58
|
+
- CLI renderers treat scanned repository content (file paths, snippets,
|
|
59
|
+
algorithm names) as untrusted and render it as plain text, so it cannot
|
|
60
|
+
inject terminal escapes or Rich/HTML/Markdown markup.
|
ecdat-0.2.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Errorists Team
|
|
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.
|
ecdat-0.2.0/MANIFEST.in
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# MANIFEST.in — controls the SOURCE DISTRIBUTION (sdist) file list.
|
|
2
|
+
# The WHEEL is governed by [tool.setuptools.packages.find] and
|
|
3
|
+
# [tool.setuptools.package-data] in pyproject.toml.
|
|
4
|
+
#
|
|
5
|
+
# This repo is a monorepo (ecdat_core + backend + frontend), but only
|
|
6
|
+
# `ecdat_core` is published on PyPI. Everything else is pruned so
|
|
7
|
+
# `pip download ecdat-cbom` never pulls in the FastAPI backend or the
|
|
8
|
+
# React frontend. LICENSE is handled by [project] license-files and is
|
|
9
|
+
# not re-listed here.
|
|
10
|
+
|
|
11
|
+
include README.md
|
|
12
|
+
include pyproject.toml
|
|
13
|
+
include PYPI_README.md
|
|
14
|
+
include CHANGELOG.md
|
|
15
|
+
|
|
16
|
+
# Ship tests + fixtures in the sdist only (standard practice; tests are not
|
|
17
|
+
# part of the wheel).
|
|
18
|
+
recursive-include ecdat_core/tests *
|
|
19
|
+
recursive-include ecdat/tests *
|
|
20
|
+
|
|
21
|
+
# Never ship the monorepo's non-published areas.
|
|
22
|
+
prune backend
|
|
23
|
+
prune frontend
|
|
24
|
+
|
|
25
|
+
# Housekeeping.
|
|
26
|
+
global-exclude __pycache__
|
|
27
|
+
global-exclude *.py[cod]
|
|
28
|
+
global-exclude *.so
|
|
29
|
+
global-exclude .DS_Store
|
ecdat-0.2.0/PKG-INFO
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ecdat
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Cryptographic discovery and post-quantum readiness scanner — CLI with a gradient ASCII banner and an animated 3D globe (CBOM, CycloneDX 1.6)
|
|
5
|
+
Author: ECDAT Team
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/profm0r14rty/ecdat
|
|
8
|
+
Project-URL: Repository, https://github.com/profm0r14rty/ecdat
|
|
9
|
+
Project-URL: Issues, https://github.com/profm0r14rty/ecdat/issues
|
|
10
|
+
Project-URL: Changelog, https://github.com/profm0r14rty/ecdat/blob/main/CHANGELOG.md
|
|
11
|
+
Keywords: cbom,cli,cryptography,cyclonedx,post-quantum,pqc,quantum,sbom,security
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Intended Audience :: Information Technology
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
23
|
+
Classifier: Topic :: Security
|
|
24
|
+
Classifier: Topic :: Security :: Cryptography
|
|
25
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
26
|
+
Requires-Python: >=3.10
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
License-File: LICENSE
|
|
29
|
+
Requires-Dist: pydantic>=2
|
|
30
|
+
Requires-Dist: rich>=13.7
|
|
31
|
+
Provides-Extra: dev
|
|
32
|
+
Requires-Dist: pytest; extra == "dev"
|
|
33
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
34
|
+
Requires-Dist: jsonschema; extra == "dev"
|
|
35
|
+
Requires-Dist: build; extra == "dev"
|
|
36
|
+
Requires-Dist: twine; extra == "dev"
|
|
37
|
+
Dynamic: license-file
|
|
38
|
+
|
|
39
|
+
# ecdat
|
|
40
|
+
|
|
41
|
+
**ECDAT** is a [CycloneDX](https://cyclonedx.org/) **Cryptography Bill of
|
|
42
|
+
Materials (CBOM) scanner for post-quantum readiness**. One command finds the
|
|
43
|
+
cryptographic artefacts in a codebase — RSA, ECC, DH, DSA, MD5, SHA-1, DES,
|
|
44
|
+
3DES, RC4, AES, and others — scores each one's post-quantum risk with Mosca's
|
|
45
|
+
inequality, recommends NIST post-quantum replacements, and emits a real
|
|
46
|
+
CycloneDX 1.6 CBOM next to a dashboard-friendly risk summary.
|
|
47
|
+
|
|
48
|
+
It is a small, self-contained Python package (runtime dependencies: `pydantic`
|
|
49
|
+
and `rich`) — no FastAPI, Postgres, Redis, or Docker required. It runs fully
|
|
50
|
+
offline: the only network access is `git clone` for an explicit URL scan.
|
|
51
|
+
|
|
52
|
+
Why it is more than a lookalike scanner:
|
|
53
|
+
|
|
54
|
+
- **Real CBOM output.** The report is genuine CycloneDX 1.6, validated against
|
|
55
|
+
the official JSON Schema on every scan in the test suite, so Dependency-Track,
|
|
56
|
+
Syft, Grype, and other CycloneDX tooling parse it unchanged.
|
|
57
|
+
- **"Classically broken" is not "quantum vulnerable".** MD5, SHA-1, DES, 3DES,
|
|
58
|
+
and RC4 are reported as broken *today*; RSA, ECC, DH, and DSA as broken *by
|
|
59
|
+
Shor's algorithm*. An actively exploitable hash is never mislabeled
|
|
60
|
+
"quantum-safe".
|
|
61
|
+
- **Offline and private.** No telemetry, no update checks.
|
|
62
|
+
- **Crash-safe.** Expected errors print a clear message and exit code;
|
|
63
|
+
unexpected errors are written to a local crash log instead of a raw
|
|
64
|
+
traceback.
|
|
65
|
+
|
|
66
|
+
## Install
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
pipx install ecdat # recommended: isolated and on PATH
|
|
70
|
+
uv tool install ecdat # recommended if you use uv
|
|
71
|
+
pip install ecdat # into the active Python environment
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
If plain `pip` reports `externally-managed-environment`, that is
|
|
75
|
+
[PEP 668](https://peps.python.org/pep-0668/) protecting your OS Python — use
|
|
76
|
+
`pipx` or `uv tool` (or a virtualenv) instead of forcing the install. On
|
|
77
|
+
Windows, install with `py -m pip install ecdat`; if `ecdat` is not on `PATH`,
|
|
78
|
+
run the CLI as `py -m ecdat …`.
|
|
79
|
+
|
|
80
|
+
## 60-second tour
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
ecdat demo # scan the bundled sample project
|
|
84
|
+
ecdat scan . # scan the current directory
|
|
85
|
+
ecdat scan https://github.com/<user>/<repo> # scan a public https:// repo
|
|
86
|
+
ecdat about # credits and an animated 3D globe
|
|
87
|
+
ecdat doctor # check your environment
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Commands
|
|
91
|
+
|
|
92
|
+
| Command | Description |
|
|
93
|
+
|---------|-------------|
|
|
94
|
+
| `ecdat scan <path-or-url>` | Scan a local directory, or an `https://` Git repository |
|
|
95
|
+
| `ecdat demo` | Scan the bundled, deliberately-insecure sample project (zero setup) |
|
|
96
|
+
| `ecdat doctor` | Environment self-check with a one-line fix per problem |
|
|
97
|
+
| `ecdat about` | Credits, project links, and a spinning 3D globe |
|
|
98
|
+
| `ecdat help [command]` | Command overview, or full help for one command |
|
|
99
|
+
| `ecdat version` | Version, engine, signature count, Python, and OS |
|
|
100
|
+
|
|
101
|
+
Global flags: `--version`, `--no-color`, and `--debug`.
|
|
102
|
+
|
|
103
|
+
## Formats
|
|
104
|
+
|
|
105
|
+
`ecdat scan --format <pretty|json|cbom|summary>`:
|
|
106
|
+
|
|
107
|
+
| Format | Contents |
|
|
108
|
+
|--------|----------|
|
|
109
|
+
| `pretty` | Colourised terminal report (default) |
|
|
110
|
+
| `json` | The full `ScanResult` |
|
|
111
|
+
| `cbom` | A CycloneDX 1.6 CBOM |
|
|
112
|
+
| `summary` | The risk rollup used by dashboards |
|
|
113
|
+
|
|
114
|
+
Payload formats write **only** the payload to stdout; progress, warnings, and
|
|
115
|
+
errors go to stderr — so `ecdat scan . -f cbom > cbom.json` is safe to pipe.
|
|
116
|
+
`ecdat demo` supports `pretty`, `json`, and `summary`.
|
|
117
|
+
|
|
118
|
+
For CI, `ecdat scan . --fail-on high` exits `1` when a finding is at or above
|
|
119
|
+
that level (`quantum-safe` findings never count) and `0` when clean. The other
|
|
120
|
+
exit codes are `2` (usage/validation error), `3` (scan/runtime/unexpected
|
|
121
|
+
error), and `130` (interrupted with `Ctrl-C`).
|
|
122
|
+
|
|
123
|
+
## Guarantees
|
|
124
|
+
|
|
125
|
+
- **Offline by default.** Only `git clone` for an explicit `https://` URL scan
|
|
126
|
+
touches the network; local scans never do.
|
|
127
|
+
- **No telemetry and no update checks.**
|
|
128
|
+
- **Injection-safe rendering.** File paths, matched snippets, and algorithm
|
|
129
|
+
names from scanned (untrusted) code are rendered as plain text and cannot
|
|
130
|
+
inject terminal escapes or Rich/HTML/Markdown markup.
|
|
131
|
+
- **Validated Git-URL scanning.** Only `https://` URLs are cloned, and the host
|
|
132
|
+
is resolved and checked against private/reserved address ranges before any
|
|
133
|
+
clone runs.
|
|
134
|
+
|
|
135
|
+
## Links
|
|
136
|
+
|
|
137
|
+
- Source, issues, and documentation: <https://github.com/profm0r14rty/ecdat>
|
|
138
|
+
- Security policy: <https://github.com/profm0r14rty/ecdat/blob/main/SECURITY.md>
|
|
139
|
+
- Changelog: <https://github.com/profm0r14rty/ecdat/blob/main/CHANGELOG.md>
|
|
140
|
+
- Live demo dashboard: <https://ecdat-web.onrender.com>
|
|
141
|
+
- Live demo API: <https://ecdat-api.onrender.com>
|
|
142
|
+
- License (MIT): <https://github.com/profm0r14rty/ecdat/blob/main/LICENSE>
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# ecdat
|
|
2
|
+
|
|
3
|
+
**ECDAT** is a [CycloneDX](https://cyclonedx.org/) **Cryptography Bill of
|
|
4
|
+
Materials (CBOM) scanner for post-quantum readiness**. One command finds the
|
|
5
|
+
cryptographic artefacts in a codebase — RSA, ECC, DH, DSA, MD5, SHA-1, DES,
|
|
6
|
+
3DES, RC4, AES, and others — scores each one's post-quantum risk with Mosca's
|
|
7
|
+
inequality, recommends NIST post-quantum replacements, and emits a real
|
|
8
|
+
CycloneDX 1.6 CBOM next to a dashboard-friendly risk summary.
|
|
9
|
+
|
|
10
|
+
It is a small, self-contained Python package (runtime dependencies: `pydantic`
|
|
11
|
+
and `rich`) — no FastAPI, Postgres, Redis, or Docker required. It runs fully
|
|
12
|
+
offline: the only network access is `git clone` for an explicit URL scan.
|
|
13
|
+
|
|
14
|
+
Why it is more than a lookalike scanner:
|
|
15
|
+
|
|
16
|
+
- **Real CBOM output.** The report is genuine CycloneDX 1.6, validated against
|
|
17
|
+
the official JSON Schema on every scan in the test suite, so Dependency-Track,
|
|
18
|
+
Syft, Grype, and other CycloneDX tooling parse it unchanged.
|
|
19
|
+
- **"Classically broken" is not "quantum vulnerable".** MD5, SHA-1, DES, 3DES,
|
|
20
|
+
and RC4 are reported as broken *today*; RSA, ECC, DH, and DSA as broken *by
|
|
21
|
+
Shor's algorithm*. An actively exploitable hash is never mislabeled
|
|
22
|
+
"quantum-safe".
|
|
23
|
+
- **Offline and private.** No telemetry, no update checks.
|
|
24
|
+
- **Crash-safe.** Expected errors print a clear message and exit code;
|
|
25
|
+
unexpected errors are written to a local crash log instead of a raw
|
|
26
|
+
traceback.
|
|
27
|
+
|
|
28
|
+
## Install
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
pipx install ecdat # recommended: isolated and on PATH
|
|
32
|
+
uv tool install ecdat # recommended if you use uv
|
|
33
|
+
pip install ecdat # into the active Python environment
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
If plain `pip` reports `externally-managed-environment`, that is
|
|
37
|
+
[PEP 668](https://peps.python.org/pep-0668/) protecting your OS Python — use
|
|
38
|
+
`pipx` or `uv tool` (or a virtualenv) instead of forcing the install. On
|
|
39
|
+
Windows, install with `py -m pip install ecdat`; if `ecdat` is not on `PATH`,
|
|
40
|
+
run the CLI as `py -m ecdat …`.
|
|
41
|
+
|
|
42
|
+
## 60-second tour
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
ecdat demo # scan the bundled sample project
|
|
46
|
+
ecdat scan . # scan the current directory
|
|
47
|
+
ecdat scan https://github.com/<user>/<repo> # scan a public https:// repo
|
|
48
|
+
ecdat about # credits and an animated 3D globe
|
|
49
|
+
ecdat doctor # check your environment
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Commands
|
|
53
|
+
|
|
54
|
+
| Command | Description |
|
|
55
|
+
|---------|-------------|
|
|
56
|
+
| `ecdat scan <path-or-url>` | Scan a local directory, or an `https://` Git repository |
|
|
57
|
+
| `ecdat demo` | Scan the bundled, deliberately-insecure sample project (zero setup) |
|
|
58
|
+
| `ecdat doctor` | Environment self-check with a one-line fix per problem |
|
|
59
|
+
| `ecdat about` | Credits, project links, and a spinning 3D globe |
|
|
60
|
+
| `ecdat help [command]` | Command overview, or full help for one command |
|
|
61
|
+
| `ecdat version` | Version, engine, signature count, Python, and OS |
|
|
62
|
+
|
|
63
|
+
Global flags: `--version`, `--no-color`, and `--debug`.
|
|
64
|
+
|
|
65
|
+
## Formats
|
|
66
|
+
|
|
67
|
+
`ecdat scan --format <pretty|json|cbom|summary>`:
|
|
68
|
+
|
|
69
|
+
| Format | Contents |
|
|
70
|
+
|--------|----------|
|
|
71
|
+
| `pretty` | Colourised terminal report (default) |
|
|
72
|
+
| `json` | The full `ScanResult` |
|
|
73
|
+
| `cbom` | A CycloneDX 1.6 CBOM |
|
|
74
|
+
| `summary` | The risk rollup used by dashboards |
|
|
75
|
+
|
|
76
|
+
Payload formats write **only** the payload to stdout; progress, warnings, and
|
|
77
|
+
errors go to stderr — so `ecdat scan . -f cbom > cbom.json` is safe to pipe.
|
|
78
|
+
`ecdat demo` supports `pretty`, `json`, and `summary`.
|
|
79
|
+
|
|
80
|
+
For CI, `ecdat scan . --fail-on high` exits `1` when a finding is at or above
|
|
81
|
+
that level (`quantum-safe` findings never count) and `0` when clean. The other
|
|
82
|
+
exit codes are `2` (usage/validation error), `3` (scan/runtime/unexpected
|
|
83
|
+
error), and `130` (interrupted with `Ctrl-C`).
|
|
84
|
+
|
|
85
|
+
## Guarantees
|
|
86
|
+
|
|
87
|
+
- **Offline by default.** Only `git clone` for an explicit `https://` URL scan
|
|
88
|
+
touches the network; local scans never do.
|
|
89
|
+
- **No telemetry and no update checks.**
|
|
90
|
+
- **Injection-safe rendering.** File paths, matched snippets, and algorithm
|
|
91
|
+
names from scanned (untrusted) code are rendered as plain text and cannot
|
|
92
|
+
inject terminal escapes or Rich/HTML/Markdown markup.
|
|
93
|
+
- **Validated Git-URL scanning.** Only `https://` URLs are cloned, and the host
|
|
94
|
+
is resolved and checked against private/reserved address ranges before any
|
|
95
|
+
clone runs.
|
|
96
|
+
|
|
97
|
+
## Links
|
|
98
|
+
|
|
99
|
+
- Source, issues, and documentation: <https://github.com/profm0r14rty/ecdat>
|
|
100
|
+
- Security policy: <https://github.com/profm0r14rty/ecdat/blob/main/SECURITY.md>
|
|
101
|
+
- Changelog: <https://github.com/profm0r14rty/ecdat/blob/main/CHANGELOG.md>
|
|
102
|
+
- Live demo dashboard: <https://ecdat-web.onrender.com>
|
|
103
|
+
- Live demo API: <https://ecdat-api.onrender.com>
|
|
104
|
+
- License (MIT): <https://github.com/profm0r14rty/ecdat/blob/main/LICENSE>
|
ecdat-0.2.0/README.md
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
# ECDAT - Enterprise Cryptographic Discovery & Analysis Tool
|
|
2
|
+
|
|
3
|
+
ECDAT is a Cryptography Bill of Materials (CBOM) scanner for post-quantum readiness assessment. It discovers cryptographic artefacts in source code, assesses their quantum-computing risk using Mosca's algorithm, and recommends NIST post-quantum replacements, outputting a CycloneDX 1.6 CBOM report.
|
|
4
|
+
|
|
5
|
+
## Install the CLI
|
|
6
|
+
|
|
7
|
+
The `ecdat` command is a standalone, pip-installable scanner — no Docker,
|
|
8
|
+
Postgres, Redis, or API required. It runs fully offline; see
|
|
9
|
+
[Privacy and trust](#privacy-and-trust).
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pipx install ecdat # recommended: isolated and on PATH
|
|
13
|
+
uv tool install ecdat # recommended if you use uv
|
|
14
|
+
pip install ecdat # into the active Python environment
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
If `pip install` stops with `error: externally-managed-environment`, that is
|
|
18
|
+
[PEP 668](https://peps.python.org/pep-0668/) protecting your OS Python — use
|
|
19
|
+
`pipx` or `uv tool` (or a virtualenv) rather than forcing the install. On
|
|
20
|
+
Windows, install with `py -m pip install ecdat`; if `ecdat` is not on `PATH`,
|
|
21
|
+
run the CLI as `py -m ecdat …`.
|
|
22
|
+
|
|
23
|
+
Upgrade or remove it later:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
pipx upgrade ecdat # or: uv tool upgrade ecdat
|
|
27
|
+
pip install --upgrade ecdat
|
|
28
|
+
pipx uninstall ecdat # or: uv tool uninstall ecdat
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### 60-second tour
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
ecdat demo # scan the bundled sample project
|
|
35
|
+
ecdat about # credits and an animated 3D globe
|
|
36
|
+
ecdat scan . # scan the current directory
|
|
37
|
+
ecdat scan https://github.com/<user>/<repo> # scan a public https:// repo
|
|
38
|
+
ecdat help # list every command
|
|
39
|
+
ecdat doctor # check your environment
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
<!-- screenshots: docs/img/*.png -->
|
|
43
|
+
|
|
44
|
+
### Commands
|
|
45
|
+
|
|
46
|
+
| Command | What it does |
|
|
47
|
+
|---------|--------------|
|
|
48
|
+
| `ecdat scan <path-or-url>` | Scan a local directory, or an `https://` Git repository |
|
|
49
|
+
| `ecdat demo` | Scan the bundled, deliberately-insecure sample project (zero setup) |
|
|
50
|
+
| `ecdat doctor` | Environment self-check (Python, git, signatures, `ECDAT_HOME`) |
|
|
51
|
+
| `ecdat about` | Credits, project links, and a spinning 3D globe |
|
|
52
|
+
| `ecdat help [command]` | Command overview, or full help for one command |
|
|
53
|
+
| `ecdat version` | Version, engine, signature count, Python, and OS |
|
|
54
|
+
|
|
55
|
+
Global flags: `--version`, `--no-color`, `--debug`.
|
|
56
|
+
|
|
57
|
+
### Output formats
|
|
58
|
+
|
|
59
|
+
`ecdat scan --format <pretty|json|cbom|summary>`:
|
|
60
|
+
|
|
61
|
+
- `pretty` (default) — the colourised terminal report.
|
|
62
|
+
- `json` — the full `ScanResult`.
|
|
63
|
+
- `cbom` — a CycloneDX 1.6 CBOM.
|
|
64
|
+
- `summary` — the risk rollup used by dashboards.
|
|
65
|
+
|
|
66
|
+
Payload formats write **only** the payload to stdout; progress, warnings, and
|
|
67
|
+
errors go to stderr. That keeps `ecdat scan . -f cbom > cbom.json` safe to
|
|
68
|
+
pipe. `ecdat demo` supports `pretty`, `json`, and `summary`.
|
|
69
|
+
|
|
70
|
+
### Use in CI
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
ecdat scan . --fail-on high
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
`--fail-on <critical|high|medium|low>` returns exit code `1` when any finding
|
|
77
|
+
is at or above that level (`quantum-safe` findings never count). Exit codes:
|
|
78
|
+
`0` success · `1` findings at or above `--fail-on` · `2` usage/validation
|
|
79
|
+
error · `3` scan/runtime/unexpected error · `130` interrupted (`Ctrl-C`).
|
|
80
|
+
|
|
81
|
+
### Privacy and trust
|
|
82
|
+
|
|
83
|
+
- **Runs fully offline.** The only network access is `git clone` for an
|
|
84
|
+
explicit `https://` URL scan; local scans never touch the network.
|
|
85
|
+
- **No telemetry, no update checks.**
|
|
86
|
+
- **Hostile repo content cannot inject escapes or markup.** File paths,
|
|
87
|
+
snippets, and algorithm names from scanned repositories are attacker-
|
|
88
|
+
controlled; the CLI renders them as plain text, never as Rich/HTML/Markdown
|
|
89
|
+
markup. Covered by `ecdat/tests/test_app_render.py`.
|
|
90
|
+
|
|
91
|
+
## Running locally
|
|
92
|
+
|
|
93
|
+
### Prerequisites
|
|
94
|
+
|
|
95
|
+
- Docker with Docker Compose (Compose v2+).
|
|
96
|
+
|
|
97
|
+
### Infrastructure + API + Dashboard
|
|
98
|
+
|
|
99
|
+
From the repo root, build and start the whole stack:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
docker compose up --build
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
This brings up four services:
|
|
106
|
+
|
|
107
|
+
| Service | Image / source | Purpose |
|
|
108
|
+
|----------|----------------------|----------------------------------------------------|
|
|
109
|
+
| postgres | `postgres:16-alpine` | Persistent scan database (named volume `postgres_data`) |
|
|
110
|
+
| redis | `redis:7-alpine` | Scan job status keys (`scan:{id}:status`) |
|
|
111
|
+
| api | `backend/Dockerfile` | FastAPI app on `http://localhost:8000`, uvicorn with hot reload |
|
|
112
|
+
| web | `frontend/Dockerfile`| React dashboard at `http://localhost:5173`, nginx serves the build and reverse-proxies `/api` + `/health` to `api` |
|
|
113
|
+
|
|
114
|
+
Database credentials are read from `.env` (copy `.env.example` to `.env` and
|
|
115
|
+
adjust as needed). The compose file falls back to the same dev defaults, so a
|
|
116
|
+
plain `docker compose up --build` works with no `.env` file at all.
|
|
117
|
+
|
|
118
|
+
Smoke test — the API should answer immediately once the containers are up
|
|
119
|
+
(either directly, or through the web container's proxy):
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
curl http://localhost:8000/health
|
|
123
|
+
# {"status":"ok"}
|
|
124
|
+
curl http://localhost:5173/health
|
|
125
|
+
# {"status":"ok"}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
The dashboard lives at `http://localhost:5173`. The `web` container keeps the
|
|
129
|
+
frontend bundle's default same-origin `VITE_API_BASE_URL`: nginx serves the
|
|
130
|
+
compiled static files and forwards `/api` + `/health` to the `api` service, so
|
|
131
|
+
no runtime env substitution or CORS config is needed in the containerized flow.
|
|
132
|
+
|
|
133
|
+
Details:
|
|
134
|
+
|
|
135
|
+
- On container start, the API entrypoint (`backend/docker-entrypoint.sh`)
|
|
136
|
+
runs `alembic upgrade head` against Postgres before launching uvicorn.
|
|
137
|
+
- `./backend` is bind-mounted into the container and uvicorn runs with
|
|
138
|
+
`--reload`, so backend code edits take effect without rebuilding.
|
|
139
|
+
- The `api` service waits for both `postgres` and `redis` to report healthy
|
|
140
|
+
(`depends_on.condition: service_healthy`); `web` waits for `api` to start.
|
|
141
|
+
|
|
142
|
+
Tear down with `docker compose down` (add `-v` to also delete the Postgres
|
|
143
|
+
named volume).
|
|
144
|
+
|
|
145
|
+
## Live Deployment
|
|
146
|
+
|
|
147
|
+
The project is deployed on Render's free tier.
|
|
148
|
+
|
|
149
|
+
- **API**: [https://ecdat-api.onrender.com](https://ecdat-api.onrender.com)
|
|
150
|
+
- **Dashboard**: [https://ecdat-web.onrender.com](https://ecdat-web.onrender.com)
|
|
151
|
+
|
|
152
|
+
**Note on cold starts**: The API sleeps after 15 minutes of inactivity. The first request after sleep will take about a minute to respond while the service warms up. Please hit the `/health` endpoint once before starting the demo to ensure the app is responsive.
|
|
153
|
+
|
|
154
|
+
## Securing a non-demo deployment (optional API-key auth)
|
|
155
|
+
|
|
156
|
+
By default ECDAT's API is fully open — anyone with the URL can submit scans and
|
|
157
|
+
read everyone's scan history. That's intentional for the public hackathon demo.
|
|
158
|
+
For anything resembling a real deployment, the API ships with a minimal
|
|
159
|
+
single-tier gate: when enabled, every `/api/scans*` endpoint (writes *and*
|
|
160
|
+
reads) requires an `Authorization: Bearer <key>` header. Full multi-tenant
|
|
161
|
+
auth (users, orgs, roles) is deliberately not part of this mechanism.
|
|
162
|
+
|
|
163
|
+
1. **Generate one or more keys** out-of-band — never reuse committed values:
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
python -c "import secrets; print(secrets.token_urlsafe(32))"
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
2. **Enable the gate** by setting two environment variables on the API:
|
|
170
|
+
|
|
171
|
+
- `REQUIRE_API_KEY=true`
|
|
172
|
+
- `API_KEYS=<comma-separated keys>` (whitespace around keys is fine)
|
|
173
|
+
|
|
174
|
+
Where to set them depends on the deployment:
|
|
175
|
+
|
|
176
|
+
- **Docker Compose** — add both to your `.env` (copied from
|
|
177
|
+
`.env.example`); the `api` service passes them through.
|
|
178
|
+
- **Render** — set both in the Web Service's **Environment** panel
|
|
179
|
+
(note: Render's env vars are separate from a local `.env` file) and
|
|
180
|
+
redeploy. Render's env changes apply on the next deploy — the gate reads
|
|
181
|
+
them per request, so no restart is needed once the new env is live.
|
|
182
|
+
|
|
183
|
+
The gate is **off by default**; with `REQUIRE_API_KEY` unset or `false`,
|
|
184
|
+
behavior is unchanged. If you enable it without setting `API_KEYS`, the API
|
|
185
|
+
fails closed (HTTP 500) rather than silently opening up.
|
|
186
|
+
|
|
187
|
+
3. **Clients** must send the key on every (non-`/health`) request:
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
curl -H "Authorization: Bearer <key>" https://your-api/api/scans
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
`GET /health` stays public so uptime monitors and warm-keeping pings keep
|
|
194
|
+
working.
|
|
195
|
+
|
|
196
|
+
**Dashboard caveat**: the bundled dashboard is a public-demo artifact — its API
|
|
197
|
+
client sends no auth header, so once you flip the gate on, the dashboard's
|
|
198
|
+
`/api/scans` calls will be rejected (401). A non-demo deployment either uses
|
|
199
|
+
API-keyed clients / CI pipelines, or terminates the key at a same-origin proxy.
|
|
200
|
+
Key entry in the UI is intentionally out of scope for this gate.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"""ECDAT — Enterprise Cryptographic Discovery & Analysis Tool."""
|
|
2
|
+
|
|
3
|
+
import importlib.metadata
|
|
4
|
+
|
|
5
|
+
DIST_NAME = "ecdat"
|
|
6
|
+
|
|
7
|
+
try:
|
|
8
|
+
__version__ = importlib.metadata.version(DIST_NAME)
|
|
9
|
+
except importlib.metadata.PackageNotFoundError:
|
|
10
|
+
__version__ = "0+unknown"
|