quickscale-cli 0.76.0__tar.gz → 0.79.0__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.
Files changed (32) hide show
  1. {quickscale_cli-0.76.0 → quickscale_cli-0.79.0}/PKG-INFO +2 -2
  2. {quickscale_cli-0.76.0 → quickscale_cli-0.79.0}/pyproject.toml +2 -2
  3. {quickscale_cli-0.76.0 → quickscale_cli-0.79.0}/src/quickscale_cli/_version.py +1 -1
  4. quickscale_cli-0.79.0/src/quickscale_cli/backups_contract.py +128 -0
  5. {quickscale_cli-0.76.0 → quickscale_cli-0.79.0}/src/quickscale_cli/commands/apply_command.py +451 -6
  6. {quickscale_cli-0.76.0 → quickscale_cli-0.79.0}/src/quickscale_cli/commands/module_commands.py +10 -1
  7. {quickscale_cli-0.76.0 → quickscale_cli-0.79.0}/src/quickscale_cli/commands/module_config.py +605 -0
  8. quickscale_cli-0.79.0/src/quickscale_cli/commands/module_wiring_specs.py +634 -0
  9. {quickscale_cli-0.76.0 → quickscale_cli-0.79.0}/src/quickscale_cli/commands/plan_command.py +3 -0
  10. {quickscale_cli-0.76.0 → quickscale_cli-0.79.0}/src/quickscale_cli/module_catalog.py +15 -0
  11. quickscale_cli-0.79.0/src/quickscale_cli/notifications_contract.py +296 -0
  12. {quickscale_cli-0.76.0 → quickscale_cli-0.79.0}/src/quickscale_cli/schema/state_schema.py +11 -2
  13. quickscale_cli-0.79.0/src/quickscale_cli/social_contract.py +483 -0
  14. {quickscale_cli-0.76.0 → quickscale_cli-0.79.0}/src/quickscale_cli/utils/dependency_utils.py +5 -1
  15. {quickscale_cli-0.76.0 → quickscale_cli-0.79.0}/src/quickscale_cli/utils/docker_utils.py +10 -2
  16. {quickscale_cli-0.76.0 → quickscale_cli-0.79.0}/src/quickscale_cli/utils/module_wiring_manager.py +7 -1
  17. {quickscale_cli-0.76.0 → quickscale_cli-0.79.0}/src/quickscale_cli/utils/railway_utils.py +50 -10
  18. quickscale_cli-0.76.0/src/quickscale_cli/commands/module_wiring_specs.py +0 -291
  19. {quickscale_cli-0.76.0 → quickscale_cli-0.79.0}/README.md +0 -0
  20. {quickscale_cli-0.76.0 → quickscale_cli-0.79.0}/src/quickscale_cli/__init__.py +0 -0
  21. {quickscale_cli-0.76.0 → quickscale_cli-0.79.0}/src/quickscale_cli/commands/__init__.py +0 -0
  22. {quickscale_cli-0.76.0 → quickscale_cli-0.79.0}/src/quickscale_cli/commands/deployment_commands.py +0 -0
  23. {quickscale_cli-0.76.0 → quickscale_cli-0.79.0}/src/quickscale_cli/commands/development_commands.py +0 -0
  24. {quickscale_cli-0.76.0 → quickscale_cli-0.79.0}/src/quickscale_cli/commands/remove_command.py +0 -0
  25. {quickscale_cli-0.76.0 → quickscale_cli-0.79.0}/src/quickscale_cli/commands/status_command.py +0 -0
  26. {quickscale_cli-0.76.0 → quickscale_cli-0.79.0}/src/quickscale_cli/main.py +0 -0
  27. {quickscale_cli-0.76.0 → quickscale_cli-0.79.0}/src/quickscale_cli/schema/__init__.py +0 -0
  28. {quickscale_cli-0.76.0 → quickscale_cli-0.79.0}/src/quickscale_cli/schema/config_schema.py +0 -0
  29. {quickscale_cli-0.76.0 → quickscale_cli-0.79.0}/src/quickscale_cli/schema/delta.py +0 -0
  30. {quickscale_cli-0.76.0 → quickscale_cli-0.79.0}/src/quickscale_cli/utils/__init__.py +0 -0
  31. {quickscale_cli-0.76.0 → quickscale_cli-0.79.0}/src/quickscale_cli/utils/project_identity.py +0 -0
  32. {quickscale_cli-0.76.0 → quickscale_cli-0.79.0}/src/quickscale_cli/utils/project_manager.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: quickscale-cli
