vibe-coding-qa 0.5.0__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.
- dashboard/__init__.py +10 -0
- dashboard/backend/__init__.py +11 -0
- dashboard/backend/__main__.py +6 -0
- dashboard/backend/ai/__init__.py +6 -0
- dashboard/backend/ai/provider.py +102 -0
- dashboard/backend/ai/service.py +757 -0
- dashboard/backend/api/__init__.py +5 -0
- dashboard/backend/api/ai.py +142 -0
- dashboard/backend/api/dashboard.py +34 -0
- dashboard/backend/api/deps.py +51 -0
- dashboard/backend/api/findings.py +102 -0
- dashboard/backend/api/intel.py +41 -0
- dashboard/backend/api/repositories.py +62 -0
- dashboard/backend/api/scans.py +168 -0
- dashboard/backend/api/system.py +69 -0
- dashboard/backend/config.py +180 -0
- dashboard/backend/main.py +183 -0
- dashboard/backend/persistence/__init__.py +5 -0
- dashboard/backend/persistence/database.py +278 -0
- dashboard/backend/persistence/store.py +600 -0
- dashboard/backend/profiles.py +141 -0
- dashboard/backend/schemas.py +452 -0
- dashboard/backend/security.py +158 -0
- dashboard/backend/services/__init__.py +7 -0
- dashboard/backend/services/dashboard.py +172 -0
- dashboard/backend/services/intel.py +341 -0
- dashboard/backend/services/paths.py +38 -0
- dashboard/backend/services/repositories.py +123 -0
- dashboard/backend/services/scans.py +328 -0
- dashboard/backend/services/settings.py +49 -0
- dashboard/frontend/dist/assets/index-COC-CdqD.js +492 -0
- dashboard/frontend/dist/assets/index-hWDLRaLr.css +1 -0
- dashboard/frontend/dist/index.html +29 -0
- dashboard/frontend/dist/phone-mascots.gif +0 -0
- dashboard/launcher.py +48 -0
- vibe_coding_qa/__init__.py +140 -0
- vibe_coding_qa/__main__.py +5 -0
- vibe_coding_qa/ai_review.py +165 -0
- vibe_coding_qa/cli.py +157 -0
- vibe_coding_qa/engine.py +860 -0
- vibe_coding_qa/fixes.py +222 -0
- vibe_coding_qa/gates.py +300 -0
- vibe_coding_qa/profile.py +471 -0
- vibe_coding_qa/repo.py +188 -0
- vibe_coding_qa/reporters/__init__.py +253 -0
- vibe_coding_qa/scanners/__init__.py +195 -0
- vibe_coding_qa/scanners/compliance.py +167 -0
- vibe_coding_qa/scanners/database.py +316 -0
- vibe_coding_qa/scanners/dependencies.py +595 -0
- vibe_coding_qa/scanners/infrastructure.py +125 -0
- vibe_coding_qa/scanners/performance.py +84 -0
- vibe_coding_qa/scanners/quality.py +129 -0
- vibe_coding_qa/scanners/security.py +521 -0
- vibe_coding_qa-0.5.0.dist-info/METADATA +323 -0
- vibe_coding_qa-0.5.0.dist-info/RECORD +58 -0
- vibe_coding_qa-0.5.0.dist-info/WHEEL +5 -0
- vibe_coding_qa-0.5.0.dist-info/entry_points.txt +3 -0
- vibe_coding_qa-0.5.0.dist-info/top_level.txt +2 -0
dashboard/__init__.py
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"""Vibe Coding QA dashboard (backend API + web UI).
|
|
2
|
+
|
|
3
|
+
The dashboard is an optional layer on top of the ``vibe_coding_qa`` engine: the
|
|
4
|
+
engine stays the single source of truth for scanning, scoring and the release
|
|
5
|
+
gate, and every dashboard feature works without AI.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from vibe_coding_qa import __version__
|
|
9
|
+
|
|
10
|
+
__all__ = ["__version__"]
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"""Vibe Coding QA dashboard backend (FastAPI + SQLite).
|
|
2
|
+
|
|
3
|
+
This package wraps the existing :mod:`vibe_coding_qa` engine behind a typed HTTP
|
|
4
|
+
API. It never re-implements scanning logic: the engine remains the single source
|
|
5
|
+
of truth for findings, scoring and the release gate.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
__all__ = ["__version__"]
|
|
9
|
+
|
|
10
|
+
# Kept in sync with vibe_coding_qa.cli and pyproject/CHANGELOG.
|
|
11
|
+
__version__ = "0.5.0"
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"""OpenAI-compatible chat provider used by the AI features.
|
|
2
|
+
|
|
3
|
+
The provider is deliberately small and stdlib-only (``urllib``) so the optional
|
|
4
|
+
AI features add no runtime dependency to the core engine. It is provider-neutral:
|
|
5
|
+
any endpoint that speaks the OpenAI chat-completions shape works (OpenRouter,
|
|
6
|
+
Groq, Ollama, vLLM, OpenAI, ...).
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import json
|
|
12
|
+
import urllib.error
|
|
13
|
+
import urllib.request
|
|
14
|
+
from dataclasses import dataclass
|
|
15
|
+
|
|
16
|
+
from vibe_coding_qa.scanners import redact_secrets
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class AIError(RuntimeError):
|
|
20
|
+
"""Raised when an AI call cannot be completed. Message is client-safe."""
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass(frozen=True)
|
|
24
|
+
class AIConfig:
|
|
25
|
+
provider: str
|
|
26
|
+
api_key: str
|
|
27
|
+
base_url: str
|
|
28
|
+
model: str
|
|
29
|
+
timeout: int
|
|
30
|
+
max_output_tokens: int
|
|
31
|
+
share_source_context: bool
|
|
32
|
+
|
|
33
|
+
@property
|
|
34
|
+
def enabled(self) -> bool:
|
|
35
|
+
return bool(self.api_key) and self.provider.lower() not in ("", "none", "false", "0")
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class ChatProvider:
|
|
39
|
+
"""Minimal OpenAI-compatible chat client."""
|
|
40
|
+
|
|
41
|
+
MAX_RESPONSE_BYTES = 1_000_000
|
|
42
|
+
MAX_OUTPUT_TOKENS = 16_000
|
|
43
|
+
|
|
44
|
+
def __init__(self, config: AIConfig):
|
|
45
|
+
self.config = config
|
|
46
|
+
|
|
47
|
+
def complete(self, messages: list[dict], *, max_tokens: int | None = None, temperature: float = 0.2) -> str:
|
|
48
|
+
if not self.config.enabled:
|
|
49
|
+
raise AIError("No AI provider is configured.")
|
|
50
|
+
payload = {
|
|
51
|
+
"model": self.config.model,
|
|
52
|
+
"messages": [
|
|
53
|
+
{"role": message["role"], "content": redact_secrets(str(message["content"]))}
|
|
54
|
+
for message in messages
|
|
55
|
+
],
|
|
56
|
+
"temperature": temperature,
|
|
57
|
+
"max_tokens": min(
|
|
58
|
+
max_tokens or self.config.max_output_tokens,
|
|
59
|
+
self.MAX_OUTPUT_TOKENS,
|
|
60
|
+
),
|
|
61
|
+
}
|
|
62
|
+
request = urllib.request.Request(
|
|
63
|
+
f"{self.config.base_url.rstrip('/')}/chat/completions",
|
|
64
|
+
data=json.dumps(payload).encode("utf-8"),
|
|
65
|
+
headers={
|
|
66
|
+
"Authorization": f"Bearer {self.config.api_key}",
|
|
67
|
+
"Content-Type": "application/json",
|
|
68
|
+
},
|
|
69
|
+
method="POST",
|
|
70
|
+
)
|
|
71
|
+
try:
|
|
72
|
+
with urllib.request.urlopen(request, timeout=self.config.timeout) as response:
|
|
73
|
+
raw = response.read(self.MAX_RESPONSE_BYTES + 1)
|
|
74
|
+
if len(raw) > self.MAX_RESPONSE_BYTES:
|
|
75
|
+
raise AIError("The AI provider response exceeded the size limit.")
|
|
76
|
+
data = json.loads(raw.decode("utf-8"))
|
|
77
|
+
except urllib.error.HTTPError as exc:
|
|
78
|
+
raise AIError(f"The AI provider rejected the request (HTTP {exc.code}).") from exc
|
|
79
|
+
except urllib.error.URLError as exc:
|
|
80
|
+
raise AIError(f"The AI provider could not be reached ({type(exc.reason).__name__}).") from exc
|
|
81
|
+
except AIError:
|
|
82
|
+
raise
|
|
83
|
+
except (TimeoutError, OSError) as exc:
|
|
84
|
+
raise AIError(f"The AI request failed ({type(exc).__name__}).") from exc
|
|
85
|
+
except json.JSONDecodeError as exc:
|
|
86
|
+
raise AIError("The AI provider returned an unreadable response.") from exc
|
|
87
|
+
|
|
88
|
+
try:
|
|
89
|
+
choices = data.get("choices") or []
|
|
90
|
+
content = choices[0]["message"]["content"]
|
|
91
|
+
except (IndexError, KeyError, TypeError) as exc:
|
|
92
|
+
raise AIError("The AI provider returned no message content.") from exc
|
|
93
|
+
return str(content or "").strip()
|
|
94
|
+
|
|
95
|
+
def check(self) -> str:
|
|
96
|
+
"""Run a one-token round trip to confirm the configuration works."""
|
|
97
|
+
reply = self.complete(
|
|
98
|
+
[{"role": "user", "content": "Reply with the single word: ready"}],
|
|
99
|
+
max_tokens=8,
|
|
100
|
+
temperature=0.0,
|
|
101
|
+
)
|
|
102
|
+
return reply[:80]
|