mcp-souschef 2.8.0__py3-none-any.whl → 3.2.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.
- {mcp_souschef-2.8.0.dist-info → mcp_souschef-3.2.0.dist-info}/METADATA +159 -384
- mcp_souschef-3.2.0.dist-info/RECORD +47 -0
- {mcp_souschef-2.8.0.dist-info → mcp_souschef-3.2.0.dist-info}/WHEEL +1 -1
- souschef/__init__.py +31 -7
- souschef/assessment.py +1451 -105
- souschef/ci/common.py +126 -0
- souschef/ci/github_actions.py +3 -92
- souschef/ci/gitlab_ci.py +2 -52
- souschef/ci/jenkins_pipeline.py +2 -59
- souschef/cli.py +149 -16
- souschef/converters/playbook.py +378 -138
- souschef/converters/resource.py +12 -11
- souschef/converters/template.py +177 -0
- souschef/core/__init__.py +6 -1
- souschef/core/metrics.py +313 -0
- souschef/core/path_utils.py +233 -19
- souschef/core/validation.py +53 -0
- souschef/deployment.py +71 -12
- souschef/generators/__init__.py +13 -0
- souschef/generators/repo.py +695 -0
- souschef/parsers/attributes.py +1 -1
- souschef/parsers/habitat.py +1 -1
- souschef/parsers/inspec.py +25 -2
- souschef/parsers/metadata.py +5 -3
- souschef/parsers/recipe.py +1 -1
- souschef/parsers/resource.py +1 -1
- souschef/parsers/template.py +1 -1
- souschef/server.py +1039 -121
- souschef/ui/app.py +486 -374
- souschef/ui/pages/ai_settings.py +74 -8
- souschef/ui/pages/cookbook_analysis.py +3216 -373
- souschef/ui/pages/validation_reports.py +274 -0
- mcp_souschef-2.8.0.dist-info/RECORD +0 -42
- souschef/converters/cookbook_specific.py.backup +0 -109
- {mcp_souschef-2.8.0.dist-info → mcp_souschef-3.2.0.dist-info}/entry_points.txt +0 -0
- {mcp_souschef-2.8.0.dist-info → mcp_souschef-3.2.0.dist-info}/licenses/LICENSE +0 -0
souschef/parsers/inspec.py
CHANGED
|
@@ -2,11 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
4
|
import re
|
|
5
|
+
import tempfile
|
|
5
6
|
from pathlib import Path
|
|
6
7
|
from typing import Any
|
|
7
8
|
|
|
8
9
|
from souschef.core.constants import ERROR_PREFIX, INSPEC_END_INDENT, INSPEC_SHOULD_EXIST
|
|
9
|
-
from souschef.core.path_utils import
|
|
10
|
+
from souschef.core.path_utils import (
|
|
11
|
+
_ensure_within_base_path,
|
|
12
|
+
_normalize_path,
|
|
13
|
+
_safe_join,
|
|
14
|
+
_trusted_workspace_root,
|
|
15
|
+
)
|
|
10
16
|
|
|
11
17
|
# Regex patterns used across converters
|
|
12
18
|
_VERSION_PATTERN = r"match\s+/([^/]+)/"
|
|
@@ -39,6 +45,23 @@ def parse_inspec_profile(path: str) -> str:
|
|
|
39
45
|
|
|
40
46
|
profile_path = _normalize_path(path)
|
|
41
47
|
|
|
48
|
+
trusted_bases = [
|
|
49
|
+
_trusted_workspace_root(),
|
|
50
|
+
Path(tempfile.gettempdir()).resolve(),
|
|
51
|
+
]
|
|
52
|
+
|
|
53
|
+
for base in trusted_bases:
|
|
54
|
+
try:
|
|
55
|
+
profile_path = _ensure_within_base_path(profile_path, base)
|
|
56
|
+
break
|
|
57
|
+
except ValueError:
|
|
58
|
+
continue
|
|
59
|
+
else:
|
|
60
|
+
return (
|
|
61
|
+
"Error: Path traversal attempt detected\n\n"
|
|
62
|
+
"Suggestion: Use a path inside the workspace or system temp directory"
|
|
63
|
+
)
|
|
64
|
+
|
|
42
65
|
if not profile_path.exists():
|
|
43
66
|
return (
|
|
44
67
|
f"Error: Path does not exist: {path}\n\n"
|
|
@@ -189,7 +212,7 @@ def _parse_controls_from_directory(profile_path: Path) -> list[dict[str, Any]]:
|
|
|
189
212
|
controls = []
|
|
190
213
|
for control_file in controls_dir.glob("*.rb"):
|
|
191
214
|
try:
|
|
192
|
-
content = control_file.read_text()
|
|
215
|
+
content = control_file.read_text() # nosonar
|
|
193
216
|
file_controls = _parse_inspec_control(content)
|
|
194
217
|
for ctrl in file_controls:
|
|
195
218
|
ctrl["file"] = str(control_file.relative_to(profile_path))
|
souschef/parsers/metadata.py
CHANGED
|
@@ -8,7 +8,7 @@ from souschef.core.constants import (
|
|
|
8
8
|
ERROR_PERMISSION_DENIED,
|
|
9
9
|
METADATA_FILENAME,
|
|
10
10
|
)
|
|
11
|
-
from souschef.core.path_utils import _normalize_path, _safe_join
|
|
11
|
+
from souschef.core.path_utils import _normalize_path, _safe_join, safe_read_text
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
def read_cookbook_metadata(path: str) -> str:
|
|
@@ -24,7 +24,7 @@ def read_cookbook_metadata(path: str) -> str:
|
|
|
24
24
|
"""
|
|
25
25
|
try:
|
|
26
26
|
file_path = _normalize_path(path)
|
|
27
|
-
content = file_path.
|
|
27
|
+
content = safe_read_text(file_path, file_path.parent, encoding="utf-8")
|
|
28
28
|
|
|
29
29
|
metadata = _extract_metadata(content)
|
|
30
30
|
|
|
@@ -58,7 +58,8 @@ def parse_cookbook_metadata(path: str) -> dict[str, str | list[str]]:
|
|
|
58
58
|
"""
|
|
59
59
|
try:
|
|
60
60
|
file_path = _normalize_path(path)
|
|
61
|
-
|
|
61
|
+
# nosonar
|
|
62
|
+
content = safe_read_text(file_path, file_path.parent, encoding="utf-8")
|
|
62
63
|
|
|
63
64
|
metadata = _extract_metadata(content)
|
|
64
65
|
return metadata
|
|
@@ -93,6 +94,7 @@ def _scan_cookbook_directory(
|
|
|
93
94
|
if not dir_path.exists() or not dir_path.is_dir():
|
|
94
95
|
return None
|
|
95
96
|
|
|
97
|
+
# nosonar
|
|
96
98
|
files = [f.name for f in dir_path.iterdir() if f.is_file()]
|
|
97
99
|
return (dir_name, files) if files else None
|
|
98
100
|
|
souschef/parsers/recipe.py
CHANGED
|
@@ -35,7 +35,7 @@ def parse_recipe(path: str) -> str:
|
|
|
35
35
|
"""
|
|
36
36
|
try:
|
|
37
37
|
file_path = _normalize_path(path)
|
|
38
|
-
content = file_path.read_text(encoding="utf-8")
|
|
38
|
+
content = file_path.read_text(encoding="utf-8") # nosonar
|
|
39
39
|
|
|
40
40
|
resources = _extract_resources(content)
|
|
41
41
|
include_recipes = _extract_include_recipes(content)
|
souschef/parsers/resource.py
CHANGED
|
@@ -26,7 +26,7 @@ def parse_custom_resource(path: str) -> str:
|
|
|
26
26
|
"""
|
|
27
27
|
try:
|
|
28
28
|
file_path = _normalize_path(path)
|
|
29
|
-
content = file_path.read_text(encoding="utf-8")
|
|
29
|
+
content = file_path.read_text(encoding="utf-8") # nosonar
|
|
30
30
|
|
|
31
31
|
# Determine resource type
|
|
32
32
|
resource_type = "custom_resource" if "property" in content else "lwrp"
|
souschef/parsers/template.py
CHANGED
|
@@ -36,7 +36,7 @@ def parse_template(path: str) -> str:
|
|
|
36
36
|
"""
|
|
37
37
|
try:
|
|
38
38
|
file_path = _normalize_path(path)
|
|
39
|
-
content = file_path.read_text(encoding="utf-8")
|
|
39
|
+
content = file_path.read_text(encoding="utf-8") # nosonar
|
|
40
40
|
|
|
41
41
|
# Extract variables
|
|
42
42
|
variables = _extract_template_variables(content)
|