datasecops-cli 0.2.0__tar.gz → 0.2.1__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.2.0 → datasecops_cli-0.2.1}/CHANGELOG.md +14 -0
- {datasecops_cli-0.2.0 → datasecops_cli-0.2.1}/PKG-INFO +1 -1
- {datasecops_cli-0.2.0 → datasecops_cli-0.2.1}/pyproject.toml +1 -1
- {datasecops_cli-0.2.0 → datasecops_cli-0.2.1}/src/datasecops_cli/main.py +3 -2
- {datasecops_cli-0.2.0 → datasecops_cli-0.2.1}/src/datasecops_cli/menus/development.py +19 -1
- {datasecops_cli-0.2.0 → datasecops_cli-0.2.1}/src/datasecops_cli/menus/downloads.py +2 -1
- {datasecops_cli-0.2.0 → datasecops_cli-0.2.1}/src/datasecops_cli/services/bootstrap_service.py +2 -1
- {datasecops_cli-0.2.0 → datasecops_cli-0.2.1}/src/datasecops_cli/services/download_service.py +7 -1
- {datasecops_cli-0.2.0 → datasecops_cli-0.2.1}/.github/workflows/publish-cli.yml +0 -0
- {datasecops_cli-0.2.0 → datasecops_cli-0.2.1}/.gitignore +0 -0
- {datasecops_cli-0.2.0 → datasecops_cli-0.2.1}/DEVELOPMENT.md +0 -0
- {datasecops_cli-0.2.0 → datasecops_cli-0.2.1}/LICENSE +0 -0
- {datasecops_cli-0.2.0 → datasecops_cli-0.2.1}/README.md +0 -0
- {datasecops_cli-0.2.0 → datasecops_cli-0.2.1}/docs/getting-started.md +0 -0
- {datasecops_cli-0.2.0 → datasecops_cli-0.2.1}/docs/legacy.md +0 -0
- {datasecops_cli-0.2.0 → datasecops_cli-0.2.1}/docs/legacy_plan_of_action.md +0 -0
- {datasecops_cli-0.2.0 → datasecops_cli-0.2.1}/docs/mcp-server.md +0 -0
- {datasecops_cli-0.2.0 → datasecops_cli-0.2.1}/mcp-servers.json +0 -0
- {datasecops_cli-0.2.0 → datasecops_cli-0.2.1}/setup.ps1 +0 -0
- {datasecops_cli-0.2.0 → datasecops_cli-0.2.1}/setup.sh +0 -0
- {datasecops_cli-0.2.0 → datasecops_cli-0.2.1}/src/datasecops_cli/__init__.py +0 -0
- {datasecops_cli-0.2.0 → datasecops_cli-0.2.1}/src/datasecops_cli/config.py +0 -0
- {datasecops_cli-0.2.0 → datasecops_cli-0.2.1}/src/datasecops_cli/menus/__init__.py +0 -0
- {datasecops_cli-0.2.0 → datasecops_cli-0.2.1}/src/datasecops_cli/menus/git_operations.py +0 -0
- {datasecops_cli-0.2.0 → datasecops_cli-0.2.1}/src/datasecops_cli/models/__init__.py +0 -0
- {datasecops_cli-0.2.0 → datasecops_cli-0.2.1}/src/datasecops_cli/models/git_helpers.py +0 -0
- {datasecops_cli-0.2.0 → datasecops_cli-0.2.1}/src/datasecops_cli/models/project_config.py +0 -0
- {datasecops_cli-0.2.0 → datasecops_cli-0.2.1}/src/datasecops_cli/services/__init__.py +0 -0
- {datasecops_cli-0.2.0 → datasecops_cli-0.2.1}/src/datasecops_cli/services/dbt_runner.py +0 -0
- {datasecops_cli-0.2.0 → datasecops_cli-0.2.1}/src/datasecops_cli/services/git_service.py +0 -0
- {datasecops_cli-0.2.0 → datasecops_cli-0.2.1}/src/datasecops_cli/services/linting_service.py +0 -0
- {datasecops_cli-0.2.0 → datasecops_cli-0.2.1}/src/datasecops_cli/services/skill_service.py +0 -0
- {datasecops_cli-0.2.0 → datasecops_cli-0.2.1}/src/datasecops_cli/services/snowflake_service.py +0 -0
- {datasecops_cli-0.2.0 → datasecops_cli-0.2.1}/src/datasecops_cli/utilities/__init__.py +0 -0
- {datasecops_cli-0.2.0 → datasecops_cli-0.2.1}/src/datasecops_cli/utilities/display.py +0 -0
- {datasecops_cli-0.2.0 → datasecops_cli-0.2.1}/src/datasecops_cli/utilities/file_utils.py +0 -0
- {datasecops_cli-0.2.0 → datasecops_cli-0.2.1}/src/datasecops_cli/utilities/yaml_utils.py +0 -0
- {datasecops_cli-0.2.0 → datasecops_cli-0.2.1}/src/datasecops_mcp/__init__.py +0 -0
- {datasecops_cli-0.2.0 → datasecops_cli-0.2.1}/src/datasecops_mcp/__main__.py +0 -0
- {datasecops_cli-0.2.0 → datasecops_cli-0.2.1}/src/datasecops_mcp/connection.py +0 -0
- {datasecops_cli-0.2.0 → datasecops_cli-0.2.1}/src/datasecops_mcp/server.py +0 -0
- {datasecops_cli-0.2.0 → datasecops_cli-0.2.1}/tests/__init__.py +0 -0
- {datasecops_cli-0.2.0 → datasecops_cli-0.2.1}/tests/test_config.py +0 -0
- {datasecops_cli-0.2.0 → datasecops_cli-0.2.1}/tests/test_file_utils.py +0 -0
- {datasecops_cli-0.2.0 → datasecops_cli-0.2.1}/tests/test_models.py +0 -0
- {datasecops_cli-0.2.0 → datasecops_cli-0.2.1}/tests/test_version.py +0 -0
- {datasecops_cli-0.2.0 → datasecops_cli-0.2.1}/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.2.1] - 2026-05-10
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- **SQLFluff config now includes `[sqlfluff:templater:dbt]` section** with `project_dir` and `profiles_dir` when downloaded from the framework, eliminating the need for `${DBT_PROFILES_DIR}` environment variable substitution
|
|
10
|
+
- **Auto-download `.sqlfluff` before linting** — the lint menu now automatically downloads the config from the framework if it doesn't exist locally, instead of failing silently or erroring
|
|
11
|
+
- **CI lint action handles missing `.sqlfluffconfig`** — the `tasks/lint-sql` action now only runs `envsubst` if `.sqlfluffconfig` exists, and accepts a pre-generated `.sqlfluff` file directly
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- `download_sqlfluff_config()` accepts an optional `profiles_dir` parameter to embed in the generated config
|
|
16
|
+
- `DevelopmentMenu` and `DownloadsMenu` pass the resolved `profiles_dir` through to the download service
|
|
17
|
+
- `.sqlfluff` no longer needs to be committed to client repos — it is generated on-the-fly from the framework
|
|
18
|
+
|
|
5
19
|
## [0.2.0] - 2026-05-09
|
|
6
20
|
|
|
7
21
|
### Added
|
|
@@ -88,12 +88,13 @@ def _main_menu(config: Config, dbt_runner: DbtRunner, git_service: GitService,
|
|
|
88
88
|
|
|
89
89
|
while option != 0:
|
|
90
90
|
if option == 1:
|
|
91
|
+
profiles_dir = str(config.get_dbt_profiles_dir())
|
|
91
92
|
if git_service:
|
|
92
93
|
dev_menu = DevelopmentMenu(dbt_runner, linting_service, git_service, profile_name,
|
|
93
|
-
download_service=download_service)
|
|
94
|
+
download_service=download_service, profiles_dir=profiles_dir)
|
|
94
95
|
else:
|
|
95
96
|
dev_menu = DevelopmentMenu(dbt_runner, linting_service, None, profile_name,
|
|
96
|
-
download_service=download_service)
|
|
97
|
+
download_service=download_service, profiles_dir=profiles_dir)
|
|
97
98
|
dev_menu.show()
|
|
98
99
|
|
|
99
100
|
elif option == 2 and git_service:
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
1
3
|
from datasecops_cli.services.dbt_runner import DbtRunner
|
|
2
4
|
from datasecops_cli.services.linting_service import LintingService
|
|
3
5
|
from datasecops_cli.services.download_service import DownloadService
|
|
@@ -12,12 +14,14 @@ from datasecops_cli.utilities.display import (
|
|
|
12
14
|
class DevelopmentMenu:
|
|
13
15
|
def __init__(self, dbt_runner: DbtRunner, linting_service: LintingService,
|
|
14
16
|
git_service: GitService, profile_name: str,
|
|
15
|
-
download_service: DownloadService = None
|
|
17
|
+
download_service: DownloadService = None,
|
|
18
|
+
profiles_dir: str = None):
|
|
16
19
|
self.dbt = dbt_runner
|
|
17
20
|
self.linting = linting_service
|
|
18
21
|
self.git = git_service
|
|
19
22
|
self.profile_name = profile_name
|
|
20
23
|
self.downloads = download_service
|
|
24
|
+
self.profiles_dir = profiles_dir
|
|
21
25
|
|
|
22
26
|
def show(self) -> None:
|
|
23
27
|
self._menu()
|
|
@@ -136,6 +140,17 @@ class DevelopmentMenu:
|
|
|
136
140
|
self.dbt.test(select=select)
|
|
137
141
|
complete_action()
|
|
138
142
|
|
|
143
|
+
def _ensure_sqlfluff_config(self) -> bool:
|
|
144
|
+
"""Download .sqlfluff from the framework if it doesn't exist locally."""
|
|
145
|
+
config_path = self.linting.project_dir / ".sqlfluff"
|
|
146
|
+
if config_path.exists():
|
|
147
|
+
return True
|
|
148
|
+
if not self.downloads:
|
|
149
|
+
error_line("No .sqlfluff config found and download service not available")
|
|
150
|
+
return False
|
|
151
|
+
info_line("No .sqlfluff config found — downloading from framework...")
|
|
152
|
+
return self.downloads.download_sqlfluff_config(profiles_dir=self.profiles_dir)
|
|
153
|
+
|
|
139
154
|
def _lint_menu(self) -> None:
|
|
140
155
|
clear()
|
|
141
156
|
display_action_header("SQLFluff Linting Options")
|
|
@@ -147,6 +162,9 @@ class DevelopmentMenu:
|
|
|
147
162
|
menu_option(6, "install - Install SQLFluff requirements from framework")
|
|
148
163
|
menu_option(0, "back - Return to development menu")
|
|
149
164
|
option = get_input_number("Choose an option: ")
|
|
165
|
+
if option in (1, 2, 3, 4, 5) and not self._ensure_sqlfluff_config():
|
|
166
|
+
complete_action()
|
|
167
|
+
return
|
|
150
168
|
if option == 1:
|
|
151
169
|
changed = [f.file for f in self.git.get_changed_files()] if self.git else []
|
|
152
170
|
self.linting.lint_modified(fix=False, changed_files=changed)
|
|
@@ -29,7 +29,8 @@ class DownloadsMenu:
|
|
|
29
29
|
while option != 0:
|
|
30
30
|
if option == 1:
|
|
31
31
|
display_action_header("Download SQLFluff Config")
|
|
32
|
-
self.
|
|
32
|
+
profiles_dir = str(Path(self.project_settings.profile_dir).expanduser()) if self.project_settings else None
|
|
33
|
+
self.downloads.download_sqlfluff_config(profiles_dir=profiles_dir)
|
|
33
34
|
complete_action()
|
|
34
35
|
elif option == 2:
|
|
35
36
|
display_action_header("Download Pipeline Files")
|
{datasecops_cli-0.2.0 → datasecops_cli-0.2.1}/src/datasecops_cli/services/bootstrap_service.py
RENAMED
|
@@ -68,7 +68,8 @@ class BootstrapService:
|
|
|
68
68
|
# Step 3: Download SQLFluff config
|
|
69
69
|
info_line("")
|
|
70
70
|
info_line("[3] Downloading SQLFluff configuration...")
|
|
71
|
-
|
|
71
|
+
profiles_dir = str(Path(self.project_settings.profile_dir).expanduser())
|
|
72
|
+
if self.download_service.download_sqlfluff_config(profiles_dir=profiles_dir):
|
|
72
73
|
steps_passed += 1
|
|
73
74
|
else:
|
|
74
75
|
info_line(" (skipped - no SQLFluff config in native app)")
|
{datasecops_cli-0.2.0 → datasecops_cli-0.2.1}/src/datasecops_cli/services/download_service.py
RENAMED
|
@@ -17,7 +17,7 @@ class DownloadService:
|
|
|
17
17
|
self.sf = snowflake_service
|
|
18
18
|
self.project_dir = project_dir
|
|
19
19
|
|
|
20
|
-
def download_sqlfluff_config(self) -> bool:
|
|
20
|
+
def download_sqlfluff_config(self, profiles_dir: str = None) -> bool:
|
|
21
21
|
info_line("Downloading SQLFluff configuration...")
|
|
22
22
|
raw = self.sf.get_framework_config("SQLFLUFF_RULES")
|
|
23
23
|
if not raw:
|
|
@@ -33,6 +33,12 @@ class DownloadService:
|
|
|
33
33
|
for opt_key, opt_val in opts.items():
|
|
34
34
|
lines.append(f"{opt_key} = {opt_val}")
|
|
35
35
|
|
|
36
|
+
lines.append("")
|
|
37
|
+
lines.append("[sqlfluff:templater:dbt]")
|
|
38
|
+
lines.append("project_dir = .")
|
|
39
|
+
if profiles_dir:
|
|
40
|
+
lines.append(f"profiles_dir = {profiles_dir}")
|
|
41
|
+
|
|
36
42
|
lines.append("")
|
|
37
43
|
lines.append("[sqlfluff:indentation]")
|
|
38
44
|
indentation = raw.get("indentation", {})
|
|
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.2.0 → datasecops_cli-0.2.1}/src/datasecops_cli/services/linting_service.py
RENAMED
|
File without changes
|
|
File without changes
|
{datasecops_cli-0.2.0 → datasecops_cli-0.2.1}/src/datasecops_cli/services/snowflake_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
|