vexa-core 1.0.35__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.
- vexa_core-1.0.35/LICENSE +21 -0
- vexa_core-1.0.35/PKG-INFO +81 -0
- vexa_core-1.0.35/README.md +32 -0
- vexa_core-1.0.35/pyproject.toml +62 -0
- vexa_core-1.0.35/setup.cfg +4 -0
- vexa_core-1.0.35/setup.py +5 -0
- vexa_core-1.0.35/src/vexa/__init__.py +19 -0
- vexa_core-1.0.35/src/vexa/ai_providers/__init__.py +0 -0
- vexa_core-1.0.35/src/vexa/ai_providers/anthropic_provider.py +144 -0
- vexa_core-1.0.35/src/vexa/ai_providers/azure_cli.py +424 -0
- vexa_core-1.0.35/src/vexa/ai_providers/base.py +91 -0
- vexa_core-1.0.35/src/vexa/ai_providers/google_cli.py +184 -0
- vexa_core-1.0.35/src/vexa/ai_providers/google_sdk.py +244 -0
- vexa_core-1.0.35/src/vexa/ai_providers/guides.py +50 -0
- vexa_core-1.0.35/src/vexa/ai_providers/kiro_cli.py +417 -0
- vexa_core-1.0.35/src/vexa/ai_providers/manager.py +701 -0
- vexa_core-1.0.35/src/vexa/ai_providers/ollama_provider.py +409 -0
- vexa_core-1.0.35/src/vexa/ai_providers/openai_provider.py +143 -0
- vexa_core-1.0.35/src/vexa/ai_providers/prompts.py +313 -0
- vexa_core-1.0.35/src/vexa/ai_providers/triage.py +472 -0
- vexa_core-1.0.35/src/vexa/attestation/__init__.py +9 -0
- vexa_core-1.0.35/src/vexa/attestation/attestation_builder.py +158 -0
- vexa_core-1.0.35/src/vexa/attestation/verifier.py +119 -0
- vexa_core-1.0.35/src/vexa/common/__init__.py +64 -0
- vexa_core-1.0.35/src/vexa/common/cloud_provider.py +253 -0
- vexa_core-1.0.35/src/vexa/common/config.py +105 -0
- vexa_core-1.0.35/src/vexa/common/config_manager.py +90 -0
- vexa_core-1.0.35/src/vexa/common/logging.py +216 -0
- vexa_core-1.0.35/src/vexa/common/models.py +261 -0
- vexa_core-1.0.35/src/vexa/common/path_filter.py +66 -0
- vexa_core-1.0.35/src/vexa/common/performance.py +111 -0
- vexa_core-1.0.35/src/vexa/jobs/__init__.py +18 -0
- vexa_core-1.0.35/src/vexa/jobs/manager.py +421 -0
- vexa_core-1.0.35/src/vexa/rag/__init__.py +6 -0
- vexa_core-1.0.35/src/vexa/rag/context_builder.py +133 -0
- vexa_core-1.0.35/src/vexa/rag/indexer.py +229 -0
- vexa_core-1.0.35/src/vexa/rag/vector_store.py +127 -0
- vexa_core-1.0.35/src/vexa/reports/__init__.py +34 -0
- vexa_core-1.0.35/src/vexa/reports/generator.py +217 -0
- vexa_core-1.0.35/src/vexa/reports/html.py +761 -0
- vexa_core-1.0.35/src/vexa/reports/json.py +147 -0
- vexa_core-1.0.35/src/vexa/reports/markdown.py +294 -0
- vexa_core-1.0.35/src/vexa/reports/sarif.py +286 -0
- vexa_core-1.0.35/src/vexa/reports/sbom.py +94 -0
- vexa_core-1.0.35/src/vexa/scanners/__init__.py +63 -0
- vexa_core-1.0.35/src/vexa/scanners/bandit.py +193 -0
- vexa_core-1.0.35/src/vexa/scanners/base.py +372 -0
- vexa_core-1.0.35/src/vexa/scanners/checkov.py +202 -0
- vexa_core-1.0.35/src/vexa/scanners/data_merger.py +270 -0
- vexa_core-1.0.35/src/vexa/scanners/deduplication_engine.py +282 -0
- vexa_core-1.0.35/src/vexa/scanners/detect_secrets.py +144 -0
- vexa_core-1.0.35/src/vexa/scanners/engine.py +492 -0
- vexa_core-1.0.35/src/vexa/scanners/framework_mapper.py +158 -0
- vexa_core-1.0.35/src/vexa/scanners/grype.py +128 -0
- vexa_core-1.0.35/src/vexa/scanners/npm_audit.py +134 -0
- vexa_core-1.0.35/src/vexa/scanners/pip_audit.py +149 -0
- vexa_core-1.0.35/src/vexa/scanners/pip_licenses.py +129 -0
- vexa_core-1.0.35/src/vexa/scanners/semgrep.py +130 -0
- vexa_core-1.0.35/src/vexa/scanners/syft.py +115 -0
- vexa_core-1.0.35/src/vexa/security/__init__.py +45 -0
- vexa_core-1.0.35/src/vexa/security/output_sanitizer.py +202 -0
- vexa_core-1.0.35/src/vexa/security/security_validator.py +300 -0
- vexa_core-1.0.35/src/vexa/security/subprocess_runner.py +369 -0
- vexa_core-1.0.35/src/vexa/security/validators.py +300 -0
- vexa_core-1.0.35/src/vexa/security_matrix/__init__.py +0 -0
- vexa_core-1.0.35/src/vexa/security_matrix/file_filter.py +0 -0
- vexa_core-1.0.35/src/vexa/security_matrix/neolifter.py +0 -0
- vexa_core-1.0.35/src/vexa/security_validate/__init__.py +0 -0
- vexa_core-1.0.35/src/vexa/security_validate/cdk.py +0 -0
- vexa_core-1.0.35/src/vexa/security_validate/cloudformation.py +0 -0
- vexa_core-1.0.35/src/vexa/security_validate/severity.py +0 -0
- vexa_core-1.0.35/src/vexa/security_validate/terraform.py +0 -0
- vexa_core-1.0.35/src/vexa/telemetry/__init__.py +3 -0
- vexa_core-1.0.35/src/vexa/telemetry/client.py +90 -0
- vexa_core-1.0.35/src/vexa/threat_model/__init__.py +0 -0
- vexa_core-1.0.35/src/vexa/threat_model/action_plan.py +0 -0
- vexa_core-1.0.35/src/vexa/threat_model/stride_engine.py +0 -0
- vexa_core-1.0.35/src/vexa_core.egg-info/PKG-INFO +81 -0
- vexa_core-1.0.35/src/vexa_core.egg-info/SOURCES.txt +81 -0
- vexa_core-1.0.35/src/vexa_core.egg-info/dependency_links.txt +1 -0
- vexa_core-1.0.35/src/vexa_core.egg-info/requires.txt +31 -0
- vexa_core-1.0.35/src/vexa_core.egg-info/top_level.txt +1 -0
- vexa_core-1.0.35/tests/test_openai_provider.py +82 -0
vexa_core-1.0.35/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 noviqtechnologies
|
|
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.
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: vexa-core
|
|
3
|
+
Version: 1.0.35
|
|
4
|
+
Summary: Enterprise-grade security analysis core engine — air-gapped scanning with AI-powered fixes
|
|
5
|
+
Author-email: Noviq Technologies <support@noviqtechnologies.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://codesecure.dev
|
|
8
|
+
Project-URL: Repository, https://github.com/noviqtechnologies/vexa
|
|
9
|
+
Project-URL: Documentation, https://github.com/noviqtechnologies/vexa/blob/main/docs/QUICKSTART.md
|
|
10
|
+
Project-URL: Issues, https://github.com/noviqtechnologies/vexa/issues
|
|
11
|
+
Keywords: security,sast,vulnerability,scanner,privacy,ai,bandit,semgrep,checkov
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Topic :: Security
|
|
20
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
21
|
+
Requires-Python: >=3.10
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
License-File: LICENSE
|
|
24
|
+
Requires-Dist: pydantic>=2.0.0
|
|
25
|
+
Requires-Dist: jinja2>=3.1.0
|
|
26
|
+
Requires-Dist: asyncio>=3.4.3
|
|
27
|
+
Requires-Dist: rich>=13.0.0
|
|
28
|
+
Requires-Dist: mermaid-py>=0.1.0
|
|
29
|
+
Requires-Dist: markdown>=3.5.2
|
|
30
|
+
Requires-Dist: pygments>=2.17.2
|
|
31
|
+
Requires-Dist: packaging>=24.0
|
|
32
|
+
Requires-Dist: bandit>=1.7.0
|
|
33
|
+
Requires-Dist: semgrep>=1.0.0; sys_platform != "win32"
|
|
34
|
+
Requires-Dist: checkov>=3.0.0
|
|
35
|
+
Requires-Dist: detect-secrets>=1.4.0
|
|
36
|
+
Requires-Dist: pip-audit>=2.0.0
|
|
37
|
+
Requires-Dist: pip-licenses>=4.0.0
|
|
38
|
+
Requires-Dist: pyyaml>=6.0
|
|
39
|
+
Provides-Extra: google
|
|
40
|
+
Requires-Dist: google-genai>=1.0.0; extra == "google"
|
|
41
|
+
Provides-Extra: openai
|
|
42
|
+
Requires-Dist: openai>=1.0.0; extra == "openai"
|
|
43
|
+
Provides-Extra: anthropicai
|
|
44
|
+
Requires-Dist: anthropic>=0.40.0; extra == "anthropicai"
|
|
45
|
+
Provides-Extra: aws
|
|
46
|
+
Provides-Extra: all
|
|
47
|
+
Requires-Dist: vexa-core[anthropicai,google,openai]; extra == "all"
|
|
48
|
+
Dynamic: license-file
|
|
49
|
+
|
|
50
|
+
# Vexa Core SDK
|
|
51
|
+

