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.
Files changed (58) hide show
  1. dashboard/__init__.py +10 -0
  2. dashboard/backend/__init__.py +11 -0
  3. dashboard/backend/__main__.py +6 -0
  4. dashboard/backend/ai/__init__.py +6 -0
  5. dashboard/backend/ai/provider.py +102 -0
  6. dashboard/backend/ai/service.py +757 -0
  7. dashboard/backend/api/__init__.py +5 -0
  8. dashboard/backend/api/ai.py +142 -0
  9. dashboard/backend/api/dashboard.py +34 -0
  10. dashboard/backend/api/deps.py +51 -0
  11. dashboard/backend/api/findings.py +102 -0
  12. dashboard/backend/api/intel.py +41 -0
  13. dashboard/backend/api/repositories.py +62 -0
  14. dashboard/backend/api/scans.py +168 -0
  15. dashboard/backend/api/system.py +69 -0
  16. dashboard/backend/config.py +180 -0
  17. dashboard/backend/main.py +183 -0
  18. dashboard/backend/persistence/__init__.py +5 -0
  19. dashboard/backend/persistence/database.py +278 -0
  20. dashboard/backend/persistence/store.py +600 -0
  21. dashboard/backend/profiles.py +141 -0
  22. dashboard/backend/schemas.py +452 -0
  23. dashboard/backend/security.py +158 -0
  24. dashboard/backend/services/__init__.py +7 -0
  25. dashboard/backend/services/dashboard.py +172 -0
  26. dashboard/backend/services/intel.py +341 -0
  27. dashboard/backend/services/paths.py +38 -0
  28. dashboard/backend/services/repositories.py +123 -0
  29. dashboard/backend/services/scans.py +328 -0
  30. dashboard/backend/services/settings.py +49 -0
  31. dashboard/frontend/dist/assets/index-COC-CdqD.js +492 -0
  32. dashboard/frontend/dist/assets/index-hWDLRaLr.css +1 -0
  33. dashboard/frontend/dist/index.html +29 -0
  34. dashboard/frontend/dist/phone-mascots.gif +0 -0
  35. dashboard/launcher.py +48 -0
  36. vibe_coding_qa/__init__.py +140 -0
  37. vibe_coding_qa/__main__.py +5 -0
  38. vibe_coding_qa/ai_review.py +165 -0
  39. vibe_coding_qa/cli.py +157 -0
  40. vibe_coding_qa/engine.py +860 -0
  41. vibe_coding_qa/fixes.py +222 -0
  42. vibe_coding_qa/gates.py +300 -0
  43. vibe_coding_qa/profile.py +471 -0
  44. vibe_coding_qa/repo.py +188 -0
  45. vibe_coding_qa/reporters/__init__.py +253 -0
  46. vibe_coding_qa/scanners/__init__.py +195 -0
  47. vibe_coding_qa/scanners/compliance.py +167 -0
  48. vibe_coding_qa/scanners/database.py +316 -0
  49. vibe_coding_qa/scanners/dependencies.py +595 -0
  50. vibe_coding_qa/scanners/infrastructure.py +125 -0
  51. vibe_coding_qa/scanners/performance.py +84 -0
  52. vibe_coding_qa/scanners/quality.py +129 -0
  53. vibe_coding_qa/scanners/security.py +521 -0
  54. vibe_coding_qa-0.5.0.dist-info/METADATA +323 -0
  55. vibe_coding_qa-0.5.0.dist-info/RECORD +58 -0
  56. vibe_coding_qa-0.5.0.dist-info/WHEEL +5 -0
  57. vibe_coding_qa-0.5.0.dist-info/entry_points.txt +3 -0
  58. 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,6 @@
1
+ """Entry point: ``python -m dashboard.backend``."""
2
+
3
+ from .main import main
4
+
5
+ if __name__ == "__main__":
6
+ main()
@@ -0,0 +1,6 @@
1
+ """Optional AI features. The engine and the release gate never depend on these."""
2
+
3
+ from .provider import AIConfig, AIError, ChatProvider
4
+ from .service import AIService
5
+
6
+ __all__ = ["AIConfig", "AIError", "ChatProvider", "AIService"]
@@ -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]