@raishin/vanguard-frontier-agentic 3.14.0 → 3.16.0

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 (223) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.cursor-plugin/plugin.json +1 -1
  4. package/.github/plugin/marketplace.json +1 -1
  5. package/agents/cross-functional/revenue-critical-journey-integrity-agent/harnesses/codex.toml +1 -1
  6. package/agents/dotnet/dotnet-aspire-cloud-native-review-agent/harnesses/codex.toml +1 -1
  7. package/agents/dotnet/dotnet-aspnetcore-api-review-agent/harnesses/codex.toml +1 -1
  8. package/agents/dotnet/dotnet-aspnetcore-identity-authz-review-agent/harnesses/codex.toml +1 -1
  9. package/agents/dotnet/dotnet-csharp-runtime-review-agent/harnesses/codex.toml +1 -1
  10. package/agents/dotnet/dotnet-efcore-data-access-review-agent/harnesses/codex.toml +1 -1
  11. package/agents/dotnet/dotnet-maestro-agent/harnesses/codex.toml +1 -1
  12. package/agents/dotnet/dotnet-observability-otel-review-agent/harnesses/codex.toml +1 -1
  13. package/agents/dotnet/dotnet-performance-aot-review-agent/harnesses/codex.toml +1 -1
  14. package/agents/dotnet/dotnet-supply-chain-review-agent/harnesses/codex.toml +1 -1
  15. package/agents/dotnet/dotnet-testing-quality-review-agent/harnesses/codex.toml +1 -1
  16. package/agents/frontend/nextjs-specialist-agent/harnesses/codex.toml +1 -1
  17. package/agents/frontend/svelte-sveltekit-specialist-agent/harnesses/codex.toml +1 -1
  18. package/agents/hr/hr-analytics-people-data-agent/harnesses/codex.toml +1 -1
  19. package/agents/hr/hr-benefits-payroll-agent/harnesses/codex.toml +1 -1
  20. package/agents/hr/hr-compensation-equity-agent/harnesses/codex.toml +1 -1
  21. package/agents/hr/hr-culture-dei-agent/harnesses/codex.toml +1 -1
  22. package/agents/hr/hr-employee-relations-agent/harnesses/codex.toml +1 -1
  23. package/agents/hr/hr-hris-process-controls-agent/harnesses/codex.toml +1 -1
  24. package/agents/hr/hr-learning-policy-agent/harnesses/codex.toml +1 -1
  25. package/agents/hr/hr-leave-accommodation-agent/harnesses/codex.toml +1 -1
  26. package/agents/hr/hr-maestro-agent/harnesses/codex.toml +1 -1
  27. package/agents/hr/hr-performance-management-agent/harnesses/codex.toml +1 -1
  28. package/agents/hr/hr-recruiting-selection-agent/harnesses/codex.toml +1 -1
  29. package/agents/hr/hr-risk-triage-review-agent/harnesses/codex.toml +1 -1
  30. package/agents/hr/hr-termination-readiness-agent/harnesses/codex.toml +1 -1
  31. package/agents/hr/hr-workforce-planning-rif-agent/harnesses/codex.toml +1 -1
  32. package/agents/hr/hr-workplace-investigations-agent/harnesses/codex.toml +1 -1
  33. package/agents/java/java-application-server-exit-agent/harnesses/codex.toml +1 -1
  34. package/agents/java/java-concurrency-and-virtual-thread-agent/harnesses/codex.toml +1 -1
  35. package/agents/java/java-container-and-kubernetes-readiness-agent/harnesses/codex.toml +1 -1
  36. package/agents/java/java-database-migration-safety-agent/harnesses/codex.toml +1 -1
  37. package/agents/java/java-deserialization-and-parser-security-agent/harnesses/codex.toml +1 -1
  38. package/agents/java/java-framework-production-readiness-agent/harnesses/codex.toml +1 -1
  39. package/agents/java/java-jdk-lifecycle-and-upgrade-agent/harnesses/codex.toml +1 -1
  40. package/agents/java/java-jpa-hibernate-performance-agent/harnesses/codex.toml +1 -1
  41. package/agents/java/java-jvm-performance-and-gc-agent/harnesses/codex.toml +1 -1
  42. package/agents/java/java-kafka-reliability-agent/harnesses/codex.toml +1 -1
  43. package/agents/java/java-maestro-agent/harnesses/codex.toml +1 -1
  44. package/agents/java/java-resilience-pattern-agent/harnesses/codex.toml +1 -1
  45. package/agents/java/java-spring-security-agent/harnesses/codex.toml +1 -1
  46. package/agents/java/java-test-architecture-agent/harnesses/codex.toml +1 -1
  47. package/agents/java/java-transaction-and-consistency-agent/harnesses/codex.toml +1 -1
  48. package/agents/legal/legal-contract-review-agent/harnesses/codex.toml +1 -1
  49. package/agents/legal/legal-counsel-review-agent/harnesses/codex.toml +1 -1
  50. package/agents/legal/legal-employment-law-risk-agent/harnesses/codex.toml +1 -1
  51. package/agents/legal/legal-ethics-investigations-agent/harnesses/codex.toml +1 -1
  52. package/agents/legal/legal-ip-open-source-agent/harnesses/codex.toml +1 -1
  53. package/agents/legal/legal-knowledge-management-agent/harnesses/codex.toml +1 -1
  54. package/agents/legal/legal-litigation-discovery-hold-agent/harnesses/codex.toml +1 -1
  55. package/agents/legal/legal-maestro-agent/harnesses/codex.toml +1 -1
  56. package/agents/legal/legal-policy-governance-agent/harnesses/codex.toml +1 -1
  57. package/agents/legal/legal-privacy-data-protection-agent/harnesses/codex.toml +1 -1
  58. package/agents/legal/legal-public-disclosure-agent/harnesses/codex.toml +1 -1
  59. package/agents/legal/legal-regulatory-compliance-agent/harnesses/codex.toml +1 -1
  60. package/agents/legal/legal-vendor-procurement-risk-agent/harnesses/codex.toml +1 -1
  61. package/agents/netsuite/netsuite-administrator-agent/harnesses/codex.toml +1 -1
  62. package/agents/netsuite/netsuite-ai-connector-mcp-agent/harnesses/codex.toml +1 -1
  63. package/agents/netsuite/netsuite-ai-foundations-agent/harnesses/codex.toml +1 -1
  64. package/agents/netsuite/netsuite-application-developer-agent/harnesses/codex.toml +1 -1
  65. package/agents/netsuite/netsuite-audit-controls-sox-agent/harnesses/codex.toml +1 -1
  66. package/agents/netsuite/netsuite-bi-reporting-agent/harnesses/codex.toml +1 -1
  67. package/agents/netsuite/netsuite-data-governance-privacy-agent/harnesses/codex.toml +1 -1
  68. package/agents/netsuite/netsuite-enterprise-architecture-agent/harnesses/codex.toml +1 -1
  69. package/agents/netsuite/netsuite-erp-consultant-agent/harnesses/codex.toml +1 -1
  70. package/agents/netsuite/netsuite-evidence-release-drift-agent/harnesses/codex.toml +1 -1
  71. package/agents/netsuite/netsuite-financial-foundations-agent/harnesses/codex.toml +1 -1
  72. package/agents/netsuite/netsuite-identity-access-role-permission-agent/harnesses/codex.toml +1 -1
  73. package/agents/netsuite/netsuite-integration-migration-agent/harnesses/codex.toml +1 -1
  74. package/agents/netsuite/netsuite-live-org-mutation-guard-agent/harnesses/codex.toml +1 -1
  75. package/agents/netsuite/netsuite-maestro-agent/harnesses/codex.toml +1 -1
  76. package/agents/netsuite/netsuite-oneworld-multisubsidiary-agent/harnesses/codex.toml +1 -1
  77. package/agents/netsuite/netsuite-sandbox-nonproduction-governance-agent/harnesses/codex.toml +1 -1
  78. package/agents/netsuite/netsuite-saved-searches-workbook-agent/harnesses/codex.toml +1 -1
  79. package/agents/netsuite/netsuite-sdf-devops-release-agent/harnesses/codex.toml +1 -1
  80. package/agents/netsuite/netsuite-sso-oauth-tba-agent/harnesses/codex.toml +1 -1
  81. package/agents/netsuite/netsuite-suitecloud-developer-agent/harnesses/codex.toml +1 -1
  82. package/agents/netsuite/netsuite-suiteflow-automation-agent/harnesses/codex.toml +1 -1
  83. package/agents/netsuite/netsuite-suitefoundation-agent/harnesses/codex.toml +1 -1
  84. package/agents/netsuite/netsuite-suitescript-secure-code-review-agent/harnesses/codex.toml +1 -1
  85. package/agents/netsuite/netsuite-web-services-integration-agent/harnesses/codex.toml +1 -1
  86. package/agents/qa/ci-test-pipeline-review-agent/harnesses/codex.toml +1 -1
  87. package/agents/qa/helm-chart-quality-review-agent/harnesses/codex.toml +1 -1
  88. package/agents/qa/kubernetes-manifest-quality-review-agent/harnesses/codex.toml +1 -1
  89. package/agents/qa/llm-ai-pipeline-test-review-agent/harnesses/codex.toml +1 -1
  90. package/agents/qa/playwright-e2e-suite-review-agent/harnesses/codex.toml +1 -1
  91. package/agents/qa/plc-control-logic-safety-review-agent/harnesses/codex.toml +1 -1
  92. package/agents/qa/rpa-workflow-resilience-review-agent/harnesses/codex.toml +1 -1
  93. package/agents/qa/test-coverage-quality-review-agent/harnesses/codex.toml +1 -1
  94. package/agents/qa/test-flakiness-triage-agent/harnesses/codex.toml +1 -1
  95. package/agents/salesforce/salesforce-adaptive-access-agent/harnesses/codex.toml +1 -1
  96. package/agents/salesforce/salesforce-agentforce-ai-agent/harnesses/codex.toml +1 -1
  97. package/agents/salesforce/salesforce-analytics-tableau-agent/harnesses/codex.toml +1 -1
  98. package/agents/salesforce/salesforce-app-builder-automation-agent/harnesses/codex.toml +1 -1
  99. package/agents/salesforce/salesforce-business-analyst-agent/harnesses/codex.toml +1 -1
  100. package/agents/salesforce/salesforce-certificate-lifecycle-agent/harnesses/codex.toml +1 -1
  101. package/agents/salesforce/salesforce-change-impact-analyst-agent/harnesses/codex.toml +1 -1
  102. package/agents/salesforce/salesforce-code-analyzer-orchestrator-agent/harnesses/codex.toml +1 -1
  103. package/agents/salesforce/salesforce-compliance-privacy-agent/harnesses/codex.toml +1 -1
  104. package/agents/salesforce/salesforce-continuous-verification-agent/harnesses/codex.toml +1 -1
  105. package/agents/salesforce/salesforce-data-architecture-agent/harnesses/codex.toml +1 -1
  106. package/agents/salesforce/salesforce-development-agent/harnesses/codex.toml +1 -1
  107. package/agents/salesforce/salesforce-devops-release-agent/harnesses/codex.toml +1 -1
  108. package/agents/salesforce/salesforce-enterprise-architect-agent/harnesses/codex.toml +1 -1
  109. package/agents/salesforce/salesforce-experience-cloud-agent/harnesses/codex.toml +1 -1
  110. package/agents/salesforce/salesforce-hyperforce-security-agent/harnesses/codex.toml +1 -1
  111. package/agents/salesforce/salesforce-industry-cloud-agent/harnesses/codex.toml +1 -1
  112. package/agents/salesforce/salesforce-integration-mulesoft-agent/harnesses/codex.toml +1 -1
  113. package/agents/salesforce/salesforce-live-guard-agent/harnesses/codex.toml +1 -1
  114. package/agents/salesforce/salesforce-maestro-agent/harnesses/codex.toml +1 -1
  115. package/agents/salesforce/salesforce-marketing-cloud-agent/harnesses/codex.toml +1 -1
  116. package/agents/salesforce/salesforce-network-policy-architect-agent/harnesses/codex.toml +1 -1
  117. package/agents/salesforce/salesforce-platform-admin-review-agent/harnesses/codex.toml +1 -1
  118. package/agents/salesforce/salesforce-sales-cloud-revenue-agent/harnesses/codex.toml +1 -1
  119. package/agents/salesforce/salesforce-sandbox-governance-agent/harnesses/codex.toml +1 -1
  120. package/agents/salesforce/salesforce-sandbox-isolation-agent/harnesses/codex.toml +1 -1
  121. package/agents/salesforce/salesforce-security-identity-access-agent/harnesses/codex.toml +1 -1
  122. package/agents/salesforce/salesforce-service-field-service-agent/harnesses/codex.toml +1 -1
  123. package/agents/salesforce/salesforce-session-governance-agent/harnesses/codex.toml +1 -1
  124. package/agents/salesforce/salesforce-slack-collaboration-agent/harnesses/codex.toml +1 -1
  125. package/catalog/AGENTS.md +2 -1
  126. package/catalog/asset-integrity.json +723 -276
  127. package/catalog/index.json +3 -2
  128. package/catalog/model-assignments.json +121 -121
  129. package/catalog/model-policy.json +9 -9
  130. package/catalog/model-registry.json +28 -13
  131. package/catalog/mods.json +131 -0
  132. package/mods/README.md +220 -0
  133. package/mods/audit-trail/README.md +70 -0
  134. package/mods/audit-trail/bin/hook.mjs +65 -0
  135. package/mods/audit-trail/claude-code/UNSUPPORTED.md +11 -0
  136. package/mods/audit-trail/claude-code/settings.hooks.json +14 -0
  137. package/mods/audit-trail/codex/hooks.json +14 -0
  138. package/mods/audit-trail/kiro/UNSUPPORTED.md +7 -0
  139. package/mods/audit-trail/kiro/audit-trail-post-tool-use-hook.json +14 -0
  140. package/mods/audit-trail/lib/common.mjs +213 -0
  141. package/mods/audit-trail/lib/core.mjs +50 -0
  142. package/mods/audit-trail/lib/runtime.mjs +140 -0
  143. package/mods/audit-trail/mod.toml +37 -0
  144. package/mods/blast-radius-guard/.claude-plugin/plugin.json +5 -0
  145. package/mods/blast-radius-guard/README.md +53 -0
  146. package/mods/blast-radius-guard/bin/hook.mjs +18 -0
  147. package/mods/blast-radius-guard/claude-code/settings.hooks.json +14 -0
  148. package/mods/blast-radius-guard/codex/UNSUPPORTED.md +7 -0
  149. package/mods/blast-radius-guard/codex/hooks.json +14 -0
  150. package/mods/blast-radius-guard/hooks/hooks.json +5 -0
  151. package/mods/blast-radius-guard/hooks/register.test.ts +97 -0
  152. package/mods/blast-radius-guard/hooks/register.ts +13 -0
  153. package/mods/blast-radius-guard/kiro/UNSUPPORTED.md +7 -0
  154. package/mods/blast-radius-guard/kiro/blast-radius-guard-pre-tool-use-hook.json +14 -0
  155. package/mods/blast-radius-guard/lib/common.mjs +213 -0
  156. package/mods/blast-radius-guard/lib/core.mjs +66 -0
  157. package/mods/blast-radius-guard/lib/patterns.mjs +102 -0
  158. package/mods/blast-radius-guard/lib/runtime.mjs +140 -0
  159. package/mods/blast-radius-guard/mod.toml +34 -0
  160. package/mods/blast-radius-guard/patterns.json +101 -0
  161. package/mods/context-burn/.claude-plugin/plugin.json +5 -0
  162. package/mods/context-burn/README.md +66 -0
  163. package/mods/context-burn/bin/hook.mjs +38 -0
  164. package/mods/context-burn/claude-code/UNSUPPORTED.md +7 -0
  165. package/mods/context-burn/claude-code/settings.hooks.json +24 -0
  166. package/mods/context-burn/codex/UNSUPPORTED.md +7 -0
  167. package/mods/context-burn/codex/hooks.json +24 -0
  168. package/mods/context-burn/hooks/hooks.json +5 -0
  169. package/mods/context-burn/hooks/register.test.ts +151 -0
  170. package/mods/context-burn/hooks/register.ts +35 -0
  171. package/mods/context-burn/kiro/UNSUPPORTED.md +7 -0
  172. package/mods/context-burn/kiro/context-burn-post-tool-use-hook.json +14 -0
  173. package/mods/context-burn/kiro/context-burn-session-start-hook.json +14 -0
  174. package/mods/context-burn/lib/common.mjs +213 -0
  175. package/mods/context-burn/lib/core.mjs +79 -0
  176. package/mods/context-burn/lib/runtime.mjs +140 -0
  177. package/mods/context-burn/mod.toml +37 -0
  178. package/mods/live-guard-gate/.claude-plugin/plugin.json +5 -0
  179. package/mods/live-guard-gate/README.md +43 -0
  180. package/mods/live-guard-gate/bin/hook.mjs +12 -0
  181. package/mods/live-guard-gate/claude-code/settings.hooks.json +14 -0
  182. package/mods/live-guard-gate/codex/UNSUPPORTED.md +7 -0
  183. package/mods/live-guard-gate/codex/hooks.json +14 -0
  184. package/mods/live-guard-gate/hooks/hooks.json +5 -0
  185. package/mods/live-guard-gate/hooks/register.test.ts +59 -0
  186. package/mods/live-guard-gate/hooks/register.ts +11 -0
  187. package/mods/live-guard-gate/kiro/UNSUPPORTED.md +7 -0
  188. package/mods/live-guard-gate/kiro/live-guard-gate-pre-tool-use-hook.json +14 -0
  189. package/mods/live-guard-gate/lib/common.mjs +213 -0
  190. package/mods/live-guard-gate/lib/core.mjs +24 -0
  191. package/mods/live-guard-gate/lib/live-agents.mjs +65 -0
  192. package/mods/live-guard-gate/lib/patterns.mjs +523 -0
  193. package/mods/live-guard-gate/lib/runtime.mjs +140 -0
  194. package/mods/live-guard-gate/mod.toml +34 -0
  195. package/mods/live-guard-gate/patterns.json +522 -0
  196. package/mods/secret-redactor/.claude-plugin/plugin.json +5 -0
  197. package/mods/secret-redactor/README.md +86 -0
  198. package/mods/secret-redactor/bin/hook.mjs +35 -0
  199. package/mods/secret-redactor/claude-code/UNSUPPORTED.md +7 -0
  200. package/mods/secret-redactor/claude-code/settings.hooks.json +24 -0
  201. package/mods/secret-redactor/codex/UNSUPPORTED.md +11 -0
  202. package/mods/secret-redactor/codex/hooks.json +14 -0
  203. package/mods/secret-redactor/hooks/hooks.json +5 -0
  204. package/mods/secret-redactor/hooks/register.test.ts +150 -0
  205. package/mods/secret-redactor/hooks/register.ts +19 -0
  206. package/mods/secret-redactor/kiro/UNSUPPORTED.md +11 -0
  207. package/mods/secret-redactor/kiro/secret-redactor-pre-tool-use-hook.json +14 -0
  208. package/mods/secret-redactor/lib/common.mjs +213 -0
  209. package/mods/secret-redactor/lib/core.mjs +61 -0
  210. package/mods/secret-redactor/lib/patterns.mjs +75 -0
  211. package/mods/secret-redactor/lib/runtime.mjs +140 -0
  212. package/mods/secret-redactor/mod.toml +43 -0
  213. package/mods/secret-redactor/patterns.json +74 -0
  214. package/package.json +9 -5
  215. package/plugins/vanguard-frontier-agentic/.codex-plugin/plugin.json +1 -1
  216. package/scripts/generate-mods.mjs +784 -0
  217. package/scripts/mods/common.mjs +213 -0
  218. package/scripts/mods/runtime.mjs +140 -0
  219. package/tests/fixtures/README.md +1 -1
  220. package/tests/fuzz-properties.test.mjs +254 -0
  221. package/tests/mods.test.mjs +768 -0
  222. package/tests/validate-asset-integrity.py +1 -0
  223. package/tests/validate-mods.py +821 -0
