@jaguilar87/gaia-ops 4.4.0 → 4.7.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 (371) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +12 -3
  3. package/ARCHITECTURE.md +9 -8
  4. package/CHANGELOG.md +34 -0
  5. package/README.md +43 -11
  6. package/agents/terraform-architect.md +1 -1
  7. package/bin/README.md +2 -2
  8. package/bin/gaia-doctor.js +18 -5
  9. package/bin/gaia-history.js +0 -1
  10. package/bin/gaia-metrics.js +2 -2
  11. package/bin/gaia-scan.py +23 -1
  12. package/bin/gaia-update.js +346 -54
  13. package/bin/pre-publish-validate.js +33 -10
  14. package/commands/gaia.md +37 -0
  15. package/config/README.md +3 -9
  16. package/config/context-contracts.json +47 -15
  17. package/config/surface-routing.json +9 -1
  18. package/dist/gaia-ops/.claude-plugin/plugin.json +22 -0
  19. package/dist/gaia-ops/agents/cloud-troubleshooter.md +73 -0
  20. package/dist/gaia-ops/agents/devops-developer.md +57 -0
  21. package/dist/gaia-ops/agents/gaia-system.md +58 -0
  22. package/dist/gaia-ops/agents/gitops-operator.md +60 -0
  23. package/dist/gaia-ops/agents/speckit-planner.md +71 -0
  24. package/dist/gaia-ops/agents/terraform-architect.md +60 -0
  25. package/dist/gaia-ops/commands/gaia.md +37 -0
  26. package/dist/gaia-ops/config/README.md +58 -0
  27. package/dist/gaia-ops/config/cloud/aws.json +140 -0
  28. package/dist/gaia-ops/config/cloud/gcp.json +145 -0
  29. package/dist/gaia-ops/config/context-contracts.json +131 -0
  30. package/dist/gaia-ops/config/git_standards.json +72 -0
  31. package/dist/gaia-ops/config/surface-routing.json +197 -0
  32. package/dist/gaia-ops/config/universal-rules.json +10 -0
  33. package/dist/gaia-ops/hooks/adapters/__init__.py +52 -0
  34. package/dist/gaia-ops/hooks/adapters/base.py +219 -0
  35. package/dist/gaia-ops/hooks/adapters/channel.py +17 -0
  36. package/dist/gaia-ops/hooks/adapters/claude_code.py +1477 -0
  37. package/dist/gaia-ops/hooks/adapters/types.py +194 -0
  38. package/dist/gaia-ops/hooks/adapters/utils.py +25 -0
  39. package/dist/gaia-ops/hooks/hooks.json +126 -0
  40. package/dist/gaia-ops/hooks/modules/__init__.py +15 -0
  41. package/dist/gaia-ops/hooks/modules/agents/__init__.py +29 -0
  42. package/dist/gaia-ops/hooks/modules/agents/contract_validator.py +647 -0
  43. package/dist/gaia-ops/hooks/modules/agents/response_contract.py +496 -0
  44. package/dist/gaia-ops/hooks/modules/agents/skill_injection_verifier.py +124 -0
  45. package/dist/gaia-ops/hooks/modules/agents/task_info_builder.py +74 -0
  46. package/dist/gaia-ops/hooks/modules/agents/transcript_analyzer.py +458 -0
  47. package/dist/gaia-ops/hooks/modules/agents/transcript_reader.py +152 -0
  48. package/dist/gaia-ops/hooks/modules/audit/__init__.py +28 -0
  49. package/dist/gaia-ops/hooks/modules/audit/event_detector.py +168 -0
  50. package/dist/gaia-ops/hooks/modules/audit/logger.py +131 -0
  51. package/dist/gaia-ops/hooks/modules/audit/metrics.py +134 -0
  52. package/dist/gaia-ops/hooks/modules/audit/workflow_auditor.py +576 -0
  53. package/dist/gaia-ops/hooks/modules/audit/workflow_recorder.py +296 -0
  54. package/dist/gaia-ops/hooks/modules/context/__init__.py +11 -0
  55. package/dist/gaia-ops/hooks/modules/context/anchor_tracker.py +317 -0
  56. package/dist/gaia-ops/hooks/modules/context/compact_context_builder.py +215 -0
  57. package/dist/gaia-ops/hooks/modules/context/context_cache.py +129 -0
  58. package/dist/gaia-ops/hooks/modules/context/context_freshness.py +145 -0
  59. package/dist/gaia-ops/hooks/modules/context/context_injector.py +427 -0
  60. package/dist/gaia-ops/hooks/modules/context/context_writer.py +518 -0
  61. package/dist/gaia-ops/hooks/modules/context/contracts_loader.py +161 -0
  62. package/dist/gaia-ops/hooks/modules/core/__init__.py +40 -0
  63. package/dist/gaia-ops/hooks/modules/core/hook_entry.py +78 -0
  64. package/dist/gaia-ops/hooks/modules/core/paths.py +160 -0
  65. package/dist/gaia-ops/hooks/modules/core/plugin_mode.py +149 -0
  66. package/dist/gaia-ops/hooks/modules/core/plugin_setup.py +558 -0
  67. package/dist/gaia-ops/hooks/modules/core/state.py +179 -0
  68. package/dist/gaia-ops/hooks/modules/core/stdin.py +24 -0
  69. package/dist/gaia-ops/hooks/modules/events/__init__.py +1 -0
  70. package/dist/gaia-ops/hooks/modules/events/event_writer.py +210 -0
  71. package/dist/gaia-ops/hooks/modules/identity/__init__.py +0 -0
  72. package/dist/gaia-ops/hooks/modules/identity/identity_provider.py +21 -0
  73. package/dist/gaia-ops/hooks/modules/identity/ops_identity.py +34 -0
  74. package/dist/gaia-ops/hooks/modules/identity/security_identity.py +10 -0
  75. package/dist/gaia-ops/hooks/modules/memory/__init__.py +8 -0
  76. package/dist/gaia-ops/hooks/modules/memory/episode_writer.py +227 -0
  77. package/dist/gaia-ops/hooks/modules/orchestrator/__init__.py +1 -0
  78. package/dist/gaia-ops/hooks/modules/orchestrator/delegate_mode.py +128 -0
  79. package/dist/gaia-ops/hooks/modules/scanning/__init__.py +8 -0
  80. package/dist/gaia-ops/hooks/modules/scanning/scan_trigger.py +84 -0
  81. package/dist/gaia-ops/hooks/modules/security/__init__.py +89 -0
  82. package/dist/gaia-ops/hooks/modules/security/approval_cleanup.py +87 -0
  83. package/dist/gaia-ops/hooks/modules/security/approval_constants.py +23 -0
  84. package/dist/gaia-ops/hooks/modules/security/approval_grants.py +912 -0
  85. package/dist/gaia-ops/hooks/modules/security/approval_messages.py +71 -0
  86. package/dist/gaia-ops/hooks/modules/security/approval_scopes.py +153 -0
  87. package/dist/gaia-ops/hooks/modules/security/blocked_commands.py +584 -0
  88. package/dist/gaia-ops/hooks/modules/security/blocked_message_formatter.py +86 -0
  89. package/dist/gaia-ops/hooks/modules/security/command_semantics.py +130 -0
  90. package/dist/gaia-ops/hooks/modules/security/gitops_validator.py +179 -0
  91. package/dist/gaia-ops/hooks/modules/security/mutative_verbs.py +850 -0
  92. package/dist/gaia-ops/hooks/modules/security/prompt_validator.py +40 -0
  93. package/dist/gaia-ops/hooks/modules/security/tiers.py +196 -0
  94. package/dist/gaia-ops/hooks/modules/session/__init__.py +10 -0
  95. package/dist/gaia-ops/hooks/modules/session/session_context_writer.py +100 -0
  96. package/dist/gaia-ops/hooks/modules/session/session_event_injector.py +158 -0
  97. package/dist/gaia-ops/hooks/modules/session/session_manager.py +31 -0
  98. package/dist/gaia-ops/hooks/modules/tools/__init__.py +25 -0
  99. package/dist/gaia-ops/hooks/modules/tools/bash_validator.py +708 -0
  100. package/dist/gaia-ops/hooks/modules/tools/cloud_pipe_validator.py +181 -0
  101. package/dist/gaia-ops/hooks/modules/tools/hook_response.py +55 -0
  102. package/dist/gaia-ops/hooks/modules/tools/shell_parser.py +227 -0
  103. package/dist/gaia-ops/hooks/modules/tools/task_validator.py +283 -0
  104. package/dist/gaia-ops/hooks/modules/validation/__init__.py +23 -0
  105. package/dist/gaia-ops/hooks/modules/validation/commit_validator.py +380 -0
  106. package/dist/gaia-ops/hooks/post_compact.py +43 -0
  107. package/dist/gaia-ops/hooks/post_tool_use.py +54 -0
  108. package/dist/gaia-ops/hooks/pre_tool_use.py +383 -0
  109. package/dist/gaia-ops/hooks/session_start.py +69 -0
  110. package/dist/gaia-ops/hooks/stop_hook.py +69 -0
  111. package/dist/gaia-ops/hooks/subagent_start.py +71 -0
  112. package/dist/gaia-ops/hooks/subagent_stop.py +288 -0
  113. package/dist/gaia-ops/hooks/task_completed.py +70 -0
  114. package/dist/gaia-ops/hooks/user_prompt_submit.py +177 -0
  115. package/dist/gaia-ops/settings.json +72 -0
  116. package/dist/gaia-ops/skills/README.md +109 -0
  117. package/dist/gaia-ops/skills/agent-protocol/SKILL.md +105 -0
  118. package/dist/gaia-ops/skills/agent-protocol/examples.md +170 -0
  119. package/dist/gaia-ops/skills/agent-response/SKILL.md +53 -0
  120. package/dist/gaia-ops/skills/approval/SKILL.md +85 -0
  121. package/dist/gaia-ops/skills/approval/examples.md +140 -0
  122. package/dist/gaia-ops/skills/approval/reference.md +57 -0
  123. package/dist/gaia-ops/skills/command-execution/SKILL.md +64 -0
  124. package/dist/gaia-ops/skills/command-execution/reference.md +83 -0
  125. package/dist/gaia-ops/skills/context-updater/SKILL.md +76 -0
  126. package/dist/gaia-ops/skills/context-updater/examples.md +71 -0
  127. package/dist/gaia-ops/skills/developer-patterns/SKILL.md +93 -0
  128. package/dist/gaia-ops/skills/developer-patterns/reference.md +112 -0
  129. package/dist/gaia-ops/skills/execution/SKILL.md +66 -0
  130. package/dist/gaia-ops/skills/fast-queries/SKILL.md +47 -0
  131. package/dist/gaia-ops/skills/gaia-patterns/SKILL.md +92 -0
  132. package/dist/gaia-ops/skills/gaia-patterns/reference.md +22 -0
  133. package/dist/gaia-ops/skills/git-conventions/SKILL.md +48 -0
  134. package/dist/gaia-ops/skills/gitops-patterns/SKILL.md +73 -0
  135. package/dist/gaia-ops/skills/gitops-patterns/reference.md +183 -0
  136. package/dist/gaia-ops/skills/investigation/SKILL.md +77 -0
  137. package/dist/gaia-ops/skills/orchestrator-approval/SKILL.md +64 -0
  138. package/dist/gaia-ops/skills/reference.md +134 -0
  139. package/dist/gaia-ops/skills/security-tiers/SKILL.md +61 -0
  140. package/dist/gaia-ops/skills/security-tiers/destructive-commands-reference.md +623 -0
  141. package/dist/gaia-ops/skills/security-tiers/reference.md +39 -0
  142. package/dist/gaia-ops/skills/skill-creation/SKILL.md +119 -0
  143. package/dist/gaia-ops/skills/specification/SKILL.md +186 -0
  144. package/dist/gaia-ops/skills/speckit-workflow/SKILL.md +165 -0
  145. package/dist/gaia-ops/skills/speckit-workflow/reference.md +117 -0
  146. package/dist/gaia-ops/skills/terraform-patterns/SKILL.md +63 -0
  147. package/dist/gaia-ops/skills/terraform-patterns/reference.md +93 -0
  148. package/dist/gaia-ops/speckit/README.md +516 -0
  149. package/dist/gaia-ops/speckit/scripts/.gitkeep +0 -0
  150. package/dist/gaia-ops/speckit/templates/adr-template.md +118 -0
  151. package/dist/gaia-ops/speckit/templates/agent-file-template.md +23 -0
  152. package/dist/gaia-ops/speckit/templates/plan-template.md +227 -0
  153. package/dist/gaia-ops/speckit/templates/spec-template.md +140 -0
  154. package/dist/gaia-ops/speckit/templates/tasks-template.md +257 -0
  155. package/dist/gaia-ops/tools/context/README.md +132 -0
  156. package/dist/gaia-ops/tools/context/__init__.py +42 -0
  157. package/dist/gaia-ops/tools/context/_paths.py +20 -0
  158. package/dist/gaia-ops/tools/context/context_provider.py +476 -0
  159. package/dist/gaia-ops/tools/context/context_section_reader.py +330 -0
  160. package/dist/gaia-ops/tools/context/deep_merge.py +159 -0
  161. package/dist/gaia-ops/tools/context/pending_updates.py +760 -0
  162. package/dist/gaia-ops/tools/context/surface_router.py +278 -0
  163. package/dist/gaia-ops/tools/fast-queries/README.md +65 -0
  164. package/dist/gaia-ops/tools/fast-queries/__init__.py +30 -0
  165. package/dist/gaia-ops/tools/fast-queries/appservices/quicktriage_devops_developer.sh +75 -0
  166. package/dist/gaia-ops/tools/fast-queries/cloud/aws/quicktriage_aws_troubleshooter.sh +32 -0
  167. package/dist/gaia-ops/tools/fast-queries/cloud/gcp/quicktriage_gcp_troubleshooter.sh +88 -0
  168. package/dist/gaia-ops/tools/fast-queries/gitops/quicktriage_gitops_operator.sh +48 -0
  169. package/dist/gaia-ops/tools/fast-queries/run_triage.sh +59 -0
  170. package/dist/gaia-ops/tools/fast-queries/terraform/quicktriage_terraform_architect.sh +80 -0
  171. package/dist/gaia-ops/tools/gaia_simulator/__init__.py +33 -0
  172. package/dist/gaia-ops/tools/gaia_simulator/cli.py +354 -0
  173. package/dist/gaia-ops/tools/gaia_simulator/extractor.py +457 -0
  174. package/dist/gaia-ops/tools/gaia_simulator/reporter.py +258 -0
  175. package/dist/gaia-ops/tools/gaia_simulator/routing_simulator.py +334 -0
  176. package/dist/gaia-ops/tools/gaia_simulator/runner.py +539 -0
  177. package/dist/gaia-ops/tools/gaia_simulator/skills_mapper.py +262 -0
  178. package/dist/gaia-ops/tools/memory/README.md +0 -0
  179. package/dist/gaia-ops/tools/memory/__init__.py +20 -0
  180. package/dist/gaia-ops/tools/memory/episodic.py +1196 -0
  181. package/dist/gaia-ops/tools/persist_transcript_analysis.py +85 -0
  182. package/dist/gaia-ops/tools/review/__init__.py +1 -0
  183. package/dist/gaia-ops/tools/review/review_engine.py +157 -0
  184. package/dist/gaia-ops/tools/scan/__init__.py +35 -0
  185. package/dist/gaia-ops/tools/scan/config.py +247 -0
  186. package/dist/gaia-ops/tools/scan/merge.py +212 -0
  187. package/dist/gaia-ops/tools/scan/orchestrator.py +549 -0
  188. package/dist/gaia-ops/tools/scan/registry.py +127 -0
  189. package/dist/gaia-ops/tools/scan/scanners/__init__.py +18 -0
  190. package/dist/gaia-ops/tools/scan/scanners/base.py +137 -0
  191. package/dist/gaia-ops/tools/scan/scanners/environment.py +324 -0
  192. package/dist/gaia-ops/tools/scan/scanners/git.py +570 -0
  193. package/dist/gaia-ops/tools/scan/scanners/infrastructure.py +875 -0
  194. package/dist/gaia-ops/tools/scan/scanners/orchestration.py +600 -0
  195. package/dist/gaia-ops/tools/scan/scanners/stack.py +1085 -0
  196. package/dist/gaia-ops/tools/scan/scanners/tools.py +260 -0
  197. package/dist/gaia-ops/tools/scan/setup.py +753 -0
  198. package/dist/gaia-ops/tools/scan/tests/__init__.py +1 -0
  199. package/dist/gaia-ops/tools/scan/tests/conftest.py +796 -0
  200. package/dist/gaia-ops/tools/scan/tests/test_environment.py +323 -0
  201. package/dist/gaia-ops/tools/scan/tests/test_git.py +419 -0
  202. package/dist/gaia-ops/tools/scan/tests/test_infrastructure.py +382 -0
  203. package/dist/gaia-ops/tools/scan/tests/test_integration.py +920 -0
  204. package/dist/gaia-ops/tools/scan/tests/test_merge.py +269 -0
  205. package/dist/gaia-ops/tools/scan/tests/test_orchestration.py +304 -0
  206. package/dist/gaia-ops/tools/scan/tests/test_stack.py +604 -0
  207. package/dist/gaia-ops/tools/scan/tests/test_tools.py +349 -0
  208. package/dist/gaia-ops/tools/scan/ui.py +624 -0
  209. package/dist/gaia-ops/tools/scan/verify.py +266 -0
  210. package/dist/gaia-ops/tools/scan/walk.py +118 -0
  211. package/dist/gaia-ops/tools/scan/workspace.py +85 -0
  212. package/dist/gaia-ops/tools/validation/README.md +244 -0
  213. package/dist/gaia-ops/tools/validation/__init__.py +17 -0
  214. package/dist/gaia-ops/tools/validation/approval_gate.py +321 -0
  215. package/dist/gaia-ops/tools/validation/validate_skills.py +189 -0
  216. package/dist/gaia-security/.claude-plugin/plugin.json +22 -0
  217. package/dist/gaia-security/config/universal-rules.json +10 -0
  218. package/dist/gaia-security/hooks/adapters/__init__.py +52 -0
  219. package/dist/gaia-security/hooks/adapters/base.py +219 -0
  220. package/dist/gaia-security/hooks/adapters/channel.py +17 -0
  221. package/dist/gaia-security/hooks/adapters/claude_code.py +1477 -0
  222. package/dist/gaia-security/hooks/adapters/types.py +194 -0
  223. package/dist/gaia-security/hooks/adapters/utils.py +25 -0
  224. package/dist/gaia-security/hooks/hooks.json +57 -0
  225. package/dist/gaia-security/hooks/modules/__init__.py +15 -0
  226. package/dist/gaia-security/hooks/modules/agents/__init__.py +29 -0
  227. package/dist/gaia-security/hooks/modules/agents/contract_validator.py +647 -0
  228. package/dist/gaia-security/hooks/modules/agents/response_contract.py +496 -0
  229. package/dist/gaia-security/hooks/modules/agents/skill_injection_verifier.py +124 -0
  230. package/dist/gaia-security/hooks/modules/agents/task_info_builder.py +74 -0
  231. package/dist/gaia-security/hooks/modules/agents/transcript_analyzer.py +458 -0
  232. package/dist/gaia-security/hooks/modules/agents/transcript_reader.py +152 -0
  233. package/dist/gaia-security/hooks/modules/audit/__init__.py +28 -0
  234. package/dist/gaia-security/hooks/modules/audit/event_detector.py +168 -0
  235. package/dist/gaia-security/hooks/modules/audit/logger.py +131 -0
  236. package/dist/gaia-security/hooks/modules/audit/metrics.py +134 -0
  237. package/dist/gaia-security/hooks/modules/audit/workflow_auditor.py +576 -0
  238. package/dist/gaia-security/hooks/modules/audit/workflow_recorder.py +296 -0
  239. package/dist/gaia-security/hooks/modules/context/__init__.py +11 -0
  240. package/dist/gaia-security/hooks/modules/context/anchor_tracker.py +317 -0
  241. package/dist/gaia-security/hooks/modules/context/compact_context_builder.py +215 -0
  242. package/dist/gaia-security/hooks/modules/context/context_cache.py +129 -0
  243. package/dist/gaia-security/hooks/modules/context/context_freshness.py +145 -0
  244. package/dist/gaia-security/hooks/modules/context/context_injector.py +427 -0
  245. package/dist/gaia-security/hooks/modules/context/context_writer.py +518 -0
  246. package/dist/gaia-security/hooks/modules/context/contracts_loader.py +161 -0
  247. package/dist/gaia-security/hooks/modules/core/__init__.py +40 -0
  248. package/dist/gaia-security/hooks/modules/core/hook_entry.py +78 -0
  249. package/dist/gaia-security/hooks/modules/core/paths.py +160 -0
  250. package/dist/gaia-security/hooks/modules/core/plugin_mode.py +149 -0
  251. package/dist/gaia-security/hooks/modules/core/plugin_setup.py +558 -0
  252. package/dist/gaia-security/hooks/modules/core/state.py +179 -0
  253. package/dist/gaia-security/hooks/modules/core/stdin.py +24 -0
  254. package/dist/gaia-security/hooks/modules/events/__init__.py +1 -0
  255. package/dist/gaia-security/hooks/modules/events/event_writer.py +210 -0
  256. package/dist/gaia-security/hooks/modules/identity/__init__.py +0 -0
  257. package/dist/gaia-security/hooks/modules/identity/identity_provider.py +21 -0
  258. package/dist/gaia-security/hooks/modules/identity/ops_identity.py +34 -0
  259. package/dist/gaia-security/hooks/modules/identity/security_identity.py +10 -0
  260. package/dist/gaia-security/hooks/modules/memory/__init__.py +8 -0
  261. package/dist/gaia-security/hooks/modules/memory/episode_writer.py +227 -0
  262. package/dist/gaia-security/hooks/modules/orchestrator/__init__.py +1 -0
  263. package/dist/gaia-security/hooks/modules/orchestrator/delegate_mode.py +128 -0
  264. package/dist/gaia-security/hooks/modules/scanning/__init__.py +8 -0
  265. package/dist/gaia-security/hooks/modules/scanning/scan_trigger.py +84 -0
  266. package/dist/gaia-security/hooks/modules/security/__init__.py +89 -0
  267. package/dist/gaia-security/hooks/modules/security/approval_cleanup.py +87 -0
  268. package/dist/gaia-security/hooks/modules/security/approval_constants.py +23 -0
  269. package/dist/gaia-security/hooks/modules/security/approval_grants.py +912 -0
  270. package/dist/gaia-security/hooks/modules/security/approval_messages.py +71 -0
  271. package/dist/gaia-security/hooks/modules/security/approval_scopes.py +153 -0
  272. package/dist/gaia-security/hooks/modules/security/blocked_commands.py +584 -0
  273. package/dist/gaia-security/hooks/modules/security/blocked_message_formatter.py +86 -0
  274. package/dist/gaia-security/hooks/modules/security/command_semantics.py +130 -0
  275. package/dist/gaia-security/hooks/modules/security/gitops_validator.py +179 -0
  276. package/dist/gaia-security/hooks/modules/security/mutative_verbs.py +850 -0
  277. package/dist/gaia-security/hooks/modules/security/prompt_validator.py +40 -0
  278. package/dist/gaia-security/hooks/modules/security/tiers.py +196 -0
  279. package/dist/gaia-security/hooks/modules/session/__init__.py +10 -0
  280. package/dist/gaia-security/hooks/modules/session/session_context_writer.py +100 -0
  281. package/dist/gaia-security/hooks/modules/session/session_event_injector.py +158 -0
  282. package/dist/gaia-security/hooks/modules/session/session_manager.py +31 -0
  283. package/dist/gaia-security/hooks/modules/tools/__init__.py +25 -0
  284. package/dist/gaia-security/hooks/modules/tools/bash_validator.py +708 -0
  285. package/dist/gaia-security/hooks/modules/tools/cloud_pipe_validator.py +181 -0
  286. package/dist/gaia-security/hooks/modules/tools/hook_response.py +55 -0
  287. package/dist/gaia-security/hooks/modules/tools/shell_parser.py +227 -0
  288. package/dist/gaia-security/hooks/modules/tools/task_validator.py +283 -0
  289. package/dist/gaia-security/hooks/modules/validation/__init__.py +23 -0
  290. package/dist/gaia-security/hooks/modules/validation/commit_validator.py +380 -0
  291. package/dist/gaia-security/hooks/post_tool_use.py +54 -0
  292. package/dist/gaia-security/hooks/pre_tool_use.py +383 -0
  293. package/dist/gaia-security/hooks/session_start.py +69 -0
  294. package/dist/gaia-security/hooks/stop_hook.py +69 -0
  295. package/dist/gaia-security/hooks/user_prompt_submit.py +177 -0
  296. package/dist/gaia-security/settings.json +58 -0
  297. package/git-hooks/commit-msg +41 -0
  298. package/hooks/README.md +8 -6
  299. package/hooks/adapters/channel.py +0 -25
  300. package/hooks/adapters/claude_code.py +364 -125
  301. package/hooks/elicitation_result.py +132 -0
  302. package/hooks/hooks.json +10 -1
  303. package/hooks/modules/README.md +3 -2
  304. package/hooks/modules/agents/contract_validator.py +3 -51
  305. package/hooks/modules/agents/response_contract.py +4 -8
  306. package/hooks/modules/agents/transcript_reader.py +4 -5
  307. package/hooks/modules/audit/__init__.py +4 -6
  308. package/hooks/modules/audit/event_detector.py +0 -2
  309. package/hooks/modules/audit/metrics.py +108 -187
  310. package/hooks/modules/audit/workflow_auditor.py +0 -4
  311. package/hooks/modules/audit/workflow_recorder.py +0 -5
  312. package/hooks/modules/context/compact_context_builder.py +1 -0
  313. package/hooks/modules/context/context_cache.py +129 -0
  314. package/hooks/modules/context/context_injector.py +18 -40
  315. package/hooks/modules/context/context_writer.py +1 -25
  316. package/hooks/modules/context/contracts_loader.py +7 -10
  317. package/hooks/modules/core/hook_entry.py +1 -0
  318. package/hooks/modules/core/paths.py +12 -13
  319. package/hooks/modules/core/plugin_mode.py +74 -4
  320. package/hooks/modules/core/plugin_setup.py +395 -23
  321. package/hooks/modules/events/__init__.py +1 -0
  322. package/hooks/modules/events/event_writer.py +210 -0
  323. package/hooks/modules/identity/ops_identity.py +18 -27
  324. package/hooks/modules/memory/episode_writer.py +1 -6
  325. package/hooks/modules/orchestrator/__init__.py +1 -0
  326. package/hooks/modules/orchestrator/delegate_mode.py +128 -0
  327. package/hooks/modules/security/__init__.py +2 -4
  328. package/hooks/modules/security/approval_constants.py +5 -1
  329. package/hooks/modules/security/approval_grants.py +189 -6
  330. package/hooks/modules/security/approval_messages.py +9 -21
  331. package/hooks/modules/security/blocked_commands.py +98 -34
  332. package/hooks/modules/security/command_semantics.py +0 -4
  333. package/hooks/modules/security/gitops_validator.py +1 -11
  334. package/hooks/modules/security/mutative_verbs.py +179 -38
  335. package/hooks/modules/security/tiers.py +1 -19
  336. package/hooks/modules/session/session_event_injector.py +1 -25
  337. package/hooks/modules/tools/bash_validator.py +310 -94
  338. package/hooks/modules/tools/shell_parser.py +0 -1
  339. package/hooks/modules/tools/task_validator.py +9 -29
  340. package/hooks/post_tool_use.py +0 -72
  341. package/hooks/pre_tool_use.py +42 -102
  342. package/hooks/session_start.py +4 -2
  343. package/hooks/subagent_start.py +6 -2
  344. package/hooks/subagent_stop.py +1 -13
  345. package/hooks/user_prompt_submit.py +119 -37
  346. package/index.js +1 -1
  347. package/package.json +5 -3
  348. package/skills/README.md +3 -5
  349. package/skills/agent-protocol/SKILL.md +17 -16
  350. package/skills/agent-protocol/examples.md +6 -6
  351. package/skills/agent-response/SKILL.md +11 -14
  352. package/skills/approval/SKILL.md +28 -13
  353. package/skills/approval/reference.md +2 -2
  354. package/skills/execution/SKILL.md +1 -1
  355. package/skills/gaia-patterns/SKILL.md +2 -3
  356. package/skills/orchestrator-approval/SKILL.md +22 -50
  357. package/skills/security-tiers/SKILL.md +1 -1
  358. package/templates/README.md +9 -9
  359. package/templates/managed-settings.template.json +43 -0
  360. package/tools/gaia_simulator/runner.py +34 -1
  361. package/tools/scan/orchestrator.py +13 -0
  362. package/tools/scan/scanners/base.py +8 -0
  363. package/tools/scan/scanners/git.py +78 -0
  364. package/tools/scan/scanners/infrastructure.py +65 -0
  365. package/tools/scan/scanners/stack.py +110 -0
  366. package/tools/scan/setup.py +120 -13
  367. package/tools/scan/workspace.py +85 -0
  368. package/config/context-contracts.aws.json +0 -42
  369. package/config/context-contracts.gcp.json +0 -39
  370. package/skills/project-dispatch/SKILL.md +0 -34
  371. package/templates/settings.template.json +0 -226
