bps-kit 1.0.1 → 1.0.2

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 (368) hide show
  1. package/package.json +1 -1
  2. package/templates/.agents/agents/backend-specialist.md +263 -0
  3. package/templates/.agents/agents/code-archaeologist.md +106 -0
  4. package/templates/.agents/agents/database-architect.md +226 -0
  5. package/templates/.agents/agents/debugger.md +225 -0
  6. package/templates/.agents/agents/devops-engineer.md +242 -0
  7. package/templates/.agents/agents/documentation-writer.md +104 -0
  8. package/templates/.agents/agents/explorer-agent.md +73 -0
  9. package/templates/.agents/agents/frontend-specialist.md +593 -0
  10. package/templates/.agents/agents/game-developer.md +162 -0
  11. package/templates/.agents/agents/mobile-developer.md +377 -0
  12. package/templates/.agents/agents/orchestrator.md +416 -0
  13. package/templates/.agents/agents/penetration-tester.md +188 -0
  14. package/templates/.agents/agents/performance-optimizer.md +187 -0
  15. package/templates/.agents/agents/product-manager.md +112 -0
  16. package/templates/.agents/agents/product-owner.md +95 -0
  17. package/templates/.agents/agents/project-planner.md +406 -0
  18. package/templates/.agents/agents/qa-automation-engineer.md +103 -0
  19. package/templates/.agents/agents/security-auditor.md +170 -0
  20. package/templates/.agents/agents/seo-specialist.md +111 -0
  21. package/templates/.agents/agents/test-engineer.md +158 -0
  22. package/templates/.agents/rules/GEMINI.md +219 -0
  23. package/templates/.agents/scripts/auto_preview.py +148 -0
  24. package/templates/.agents/scripts/checklist.py +217 -0
  25. package/templates/.agents/scripts/session_manager.py +120 -0
  26. package/templates/.agents/scripts/verify_all.py +327 -0
  27. package/templates/.agents/workflows/brainstorm.md +113 -0
  28. package/templates/.agents/workflows/create.md +59 -0
  29. package/templates/.agents/workflows/debug.md +103 -0
  30. package/templates/.agents/workflows/deploy.md +176 -0
  31. package/templates/.agents/workflows/enhance.md +63 -0
  32. package/templates/.agents/workflows/orchestrate.md +237 -0
  33. package/templates/.agents/workflows/plan.md +89 -0
  34. package/templates/.agents/workflows/preview.md +81 -0
  35. package/templates/.agents/workflows/setup-brain.md +39 -0
  36. package/templates/.agents/workflows/status.md +86 -0
  37. package/templates/.agents/workflows/test.md +144 -0
  38. package/templates/.agents/workflows/ui-ux-pro-max.md +296 -0
  39. package/templates/skills_normal/api-patterns/scripts/api_validator.py +211 -0
  40. package/templates/skills_normal/database-design/scripts/schema_validator.py +172 -0
  41. package/templates/skills_normal/frontend-design/scripts/accessibility_checker.py +183 -0
  42. package/templates/skills_normal/frontend-design/scripts/ux_audit.py +722 -0
  43. package/templates/skills_normal/git-pushing/scripts/smart_commit.sh +19 -0
  44. package/templates/skills_normal/lint-and-validate/scripts/lint_runner.py +184 -0
  45. package/templates/skills_normal/lint-and-validate/scripts/type_coverage.py +173 -0
  46. package/templates/skills_normal/performance-profiling/scripts/lighthouse_audit.py +76 -0
  47. package/templates/skills_normal/senior-fullstack/scripts/code_quality_analyzer.py +114 -0
  48. package/templates/skills_normal/senior-fullstack/scripts/fullstack_scaffolder.py +114 -0
  49. package/templates/skills_normal/senior-fullstack/scripts/project_scaffolder.py +114 -0
  50. package/templates/skills_normal/seo-fundamentals/scripts/seo_checker.py +219 -0
  51. package/templates/skills_normal/testing-patterns/scripts/test_runner.py +219 -0
  52. package/templates/skills_normal/vulnerability-scanner/scripts/security_scan.py +458 -0
  53. package/templates/vault/007/scripts/config.py +472 -0
  54. package/templates/vault/007/scripts/full_audit.py +1306 -0
  55. package/templates/vault/007/scripts/quick_scan.py +481 -0
  56. package/templates/vault/007/scripts/requirements.txt +26 -0
  57. package/templates/vault/007/scripts/scanners/__init__.py +0 -0
  58. package/templates/vault/007/scripts/scanners/dependency_scanner.py +1305 -0
  59. package/templates/vault/007/scripts/scanners/injection_scanner.py +1104 -0
  60. package/templates/vault/007/scripts/scanners/secrets_scanner.py +1008 -0
  61. package/templates/vault/007/scripts/score_calculator.py +693 -0
  62. package/templates/vault/agent-orchestrator/scripts/match_skills.py +329 -0
  63. package/templates/vault/agent-orchestrator/scripts/orchestrate.py +304 -0
  64. package/templates/vault/agent-orchestrator/scripts/requirements.txt +1 -0
  65. package/templates/vault/agent-orchestrator/scripts/scan_registry.py +508 -0
  66. package/templates/vault/ai-studio-image/scripts/config.py +613 -0
  67. package/templates/vault/ai-studio-image/scripts/generate.py +630 -0
  68. package/templates/vault/ai-studio-image/scripts/prompt_engine.py +424 -0
  69. package/templates/vault/ai-studio-image/scripts/requirements.txt +4 -0
  70. package/templates/vault/ai-studio-image/scripts/templates.py +349 -0
  71. package/templates/vault/android_ui_verification/scripts/verify_ui.sh +32 -0
  72. package/templates/vault/apify-audience-analysis/reference/scripts/run_actor.js +363 -0
  73. package/templates/vault/apify-brand-reputation-monitoring/reference/scripts/run_actor.js +363 -0
  74. package/templates/vault/apify-competitor-intelligence/reference/scripts/run_actor.js +363 -0
  75. package/templates/vault/apify-content-analytics/reference/scripts/run_actor.js +363 -0
  76. package/templates/vault/apify-ecommerce/reference/scripts/package.json +3 -0
  77. package/templates/vault/apify-ecommerce/reference/scripts/run_actor.js +369 -0
  78. package/templates/vault/apify-influencer-discovery/reference/scripts/run_actor.js +363 -0
  79. package/templates/vault/apify-lead-generation/reference/scripts/run_actor.js +363 -0
  80. package/templates/vault/apify-market-research/reference/scripts/run_actor.js +363 -0
  81. package/templates/vault/apify-trend-analysis/reference/scripts/run_actor.js +363 -0
  82. package/templates/vault/apify-ultimate-scraper/reference/scripts/run_actor.js +363 -0
  83. package/templates/vault/audio-transcriber/scripts/install-requirements.sh +190 -0
  84. package/templates/vault/audio-transcriber/scripts/transcribe.py +486 -0
  85. package/templates/vault/claude-monitor/scripts/api_bench.py +240 -0
  86. package/templates/vault/claude-monitor/scripts/config.py +69 -0
  87. package/templates/vault/claude-monitor/scripts/health_check.py +362 -0
  88. package/templates/vault/claude-monitor/scripts/monitor.py +296 -0
  89. package/templates/vault/content-creator/scripts/brand_voice_analyzer.py +185 -0
  90. package/templates/vault/content-creator/scripts/seo_optimizer.py +419 -0
  91. package/templates/vault/context-agent/scripts/active_context.py +227 -0
  92. package/templates/vault/context-agent/scripts/compressor.py +149 -0
  93. package/templates/vault/context-agent/scripts/config.py +69 -0
  94. package/templates/vault/context-agent/scripts/context_loader.py +155 -0
  95. package/templates/vault/context-agent/scripts/context_manager.py +302 -0
  96. package/templates/vault/context-agent/scripts/models.py +103 -0
  97. package/templates/vault/context-agent/scripts/project_registry.py +132 -0
  98. package/templates/vault/context-agent/scripts/requirements.txt +6 -0
  99. package/templates/vault/context-agent/scripts/search.py +115 -0
  100. package/templates/vault/context-agent/scripts/session_parser.py +206 -0
  101. package/templates/vault/context-agent/scripts/session_summary.py +319 -0
  102. package/templates/vault/context-guardian/scripts/context_snapshot.py +229 -0
  103. package/templates/vault/docx/ooxml/scripts/pack.py +159 -0
  104. package/templates/vault/docx/ooxml/scripts/unpack.py +29 -0
  105. package/templates/vault/docx/ooxml/scripts/validate.py +69 -0
  106. package/templates/vault/docx/ooxml/scripts/validation/__init__.py +15 -0
  107. package/templates/vault/docx/ooxml/scripts/validation/base.py +951 -0
  108. package/templates/vault/docx/ooxml/scripts/validation/docx.py +274 -0
  109. package/templates/vault/docx/ooxml/scripts/validation/pptx.py +315 -0
  110. package/templates/vault/docx/ooxml/scripts/validation/redlining.py +279 -0
  111. package/templates/vault/docx/scripts/__init__.py +1 -0
  112. package/templates/vault/docx/scripts/document.py +1276 -0
  113. package/templates/vault/docx/scripts/templates/comments.xml +3 -0
  114. package/templates/vault/docx/scripts/templates/commentsExtended.xml +3 -0
  115. package/templates/vault/docx/scripts/templates/commentsExtensible.xml +3 -0
  116. package/templates/vault/docx/scripts/templates/commentsIds.xml +3 -0
  117. package/templates/vault/docx/scripts/templates/people.xml +3 -0
  118. package/templates/vault/docx/scripts/utilities.py +374 -0
  119. package/templates/vault/docx-official/ooxml/scripts/pack.py +159 -0
  120. package/templates/vault/docx-official/ooxml/scripts/unpack.py +29 -0
  121. package/templates/vault/docx-official/ooxml/scripts/validate.py +69 -0
  122. package/templates/vault/docx-official/ooxml/scripts/validation/__init__.py +15 -0
  123. package/templates/vault/docx-official/ooxml/scripts/validation/base.py +951 -0
  124. package/templates/vault/docx-official/ooxml/scripts/validation/docx.py +274 -0
  125. package/templates/vault/docx-official/ooxml/scripts/validation/pptx.py +315 -0
  126. package/templates/vault/docx-official/ooxml/scripts/validation/redlining.py +279 -0
  127. package/templates/vault/docx-official/scripts/__init__.py +1 -0
  128. package/templates/vault/docx-official/scripts/document.py +1276 -0
  129. package/templates/vault/docx-official/scripts/templates/comments.xml +3 -0
  130. package/templates/vault/docx-official/scripts/templates/commentsExtended.xml +3 -0
  131. package/templates/vault/docx-official/scripts/templates/commentsExtensible.xml +3 -0
  132. package/templates/vault/docx-official/scripts/templates/commentsIds.xml +3 -0
  133. package/templates/vault/docx-official/scripts/templates/people.xml +3 -0
  134. package/templates/vault/docx-official/scripts/utilities.py +374 -0
  135. package/templates/vault/geo-fundamentals/scripts/geo_checker.py +289 -0
  136. package/templates/vault/helm-chart-scaffolding/scripts/validate-chart.sh +244 -0
  137. package/templates/vault/i18n-localization/scripts/i18n_checker.py +241 -0
  138. package/templates/vault/instagram/scripts/account_setup.py +233 -0
  139. package/templates/vault/instagram/scripts/analyze.py +221 -0
  140. package/templates/vault/instagram/scripts/api_client.py +444 -0
  141. package/templates/vault/instagram/scripts/auth.py +411 -0
  142. package/templates/vault/instagram/scripts/comments.py +160 -0
  143. package/templates/vault/instagram/scripts/config.py +111 -0
  144. package/templates/vault/instagram/scripts/db.py +467 -0
  145. package/templates/vault/instagram/scripts/export.py +138 -0
  146. package/templates/vault/instagram/scripts/governance.py +233 -0
  147. package/templates/vault/instagram/scripts/hashtags.py +114 -0
  148. package/templates/vault/instagram/scripts/insights.py +170 -0
  149. package/templates/vault/instagram/scripts/media.py +65 -0
  150. package/templates/vault/instagram/scripts/messages.py +103 -0
  151. package/templates/vault/instagram/scripts/profile.py +58 -0
  152. package/templates/vault/instagram/scripts/publish.py +449 -0
  153. package/templates/vault/instagram/scripts/requirements.txt +5 -0
  154. package/templates/vault/instagram/scripts/run_all.py +189 -0
  155. package/templates/vault/instagram/scripts/schedule.py +189 -0
  156. package/templates/vault/instagram/scripts/serve_api.py +234 -0
  157. package/templates/vault/instagram/scripts/templates.py +155 -0
  158. package/templates/vault/junta-leiloeiros/scripts/db.py +216 -0
  159. package/templates/vault/junta-leiloeiros/scripts/export.py +137 -0
  160. package/templates/vault/junta-leiloeiros/scripts/requirements.txt +15 -0
  161. package/templates/vault/junta-leiloeiros/scripts/run_all.py +190 -0
  162. package/templates/vault/junta-leiloeiros/scripts/scraper/__init__.py +4 -0
  163. package/templates/vault/junta-leiloeiros/scripts/scraper/base_scraper.py +209 -0
  164. package/templates/vault/junta-leiloeiros/scripts/scraper/generic_scraper.py +110 -0
  165. package/templates/vault/junta-leiloeiros/scripts/scraper/jucap.py +110 -0
  166. package/templates/vault/junta-leiloeiros/scripts/scraper/juceac.py +72 -0
  167. package/templates/vault/junta-leiloeiros/scripts/scraper/juceal.py +72 -0
  168. package/templates/vault/junta-leiloeiros/scripts/scraper/juceb.py +68 -0
  169. package/templates/vault/junta-leiloeiros/scripts/scraper/jucec.py +63 -0
  170. package/templates/vault/junta-leiloeiros/scripts/scraper/jucema.py +211 -0
  171. package/templates/vault/junta-leiloeiros/scripts/scraper/jucemg.py +218 -0
  172. package/templates/vault/junta-leiloeiros/scripts/scraper/jucep.py +70 -0
  173. package/templates/vault/junta-leiloeiros/scripts/scraper/jucepa.py +74 -0
  174. package/templates/vault/junta-leiloeiros/scripts/scraper/jucepar.py +80 -0
  175. package/templates/vault/junta-leiloeiros/scripts/scraper/jucepe.py +78 -0
  176. package/templates/vault/junta-leiloeiros/scripts/scraper/jucepi.py +69 -0
  177. package/templates/vault/junta-leiloeiros/scripts/scraper/jucer.py +256 -0
  178. package/templates/vault/junta-leiloeiros/scripts/scraper/jucerja.py +170 -0
  179. package/templates/vault/junta-leiloeiros/scripts/scraper/jucern.py +71 -0
  180. package/templates/vault/junta-leiloeiros/scripts/scraper/jucesc.py +89 -0
  181. package/templates/vault/junta-leiloeiros/scripts/scraper/jucesp.py +233 -0
  182. package/templates/vault/junta-leiloeiros/scripts/scraper/jucetins.py +134 -0
  183. package/templates/vault/junta-leiloeiros/scripts/scraper/jucis_df.py +63 -0
  184. package/templates/vault/junta-leiloeiros/scripts/scraper/jucisrs.py +299 -0
  185. package/templates/vault/junta-leiloeiros/scripts/scraper/states.py +99 -0
  186. package/templates/vault/junta-leiloeiros/scripts/serve_api.py +164 -0
  187. package/templates/vault/junta-leiloeiros/scripts/web_scraper_fallback.py +233 -0
  188. package/templates/vault/last30days/scripts/last30days.py +521 -0
  189. package/templates/vault/last30days/scripts/lib/__init__.py +1 -0
  190. package/templates/vault/last30days/scripts/lib/cache.py +152 -0
  191. package/templates/vault/last30days/scripts/lib/dates.py +124 -0
  192. package/templates/vault/last30days/scripts/lib/dedupe.py +120 -0
  193. package/templates/vault/last30days/scripts/lib/env.py +149 -0
  194. package/templates/vault/last30days/scripts/lib/http.py +152 -0
  195. package/templates/vault/last30days/scripts/lib/models.py +175 -0
  196. package/templates/vault/last30days/scripts/lib/normalize.py +160 -0
  197. package/templates/vault/last30days/scripts/lib/openai_reddit.py +230 -0
  198. package/templates/vault/last30days/scripts/lib/reddit_enrich.py +232 -0
  199. package/templates/vault/last30days/scripts/lib/render.py +383 -0
  200. package/templates/vault/last30days/scripts/lib/schema.py +336 -0
  201. package/templates/vault/last30days/scripts/lib/score.py +311 -0
  202. package/templates/vault/last30days/scripts/lib/ui.py +324 -0
  203. package/templates/vault/last30days/scripts/lib/websearch.py +401 -0
  204. package/templates/vault/last30days/scripts/lib/xai_x.py +217 -0
  205. package/templates/vault/leiloeiro-avaliacao/scripts/governance.py +106 -0
  206. package/templates/vault/leiloeiro-avaliacao/scripts/requirements.txt +1 -0
  207. package/templates/vault/leiloeiro-edital/scripts/governance.py +106 -0
  208. package/templates/vault/leiloeiro-edital/scripts/requirements.txt +1 -0
  209. package/templates/vault/leiloeiro-ia/scripts/governance.py +106 -0
  210. package/templates/vault/leiloeiro-ia/scripts/requirements.txt +1 -0
  211. package/templates/vault/leiloeiro-juridico/scripts/governance.py +106 -0
  212. package/templates/vault/leiloeiro-juridico/scripts/requirements.txt +1 -0
  213. package/templates/vault/leiloeiro-mercado/scripts/governance.py +106 -0
  214. package/templates/vault/leiloeiro-mercado/scripts/requirements.txt +1 -0
  215. package/templates/vault/leiloeiro-risco/scripts/governance.py +106 -0
  216. package/templates/vault/leiloeiro-risco/scripts/requirements.txt +1 -0
  217. package/templates/vault/loki-mode/examples/todo-app-generated/backend/src/db/database.ts +24 -0
  218. package/templates/vault/loki-mode/examples/todo-app-generated/backend/src/db/db.ts +35 -0
  219. package/templates/vault/loki-mode/examples/todo-app-generated/backend/src/db/index.ts +2 -0
  220. package/templates/vault/loki-mode/examples/todo-app-generated/backend/src/db/migrations.ts +31 -0
  221. package/templates/vault/loki-mode/examples/todo-app-generated/backend/src/db/schema.sql +8 -0
  222. package/templates/vault/loki-mode/examples/todo-app-generated/backend/src/index.ts +44 -0
  223. package/templates/vault/loki-mode/examples/todo-app-generated/backend/src/routes/todos.ts +155 -0
  224. package/templates/vault/loki-mode/examples/todo-app-generated/backend/src/types/index.ts +35 -0
  225. package/templates/vault/loki-mode/examples/todo-app-generated/frontend/src/App.css +384 -0
  226. package/templates/vault/loki-mode/examples/todo-app-generated/frontend/src/App.tsx +81 -0
  227. package/templates/vault/loki-mode/examples/todo-app-generated/frontend/src/api/todos.ts +57 -0
  228. package/templates/vault/loki-mode/examples/todo-app-generated/frontend/src/components/ConfirmDialog.tsx +26 -0
  229. package/templates/vault/loki-mode/examples/todo-app-generated/frontend/src/components/EmptyState.tsx +8 -0
  230. package/templates/vault/loki-mode/examples/todo-app-generated/frontend/src/components/TodoForm.tsx +43 -0
  231. package/templates/vault/loki-mode/examples/todo-app-generated/frontend/src/components/TodoItem.tsx +36 -0
  232. package/templates/vault/loki-mode/examples/todo-app-generated/frontend/src/components/TodoList.tsx +27 -0
  233. package/templates/vault/loki-mode/examples/todo-app-generated/frontend/src/hooks/useTodos.ts +81 -0
  234. package/templates/vault/loki-mode/examples/todo-app-generated/frontend/src/index.css +48 -0
  235. package/templates/vault/loki-mode/examples/todo-app-generated/frontend/src/main.tsx +10 -0
  236. package/templates/vault/loki-mode/examples/todo-app-generated/frontend/src/vite-env.d.ts +1 -0
  237. package/templates/vault/loki-mode/scripts/export-to-vibe-kanban.sh +178 -0
  238. package/templates/vault/loki-mode/scripts/loki-wrapper.sh +281 -0
  239. package/templates/vault/loki-mode/scripts/take-screenshots.js +55 -0
  240. package/templates/vault/matematico-tao/scripts/complexity_analyzer.py +544 -0
  241. package/templates/vault/matematico-tao/scripts/dependency_graph.py +538 -0
  242. package/templates/vault/mcp-builder/scripts/connections.py +151 -0
  243. package/templates/vault/mcp-builder/scripts/evaluation.py +373 -0
  244. package/templates/vault/mcp-builder/scripts/example_evaluation.xml +22 -0
  245. package/templates/vault/mcp-builder/scripts/requirements.txt +2 -0
  246. package/templates/vault/mobile-design/scripts/mobile_audit.py +670 -0
  247. package/templates/vault/notebooklm/scripts/__init__.py +81 -0
  248. package/templates/vault/notebooklm/scripts/ask_question.py +256 -0
  249. package/templates/vault/notebooklm/scripts/auth_manager.py +358 -0
  250. package/templates/vault/notebooklm/scripts/browser_session.py +255 -0
  251. package/templates/vault/notebooklm/scripts/browser_utils.py +107 -0
  252. package/templates/vault/notebooklm/scripts/cleanup_manager.py +302 -0
  253. package/templates/vault/notebooklm/scripts/config.py +44 -0
  254. package/templates/vault/notebooklm/scripts/notebook_manager.py +410 -0
  255. package/templates/vault/notebooklm/scripts/run.py +102 -0
  256. package/templates/vault/notebooklm/scripts/setup_environment.py +204 -0
  257. package/templates/vault/pdf/scripts/check_bounding_boxes.py +70 -0
  258. package/templates/vault/pdf/scripts/check_bounding_boxes_test.py +226 -0
  259. package/templates/vault/pdf/scripts/check_fillable_fields.py +12 -0
  260. package/templates/vault/pdf/scripts/convert_pdf_to_images.py +35 -0
  261. package/templates/vault/pdf/scripts/create_validation_image.py +41 -0
  262. package/templates/vault/pdf/scripts/extract_form_field_info.py +152 -0
  263. package/templates/vault/pdf/scripts/fill_fillable_fields.py +114 -0
  264. package/templates/vault/pdf/scripts/fill_pdf_form_with_annotations.py +108 -0
  265. package/templates/vault/pdf-official/scripts/check_bounding_boxes.py +70 -0
  266. package/templates/vault/pdf-official/scripts/check_bounding_boxes_test.py +226 -0
  267. package/templates/vault/pdf-official/scripts/check_fillable_fields.py +12 -0
  268. package/templates/vault/pdf-official/scripts/convert_pdf_to_images.py +35 -0
  269. package/templates/vault/pdf-official/scripts/create_validation_image.py +41 -0
  270. package/templates/vault/pdf-official/scripts/extract_form_field_info.py +152 -0
  271. package/templates/vault/pdf-official/scripts/fill_fillable_fields.py +114 -0
  272. package/templates/vault/pdf-official/scripts/fill_pdf_form_with_annotations.py +108 -0
  273. package/templates/vault/planning-with-files/scripts/check-complete.sh +44 -0
  274. package/templates/vault/planning-with-files/scripts/init-session.sh +120 -0
  275. package/templates/vault/pptx/ooxml/scripts/pack.py +159 -0
  276. package/templates/vault/pptx/ooxml/scripts/unpack.py +29 -0
  277. package/templates/vault/pptx/ooxml/scripts/validate.py +69 -0
  278. package/templates/vault/pptx/ooxml/scripts/validation/__init__.py +15 -0
  279. package/templates/vault/pptx/ooxml/scripts/validation/base.py +951 -0
  280. package/templates/vault/pptx/ooxml/scripts/validation/docx.py +274 -0
  281. package/templates/vault/pptx/ooxml/scripts/validation/pptx.py +315 -0
  282. package/templates/vault/pptx/ooxml/scripts/validation/redlining.py +279 -0
  283. package/templates/vault/pptx/scripts/html2pptx.js +979 -0
  284. package/templates/vault/pptx/scripts/inventory.py +1020 -0
  285. package/templates/vault/pptx/scripts/rearrange.py +231 -0
  286. package/templates/vault/pptx/scripts/replace.py +385 -0
  287. package/templates/vault/pptx/scripts/thumbnail.py +450 -0
  288. package/templates/vault/pptx-official/ooxml/scripts/pack.py +159 -0
  289. package/templates/vault/pptx-official/ooxml/scripts/unpack.py +29 -0
  290. package/templates/vault/pptx-official/ooxml/scripts/validate.py +69 -0
  291. package/templates/vault/pptx-official/ooxml/scripts/validation/__init__.py +15 -0
  292. package/templates/vault/pptx-official/ooxml/scripts/validation/base.py +951 -0
  293. package/templates/vault/pptx-official/ooxml/scripts/validation/docx.py +274 -0
  294. package/templates/vault/pptx-official/ooxml/scripts/validation/pptx.py +315 -0
  295. package/templates/vault/pptx-official/ooxml/scripts/validation/redlining.py +279 -0
  296. package/templates/vault/pptx-official/scripts/html2pptx.js +979 -0
  297. package/templates/vault/pptx-official/scripts/inventory.py +1020 -0
  298. package/templates/vault/pptx-official/scripts/rearrange.py +231 -0
  299. package/templates/vault/pptx-official/scripts/replace.py +385 -0
  300. package/templates/vault/pptx-official/scripts/thumbnail.py +450 -0
  301. package/templates/vault/product-manager-toolkit/scripts/customer_interview_analyzer.py +441 -0
  302. package/templates/vault/product-manager-toolkit/scripts/rice_prioritizer.py +296 -0
  303. package/templates/vault/prompt-engineering-patterns/scripts/optimize-prompt.py +279 -0
  304. package/templates/vault/scripts/.skill_cache.json +7538 -0
  305. package/templates/vault/scripts/skill_search.py +228 -0
  306. package/templates/vault/senior-architect/scripts/architecture_diagram_generator.py +114 -0
  307. package/templates/vault/senior-architect/scripts/dependency_analyzer.py +114 -0
  308. package/templates/vault/senior-architect/scripts/project_architect.py +114 -0
  309. package/templates/vault/shopify-development/scripts/requirements.txt +19 -0
  310. package/templates/vault/shopify-development/scripts/shopify_graphql.py +428 -0
  311. package/templates/vault/shopify-development/scripts/shopify_init.py +441 -0
  312. package/templates/vault/shopify-development/scripts/tests/test_shopify_init.py +379 -0
  313. package/templates/vault/skill-creator/scripts/init_skill.py +303 -0
  314. package/templates/vault/skill-creator/scripts/package_skill.py +110 -0
  315. package/templates/vault/skill-creator/scripts/quick_validate.py +95 -0
  316. package/templates/vault/skill-installer/scripts/detect_skills.py +318 -0
  317. package/templates/vault/skill-installer/scripts/install_skill.py +1708 -0
  318. package/templates/vault/skill-installer/scripts/package_skill.py +417 -0
  319. package/templates/vault/skill-installer/scripts/requirements.txt +1 -0
  320. package/templates/vault/skill-installer/scripts/validate_skill.py +430 -0
  321. package/templates/vault/skill-sentinel/scripts/analyzers/__init__.py +13 -0
  322. package/templates/vault/skill-sentinel/scripts/analyzers/code_quality.py +247 -0
  323. package/templates/vault/skill-sentinel/scripts/analyzers/cross_skill.py +134 -0
  324. package/templates/vault/skill-sentinel/scripts/analyzers/dependencies.py +121 -0
  325. package/templates/vault/skill-sentinel/scripts/analyzers/documentation.py +189 -0
  326. package/templates/vault/skill-sentinel/scripts/analyzers/governance_audit.py +153 -0
  327. package/templates/vault/skill-sentinel/scripts/analyzers/performance.py +164 -0
  328. package/templates/vault/skill-sentinel/scripts/analyzers/security.py +189 -0
  329. package/templates/vault/skill-sentinel/scripts/config.py +158 -0
  330. package/templates/vault/skill-sentinel/scripts/cost_optimizer.py +146 -0
  331. package/templates/vault/skill-sentinel/scripts/db.py +354 -0
  332. package/templates/vault/skill-sentinel/scripts/governance.py +58 -0
  333. package/templates/vault/skill-sentinel/scripts/recommender.py +228 -0
  334. package/templates/vault/skill-sentinel/scripts/report_generator.py +224 -0
  335. package/templates/vault/skill-sentinel/scripts/requirements.txt +1 -0
  336. package/templates/vault/skill-sentinel/scripts/run_audit.py +290 -0
  337. package/templates/vault/skill-sentinel/scripts/scanner.py +271 -0
  338. package/templates/vault/stability-ai/scripts/config.py +266 -0
  339. package/templates/vault/stability-ai/scripts/generate.py +687 -0
  340. package/templates/vault/stability-ai/scripts/requirements.txt +4 -0
  341. package/templates/vault/stability-ai/scripts/styles.py +174 -0
  342. package/templates/vault/telegram/assets/boilerplate/nodejs/src/bot-client.ts +86 -0
  343. package/templates/vault/telegram/assets/boilerplate/nodejs/src/handlers.ts +79 -0
  344. package/templates/vault/telegram/assets/boilerplate/nodejs/src/index.ts +32 -0
  345. package/templates/vault/telegram/scripts/send_message.py +143 -0
  346. package/templates/vault/telegram/scripts/setup_project.py +103 -0
  347. package/templates/vault/telegram/scripts/test_bot.py +144 -0
  348. package/templates/vault/typescript-expert/scripts/ts_diagnostic.py +203 -0
  349. package/templates/vault/ui-ux-pro-max/scripts/__pycache__/core.cpython-314.pyc +0 -0
  350. package/templates/vault/ui-ux-pro-max/scripts/__pycache__/design_system.cpython-314.pyc +0 -0
  351. package/templates/vault/ui-ux-pro-max/scripts/core.py +257 -0
  352. package/templates/vault/ui-ux-pro-max/scripts/design_system.py +487 -0
  353. package/templates/vault/ui-ux-pro-max/scripts/search.py +76 -0
  354. package/templates/vault/videodb/scripts/ws_listener.py +204 -0
  355. package/templates/vault/web-artifacts-builder/scripts/bundle-artifact.sh +54 -0
  356. package/templates/vault/web-artifacts-builder/scripts/init-artifact.sh +322 -0
  357. package/templates/vault/web-artifacts-builder/scripts/shadcn-components.tar.gz +0 -0
  358. package/templates/vault/webapp-testing/scripts/with_server.py +106 -0
  359. package/templates/vault/whatsapp-cloud-api/assets/boilerplate/nodejs/src/index.ts +125 -0
  360. package/templates/vault/whatsapp-cloud-api/assets/boilerplate/nodejs/src/template-manager.ts +67 -0
  361. package/templates/vault/whatsapp-cloud-api/assets/boilerplate/nodejs/src/types.ts +216 -0
  362. package/templates/vault/whatsapp-cloud-api/assets/boilerplate/nodejs/src/webhook-handler.ts +173 -0
  363. package/templates/vault/whatsapp-cloud-api/assets/boilerplate/nodejs/src/whatsapp-client.ts +193 -0
  364. package/templates/vault/whatsapp-cloud-api/scripts/send_test_message.py +137 -0
  365. package/templates/vault/whatsapp-cloud-api/scripts/setup_project.py +118 -0
  366. package/templates/vault/whatsapp-cloud-api/scripts/validate_config.py +190 -0
  367. package/templates/vault/youtube-summarizer/scripts/extract-transcript.py +65 -0
  368. package/templates/vault/youtube-summarizer/scripts/install-dependencies.sh +28 -0
