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

1""" 

2Configuration file generators. 

3 

4This module generates configuration files (pyproject.toml, pre-commit, etc.) 

5with proper validation and templating. 

6""" 

7 

8from taipanstack.config.models import StackConfig 

9 

10 

11def _generate_ruff_config(target_version: str) -> str: 

12 """Generate Ruff configuration. 

13 

14 Args: 

15 target_version: The target Python version. 

16 

17 Returns: 

18 Ruff configuration string. 

19 

20 """ 

21 return f"""[tool.ruff] 

22line-length = 88 

23target-version = "{target_version}" 

24 

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"] 

54 

55[tool.ruff.lint.mccabe] 

56max-complexity = 10 

57 

58[tool.ruff.lint.per-file-ignores] 

59"tests/**/*.py" = ["S101", "D"] 

60 

61[tool.ruff.format] 

62quote-style = "double" 

63indent-style = "space" 

64""" 

65 

66 

67def _generate_mypy_config(python_version: str) -> str: 

68 """Generate Mypy configuration. 

69 

70 Args: 

71 python_version: The target Python version. 

72 

73 Returns: 

74 Mypy configuration string. 

75 

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""" 

91 

92 

93def _generate_pytest_config() -> str: 

94 """Generate Pytest configuration. 

95 

96 Returns: 

97 Pytest configuration string. 

98 

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""" 

108 

109 

110def _generate_coverage_config() -> str: 

111 """Generate Coverage configuration. 

112 

113 Returns: 

114 Coverage configuration string. 

115 

116 """ 

117 return """[tool.coverage.run] 

118branch = true 

119source = ["src"] 

120omit = ["*/tests/*", "*/__pycache__/*"] 

121 

122[tool.coverage.report] 

123exclude_lines = [ 

124 "def __repr__", 

125 "raise NotImplementedError", 

126 "if TYPE_CHECKING:", 

127 "if __name__ == .__main__.:", 

128] 

129""" 

130 

131 

132def generate_pyproject_config(config: StackConfig) -> str: 

133 """Generate Ruff, Mypy, and Pytest configuration for pyproject.toml. 

134 

135 Args: 

136 config: The Stack configuration. 

137 

138 Returns: 

139 Configuration string to append to pyproject.toml. 

140 

141 """ 

142 target_version = config.to_target_version() 

143 python_version = config.python_version 

144 

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()}""" 

151 

152 

153def _generate_bandit_hook(severity: str) -> str: 

154 """Generate Bandit pre-commit hook. 

155 

156 Args: 

157 severity: Bandit severity level. 

158 

159 Returns: 

160 Bandit hook YAML string. 

161 

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""" 

171 

172 

173def _generate_safety_hook() -> str: 

174 """Generate Safety pre-commit hook. 

175 

176 Returns: 

177 Safety hook YAML string. 

178 

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""" 

187 

188 

189def _generate_semgrep_hook() -> str: 

190 """Generate Semgrep pre-commit hook. 

191 

192 Returns: 

193 Semgrep hook YAML string. 

194 

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""" 

203 

204 

205def _generate_detect_secrets_hook() -> str: 

206 """Generate detect-secrets pre-commit hook. 

207 

208 Returns: 

209 Detect-secrets hook YAML string. 

210 

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""" 

219 

220 

221def _generate_paranoid_hooks() -> str: 

222 """Generate extra security hooks for paranoid mode. 

223 

224 Returns: 

225 Paranoid hooks YAML string. 

226 

227 """ 

228 return """ 

229 - repo: https://github.com/trailofbits/pip-audit 

230 rev: 'v2.7.3' 

231 hooks: 

232 - id: pip-audit 

233 

234 - repo: https://github.com/jendrikseipp/vulture 

235 rev: 'v2.11' 

236 hooks: 

237 - id: vulture 

238 

239 - repo: https://github.com/guilatrova/tryceratops 

240 rev: 'v2.3.3' 

241 hooks: 

242 - id: tryceratops 

243""" 

244 

245 

246def generate_pre_commit_config(config: StackConfig) -> str: 

247 """Generate .pre-commit-config.yaml content. 

248 

249 Args: 

250 config: The Stack configuration. 

251 

252 Returns: 

253 Pre-commit configuration YAML string. 

254 

255 """ 

256 security_hooks: list[str] = [] 

257 

258 if config.security.enable_bandit: 

259 security_hooks.append(_generate_bandit_hook(config.security.bandit_severity)) 

260 

261 if config.security.enable_safety: 

262 security_hooks.append(_generate_safety_hook()) 

263 

264 if config.security.enable_semgrep: 

265 security_hooks.append(_generate_semgrep_hook()) 

266 

267 if config.security.enable_detect_secrets: 

268 security_hooks.append(_generate_detect_secrets_hook()) 

269 

270 # Add extra hooks for paranoid mode 

271 if config.security.level == "paranoid": 

272 security_hooks.append(_generate_paranoid_hooks()) 

273 

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 

287 

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 

294 

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)}""" 

301 

302 

303def generate_security_policy() -> str: 

304 """Generate SECURITY.md content. 

305 

306 Returns: 

307 Security policy markdown string. 

308 

309 """ 

310 return """# Security Policy 

311 

312## Supported Versions 

313 

314We prioritize security fixes for the latest version (Rolling Release). 

315 

316| Version | Supported | 

317| ------- | ------------------ | 

318| Latest | :white_check_mark: | 

319| Older | :x: | 

320 

321## Security Features 

322 

323This project includes multiple layers of security: 

324 

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 

330 

331## Reporting a Vulnerability 

332 

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) 

341 

342## Response Timeline 

343 

344- **Acknowledgment**: Within 48 hours 

345- **Initial Assessment**: Within 1 week 

346- **Fix Release**: Depends on severity (critical: ASAP, others: next release) 

347"""