3
- Version: 0.76.0
3
+ Version: 0.79.0
4
4
  Summary: Command-line interface for QuickScale Django project generator
5
5
  License-Expression: Apache-2.0
6
6
  Keywords: django,cli,project-generator,saas
@@ -14,7 +14,7 @@ Classifier: Programming Language :: Python :: 3.14
14
14
  Classifier: Framework :: Django
15
15
  Classifier: Framework :: Django :: 6.0
16
16
  Requires-Dist: click (>=8.3.1,<9.0.0)
17
- Requires-Dist: quickscale-core (>=0.76.0,<0.77.0)
17
+ Requires-Dist: quickscale-core (>=0.79.0,<0.80.0)
18
18
  Project-URL: Documentation, https://github.com/Experto-AI/quickscale/tree/main/docs
19
19
  Project-URL: Homepage, https://github.com/Experto-AI/quickscale
20
20
  Project-URL: Repository, https://github.com/Experto-AI/quickscale
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "quickscale-cli"
3
- version = "0.76.0"
3
+ version = "0.79.0"
4
4
  description = "Command-line interface for QuickScale Django project generator"
5
5
  requires-python = ">=3.14,<4.0"
6
6
  readme = "README.md"
@@ -31,7 +31,7 @@ packages = [{include = "quickscale_cli", from = "src"}]
31
31
  [tool.poetry.dependencies]
32
32
  python = "^3.14"
33
33
  click = "^8.3.1"
34
- quickscale-core = "^0.76.0"
34
+ quickscale-core = "^0.79.0"
35
35
 
36
36
  [tool.poetry.group.dev.dependencies]
37
37
  # Dev dependencies centralized in root pyproject.toml
@@ -1,2 +1,2 @@
1
1
  # Auto-generated by scripts/version_tool.sh