@@ -0,0 +1,1104 @@
1
+ """007 Injection Scanner -- Specialized scanner for injection vulnerabilities.
2
+
3
+ Detects code injection, SQL injection, command injection, prompt injection,
4
+ XSS, SSRF, and path traversal patterns across Python, JavaScript/Node.js,
5
+ and shell codebases. Performs context-aware analysis to reduce false positives
6
+ by tracking user-input sources and adjusting severity for hardcoded values,
7
+ test files, comments, and docstrings.
8
+
9
+ Usage:
10
+ python injection_scanner.py --target /path/to/project
11
+ python injection_scanner.py --target /path/to/project --output json --verbose
12
+ python injection_scanner.py --target /path/to/project --include-low
13
+ """
14
+
15
+ import argparse
16
+ import json
17
+ import os
18
+ import re
19
+ import sys
20
+ import time
21
+ from pathlib import Path
22
+
23
+ # ---------------------------------------------------------------------------
24
+ # Import from the 007 config hub (parent directory)
25
+ # ---------------------------------------------------------------------------
26
+ sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
27
+
28
+ import config # noqa: E402
29
+
30
+ # ---------------------------------------------------------------------------
31
+ # Logger
32
+ # ---------------------------------------------------------------------------
33
+ logger = config.setup_logging("007-injection-scanner")
34
+
35
+ # ---------------------------------------------------------------------------
36
+ # Context markers: sources of user input
37
+ # ---------------------------------------------------------------------------
38
+ # If a line (or nearby lines) contain any of these tokens, variables on that
39
+ # line are treated as *tainted* (user-controlled). When a dangerous pattern
40
+ # uses only a hardcoded literal, severity is reduced.
41
+
42
+ _USER_INPUT_MARKERS_PY = re.compile(
43
+ r"""(?:request\.(?:args|form|json|data|files|values|headers|cookies|get_json)|"""
44
+ r"""request\.GET|request\.POST|request\.query_params|"""
45
+ r"""sys\.argv|input\s*\(|os\.environ|"""
46
+ r"""flask\.request|django\.http|"""
47
+ r"""click\.argument|click\.option|argparse|"""
48
+ r"""websocket\.recv|channel\.receive|"""
49
+ r"""getattr\s*\(\s*request)""",
50
+ re.IGNORECASE,
51
+ )
52
+
53
+ _USER_INPUT_MARKERS_JS = re.compile(
54
+ r"""(?:req\.(?:body|params|query|headers|cookies)|"""
55
+ r"""request\.(?:body|params|query|headers)|"""
56
+ r"""process\.argv|"""
57
+ r"""\.useParams|\.useSearchParams|"""
58
+ r"""window\.location|document\.location|"""
59
+ r"""location\.(?:search|hash|href)|"""
60
+ r"""URLSearchParams|"""
61
+ r"""event\.(?:target|data)|"""
62
+ r"""document\.(?:getElementById|querySelector)|\.value|"""
63
+ r"""localStorage|sessionStorage|"""
64
+ r"""socket\.on)""",
65
+ re.IGNORECASE,
66
+ )
67
+
68
+ _USER_INPUT_MARKERS = re.compile(
69
+ _USER_INPUT_MARKERS_PY.pattern + r"|" + _USER_INPUT_MARKERS_JS.pattern,
70
+ re.IGNORECASE,
71
+ )
72
+
73
+ # ---------------------------------------------------------------------------
74
+ # Comment / docstring detection
75
+ # ---------------------------------------------------------------------------
76
+
77
+ _COMMENT_LINE_RE = re.compile(
78
+ r"""^\s*(?:#|//|/\*|\*|;|rem\b|@rem\b)""", re.IGNORECASE
79
+ )
80
+
81
+ _TRIPLE_QUOTE_RE = re.compile(r'''^\s*(?:\"{3}|'{3})''')
82
+
83
+ _MARKDOWN_CODE_FENCE = re.compile(r"""^\s*```""")
84
+
85
+
86
+ def _is_comment_line(line: str) -> bool:
87
+ """Return True if the line is a single-line comment."""
88
+ return bool(_COMMENT_LINE_RE.match(line))
89
+
90
+
91
+ # ---------------------------------------------------------------------------
92
+ # Test file detection
93
+ # ---------------------------------------------------------------------------
94
+
95
+ _TEST_FILE_RE = re.compile(
96
+ r"""(?i)(?:^test_|_test\.py$|\.test\.[jt]sx?$|\.spec\.[jt]sx?$|"""
97
+ r"""__tests__|fixtures?[/\\]|test[/\\]|tests[/\\]|"""
98
+ r"""mocks?[/\\]|__mocks__[/\\])"""
99
+ )
100
+
101
+
102
+ def _is_test_file(filepath: Path) -> bool:
103
+ """Return True if *filepath* looks like a test or fixture file."""
104
+ return bool(_TEST_FILE_RE.search(filepath.name)) or bool(
105
+ _TEST_FILE_RE.search(str(filepath))
106
+ )
107
+
108
+
109
+ # ---------------------------------------------------------------------------
110
+ # Severity helpers
111
+ # ---------------------------------------------------------------------------
112
+
113
+ def _lower_severity(severity: str) -> str:
114
+ """Return the next-lower severity level."""
115
+ order = ["CRITICAL", "HIGH", "MEDIUM", "LOW", "INFO"]
116
+ idx = order.index(severity) if severity in order else 0
117
+ return order[min(idx + 1, len(order) - 1)]
118
+
119
+
120
+ def _has_user_input(line: str) -> bool:
121
+ """Return True if *line* references a known user-input source."""
122
+ return bool(_USER_INPUT_MARKERS.search(line))
123
+
124
+
125
+ def _has_variable_interpolation(line: str) -> bool:
126
+ """Return True if *line* contains f-string braces, .format(), or % formatting."""
127
+ # f-string-style braces (not escaped)
128
+ if re.search(r"""(?<!\{)\{[^{}\s][^{}]*\}(?!\})""", line):
129
+ return True
130
+ # .format() call
131
+ if ".format(" in line:
132
+ return True
133
+ # %-style formatting with a variable (%s, %d etc followed by %)
134
+ if re.search(r"""%[sdifr]""", line) and "%" in line:
135
+ return True
136
+ return False
137
+
138
+
139
+ def _only_hardcoded_string(line: str) -> bool:
140
+ """Heuristic: return True if the dangerous call appears to use only literals.
141
+
142
+ For example, ``eval("1+1")`` or ``os.system("clear")`` with no variables.
143
+ """
144
+ # If there is variable interpolation, not hardcoded
145
+ if _has_variable_interpolation(line):
146
+ return False
147
+ # If there's a user input marker, not hardcoded
148
+ if _has_user_input(line):
149
+ return False
150
+ # Check for variable references inside the call parens
151
+ # Look for identifiers that aren't string literals
152
+ paren = line.find("(")
153
+ if paren == -1:
154
+ return False
155
+ inside = line[paren:]
156
+ # If the argument is just a string literal, treat as hardcoded
157
+ if re.match(r"""\(\s*['\"]{1,3}[^'\"]*['\"]{1,3}\s*\)""", inside):
158
+ return True
159
+ return False
160
+
161
+
162
+ # =========================================================================
163
+ # INJECTION PATTERN DEFINITIONS
164
+ # =========================================================================
165
+ # Each entry: (pattern_name, compiled_regex, base_severity, injection_type,
166
+ # description)
167
+ # The scanner applies context analysis on top of base_severity.
168
+
169
+ _INJECTION_DEFS: list[tuple[str, str, str, str, str]] = [
170
+
171
+ # -----------------------------------------------------------------
172
+ # 1. CODE INJECTION (Python)
173
+ # -----------------------------------------------------------------
174
+ (
175
+ "py_eval_user_input",
176
+ r"""\beval\s*\([^)]*(?:\bvar\b|\bdata\b|\brequest\b|\binput\b|\bargv\b|\bparams?\b|"""
177
+ r"""\bquery\b|\bform\b|\buser\b|\bf['\"])""",
178
+ "CRITICAL",
179
+ "code_injection",
180
+ "eval() with potential user input",
181
+ ),
182
+ (
183
+ "py_eval_any",
184
+ r"""\beval\s*\(""",
185
+ "CRITICAL",
186
+ "code_injection",
187
+ "eval() usage -- verify input is not user-controlled",
188
+ ),
189
+ (
190
+ "py_exec_any",
191
+ r"""\bexec\s*\(""",
192
+ "CRITICAL",
193
+ "code_injection",
194
+ "exec() usage -- verify input is not user-controlled",
195
+ ),
196
+ (
197
+ "py_compile_external",
198
+ r"""\bcompile\s*\([^)]*(?:\bvar\b|\bdata\b|\brequest\b|\binput\b|\bargv\b|"""
199
+ r"""\bparams?\b|\bquery\b|\bform\b|\buser\b|\bf['\"])""",
200
+ "CRITICAL",
201
+ "code_injection",
202
+ "compile() with potential user input",
203
+ ),
204
+ (
205
+ "py_dunder_import_dynamic",
206
+ r"""\b__import__\s*\([^'\"][^)]*\)""",
207
+ "HIGH",
208
+ "code_injection",
209
+ "__import__() with dynamic name",
210
+ ),
211
+ (
212
+ "py_importlib_dynamic",
213
+ r"""\bimportlib\.import_module\s*\([^'\"][^)]*\)""",
214
+ "HIGH",
215
+ "code_injection",
216
+ "importlib.import_module() with dynamic name",
217
+ ),
218
+ # Node.js code injection
219
+ (
220
+ "js_eval_any",
221
+ r"""\beval\s*\(""",
222
+ "CRITICAL",
223
+ "code_injection",
224
+ "eval() in JavaScript -- verify input is not user-controlled",
225
+ ),
226
+ (
227
+ "js_function_constructor",
228
+ r"""\bnew\s+Function\s*\(""",
229
+ "CRITICAL",
230
+ "code_injection",
231
+ "Function() constructor -- equivalent to eval",
232
+ ),
233
+ (
234
+ "js_vm_run",
235
+ r"""\bvm\.run(?:InNewContext|InThisContext|InContext)?\s*\(""",
236
+ "HIGH",
237
+ "code_injection",
238
+ "vm.run*() -- verify input is not user-controlled",
239
+ ),
240
+ # Template injection
241
+ (
242
+ "template_injection_fstring",
243
+ r"""(?:render|template|jinja|mako|render_template_string)\s*\(.*\bf['\"]""",
244
+ "CRITICAL",
245
+ "code_injection",
246
+ "f-string in template rendering context (template injection)",
247
+ ),
248
+ (
249
+ "template_injection_format",
250
+ r"""(?:render|template|jinja|mako|render_template_string)\s*\(.*\.format\s*\(""",
251
+ "CRITICAL",
252
+ "code_injection",
253
+ ".format() in template rendering context (template injection)",
254
+ ),
255
+
256
+ # -----------------------------------------------------------------
257
+ # 2. COMMAND INJECTION
258
+ # -----------------------------------------------------------------
259
+ (
260
+ "subprocess_shell_true",
261
+ r"""\bsubprocess\.(?:call|run|Popen|check_output|check_call)\s*\("""
262
+ r"""[^)]*shell\s*=\s*True""",
263
+ "CRITICAL",
264
+ "command_injection",
265
+ "subprocess with shell=True -- command injection risk if input is variable",
266
+ ),
267
+ (
268
+ "os_system_var",
269
+ r"""\bos\.system\s*\(""",
270
+ "CRITICAL",
271
+ "command_injection",
272
+ "os.system() -- always uses a shell; prefer subprocess without shell=True",
273
+ ),
274
+ (
275
+ "os_popen_var",
276
+ r"""\bos\.popen\s*\(""",
277
+ "HIGH",
278
+ "command_injection",
279
+ "os.popen() -- shell command execution",
280
+ ),
281
+ (
282
+ "child_process_exec",
283
+ r"""\b(?:child_process\.exec|execSync|exec)\s*\(""",
284
+ "CRITICAL",
285
+ "command_injection",
286
+ "child_process.exec() in Node.js -- uses shell by default",
287
+ ),
288
+ (
289
+ "shell_backtick_var",
290
+ r"""`[^`]*\$\{?\w+\}?[^`]*`""",
291
+ "HIGH",
292
+ "command_injection",
293
+ "Backtick execution with variable interpolation",
294
+ ),
295
+
296
+ # -----------------------------------------------------------------
297
+ # 3. SQL INJECTION
298
+ # -----------------------------------------------------------------
299
+ (
300
+ "sql_fstring",
301
+ r"""(?i)\bf['\"](?:[^'\"]*?)(?:SELECT|INSERT|UPDATE|DELETE|DROP|ALTER|CREATE|"""
302
+ r"""TRUNCATE|UNION|EXEC|EXECUTE)\b""",
303
+ "CRITICAL",
304
+ "sql_injection",
305
+ "f-string in SQL query (SQL injection)",
306
+ ),
307
+ (
308
+ "sql_format_method",
309
+ r"""(?i)(?:['\"]\s*(?:SELECT|INSERT|UPDATE|DELETE|DROP|ALTER|CREATE|"""
310
+ r"""TRUNCATE|UNION|EXEC|EXECUTE)\b[^'\"]*['\"])\.format\s*\(""",
311
+ "CRITICAL",
312
+ "sql_injection",
313
+ ".format() in SQL query string (SQL injection)",
314
+ ),
315
+ (
316
+ "sql_concat",
317
+ r"""(?i)(?:SELECT|INSERT|UPDATE|DELETE|DROP|ALTER|CREATE)\b[^;]*?\+\s*(?!['\"]\s*\+)""",
318
+ "HIGH",
319
+ "sql_injection",
320
+ "String concatenation in SQL query",
321
+ ),
322
+ (
323
+ "sql_percent_format",
324
+ r"""(?i)(?:cursor\.execute|execute|executemany)\s*\(\s*['\"]"""
325
+ r"""[^'\"]*(?:SELECT|INSERT|UPDATE|DELETE|DROP)\b[^'\"]*%[sd]""",
326
+ "CRITICAL",
327
+ "sql_injection",
328
+ "%-format in cursor.execute() (SQL injection)",
329
+ ),
330
+ (
331
+ "sql_fstring_execute",
332
+ r"""(?i)(?:cursor\.execute|execute|executemany)\s*\(\s*f['\"]""",
333
+ "CRITICAL",
334
+ "sql_injection",
335
+ "f-string in execute() call (SQL injection)",
336
+ ),
337
+
338
+ # -----------------------------------------------------------------
339
+ # 4. PROMPT INJECTION
340
+ # -----------------------------------------------------------------
341
+ (
342
+ "prompt_injection_fstring",
343
+ r"""(?i)(?:prompt|system_prompt|user_prompt|message|messages)\s*=\s*f['\"]"""
344
+ r"""[^'\"]*\{(?:user|input|query|request|data|text|content|message)""",
345
+ "HIGH",
346
+ "prompt_injection",
347
+ "User input directly in LLM prompt via f-string",
348
+ ),
349
+ (
350
+ "prompt_injection_concat",
351
+ r"""(?i)(?:prompt|system_prompt|user_prompt|messages?)\s*(?:=|\+=)\s*"""
352
+ r"""[^=\n]*(?:user_input|user_message|request\.(?:body|data|form|json)|input\()""",
353
+ "HIGH",
354
+ "prompt_injection",
355
+ "User input concatenated into LLM prompt",
356
+ ),
357
+ (
358
+ "prompt_injection_openai",
359
+ r"""(?i)(?:openai|anthropic|llm|chat|completion).*\bf['\"][^'\"]*\{"""
360
+ r"""(?:user|input|query|request|data|prompt|text|content|message)""",
361
+ "HIGH",
362
+ "prompt_injection",
363
+ "User variable in f-string near LLM API call",
364
+ ),
365
+ (
366
+ "prompt_injection_format",
367
+ r"""(?i)(?:prompt|system_prompt|user_prompt)\s*=\s*['\"][^'\"]*['\"]"""
368
+ r"""\.format\s*\([^)]*(?:user|input|query|request|data)""",
369
+ "HIGH",
370
+ "prompt_injection",
371
+ ".format() with user input in prompt template",
372
+ ),
373
+ (
374
+ "prompt_no_sanitize_direct",
375
+ r"""(?i)(?:messages|prompt)\s*(?:\.\s*append|\[\s*\{).*(?:content|text)\s*"""
376
+ r"""[:=]\s*(?:user_input|user_message|request\.|input\()""",
377
+ "MEDIUM",
378
+ "prompt_injection",
379
+ "User input passed directly to LLM messages without sanitization",
380
+ ),
381
+
382
+ # -----------------------------------------------------------------
383
+ # 5. XSS (Cross-Site Scripting)
384
+ # -----------------------------------------------------------------
385
+ (
386
+ "xss_innerhtml",
387
+ r"""\.innerHTML\s*=\s*(?!['\"]\s*$)[^;]+""",
388
+ "HIGH",
389
+ "xss",
390
+ "innerHTML assignment with variable (XSS risk)",
391
+ ),
392
+ (
393
+ "xss_document_write",
394
+ r"""\bdocument\.write\s*\([^)]*(?:\+|\$\{|\bvar\b|\bdata\b)""",
395
+ "HIGH",
396
+ "xss",
397
+ "document.write() with variable content",
398
+ ),
399
+ (
400
+ "xss_document_write_any",
401
+ r"""\bdocument\.write(?:ln)?\s*\(""",
402
+ "MEDIUM",
403
+ "xss",
404
+ "document.write() usage -- verify no user content",
405
+ ),
406
+ (
407
+ "xss_dangerously_set",
408
+ r"""\bdangerouslySetInnerHTML\s*=\s*\{""",
409
+ "HIGH",
410
+ "xss",
411
+ "dangerouslySetInnerHTML in React (XSS risk)",
412
+ ),
413
+ (
414
+ "xss_template_literal_html",
415
+ r"""(?:innerHTML|outerHTML|insertAdjacentHTML)\s*(?:=|\()\s*`[^`]*\$\{""",
416
+ "HIGH",
417
+ "xss",
418
+ "Template literal with interpolation in HTML context",
419
+ ),
420
+ (
421
+ "xss_jquery_html",
422
+ r"""\$\s*\([^)]*\)\s*\.html\s*\([^)]*(?:\+|\$\{|\bvar\b|\bdata\b)""",
423
+ "HIGH",
424
+ "xss",
425
+ "jQuery .html() with variable content",
426
+ ),
427
+
428
+ # -----------------------------------------------------------------
429
+ # 6. SSRF (Server-Side Request Forgery)
430
+ # -----------------------------------------------------------------
431
+ (
432
+ "ssrf_requests",
433
+ r"""\brequests\.(?:get|post|put|patch|delete|head|options|request)\s*\("""
434
+ r"""[^)]*(?:\bvar\b|\bdata\b|\brequest\b|\bparams?\b|\bquery\b|"""
435
+ r"""\bform\b|\buser\b|\burl\b|\bf['\"])""",
436
+ "HIGH",
437
+ "ssrf",
438
+ "requests.get/post with potentially user-controlled URL",
439
+ ),
440
+ (
441
+ "ssrf_urllib",
442
+ r"""\b(?:urllib\.request\.urlopen|urllib\.request\.Request|"""
443
+ r"""urllib2\.urlopen|urlopen)\s*\([^)]*(?:\bvar\b|\bdata\b|\brequest\b|"""
444
+ r"""\bparams?\b|\burl\b|\buser\b|\bf['\"])""",
445
+ "HIGH",
446
+ "ssrf",
447
+ "urllib with potentially user-controlled URL",
448
+ ),
449
+ (
450
+ "ssrf_fetch",
451
+ r"""\bfetch\s*\([^)]*(?:\bvar\b|\bdata\b|\breq\b|\bparams?\b|"""
452
+ r"""\burl\b|\buser\b|\$\{)""",
453
+ "HIGH",
454
+ "ssrf",
455
+ "fetch() with potentially user-controlled URL",
456
+ ),
457
+ (
458
+ "ssrf_axios",
459
+ r"""\baxios\.(?:get|post|put|patch|delete|head|options|request)\s*\("""
460
+ r"""[^)]*(?:\bvar\b|\bdata\b|\breq\b|\bparams?\b|\burl\b|\buser\b|\$\{)""",
461
+ "HIGH",
462
+ "ssrf",
463
+ "axios with potentially user-controlled URL",
464
+ ),
465
+ (
466
+ "ssrf_no_allowlist",
467
+ r"""\brequests\.(?:get|post|put|patch|delete)\s*\(""",
468
+ "MEDIUM",
469
+ "ssrf",
470
+ "HTTP request without visible URL allowlist/blocklist validation",
471
+ ),
472
+
473
+ # -----------------------------------------------------------------
474
+ # 7. PATH TRAVERSAL
475
+ # -----------------------------------------------------------------
476
+ (
477
+ "path_traversal_open",
478
+ r"""\bopen\s*\([^)]*(?:\brequest\b|\bparams?\b|\bquery\b|\bform\b|"""
479
+ r"""\buser\b|\bargv\b|\binput\s*\()""",
480
+ "HIGH",
481
+ "path_traversal",
482
+ "open() with user-controlled path (path traversal risk)",
483
+ ),
484
+ (
485
+ "path_traversal_join",
486
+ r"""\bos\.path\.join\s*\([^)]*(?:\brequest\b|\bparams?\b|\bquery\b|"""
487
+ r"""\bform\b|\buser\b|\bargv\b|\binput\s*\()""",
488
+ "HIGH",
489
+ "path_traversal",
490
+ "os.path.join with user input (can bypass with absolute paths)",
491
+ ),
492
+ (
493
+ "path_traversal_pathlib",
494
+ r"""\bPath\s*\([^)]*(?:\brequest\b|\bparams?\b|\bquery\b|\bform\b|"""
495
+ r"""\buser\b|\bargv\b|\binput\s*\()""",
496
+ "MEDIUM",
497
+ "path_traversal",
498
+ "Path() with user input -- verify resolve() and containment check",
499
+ ),
500
+ (
501
+ "path_traversal_send_file",
502
+ r"""\bsend_file\s*\([^)]*(?:\brequest\b|\bparams?\b|\bquery\b|\bform\b|"""
503
+ r"""\buser\b)""",
504
+ "HIGH",
505
+ "path_traversal",
506
+ "send_file() with user-controlled path",
507
+ ),
508
+ (
509
+ "path_traversal_no_resolve",
510
+ r"""\bopen\s*\(\s*(?:os\.path\.join|Path)\s*\(""",
511
+ "MEDIUM",
512
+ "path_traversal",
513
+ "File open via path join without visible resolve()/realpath() check",
514
+ ),
515
+ ]
516
+
517
+ # Compile all patterns
518
+ INJECTION_PATTERNS: list[tuple[str, re.Pattern, str, str, str]] = []
519
+ for _name, _pat, _sev, _itype, _desc in _INJECTION_DEFS:
520
+ try:
521
+ INJECTION_PATTERNS.append((_name, re.compile(_pat), _sev, _itype, _desc))
522
+ except re.error as exc:
523
+ logger.warning("Failed to compile pattern %s: %s", _name, exc)
524
+
525
+
526
+ # =========================================================================
527
+ # File collection
528
+ # =========================================================================
529
+
530
+ def _should_scan_file(filepath: Path) -> bool:
531
+ """Decide if a file should be included for injection scanning."""
532
+ name = filepath.name.lower()
533
+ suffix = filepath.suffix.lower()
534
+
535
+ for ext in config.SCANNABLE_EXTENSIONS:
536
+ if name.endswith(ext):
537
+ return True
538
+ if suffix in config.SCANNABLE_EXTENSIONS:
539
+ return True
540
+
541
+ return False
542
+
543
+
544
+ def collect_files(target: Path) -> list[Path]:
545
+ """Walk *target* recursively and return files for injection scanning."""
546
+ files: list[Path] = []
547
+ max_files = config.LIMITS["max_files_per_scan"]
548
+
549
+ for root, dirs, filenames in os.walk(target):
550
+ dirs[:] = [d for d in dirs if d not in config.SKIP_DIRECTORIES]
551
+
552
+ for fname in filenames:
553
+ if len(files) >= max_files:
554
+ logger.warning(
555
+ "Reached max_files_per_scan limit (%d). Stopping.", max_files
556
+ )
557
+ return files
558
+
559
+ fpath = Path(root) / fname
560
+ if _should_scan_file(fpath):
561
+ files.append(fpath)
562
+
563
+ return files
564
+
565
+
566
+ # =========================================================================
567
+ # Core scanning logic
568
+ # =========================================================================
569
+
570
+ def _snippet(line: str, match_start: int, context: int = 80) -> str:
571
+ """Extract a short snippet around the match position."""
572
+ start = max(0, match_start - context // 4)
573
+ end = min(len(line), match_start + context)
574
+ raw = line[start:end].strip()
575
+ if len(raw) > context:
576
+ raw = raw[:context] + "..."
577
+ return raw
578
+
579
+
580
+ def _is_in_docstring(lines: list[str], line_idx: int) -> bool:
581
+ """Rough heuristic: check if line_idx falls inside a Python docstring.
582
+
583
+ Counts triple-quote occurrences above the current line. Odd count
584
+ means we are inside a docstring.
585
+ """
586
+ count = 0
587
+ for i in range(line_idx):
588
+ # Count triple quotes in each preceding line
589
+ content = lines[i]
590
+ count += len(re.findall(r'''(?:\"{3}|'{3})''', content))
591
+ return count % 2 == 1
592
+
593
+
594
+ def scan_file(filepath: Path, verbose: bool = False) -> list[dict]:
595
+ """Scan a single file for injection vulnerabilities.
596
+
597
+ Returns a list of finding dicts.
598
+ """
599
+ findings: list[dict] = []
600
+ max_findings = config.LIMITS["max_findings_per_file"]
601
+ file_str = str(filepath)
602
+ is_test = _is_test_file(filepath)
603
+
604
+ # --- File size check ---
605
+ try:
606
+ size = filepath.stat().st_size
607
+ except OSError:
608
+ return findings
609
+
610
+ if size > config.LIMITS["max_file_size_bytes"]:
611
+ if verbose:
612
+ logger.debug("Skipping oversized file: %s (%d bytes)", filepath, size)
613
+ return findings
614
+
615
+ # --- Read content ---
616
+ try:
617
+ text = filepath.read_text(encoding="utf-8", errors="replace")
618
+ except OSError as exc:
619
+ if verbose:
620
+ logger.debug("Cannot read %s: %s", filepath, exc)
621
+ return findings
622
+
623
+ lines = text.splitlines()
624
+ in_markdown_block = False
625
+
626
+ # Build a *nearby user-input context* -- for each line, check if the
627
+ # surrounding +/-5 lines mention user input sources. This helps detect
628
+ # indirect taint (variable assigned from request on line N, used on N+3).
629
+ _CONTEXT_WINDOW = 5
630
+ line_has_user_input = [False] * len(lines)
631
+ for idx, ln in enumerate(lines):
632
+ if _has_user_input(ln):
633
+ lo = max(0, idx - _CONTEXT_WINDOW)
634
+ hi = min(len(lines), idx + _CONTEXT_WINDOW + 1)
635
+ for j in range(lo, hi):
636
+ line_has_user_input[j] = True
637
+
638
+ # Track patterns already matched per line to avoid duplicates
639
+ # (more specific patterns override generic ones)
640
+ line_patterns: dict[int, set[str]] = {}
641
+
642
+ for line_idx, line in enumerate(lines):
643
+ if len(findings) >= max_findings:
644
+ break
645
+
646
+ line_num = line_idx + 1
647
+ stripped = line.strip()
648
+
649
+ if not stripped:
650
+ continue
651
+
652
+ # Markdown code fence tracking
653
+ if _MARKDOWN_CODE_FENCE.match(stripped):
654
+ in_markdown_block = not in_markdown_block
655
+ continue
656
+
657
+ # Skip comments
658
+ if _is_comment_line(stripped):
659
+ continue
660
+
661
+ # Skip if inside markdown code block
662
+ if in_markdown_block:
663
+ continue
664
+
665
+ # Skip if inside docstring (for Python files)
666
+ if filepath.suffix.lower() == ".py" and _is_in_docstring(lines, line_idx):
667
+ continue
668
+
669
+ for pat_name, regex, base_severity, injection_type, description in INJECTION_PATTERNS:
670
+ m = regex.search(line)
671
+ if not m:
672
+ continue
673
+
674
+ # --- De-duplication: skip generic if specific already matched ---
675
+ # e.g., if py_eval_user_input matched, skip py_eval_any on same line
676
+ if line_num not in line_patterns:
677
+ line_patterns[line_num] = set()
678
+
679
+ # Build a group key from injection_type + rough function name
680
+ group_key = injection_type + ":" + pat_name.rsplit("_", 1)[0]
681
+ if group_key in line_patterns.get(line_num, set()):
682
+ continue
683
+
684
+ # More specific: if a *_user_input variant matched, mark its group
685
+ if "user_input" in pat_name or "var" in pat_name:
686
+ generic_group = injection_type + ":" + pat_name.replace("_user_input", "").replace("_var", "").rsplit("_", 1)[0]
687
+ line_patterns[line_num].add(generic_group)
688
+
689
+ line_patterns[line_num].add(group_key)
690
+
691
+ # --- Context-aware severity adjustment ---
692
+ adjusted_severity = base_severity
693
+
694
+ # 1. If only hardcoded string, lower to INFO
695
+ if _only_hardcoded_string(line):
696
+ adjusted_severity = "INFO"
697
+
698
+ # 2. If no user input nearby, lower by one level (but not below MEDIUM
699
+ # for CRITICAL patterns, since the pattern itself is dangerous)
700
+ elif not line_has_user_input[line_idx] and not _has_user_input(line):
701
+ if not _has_variable_interpolation(line):
702
+ adjusted_severity = _lower_severity(base_severity)
703
+ # For the generic "any" patterns, lower further if no vars
704
+ if pat_name.endswith("_any"):
705
+ adjusted_severity = _lower_severity(adjusted_severity)
706
+
707
+ # 3. Test files: lower severity by one level
708
+ if is_test:
709
+ adjusted_severity = _lower_severity(adjusted_severity)
710
+
711
+ findings.append({
712
+ "type": "injection",
713
+ "injection_type": injection_type,
714
+ "pattern": pat_name,
715
+ "severity": adjusted_severity,
716
+ "file": file_str,
717
+ "line": line_num,
718
+ "snippet": _snippet(line, m.start()),
719
+ "description": description,
720
+ "has_user_input_nearby": line_has_user_input[line_idx],
721
+ })
722
+
723
+ return findings
724
+
725
+
726
+ # =========================================================================
727
+ # Aggregation and scoring
728
+ # =========================================================================
729
+
730
+ SCORE_DEDUCTIONS = {
731
+ "CRITICAL": 12,
732
+ "HIGH": 6,
733
+ "MEDIUM": 3,
734
+ "LOW": 1,
735
+ "INFO": 0,
736
+ }
737
+
738
+
739
+ def aggregate_by_severity(findings: list[dict]) -> dict[str, int]:
740
+ """Count findings per severity level."""
741
+ counts: dict[str, int] = {sev: 0 for sev in config.SEVERITY}
742
+ for f in findings:
743
+ sev = f.get("severity", "INFO")
744
+ if sev in counts:
745
+ counts[sev] += 1
746
+ return counts
747
+
748
+
749
+ def aggregate_by_injection_type(findings: list[dict]) -> dict[str, int]:
750
+ """Count findings per injection type."""
751
+ counts: dict[str, int] = {}
752
+ for f in findings:
753
+ itype = f.get("injection_type", "unknown")
754
+ counts[itype] = counts.get(itype, 0) + 1
755
+ return counts
756
+
757
+
758
+ def aggregate_by_pattern(findings: list[dict]) -> dict[str, int]:
759
+ """Count findings per pattern name."""
760
+ counts: dict[str, int] = {}
761
+ for f in findings:
762
+ pattern = f.get("pattern", "unknown")
763
+ counts[pattern] = counts.get(pattern, 0) + 1
764
+ return counts
765
+
766
+
767
+ def compute_score(findings: list[dict]) -> int:
768
+ """Compute injection security score starting at 100, deducting by severity."""
769
+ score = 100
770
+ for f in findings:
771
+ deduction = SCORE_DEDUCTIONS.get(f["severity"], 0)
772
+ score -= deduction
773
+ return max(0, score)
774
+
775
+
776
+ # =========================================================================
777
+ # Report formatters
778
+ # =========================================================================
779
+
780
+ _INJECTION_TYPE_LABELS = {
781
+ "code_injection": "Code Injection",
782
+ "command_injection": "Command Injection",
783
+ "sql_injection": "SQL Injection",
784
+ "prompt_injection": "Prompt Injection",
785
+ "xss": "Cross-Site Scripting (XSS)",
786
+ "ssrf": "Server-Side Request Forgery (SSRF)",
787
+ "path_traversal": "Path Traversal",
788
+ }
789
+
790
+
791
+ def format_text_report(
792
+ target: str,
793
+ total_files: int,
794
+ findings: list[dict],
795
+ severity_counts: dict[str, int],
796
+ type_counts: dict[str, int],
797
+ pattern_counts: dict[str, int],
798
+ score: int,
799
+ verdict: dict,
800
+ elapsed: float,
801
+ include_low: bool = False,
802
+ ) -> str:
803
+ """Build a human-readable text report grouped by injection type."""
804
+ lines: list[str] = []
805
+
806
+ lines.append("=" * 72)
807
+ lines.append(" 007 INJECTION SCANNER -- VULNERABILITY REPORT")
808
+ lines.append("=" * 72)
809
+ lines.append("")
810
+
811
+ # Metadata
812
+ lines.append(f" Target: {target}")
813
+ lines.append(f" Timestamp: {config.get_timestamp()}")
814
+ lines.append(f" Duration: {elapsed:.2f}s")
815
+ lines.append(f" Files scanned: {total_files}")
816
+ lines.append(f" Total findings: {len(findings)}")
817
+ lines.append("")
818
+
819
+ # Severity distribution
820
+ lines.append("-" * 72)
821
+ lines.append(" SEVERITY DISTRIBUTION")
822
+ lines.append("-" * 72)
823
+ for sev in ("CRITICAL", "HIGH", "MEDIUM", "LOW", "INFO"):
824
+ count = severity_counts.get(sev, 0)
825
+ bar = "#" * min(count, 40)
826
+ lines.append(f" {sev:<10} {count:>5} {bar}")
827
+ lines.append("")
828
+
829
+ # Injection type breakdown
830
+ if type_counts:
831
+ lines.append("-" * 72)
832
+ lines.append(" FINDINGS BY INJECTION TYPE")
833
+ lines.append("-" * 72)
834
+ sorted_types = sorted(type_counts.items(), key=lambda x: x[1], reverse=True)
835
+ for itype, count in sorted_types:
836
+ label = _INJECTION_TYPE_LABELS.get(itype, itype)
837
+ lines.append(f" {label:<40} {count:>5}")
838
+ lines.append("")
839
+
840
+ # Detailed findings grouped by injection type
841
+ min_severity = config.SEVERITY["LOW"] if include_low else config.SEVERITY["MEDIUM"]
842
+
843
+ displayed = [
844
+ f for f in findings
845
+ if config.SEVERITY.get(f.get("severity", "INFO"), 0) >= min_severity
846
+ ]
847
+
848
+ if displayed:
849
+ # Group by injection type
850
+ by_type: dict[str, list[dict]] = {}
851
+ for f in displayed:
852
+ itype = f.get("injection_type", "unknown")
853
+ by_type.setdefault(itype, []).append(f)
854
+
855
+ # Order: code_injection, command_injection, sql_injection, prompt_injection,
856
+ # xss, ssrf, path_traversal, then anything else
857
+ type_order = [
858
+ "code_injection", "command_injection", "sql_injection",
859
+ "prompt_injection", "xss", "ssrf", "path_traversal",
860
+ ]
861
+ # Add any types not in the predefined order
862
+ for t in by_type:
863
+ if t not in type_order:
864
+ type_order.append(t)
865
+
866
+ for itype in type_order:
867
+ itype_findings = by_type.get(itype, [])
868
+ if not itype_findings:
869
+ continue
870
+
871
+ label = _INJECTION_TYPE_LABELS.get(itype, itype)
872
+ lines.append("-" * 72)
873
+ lines.append(f" [{label.upper()}] ({len(itype_findings)} findings)")
874
+ lines.append("-" * 72)
875
+
876
+ # Sub-group by severity
877
+ for sev in ("CRITICAL", "HIGH", "MEDIUM", "LOW"):
878
+ sev_group = [f for f in itype_findings if f["severity"] == sev]
879
+ if not sev_group:
880
+ continue
881
+
882
+ for f in sorted(sev_group, key=lambda x: (x["file"], x.get("line", 0))):
883
+ taint_marker = " [TAINTED]" if f.get("has_user_input_nearby") else ""
884
+ lines.append(
885
+ f" [{sev}] {f['file']}:L{f.get('line', 0)}{taint_marker}"
886
+ )
887
+ lines.append(f" {f['description']}")
888
+ if f.get("snippet"):
889
+ lines.append(f" > {f['snippet']}")
890
+ lines.append("")
891
+ else:
892
+ lines.append(" No injection findings above the display threshold.")
893
+ lines.append("")
894
+
895
+ # Score and verdict
896
+ lines.append("=" * 72)
897
+ lines.append(f" INJECTION SECURITY SCORE: {score} / 100")
898
+ lines.append(f" VERDICT: {verdict['emoji']} {verdict['label']}")
899
+ lines.append(f" {verdict['description']}")
900
+ lines.append("=" * 72)
901
+ lines.append("")
902
+
903
+ return "\n".join(lines)
904
+
905
+
906
+ def build_json_report(
907
+ target: str,
908
+ total_files: int,
909
+ findings: list[dict],
910
+ severity_counts: dict[str, int],
911
+ type_counts: dict[str, int],
912
+ pattern_counts: dict[str, int],
913
+ score: int,
914
+ verdict: dict,
915
+ elapsed: float,
916
+ ) -> dict:
917
+ """Build a structured JSON-serializable report dict."""
918
+ return {
919
+ "scan": "injection_scanner",
920
+ "target": target,
921
+ "timestamp": config.get_timestamp(),
922
+ "duration_seconds": round(elapsed, 3),
923
+ "total_files_scanned": total_files,
924
+ "total_findings": len(findings),
925
+ "severity_counts": severity_counts,
926
+ "injection_type_counts": type_counts,
927
+ "pattern_counts": pattern_counts,
928
+ "score": score,
929
+ "verdict": {
930
+ "label": verdict["label"],
931
+ "description": verdict["description"],
932
+ "emoji": verdict["emoji"],
933
+ },
934
+ "findings": findings,
935
+ }
936
+
937
+
938
+ # =========================================================================
939
+ # Main entry point
940
+ # =========================================================================
941
+
942
+ def run_scan(
943
+ target_path: str,
944
+ output_format: str = "text",
945
+ verbose: bool = False,
946
+ include_low: bool = False,
947
+ ) -> dict:
948
+ """Execute the injection vulnerability scan and return the report dict.
949
+
950
+ Args:
951
+ target_path: Path to the directory to scan.
952
+ output_format: 'text' or 'json'.
953
+ verbose: Enable debug-level logging.
954
+ include_low: Include LOW severity findings in text output.
955
+
956
+ Returns:
957
+ JSON-compatible report dict.
958
+ """
959
+ if verbose:
960
+ logger.setLevel("DEBUG")
961
+
962
+ config.ensure_directories()
963
+
964
+ target = Path(target_path).resolve()
965
+ if not target.exists():
966
+ logger.error("Target path does not exist: %s", target)
967
+ sys.exit(1)
968
+ if not target.is_dir():
969
+ logger.error("Target is not a directory: %s", target)
970
+ sys.exit(1)
971
+
972
+ logger.info("Starting injection vulnerability scan of %s", target)
973
+ start_time = time.time()
974
+
975
+ # Collect files
976
+ files = collect_files(target)
977
+ total_files = len(files)
978
+ logger.info("Collected %d files for injection scanning", total_files)
979
+
980
+ # Scan each file
981
+ all_findings: list[dict] = []
982
+ max_report = config.LIMITS["max_report_findings"]
983
+
984
+ for fpath in files:
985
+ if len(all_findings) >= max_report:
986
+ logger.warning(
987
+ "Reached max_report_findings limit (%d). Truncating.", max_report
988
+ )
989
+ break
990
+
991
+ file_findings = scan_file(fpath, verbose=verbose)
992
+ remaining = max_report - len(all_findings)
993
+ all_findings.extend(file_findings[:remaining])
994
+
995
+ elapsed = time.time() - start_time
996
+ logger.info(
997
+ "Injection scan complete: %d files, %d findings in %.2fs",
998
+ total_files, len(all_findings), elapsed,
999
+ )
1000
+
1001
+ # Aggregation
1002
+ severity_counts = aggregate_by_severity(all_findings)
1003
+ type_counts = aggregate_by_injection_type(all_findings)
1004
+ pattern_counts = aggregate_by_pattern(all_findings)
1005
+ score = compute_score(all_findings)
1006
+ verdict = config.get_verdict(score)
1007
+
1008
+ # Audit log
1009
+ config.log_audit_event(
1010
+ action="injection_scan",
1011
+ target=str(target),
1012
+ result=f"score={score}, findings={len(all_findings)}, verdict={verdict['label']}",
1013
+ details={
1014
+ "total_files": total_files,
1015
+ "severity_counts": severity_counts,
1016
+ "injection_type_counts": type_counts,
1017
+ "pattern_counts": pattern_counts,
1018
+ "duration_seconds": round(elapsed, 3),
1019
+ },
1020
+ )
1021
+
1022
+ # Build report
1023
+ report = build_json_report(
1024
+ target=str(target),
1025
+ total_files=total_files,
1026
+ findings=all_findings,
1027
+ severity_counts=severity_counts,
1028
+ type_counts=type_counts,
1029
+ pattern_counts=pattern_counts,
1030
+ score=score,
1031
+ verdict=verdict,
1032
+ elapsed=elapsed,
1033
+ )
1034
+
1035
+ # Output
1036
+ if output_format == "json":
1037
+ print(json.dumps(report, indent=2, ensure_ascii=False))
1038
+ else:
1039
+ print(format_text_report(
1040
+ target=str(target),
1041
+ total_files=total_files,
1042
+ findings=all_findings,
1043
+ severity_counts=severity_counts,
1044
+ type_counts=type_counts,
1045
+ pattern_counts=pattern_counts,
1046
+ score=score,
1047
+ verdict=verdict,
1048
+ elapsed=elapsed,
1049
+ include_low=include_low,
1050
+ ))
1051
+
1052
+ return report
1053
+
1054
+
1055
+ # =========================================================================
1056
+ # CLI
1057
+ # =========================================================================
1058
+
1059
+ if __name__ == "__main__":
1060
+ parser = argparse.ArgumentParser(
1061
+ description=(
1062
+ "007 Injection Scanner -- Specialized scanner for injection "
1063
+ "vulnerabilities (code injection, SQL injection, command injection, "
1064
+ "prompt injection, XSS, SSRF, path traversal)."
1065
+ ),
1066
+ epilog=(
1067
+ "Examples:\n"
1068
+ " python injection_scanner.py --target ./my-project\n"
1069
+ " python injection_scanner.py --target ./my-project --output json\n"
1070
+ " python injection_scanner.py --target ./my-project --verbose --include-low"
1071
+ ),
1072
+ formatter_class=argparse.RawDescriptionHelpFormatter,
1073
+ )
1074
+ parser.add_argument(
1075
+ "--target",
1076
+ required=True,
1077
+ help="Path to the directory to scan (required).",
1078
+ )
1079
+ parser.add_argument(
1080
+ "--output",
1081
+ choices=["text", "json"],
1082
+ default="text",
1083
+ help="Output format: 'text' (default) or 'json'.",
1084
+ )
1085
+ parser.add_argument(
1086
+ "--verbose",
1087
+ action="store_true",
1088
+ default=False,
1089
+ help="Enable verbose/debug logging.",
1090
+ )
1091
+ parser.add_argument(
1092
+ "--include-low",
1093
+ action="store_true",
1094
+ default=False,
1095
+ help="Include LOW severity findings in text output (hidden by default).",
1096
+ )
1097
+
1098
+ args = parser.parse_args()
1099
+ run_scan(
1100
+ target_path=args.target,
1101
+ output_format=args.output,
1102
+ verbose=args.verbose,
1103
+ include_low=args.include_low,
1104
+ )