@@ -0,0 +1,7 @@
1
+ # Blast Radius Guard on Codex
2
+
3
+ <!-- Generated by scripts/generate-mods.mjs from mod.toml. Do not edit. -->
4
+
5
+ ## Degraded
6
+
7
+ - `PreToolUse`: Codex rejects ask; confirm mode denies with a reason.
@@ -0,0 +1,14 @@
1
+ {
2
+ "hooks": {
3
+ "PreToolUse": [
4
+ {
5
+ "hooks": [
6
+ {
7
+ "type": "command",
8
+ "command": "node .codex/vanguard-mods/blast-radius-guard/bin/hook.mjs --harness codex --event PreToolUse"
9
+ }
10
+ ]
11
+ }
12
+ ]
13
+ }
14
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "modules": [
3
+ "./register.ts"
4
+ ]
5
+ }
@@ -0,0 +1,97 @@
1
+ import { test, expect, mock } from 'claude-code/testing'
2
+
3
+ const ENV_MODE = 'VANGUARD_BLAST_RADIUS_GUARD_MODE'
4
+ const ENV_PATTERNS = 'VANGUARD_BLAST_RADIUS_GUARD_PATTERNS'
5
+ const allow = () => ({ decision: 'allow' as const })
6
+ const bash = (command: string) => ({ tool: 'Bash', input: { command } })
7
+ const ext = (over: object = {}) =>
8
+ JSON.stringify([{ id: 'danger-cmd', name: 'danger cmd', regex: 'danger-cmd', flags: '', context: ['bash'], ...over }])
9
+
10
+ test('rm -rf / asks by default', async ($, on) => {
11
+ mock.env(on, {})
12
+ on('tool.check', allow)
13
+ expect((await $.tool.check(bash('rm -rf /'))).decision).toBe('ask')
14
+ })
15
+
16
+ test('block mode denies', async ($, on) => {
17
+ mock.env(on, { [ENV_MODE]: 'block' })
18
+ on('tool.check', allow)
19
+ expect((await $.tool.check(bash('rm -rf /'))).decision).toBe('deny')
20
+ })
21
+
22
+ test('unknown mode denies', async ($, on) => {
23
+ mock.env(on, { [ENV_MODE]: 'bogus' })
24
+ on('tool.check', allow)
25
+ expect((await $.tool.check(bash('rm -rf /'))).decision).toBe('deny')
26
+ })
27
+
28
+ test('clean command passes the engine verdict', async ($, on) => {
29
+ mock.env(on, {})
30
+ on('tool.check', allow)
31
+ expect((await $.tool.check(bash('ls'))).decision).toBe('allow')
32
+ })
33
+
34
+ test('engine deny stays deny', async ($, on) => {
35
+ mock.env(on, {})
36
+ on('tool.check', () => ({ decision: 'deny' as const, reason: 'engine' }))
37
+ expect((await $.tool.check(bash('ls'))).decision).toBe('deny')
38
+ })
39
+
40
+ test('Write to a traversal path to /etc asks', async ($, on) => {
41
+ mock.env(on, {})
42
+ on('tool.check', allow)
43
+ const v = await $.tool.check({ tool: 'Write', input: { file_path: '/tmp/../etc/passwd', content: 'x' } })
44
+ expect(v.decision).toBe('ask')
45
+ })
46
+
47
+ test('Read of /etc/passwd is allowed', async ($, on) => {
48
+ mock.env(on, {})
49
+ on('tool.check', allow)
50
+ const v = await $.tool.check({ tool: 'Read', input: { file_path: '/etc/passwd' } })
51
+ expect(v.decision).toBe('allow')
52
+ })
53
+
54
+ test('argv array is read as a command line', async ($, on) => {
55
+ mock.env(on, {})
56
+ on('tool.check', allow)
57
+ const v = await $.tool.check({ tool: 'Exec', input: { argv: ['rm', '-rf', '/'] } })
58
+ expect(v.decision).toBe('ask')
59
+ })
60
+
61
+ test('extension pattern asks', async ($, on) => {
62
+ mock.env(on, { [ENV_PATTERNS]: '/ext.json' })
63
+ on('tool.check', allow)
64
+ on('fs.read', () => ({ value: ext() }))
65
+ expect((await $.tool.check(bash('run danger-cmd now'))).decision).toBe('ask')
66
+ })
67
+
68
+ test('unreadable extension file denies', async ($, on) => {
69
+ mock.env(on, { [ENV_PATTERNS]: '/ext.json' })
70
+ on('tool.check', allow)
71
+ on('fs.read', () => {
72
+ throw new Error('nope')
73
+ })
74
+ expect((await $.tool.check(bash('ls'))).decision).toBe('deny')
75
+ })
76
+
77
+ test('extension that is not JSON denies', async ($, on) => {
78
+ mock.env(on, { [ENV_PATTERNS]: '/ext.json' })
79
+ on('tool.check', allow)
80
+ on('fs.read', () => ({ value: 'not json' }))
81
+ expect((await $.tool.check(bash('ls'))).decision).toBe('deny')
82
+ })
83
+
84
+ test('extension reusing a built-in id denies', async ($, on) => {
85
+ mock.env(on, { [ENV_PATTERNS]: '/ext.json' })
86
+ on('tool.check', allow)
87
+ on('fs.read', () => ({ value: ext({ id: 'rm-rf-root-or-home' }) }))
88
+ expect((await $.tool.check(bash('ls'))).decision).toBe('deny')
89
+ })
90
+
91
+ test('oversized command asks as too large', async ($, on) => {
92
+ mock.env(on, {})
93
+ on('tool.check', allow)
94
+ const v = await $.tool.check(bash('a'.repeat(70000)))
95
+ expect(v.decision).toBe('ask')
96
+ expect(v.reason).toContain('input too large to evaluate')
97
+ })
@@ -0,0 +1,13 @@
1
+ import type { Register } from 'claude-code'
2
+ import { checkToolUse, compileGuardPatterns, modeOf } from '../lib/core.mjs'
3
+
4
+ export const register: Register = (on) => {
5
+ on('tool.check', async ($, e, next) => {
6
+ const v = await next(e)
7
+ if (v.decision === 'deny') return v
8
+ const mode = modeOf(await $.env.get('VANGUARD_BLAST_RADIUS_GUARD_MODE'))
9
+ const file = await $.env.get('VANGUARD_BLAST_RADIUS_GUARD_PATTERNS')
10
+ const patterns = compileGuardPatterns(file ? await $.fs.read(file) : undefined)
11
+ return checkToolUse({ tool: e.tool, input: e.input }, patterns, mode) ?? v
12
+ }).catch(() => ({ decision: 'deny', reason: 'blast-radius-guard: check failed; denied' }))
13
+ }
@@ -0,0 +1,7 @@
1
+ # Blast Radius Guard on Kiro
2
+
3
+ <!-- Generated by scripts/generate-mods.mjs from mod.toml. Do not edit. -->
4
+
5
+ ## Degraded
6
+
7
+ - `PreToolUse`: Kiro documents no confirmation protocol or stdin field names; the whole payload is scanned, the system-path rule applies to the path keys whatever the tool, and confirm mode denies.
@@ -0,0 +1,14 @@
1
+ {
2
+ "version": "v1",
3
+ "hooks": [
4
+ {
5
+ "name": "blast-radius-guard:PreToolUse",
6
+ "description": "Asks before, or blocks, destructive shell commands and writes to system paths.",
7
+ "trigger": "PreToolUse",
8
+ "action": {
9
+ "type": "command",
10
+ "command": "node .kiro/vanguard-mods/blast-radius-guard/bin/hook.mjs --harness kiro --event PreToolUse"
11
+ }
12
+ }
13
+ ]
14
+ }
@@ -0,0 +1,213 @@
1
+ // Shared helpers for the mods under mods/. scripts/generate-mods.mjs copies this file
2
+ // byte-for-byte to mods/<id>/lib/common.mjs, so edit it here and run `npm run mods:write`.
3
+ //
4
+ // Pure on purpose: no imports, no environment, no I/O. Claude Code's native mod runtime
5
+ // imports it and has no Node, and every harness must reach the same verdict on the same
6
+ // input. Regexes compile without the `u` flag so Node and Python `re.ASCII`
7
+ // (tests/validate-mods.py) read them the same way.
8
+
9
+ export const LIMITS = Object.freeze({
10
+ // A redaction that still changes after this many passes is withheld as a whole.
11
+ maxPasses: 8,
12
+ // A guard candidate longer than this is not evaluated and counts as a hit.
13
+ maxCandidateChars: 65536,
14
+ // Guard candidates are not evaluated past this combined length; the call counts as a hit.
15
+ maxTotalChars: 262144,
16
+ // Only the tail of a leaf's context (key or previous sibling) is prefixed to it.
17
+ maxContextChars: 256,
18
+ })
19
+
20
+ const MARKER_PREFIX = '[REDACTED:'
21
+ export const OVERFLOW_MARKER = '[REDACTED:overflow]'
22
+ const OVERFLOW_HIT = Object.freeze({ id: 'overflow', name: 'redaction did not converge' })
23
+ export const TOO_LARGE_HIT = Object.freeze({ id: 'too-large', name: 'input too large to evaluate' })
24
+
25
+ const ID_RE = /^[a-z0-9]+(-[a-z0-9]+)*$/
26
+ const PATTERN_KEYS = new Set(['id', 'name', 'description', 'regex', 'flags', 'context', 'severity', 'agents'])
27
+ const isStringArray = (v) => Array.isArray(v) && v.every((s) => typeof s === 'string' && s !== '')
28
+
29
+ // Parser diagnostics can quote credential-bearing data; never expose it in hook logs.
30
+ export function parseJson(text, source) {
31
+ try {
32
+ return JSON.parse(text)
33
+ } catch {
34
+ throw new Error(`${source}: invalid JSON`)
35
+ }
36
+ }
37
+
38
+ // Validates a patterns.json-shaped list and compiles it. Throws on anything malformed so a
39
+ // bad extension file fails closed in the caller instead of silently matching nothing.
40
+ export function compilePatterns(list, source = 'patterns') {
41
+ if (!Array.isArray(list)) throw new Error(`${source}: expected an array of patterns`)
42
+ const seen = new Set()
43
+ return list.map((p, i) => {
44
+ const where = `${source}[${i}]`
45
+ if (p === null || typeof p !== 'object' || Array.isArray(p)) throw new Error(`${where}: expected an object`)
46
+ for (const k of Object.keys(p)) if (!PATTERN_KEYS.has(k)) throw new Error(`${where}: unknown key ${k}`)
47
+ if (typeof p.id !== 'string' || !ID_RE.test(p.id)) throw new Error(`${where}: id must be kebab-case`)
48
+ if (seen.has(p.id)) throw new Error(`${where}: duplicate id ${p.id}`)
49
+ seen.add(p.id)
50
+ if (typeof p.name !== 'string' || p.name === '') throw new Error(`${where}: name must be a non-empty string`)
51
+ if (typeof p.regex !== 'string' || p.regex === '') throw new Error(`${where}: regex must be a non-empty string`)
52
+ if (p.flags !== '' && p.flags !== 'i') throw new Error(`${where}: flags must be "" or "i"`)
53
+ if (!isStringArray(p.context) || p.context.length === 0) throw new Error(`${where}: context must be a non-empty string array`)
54
+ for (const k of ['description', 'severity']) {
55
+ if (p[k] !== undefined && typeof p[k] !== 'string') throw new Error(`${where}: ${k} must be a string`)
56
+ }
57
+ if (p.agents !== undefined && !isStringArray(p.agents)) throw new Error(`${where}: agents must be a string array`)
58
+ let rx, rxg
59
+ try {
60
+ rx = new RegExp(p.regex, p.flags)
61
+ rxg = new RegExp(p.regex, 'g' + p.flags)
62
+ } catch {
63
+ throw new Error(`${where}: regex does not compile`)
64
+ }
65
+ return Object.freeze({
66
+ id: p.id,
67
+ name: p.name,
68
+ severity: p.severity,
69
+ context: Object.freeze([...p.context]),
70
+ agents: p.agents ? Object.freeze([...p.agents]) : undefined,
71
+ rx,
72
+ rxg,
73
+ marker: `${MARKER_PREFIX}${p.id}]`,
74
+ })
75
+ })
76
+ }
77
+
78
+ // Every string value (not key) in depth-first order. The order follows the input, so the
79
+ // same payload always yields the same list.
80
+ export function stringLeaves(value, out = []) {
81
+ if (typeof value === 'string') out.push(value)
82
+ else if (Array.isArray(value)) for (const v of value) stringLeaves(v, out)
83
+ else if (value !== null && typeof value === 'object') for (const v of Object.values(value)) stringLeaves(v, out)
84
+ return out
85
+ }
86
+
87
+ // Guard candidates: every string leaf, plus every all-string array joined with spaces so
88
+ // an argv-style command (["rm", "-rf", "/"]) reads like the shell line it runs.
89
+ export function candidates(value) {
90
+ const out = stringLeaves(value)
91
+ const joinArrays = (v) => {
92
+ if (Array.isArray(v)) {
93
+ if (v.length > 1 && v.every((s) => typeof s === 'string')) out.push(v.join(' '))
94
+ v.forEach(joinArrays)
95
+ } else if (v !== null && typeof v === 'object') {
96
+ Object.values(v).forEach(joinArrays)
97
+ }
98
+ }
99
+ joinArrays(value)
100
+ return out
101
+ }
102
+
103
+ // The patterns tagged with `context` that match any text, in catalog order. Oversized input
104
+ // is not evaluated (regex cost is unbounded there) and reports TOO_LARGE_HIT instead.
105
+ export function matchPatterns(patterns, texts, context) {
106
+ let total = 0
107
+ for (const t of texts) {
108
+ total += t.length
109
+ if (t.length > LIMITS.maxCandidateChars || total > LIMITS.maxTotalChars) return [TOO_LARGE_HIT]
110
+ }
111
+ return patterns.filter((p) => p.context.includes(context) && texts.some((t) => p.rx.test(t)))
112
+ }
113
+
114
+ // One pattern pass after another until the text stops changing. Each pass can expose a new
115
+ // match (password-in-url can swallow an earlier marker), so a single pass is not enough.
116
+ function fixedPoint(text, patterns, hits) {
117
+ let x = text
118
+ for (let pass = 0; pass <= LIMITS.maxPasses; pass++) {
119
+ let y = x
120
+ for (const p of patterns) {
121
+ y = y.replace(p.rxg, (m) => {
122
+ if (m === '') return m
123
+ hits.add(p)
124
+ return p.marker
125
+ })
126
+ }
127
+ if (y === x) return x
128
+ x = y
129
+ }
130
+ hits.add(OVERFLOW_HIT)
131
+ return OVERFLOW_MARKER
132
+ }
133
+
134
+ // Redacts `s` with `ctx` in front so a secret split across a key and its value, or across
135
+ // argv elements ("Bearer", "<token>"), still matches; then strips the context back off.
136
+ function redactLeaf(s, ctx, patterns, hits) {
137
+ if (ctx === '') return fixedPoint(s, patterns, hits)
138
+ const pre = ctx.slice(-LIMITS.maxContextChars) + ' '
139
+ const y = fixedPoint(pre + s, patterns, hits)
140
+ if (y === OVERFLOW_MARKER) return y
141
+ const r = fixedPoint(pre, patterns, new Set())
142
+ if (y.startsWith(r)) return fixedPoint(y.slice(r.length), patterns, hits)
143
+ // A match spans the boundary: keep from the marker that covers it. Slicing changes
144
+ // anchors and boundaries, so also check the standalone leaf after contextual matching.
145
+ let d = 0
146
+ while (d < r.length && y[d] === r[d]) d++
147
+ const i = y.lastIndexOf(MARKER_PREFIX, d)
148
+ return fixedPoint(i >= 0 ? y.slice(i) : y, patterns, hits)
149
+ }
150
+
151
+ function walk(v, ctx, patterns, hits) {
152
+ if (typeof v === 'string') {
153
+ const local = new Set()
154
+ const out = redactLeaf(v, ctx, patterns, local)
155
+ if (out !== v) for (const h of local) hits.add(h)
156
+ return out
157
+ }
158
+ if (Array.isArray(v)) {
159
+ let prev = null
160
+ return v.map((el) => {
161
+ const out = walk(el, typeof prev === 'string' ? prev : ctx, patterns, hits)
162
+ prev = el
163
+ return out
164
+ })
165
+ }
166
+ if (v !== null && typeof v === 'object') {
167
+ const named = typeof v.name === 'string' ? v.name : typeof v.key === 'string' ? v.key : null
168
+ // fromEntries, not assignment: `out[k] = v` would drop an own "__proto__" key.
169
+ return Object.fromEntries(
170
+ Object.entries(v).map(([k, x]) => [
171
+ walk(k, '', patterns, hits),
172
+ walk(x, k === 'value' && named !== null ? named : k, patterns, hits),
173
+ ]),
174
+ )
175
+ }
176
+ return v
177
+ }
178
+
179
+ // Returns a copy of `value` with every match replaced by `[REDACTED:<id>]`, plus the
180
+ // patterns that fired (catalog order, unique). Keys are redacted too; two keys that redact
181
+ // to the same marker collapse into one, which loses data but never leaks it.
182
+ export function redactValue(value, patterns) {
183
+ const hits = new Set()
184
+ const out = walk(value, '', patterns, hits)
185
+ const order = [...patterns, OVERFLOW_HIT]
186
+ return { value: out, hits: order.filter((p) => hits.has(p)) }
187
+ }
188
+
189
+ // Same shape as `value`, every string replaced by `text`. The fallback when redaction
190
+ // itself failed: withhold everything rather than pass anything through.
191
+ export function maskValue(value, text) {
192
+ if (typeof value === 'string') return text
193
+ if (Array.isArray(value)) return value.map((v) => maskValue(v, text))
194
+ if (value !== null && typeof value === 'object') {
195
+ return Object.fromEntries(Object.entries(value).map(([k, v]) => [k, maskValue(v, text)]))
196
+ }
197
+ return value
198
+ }
199
+
200
+ // JSON with object keys sorted at every level, so equal values hash equally.
201
+ export function canonicalJson(value) {
202
+ if (Array.isArray(value)) return '[' + value.map((v) => (v === undefined ? 'null' : canonicalJson(v))).join(',') + ']'
203
+ if (value !== null && typeof value === 'object') {
204
+ const keys = Object.keys(value).filter((k) => value[k] !== undefined).sort()
205
+ return '{' + keys.map((k) => JSON.stringify(k) + ':' + canonicalJson(value[k])).join(',') + '}'
206
+ }
207
+ return JSON.stringify(value) ?? 'null'
208
+ }
209
+
210
+ export async function sha256Hex(text) {
211
+ const digest = await globalThis.crypto.subtle.digest('SHA-256', new TextEncoder().encode(text))
212
+ return Array.from(new Uint8Array(digest), (b) => b.toString(16).padStart(2, '0')).join('')
213
+ }
@@ -0,0 +1,66 @@
1
+ // Blast Radius Guard logic, shared by the native module and the Node hook so every
2
+ // harness reaches the same verdict. Pure: no I/O, no environment.
3
+ import { candidates, compilePatterns, matchPatterns, parseJson } from './common.mjs'
4
+ import builtin from './patterns.mjs'
5
+
6
+ const PATH_KEYS = new Set(['file_path', 'path', 'notebook_path', 'filePath'])
7
+ const WRITE_TOOL = /write|edit|create|patch|delete|move|rename/i
8
+
9
+ // Built-in patterns, plus the operator's extension appended (never replacing). Throws on
10
+ // bad JSON or shape, or an id reused from the built-ins; callers fail closed.
11
+ export function compileGuardPatterns(extraText, source = 'extension patterns') {
12
+ if (extraText === undefined) return compilePatterns(builtin, 'built-in patterns')
13
+ return compilePatterns([...builtin, ...parseJson(extraText, source)], source)
14
+ }
15
+
16
+ // Only an unset value or exactly `confirm` asks; any other value (typos included) blocks.
17
+ export function modeOf(value) {
18
+ return value === undefined || value === 'confirm' ? 'confirm' : 'block'
19
+ }
20
+
21
+ // Lexical POSIX normalization: no cwd, `..` never climbs above an absolute root.
22
+ export function normalizePosix(p) {
23
+ const abs = p.startsWith('/')
24
+ const out = []
25
+ for (const seg of p.split('/')) {
26
+ if (seg === '' || seg === '.') continue
27
+ if (seg !== '..') out.push(seg)
28
+ else if (out.length > 0 && out[out.length - 1] !== '..') out.pop()
29
+ else if (!abs) out.push('..')
30
+ }
31
+ const body = out.join('/')
32
+ return abs ? '/' + body : body || '.'
33
+ }
34
+
35
+ // String values of path-like keys at any depth.
36
+ function pathValues(value, out = []) {
37
+ if (Array.isArray(value)) value.forEach((v) => pathValues(v, out))
38
+ else if (value !== null && typeof value === 'object') {
39
+ for (const [k, v] of Object.entries(value)) {
40
+ if (PATH_KEYS.has(k) && typeof v === 'string') out.push(v)
41
+ else pathValues(v, out)
42
+ }
43
+ }
44
+ return out
45
+ }
46
+
47
+ // undefined when nothing matched, else the ask/deny verdict naming every pattern hit.
48
+ export function checkToolUse({ tool, input }, patterns, mode) {
49
+ const hits = new Set(matchPatterns(patterns, candidates(input), 'bash'))
50
+ if (typeof tool !== 'string' || WRITE_TOOL.test(tool)) {
51
+ for (const h of matchPatterns(patterns, pathValues(input).map(normalizePosix), 'file-write')) hits.add(h)
52
+ }
53
+ if (hits.size === 0) return undefined
54
+ const names = [...hits].map((h) => h.name)
55
+ return {
56
+ decision: mode === 'confirm' ? 'ask' : 'deny',
57
+ reason: `blast-radius-guard: ${[...new Set(names)].join('; ')}`,
58
+ }
59
+ }
60
+
61
+ // Node harnesses: without a tool_input object (Kiro) the whole payload is scanned.
62
+ export function toolUseFromPayload(payload) {
63
+ const ti = payload.tool_input
64
+ const plain = ti !== null && typeof ti === 'object' && !Array.isArray(ti)
65
+ return { tool: typeof payload.tool_name === 'string' ? payload.tool_name : undefined, input: plain ? ti : payload }
66
+ }
@@ -0,0 +1,102 @@
1
+ // Generated by scripts/generate-mods.mjs from patterns.json. Do not edit.
2
+ export default [
3
+ {
4
+ "id": "rm-rf-root-or-home",
5
+ "name": "rm -r on /, /*, ~, ~/, $HOME or a top-level system dir",
6
+ "description": "rm with a recursive flag (any of -r -R -rf -fr -Rf -rfv, split -r -f, --recursive) AND a whole-token target of / /* ~ ~/ ~/* $HOME ${HOME} (optionally quoted) or a top-level system dir (/etc /usr /var ...). Flag/target order-independent (lookahead AND). Force flag deliberately not required: rm -r / is as destructive. Known FP: the text inside echo/grep/commit messages.",
7
+ "regex": "(?:^|[^A-Za-z0-9_.-])rm(?=[ \\t])(?=[^;&|\\n]*[ \\t](?:-[A-Za-z]*[rR][A-Za-z]*|--recursive)(?![^ \\t\\r\\n;&|)]))(?=[^;&|\\n]*[ \\t][\"']?(?:/(?:(?:bin|boot|dev|etc|home|lib|lib32|lib64|opt|proc|root|sbin|srv|sys|usr|var)/?)?\\*?|~/?\\*?|\\$HOME/?\\*?|\\$\\{HOME\\}/?\\*?)[\"']?(?![^ \\t\\r\\n;&|)]))",
8
+ "flags": "",
9
+ "severity": "critical",
10
+ "context": [
11
+ "bash"
12
+ ]
13
+ },
14
+ {
15
+ "id": "sql-drop-object",
16
+ "name": "SQL DROP TABLE/DATABASE/SCHEMA",
17
+ "description": "DROP followed by whitespace/newline and TABLE|DATABASE|SCHEMA, case-insensitive, left/right word-bounded. Matches the SQL text inside psql -c / mysql -e / sqlcmd -Q strings. Does not see SQL inside files (psql -f x.sql) nor the dropdb CLI.",
18
+ "regex": "(?:^|[^A-Za-z0-9_])drop[ \\t\\r\\n]+(?:table|database|schema)(?![A-Za-z0-9_])",
19
+ "flags": "i",
20
+ "severity": "critical",
21
+ "context": [
22
+ "bash"
23
+ ]
24
+ },
25
+ {
26
+ "id": "git-force-push-protected",
27
+ "name": "git push --force / -f / --force-with-lease / +refspec to protected branch",
28
+ "description": "git [global opts] push with (a force flag AND a protected-branch token) OR a +refspec of a protected branch. Protected = main, master, release/*, prod, production, prod-*, prod_*, prod/*. Branch token may be bare, src:dst, or refs/heads/*. --force-with-lease IS included: the lease only guards against clobbering unseen commits, it still rewrites protected history. 'prod*' from the spec narrowed so product-page does not match. Bare 'git push -f' (current branch unknown) is NOT matched.",
29
+ "regex": "(?:^|[^A-Za-z0-9_.-])git(?:[ \\t]+-[^ \\t\\r\\n;&|]+(?:[ \\t]+[^ \\t\\r\\n;&|-][^ \\t\\r\\n;&|]*)?){0,6}[ \\t]+push(?![A-Za-z0-9_-])(?:(?=[^;&|\\n]*[ \\t](?:--force(?:-with-lease|-if-includes)?(?:=[^ \\t\\r\\n;&|]*)?|-[A-Za-z]*f[A-Za-z]*)(?![^ \\t\\r\\n;&|)]))(?=[^;&|\\n]*[ \\t][\"']?\\+?(?:[^ \\t\\r\\n;&|:]*:)?(?:refs/heads/)?(?:main|master|release/[^ \\t\\r\\n;&|\"']+|prod(?:uction)?|prod[-_/][^ \\t\\r\\n;&|\"']*)[\"']?(?![^ \\t\\r\\n;&|)]))|(?=[^;&|\\n]*[ \\t][\"']?\\+(?:[^ \\t\\r\\n;&|:]*:)?(?:refs/heads/)?(?:main|master|release/[^ \\t\\r\\n;&|\"']+|prod(?:uction)?|prod[-_/][^ \\t\\r\\n;&|\"']*)[\"']?(?![^ \\t\\r\\n;&|)])))",
30
+ "flags": "",
31
+ "severity": "high",
32
+ "context": [
33
+ "bash"
34
+ ]
35
+ },
36
+ {
37
+ "id": "pipe-remote-to-shell",
38
+ "name": "curl|wget piped to a shell",
39
+ "description": "curl or wget whose output is piped (possibly through intermediate filters) into sh/bash/zsh/dash/ksh/csh, optionally via sudo/env and an absolute path. '||' is not treated as a pipe. Interpreters other than shells (python, node, perl) are not covered.",
40
+ "regex": "(?:^|[^A-Za-z0-9_.-])(?:curl|wget)(?![A-Za-z0-9_-])[^;&\\n|]*(?:\\|(?!\\|)[^;&\\n|]*)*\\|(?!\\|)[ \\t]*(?:sudo(?:[ \\t]+-[^ \\t\\r\\n;&|]+(?:[ \\t]+[^ \\t\\r\\n;&|-][^ \\t\\r\\n;&|]*)?){0,4}[ \\t]+|env[ \\t]+)?(?:/[A-Za-z0-9_./-]*/)?(?:ba|z|da|k|c)?sh(?![A-Za-z0-9_.-])",
41
+ "flags": "",
42
+ "severity": "high",
43
+ "context": [
44
+ "bash"
45
+ ]
46
+ },
47
+ {
48
+ "id": "remote-script-substitution",
49
+ "name": "shell/source/eval of curl|wget command substitution",
50
+ "description": "bash <(curl ...), sh -c \"$(curl ...)\", eval \"$(wget ...)\", source <(curl ...), . <(curl ...). Same threat as pipe-to-shell via process/command substitution.",
51
+ "regex": "(?:^|[^A-Za-z0-9_.-])(?:(?:ba|z|da|k)?sh(?:[ \\t]+-[A-Za-z]+)*|source|eval|\\.)[ \\t]+[\"']?(?:<\\(|\\$\\()[ \\t]*(?:curl|wget)(?![A-Za-z0-9_-])",
52
+ "flags": "",
53
+ "severity": "high",
54
+ "context": [
55
+ "bash"
56
+ ]
57
+ },
58
+ {
59
+ "id": "terraform-destroy-auto-approve",
60
+ "name": "terraform/tofu/terragrunt destroy with -auto-approve",
61
+ "description": "terraform|tofu|terragrunt with a destroy token (destroy or -destroy, so 'apply -destroy' is included) AND -auto-approve/--auto-approve, in either order. Plain 'terraform destroy' (interactive confirm; no TTY in agent shells) and plain 'terraform apply -auto-approve' are deliberately NOT matched: apply is covered by live-guard-gate, and matching all auto-approved applies would double-prompt and flag routine CI-style usage.",
62
+ "regex": "(?:^|[^A-Za-z0-9_.-])(?:terraform|tofu|terragrunt)(?![A-Za-z0-9_-])(?=[^;&|\\n]*[ \\t]-?destroy(?![^ \\t\\r\\n;&|)]))(?=[^;&|\\n]*[ \\t]--?auto-approve(?:=[^ \\t\\r\\n;&|]*)?(?![^ \\t\\r\\n;&|)]))",
63
+ "flags": "",
64
+ "severity": "critical",
65
+ "context": [
66
+ "bash"
67
+ ]
68
+ },
69
+ {
70
+ "id": "kubectl-delete-namespace",
71
+ "name": "kubectl/oc delete namespace",
72
+ "description": "kubectl|oc ... delete [flags] namespace|namespaces|ns (also ns/<name>). Flags between delete and the resource kind are allowed (--force --grace-period=0).",
73
+ "regex": "(?:^|[^A-Za-z0-9_.-])(?:kubectl|oc)(?![A-Za-z0-9_-])(?:[ \\t]+-[^ \\t\\r\\n;&|]+(?:[ \\t]+[^ \\t\\r\\n;&|-][^ \\t\\r\\n;&|]*)?){0,8}[ \\t]+delete(?:[ \\t]+-[^ \\t\\r\\n;&|]+(?:[ \\t]+[^ \\t\\r\\n;&|-][^ \\t\\r\\n;&|]*)?){0,6}[ \\t]+(?:namespaces?|ns)(?:/|,|(?![^ \\t\\r\\n;&|)]))",
74
+ "flags": "",
75
+ "severity": "critical",
76
+ "context": [
77
+ "bash"
78
+ ]
79
+ },
80
+ {
81
+ "id": "kubectl-delete-all",
82
+ "name": "kubectl/oc delete ... --all",
83
+ "description": "kubectl|oc with a delete token AND --all (or --all=true). --all-namespaces is excluded by the terminator check.",
84
+ "regex": "(?:^|[^A-Za-z0-9_.-])(?:kubectl|oc)(?![A-Za-z0-9_-])(?:[ \\t]+-[^ \\t\\r\\n;&|]+(?:[ \\t]+[^ \\t\\r\\n;&|-][^ \\t\\r\\n;&|]*)?){0,8}[ \\t]+delete(?![^ \\t\\r\\n;&|)])(?=[^;&|\\n]*[ \\t]--all(?:=[^ \\t\\r\\n;&|]*)?(?![^ \\t\\r\\n;&|)]))",
85
+ "flags": "",
86
+ "severity": "high",
87
+ "context": [
88
+ "bash"
89
+ ]
90
+ },
91
+ {
92
+ "id": "file-write-system-path",
93
+ "name": "File write into a system directory",
94
+ "description": "Anchored at path start: /etc/ /usr/ /bin/ /sbin/ /boot/ /sys/ /proc/ (leading // tolerated). Anchoring avoids matching myproject/etc/x or /home/u/usr/x, which the spec's unanchored /(etc|usr|...)/ would. The caller MUST resolve the path (path.resolve / realpath -m) first; ../../etc/passwd or symlinks are not caught by the pattern.",
95
+ "regex": "^/+(?:etc|usr|bin|sbin|boot|sys|proc)/",
96
+ "flags": "",
97
+ "severity": "critical",
98
+ "context": [
99
+ "file-write"
100
+ ]
101
+ }
102
+ ];