datasecops-cli 0.5.4__tar.gz → 0.5.6__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.
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/CHANGELOG.md +14 -0
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/PKG-INFO +1 -1
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/pyproject.toml +1 -1
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/src/datasecops_cli/main.py +9 -6
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/src/datasecops_cli/menus/configuration.py +1 -1
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/src/datasecops_cli/menus/downloads.py +1 -1
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/src/datasecops_cli/services/download_service.py +9 -2
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/src/datasecops_cli/utilities/mcp.py +17 -1
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/.github/workflows/auto-tag.yml +0 -0
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/.github/workflows/publish-cli.yml +0 -0
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/.github/workflows/test.yml +0 -0
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/.gitignore +0 -0
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/DEVELOPMENT.md +0 -0
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/LICENSE +0 -0
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/README.md +0 -0
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/docs/getting-started.md +0 -0
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/docs/git-operations.md +0 -0
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/docs/legacy.md +0 -0
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/docs/legacy_plan_of_action.md +0 -0
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/docs/mcp-server.md +0 -0
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/mcp-servers.json +0 -0
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/setup.ps1 +0 -0
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/setup.sh +0 -0
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/src/datasecops_cli/__init__.py +0 -0
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/src/datasecops_cli/config.py +0 -0
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/src/datasecops_cli/menus/__init__.py +0 -0
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/src/datasecops_cli/menus/development.py +0 -0
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/src/datasecops_cli/menus/git_operations.py +0 -0
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/src/datasecops_cli/models/__init__.py +0 -0
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/src/datasecops_cli/models/git_helpers.py +0 -0
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/src/datasecops_cli/models/project_config.py +0 -0
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/src/datasecops_cli/services/__init__.py +0 -0
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/src/datasecops_cli/services/bootstrap_service.py +0 -0
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/src/datasecops_cli/services/dbt_project_generator.py +0 -0
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/src/datasecops_cli/services/dbt_runner.py +0 -0
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/src/datasecops_cli/services/directory_scaffolder.py +0 -0
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/src/datasecops_cli/services/git_service.py +0 -0
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/src/datasecops_cli/services/linting_service.py +0 -0
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/src/datasecops_cli/services/skill_service.py +0 -0
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/src/datasecops_cli/services/snowflake_service.py +0 -0
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/src/datasecops_cli/services/upstream_service.py +0 -0
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/src/datasecops_cli/utilities/__init__.py +0 -0
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/src/datasecops_cli/utilities/display.py +0 -0
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/src/datasecops_cli/utilities/file_utils.py +0 -0
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/src/datasecops_cli/utilities/yaml_utils.py +0 -0
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/src/datasecops_mcp/__init__.py +0 -0
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/src/datasecops_mcp/__main__.py +0 -0
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/src/datasecops_mcp/connection.py +0 -0
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/src/datasecops_mcp/server.py +0 -0
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/tests/__init__.py +0 -0
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/tests/test_config.py +0 -0
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/tests/test_file_utils.py +0 -0
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/tests/test_main.py +0 -0
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/tests/test_models.py +0 -0
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/tests/test_version.py +0 -0
- {datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/tests/test_yaml_utils.py +0 -0
|
@@ -2,6 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to the DataSecOps CLI are documented in this file.
|
|
4
4
|
|
|
5
|
+
## [0.5.6] - 2026-06-19
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- **AzureDevOps pipeline platform filter mismatch** — the platform comparison in `download_pipelines` now normalizes by stripping spaces (e.g. `"Azure DevOps"` → `"azuredevops"`) so pipelines returned by the stored procedure are no longer silently skipped when the caller passes `"azuredevops"`.
|
|
10
|
+
|
|
11
|
+
## [0.5.5] - 2026-06-19
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- **AzureDevOps pipelines download to correct folder** — `download_pipelines` now writes AzureDevOps pipeline files to `.azuredevops/workflows/` instead of the project root, matching the platform convention (similar to how GitHub pipelines are written to `.github/workflows/`).
|
|
16
|
+
- **MCP server setup recognises all AzureDevOps platform variants** — the initial setup flow in `main.py` now uses case-insensitive matching for the platform name (`"AzureDevOps"` and `"Azure DevOps"` both work), consistent with the menu paths.
|
|
17
|
+
- **Cortex Code MCP server uses absolute venv path** — the `datasecops-framework` MCP server entry in `.snowflake/cortex/mcp.json` now uses the absolute path to the project's `.venv/Scripts/datasecops-mcp` (Windows) or `.venv/bin/datasecops-mcp` (Unix) instead of the bare `datasecops-mcp` command, fixing "Process exited with code 1" errors in Cortex Code Desktop when the venv isn't on the system PATH.
|
|
18
|
+
|
|
5
19
|
## [0.5.4] - 2026-06-05
|
|
6
20
|
|
|
7
21
|
### Changed
|
|
@@ -307,7 +307,7 @@ def _run_setup(project_dir: Path):
|
|
|
307
307
|
|
|
308
308
|
info_line("")
|
|
309
309
|
info_line("Which AI tool are you configuring?")
|
|
310
|
-
tool_options = ["
|
|
310
|
+
tool_options = ["Cortex Code", "Cursor", "Claude Code", "VS Code (Copilot)"]
|
|
311
311
|
tool_options.append("Skip")
|
|
312
312
|
tool_choice = select_from_list(tool_options, "tool", add_back=False)
|
|
313
313
|
|
|
@@ -316,9 +316,12 @@ def _run_setup(project_dir: Path):
|
|
|
316
316
|
info_line("Adding MCP servers to Cortex Code...")
|
|
317
317
|
mcp_path = project_dir / ".snowflake" / "cortex" / "mcp.json"
|
|
318
318
|
|
|
319
|
+
from datasecops_cli.utilities.mcp import _resolve_mcp_command
|
|
320
|
+
mcp_command = _resolve_mcp_command()
|
|
321
|
+
|
|
319
322
|
servers = {"datasecops-framework": {
|
|
320
323
|
"type": "stdio",
|
|
321
|
-
"command":
|
|
324
|
+
"command": mcp_command,
|
|
322
325
|
"args": ["--connection-name", connection_name, "--app-database", app_database],
|
|
323
326
|
}}
|
|
324
327
|
|
|
@@ -336,7 +339,7 @@ def _run_setup(project_dir: Path):
|
|
|
336
339
|
server_entry["headers"] = {"Authorization": f"Bearer {snowflake_pat}"}
|
|
337
340
|
servers["datasecops-docs"] = server_entry
|
|
338
341
|
|
|
339
|
-
if platform_choice == "
|
|
342
|
+
if platform_choice.lower() == "github":
|
|
340
343
|
github_token = get_input_string("Enter your GitHub PAT (or press Enter to skip): ", allow_empty=True)
|
|
341
344
|
if github_token:
|
|
342
345
|
servers["github"] = {
|
|
@@ -345,7 +348,7 @@ def _run_setup(project_dir: Path):
|
|
|
345
348
|
"args": ["-y", "@modelcontextprotocol/server-github"],
|
|
346
349
|
"env": {"GITHUB_PERSONAL_ACCESS_TOKEN": github_token},
|
|
347
350
|
}
|
|
348
|
-
elif platform_choice
|
|
351
|
+
elif platform_choice.lower() in ("azuredevops", "azure devops"):
|
|
349
352
|
azure_org = get_input_string("Enter your Azure DevOps org URL (e.g. https://dev.azure.com/myorg): ")
|
|
350
353
|
azure_pat = get_input_string("Enter your Azure DevOps PAT (or press Enter to skip): ", allow_empty=True)
|
|
351
354
|
if azure_pat:
|
|
@@ -387,13 +390,13 @@ def _run_setup(project_dir: Path):
|
|
|
387
390
|
}
|
|
388
391
|
info_line("Note: Replace <YOUR_PAT> in datasecops-docs headers with your Snowflake PAT")
|
|
389
392
|
|
|
390
|
-
if platform_choice == "
|
|
393
|
+
if platform_choice.lower() == "github":
|
|
391
394
|
servers["github"] = {
|
|
392
395
|
"command": "npx",
|
|
393
396
|
"args": ["-y", "@modelcontextprotocol/server-github"],
|
|
394
397
|
"env": {"GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_TOKEN}"},
|
|
395
398
|
}
|
|
396
|
-
elif platform_choice
|
|
399
|
+
elif platform_choice.lower() in ("azuredevops", "azure devops"):
|
|
397
400
|
servers["azure-devops"] = {
|
|
398
401
|
"command": "npx",
|
|
399
402
|
"args": ["-y", "@tiberriver256/mcp-server-azure-devops"],
|
|
@@ -150,7 +150,7 @@ class ConfigurationMenu:
|
|
|
150
150
|
# Select target tool
|
|
151
151
|
info_line("")
|
|
152
152
|
info_line("Which AI tool are you configuring?")
|
|
153
|
-
tool_options = ["
|
|
153
|
+
tool_options = ["Cortex Code", "Cursor", "Claude Code", "VS Code (Copilot)"]
|
|
154
154
|
tool_choice = select_from_list(tool_options, "tool", add_back=False)
|
|
155
155
|
|
|
156
156
|
if tool_choice == "Cortex Code":
|
|
@@ -134,7 +134,7 @@ class DownloadsMenu:
|
|
|
134
134
|
# Select target tool
|
|
135
135
|
info_line("")
|
|
136
136
|
info_line("Which AI tool are you configuring?")
|
|
137
|
-
tool_options = ["
|
|
137
|
+
tool_options = ["Cortex Code", "Cursor", "Claude Code", "VS Code (Copilot)"]
|
|
138
138
|
tool_choice = select_from_list(tool_options, "tool", add_back=False)
|
|
139
139
|
|
|
140
140
|
if tool_choice == "Cortex Code":
|
{datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/src/datasecops_cli/services/download_service.py
RENAMED
|
@@ -129,16 +129,23 @@ class DownloadService:
|
|
|
129
129
|
error_line("No pipeline configuration found in native app")
|
|
130
130
|
return False
|
|
131
131
|
|
|
132
|
+
def _normalize_platform(p: str) -> str:
|
|
133
|
+
return p.lower().replace(" ", "")
|
|
134
|
+
|
|
135
|
+
normalized = _normalize_platform(platform)
|
|
132
136
|
pipelines = raw.get("pipelines", [])
|
|
133
137
|
count = 0
|
|
134
138
|
for pipe in pipelines:
|
|
135
|
-
|
|
139
|
+
pipe_platform = _normalize_platform(pipe.get("platform", "github"))
|
|
140
|
+
if pipe_platform != normalized or not pipe.get("enabled", True):
|
|
136
141
|
continue
|
|
137
142
|
filename = pipe.get("filename", "")
|
|
138
143
|
yaml_content = pipe.get("yaml_content", "")
|
|
139
144
|
if filename and yaml_content:
|
|
140
|
-
if
|
|
145
|
+
if normalized == "github":
|
|
141
146
|
dest = self.project_dir / ".github" / "workflows" / filename
|
|
147
|
+
elif normalized == "azuredevops":
|
|
148
|
+
dest = self.project_dir / ".azuredevops" / "workflows" / filename
|
|
142
149
|
else:
|
|
143
150
|
dest = self.project_dir / filename
|
|
144
151
|
write_file(dest, yaml_content)
|
|
@@ -1,12 +1,27 @@
|
|
|
1
1
|
"""MCP server configuration utilities."""
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
|
+
import shutil
|
|
5
|
+
import sys
|
|
4
6
|
from pathlib import Path
|
|
5
7
|
|
|
6
8
|
from datasecops_cli.utilities.display import get_input_string, success_line
|
|
7
9
|
from datasecops_cli.utilities.file_utils import ensure_dir, write_file
|
|
8
10
|
|
|
9
11
|
|
|
12
|
+
def _resolve_mcp_command() -> str:
|
|
13
|
+
"""Resolve the path to the datasecops-mcp executable.
|
|
14
|
+
|
|
15
|
+
Checks shutil.which first (covers global/pipx installs), then falls back
|
|
16
|
+
to the project .venv path.
|
|
17
|
+
"""
|
|
18
|
+
found = shutil.which("datasecops-mcp")
|
|
19
|
+
if found:
|
|
20
|
+
return found
|
|
21
|
+
venv_bin = "Scripts" if sys.platform == "win32" else "bin"
|
|
22
|
+
return f".venv/{venv_bin}/datasecops-mcp"
|
|
23
|
+
|
|
24
|
+
|
|
10
25
|
def build_cortex_mcp_servers(
|
|
11
26
|
servers: list[str],
|
|
12
27
|
connection_name: str,
|
|
@@ -16,13 +31,14 @@ def build_cortex_mcp_servers(
|
|
|
16
31
|
|
|
17
32
|
Returns a dict suitable for {"mcpServers": ...} JSON output.
|
|
18
33
|
"""
|
|
34
|
+
mcp_command = _resolve_mcp_command()
|
|
19
35
|
server_config = {}
|
|
20
36
|
|
|
21
37
|
for server in servers:
|
|
22
38
|
if server == "datasecops-framework":
|
|
23
39
|
server_config["datasecops-framework"] = {
|
|
24
40
|
"type": "stdio",
|
|
25
|
-
"command":
|
|
41
|
+
"command": mcp_command,
|
|
26
42
|
"args": ["--connection-name", connection_name, "--app-database", app_database],
|
|
27
43
|
}
|
|
28
44
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/src/datasecops_cli/services/bootstrap_service.py
RENAMED
|
File without changes
|
{datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/src/datasecops_cli/services/dbt_project_generator.py
RENAMED
|
File without changes
|
|
File without changes
|
{datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/src/datasecops_cli/services/directory_scaffolder.py
RENAMED
|
File without changes
|
|
File without changes
|
{datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/src/datasecops_cli/services/linting_service.py
RENAMED
|
File without changes
|
|
File without changes
|
{datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/src/datasecops_cli/services/snowflake_service.py
RENAMED
|
File without changes
|
{datasecops_cli-0.5.4 → datasecops_cli-0.5.6}/src/datasecops_cli/services/upstream_service.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|