codedd-cli 0.1.1__py3-none-any.whl
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.
- codedd_cli/__init__.py +3 -0
- codedd_cli/__main__.py +19 -0
- codedd_cli/api/__init__.py +4 -0
- codedd_cli/api/client.py +120 -0
- codedd_cli/api/endpoints.py +44 -0
- codedd_cli/api/exceptions.py +24 -0
- codedd_cli/auditor/__init__.py +6 -0
- codedd_cli/auditor/architecture_analyzer.py +1251 -0
- codedd_cli/auditor/architecture_prompts.py +173 -0
- codedd_cli/auditor/complexity_analyzer.py +1739 -0
- codedd_cli/auditor/dependency_scanner.py +2485 -0
- codedd_cli/auditor/file_auditor.py +578 -0
- codedd_cli/auditor/git_stats_collector.py +417 -0
- codedd_cli/auditor/response_parser.py +484 -0
- codedd_cli/auditor/vulnerability_validator.py +323 -0
- codedd_cli/auth/__init__.py +4 -0
- codedd_cli/auth/session.py +40 -0
- codedd_cli/auth/token_manager.py +86 -0
- codedd_cli/cli.py +69 -0
- codedd_cli/commands/__init__.py +1 -0
- codedd_cli/commands/audit_cmd.py +1987 -0
- codedd_cli/commands/audits_cmd.py +276 -0
- codedd_cli/commands/auth_cmd.py +235 -0
- codedd_cli/commands/config_cmd.py +421 -0
- codedd_cli/commands/scope_cmd.py +1016 -0
- codedd_cli/config/__init__.py +4 -0
- codedd_cli/config/constants.py +22 -0
- codedd_cli/config/settings.py +389 -0
- codedd_cli/llm/__init__.py +1 -0
- codedd_cli/llm/key_manager.py +267 -0
- codedd_cli/models/__init__.py +5 -0
- codedd_cli/models/account.py +13 -0
- codedd_cli/models/audit.py +31 -0
- codedd_cli/models/local_directory.py +25 -0
- codedd_cli/scanner/__init__.py +18 -0
- codedd_cli/scanner/file_classifier.py +752 -0
- codedd_cli/scanner/file_walker.py +213 -0
- codedd_cli/scanner/line_counter.py +80 -0
- codedd_cli/utils/__init__.py +1 -0
- codedd_cli/utils/directory_validator.py +178 -0
- codedd_cli/utils/display.py +497 -0
- codedd_cli/utils/payload_inspector.py +178 -0
- codedd_cli/utils/security.py +14 -0
- codedd_cli/utils/validators.py +37 -0
- codedd_cli-0.1.1.dist-info/METADATA +306 -0
- codedd_cli-0.1.1.dist-info/RECORD +49 -0
- codedd_cli-0.1.1.dist-info/WHEEL +4 -0
- codedd_cli-0.1.1.dist-info/entry_points.txt +3 -0
- codedd_cli-0.1.1.dist-info/licenses/LICENSE +21 -0
codedd_cli/__init__.py
ADDED
codedd_cli/__main__.py
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""Allow running via ``python -m codedd_cli``."""
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
|
|
5
|
+
from codedd_cli.api.exceptions import CodeDDConnectionError
|
|
6
|
+
from codedd_cli.cli import app
|
|
7
|
+
from codedd_cli.utils.display import print_error
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def main() -> None:
|
|
11
|
+
try:
|
|
12
|
+
app()
|
|
13
|
+
except CodeDDConnectionError as e:
|
|
14
|
+
print_error(str(e))
|
|
15
|
+
sys.exit(1)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
if __name__ == "__main__":
|
|
19
|
+
main()
|
codedd_cli/api/client.py
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"""
|
|
2
|
+
HTTP client for communicating with the CodeDD API.
|
|
3
|
+
|
|
4
|
+
Wraps ``httpx`` with:
|
|
5
|
+
- Automatic ``X-CLI-Token`` header injection
|
|
6
|
+
- Configurable base URL from ``~/.codedd/config.toml``
|
|
7
|
+
- Retry logic with exponential back-off
|
|
8
|
+
- TLS certificate verification (enforced)
|
|
9
|
+
- Descriptive User-Agent header
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import time
|
|
13
|
+
from typing import Any
|
|
14
|
+
|
|
15
|
+
import httpx
|
|
16
|
+
|
|
17
|
+
from codedd_cli import __version__
|
|
18
|
+
from codedd_cli.api.exceptions import CodeDDConnectionError
|
|
19
|
+
from codedd_cli.auth.token_manager import TokenManager
|
|
20
|
+
from codedd_cli.config.constants import (
|
|
21
|
+
MAX_RETRIES,
|
|
22
|
+
REQUEST_TIMEOUT_SECONDS,
|
|
23
|
+
USER_AGENT_PREFIX,
|
|
24
|
+
)
|
|
25
|
+
from codedd_cli.config.settings import ConfigManager
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class CodeDDClient:
|
|
29
|
+
"""
|
|
30
|
+
Thin HTTP client that authenticates via the ``X-CLI-Token`` header.
|
|
31
|
+
|
|
32
|
+
Usage::
|
|
33
|
+
|
|
34
|
+
client = CodeDDClient()
|
|
35
|
+
resp = client.get("/api/cli/audits/", params={"limit": 20})
|
|
36
|
+
data = resp.json()
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
def __init__(self, config: ConfigManager | None = None) -> None:
|
|
40
|
+
self._config = config or ConfigManager()
|
|
41
|
+
self._base_url = self._config.api_url.rstrip("/")
|
|
42
|
+
self._token = TokenManager.retrieve()
|
|
43
|
+
|
|
44
|
+
# For localhost HTTP, disable TLS verification (not applicable anyway)
|
|
45
|
+
# For HTTPS, always verify certificates
|
|
46
|
+
verify_tls = not self._base_url.startswith("http://localhost") and not self._base_url.startswith(
|
|
47
|
+
"http://127.0.0.1"
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
self._client = httpx.Client(
|
|
51
|
+
base_url=self._base_url,
|
|
52
|
+
headers=self._build_headers(),
|
|
53
|
+
timeout=REQUEST_TIMEOUT_SECONDS,
|
|
54
|
+
verify=verify_tls,
|
|
55
|
+
follow_redirects=True,
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
def _build_headers(self) -> dict[str, str]:
|
|
59
|
+
headers: dict[str, str] = {
|
|
60
|
+
"User-Agent": f"{USER_AGENT_PREFIX}/{__version__}",
|
|
61
|
+
"Accept": "application/json",
|
|
62
|
+
}
|
|
63
|
+
if self._token:
|
|
64
|
+
headers["X-CLI-Token"] = self._token
|
|
65
|
+
return headers
|
|
66
|
+
|
|
67
|
+
# ---- HTTP verbs with retry ----
|
|
68
|
+
|
|
69
|
+
def get(self, path: str, **kwargs: Any) -> httpx.Response:
|
|
70
|
+
return self._request("GET", path, **kwargs)
|
|
71
|
+
|
|
72
|
+
def post(self, path: str, **kwargs: Any) -> httpx.Response:
|
|
73
|
+
return self._request("POST", path, **kwargs)
|
|
74
|
+
|
|
75
|
+
# ---- internal ----
|
|
76
|
+
|
|
77
|
+
def _request(self, method: str, path: str, **kwargs: Any) -> httpx.Response:
|
|
78
|
+
"""
|
|
79
|
+
Execute an HTTP request with automatic retries on transient errors.
|
|
80
|
+
|
|
81
|
+
Retries on 5xx responses and connection errors using exponential
|
|
82
|
+
back-off (1s, 2s, 4s …).
|
|
83
|
+
"""
|
|
84
|
+
last_exc: Exception | None = None
|
|
85
|
+
|
|
86
|
+
for attempt in range(1, MAX_RETRIES + 1):
|
|
87
|
+
try:
|
|
88
|
+
resp = self._client.request(method, path, **kwargs)
|
|
89
|
+
|
|
90
|
+
# Don't retry client errors (4xx)
|
|
91
|
+
if resp.status_code < 500:
|
|
92
|
+
return resp
|
|
93
|
+
|
|
94
|
+
# Retry on server errors
|
|
95
|
+
if attempt < MAX_RETRIES:
|
|
96
|
+
time.sleep(2 ** (attempt - 1))
|
|
97
|
+
continue
|
|
98
|
+
|
|
99
|
+
return resp
|
|
100
|
+
|
|
101
|
+
except httpx.RequestError as exc:
|
|
102
|
+
last_exc = exc
|
|
103
|
+
if attempt < MAX_RETRIES:
|
|
104
|
+
time.sleep(2 ** (attempt - 1))
|
|
105
|
+
continue
|
|
106
|
+
raise CodeDDConnectionError() from None
|
|
107
|
+
|
|
108
|
+
# Should not normally reach here, but satisfy the type checker
|
|
109
|
+
if last_exc:
|
|
110
|
+
raise CodeDDConnectionError() from None
|
|
111
|
+
raise RuntimeError("Request failed after retries") # pragma: no cover
|
|
112
|
+
|
|
113
|
+
def close(self) -> None:
|
|
114
|
+
self._client.close()
|
|
115
|
+
|
|
116
|
+
def __enter__(self):
|
|
117
|
+
return self
|
|
118
|
+
|
|
119
|
+
def __exit__(self, *args):
|
|
120
|
+
self.close()
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Server endpoint path constants.
|
|
3
|
+
|
|
4
|
+
All paths are relative to the ``api_url`` stored in the CLI config
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Endpoints:
|
|
9
|
+
"""Centralised registry of API paths consumed by the CLI."""
|
|
10
|
+
|
|
11
|
+
# Authentication
|
|
12
|
+
VERIFY_TOKEN = "/api/cli/auth/verify/"
|
|
13
|
+
|
|
14
|
+
# Audits
|
|
15
|
+
LIST_AUDITS = "/api/cli/audits/"
|
|
16
|
+
|
|
17
|
+
# Scope
|
|
18
|
+
REGISTER_SCOPE = "/api/cli/scope/register/"
|
|
19
|
+
SCOPE_FILES = "/api/cli/scope/files/"
|
|
20
|
+
|
|
21
|
+
# Audit lifecycle
|
|
22
|
+
AUDIT_CAN_START = "/api/cli/audit/can-start/"
|
|
23
|
+
AUDIT_START = "/api/cli/audit/start/"
|
|
24
|
+
AUDIT_CHECKOUT = "/api/cli/audit/checkout/"
|
|
25
|
+
AUDIT_PAYMENT_STATUS = "/api/cli/audit/payment-status/"
|
|
26
|
+
|
|
27
|
+
# Local audit execution (CLI-side file auditing)
|
|
28
|
+
AUDIT_PLAN = "/api/cli/audit/plan/"
|
|
29
|
+
AUDIT_RESULTS = "/api/cli/audit/results/"
|
|
30
|
+
AUDIT_COMPLETE = "/api/cli/audit/complete/"
|
|
31
|
+
|
|
32
|
+
# Local complexity analysis results
|
|
33
|
+
AUDIT_COMPLEXITY = "/api/cli/audit/complexity/"
|
|
34
|
+
|
|
35
|
+
# Local dependency scanning
|
|
36
|
+
AUDIT_DEPENDENCY_CONFIG = "/api/cli/audit/dependency-config/"
|
|
37
|
+
AUDIT_DEPENDENCIES = "/api/cli/audit/dependencies/"
|
|
38
|
+
|
|
39
|
+
# Local git statistics (for CLI-driven audits; enables dashboards)
|
|
40
|
+
AUDIT_GIT_STATISTICS = "/api/cli/audit/git-statistics/"
|
|
41
|
+
AUDIT_VULNERABILITY_VALIDATION = "/api/cli/audit/vulnerability-validation/"
|
|
42
|
+
|
|
43
|
+
# Architecture analysis (Phase 1+2 run locally; server runs Phase 3 + storage)
|
|
44
|
+
AUDIT_ARCHITECTURE = "/api/cli/audit/architecture/"
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""
|
|
2
|
+
API-layer exceptions with user-facing messages.
|
|
3
|
+
|
|
4
|
+
Raised when the CLI cannot reach the CodeDD server (connection refused,
|
|
5
|
+
timeout, server disconnected, etc.). Handled at the CLI entry point to
|
|
6
|
+
display a single, clear message instead of a full traceback.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
# Pre-defined message shown when the remote is not responding.
|
|
10
|
+
CONNECTION_ERROR_MESSAGE = (
|
|
11
|
+
"Unable to reach CodeDD. "
|
|
12
|
+
"Check that the server is running and your network connection is available, "
|
|
13
|
+
"or try again later."
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class CodeDDConnectionError(Exception):
|
|
18
|
+
"""
|
|
19
|
+
Raised when a request to the CodeDD API fails due to connection
|
|
20
|
+
or transport errors (e.g. server not responding, timeout, disconnect).
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
def __init__(self, message: str | None = None) -> None:
|
|
24
|
+
super().__init__(message or CONNECTION_ERROR_MESSAGE)
|