|
|
52
|
+
The fundamental engine powering AI-native security analysis.
|
|
53
|
+
|
|
54
|
+
Vexa Core provides the underlying logic for multi-scanner orchestration, AI-powered remediation, and security audit logging.
|
|
55
|
+
|
|
56
|
+
### Installation
|
|
57
|
+
```bash
|
|
58
|
+
pip install vexa-core
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Getting Started
|
|
62
|
+
```python
|
|
63
|
+
from vexa.core.engine import ScanEngine
|
|
64
|
+
from vexa.ai_providers import AIManager
|
|
65
|
+
|
|
66
|
+
# Initialize engine with default scanners
|
|
67
|
+
engine = ScanEngine(scanners=['bandit', 'semgrep'])
|
|
68
|
+
|
|
69
|
+
# Run analysis
|
|
70
|
+
findings = engine.scan_file("insecure.py")
|
|
71
|
+
|
|
72
|
+
for finding in findings:
|
|
73
|
+
print(f"[{finding.severity}] {finding.title}: {finding.description}")
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Requirements
|
|
77
|
+
- Python 3.9+
|
|
78
|
+
- Security Scanners (Bandit, Semgrep, etc.) installed on PATH.
|
|
79
|
+
|
|
80
|
+
### License
|
|
81
|
+
MIT License.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Vexa Core SDK
|
|
2
|
+

