taipanstack 0.1.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.
- taipanstack/__init__.py +53 -0
- taipanstack/config/__init__.py +25 -0
- taipanstack/config/generators.py +357 -0
- taipanstack/config/models.py +316 -0
- taipanstack/config/version_config.py +227 -0
- taipanstack/core/__init__.py +47 -0
- taipanstack/core/compat.py +329 -0
- taipanstack/core/optimizations.py +392 -0
- taipanstack/core/result.py +199 -0
- taipanstack/security/__init__.py +55 -0
- taipanstack/security/decorators.py +369 -0
- taipanstack/security/guards.py +362 -0
- taipanstack/security/sanitizers.py +321 -0
- taipanstack/security/validators.py +342 -0
- taipanstack/utils/__init__.py +24 -0
- taipanstack/utils/circuit_breaker.py +268 -0
- taipanstack/utils/filesystem.py +417 -0
- taipanstack/utils/logging.py +328 -0
- taipanstack/utils/metrics.py +272 -0
- taipanstack/utils/retry.py +300 -0
- taipanstack/utils/subprocess.py +344 -0
- taipanstack-0.1.0.dist-info/METADATA +350 -0
- taipanstack-0.1.0.dist-info/RECORD +25 -0
- taipanstack-0.1.0.dist-info/WHEEL +4 -0
- taipanstack-0.1.0.dist-info/licenses/LICENSE +21 -0
taipanstack/__init__.py
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"""
|
|
2
|
+
TaipanStack - Python Security & Quality Bootstrapper.
|
|
3
|
+
|
|
4
|
+
A modular, secure, and scalable Python stack for robust development.
|
|
5
|
+
Supports Python 3.11+ with version-aware optimizations for 3.13/3.14.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
__version__ = "2.0.0"
|
|
9
|
+
|
|
10
|
+
from taipanstack.config.models import StackConfig
|
|
11
|
+
from taipanstack.config.version_config import (
|
|
12
|
+
VersionRecommendations,
|
|
13
|
+
get_version_recommendations,
|
|
14
|
+
)
|
|
15
|
+
from taipanstack.core.compat import (
|
|
16
|
+
PY311,
|
|
17
|
+
PY312,
|
|
18
|
+
PY313,
|
|
19
|
+
PY314,
|
|
20
|
+
PY_VERSION,
|
|
21
|
+
get_features,
|
|
22
|
+
get_python_info,
|
|
23
|
+
)
|
|
24
|
+
from taipanstack.core.optimizations import apply_optimizations, get_optimization_profile
|
|
25
|
+
from taipanstack.security.guards import (
|
|
26
|
+
guard_command_injection,
|
|
27
|
+
guard_path_traversal,
|
|
28
|
+
)
|
|
29
|
+
from taipanstack.security.validators import (
|
|
30
|
+
validate_email,
|
|
31
|
+
validate_project_name,
|
|
32
|
+
validate_python_version,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
__all__ = [
|
|
36
|
+
"PY311",
|
|
37
|
+
"PY312",
|
|
38
|
+
"PY313",
|
|
39
|
+
"PY314",
|
|
40
|
+
"PY_VERSION",
|
|
41
|
+
"StackConfig",
|
|
42
|
+
"VersionRecommendations",
|
|
43
|
+
"apply_optimizations",
|
|
44
|
+
"get_features",
|
|
45
|
+
"get_optimization_profile",
|
|
46
|
+
"get_python_info",
|
|
47
|
+
"get_version_recommendations",
|
|
48
|
+
"guard_command_injection",
|
|
49
|
+
"guard_path_traversal",
|
|
50
|
+
"validate_email",
|
|
51
|
+
"validate_project_name",
|
|
52
|
+
"validate_python_version",
|
|
53
|
+
]
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""Configuration models package."""
|
|
2
|
+
|
|
3
|
+
from taipanstack.config.generators import (
|
|
4
|
+
generate_dependabot_config,
|
|
5
|
+
generate_pre_commit_config,
|
|
6
|
+
generate_pyproject_config,
|
|
7
|
+
generate_security_policy,
|
|
8
|
+
)
|
|
9
|
+
from taipanstack.config.models import (
|
|
10
|
+
DependencyConfig,
|
|
11
|
+
LoggingConfig,
|
|
12
|
+
SecurityConfig,
|
|
13
|
+
StackConfig,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
__all__ = [
|
|
17
|
+
"DependencyConfig",
|
|
18
|
+
"LoggingConfig",
|
|
19
|
+
"SecurityConfig",
|
|
20
|
+
"StackConfig",
|
|
21
|
+
"generate_dependabot_config",
|
|
22
|
+
"generate_pre_commit_config",
|
|
23
|
+
"generate_pyproject_config",
|
|
24
|
+
"generate_security_policy",
|
|
25
|
+
]
|
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Configuration file generators.
|
|
3
|
+
|
|
4
|
+
This module generates configuration files (pyproject.toml, pre-commit, etc.)
|
|
5
|
+
with proper validation and templating.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import TYPE_CHECKING
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from taipanstack.config.models import StackConfig
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def generate_pyproject_config(config: StackConfig) -> str:
|
|
18
|
+
"""Generate Ruff, Mypy, and Pytest configuration for pyproject.toml.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
config: The Stack configuration.
|
|
22
|
+
|
|
23
|
+
Returns:
|
|
24
|
+
Configuration string to append to pyproject.toml.
|
|
25
|
+
|
|
26
|
+
"""
|
|
27
|
+
target_version = config.to_target_version()
|
|
28
|
+
python_version = config.python_version
|
|
29
|
+
|
|
30
|
+
return f"""
|
|
31
|
+
# --- Stack v2.0 Quality Configuration ---
|
|
32
|
+
[tool.ruff]
|
|
33
|
+
line-length = 88
|
|
34
|
+
target-version = "{target_version}"
|
|
35
|
+
|
|
36
|
+
[tool.ruff.lint]
|
|
37
|
+
select = [
|
|
38
|
+
"F", # Pyflakes
|
|
39
|
+
"E", # pycodestyle errors
|
|
40
|
+
"W", # pycodestyle warnings
|
|
41
|
+
"I", # isort
|
|
42
|
+
"N", # pep8-naming
|
|
43
|
+
"D", # pydocstyle
|
|
44
|
+
"Q", # flake8-quotes
|
|
45
|
+
"S", # flake8-bandit
|
|
46
|
+
"B", # flake8-bugbear
|
|
47
|
+
"A", # flake8-builtins
|
|
48
|
+
"C4", # flake8-comprehensions
|
|
49
|
+
"T20", # flake8-print
|
|
50
|
+
"SIM", # flake8-simplify
|
|
51
|
+
"PTH", # flake8-use-pathlib
|
|
52
|
+
"TID", # flake8-tidy-imports
|
|
53
|
+
"ARG", # flake8-unused-arguments
|
|
54
|
+
"PIE", # flake8-pie
|
|
55
|
+
"PLC", # Pylint Convention
|
|
56
|
+
"PLE", # Pylint Error
|
|
57
|
+
"PLR", # Pylint Refactor
|
|
58
|
+
"PLW", # Pylint Warning
|
|
59
|
+
"RUF", # Ruff-specific
|
|
60
|
+
"UP", # pyupgrade
|
|
61
|
+
"ERA", # eradicate
|
|
62
|
+
"TRY", # tryceratops
|
|
63
|
+
]
|
|
64
|
+
ignore = ["D203", "D212", "D213", "D416", "D417", "B905"]
|
|
65
|
+
|
|
66
|
+
[tool.ruff.lint.mccabe]
|
|
67
|
+
max-complexity = 10
|
|
68
|
+
|
|
69
|
+
[tool.ruff.lint.per-file-ignores]
|
|
70
|
+
"tests/**/*.py" = ["S101", "D"]
|
|
71
|
+
|
|
72
|
+
[tool.ruff.format]
|
|
73
|
+
quote-style = "double"
|
|
74
|
+
indent-style = "space"
|
|
75
|
+
|
|
76
|
+
[tool.mypy]
|
|
77
|
+
python_version = "{python_version}"
|
|
78
|
+
warn_return_any = true
|
|
79
|
+
warn_unused_configs = true
|
|
80
|
+
disallow_untyped_defs = true
|
|
81
|
+
disallow_any_unimported = false
|
|
82
|
+
no_implicit_optional = true
|
|
83
|
+
check_untyped_defs = true
|
|
84
|
+
strict_optional = true
|
|
85
|
+
strict_equality = true
|
|
86
|
+
ignore_missing_imports = true
|
|
87
|
+
show_error_codes = true
|
|
88
|
+
enable_error_code = ["ignore-without-code", "redundant-cast", "truthy-bool"]
|
|
89
|
+
|
|
90
|
+
[tool.pytest.ini_options]
|
|
91
|
+
testpaths = ["tests"]
|
|
92
|
+
addopts = "-v --cov=src --cov-report=html --cov-report=term-missing --cov-fail-under=80 --strict-markers"
|
|
93
|
+
markers = [
|
|
94
|
+
"slow: marks tests as slow (deselect with '-m \"not slow\"')",
|
|
95
|
+
"security: marks tests as security-related",
|
|
96
|
+
]
|
|
97
|
+
|
|
98
|
+
[tool.coverage.run]
|
|
99
|
+
branch = true
|
|
100
|
+
source = ["src"]
|
|
101
|
+
omit = ["*/tests/*", "*/__pycache__/*"]
|
|
102
|
+
|
|
103
|
+
[tool.coverage.report]
|
|
104
|
+
exclude_lines = [
|
|
105
|
+
"pragma: no cover",
|
|
106
|
+
"def __repr__",
|
|
107
|
+
"raise NotImplementedError",
|
|
108
|
+
"if TYPE_CHECKING:",
|
|
109
|
+
"if __name__ == .__main__.:",
|
|
110
|
+
]
|
|
111
|
+
"""
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def generate_pre_commit_config(config: StackConfig) -> str:
|
|
115
|
+
"""Generate .pre-commit-config.yaml content.
|
|
116
|
+
|
|
117
|
+
Args:
|
|
118
|
+
config: The Stack configuration.
|
|
119
|
+
|
|
120
|
+
Returns:
|
|
121
|
+
Pre-commit configuration YAML string.
|
|
122
|
+
|
|
123
|
+
"""
|
|
124
|
+
security_hooks = ""
|
|
125
|
+
|
|
126
|
+
if config.security.enable_bandit:
|
|
127
|
+
severity = config.security.bandit_severity[0].upper()
|
|
128
|
+
security_hooks += f"""
|
|
129
|
+
- repo: https://github.com/PyCQA/bandit
|
|
130
|
+
rev: '1.8.0'
|
|
131
|
+
hooks:
|
|
132
|
+
- id: bandit
|
|
133
|
+
args: ["-r", ".", "-l{severity}"]
|
|
134
|
+
"""
|
|
135
|
+
|
|
136
|
+
if config.security.enable_safety:
|
|
137
|
+
security_hooks += """
|
|
138
|
+
- repo: https://github.com/pyupio/safety
|
|
139
|
+
rev: '3.2.11'
|
|
140
|
+
hooks:
|
|
141
|
+
- id: safety
|
|
142
|
+
args: ["check", "--json"]
|
|
143
|
+
"""
|
|
144
|
+
|
|
145
|
+
if config.security.enable_semgrep:
|
|
146
|
+
security_hooks += """
|
|
147
|
+
- repo: https://github.com/semgrep/pre-commit
|
|
148
|
+
rev: 'v1.99.0'
|
|
149
|
+
hooks:
|
|
150
|
+
- id: semgrep
|
|
151
|
+
args: ['--config=auto']
|
|
152
|
+
"""
|
|
153
|
+
|
|
154
|
+
if config.security.enable_detect_secrets:
|
|
155
|
+
security_hooks += """
|
|
156
|
+
- repo: https://github.com/Yelp/detect-secrets
|
|
157
|
+
rev: 'v1.5.0'
|
|
158
|
+
hooks:
|
|
159
|
+
- id: detect-secrets
|
|
160
|
+
args: ['--baseline', '.secrets.baseline']
|
|
161
|
+
"""
|
|
162
|
+
|
|
163
|
+
# Add pip-audit for paranoid mode
|
|
164
|
+
if config.security.level == "paranoid":
|
|
165
|
+
security_hooks += """
|
|
166
|
+
- repo: https://github.com/trailofbits/pip-audit
|
|
167
|
+
rev: 'v2.7.3'
|
|
168
|
+
hooks:
|
|
169
|
+
- id: pip-audit
|
|
170
|
+
|
|
171
|
+
- repo: https://github.com/jendrikseipp/vulture
|
|
172
|
+
rev: 'v2.11'
|
|
173
|
+
hooks:
|
|
174
|
+
- id: vulture
|
|
175
|
+
|
|
176
|
+
- repo: https://github.com/guilatrova/tryceratops
|
|
177
|
+
rev: 'v2.3.3'
|
|
178
|
+
hooks:
|
|
179
|
+
- id: tryceratops
|
|
180
|
+
"""
|
|
181
|
+
|
|
182
|
+
return f"""# Stack v2.0 Pre-commit Configuration
|
|
183
|
+
# Security Level: {config.security.level}
|
|
184
|
+
repos:
|
|
185
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
186
|
+
rev: v5.0.0
|
|
187
|
+
hooks:
|
|
188
|
+
- id: trailing-whitespace
|
|
189
|
+
- id: end-of-file-fixer
|
|
190
|
+
- id: check-yaml
|
|
191
|
+
- id: check-added-large-files
|
|
192
|
+
- id: check-merge-conflict
|
|
193
|
+
- id: check-case-conflict
|
|
194
|
+
- id: detect-private-key
|
|
195
|
+
|
|
196
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
197
|
+
rev: 'v0.8.4'
|
|
198
|
+
hooks:
|
|
199
|
+
- id: ruff
|
|
200
|
+
args: [--fix, --exit-non-zero-on-fix]
|
|
201
|
+
- id: ruff-format
|
|
202
|
+
|
|
203
|
+
- repo: https://github.com/pre-commit/mirrors-mypy
|
|
204
|
+
rev: 'v1.13.0'
|
|
205
|
+
hooks:
|
|
206
|
+
- id: mypy
|
|
207
|
+
additional_dependencies: [types-all, pydantic]
|
|
208
|
+
{security_hooks}"""
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def generate_dependabot_config() -> str:
|
|
212
|
+
"""Generate .github/dependabot.yml content.
|
|
213
|
+
|
|
214
|
+
Returns:
|
|
215
|
+
Dependabot configuration YAML string.
|
|
216
|
+
|
|
217
|
+
"""
|
|
218
|
+
return """# Stack v2.0 Dependabot Configuration
|
|
219
|
+
version: 2
|
|
220
|
+
updates:
|
|
221
|
+
- package-ecosystem: "pip"
|
|
222
|
+
directory: "/"
|
|
223
|
+
schedule:
|
|
224
|
+
interval: "daily"
|
|
225
|
+
open-pull-requests-limit: 10
|
|
226
|
+
groups:
|
|
227
|
+
dev-dependencies:
|
|
228
|
+
patterns:
|
|
229
|
+
- "ruff"
|
|
230
|
+
- "mypy"
|
|
231
|
+
- "bandit"
|
|
232
|
+
- "safety"
|
|
233
|
+
- "pytest*"
|
|
234
|
+
- "pre-commit"
|
|
235
|
+
- "semgrep"
|
|
236
|
+
- "py-spy"
|
|
237
|
+
security-tools:
|
|
238
|
+
patterns:
|
|
239
|
+
- "bandit"
|
|
240
|
+
- "safety"
|
|
241
|
+
- "semgrep"
|
|
242
|
+
- "pip-audit"
|
|
243
|
+
reviewers:
|
|
244
|
+
- "gabrielima7"
|
|
245
|
+
|
|
246
|
+
- package-ecosystem: "github-actions"
|
|
247
|
+
directory: "/"
|
|
248
|
+
schedule:
|
|
249
|
+
interval: "weekly"
|
|
250
|
+
groups:
|
|
251
|
+
actions:
|
|
252
|
+
patterns:
|
|
253
|
+
- "*"
|
|
254
|
+
"""
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
def generate_security_policy() -> str:
|
|
258
|
+
"""Generate SECURITY.md content.
|
|
259
|
+
|
|
260
|
+
Returns:
|
|
261
|
+
Security policy markdown string.
|
|
262
|
+
|
|
263
|
+
"""
|
|
264
|
+
return """# Security Policy
|
|
265
|
+
|
|
266
|
+
## Supported Versions
|
|
267
|
+
|
|
268
|
+
We prioritize security fixes for the latest version (Rolling Release).
|
|
269
|
+
|
|
270
|
+
| Version | Supported |
|
|
271
|
+
| ------- | ------------------ |
|
|
272
|
+
| Latest | :white_check_mark: |
|
|
273
|
+
| Older | :x: |
|
|
274
|
+
|
|
275
|
+
## Security Features
|
|
276
|
+
|
|
277
|
+
This project includes multiple layers of security:
|
|
278
|
+
|
|
279
|
+
- **SAST**: Bandit for static security analysis
|
|
280
|
+
- **SCA**: Safety/pip-audit for dependency vulnerabilities
|
|
281
|
+
- **Secrets**: detect-secrets for preventing credential leaks
|
|
282
|
+
- **Type Safety**: Mypy + Pydantic for runtime validation
|
|
283
|
+
- **Runtime Guards**: Protection against path traversal and injection
|
|
284
|
+
|
|
285
|
+
## Reporting a Vulnerability
|
|
286
|
+
|
|
287
|
+
1. **DO NOT** create a public issue for security vulnerabilities
|
|
288
|
+
2. Report via the [Security tab](../../security/advisories/new)
|
|
289
|
+
3. Or email the maintainer directly
|
|
290
|
+
4. Include:
|
|
291
|
+
- Description of the vulnerability
|
|
292
|
+
- Steps to reproduce
|
|
293
|
+
- Potential impact
|
|
294
|
+
- Suggested fix (if any)
|
|
295
|
+
|
|
296
|
+
## Response Timeline
|
|
297
|
+
|
|
298
|
+
- **Acknowledgment**: Within 48 hours
|
|
299
|
+
- **Initial Assessment**: Within 1 week
|
|
300
|
+
- **Fix Release**: Depends on severity (critical: ASAP, others: next release)
|
|
301
|
+
"""
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
def generate_editorconfig() -> str:
|
|
305
|
+
"""Generate .editorconfig content.
|
|
306
|
+
|
|
307
|
+
Returns:
|
|
308
|
+
EditorConfig content string.
|
|
309
|
+
|
|
310
|
+
"""
|
|
311
|
+
return """# Stack v2.0 EditorConfig
|
|
312
|
+
root = true
|
|
313
|
+
|
|
314
|
+
[*]
|
|
315
|
+
end_of_line = lf
|
|
316
|
+
insert_final_newline = true
|
|
317
|
+
trim_trailing_whitespace = true
|
|
318
|
+
charset = utf-8
|
|
319
|
+
indent_style = space
|
|
320
|
+
indent_size = 4
|
|
321
|
+
|
|
322
|
+
[*.py]
|
|
323
|
+
max_line_length = 88
|
|
324
|
+
|
|
325
|
+
[*.{yml,yaml,toml,json}]
|
|
326
|
+
indent_size = 2
|
|
327
|
+
|
|
328
|
+
[Makefile]
|
|
329
|
+
indent_style = tab
|
|
330
|
+
"""
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
def write_config_file(
|
|
334
|
+
path: Path,
|
|
335
|
+
content: str,
|
|
336
|
+
config: StackConfig,
|
|
337
|
+
) -> bool:
|
|
338
|
+
"""Write configuration file with backup support.
|
|
339
|
+
|
|
340
|
+
Args:
|
|
341
|
+
path: Path to write the file.
|
|
342
|
+
content: Content to write.
|
|
343
|
+
config: Stack configuration.
|
|
344
|
+
|
|
345
|
+
Returns:
|
|
346
|
+
True if file was written, False if in dry-run mode.
|
|
347
|
+
|
|
348
|
+
"""
|
|
349
|
+
if config.dry_run:
|
|
350
|
+
return False
|
|
351
|
+
|
|
352
|
+
if path.exists() and not config.force:
|
|
353
|
+
backup_path = path.with_suffix(f"{path.suffix}.bak")
|
|
354
|
+
path.rename(backup_path)
|
|
355
|
+
|
|
356
|
+
path.write_text(content, encoding="utf-8")
|
|
357
|
+
return True
|