Coverage for src / taipanstack / config / generators.py: 100%
38 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-05-12 21:18 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-05-12 21:18 +0000
1"""
2Configuration file generators.
4This module generates configuration files (pyproject.toml, pre-commit, etc.)
5with proper validation and templating.
6"""
8from taipanstack.config.models import StackConfig
11def _generate_ruff_config(target_version: str) -> str:
12 """Generate Ruff configuration.
14 Args:
15 target_version: The target Python version.
17 Returns:
18 Ruff configuration string.
20 """
21 return f"""[tool.ruff]
22line-length = 88
23target-version = "{target_version}"
25[tool.ruff.lint]
26select = [
27 "F", # Pyflakes
28 "E", # pycodestyle errors
29 "W", # pycodestyle warnings
30 "I", # isort
31 "N", # pep8-naming
32 "D", # pydocstyle
33 "Q", # flake8-quotes
34 "S", # flake8-bandit
35 "B", # flake8-bugbear
36 "A", # flake8-builtins
37 "C4", # flake8-comprehensions
38 "T20", # flake8-print
39 "SIM", # flake8-simplify
40 "PTH", # flake8-use-pathlib
41 "TID", # flake8-tidy-imports
42 "ARG", # flake8-unused-arguments
43 "PIE", # flake8-pie
44 "PLC", # Pylint Convention
45 "PLE", # Pylint Error
46 "PLR", # Pylint Refactor
47 "PLW", # Pylint Warning
48 "RUF", # Ruff-specific
49 "UP", # pyupgrade
50 "ERA", # eradicate
51 "TRY", # tryceratops
52]
53ignore = ["D203", "D212", "D213", "D416", "D417"]
55[tool.ruff.lint.mccabe]
56max-complexity = 10
58[tool.ruff.lint.per-file-ignores]
59"tests/**/*.py" = ["S101", "D"]
61[tool.ruff.format]
62quote-style = "double"
63indent-style = "space"
64"""
67def _generate_mypy_config(python_version: str) -> str:
68 """Generate Mypy configuration.
70 Args:
71 python_version: The target Python version.
73 Returns:
74 Mypy configuration string.
76 """
77 return f"""[tool.mypy]
78python_version = "{python_version}"
79warn_return_any = true
80warn_unused_configs = true
81disallow_untyped_defs = true
82disallow_any_unimported = false
83no_implicit_optional = true
84check_untyped_defs = true
85strict_optional = true
86strict_equality = true
87ignore_missing_imports = true
88show_error_codes = true
89enable_error_code = ["ignore-without-code", "redundant-cast", "truthy-bool"]
90"""
93def _generate_pytest_config() -> str:
94 """Generate Pytest configuration.
96 Returns:
97 Pytest configuration string.
99 """
100 return """[tool.pytest.ini_options]
101testpaths = ["tests"]
102addopts = "-v --cov=src --cov-report=html --cov-report=term-missing --cov-fail-under=80 --strict-markers"
103markers = [
104 "slow: marks tests as slow (deselect with '-m \"not slow\"')",
105 "security: marks tests as security-related",
106]
107"""
110def _generate_coverage_config() -> str:
111 """Generate Coverage configuration.
113 Returns:
114 Coverage configuration string.
116 """
117 return """[tool.coverage.run]
118branch = true
119source = ["src"]
120omit = ["*/tests/*", "*/__pycache__/*"]
122[tool.coverage.report]
123exclude_lines = [
124 "def __repr__",
125 "raise NotImplementedError",
126 "if TYPE_CHECKING:",
127 "if __name__ == .__main__.:",
128]
129"""
132def generate_pyproject_config(config: StackConfig) -> str:
133 """Generate Ruff, Mypy, and Pytest configuration for pyproject.toml.
135 Args:
136 config: The Stack configuration.
138 Returns:
139 Configuration string to append to pyproject.toml.
141 """
142 target_version = config.to_target_version()
143 python_version = config.python_version
145 return f"""
146# --- Stack v2.0 Quality Configuration ---
147{_generate_ruff_config(target_version)}
148{_generate_mypy_config(python_version)}
149{_generate_pytest_config()}
150{_generate_coverage_config()}"""
153def _generate_bandit_hook(severity: str) -> str:
154 """Generate Bandit pre-commit hook.
156 Args:
157 severity: Bandit severity level.
159 Returns:
160 Bandit hook YAML string.
162 """
163 sev_char = severity[0].upper()
164 return f"""
165 - repo: https://github.com/PyCQA/bandit
166 rev: '1.8.0'
167 hooks:
168 - id: bandit
169 args: ["-r", ".", "-l{sev_char}"]
170"""
173def _generate_safety_hook() -> str:
174 """Generate Safety pre-commit hook.
176 Returns:
177 Safety hook YAML string.
179 """
180 return """
181 - repo: https://github.com/pyupio/safety
182 rev: '3.2.11'
183 hooks:
184 - id: safety
185 args: ["check", "--json"]
186"""
189def _generate_semgrep_hook() -> str:
190 """Generate Semgrep pre-commit hook.
192 Returns:
193 Semgrep hook YAML string.
195 """
196 return """
197 - repo: https://github.com/semgrep/pre-commit
198 rev: 'v1.99.0'
199 hooks:
200 - id: semgrep
201 args: ['--config=auto']
202"""
205def _generate_detect_secrets_hook() -> str:
206 """Generate detect-secrets pre-commit hook.
208 Returns:
209 Detect-secrets hook YAML string.
211 """
212 return """
213 - repo: https://github.com/Yelp/detect-secrets
214 rev: 'v1.5.0'
215 hooks:
216 - id: detect-secrets
217 args: ['--baseline', '.secrets.baseline']
218"""
221def _generate_paranoid_hooks() -> str:
222 """Generate extra security hooks for paranoid mode.
224 Returns:
225 Paranoid hooks YAML string.
227 """
228 return """
229 - repo: https://github.com/trailofbits/pip-audit
230 rev: 'v2.7.3'
231 hooks:
232 - id: pip-audit
234 - repo: https://github.com/jendrikseipp/vulture
235 rev: 'v2.11'
236 hooks:
237 - id: vulture
239 - repo: https://github.com/guilatrova/tryceratops
240 rev: 'v2.3.3'
241 hooks:
242 - id: tryceratops
243"""
246def generate_pre_commit_config(config: StackConfig) -> str:
247 """Generate .pre-commit-config.yaml content.
249 Args:
250 config: The Stack configuration.
252 Returns:
253 Pre-commit configuration YAML string.
255 """
256 security_hooks: list[str] = []
258 if config.security.enable_bandit:
259 security_hooks.append(_generate_bandit_hook(config.security.bandit_severity))
261 if config.security.enable_safety:
262 security_hooks.append(_generate_safety_hook())
264 if config.security.enable_semgrep:
265 security_hooks.append(_generate_semgrep_hook())
267 if config.security.enable_detect_secrets:
268 security_hooks.append(_generate_detect_secrets_hook())
270 # Add extra hooks for paranoid mode
271 if config.security.level == "paranoid":
272 security_hooks.append(_generate_paranoid_hooks())
274 return f"""# Stack v2.0 Pre-commit Configuration
275# Security Level: {config.security.level}
276repos:
277 - repo: https://github.com/pre-commit/pre-commit-hooks
278 rev: v5.0.0
279 hooks:
280 - id: trailing-whitespace
281 - id: end-of-file-fixer
282 - id: check-yaml
283 - id: check-added-large-files
284 - id: check-merge-conflict
285 - id: check-case-conflict
286 - id: detect-private-key
288 - repo: https://github.com/astral-sh/ruff-pre-commit
289 rev: 'v0.8.4'
290 hooks:
291 - id: ruff
292 args: [--fix, --exit-non-zero-on-fix]
293 - id: ruff-format
295 - repo: https://github.com/pre-commit/mirrors-mypy
296 rev: 'v1.13.0'
297 hooks:
298 - id: mypy
299 additional_dependencies: [types-all, pydantic]
300{"".join(security_hooks)}"""
303def generate_security_policy() -> str:
304 """Generate SECURITY.md content.
306 Returns:
307 Security policy markdown string.
309 """
310 return """# Security Policy
312## Supported Versions
314We prioritize security fixes for the latest version (Rolling Release).
316| Version | Supported |
317| ------- | ------------------ |
318| Latest | :white_check_mark: |
319| Older | :x: |
321## Security Features
323This project includes multiple layers of security:
325- **SAST**: Bandit for static security analysis
326- **SCA**: Safety/pip-audit for dependency vulnerabilities
327- **Secrets**: detect-secrets for preventing credential leaks
328- **Type Safety**: Mypy + Pydantic for runtime validation
329- **Runtime Guards**: Protection against path traversal and injection
331## Reporting a Vulnerability
3331. **DO NOT** create a public issue for security vulnerabilities
3342. Report via the [Security tab](../../security/advisories/new)
3353. Or email the maintainer directly
3364. Include:
337 - Description of the vulnerability
338 - Steps to reproduce
339 - Potential impact
340 - Suggested fix (if any)
342## Response Timeline
344- **Acknowledgment**: Within 48 hours
345- **Initial Assessment**: Within 1 week
346- **Fix Release**: Depends on severity (critical: ASAP, others: next release)
347"""