2
- __version__ = "0.76.0"
2
+ __version__ = "0.79.0"
@@ -0,0 +1,128 @@
1
+ """Shared backups-module configuration helpers.
2
+
3
+ This module centralizes the non-secret configuration contract used by the
4
+ planner, apply flow, and state persistence for the backups module.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from collections.abc import Mapping
10
+ import re
11
+ from typing import Any
12
+
13
+ from quickscale_cli.notifications_contract import normalize_notifications_module_options
14
+ from quickscale_cli.social_contract import normalize_social_module_options
15
+
16
+ DEFAULT_BACKUPS_REMOTE_ACCESS_KEY_ID_ENV_VAR = "QUICKSCALE_BACKUPS_REMOTE_ACCESS_KEY_ID"
17
+ DEFAULT_BACKUPS_REMOTE_SECRET_ACCESS_KEY_ENV_VAR = (
18
+ "QUICKSCALE_BACKUPS_REMOTE_SECRET_ACCESS_KEY"
19
+ )
20
+
21
+ BACKUPS_REMOTE_ACCESS_KEY_ID_ENV_VAR_OPTION = "remote_access_key_id_env_var"
22
+ BACKUPS_REMOTE_SECRET_ACCESS_KEY_ENV_VAR_OPTION = "remote_secret_access_key_env_var"
23
+
24
+ _LEGACY_BACKUPS_SECRET_OPTIONS = {
25
+ "remote_access_key_id": DEFAULT_BACKUPS_REMOTE_ACCESS_KEY_ID_ENV_VAR,
26
+ "remote_secret_access_key": DEFAULT_BACKUPS_REMOTE_SECRET_ACCESS_KEY_ENV_VAR,
27
+ }
28
+
29
+ _BACKUPS_ENV_VAR_NAME_PATTERN = re.compile(r"^[A-Z][A-Z0-9_]*$")
30
+ _LIKELY_AWS_ACCESS_KEY_ID_PATTERN = re.compile(r"^(?:AKIA|ASIA)[A-Z0-9]{16}$")
31
+
32
+
33
+ def normalize_backups_module_options(
34
+ options: Mapping[str, Any] | None,
35
+ ) -> dict[str, Any]:
36
+ """Return backups options with legacy raw-secret keys removed.
37
+
38
+ Legacy raw credential values are converted into conventional environment-variable
39
+ references so downstream persistence layers never re-store the secret values.
40
+ """
41
+ normalized = dict(options or {})
42
+
43
+ legacy_access_key_id = str(normalized.pop("remote_access_key_id", "")).strip()
44
+ legacy_secret_access_key = str(
45
+ normalized.pop("remote_secret_access_key", "")
46
+ ).strip()
47
+
48
+ access_key_env_var = str(
49
+ normalized.get(BACKUPS_REMOTE_ACCESS_KEY_ID_ENV_VAR_OPTION, "")
50
+ ).strip()
51
+ secret_access_key_env_var = str(
52
+ normalized.get(BACKUPS_REMOTE_SECRET_ACCESS_KEY_ENV_VAR_OPTION, "")
53
+ ).strip()
54
+
55
+ if legacy_access_key_id and not access_key_env_var:
56
+ normalized[BACKUPS_REMOTE_ACCESS_KEY_ID_ENV_VAR_OPTION] = (
57
+ DEFAULT_BACKUPS_REMOTE_ACCESS_KEY_ID_ENV_VAR
58
+ )
59
+ if legacy_secret_access_key and not secret_access_key_env_var:
60
+ normalized[BACKUPS_REMOTE_SECRET_ACCESS_KEY_ENV_VAR_OPTION] = (
61
+ DEFAULT_BACKUPS_REMOTE_SECRET_ACCESS_KEY_ENV_VAR
62
+ )
63
+
64
+ return normalized
65
+
66
+
67
+ def has_legacy_backups_secret_values(options: Mapping[str, Any] | None) -> bool:
68
+ """Return whether backups options still include legacy raw-secret keys."""
69
+ if not options:
70
+ return False
71
+
72
+ for option_name in _LEGACY_BACKUPS_SECRET_OPTIONS:
73
+ if str(options.get(option_name, "")).strip():
74
+ return True
75
+ return False
76
+
77
+
78
+ def validate_backups_env_var_reference(option_name: str, value: Any) -> str | None:
79
+ """Validate a backups env-var reference field.
80
+
81
+ Returns an actionable error string when the value is not a safe environment
82
+ variable name or appears to be a literal credential value.
83
+ """
84
+ candidate = str(value).strip()
85
+ if not candidate:
86
+ return None
87
+
88
+ qualified_option = f"modules.backups.{option_name}"
89
+ if not _BACKUPS_ENV_VAR_NAME_PATTERN.fullmatch(candidate):
90
+ return (
91
+ f"{qualified_option} must be an environment variable name matching "
92
+ "^[A-Z][A-Z0-9_]*$"
93
+ )
94
+
95
+ if option_name == BACKUPS_REMOTE_ACCESS_KEY_ID_ENV_VAR_OPTION:
96
+ if _LIKELY_AWS_ACCESS_KEY_ID_PATTERN.fullmatch(candidate):
97
+ return (
98
+ f"{qualified_option} must reference an environment variable name, "
99
+ "not a literal AWS access key id"
100
+ )
101
+
102
+ return None
103
+
104
+
105
+ def sanitize_module_options(
106
+ module_name: str,
107
+ options: Mapping[str, Any] | None,
108
+ ) -> dict[str, Any]:
109
+ """Return module options safe for config/state persistence."""
110
+ if module_name == "backups":
111
+ return normalize_backups_module_options(options)
112
+ if module_name == "notifications":
113
+ return normalize_notifications_module_options(options)
114
+ if module_name == "social":
115
+ return normalize_social_module_options(dict(options or {}))
116
+ return dict(options or {})
117
+
118
+
119
+ __all__ = [
120
+ "BACKUPS_REMOTE_ACCESS_KEY_ID_ENV_VAR_OPTION",
121
+ "BACKUPS_REMOTE_SECRET_ACCESS_KEY_ENV_VAR_OPTION",
122
+ "DEFAULT_BACKUPS_REMOTE_ACCESS_KEY_ID_ENV_VAR",
123
+ "DEFAULT_BACKUPS_REMOTE_SECRET_ACCESS_KEY_ENV_VAR",
124
+ "has_legacy_backups_secret_values",
125
+ "normalize_backups_module_options",
126
+ "sanitize_module_options",
127
+ "validate_backups_env_var_reference",
128
+ ]