@@ -0,0 +1,584 @@
1
+ """
2
+ Blocked command patterns - PERMANENTLY BLOCKED operations (exit 2, never approvable).
3
+
4
+ This is the single source of truth for DESTRUCTIVE commands. Commands matched here
5
+ are blocked with exit 2 and cannot be approved.
6
+
7
+ All other state-modifying commands are detected by the universal verb detector
8
+ (mutative_verbs.py) as MUTATIVE and routed through the user approval workflow.
9
+
10
+ Categories:
11
+ - AWS networking/data infrastructure delete operations
12
+ - AWS KMS/Route53/Organizations operations
13
+ - Azure resource group/networking/data/AKS/Key Vault delete operations
14
+ - GCP project/cluster/database delete operations
15
+ - Kubernetes critical delete operations (cluster, namespace, pv, node, CRD, webhooks)
16
+ - Kubernetes bulk delete operations (--all flag)
17
+ - Terraform/Terragrunt destroy (without -target)
18
+ - Docker bulk prune operations
19
+ - Flux uninstall (removes all Flux components)
20
+ - Git force push operations (not --force-with-lease)
21
+ - Git reset --hard
22
+ - GitHub/GitLab repo delete
23
+ - npm unpublish (entire package)
24
+ - SQL destructive operations (drop database, drop table)
25
+ - Disk/filesystem destruction operations (dd, fdisk, mkfs)
26
+ - rm -rf / and rm -rf ~
27
+ """
28
+
29
+ import re
30
+ import logging
31
+ from typing import Dict, List, Optional, Tuple
32
+ from dataclasses import dataclass
33
+
34
+ from .command_semantics import CommandSemantics, analyze_command, _contains_ordered_sequence
35
+
36
+ logger = logging.getLogger(__name__)
37
+
38
+
39
+ @dataclass
40
+ class BlockedCommandResult:
41
+ """Result of blocked command check."""
42
+ is_blocked: bool
43
+ pattern_matched: Optional[str] = None
44
+ category: Optional[str] = None
45
+ suggestion: Optional[str] = None
46
+
47
+
48
+ @dataclass(frozen=True)
49
+ class SemanticBlockedRule:
50
+ """Ordered-token signature for deny-listed commands."""
51
+
52
+ category: str
53
+ sequence: Tuple[str, ...]
54
+ suggestion_key: str
55
+ required_flags: Tuple[str, ...] = ()
56
+ forbidden_flags: Tuple[str, ...] = ()
57
+ head_only: bool = True
58
+
59
+ def matches(self, semantics: CommandSemantics) -> bool:
60
+ tokens = semantics.semantic_head_tokens if self.head_only else semantics.semantic_tokens
61
+ if not _contains_ordered_sequence(tokens, self.sequence):
62
+ return False
63
+
64
+ flags = set(semantics.flag_tokens)
65
+ if any(flag not in flags for flag in self.required_flags):
66
+ return False
67
+ # forbidden_flags uses prefix matching to handle -flag=value forms
68
+ # (e.g., "-target=aws_instance.web" should match forbidden flag "-target")
69
+ if self.forbidden_flags:
70
+ for flag_token in semantics.flag_tokens:
71
+ for forbidden in self.forbidden_flags:
72
+ if flag_token == forbidden or flag_token.startswith(forbidden + "="):
73
+ return False
74
+ return True
75
+
76
+
77
+ # ============================================================================
78
+ # BLOCKED PATTERNS - PERMANENTLY BLOCKED (exit 2, no nonce, never approvable)
79
+ # ============================================================================
80
+ # These commands are PERMANENTLY BLOCKED and cannot be executed even with approval.
81
+ # They represent irreversible, catastrophic operations at scale.
82
+ #
83
+ # The following are MUTATIVE (approvable via nonce, handled by mutative_verbs.py):
84
+ # - aws iam delete-*, detach-*, remove-user-from-group
85
+ # - aws ec2 delete-key-pair, delete-snapshot, delete-volume,
86
+ # delete-security-group, delete-network-interface
87
+ # - aws lambda delete-function
88
+ # - aws rds delete-db-parameter-group, delete-db-cluster-parameter-group
89
+ # - aws cloudformation delete-stack
90
+ # - aws s3api delete-objects
91
+ # - aws sns delete-topic, aws sqs delete-queue
92
+ # - aws dynamodb delete-item
93
+ # - aws backup delete
94
+ # - aws eks delete-nodegroup, delete-addon
95
+ # - gcloud compute firewall-rules/instances/networks/disks/images/snapshots delete
96
+ # - gcloud container node-pools delete
97
+ # - gcloud iam roles delete
98
+ # - gcloud storage rm
99
+ # - kubectl delete pod/deployment/service/configmap/secret/clusterrole/clusterrolebinding
100
+ # - flux delete (single resource)
101
+ # - terraform destroy -target=<resource> (targeted)
102
+ # - helm uninstall (any release)
103
+ # - docker rm, docker rmi (individual containers/images)
104
+ # ============================================================================
105
+
106
+ BLOCKED_PATTERNS: Dict[str, List[re.Pattern]] = {
107
+ # AWS - Networking and data infrastructure (irreversible)
108
+ # Patterns use (?!-) negative lookahead to prevent prefix matching
109
+ # (e.g., delete-db-cluster must not match delete-db-cluster-parameter-group).
110
+ # \b alone is insufficient because hyphens are non-word characters.
111
+ "aws_critical": [
112
+ re.compile(r"aws\s+ec2\s+delete-vpc(?!-)\b", re.IGNORECASE),
113
+ re.compile(r"aws\s+ec2\s+delete-subnet(?!-)\b", re.IGNORECASE),
114
+ re.compile(r"aws\s+ec2\s+delete-internet-gateway(?!-)\b", re.IGNORECASE),
115
+ re.compile(r"aws\s+ec2\s+delete-route-table(?!-)\b", re.IGNORECASE),
116
+ re.compile(r"aws\s+ec2\s+delete-route(?!-)\b", re.IGNORECASE),
117
+ re.compile(r"aws\s+ec2\s+terminate-instances\b", re.IGNORECASE),
118
+ re.compile(r"aws\s+rds\s+delete-db-instance(?!-)\b", re.IGNORECASE),
119
+ re.compile(r"aws\s+rds\s+delete-db-cluster(?!-)\b", re.IGNORECASE),
120
+ re.compile(r"aws\s+dynamodb\s+delete-table(?!-)\b", re.IGNORECASE),
121
+ re.compile(r"aws\s+s3\s+rb(?!-)\b", re.IGNORECASE),
122
+ re.compile(r"aws\s+s3api\s+delete-bucket(?!-)\b", re.IGNORECASE),
123
+ re.compile(r"aws\s+elasticache\s+delete-cache-cluster(?!-)\b", re.IGNORECASE),
124
+ re.compile(r"aws\s+elasticache\s+delete-replication-group(?!-)\b", re.IGNORECASE),
125
+ re.compile(r"aws\s+eks\s+delete-cluster(?!-)\b", re.IGNORECASE),
126
+ re.compile(r"aws\s+kms\s+schedule-key-deletion\b", re.IGNORECASE),
127
+ re.compile(r"aws\s+organizations\s+delete-organization\b", re.IGNORECASE),
128
+ re.compile(r"aws\s+route53\s+delete-hosted-zone\b", re.IGNORECASE),
129
+ ],
130
+
131
+ # Azure - Resource group, networking, data infrastructure (irreversible)
132
+ "azure_critical": [
133
+ re.compile(r"az\s+group\s+delete\b", re.IGNORECASE),
134
+ re.compile(r"az\s+network\s+vnet\s+delete\b", re.IGNORECASE),
135
+ re.compile(r"az\s+network\s+vnet\s+subnet\s+delete\b", re.IGNORECASE),
136
+ re.compile(r"az\s+network\s+nsg\s+delete\b", re.IGNORECASE),
137
+ re.compile(r"az\s+network\s+public-ip\s+delete\b", re.IGNORECASE),
138
+ re.compile(r"az\s+network\s+application-gateway\s+delete\b", re.IGNORECASE),
139
+ re.compile(r"az\s+network\s+lb\s+delete\b", re.IGNORECASE),
140
+ re.compile(r"az\s+network\s+dns\s+zone\s+delete\b", re.IGNORECASE),
141
+ re.compile(r"az\s+network\s+private-dns\s+zone\s+delete\b", re.IGNORECASE),
142
+ re.compile(r"az\s+vm\s+delete\b", re.IGNORECASE),
143
+ re.compile(r"az\s+vmss\s+delete\b", re.IGNORECASE),
144
+ re.compile(r"az\s+disk\s+delete\b", re.IGNORECASE),
145
+ re.compile(r"az\s+snapshot\s+delete\b", re.IGNORECASE),
146
+ re.compile(r"az\s+image\s+delete\b", re.IGNORECASE),
147
+ re.compile(r"az\s+sql\s+server\s+delete\b", re.IGNORECASE),
148
+ re.compile(r"az\s+sql\s+db\s+delete\b", re.IGNORECASE),
149
+ re.compile(r"az\s+cosmosdb\s+delete\b", re.IGNORECASE),
150
+ re.compile(r"az\s+redis\s+delete\b", re.IGNORECASE),
151
+ re.compile(r"az\s+storage\s+account\s+delete\b", re.IGNORECASE),
152
+ re.compile(r"az\s+storage\s+container\s+delete\b", re.IGNORECASE),
153
+ re.compile(r"az\s+storage\s+blob\s+delete-batch\b", re.IGNORECASE),
154
+ re.compile(r"az\s+aks\s+delete\b", re.IGNORECASE),
155
+ re.compile(r"az\s+aks\s+nodepool\s+delete\b", re.IGNORECASE),
156
+ re.compile(r"az\s+acr\s+delete\b", re.IGNORECASE),
157
+ re.compile(r"az\s+keyvault\s+delete\b", re.IGNORECASE),
158
+ re.compile(r"az\s+keyvault\s+key\s+delete\b", re.IGNORECASE),
159
+ re.compile(r"az\s+keyvault\s+secret\s+delete\b", re.IGNORECASE),
160
+ re.compile(r"az\s+functionapp\s+delete\b", re.IGNORECASE),
161
+ re.compile(r"az\s+webapp\s+delete\b", re.IGNORECASE),
162
+ re.compile(r"az\s+ad\s+app\s+delete\b", re.IGNORECASE),
163
+ re.compile(r"az\s+ad\s+sp\s+delete\b", re.IGNORECASE),
164
+ re.compile(r"az\s+servicebus\s+namespace\s+delete\b", re.IGNORECASE),
165
+ re.compile(r"az\s+eventhubs\s+namespace\s+delete\b", re.IGNORECASE),
166
+ ],
167
+
168
+ # GCP - Project, cluster, and database operations (irreversible)
169
+ "gcp_critical": [
170
+ re.compile(r"gcloud\s+projects\s+delete\b", re.IGNORECASE),
171
+ re.compile(r"gcloud\s+container\s+clusters\s+delete\b", re.IGNORECASE),
172
+ re.compile(r"gcloud\s+sql\s+instances\s+delete\b", re.IGNORECASE),
173
+ re.compile(r"gcloud\s+sql\s+databases\s+delete\b", re.IGNORECASE),
174
+ re.compile(r"gcloud\s+services\s+disable\b", re.IGNORECASE),
175
+ re.compile(r"gsutil\s+rb\b", re.IGNORECASE),
176
+ re.compile(r"gsutil\s+rm\s+-r\b", re.IGNORECASE),
177
+ ],
178
+
179
+ # Kubernetes - Critical cluster operations (irreversible)
180
+ # Word boundaries prevent "cluster" from matching "clusterrole" etc.
181
+ "kubernetes_critical": [
182
+ re.compile(r"kubectl\s+delete\s+namespace\b", re.IGNORECASE),
183
+ re.compile(r"kubectl\s+delete\s+ns\b", re.IGNORECASE),
184
+ re.compile(r"kubectl\s+delete\s+node\b", re.IGNORECASE),
185
+ re.compile(r"kubectl\s+delete\s+cluster\b", re.IGNORECASE),
186
+ re.compile(r"kubectl\s+delete\s+(pv|persistentvolume)\b", re.IGNORECASE),
187
+ re.compile(r"kubectl\s+delete\s+(pvc|persistentvolumeclaim)\b", re.IGNORECASE),
188
+ re.compile(r"kubectl\s+delete\s+(crd|customresourcedefinition)\b", re.IGNORECASE),
189
+ re.compile(r"kubectl\s+delete\s+mutatingwebhookconfiguration\b", re.IGNORECASE),
190
+ re.compile(r"kubectl\s+delete\s+validatingwebhookconfiguration\b", re.IGNORECASE),
191
+ re.compile(r"kubectl\s+drain\b", re.IGNORECASE),
192
+ # Bulk delete with --all flag on any resource type
193
+ re.compile(r"kubectl\s+delete\s+\w+\s+.*--all\b", re.IGNORECASE),
194
+ ],
195
+
196
+ # Terraform / Terragrunt - Whole-state destruction
197
+ "terraform_destroy": [
198
+ # terraform destroy WITHOUT -target (bare destroy is destructive)
199
+ # Uses negative lookahead to allow "terraform destroy -target=X" through
200
+ re.compile(r"terraform\s+destroy\b(?!.*-target)", re.IGNORECASE),
201
+ re.compile(r"terragrunt\s+destroy\b(?!.*-target)", re.IGNORECASE),
202
+ re.compile(r"terragrunt\s+run-all\s+destroy\b", re.IGNORECASE),
203
+ re.compile(r"terragrunt\s+destroy-all\b", re.IGNORECASE),
204
+ ],
205
+
206
+ # Docker - Bulk prune operations
207
+ "docker_critical": [
208
+ re.compile(r"docker\s+system\s+prune\s+.*(-a|--all)\b", re.IGNORECASE),
209
+ re.compile(r"docker\s+system\s+prune\s+.*--volumes\b", re.IGNORECASE),
210
+ re.compile(r"docker\s+volume\s+prune\b", re.IGNORECASE),
211
+ ],
212
+
213
+ # Flux - Uninstall removes ALL Flux components from cluster
214
+ "flux_critical": [
215
+ re.compile(r"flux\s+uninstall\b", re.IGNORECASE),
216
+ ],
217
+
218
+ # Git - Force push (history rewrite, not --force-with-lease) and reset --hard
219
+ "git_destructive": [
220
+ re.compile(r"git\s+push\s+.*--force(?!-with-lease)", re.IGNORECASE),
221
+ re.compile(r"git\s+push\s+.*(?<!\w)-f\b", re.IGNORECASE),
222
+ re.compile(r"git\s+reset\s+.*--hard\b", re.IGNORECASE),
223
+ ],
224
+
225
+ # GitHub/GitLab - Repo deletion
226
+ "repo_delete": [
227
+ re.compile(r"gh\s+repo\s+delete\b", re.IGNORECASE),
228
+ re.compile(r"glab\s+project\s+delete\b", re.IGNORECASE),
229
+ ],
230
+
231
+ # npm - Unpublish entire package (without @version)
232
+ "npm_critical": [
233
+ # Matches "npm unpublish packagename" but NOT "npm unpublish package@1.0.0"
234
+ re.compile(r"npm\s+unpublish\s+(?!.*@)\S+", re.IGNORECASE),
235
+ ],
236
+
237
+ # SQL - Drop database/table
238
+ "sql_critical": [
239
+ re.compile(r"drop\s+database\b", re.IGNORECASE),
240
+ re.compile(r"drop\s+table\b", re.IGNORECASE),
241
+ ],
242
+
243
+ # Disk operations - Irreversible data destruction
244
+ "disk_operations": [
245
+ re.compile(r"^dd\s+", re.IGNORECASE),
246
+ re.compile(r"^fdisk\s+", re.IGNORECASE),
247
+ re.compile(r"^mkfs(\.(ext[34]|fat|ntfs))?\s+", re.IGNORECASE),
248
+ ],
249
+
250
+ # rm -rf / and rm -rf ~ (catastrophic filesystem destruction)
251
+ "rm_critical": [
252
+ re.compile(r"rm\s+.*-[a-z]*r[a-z]*f[a-z]*\s+/\s*$", re.IGNORECASE),
253
+ re.compile(r"rm\s+.*-[a-z]*f[a-z]*r[a-z]*\s+/\s*$", re.IGNORECASE),
254
+ re.compile(r"rm\s+.*-[a-z]*r[a-z]*f[a-z]*\s+/\*", re.IGNORECASE),
255
+ re.compile(r"rm\s+.*-[a-z]*f[a-z]*r[a-z]*\s+/\*", re.IGNORECASE),
256
+ re.compile(r"rm\s+.*-[a-z]*r[a-z]*f[a-z]*\s+~/?", re.IGNORECASE),
257
+ re.compile(r"rm\s+.*-[a-z]*f[a-z]*r[a-z]*\s+~/?", re.IGNORECASE),
258
+ ],
259
+ }
260
+
261
+ # Suggestions for permanently blocked commands
262
+ BLOCKED_COMMAND_SUGGESTIONS = {
263
+ # AWS suggestions
264
+ "aws ec2 delete-vpc": "[BLOCKED] VPC deletion is irreversible - use Terraform/Terragrunt",
265
+ "aws ec2 delete-subnet": "[BLOCKED] Subnet deletion is irreversible - use Terraform/Terragrunt",
266
+ "aws ec2 delete-internet-gateway": "[BLOCKED] Internet gateway deletion is irreversible - use Terraform/Terragrunt",
267
+ "aws ec2 delete-route-table": "[BLOCKED] Route table deletion is irreversible - use Terraform/Terragrunt",
268
+ "aws ec2 delete-route": "[BLOCKED] Route deletion should be done via Terraform/Terragrunt",
269
+ "aws ec2 terminate-instances": "[BLOCKED] Instance termination is irreversible - use Terraform/Terragrunt",
270
+ "aws rds delete-db-instance": "[BLOCKED] Use Terraform/Terragrunt for RDS lifecycle management",
271
+ "aws rds delete-db-cluster": "[BLOCKED] Use Terraform/Terragrunt for RDS cluster management",
272
+ "aws dynamodb delete-table": "[BLOCKED] Table deletion loses all data - use Terraform/Terragrunt",
273
+ "aws s3 rb": "[BLOCKED] Bucket removal is irreversible - use Terraform/Terragrunt",
274
+ "aws s3api delete-bucket": "[BLOCKED] Bucket deletion is irreversible - use Terraform/Terragrunt",
275
+ "aws eks delete-cluster": "[BLOCKED] Use Terraform/Terragrunt for EKS management",
276
+ "aws elasticache delete": "[BLOCKED] Use Terraform/Terragrunt for ElastiCache management",
277
+ "aws kms schedule-key-deletion": "[BLOCKED] KMS key deletion renders all encrypted data permanently unrecoverable",
278
+ "aws organizations delete-organization": "[BLOCKED] Organization deletion is irreversible",
279
+ "aws route53 delete-hosted-zone": "[BLOCKED] DNS zone deletion causes widespread outage",
280
+
281
+ # Azure suggestions
282
+ "az group delete": "[BLOCKED] Resource group deletion destroys all contained resources - use Terraform/Terragrunt",
283
+ "az network vnet delete": "[BLOCKED] VNet deletion is irreversible - use Terraform/Terragrunt",
284
+ "az network vnet subnet delete": "[BLOCKED] Subnet deletion is irreversible - use Terraform/Terragrunt",
285
+ "az network nsg delete": "[BLOCKED] NSG deletion removes all security rules - use Terraform/Terragrunt",
286
+ "az vm delete": "[BLOCKED] VM deletion is irreversible - use Terraform/Terragrunt",
287
+ "az vmss delete": "[BLOCKED] Scale set deletion is irreversible - use Terraform/Terragrunt",
288
+ "az disk delete": "[BLOCKED] Disk deletion loses all data - use Terraform/Terragrunt",
289
+ "az sql server delete": "[BLOCKED] SQL Server deletion destroys all databases - use Terraform/Terragrunt",
290
+ "az sql db delete": "[BLOCKED] Database deletion loses all data - use Terraform/Terragrunt",
291
+ "az cosmosdb delete": "[BLOCKED] CosmosDB deletion is irreversible - use Terraform/Terragrunt",
292
+ "az redis delete": "[BLOCKED] Redis deletion loses all cached data - use Terraform/Terragrunt",
293
+ "az storage account delete": "[BLOCKED] Storage account deletion destroys all data - use Terraform/Terragrunt",
294
+ "az aks delete": "[BLOCKED] AKS cluster deletion is irreversible - use Terraform/Terragrunt",
295
+ "az acr delete": "[BLOCKED] Container registry deletion destroys all images - use Terraform/Terragrunt",
296
+ "az keyvault delete": "[BLOCKED] Key Vault deletion can render encrypted data unrecoverable",
297
+ "az functionapp delete": "[BLOCKED] Function App deletion is irreversible - use Terraform/Terragrunt",
298
+ "az webapp delete": "[BLOCKED] Web App deletion is irreversible - use Terraform/Terragrunt",
299
+ "az ad app delete": "[BLOCKED] App registration deletion breaks all dependent services",
300
+ "az ad sp delete": "[BLOCKED] Service principal deletion breaks authentication for dependent services",
301
+ "az servicebus namespace delete": "[BLOCKED] Service Bus namespace deletion is irreversible - use Terraform/Terragrunt",
302
+ "az eventhubs namespace delete": "[BLOCKED] Event Hubs namespace deletion is irreversible - use Terraform/Terragrunt",
303
+
304
+ # GCP suggestions
305
+ "gcloud projects delete": "[BLOCKED] Project deletion is irreversible - must be done via Cloud Console",
306
+ "gcloud container clusters delete": "[BLOCKED] Use Terraform/Terragrunt for GKE management",
307
+ "gcloud sql instances delete": "[BLOCKED] Use Terraform/Terragrunt for Cloud SQL management",
308
+ "gcloud sql databases delete": "[BLOCKED] Database deletion loses all data - use Terraform/Terragrunt",
309
+ "gcloud services disable": "[BLOCKED] Disabling services can break dependent resources",
310
+ "gsutil rb": "[BLOCKED] Bucket removal is irreversible",
311
+ "gsutil rm -r": "[BLOCKED] Recursive deletion of cloud storage is irreversible",
312
+
313
+ # Kubernetes suggestions
314
+ "kubectl delete namespace": "[BLOCKED] Namespace deletion destroys all resources within it",
315
+ "kubectl delete ns": "[BLOCKED] Namespace deletion destroys all resources within it",
316
+ "kubectl delete node": "[BLOCKED] Node deletion removes the node from the cluster",
317
+ "kubectl delete cluster": "[BLOCKED] Cluster deletion is irreversible and impacts all workloads",
318
+ "kubectl delete pv": "[BLOCKED] Persistent volume deletion loses data",
319
+ "kubectl delete pvc": "[BLOCKED] PVC deletion can trigger PV reclaim and data loss",
320
+ "kubectl delete crd": "[BLOCKED] CRD deletion destroys all custom resources of that type",
321
+ "kubectl delete mutatingwebhookconfiguration": "[BLOCKED] Webhook deletion can break admission control and cluster safety",
322
+ "kubectl delete validatingwebhookconfiguration": "[BLOCKED] Webhook deletion can break admission control and cluster safety",
323
+ "kubectl drain": "[BLOCKED] Node draining can cause service disruption",
324
+ "kubectl delete --all": "[BLOCKED] Bulk deletion of all resources is irreversible",
325
+
326
+ # Terraform / Terragrunt suggestions
327
+ "terraform destroy": "[BLOCKED] terraform destroy without -target destroys entire state - use terraform destroy -target=<resource>",
328
+ "terragrunt destroy": "[BLOCKED] terragrunt destroy without -target destroys entire state",
329
+ "terragrunt run-all destroy": "[BLOCKED] Recursive destruction of all modules",
330
+ "terragrunt destroy-all": "[BLOCKED] Recursive destruction of all modules",
331
+
332
+ # Docker suggestions
333
+ "docker system prune": "[BLOCKED] docker system prune with -a or --volumes removes all unused resources",
334
+ "docker volume prune": "[BLOCKED] docker volume prune removes all unused volumes and data",
335
+
336
+ # Flux suggestions
337
+ "flux uninstall": "[BLOCKED] flux uninstall removes ALL Flux components from the cluster",
338
+
339
+ # Git suggestions
340
+ "git push --force": "[BLOCKED] Force push rewrites history - use git push --force-with-lease",
341
+ "git push -f": "[BLOCKED] Force push rewrites history - use git push --force-with-lease",
342
+ "git reset --hard": "[BLOCKED] git reset --hard permanently discards uncommitted changes",
343
+
344
+ # GitHub/GitLab suggestions
345
+ "gh repo delete": "[BLOCKED] Repository deletion is irreversible - destroys all code and history",
346
+ "glab project delete": "[BLOCKED] Project deletion is irreversible - destroys all code and history",
347
+
348
+ # npm suggestions
349
+ "npm unpublish": "[BLOCKED] npm unpublish without @version removes entire package from registry",
350
+
351
+ # SQL suggestions
352
+ "drop database": "[BLOCKED] DROP DATABASE is irreversible - destroys all data",
353
+ "drop table": "[BLOCKED] DROP TABLE is irreversible - destroys all data",
354
+
355
+ # Disk operations
356
+ "dd": "[BLOCKED] Low-level disk operations can destroy data",
357
+ "fdisk": "[BLOCKED] Disk partitioning can destroy data",
358
+ "mkfs": "[BLOCKED] Filesystem creation destroys all data on target",
359
+
360
+ # rm critical
361
+ "rm -rf /": "[BLOCKED] Filesystem destruction is irreversible",
362
+ "rm -rf ~": "[BLOCKED] Home directory destruction is irreversible",
363
+ }
364
+
365
+ # Structured deny signatures complement the raw regex patterns above.
366
+ # They make the deny list resilient to extra flag/value pairs inserted before
367
+ # the real subcommand, e.g.:
368
+ # kubectl --context prod delete namespace
369
+ # aws --profile prod ec2 delete-vpc
370
+ # git -C repo push origin main --force
371
+ SEMANTIC_BLOCKED_RULES = (
372
+ # AWS
373
+ SemanticBlockedRule("aws_critical", ("aws", "ec2", "delete-vpc"), "aws ec2 delete-vpc"),
374
+ SemanticBlockedRule("aws_critical", ("aws", "ec2", "delete-subnet"), "aws ec2 delete-subnet"),
375
+ SemanticBlockedRule("aws_critical", ("aws", "ec2", "delete-internet-gateway"), "aws ec2 delete-internet-gateway"),
376
+ SemanticBlockedRule("aws_critical", ("aws", "ec2", "delete-route-table"), "aws ec2 delete-route-table"),
377
+ SemanticBlockedRule("aws_critical", ("aws", "ec2", "delete-route"), "aws ec2 delete-route"),
378
+ SemanticBlockedRule("aws_critical", ("aws", "ec2", "terminate-instances"), "aws ec2 terminate-instances"),
379
+ SemanticBlockedRule("aws_critical", ("aws", "rds", "delete-db-instance"), "aws rds delete-db-instance"),
380
+ SemanticBlockedRule("aws_critical", ("aws", "rds", "delete-db-cluster"), "aws rds delete-db-cluster"),
381
+ SemanticBlockedRule("aws_critical", ("aws", "dynamodb", "delete-table"), "aws dynamodb delete-table"),
382
+ SemanticBlockedRule("aws_critical", ("aws", "s3", "rb"), "aws s3 rb"),
383
+ SemanticBlockedRule("aws_critical", ("aws", "s3api", "delete-bucket"), "aws s3api delete-bucket"),
384
+ SemanticBlockedRule(
385
+ "aws_critical",
386
+ ("aws", "elasticache", "delete-cache-cluster"),
387
+ "aws elasticache delete",
388
+ ),
389
+ SemanticBlockedRule(
390
+ "aws_critical",
391
+ ("aws", "elasticache", "delete-replication-group"),
392
+ "aws elasticache delete",
393
+ ),
394
+ SemanticBlockedRule("aws_critical", ("aws", "eks", "delete-cluster"), "aws eks delete-cluster"),
395
+ SemanticBlockedRule("aws_critical", ("aws", "kms", "schedule-key-deletion"), "aws kms schedule-key-deletion"),
396
+ SemanticBlockedRule("aws_critical", ("aws", "organizations", "delete-organization"), "aws organizations delete-organization"),
397
+ SemanticBlockedRule("aws_critical", ("aws", "route53", "delete-hosted-zone"), "aws route53 delete-hosted-zone"),
398
+
399
+ # Azure
400
+ SemanticBlockedRule("azure_critical", ("az", "group", "delete"), "az group delete"),
401
+ SemanticBlockedRule("azure_critical", ("az", "network", "vnet", "delete"), "az network vnet delete"),
402
+ SemanticBlockedRule("azure_critical", ("az", "network", "vnet", "subnet", "delete"), "az network vnet subnet delete"),
403
+ SemanticBlockedRule("azure_critical", ("az", "network", "nsg", "delete"), "az network nsg delete"),
404
+ SemanticBlockedRule("azure_critical", ("az", "network", "public-ip", "delete"), "az network vnet delete"),
405
+ SemanticBlockedRule("azure_critical", ("az", "network", "application-gateway", "delete"), "az network vnet delete"),
406
+ SemanticBlockedRule("azure_critical", ("az", "network", "lb", "delete"), "az network vnet delete"),
407
+ SemanticBlockedRule("azure_critical", ("az", "network", "dns", "zone", "delete"), "az network vnet delete"),
408
+ SemanticBlockedRule("azure_critical", ("az", "network", "private-dns", "zone", "delete"), "az network vnet delete"),
409
+ SemanticBlockedRule("azure_critical", ("az", "vm", "delete"), "az vm delete"),
410
+ SemanticBlockedRule("azure_critical", ("az", "vmss", "delete"), "az vmss delete"),
411
+ SemanticBlockedRule("azure_critical", ("az", "disk", "delete"), "az disk delete"),
412
+ SemanticBlockedRule("azure_critical", ("az", "snapshot", "delete"), "az disk delete"),
413
+ SemanticBlockedRule("azure_critical", ("az", "image", "delete"), "az disk delete"),
414
+ SemanticBlockedRule("azure_critical", ("az", "sql", "server", "delete"), "az sql server delete"),
415
+ SemanticBlockedRule("azure_critical", ("az", "sql", "db", "delete"), "az sql db delete"),
416
+ SemanticBlockedRule("azure_critical", ("az", "cosmosdb", "delete"), "az cosmosdb delete"),
417
+ SemanticBlockedRule("azure_critical", ("az", "redis", "delete"), "az redis delete"),
418
+ SemanticBlockedRule("azure_critical", ("az", "storage", "account", "delete"), "az storage account delete"),
419
+ SemanticBlockedRule("azure_critical", ("az", "storage", "container", "delete"), "az storage account delete"),
420
+ SemanticBlockedRule("azure_critical", ("az", "storage", "blob", "delete-batch"), "az storage account delete"),
421
+ SemanticBlockedRule("azure_critical", ("az", "aks", "delete"), "az aks delete"),
422
+ SemanticBlockedRule("azure_critical", ("az", "aks", "nodepool", "delete"), "az aks delete"),
423
+ SemanticBlockedRule("azure_critical", ("az", "acr", "delete"), "az acr delete"),
424
+ SemanticBlockedRule("azure_critical", ("az", "keyvault", "delete"), "az keyvault delete"),
425
+ SemanticBlockedRule("azure_critical", ("az", "keyvault", "key", "delete"), "az keyvault delete"),
426
+ SemanticBlockedRule("azure_critical", ("az", "keyvault", "secret", "delete"), "az keyvault delete"),
427
+ SemanticBlockedRule("azure_critical", ("az", "functionapp", "delete"), "az functionapp delete"),
428
+ SemanticBlockedRule("azure_critical", ("az", "webapp", "delete"), "az webapp delete"),
429
+ SemanticBlockedRule("azure_critical", ("az", "ad", "app", "delete"), "az ad app delete"),
430
+ SemanticBlockedRule("azure_critical", ("az", "ad", "sp", "delete"), "az ad sp delete"),
431
+ SemanticBlockedRule("azure_critical", ("az", "servicebus", "namespace", "delete"), "az servicebus namespace delete"),
432
+ SemanticBlockedRule("azure_critical", ("az", "eventhubs", "namespace", "delete"), "az eventhubs namespace delete"),
433
+
434
+ # GCP
435
+ SemanticBlockedRule("gcp_critical", ("gcloud", "projects", "delete"), "gcloud projects delete"),
436
+ SemanticBlockedRule(
437
+ "gcp_critical",
438
+ ("gcloud", "container", "clusters", "delete"),
439
+ "gcloud container clusters delete",
440
+ ),
441
+ SemanticBlockedRule("gcp_critical", ("gcloud", "sql", "instances", "delete"), "gcloud sql instances delete"),
442
+ SemanticBlockedRule("gcp_critical", ("gcloud", "sql", "databases", "delete"), "gcloud sql databases delete"),
443
+ SemanticBlockedRule("gcp_critical", ("gcloud", "services", "disable"), "gcloud services disable"),
444
+ SemanticBlockedRule("gcp_critical", ("gsutil", "rb"), "gsutil rb"),
445
+ SemanticBlockedRule("gcp_critical", ("gsutil", "rm"), "gsutil rm -r", required_flags=("-r",)),
446
+
447
+ # Kubernetes
448
+ SemanticBlockedRule("kubernetes_critical", ("kubectl", "delete", "namespace"), "kubectl delete namespace"),
449
+ SemanticBlockedRule("kubernetes_critical", ("kubectl", "delete", "ns"), "kubectl delete ns"),
450
+ SemanticBlockedRule("kubernetes_critical", ("kubectl", "delete", "node"), "kubectl delete node"),
451
+ SemanticBlockedRule("kubernetes_critical", ("kubectl", "delete", "cluster"), "kubectl delete cluster"),
452
+ SemanticBlockedRule("kubernetes_critical", ("kubectl", "delete", "pv"), "kubectl delete pv"),
453
+ SemanticBlockedRule(
454
+ "kubernetes_critical",
455
+ ("kubectl", "delete", "persistentvolume"),
456
+ "kubectl delete pv",
457
+ ),
458
+ SemanticBlockedRule("kubernetes_critical", ("kubectl", "delete", "pvc"), "kubectl delete pvc"),
459
+ SemanticBlockedRule(
460
+ "kubernetes_critical",
461
+ ("kubectl", "delete", "persistentvolumeclaim"),
462
+ "kubectl delete pvc",
463
+ ),
464
+ SemanticBlockedRule("kubernetes_critical", ("kubectl", "delete", "crd"), "kubectl delete crd"),
465
+ SemanticBlockedRule(
466
+ "kubernetes_critical",
467
+ ("kubectl", "delete", "customresourcedefinition"),
468
+ "kubectl delete crd",
469
+ ),
470
+ SemanticBlockedRule(
471
+ "kubernetes_critical",
472
+ ("kubectl", "delete", "mutatingwebhookconfiguration"),
473
+ "kubectl delete mutatingwebhookconfiguration",
474
+ ),
475
+ SemanticBlockedRule(
476
+ "kubernetes_critical",
477
+ ("kubectl", "delete", "validatingwebhookconfiguration"),
478
+ "kubectl delete validatingwebhookconfiguration",
479
+ ),
480
+ SemanticBlockedRule("kubernetes_critical", ("kubectl", "drain"), "kubectl drain"),
481
+
482
+ # Terraform / Terragrunt (semantic rules use forbidden_flags to allow -target through)
483
+ SemanticBlockedRule(
484
+ "terraform_destroy",
485
+ ("terraform", "destroy"),
486
+ "terraform destroy",
487
+ forbidden_flags=("-target", "--target"),
488
+ ),
489
+ SemanticBlockedRule(
490
+ "terraform_destroy",
491
+ ("terragrunt", "destroy"),
492
+ "terragrunt destroy",
493
+ forbidden_flags=("-target", "--target"),
494
+ ),
495
+ SemanticBlockedRule("terraform_destroy", ("terragrunt", "run-all", "destroy"), "terragrunt run-all destroy"),
496
+ SemanticBlockedRule("terraform_destroy", ("terragrunt", "destroy-all"), "terragrunt destroy-all"),
497
+
498
+ # Docker
499
+ SemanticBlockedRule("docker_critical", ("docker", "system", "prune"), "docker system prune", required_flags=("-a",)),
500
+ SemanticBlockedRule("docker_critical", ("docker", "system", "prune"), "docker system prune", required_flags=("--all",)),
501
+ SemanticBlockedRule("docker_critical", ("docker", "system", "prune"), "docker system prune", required_flags=("--volumes",)),
502
+ SemanticBlockedRule("docker_critical", ("docker", "volume", "prune"), "docker volume prune"),
503
+
504
+ # Flux
505
+ SemanticBlockedRule("flux_critical", ("flux", "uninstall"), "flux uninstall"),
506
+
507
+ # Git
508
+ SemanticBlockedRule("git_destructive", ("git", "push"), "git push --force", required_flags=("--force",)),
509
+ SemanticBlockedRule("git_destructive", ("git", "push"), "git push -f", required_flags=("-f",)),
510
+ SemanticBlockedRule("git_destructive", ("git", "reset"), "git reset --hard", required_flags=("--hard",)),
511
+
512
+ # GitHub/GitLab
513
+ SemanticBlockedRule("repo_delete", ("gh", "repo", "delete"), "gh repo delete"),
514
+ SemanticBlockedRule("repo_delete", ("glab", "project", "delete"), "glab project delete"),
515
+ )
516
+
517
+
518
+ def get_blocked_patterns() -> List[re.Pattern]:
519
+ """
520
+ Get flat list of all blocked patterns (pre-compiled).
521
+
522
+ Returns:
523
+ List of compiled regex patterns
524
+ """
525
+ patterns = []
526
+ for category_patterns in BLOCKED_PATTERNS.values():
527
+ patterns.extend(category_patterns)
528
+ return patterns
529
+
530
+
531
+
532
+ def is_blocked_command(command: str) -> BlockedCommandResult:
533
+ """
534
+ Check if command matches any blocked pattern.
535
+
536
+ Args:
537
+ command: Shell command to check
538
+
539
+ Returns:
540
+ BlockedCommandResult with match details
541
+ """
542
+ if not command or not command.strip():
543
+ return BlockedCommandResult(is_blocked=False)
544
+
545
+ command = command.strip()
546
+
547
+ semantic_rule = _match_semantic_block_rule(command)
548
+ if semantic_rule is not None:
549
+ suggestion = BLOCKED_COMMAND_SUGGESTIONS.get(semantic_rule.suggestion_key)
550
+ return BlockedCommandResult(
551
+ is_blocked=True,
552
+ pattern_matched=f"semantic:{' '.join(semantic_rule.sequence)}",
553
+ category=semantic_rule.category,
554
+ suggestion=suggestion,
555
+ )
556
+
557
+ for category, patterns in BLOCKED_PATTERNS.items():
558
+ for pattern in patterns:
559
+ if pattern.search(command):
560
+ # Find suggestion for this command
561
+ suggestion = None
562
+ for cmd_prefix, cmd_suggestion in BLOCKED_COMMAND_SUGGESTIONS.items():
563
+ if cmd_prefix in command.lower():
564
+ suggestion = cmd_suggestion
565
+ break
566
+
567
+ return BlockedCommandResult(
568
+ is_blocked=True,
569
+ pattern_matched=pattern.pattern,
570
+ category=category,
571
+ suggestion=suggestion,
572
+ )
573
+
574
+ return BlockedCommandResult(is_blocked=False)
575
+
576
+
577
+
578
+ def _match_semantic_block_rule(command: str) -> Optional[SemanticBlockedRule]:
579
+ """Return the first semantic deny rule that matches a command."""
580
+ semantics = analyze_command(command)
581
+ for rule in SEMANTIC_BLOCKED_RULES:
582
+ if rule.matches(semantics):
583
+ return rule
584
+ return None