|
|
3
|
+
The fundamental engine powering AI-native security analysis.
|
|
4
|
+
|
|
5
|
+
Vexa Core provides the underlying logic for multi-scanner orchestration, AI-powered remediation, and security audit logging.
|
|
6
|
+
|
|
7
|
+
### Installation
|
|
8
|
+
```bash
|
|
9
|
+
pip install vexa-core
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
### Getting Started
|
|
13
|
+
```python
|
|
14
|
+
from vexa.core.engine import ScanEngine
|
|
15
|
+
from vexa.ai_providers import AIManager
|
|
16
|
+
|
|
17
|
+
# Initialize engine with default scanners
|
|
18
|
+
engine = ScanEngine(scanners=['bandit', 'semgrep'])
|
|
19
|
+
|
|
20
|
+
# Run analysis
|
|
21
|
+
findings = engine.scan_file("insecure.py")
|
|
22
|
+
|
|
23
|
+
for finding in findings:
|
|
24
|
+
print(f"[{finding.severity}] {finding.title}: {finding.description}")
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Requirements
|
|
28
|
+
- Python 3.9+
|
|
29
|
+
- Security Scanners (Bandit, Semgrep, etc.) installed on PATH.
|
|
30
|
+
|
|
31
|
+
### License
|
|
32
|
+
MIT License.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "vexa-core"
|
|
7
|
+
version = "1.0.35"
|
|
8
|
+
description = "Enterprise-grade security analysis core engine — air-gapped scanning with AI-powered fixes"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = {text = "MIT"}
|
|
12
|
+
authors = [{name = "Noviq Technologies", email = "support@noviqtechnologies.com"}]
|
|
13
|
+
keywords = ["security", "sast", "vulnerability", "scanner", "privacy", "ai", "bandit", "semgrep", "checkov"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 4 - Beta",
|
|
16
|
+
"Intended Audience :: Developers",
|
|
17
|
+
"License :: OSI Approved :: MIT License",
|
|
18
|
+
"Programming Language :: Python :: 3",
|
|
19
|
+
"Programming Language :: Python :: 3.10",
|
|
20
|
+
"Programming Language :: Python :: 3.11",
|
|
21
|
+
"Programming Language :: Python :: 3.12",
|
|
22
|
+
"Topic :: Security",
|
|
23
|
+
"Topic :: Software Development :: Quality Assurance",
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
dependencies = [
|
|
28
|
+
"pydantic>=2.0.0",
|
|
29
|
+
"jinja2>=3.1.0",
|
|
30
|
+
"asyncio>=3.4.3",
|
|
31
|
+
"rich>=13.0.0",
|
|
32
|
+
"mermaid-py>=0.1.0",
|
|
33
|
+
"markdown>=3.5.2",
|
|
34
|
+
"pygments>=2.17.2",
|
|
35
|
+
"packaging>=24.0",
|
|
36
|
+
# Scanners
|
|
37
|
+
"bandit>=1.7.0",
|
|
38
|
+
"semgrep>=1.0.0; sys_platform != 'win32'",
|
|
39
|
+
"checkov>=3.0.0",
|
|
40
|
+
"detect-secrets>=1.4.0",
|
|
41
|
+
"pip-audit>=2.0.0",
|
|
42
|
+
"pip-licenses>=4.0.0",
|
|
43
|
+
"pyyaml>=6.0",
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
[project.optional-dependencies]
|
|
47
|
+
google = ["google-genai>=1.0.0"]
|
|
48
|
+
openai = ["openai>=1.0.0"]
|
|
49
|
+
anthropicai = ["anthropic>=0.40.0"]
|
|
50
|
+
# aws = ["kiro-cli>=1.0.0"] # Disabled: not on PyPI, CLI provider disabled
|
|
51
|
+
aws = []
|
|
52
|
+
all = ["vexa-core[google,openai,anthropicai]"]
|
|
53
|
+
|
|
54
|
+
[tool.setuptools.packages.find]
|
|
55
|
+
where = ["src"]
|
|
56
|
+
include = ["vexa*"]
|
|
57
|
+
|
|
58
|
+
[project.urls]
|
|
59
|
+
Homepage = "https://codesecure.dev"
|
|
60
|
+
Repository = "https://github.com/noviqtechnologies/vexa"
|
|
61
|
+
Documentation = "https://github.com/noviqtechnologies/vexa/blob/main/docs/QUICKSTART.md"
|
|
62
|
+
Issues = "https://github.com/noviqtechnologies/vexa/issues"
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Vexa - Enterprise Security Analysis Platform.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
try:
|
|
6
|
+
from importlib.metadata import version, PackageNotFoundError
|
|
7
|
+
except ImportError:
|
|
8
|
+
# Fallback for Python < 3.8
|
|
9
|
+
try:
|
|
10
|
+
from importlib_metadata import version, PackageNotFoundError
|
|
11
|
+
except ImportError:
|
|
12
|
+
version = lambda _: "unknown"
|
|
13
|
+
PackageNotFoundError = Exception
|
|
14
|
+
|
|
15
|
+
try:
|
|
16
|
+
__version__ = version("vexa-core")
|
|
17
|
+
except (PackageNotFoundError, NameError, ImportError):
|
|
18
|
+
# Fallback for development where the package is not installed
|
|
19
|
+
__version__ = "1.0.35"
|
|
File without changes
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
from typing import List, Dict, Any, Optional
|
|
3
|
+
|
|
4
|
+
from vexa.common.models import Finding, EnhancedFinding
|
|
5
|
+
from vexa.common.logging import get_logger
|
|
6
|
+
from vexa.ai_providers.base import (
|
|
7
|
+
BaseAIProvider,
|
|
8
|
+
AIProviderType,
|
|
9
|
+
AIProviderStatus,
|
|
10
|
+
)
|
|
11
|
+
from vexa.ai_providers.prompts import GenericPromptBuilder, GenericMarkdownParser
|
|
12
|
+
from vexa.common.config import get_env
|
|
13
|
+
|
|
14
|
+
logger = get_logger(__name__)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class AnthropicWrapper(BaseAIProvider):
|
|
18
|
+
"""Anthropic Provider Implementation"""
|
|
19
|
+
|
|
20
|
+
PROVIDER_TYPE = AIProviderType.ANTHROPIC
|
|
21
|
+
|
|
22
|
+
def __init__(self):
|
|
23
|
+
self.prompt_builder = GenericPromptBuilder()
|
|
24
|
+
self.parser = GenericMarkdownParser()
|
|
25
|
+
self._api_key = get_env("VEXA_ANTHROPIC_API_KEY", "")
|
|
26
|
+
self._model = get_env("VEXA_ANTHROPIC_MODEL", "claude-sonnet-4-20250514")
|
|
27
|
+
|
|
28
|
+
def _get_client(self):
|
|
29
|
+
try:
|
|
30
|
+
import anthropic
|
|
31
|
+
return anthropic.AsyncAnthropic(api_key=self._api_key)
|
|
32
|
+
except ImportError:
|
|
33
|
+
raise RuntimeError("anthropic SDK not installed")
|
|
34
|
+
|
|
35
|
+
def set_api_key(self, api_key: str):
|
|
36
|
+
self._api_key = api_key
|
|
37
|
+
|
|
38
|
+
def set_model(self, model: str):
|
|
39
|
+
self._model = model
|
|
40
|
+
|
|
41
|
+
@property
|
|
42
|
+
def is_available(self) -> bool:
|
|
43
|
+
try:
|
|
44
|
+
import anthropic
|
|
45
|
+
return bool(self._api_key)
|
|
46
|
+
except ImportError:
|
|
47
|
+
return False
|
|
48
|
+
|
|
49
|
+
async def check_availability(self) -> tuple[AIProviderStatus, str]:
|
|
50
|
+
try:
|
|
51
|
+
import anthropic
|
|
52
|
+
except ImportError:
|
|
53
|
+
return AIProviderStatus.UNAVAILABLE, "Anthropic SDK not found (install with 'pip install anthropic')"
|
|
54
|
+
|
|
55
|
+
if not self._api_key:
|
|
56
|
+
return AIProviderStatus.UNAVAILABLE, "VEXA_ANTHROPIC_API_KEY is not set"
|
|
57
|
+
|
|
58
|
+
return AIProviderStatus.AVAILABLE, "Ready"
|
|
59
|
+
|
|
60
|
+
def _classify_error(self, err_msg: str, status_code: Optional[int] = None) -> str:
|
|
61
|
+
err_lower = err_msg.lower()
|
|
62
|
+
if status_code in (401, 403) or any(w in err_lower for w in ["invalid x-api-key", "authentication"]):
|
|
63
|
+
return "auth"
|
|
64
|
+
if status_code == 429 or any(w in err_lower for w in ["rate_limit", "too many requests"]):
|
|
65
|
+
return "rate_limit"
|
|
66
|
+
return "other"
|
|
67
|
+
|
|
68
|
+
async def test_connection(self) -> tuple[AIProviderStatus, str]:
|
|
69
|
+
status, msg = await self.check_availability()
|
|
70
|
+
if status != AIProviderStatus.AVAILABLE:
|
|
71
|
+
return status, msg
|
|
72
|
+
|
|
73
|
+
try:
|
|
74
|
+
client = self._get_client()
|
|
75
|
+
logger.info("Validating Anthropic API key with model %s...", self._model)
|
|
76
|
+
await client.messages.create(
|
|
77
|
+
model=self._model,
|
|
78
|
+
messages=[{"role": "user", "content": "Reply with 'ok'"}],
|
|
79
|
+
max_tokens=5,
|
|
80
|
+
)
|
|
81
|
+
return AIProviderStatus.AVAILABLE, "Ready"
|
|
82
|
+
except Exception as e:
|
|
83
|
+
err_type = self._classify_error(str(e), getattr(e, "status_code", None))
|
|
84
|
+
if err_type == "auth":
|
|
85
|
+
return AIProviderStatus.ERROR, f"Anthropic Auth Error: {e}"
|
|
86
|
+
if err_type == "rate_limit":
|
|
87
|
+
return AIProviderStatus.ERROR, f"Anthropic Rate Limit Error: {e}"
|
|
88
|
+
return AIProviderStatus.ERROR, f"Anthropic Connection Failed: {str(e)}"
|
|
89
|
+
|
|
90
|
+
async def analyze_findings_batch(
|
|
91
|
+
self,
|
|
92
|
+
findings: List[Finding],
|
|
93
|
+
code_contexts: Dict[str, str],
|
|
94
|
+
batch_size: int = 10,
|
|
95
|
+
app_context: Optional[Dict[str, Any]] = None,
|
|
96
|
+
is_workspace_scan: bool = False
|
|
97
|
+
) -> List[EnhancedFinding]:
|
|
98
|
+
|
|
99
|
+
if not findings:
|
|
100
|
+
return []
|
|
101
|
+
|
|
102
|
+
client = self._get_client()
|
|
103
|
+
prompt = self.prompt_builder.build_batch_prompt(findings, app_context=app_context, is_workspace_scan=is_workspace_scan)
|
|
104
|
+
|
|
105
|
+
system_prompt = (
|
|
106
|
+
"You are Vexa, an expert AI security assistant. "
|
|
107
|
+
"Analyze security findings and provide remediation in Markdown format. "
|
|
108
|
+
"Follow the ZERO-CHATTER RULE: remediation code blocks must contain "
|
|
109
|
+
"ONLY pure source code, no explanations."
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
try:
|
|
113
|
+
logger.info("Sending batch of %d findings to Anthropic (%s)...", len(findings), self._model)
|
|
114
|
+
|
|
115
|
+
response = await client.messages.create(
|
|
116
|
+
model=self._model,
|
|
117
|
+
system=system_prompt,
|
|
118
|
+
messages=[
|
|
119
|
+
{"role": "user", "content": prompt}
|
|
120
|
+
],
|
|
121
|
+
temperature=0.2,
|
|
122
|
+
max_tokens=4096,
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
text = response.content[0].text if response.content else ""
|
|
126
|
+
logger.debug("Received AI response length: %d characters", len(text))
|
|
127
|
+
|
|
128
|
+
return self.parser.parse(text, findings)
|
|
129
|
+
|
|
130
|
+
except Exception as e:
|
|
131
|
+
err_type = self._classify_error(str(e), getattr(e, "status_code", None))
|
|
132
|
+
if err_type == "rate_limit":
|
|
133
|
+
raise RuntimeError(f"Anthropic Rate Limit Exceeded: {e}")
|
|
134
|
+
logger.exception("Anthropic Analysis failed: %s", e)
|
|
135
|
+
raise e
|
|
136
|
+
|
|
137
|
+
def enhance_finding(self, finding: Finding, analysis: Any) -> EnhancedFinding:
|
|
138
|
+
pass
|
|
139
|
+
|
|
140
|
+
async def generate_stride_analysis(self, repo_path: Any, category: str) -> Dict[str, Any]:
|
|
141
|
+
return {"error": "Not implemented"}
|
|
142
|
+
|
|
143
|
+
def get_anthropic_wrapper() -> AnthropicWrapper:
|
|
144
|
+
return AnthropicWrapper()
|