damage-control-dev 0.1.0__py3-none-any.whl

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 (74) hide show
  1. damage_control/__init__.py +9 -0
  2. damage_control/__main__.py +7 -0
  3. damage_control/adapter.py +179 -0
  4. damage_control/audit.py +432 -0
  5. damage_control/breakglass.py +155 -0
  6. damage_control/claude_code.py +148 -0
  7. damage_control/cli.py +173 -0
  8. damage_control/engine.py +10656 -0
  9. damage_control/groups.py +114 -0
  10. damage_control/harness_config.py +205 -0
  11. damage_control/hook.py +54 -0
  12. damage_control/install.py +618 -0
  13. damage_control/packs.py +219 -0
  14. damage_control/policy.py +323 -0
  15. damage_control/profile.py +177 -0
  16. damage_control/rules/aws.json +85 -0
  17. damage_control/rules/aws.yaml +76 -0
  18. damage_control/rules/cloud-hosting.json +162 -0
  19. damage_control/rules/cloud-hosting.yaml +163 -0
  20. damage_control/rules/containers.json +67 -0
  21. damage_control/rules/containers.yaml +69 -0
  22. damage_control/rules/control-plane.json +7 -0
  23. damage_control/rules/control-plane.yaml +21 -0
  24. damage_control/rules/core.json +332 -0
  25. damage_control/rules/core.yaml +441 -0
  26. damage_control/rules/databases.json +117 -0
  27. damage_control/rules/databases.yaml +123 -0
  28. damage_control/rules/firebase.json +34 -0
  29. damage_control/rules/firebase.yaml +30 -0
  30. damage_control/rules/gcp.json +60 -0
  31. damage_control/rules/gcp.yaml +57 -0
  32. damage_control/rules/git.json +119 -0
  33. damage_control/rules/git.yaml +120 -0
  34. damage_control/rules/infrastructure.json +69 -0
  35. damage_control/rules/infrastructure.yaml +66 -0
  36. damage_control/rules/mcp-tools.json +11 -0
  37. damage_control/rules/mcp-tools.yaml +47 -0
  38. damage_control/rules/outbound.json +40 -0
  39. damage_control/rules/outbound.yaml +58 -0
  40. damage_control/rules/payloads.json +120 -0
  41. damage_control/rules/payloads.yaml +155 -0
  42. damage_control/rules/publish.json +46 -0
  43. damage_control/rules/publish.yaml +46 -0
  44. damage_control/rules/registry.json +10 -0
  45. damage_control/rules/registry.yaml +11 -0
  46. damage_control/rules/remote.json +31 -0
  47. damage_control/rules/remote.yaml +53 -0
  48. damage_control/rules/tmux.json +17 -0
  49. damage_control/rules/tmux.yaml +16 -0
  50. damage_control/ruleset.py +94 -0
  51. damage_control/tooldefs/aws.json +140 -0
  52. damage_control/tooldefs/aws.yaml +119 -0
  53. damage_control/tooldefs/docker.json +146 -0
  54. damage_control/tooldefs/docker.yaml +123 -0
  55. damage_control/tooldefs/gcp.json +186 -0
  56. damage_control/tooldefs/gcp.yaml +158 -0
  57. damage_control/tooldefs/gh.json +172 -0
  58. damage_control/tooldefs/gh.yaml +145 -0
  59. damage_control/tooldefs/git.json +166 -0
  60. damage_control/tooldefs/git.yaml +143 -0
  61. damage_control/tooldefs/kubectl.json +101 -0
  62. damage_control/tooldefs/kubectl.yaml +85 -0
  63. damage_control/tooldefs/npm.json +77 -0
  64. damage_control/tooldefs/npm.yaml +65 -0
  65. damage_control/tooldefs/terraform.json +68 -0
  66. damage_control/tooldefs/terraform.yaml +57 -0
  67. damage_control/tooldefs/uv.json +112 -0
  68. damage_control/tooldefs/uv.yaml +97 -0
  69. damage_control_dev-0.1.0.dist-info/METADATA +15 -0
  70. damage_control_dev-0.1.0.dist-info/RECORD +74 -0
  71. damage_control_dev-0.1.0.dist-info/WHEEL +4 -0
  72. damage_control_dev-0.1.0.dist-info/entry_points.txt +2 -0
  73. damage_control_dev-0.1.0.dist-info/licenses/LICENSE +201 -0
  74. damage_control_dev-0.1.0.dist-info/licenses/NOTICE +4 -0
@@ -0,0 +1,34 @@
1
+ {
2
+ "bashToolPatterns": [
3
+ {
4
+ "id": "firebase.firebase-projects-delete-deletes-entire-project",
5
+ "pattern": "\\bfirebase\\s+projects:delete\\b",
6
+ "reason": "firebase projects:delete (deletes entire project)",
7
+ "anchored": true
8
+ },
9
+ {
10
+ "id": "firebase.firebase-firestore-delete-all-collections-wipes-all-data",
11
+ "pattern": "\\bfirebase\\s+firestore:delete\\s+.*--all-collections",
12
+ "reason": "firebase firestore:delete --all-collections (wipes all data)",
13
+ "anchored": true
14
+ },
15
+ {
16
+ "id": "firebase.firebase-database-remove-wipes-realtime-db",
17
+ "pattern": "\\bfirebase\\s+database:remove\\b",
18
+ "reason": "firebase database:remove (wipes Realtime DB)",
19
+ "anchored": true
20
+ },
21
+ {
22
+ "id": "firebase.firebase-hosting-disable",
23
+ "pattern": "\\bfirebase\\s+hosting:disable\\b",
24
+ "reason": "firebase hosting:disable",
25
+ "anchored": true
26
+ },
27
+ {
28
+ "id": "firebase.firebase-functions-delete",
29
+ "pattern": "\\bfirebase\\s+functions:delete\\b",
30
+ "reason": "firebase functions:delete",
31
+ "anchored": true
32
+ }
33
+ ]
34
+ }
@@ -0,0 +1,30 @@
1
+ # Firebase CLI damage control rules
2
+
3
+ bashToolPatterns:
4
+ # ---------------------------------------------------------------------------
5
+ # FIREBASE DESTRUCTIVE OPERATIONS
6
+ # ---------------------------------------------------------------------------
7
+ - id: firebase.firebase-projects-delete-deletes-entire-project
8
+ pattern: '\bfirebase\s+projects:delete\b'
9
+ reason: firebase projects:delete (deletes entire project)
10
+ anchored: true
11
+
12
+ - id: firebase.firebase-firestore-delete-all-collections-wipes-all-data
13
+ pattern: '\bfirebase\s+firestore:delete\s+.*--all-collections'
14
+ reason: firebase firestore:delete --all-collections (wipes all data)
15
+ anchored: true
16
+
17
+ - id: firebase.firebase-database-remove-wipes-realtime-db
18
+ pattern: '\bfirebase\s+database:remove\b'
19
+ reason: firebase database:remove (wipes Realtime DB)
20
+ anchored: true
21
+
22
+ - id: firebase.firebase-hosting-disable
23
+ pattern: '\bfirebase\s+hosting:disable\b'
24
+ reason: firebase hosting:disable
25
+ anchored: true
26
+
27
+ - id: firebase.firebase-functions-delete
28
+ pattern: '\bfirebase\s+functions:delete\b'
29
+ reason: firebase functions:delete
30
+ anchored: true
@@ -0,0 +1,60 @@
1
+ {
2
+ "bashToolPatterns": [
3
+ {
4
+ "id": "gcp.gcloud-projects-delete-deletes-entire-project",
5
+ "pattern": "\\bgcloud\\s+projects\\s+delete\\b",
6
+ "reason": "gcloud projects delete (DELETES ENTIRE PROJECT)",
7
+ "anchored": true
8
+ },
9
+ {
10
+ "id": "gcp.gcloud-compute-instances-delete",
11
+ "pattern": "\\bgcloud\\s+compute\\s+instances\\s+delete\\b",
12
+ "reason": "gcloud compute instances delete",
13
+ "anchored": true
14
+ },
15
+ {
16
+ "id": "gcp.gcloud-sql-instances-delete",
17
+ "pattern": "\\bgcloud\\s+sql\\s+instances\\s+delete\\b",
18
+ "reason": "gcloud sql instances delete",
19
+ "anchored": true
20
+ },
21
+ {
22
+ "id": "gcp.gcloud-container-clusters-delete-gke",
23
+ "pattern": "\\bgcloud\\s+container\\s+clusters\\s+delete\\b",
24
+ "reason": "gcloud container clusters delete (GKE)",
25
+ "anchored": true
26
+ },
27
+ {
28
+ "id": "gcp.gcloud-storage-rm-r-recursive-delete",
29
+ "pattern": "\\bgcloud\\s+storage\\s+rm\\s+.*-r",
30
+ "reason": "gcloud storage rm -r (recursive delete)",
31
+ "anchored": true
32
+ },
33
+ {
34
+ "id": "gcp.gcloud-functions-delete",
35
+ "pattern": "\\bgcloud\\s+functions\\s+delete\\b",
36
+ "reason": "gcloud functions delete",
37
+ "anchored": true
38
+ },
39
+ {
40
+ "id": "gcp.gcloud-iam-service-accounts-delete",
41
+ "pattern": "\\bgcloud\\s+iam\\s+service-accounts\\s+delete\\b",
42
+ "reason": "gcloud iam service-accounts delete",
43
+ "anchored": true
44
+ },
45
+ {
46
+ "pattern": "\\bgcloud\\s+run\\s+deploy\\b",
47
+ "reason": "gcloud run deploy (ships a Cloud Run service)",
48
+ "ask": true,
49
+ "id": "deploy.gcloud-run",
50
+ "anchored": true
51
+ },
52
+ {
53
+ "pattern": "\\bgcloud\\s+app\\s+deploy\\b",
54
+ "reason": "gcloud app deploy (ships an App Engine version)",
55
+ "ask": true,
56
+ "id": "deploy.gcloud-app",
57
+ "anchored": true
58
+ }
59
+ ]
60
+ }
@@ -0,0 +1,57 @@
1
+ # GCP (gcloud) damage control rules
2
+
3
+ bashToolPatterns:
4
+ # ---------------------------------------------------------------------------
5
+ # GCP (gcloud) DESTRUCTIVE OPERATIONS
6
+ # ---------------------------------------------------------------------------
7
+ - id: gcp.gcloud-projects-delete-deletes-entire-project
8
+ pattern: '\bgcloud\s+projects\s+delete\b'
9
+ reason: gcloud projects delete (DELETES ENTIRE PROJECT)
10
+ anchored: true
11
+
12
+ - id: gcp.gcloud-compute-instances-delete
13
+ pattern: '\bgcloud\s+compute\s+instances\s+delete\b'
14
+ reason: gcloud compute instances delete
15
+ anchored: true
16
+
17
+ - id: gcp.gcloud-sql-instances-delete
18
+ pattern: '\bgcloud\s+sql\s+instances\s+delete\b'
19
+ reason: gcloud sql instances delete
20
+ anchored: true
21
+
22
+ - id: gcp.gcloud-container-clusters-delete-gke
23
+ pattern: '\bgcloud\s+container\s+clusters\s+delete\b'
24
+ reason: gcloud container clusters delete (GKE)
25
+ anchored: true
26
+
27
+ - id: gcp.gcloud-storage-rm-r-recursive-delete
28
+ pattern: '\bgcloud\s+storage\s+rm\s+.*-r'
29
+ reason: gcloud storage rm -r (recursive delete)
30
+ anchored: true
31
+
32
+ - id: gcp.gcloud-functions-delete
33
+ pattern: '\bgcloud\s+functions\s+delete\b'
34
+ reason: gcloud functions delete
35
+ anchored: true
36
+
37
+ - id: gcp.gcloud-iam-service-accounts-delete
38
+ pattern: '\bgcloud\s+iam\s+service-accounts\s+delete\b'
39
+ reason: gcloud iam service-accounts delete
40
+ anchored: true
41
+
42
+ # ---------------------------------------------------------------------------
43
+ # GCP DEPLOYS (ask: true — outward-facing, caught in unattended sessions)
44
+ # ---------------------------------------------------------------------------
45
+ # `gcloud functions deploy` is already ask-tier via the gcp tooldef; these
46
+ # cover the other deploy surfaces (Cloud Run, App Engine).
47
+ - pattern: '\bgcloud\s+run\s+deploy\b'
48
+ reason: gcloud run deploy (ships a Cloud Run service)
49
+ ask: true
50
+ id: deploy.gcloud-run
51
+ anchored: true
52
+
53
+ - pattern: '\bgcloud\s+app\s+deploy\b'
54
+ reason: gcloud app deploy (ships an App Engine version)
55
+ ask: true
56
+ id: deploy.gcloud-app
57
+ anchored: true
@@ -0,0 +1,119 @@
1
+ {
2
+ "bashToolPatterns": [
3
+ {
4
+ "id": "git.git-reset-hard-use-soft-or-stash",
5
+ "pattern": "\\bgit\\s+reset\\s+(?:(?!--(?:\\s|$))[^\\s;&|]+\\s+)*?--hard\\b",
6
+ "pattern_src": "\\bgit\\s+reset\\s+{ARGS}--hard\\b",
7
+ "reason": "git reset --hard (use --soft or stash)",
8
+ "anchored": true
9
+ },
10
+ {
11
+ "id": "git.git-clean-with-force-directory-flags",
12
+ "pattern": "\\bgit\\s+clean\\s+(?!(?:[^;&|]*\\s)?(?:-(?!-)[a-z]*n[a-z]*(?=[\\s;&|)`]|$)|--dry-run\\b))(?:(?!--(?:\\s|$))[^\\s;&|]+\\s+)*?(?:-(?!-)[a-z]*[fd][a-z]*|--force)(?=[\\s;&|)`]|$)",
13
+ "pattern_src": "\\bgit\\s+clean\\s+(?!(?:[^;&|]*\\s)?(?:-(?!-)[a-z]*n[a-z]*(?=[\\s;&|)`]|$)|--dry-run\\b)){ARGS}(?:-(?!-)[a-z]*[fd][a-z]*|--force)(?=[\\s;&|)`]|$)",
14
+ "reason": "git clean with force/directory flags",
15
+ "anchored": true
16
+ },
17
+ {
18
+ "id": "git.git-push-force-use-force-with-lease",
19
+ "pattern": "\\bgit\\s+push\\s+.*--force(?!-with-lease)",
20
+ "reason": "git push --force (use --force-with-lease)",
21
+ "anchored": true
22
+ },
23
+ {
24
+ "id": "git.git-push-f-use-force-with-lease",
25
+ "pattern": "\\bgit\\s+push\\s+(?:(?!--(?:\\s|$))[^\\s;&|]+\\s+)*?-(?!-)[a-z]*f[a-z]*(?=[\\s;&|)`]|$)",
26
+ "pattern_src": "\\bgit\\s+push\\s+{ARGS}-(?!-)[a-z]*f[a-z]*(?=[\\s;&|)`]|$)",
27
+ "reason": "git push -f (use --force-with-lease)",
28
+ "anchored": true
29
+ },
30
+ {
31
+ "id": "git.git-stash-clear-deletes-all-stashes",
32
+ "pattern": "\\bgit\\s+stash\\s+clear\\b",
33
+ "reason": "git stash clear (deletes ALL stashes)",
34
+ "anchored": true
35
+ },
36
+ {
37
+ "id": "git.git-reflog-expire-destroys-recovery-mechanism",
38
+ "pattern": "\\bgit\\s+reflog\\s+expire\\b",
39
+ "reason": "git reflog expire (destroys recovery mechanism)",
40
+ "anchored": true
41
+ },
42
+ {
43
+ "id": "git.git-gc-prune-now-can-lose-dangling-commits",
44
+ "pattern": "\\bgit\\s+gc\\s+.*--prune=now",
45
+ "reason": "git gc --prune=now (can lose dangling commits)",
46
+ "anchored": true
47
+ },
48
+ {
49
+ "id": "git.git-filter-branch-rewrites-entire-history",
50
+ "pattern": "\\bgit\\s+filter-branch\\b",
51
+ "reason": "git filter-branch (rewrites entire history)",
52
+ "anchored": true
53
+ },
54
+ {
55
+ "id": "git.discards-all-uncommitted-changes",
56
+ "pattern": "\\bgit\\s+checkout\\s+--\\s*\\.",
57
+ "reason": "Discards all uncommitted changes",
58
+ "ask": true,
59
+ "anchored": true
60
+ },
61
+ {
62
+ "id": "git.discards-all-uncommitted-changes-2",
63
+ "pattern": "\\bgit\\s+restore\\s+\\.",
64
+ "reason": "Discards all uncommitted changes",
65
+ "ask": true,
66
+ "anchored": true
67
+ },
68
+ {
69
+ "id": "git.rm-tracked-files",
70
+ "pattern": "\\bgit\\s+rm\\b(?!.*--cached)",
71
+ "reason": "git rm deletes tracked files (use rm of a clean file, or confirm)",
72
+ "ask": true,
73
+ "anchored": true
74
+ },
75
+ {
76
+ "id": "git.config-set-redirect-key",
77
+ "pattern": "\\bgit\\s+config\\b(?![^;&|]*\\s(?:--(?:get|unset|list|edit)|-l\\b|-e\\b))[^;&|]*?\\s(?:core\\.(?:worktree|hookspath)|include\\.path|includeif\\.\\S+\\.path)\\s+\\S",
78
+ "reason": "git config redirects the worktree, hooks dir, or an included config",
79
+ "ask": true,
80
+ "anchored": true
81
+ },
82
+ {
83
+ "id": "git.permanently-deletes-a-stash",
84
+ "pattern": "\\bgit\\s+stash\\s+drop\\b",
85
+ "reason": "Permanently deletes a stash",
86
+ "ask": true,
87
+ "anchored": true
88
+ },
89
+ {
90
+ "id": "git.force-deletes-branch-even-if-unmerged",
91
+ "pattern": "\\bgit\\s+branch\\s+(?:(?:(?!--(?:\\s|$))[^\\s;&|]+\\s+)*?-(?!-)[a-z]*(?-i:D)[a-z]*(?=[\\s;&|)`]|$)|(?=(?:[^;&|]*\\s)?(?:-(?!-)[a-z]*d[a-z]*|--delete)(?=[\\s;&|)`]|$))(?=(?:[^;&|]*\\s)?(?:-(?!-)[a-z]*f[a-z]*|--force)(?=[\\s;&|)`]|$)))",
92
+ "pattern_src": "\\bgit\\s+branch\\s+(?:{ARGS}-(?!-)[a-z]*(?-i:D)[a-z]*(?=[\\s;&|)`]|$)|(?=(?:[^;&|]*\\s)?(?:-(?!-)[a-z]*d[a-z]*|--delete)(?=[\\s;&|)`]|$))(?=(?:[^;&|]*\\s)?(?:-(?!-)[a-z]*f[a-z]*|--force)(?=[\\s;&|)`]|$)))",
93
+ "reason": "Force deletes branch (even if unmerged)",
94
+ "ask": true,
95
+ "anchored": true
96
+ },
97
+ {
98
+ "id": "git.deletes-remote-branch",
99
+ "pattern": "\\bgit\\s+push\\s+(?:(?!--(?:\\s|$))[^\\s;&|]+\\s+)*?--delete\\b",
100
+ "pattern_src": "\\bgit\\s+push\\s+{ARGS}--delete\\b",
101
+ "reason": "Deletes remote branch",
102
+ "ask": true,
103
+ "anchored": true
104
+ },
105
+ {
106
+ "id": "git.deletes-remote-branch-old-syntax",
107
+ "pattern": "\\bgit\\s+push\\s+\\S+\\s+:\\S+",
108
+ "reason": "Deletes remote branch (old syntax)",
109
+ "ask": true,
110
+ "anchored": true
111
+ },
112
+ {
113
+ "id": "git.gh-repo-delete-deletes-repository",
114
+ "pattern": "\\bgh\\s+repo\\s+delete\\b",
115
+ "reason": "gh repo delete (deletes repository)",
116
+ "anchored": true
117
+ }
118
+ ]
119
+ }
@@ -0,0 +1,120 @@
1
+ # Git damage control rules
2
+ # Destructive and confirmation-required git operations
3
+
4
+ bashToolPatterns:
5
+ # ---------------------------------------------------------------------------
6
+ # GIT DESTRUCTIVE OPERATIONS
7
+ # ---------------------------------------------------------------------------
8
+ - id: git.git-reset-hard-use-soft-or-stash
9
+ pattern: '\bgit\s+reset\s+(?:(?!--(?:\s|$))[^\s;&|]+\s+)*?--hard\b'
10
+ pattern_src: '\bgit\s+reset\s+{ARGS}--hard\b'
11
+ reason: git reset --hard (use --soft or stash)
12
+ anchored: true
13
+
14
+ - id: git.git-clean-with-force-directory-flags
15
+ pattern: '\bgit\s+clean\s+(?!(?:[^;&|]*\s)?(?:-(?!-)[a-z]*n[a-z]*(?=[\s;&|)`]|$)|--dry-run\b))(?:(?!--(?:\s|$))[^\s;&|]+\s+)*?(?:-(?!-)[a-z]*[fd][a-z]*|--force)(?=[\s;&|)`]|$)'
16
+ pattern_src: '\bgit\s+clean\s+(?!(?:[^;&|]*\s)?(?:-(?!-)[a-z]*n[a-z]*(?=[\s;&|)`]|$)|--dry-run\b)){ARGS}(?:-(?!-)[a-z]*[fd][a-z]*|--force)(?=[\s;&|)`]|$)'
17
+ reason: git clean with force/directory flags
18
+ anchored: true
19
+
20
+ # Note: This blocks --force but NOT --force-with-lease
21
+ - id: git.git-push-force-use-force-with-lease
22
+ pattern: '\bgit\s+push\s+.*--force(?!-with-lease)'
23
+ reason: git push --force (use --force-with-lease)
24
+ anchored: true
25
+
26
+ - id: git.git-push-f-use-force-with-lease
27
+ pattern: '\bgit\s+push\s+(?:(?!--(?:\s|$))[^\s;&|]+\s+)*?-(?!-)[a-z]*f[a-z]*(?=[\s;&|)`]|$)'
28
+ pattern_src: '\bgit\s+push\s+{ARGS}-(?!-)[a-z]*f[a-z]*(?=[\s;&|)`]|$)'
29
+ reason: git push -f (use --force-with-lease)
30
+ anchored: true
31
+
32
+ - id: git.git-stash-clear-deletes-all-stashes
33
+ pattern: '\bgit\s+stash\s+clear\b'
34
+ reason: git stash clear (deletes ALL stashes)
35
+ anchored: true
36
+
37
+ - id: git.git-reflog-expire-destroys-recovery-mechanism
38
+ pattern: '\bgit\s+reflog\s+expire\b'
39
+ reason: git reflog expire (destroys recovery mechanism)
40
+ anchored: true
41
+
42
+ - id: git.git-gc-prune-now-can-lose-dangling-commits
43
+ pattern: '\bgit\s+gc\s+.*--prune=now'
44
+ reason: git gc --prune=now (can lose dangling commits)
45
+ anchored: true
46
+
47
+ - id: git.git-filter-branch-rewrites-entire-history
48
+ pattern: '\bgit\s+filter-branch\b'
49
+ reason: git filter-branch (rewrites entire history)
50
+ anchored: true
51
+
52
+ # ---------------------------------------------------------------------------
53
+ # GIT OPERATIONS REQUIRING CONFIRMATION (ask: true)
54
+ # ---------------------------------------------------------------------------
55
+ - id: git.discards-all-uncommitted-changes
56
+ pattern: '\bgit\s+checkout\s+--\s*\.'
57
+ reason: Discards all uncommitted changes
58
+ ask: true
59
+ anchored: true
60
+
61
+ - id: git.discards-all-uncommitted-changes-2
62
+ pattern: '\bgit\s+restore\s+\.'
63
+ reason: Discards all uncommitted changes
64
+ ask: true
65
+ anchored: true
66
+
67
+ # `git rm` deletes tracked files from the working tree AND the index; unlike a
68
+ # plain rm of a clean file it is a deliberate history-shaping act, rarely
69
+ # right for an agent. `--cached` only unstages (the file stays), so it passes.
70
+ - id: git.rm-tracked-files
71
+ pattern: '\bgit\s+rm\b(?!.*--cached)'
72
+ reason: git rm deletes tracked files (use rm of a clean file, or confirm)
73
+ ask: true
74
+ anchored: true
75
+
76
+ # SET-FORM config (`git config [--global] <key> <value>`, #1133/#9/#28): the
77
+ # same keys `git -c` is asked about (git.config-exec-key), plus the keys that
78
+ # REDIRECT git itself. Reads (`--get*`, `--list`, `--unset*`, `--edit`) and a
79
+ # keyless/valueless call never match.
80
+ # 1) Redirect keys: no benign value exists, always ask.
81
+ - id: git.config-set-redirect-key
82
+ pattern: '\bgit\s+config\b(?![^;&|]*\s(?:--(?:get|unset|list|edit)|-l\b|-e\b))[^;&|]*?\s(?:core\.(?:worktree|hookspath)|include\.path|includeif\.\S+\.path)\s+\S'
83
+ reason: git config redirects the worktree, hooks dir, or an included config
84
+ ask: true
85
+ anchored: true
86
+
87
+ - id: git.permanently-deletes-a-stash
88
+ pattern: '\bgit\s+stash\s+drop\b'
89
+ reason: Permanently deletes a stash
90
+ ask: true
91
+ anchored: true
92
+
93
+ - id: git.force-deletes-branch-even-if-unmerged
94
+ pattern: '\bgit\s+branch\s+(?:(?:(?!--(?:\s|$))[^\s;&|]+\s+)*?-(?!-)[a-z]*(?-i:D)[a-z]*(?=[\s;&|)`]|$)|(?=(?:[^;&|]*\s)?(?:-(?!-)[a-z]*d[a-z]*|--delete)(?=[\s;&|)`]|$))(?=(?:[^;&|]*\s)?(?:-(?!-)[a-z]*f[a-z]*|--force)(?=[\s;&|)`]|$)))'
95
+ pattern_src: '\bgit\s+branch\s+(?:{ARGS}-(?!-)[a-z]*(?-i:D)[a-z]*(?=[\s;&|)`]|$)|(?=(?:[^;&|]*\s)?(?:-(?!-)[a-z]*d[a-z]*|--delete)(?=[\s;&|)`]|$))(?=(?:[^;&|]*\s)?(?:-(?!-)[a-z]*f[a-z]*|--force)(?=[\s;&|)`]|$)))'
96
+ reason: Force deletes branch (even if unmerged)
97
+ ask: true
98
+ anchored: true
99
+
100
+ - id: git.deletes-remote-branch
101
+ pattern: '\bgit\s+push\s+(?:(?!--(?:\s|$))[^\s;&|]+\s+)*?--delete\b'
102
+ pattern_src: '\bgit\s+push\s+{ARGS}--delete\b'
103
+ reason: Deletes remote branch
104
+ ask: true
105
+ anchored: true
106
+
107
+ - id: git.deletes-remote-branch-old-syntax
108
+ pattern: '\bgit\s+push\s+\S+\s+:\S+'
109
+ reason: Deletes remote branch (old syntax)
110
+ ask: true
111
+ anchored: true
112
+
113
+ # ---------------------------------------------------------------------------
114
+ # GITHUB CLI DESTRUCTIVE OPERATIONS (default-on: moved out of the cloud-hosting
115
+ # pack so a fresh install keeps it, #1141)
116
+ # ---------------------------------------------------------------------------
117
+ - id: git.gh-repo-delete-deletes-repository
118
+ pattern: '\bgh\s+repo\s+delete\b'
119
+ reason: gh repo delete (deletes repository)
120
+ anchored: true
@@ -0,0 +1,69 @@
1
+ {
2
+ "bashToolPatterns": [
3
+ {
4
+ "id": "infrastructure.terraform-destroy-destroys-all-infrastructure",
5
+ "pattern": "\\bterraform\\s+destroy\\b",
6
+ "reason": "terraform destroy (destroys all infrastructure)",
7
+ "anchored": true
8
+ },
9
+ {
10
+ "id": "infrastructure.pulumi-destroy-destroys-all-resources",
11
+ "pattern": "\\bpulumi\\s+destroy\\b",
12
+ "reason": "pulumi destroy (destroys all resources)",
13
+ "anchored": true
14
+ },
15
+ {
16
+ "id": "infrastructure.serverless-remove-removes-stack",
17
+ "pattern": "\\bserverless\\s+remove\\b",
18
+ "reason": "serverless remove (removes stack)",
19
+ "anchored": true
20
+ },
21
+ {
22
+ "id": "infrastructure.sls-remove-removes-stack",
23
+ "pattern": "\\bsls\\s+remove\\b",
24
+ "reason": "sls remove (removes stack)",
25
+ "anchored": true
26
+ },
27
+ {
28
+ "id": "infrastructure.sam-delete-deletes-sam-application",
29
+ "pattern": "\\bsam\\s+delete\\b",
30
+ "reason": "sam delete (deletes SAM application)",
31
+ "anchored": true
32
+ },
33
+ {
34
+ "pattern": "\\bpulumi\\s+up\\b",
35
+ "reason": "pulumi up (provisions/updates infrastructure)",
36
+ "ask": true,
37
+ "id": "deploy.pulumi-up",
38
+ "anchored": true
39
+ },
40
+ {
41
+ "pattern": "\\b(serverless|sls)\\s+deploy\\b",
42
+ "reason": "serverless deploy (ships a Serverless Framework stack)",
43
+ "ask": true,
44
+ "id": "deploy.serverless",
45
+ "anchored": true
46
+ },
47
+ {
48
+ "pattern": "\\bsam\\s+deploy\\b",
49
+ "reason": "sam deploy (ships an AWS SAM application)",
50
+ "ask": true,
51
+ "id": "deploy.sam",
52
+ "anchored": true
53
+ },
54
+ {
55
+ "pattern": "\\bcdk\\s+deploy\\b",
56
+ "reason": "cdk deploy (ships an AWS CDK stack)",
57
+ "ask": true,
58
+ "id": "deploy.cdk",
59
+ "anchored": true
60
+ },
61
+ {
62
+ "pattern": "\\bansible-playbook\\b",
63
+ "reason": "ansible-playbook (applies configuration to remote hosts)",
64
+ "ask": true,
65
+ "id": "deploy.ansible",
66
+ "anchored": true
67
+ }
68
+ ]
69
+ }
@@ -0,0 +1,66 @@
1
+ # Infrastructure as Code damage control rules
2
+ # Terraform, Pulumi, Serverless Framework, SAM
3
+
4
+ bashToolPatterns:
5
+ # ---------------------------------------------------------------------------
6
+ # INFRASTRUCTURE AS CODE DESTRUCTIVE OPERATIONS
7
+ # ---------------------------------------------------------------------------
8
+ - id: infrastructure.terraform-destroy-destroys-all-infrastructure
9
+ pattern: '\bterraform\s+destroy\b'
10
+ reason: terraform destroy (destroys all infrastructure)
11
+ anchored: true
12
+
13
+ - id: infrastructure.pulumi-destroy-destroys-all-resources
14
+ pattern: '\bpulumi\s+destroy\b'
15
+ reason: pulumi destroy (destroys all resources)
16
+ anchored: true
17
+
18
+ - id: infrastructure.serverless-remove-removes-stack
19
+ pattern: '\bserverless\s+remove\b'
20
+ reason: serverless remove (removes stack)
21
+ anchored: true
22
+
23
+ - id: infrastructure.sls-remove-removes-stack
24
+ pattern: '\bsls\s+remove\b'
25
+ reason: sls remove (removes stack)
26
+ anchored: true
27
+
28
+ - id: infrastructure.sam-delete-deletes-sam-application
29
+ pattern: '\bsam\s+delete\b'
30
+ reason: sam delete (deletes SAM application)
31
+ anchored: true
32
+
33
+ # ---------------------------------------------------------------------------
34
+ # IaC DEPLOYS (ask: true — provision/ship infra, caught in unattended sessions)
35
+ # ---------------------------------------------------------------------------
36
+ # `terraform apply` is already ask-tier via the terraform tooldef; these cover
37
+ # the other IaC apply verbs that were previously `allow`-tier.
38
+ - pattern: '\bpulumi\s+up\b'
39
+ reason: pulumi up (provisions/updates infrastructure)
40
+ ask: true
41
+ id: deploy.pulumi-up
42
+ anchored: true
43
+
44
+ - pattern: '\b(serverless|sls)\s+deploy\b'
45
+ reason: serverless deploy (ships a Serverless Framework stack)
46
+ ask: true
47
+ id: deploy.serverless
48
+ anchored: true
49
+
50
+ - pattern: '\bsam\s+deploy\b'
51
+ reason: sam deploy (ships an AWS SAM application)
52
+ ask: true
53
+ id: deploy.sam
54
+ anchored: true
55
+
56
+ - pattern: '\bcdk\s+deploy\b'
57
+ reason: cdk deploy (ships an AWS CDK stack)
58
+ ask: true
59
+ id: deploy.cdk
60
+ anchored: true
61
+
62
+ - pattern: '\bansible-playbook\b'
63
+ reason: ansible-playbook (applies configuration to remote hosts)
64
+ ask: true
65
+ id: deploy.ansible
66
+ anchored: true
@@ -0,0 +1,11 @@
1
+ {
2
+ "mcpToolPolicies": [
3
+ {
4
+ "match": "(write|edit|delete|remove|move|rename|create|append|patch|mkdir|rmdir|copy|upload|chmod|prune|kill|purge)",
5
+ "id": "mcp.writeish-name",
6
+ "tier": "allow",
7
+ "mutates": true,
8
+ "reason": "write-shaped MCP tool name — protected control-plane path arguments are refused"
9
+ }
10
+ ]
11
+ }
@@ -0,0 +1,47 @@
1
+ # Per-tool policy for MCP tool calls (#923 option 1).
2
+ #
3
+ # The bash rules match shell command strings; an MCP call is a name plus a JSON
4
+ # object, so coverage does not transfer — a tool is classified HERE instead.
5
+ # First match wins. Fields: `tool` (exact full name) or `match` (regex on the
6
+ # name), `tier` (allow | ask | block; default ask), `mutates` (screen protected
7
+ # control-plane path arguments; defaults true for any non-allow tier), `id`
8
+ # (stable — `unattended_allow` / `disabled_rules` name it), `reason`.
9
+ #
10
+ # Tier semantics are the Bash hook's, unchanged: `ask` is an interactive
11
+ # confirm, demoted to allow under bypassPermissions/auto, and FAIL-CLOSED
12
+ # (block + owner email) in an unattended session unless the id is granted.
13
+ # A tool call names no directory, so a path-scoped grant refuses — grant these
14
+ # ids unscoped, per task, deliberately.
15
+ #
16
+ # WHAT IS CLASSIFIED: the measured dangerous core — the kill/remove/teardown
17
+ # class whose effect is not "a message to a guarded session". Each mirrors the
18
+ # in-CLI safety its command path already carries (merge-verification, dirty
19
+ # refusal, PR guards); the tier is additive on top, giving the tool call the
20
+ # same unattended fail-closed posture its Bash spelling gets from the rules.
21
+ #
22
+ # WHAT IS DELIBERATELY NOT CLASSIFIED (pricing both halves — a wrongful tool
23
+ # refusal in an unattended session is a silent loop):
24
+ # * session_send / session_send_keys / pane_send / msg_send — their effect is
25
+ # a message to a Claude session that runs its OWN damage control; the Bash
26
+ # twin (`agentwire send`) is unruled, and gating only the tool would
27
+ # recreate #923's channel asymmetry in reverse.
28
+ # * everything read-shaped or additive (create/list/status/output) — allow by
29
+ # falling through, with zero-access secret screening still applied to every
30
+ # tool's path arguments.
31
+ #
32
+ # UNCLASSIFIED TOOLS fall through to the final name-shape entry below (the
33
+ # #1036 heuristic, now data a host can edit) and otherwise to allow-with-
34
+ # screening. That default is the design decision #923 names: fail-closed would
35
+ # kill every third-party tool and every future tool until classified.
36
+
37
+ mcpToolPolicies:
38
+ # --- fallback for unclassified tools --------------------------------------
39
+ # The #1036 write-shaped-name heuristic, kept as DATA rather than code: a
40
+ # tool whose name declares a mutating operation gets its path-valued
41
+ # arguments screened against the protected control plane. `allow` tier — the
42
+ # name shape alone never blocks or asks; only a protected path argument does.
43
+ - match: "(write|edit|delete|remove|move|rename|create|append|patch|mkdir|rmdir|copy|upload|chmod|prune|kill|purge)"
44
+ id: mcp.writeish-name
45
+ tier: allow
46
+ mutates: true
47
+ reason: write-shaped MCP tool name — protected control-plane path arguments are refused
@@ -0,0 +1,40 @@
1
+ {
2
+ "bashToolPatterns": [
3
+ {
4
+ "pattern": "\\btwilio\\s+api[:\\w.]*messages[:\\w.]*create\\b",
5
+ "reason": "twilio messages create (sends an SMS/MMS)",
6
+ "ask": true,
7
+ "id": "outbound.twilio-messages",
8
+ "anchored": true
9
+ },
10
+ {
11
+ "pattern": "\\baws\\s+ses(v2)?\\s+send-email\\b",
12
+ "reason": "aws ses send-email (sends an external email)",
13
+ "ask": true,
14
+ "id": "outbound.aws-ses",
15
+ "anchored": true
16
+ },
17
+ {
18
+ "pattern": "\\baws\\s+sns\\s+publish\\b",
19
+ "reason": "aws sns publish (sends an SMS/notification)",
20
+ "ask": true,
21
+ "id": "outbound.aws-sns",
22
+ "anchored": true
23
+ },
24
+ {
25
+ "pattern": "\\bsendmail\\b",
26
+ "reason": "sendmail (sends external email)",
27
+ "ask": true,
28
+ "id": "outbound.sendmail",
29
+ "anchored": true
30
+ },
31
+ {
32
+ "pattern": "\\b(mail|mailx)\\s+(?:(?!--(?:\\s|$))[^\\s;&|]+\\s+)*?-s\\b",
33
+ "pattern_src": "\\b(mail|mailx)\\s+{ARGS}-s\\b",
34
+ "reason": "mail -s (sends external email)",
35
+ "ask": true,
36
+ "id": "outbound.mail",
37
+ "anchored": true
38
+ }
39
+ ]
40
+ }