@sponsio/sdk 0.1.0-alpha.3 → 0.1.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 (176) hide show
  1. package/bin/sponsio.cjs +11 -0
  2. package/contracts/capability/credentials.yaml +8 -8
  3. package/contracts/capability/database.yaml +6 -6
  4. package/contracts/capability/filesystem-strict.yaml +4 -4
  5. package/contracts/capability/filesystem.yaml +9 -9
  6. package/contracts/capability/host-config-integrity.yaml +285 -0
  7. package/contracts/capability/self-modify.yaml +214 -9
  8. package/contracts/capability/shell.yaml +25 -32
  9. package/contracts/capability/subagent.yaml +5 -5
  10. package/contracts/core/llm_safety.yaml +23 -13
  11. package/contracts/incident/claude-code-secret-bypass.yaml +10 -11
  12. package/contracts/incident/cursor-railway-wipe.yaml +3 -3
  13. package/contracts/incident/mcp-composition.yaml +12 -12
  14. package/contracts/incident/openclaw.yaml +53 -45
  15. package/contracts/incident/subagent-escape.yaml +4 -4
  16. package/dist/cli/check.d.ts +2 -0
  17. package/dist/cli/check.d.ts.map +1 -0
  18. package/dist/cli/check.js +283 -0
  19. package/dist/cli/check.js.map +1 -0
  20. package/dist/cli/cli.d.ts +25 -0
  21. package/dist/cli/cli.d.ts.map +1 -0
  22. package/dist/cli/cli.js +459 -0
  23. package/dist/cli/cli.js.map +1 -0
  24. package/dist/cli/config.d.ts +88 -0
  25. package/dist/cli/config.d.ts.map +1 -0
  26. package/dist/cli/config.js +243 -0
  27. package/dist/cli/config.js.map +1 -0
  28. package/dist/cli/demo.d.ts +12 -0
  29. package/dist/cli/demo.d.ts.map +1 -0
  30. package/dist/cli/demo.js +350 -0
  31. package/dist/cli/demo.js.map +1 -0
  32. package/dist/cli/doctor.d.ts +11 -0
  33. package/dist/cli/doctor.d.ts.map +1 -0
  34. package/dist/cli/doctor.js +201 -0
  35. package/dist/cli/doctor.js.map +1 -0
  36. package/dist/cli/eval.d.ts +2 -0
  37. package/dist/cli/eval.d.ts.map +1 -0
  38. package/dist/cli/eval.js +361 -0
  39. package/dist/cli/eval.js.map +1 -0
  40. package/dist/cli/explain.d.ts +2 -0
  41. package/dist/cli/explain.d.ts.map +1 -0
  42. package/dist/cli/explain.js +266 -0
  43. package/dist/cli/explain.js.map +1 -0
  44. package/dist/cli/export-sessions.d.ts +2 -0
  45. package/dist/cli/export-sessions.d.ts.map +1 -0
  46. package/dist/cli/export-sessions.js +182 -0
  47. package/dist/cli/export-sessions.js.map +1 -0
  48. package/dist/cli/export.d.ts +2 -0
  49. package/dist/cli/export.d.ts.map +1 -0
  50. package/dist/cli/export.js +222 -0
  51. package/dist/cli/export.js.map +1 -0
  52. package/dist/cli/extractors/common.d.ts +27 -0
  53. package/dist/cli/extractors/common.d.ts.map +1 -0
  54. package/dist/cli/extractors/common.js +107 -0
  55. package/dist/cli/extractors/common.js.map +1 -0
  56. package/dist/cli/extractors/generic.d.ts +37 -0
  57. package/dist/cli/extractors/generic.d.ts.map +1 -0
  58. package/dist/cli/extractors/generic.js +185 -0
  59. package/dist/cli/extractors/generic.js.map +1 -0
  60. package/dist/cli/extractors/langchain.d.ts +18 -0
  61. package/dist/cli/extractors/langchain.d.ts.map +1 -0
  62. package/dist/cli/extractors/langchain.js +86 -0
  63. package/dist/cli/extractors/langchain.js.map +1 -0
  64. package/dist/cli/extractors/vercel.d.ts +17 -0
  65. package/dist/cli/extractors/vercel.d.ts.map +1 -0
  66. package/dist/cli/extractors/vercel.js +46 -0
  67. package/dist/cli/extractors/vercel.js.map +1 -0
  68. package/dist/cli/index.d.ts +38 -0
  69. package/dist/cli/index.d.ts.map +1 -0
  70. package/dist/cli/index.js +146 -0
  71. package/dist/cli/index.js.map +1 -0
  72. package/dist/cli/init.d.ts +2 -0
  73. package/dist/cli/init.d.ts.map +1 -0
  74. package/dist/cli/init.js +177 -0
  75. package/dist/cli/init.js.map +1 -0
  76. package/dist/cli/mode.d.ts +2 -0
  77. package/dist/cli/mode.d.ts.map +1 -0
  78. package/dist/cli/mode.js +71 -0
  79. package/dist/cli/mode.js.map +1 -0
  80. package/dist/cli/onboard.d.ts +88 -0
  81. package/dist/cli/onboard.d.ts.map +1 -0
  82. package/dist/cli/onboard.js +758 -0
  83. package/dist/cli/onboard.js.map +1 -0
  84. package/dist/cli/otlp.d.ts +27 -0
  85. package/dist/cli/otlp.d.ts.map +1 -0
  86. package/dist/cli/otlp.js +79 -0
  87. package/dist/cli/otlp.js.map +1 -0
  88. package/dist/cli/package.json +1 -0
  89. package/dist/cli/packs.d.ts +16 -0
  90. package/dist/cli/packs.d.ts.map +1 -0
  91. package/dist/cli/packs.js +184 -0
  92. package/dist/cli/packs.js.map +1 -0
  93. package/dist/cli/patterns.d.ts +15 -0
  94. package/dist/cli/patterns.d.ts.map +1 -0
  95. package/dist/cli/patterns.js +135 -0
  96. package/dist/cli/patterns.js.map +1 -0
  97. package/dist/cli/prompt.d.ts +2 -0
  98. package/dist/cli/prompt.d.ts.map +1 -0
  99. package/dist/cli/prompt.js +54 -0
  100. package/dist/cli/prompt.js.map +1 -0
  101. package/dist/cli/replay.d.ts +2 -0
  102. package/dist/cli/replay.d.ts.map +1 -0
  103. package/dist/cli/replay.js +196 -0
  104. package/dist/cli/replay.js.map +1 -0
  105. package/dist/cli/report.d.ts +57 -0
  106. package/dist/cli/report.d.ts.map +1 -0
  107. package/dist/cli/report.js +298 -0
  108. package/dist/cli/report.js.map +1 -0
  109. package/dist/cli/scan.d.ts +2 -0
  110. package/dist/cli/scan.d.ts.map +1 -0
  111. package/dist/cli/scan.js +172 -0
  112. package/dist/cli/scan.js.map +1 -0
  113. package/dist/cli/skill.d.ts +15 -0
  114. package/dist/cli/skill.d.ts.map +1 -0
  115. package/dist/cli/skill.js +131 -0
  116. package/dist/cli/skill.js.map +1 -0
  117. package/dist/cli/tokens.d.ts +31 -0
  118. package/dist/cli/tokens.d.ts.map +1 -0
  119. package/dist/cli/tokens.js +73 -0
  120. package/dist/cli/tokens.js.map +1 -0
  121. package/dist/cli/types.d.ts +46 -0
  122. package/dist/cli/types.d.ts.map +1 -0
  123. package/dist/cli/types.js +3 -0
  124. package/dist/cli/types.js.map +1 -0
  125. package/dist/cli/validate.d.ts +19 -0
  126. package/dist/cli/validate.d.ts.map +1 -0
  127. package/dist/cli/validate.js +205 -0
  128. package/dist/cli/validate.js.map +1 -0
  129. package/dist/cli/zod.d.ts +36 -0
  130. package/dist/cli/zod.d.ts.map +1 -0
  131. package/dist/cli/zod.js +226 -0
  132. package/dist/cli/zod.js.map +1 -0
  133. package/dist/contract.d.ts +13 -13
  134. package/dist/contract.d.ts.map +1 -1
  135. package/dist/contract.js +21 -21
  136. package/dist/contract.js.map +1 -1
  137. package/dist/core/config-loader.d.ts +1 -1
  138. package/dist/core/config-loader.js +35 -17
  139. package/dist/core/config-loader.js.map +1 -1
  140. package/dist/core/grounding.d.ts +49 -2
  141. package/dist/core/grounding.d.ts.map +1 -1
  142. package/dist/core/grounding.js +302 -142
  143. package/dist/core/grounding.js.map +1 -1
  144. package/dist/core/nl-parser.d.ts.map +1 -1
  145. package/dist/core/nl-parser.js +74 -2
  146. package/dist/core/nl-parser.js.map +1 -1
  147. package/dist/core/pattern-factory.d.ts +4 -4
  148. package/dist/core/pattern-factory.d.ts.map +1 -1
  149. package/dist/core/pattern-factory.js +46 -4
  150. package/dist/core/pattern-factory.js.map +1 -1
  151. package/dist/core/patterns.d.ts +78 -4
  152. package/dist/core/patterns.d.ts.map +1 -1
  153. package/dist/core/patterns.js +211 -3
  154. package/dist/core/patterns.js.map +1 -1
  155. package/dist/core/spans.d.ts +1 -1
  156. package/dist/core/spans.d.ts.map +1 -1
  157. package/dist/core/spans.js.map +1 -1
  158. package/dist/core/sto.d.ts +32 -62
  159. package/dist/core/sto.d.ts.map +1 -1
  160. package/dist/core/sto.js +32 -90
  161. package/dist/core/sto.js.map +1 -1
  162. package/dist/index.d.ts +77 -32
  163. package/dist/index.d.ts.map +1 -1
  164. package/dist/index.js +172 -133
  165. package/dist/index.js.map +1 -1
  166. package/dist/integrations/openai-agents.d.ts.map +1 -1
  167. package/dist/integrations/openai-agents.js +5 -4
  168. package/dist/integrations/openai-agents.js.map +1 -1
  169. package/dist/render/tokens.d.ts.map +1 -1
  170. package/dist/render/tokens.js +1 -0
  171. package/dist/render/tokens.js.map +1 -1
  172. package/package.json +28 -4
  173. package/prompts/onboard.md +250 -0
  174. package/prompts/refresh.md +118 -0
  175. package/prompts/scan.md +125 -0
  176. package/skills/SKILL.md +502 -0
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env node
2
+ // Thin shim → compiled ``dist/cli/cli.js``. Keeps ``npx`` invocations
3
+ // snappy and lets us publish a single pre-compiled artifact without
4
+ // shipping a ``tsx`` / ``esbuild`` dependency.
5
+ //
6
+ // Lives at ``bin/sponsio.cjs`` (CommonJS) so it can ``require()`` the
7
+ // CLI's compiled CJS output directly without an ESM detour. The
8
+ // runtime SDK at ``dist/index.js`` is ESM; the CLI at ``dist/cli/cli.js``
9
+ // is CJS — two compile targets in one package, mapped through this
10
+ // shim and ``package.json``'s ``bin`` field.
11
+ require("../dist/cli/cli.js");
@@ -75,7 +75,7 @@ agents:
75
75
  # False negatives mean the secret ships, which is much worse.
76
76
 
77
77
  - desc: "Block writes containing AWS / GCP / Azure / cloud creds"
78
- E:
78
+ G:
79
79
  pattern: arg_blacklist
80
80
  args:
81
81
  - write
@@ -88,7 +88,7 @@ agents:
88
88
  source: "library:tier1.credentials"
89
89
 
90
90
  - desc: "Block writes containing GitHub tokens"
91
- E:
91
+ G:
92
92
  pattern: arg_blacklist
93
93
  args:
94
94
  - write
@@ -101,7 +101,7 @@ agents:
101
101
  source: "library:tier1.credentials"
102
102
 
103
103
  - desc: "Block writes containing payment-processor / SaaS API keys"
104
- E:
104
+ G:
105
105
  pattern: arg_blacklist
106
106
  args:
107
107
  - write
@@ -119,7 +119,7 @@ agents:
119
119
  source: "library:tier1.credentials"
120
120
 
121
121
  - desc: "Block writes containing private keys / SSH material"
122
- E:
122
+ G:
123
123
  pattern: arg_blacklist
124
124
  args:
125
125
  - write
@@ -138,7 +138,7 @@ agents:
138
138
  # ``new_string`` (the canonical `edit` tool's payload field).
139
139
 
140
140
  - desc: "Block edits containing AWS / GCP / Azure / cloud creds"
141
- E:
141
+ G:
142
142
  pattern: arg_blacklist
143
143
  args:
144
144
  - edit
@@ -151,7 +151,7 @@ agents:
151
151
  source: "library:tier1.credentials"
152
152
 
153
153
  - desc: "Block edits containing GitHub tokens"
154
- E:
154
+ G:
155
155
  pattern: arg_blacklist
156
156
  args:
157
157
  - edit
@@ -164,7 +164,7 @@ agents:
164
164
  source: "library:tier1.credentials"
165
165
 
166
166
  - desc: "Block edits containing payment-processor / SaaS API keys"
167
- E:
167
+ G:
168
168
  pattern: arg_blacklist
169
169
  args:
170
170
  - edit
@@ -178,7 +178,7 @@ agents:
178
178
  source: "library:tier1.credentials"
179
179
 
180
180
  - desc: "Block edits containing private keys / SSH material"
181
- E:
181
+ G:
182
182
  pattern: arg_blacklist
183
183
  args:
184
184
  - edit
@@ -52,7 +52,7 @@ agents:
52
52
  # =================================================================
53
53
 
54
54
  - desc: "Ban DROP DATABASE / DROP TABLE / DROP SCHEMA via shell"
55
- E:
55
+ G:
56
56
  pattern: arg_blacklist
57
57
  args:
58
58
  - exec
@@ -65,7 +65,7 @@ agents:
65
65
  source: "library:tier1.database"
66
66
 
67
67
  - desc: "Ban TRUNCATE TABLE via shell (whole-table wipe)"
68
- E:
68
+ G:
69
69
  pattern: arg_blacklist
70
70
  args:
71
71
  - exec
@@ -77,7 +77,7 @@ agents:
77
77
  source: "library:tier1.database"
78
78
 
79
79
  - desc: "Ban unbounded DELETE FROM (no WHERE clause)"
80
- E:
80
+ G:
81
81
  pattern: arg_blacklist
82
82
  args:
83
83
  - exec
@@ -95,7 +95,7 @@ agents:
95
95
  # =================================================================
96
96
 
97
97
  - desc: "Ban dropdb / mysqladmin drop / redis FLUSHALL / FLUSHDB"
98
- E:
98
+ G:
99
99
  pattern: arg_blacklist
100
100
  args:
101
101
  - exec
@@ -107,7 +107,7 @@ agents:
107
107
  source: "library:tier1.database"
108
108
 
109
109
  - desc: "Ban migration rollback to empty schema"
110
- E:
110
+ G:
111
111
  pattern: arg_blacklist
112
112
  args:
113
113
  - exec
@@ -125,7 +125,7 @@ agents:
125
125
  # =================================================================
126
126
 
127
127
  - desc: "Ban deletion of database data directories"
128
- E:
128
+ G:
129
129
  pattern: arg_blacklist
130
130
  args:
131
131
  - exec
@@ -53,7 +53,7 @@ agents:
53
53
  # =================================================================
54
54
 
55
55
  - desc: "Writes restricted to workspace"
56
- E:
56
+ G:
57
57
  pattern: scope_limit
58
58
  args:
59
59
  - write
@@ -61,7 +61,7 @@ agents:
61
61
  source: "library:tier1.filesystem-strict"
62
62
 
63
63
  - desc: "In-place edits restricted to workspace"
64
- E:
64
+ G:
65
65
  pattern: scope_limit
66
66
  args:
67
67
  - edit
@@ -69,7 +69,7 @@ agents:
69
69
  source: "library:tier1.filesystem-strict"
70
70
 
71
71
  - desc: "Patch application restricted to workspace"
72
- E:
72
+ G:
73
73
  pattern: scope_limit
74
74
  args:
75
75
  - apply_patch
@@ -82,7 +82,7 @@ agents:
82
82
  # sensitive-path blacklist in the base ``filesystem`` pack
83
83
  # keeps secrets hard-denied under any of these roots.
84
84
  - desc: "Reads restricted to workspace, /tmp, and read-only system paths"
85
- E:
85
+ G:
86
86
  pattern: scope_limit
87
87
  args:
88
88
  - read
@@ -67,7 +67,7 @@ agents:
67
67
  # `crontab` is end-anchored to avoid matching paths like
68
68
  # `/projects/crontab-tests/` or `mycrontab.txt`.
69
69
  - desc: "Deny reads of SSH keys, AWS credentials, browser keychains, dotenv secrets"
70
- E:
70
+ G:
71
71
  pattern: arg_blacklist
72
72
  args:
73
73
  - read
@@ -96,7 +96,7 @@ agents:
96
96
  source: "library:tier1.filesystem"
97
97
 
98
98
  - desc: "Deny writes / edits into sensitive paths (prevent persistence or cred overwrite)"
99
- E:
99
+ G:
100
100
  pattern: arg_blacklist
101
101
  args:
102
102
  - write
@@ -114,7 +114,7 @@ agents:
114
114
  source: "library:tier1.filesystem"
115
115
 
116
116
  - desc: "Same denial applies to in-place edits"
117
- E:
117
+ G:
118
118
  pattern: arg_blacklist
119
119
  args:
120
120
  - edit
@@ -131,7 +131,7 @@ agents:
131
131
  source: "library:tier1.filesystem"
132
132
 
133
133
  - desc: "And to unified-diff patches"
134
- E:
134
+ G:
135
135
  pattern: arg_blacklist
136
136
  args:
137
137
  - apply_patch
@@ -165,13 +165,13 @@ agents:
165
165
  # =================================================================
166
166
 
167
167
  - desc: "Must read a file before editing it (no blind patches)"
168
- E:
168
+ G:
169
169
  pattern: must_precede
170
170
  args: [read, edit]
171
171
  source: "library:tier1.filesystem"
172
172
 
173
173
  - desc: "Must read a file before apply_patch (no blind diffs)"
174
- E:
174
+ G:
175
175
  pattern: must_precede
176
176
  args: [read, apply_patch]
177
177
  source: "library:tier1.filesystem"
@@ -191,12 +191,12 @@ agents:
191
191
  # =================================================================
192
192
 
193
193
  - desc: "Editing bootstrap / system-prompt files requires human confirmation"
194
- E:
194
+ G:
195
195
  ltl: 'G(called_with(edit, "(AGENTS|SOUL|IDENTITY|USER|CLAUDE|\\.cursorrules)\\.md?") -> count(confirm_reconfirmed) >= count_with(edit, "(AGENTS|SOUL|IDENTITY|USER|CLAUDE|\\.cursorrules)\\.md?"))'
196
196
  source: "library:tier1.filesystem"
197
197
 
198
198
  - desc: "apply_patch against bootstrap files requires confirmation"
199
- E:
199
+ G:
200
200
  ltl: 'G(called_with(apply_patch, "(AGENTS|SOUL|IDENTITY|USER|CLAUDE|\\.cursorrules)\\.md?") -> count(confirm_reconfirmed) >= count_with(apply_patch, "(AGENTS|SOUL|IDENTITY|USER|CLAUDE|\\.cursorrules)\\.md?"))'
201
201
  source: "library:tier1.filesystem"
202
202
 
@@ -213,7 +213,7 @@ agents:
213
213
  # =================================================================
214
214
 
215
215
  - desc: "Data read from filesystem must not flow to outbound messages"
216
- E:
216
+ G:
217
217
  pattern: no_data_leak
218
218
  args: [read, send_message]
219
219
  source: "library:tier1.filesystem"
@@ -0,0 +1,285 @@
1
+ # =============================================================================
2
+ # sponsio/contracts/capability/host-config-integrity.yaml
3
+ #
4
+ # Capability pack — IDE host config integrity protection.
5
+ # Include in your per-host bucket (``_host_cursor`` /
6
+ # ``_host_claude_code`` / ``_host_codex`` / ``_host_windsurf``)
7
+ # so the agent under guard cannot disable Sponsio by rewriting
8
+ # the IDE's hook registration files.
9
+ #
10
+ # Threat model:
11
+ #
12
+ # Sponsio's enforcement on IDE coding agents is mediated through
13
+ # the host IDE's hook system: Cursor's ``.cursor/hooks.json``,
14
+ # Claude Code's ``~/.claude/settings.json`` /
15
+ # ``.claude/settings.local.json``, the per-project ``.claude/hooks/``
16
+ # directory, etc. These files declare WHICH commands the IDE invokes
17
+ # at which hook events. If the agent can rewrite them, it doesn't
18
+ # need to defeat any individual rule — it just removes the
19
+ # ``preToolUse`` entry that calls Sponsio at all, and on the next IDE
20
+ # restart Sponsio is silently absent. Every rule in
21
+ # ``capability/self-modify`` and ``incident/subagent-escape`` keeps
22
+ # working perfectly, against an enforcer that no longer exists.
23
+ # This is sponsio:capability/self-modify's blind spot — that pack
24
+ # protects the rule files; this pack protects the wiring that
25
+ # routes calls to the rule files in the first place.
26
+ #
27
+ # Concrete attack shapes observed (or trivially derivable from §1
28
+ # of self-modify.yaml's threat model):
29
+ #
30
+ # 1. ``Write .cursor/hooks.json '{"version":1,"hooks":{}}'``
31
+ # — wipe all hook entries; next Cursor restart, no enforcement.
32
+ # 2. ``Edit .cursor/hooks.json``: change ``"failClosed": true``
33
+ # to ``"failClosed": false`` — Sponsio is still wired in but
34
+ # any spawn / parse / runtime error fails open.
35
+ # 3. ``Write merge_hooks.py`` whose content opens hooks.json in
36
+ # 'w' mode (the §4 self-modify bypass shape, instantiated
37
+ # against hook config instead of plugin yaml).
38
+ # 4. ``python -c "open('.cursor/hooks.json','w').write('...')"``
39
+ # — the §5 self-modify interpreter-bypass shape against hook
40
+ # config.
41
+ # 5. ``echo '{}' > .cursor/hooks.json`` / ``sed -i 's/true/false/'``
42
+ # — bash redirect / mutator forms that the self-modify pack
43
+ # doesn't currently match because its regex anchors on
44
+ # ``.sponsio/plugins/...`` paths only.
45
+ #
46
+ # What this pack denies:
47
+ #
48
+ # - Edit / Write / MultiEdit on the IDE hook registration files.
49
+ # - Bash redirect / sed / awk / tee that targets the same files.
50
+ # - Script *creation* whose content references a hook config path
51
+ # AND uses an open-for-write idiom (mirror of self-modify §4).
52
+ # - Interpreter invocation whose command line carries a hook
53
+ # config path (mirror of self-modify §5).
54
+ #
55
+ # What this pack does NOT deny:
56
+ #
57
+ # - ``sponsio host install`` and ``sponsio host uninstall``
58
+ # write hooks.json via Python subprocess from the Sponsio
59
+ # binary itself, not through the agent's Edit / Write tool
60
+ # surface — the legitimate install path is unaffected.
61
+ # - The user hand-editing hooks.json in their text editor
62
+ # similarly does not pass through the IDE's Edit / Write
63
+ # tool; this pack is silent on that surface.
64
+ # - Reads of hook config files are not denied. The file format
65
+ # is documented public knowledge; recon defense here would
66
+ # give negligible benefit at significant false-positive cost
67
+ # (legitimate "what hooks are registered?" debug queries).
68
+ # The subagent-escape pack covers the recon angle for
69
+ # sub-agents specifically.
70
+ #
71
+ # Pair with: ``sponsio:capability/self-modify`` (rule-file integrity)
72
+ # and ``sponsio:incident/subagent-escape`` (sub-agent containment).
73
+ # Together the three packs form the control-plane defense surface
74
+ # documented in ``agent_docs/control_plane_threat_model.md``.
75
+ #
76
+ # Include via:
77
+ # include:
78
+ # - sponsio:capability/host-config-integrity
79
+ #
80
+ # Source tag convention:
81
+ # library:tier1.host-config-integrity
82
+ # =============================================================================
83
+
84
+ version: "1"
85
+
86
+ agents:
87
+ "*":
88
+ contracts:
89
+
90
+ # =================================================================
91
+ # § 1 — No agent-mediated Edit of IDE hook config
92
+ # =================================================================
93
+ #
94
+ # Path set covers the wiring files for every host Sponsio
95
+ # currently supports. Add new hosts here as ``sponsio host
96
+ # install`` learns to register them.
97
+ #
98
+ # Anchor pattern note:
99
+ #
100
+ # The ``(^|/)`` anchor at the start of each alternative
101
+ # matches both absolute paths (``/Users/x/.cursor/hooks.json``)
102
+ # and project-relative paths (``.cursor/hooks.json``). The
103
+ # ``$`` anchors at the end pin the match to exact filenames,
104
+ # so a file named ``hooks.json.bak`` or ``settings.json.tmpl``
105
+ # stays editable.
106
+ #
107
+ # The Cursor MCP config (``.cursor/mcp.json``) is included
108
+ # because it's the file that declares Sponsio's MCP server
109
+ # to Cursor — same disable-by-rewrite attack shape, different
110
+ # file. Same for Claude Code's ``hooks/`` directory.
111
+
112
+ - desc: "Host agent must not edit IDE hook / MCP wiring files — disabling Sponsio's call site is privilege escalation"
113
+ G:
114
+ pattern: arg_blacklist
115
+ args:
116
+ - Edit
117
+ - file_path
118
+ - - "(^|/)\\.cursor/hooks\\.json$"
119
+ - "(^|/)\\.cursor/mcp\\.json$"
120
+ - "(^|/)\\.claude/settings\\.json$"
121
+ - "(^|/)\\.claude/settings\\.local\\.json$"
122
+ - "(^|/)\\.claude/hooks/[^/]+\\.json$"
123
+ - "(^|/)\\.codex/hooks\\.json$"
124
+ - "(^|/)\\.windsurf/hooks\\.json$"
125
+ source: "library:tier1.host-config-integrity"
126
+
127
+ # =================================================================
128
+ # § 2 — No agent-mediated Write of IDE hook config
129
+ # =================================================================
130
+ #
131
+ # ``Write`` overwrites the whole file — closes the
132
+ # "delete-and-recreate-empty" workaround a pure ``Edit`` block
133
+ # would leave open.
134
+
135
+ - desc: "Host agent must not overwrite IDE hook / MCP wiring files — use `sponsio host install` / hand-edit"
136
+ G:
137
+ pattern: arg_blacklist
138
+ args:
139
+ - Write
140
+ - file_path
141
+ - - "(^|/)\\.cursor/hooks\\.json$"
142
+ - "(^|/)\\.cursor/mcp\\.json$"
143
+ - "(^|/)\\.claude/settings\\.json$"
144
+ - "(^|/)\\.claude/settings\\.local\\.json$"
145
+ - "(^|/)\\.claude/hooks/[^/]+\\.json$"
146
+ - "(^|/)\\.codex/hooks\\.json$"
147
+ - "(^|/)\\.windsurf/hooks\\.json$"
148
+ source: "library:tier1.host-config-integrity"
149
+
150
+ # =================================================================
151
+ # § 3 — No agent-mediated MultiEdit of IDE hook config
152
+ # =================================================================
153
+
154
+ - desc: "Host agent must not multi-edit IDE hook / MCP wiring files — use `sponsio host install` / hand-edit"
155
+ G:
156
+ pattern: arg_blacklist
157
+ args:
158
+ - MultiEdit
159
+ - file_path
160
+ - - "(^|/)\\.cursor/hooks\\.json$"
161
+ - "(^|/)\\.cursor/mcp\\.json$"
162
+ - "(^|/)\\.claude/settings\\.json$"
163
+ - "(^|/)\\.claude/settings\\.local\\.json$"
164
+ - "(^|/)\\.claude/hooks/[^/]+\\.json$"
165
+ - "(^|/)\\.codex/hooks\\.json$"
166
+ - "(^|/)\\.windsurf/hooks\\.json$"
167
+ source: "library:tier1.host-config-integrity"
168
+
169
+ # =================================================================
170
+ # § 4 — No script creation that mutates IDE hook config
171
+ # (mirror of self-modify §4, against hook paths)
172
+ # =================================================================
173
+ #
174
+ # The same lookahead-conjunction shape as self-modify §4: deny
175
+ # only if the content carries BOTH a hook-config path AND a
176
+ # write-shape idiom. Pure docs that mention the path stay
177
+ # editable — the rule is narrow on purpose.
178
+
179
+ - desc: "Host agent must not write a script that mutates IDE hook / MCP wiring files"
180
+ G:
181
+ pattern: arg_blacklist
182
+ args:
183
+ - Write
184
+ - content
185
+ - - "(?s)(?=.*\\.cursor/(hooks|mcp)\\.json|\\.claude/(settings(\\.local)?\\.json|hooks/)|\\.codex/hooks\\.json|\\.windsurf/hooks\\.json).*(\\.write_text\\s*\\(|\\.write_bytes\\s*\\(|\\bf\\.write\\s*\\(|\\bopen\\s*\\([^)]*['\\\"][aw][\\+bxt]*['\\\"]\\s*\\)|\\bfs\\.(writeFileSync|appendFileSync|createWriteStream|writeFile)\\s*\\(|\\bFile\\.(open|write)\\s*\\(|\\b(IO|File)\\.write\\b)"
186
+ source: "library:tier1.host-config-integrity"
187
+
188
+ - desc: "Host agent must not edit a script that mutates IDE hook / MCP wiring files"
189
+ G:
190
+ pattern: arg_blacklist
191
+ args:
192
+ - Edit
193
+ - new_string
194
+ - - "(?s)(?=.*\\.cursor/(hooks|mcp)\\.json|\\.claude/(settings(\\.local)?\\.json|hooks/)|\\.codex/hooks\\.json|\\.windsurf/hooks\\.json).*(\\.write_text\\s*\\(|\\.write_bytes\\s*\\(|\\bf\\.write\\s*\\(|\\bopen\\s*\\([^)]*['\\\"][aw][\\+bxt]*['\\\"]\\s*\\)|\\bfs\\.(writeFileSync|appendFileSync|createWriteStream|writeFile)\\s*\\(|\\bFile\\.(open|write)\\s*\\(|\\b(IO|File)\\.write\\b)"
195
+ source: "library:tier1.host-config-integrity"
196
+
197
+ # =================================================================
198
+ # § 5 — No interpreter invocation targeting IDE hook config
199
+ # (mirror of self-modify §5, against hook paths)
200
+ # =================================================================
201
+ #
202
+ # Catches both inline forms (``python -c "...hooks.json..."``)
203
+ # and path-as-argument forms (``python merge.py
204
+ # .cursor/hooks.json``). The ``[^|\n]*`` between the
205
+ # interpreter token and the path token excludes cross-pipeline
206
+ # matches, same idiom as self-modify §5.
207
+
208
+ - desc: "Host agent must not run an interpreter against IDE hook / MCP wiring files"
209
+ G:
210
+ pattern: arg_blacklist
211
+ args:
212
+ - Bash
213
+ - command
214
+ - - "\\b(python|python2|python3|node|deno|bun|ruby|perl|php|lua|tclsh|R|Rscript)\\b[^|\\n]*(\\.cursor/(hooks|mcp)\\.json|\\.claude/(settings(\\.local)?\\.json|hooks/)|\\.codex/hooks\\.json|\\.windsurf/hooks\\.json)"
215
+ source: "library:tier1.host-config-integrity"
216
+
217
+ # =================================================================
218
+ # § 6 — No bash redirect / mutator targeting IDE hook config
219
+ # =================================================================
220
+ #
221
+ # Catches the cheap shell shapes that don't go through any
222
+ # interpreter: ``echo '{}' > hooks.json``, ``cat /dev/null >
223
+ # settings.json``, ``: > hooks.json``, ``sed -i 's/true/false/'
224
+ # hooks.json``, ``tee hooks.json``, ``cp empty.json
225
+ # hooks.json``, ``mv x hooks.json``, ``rm hooks.json``.
226
+ #
227
+ # The pattern is "any of {redirect, sed, awk, tee, cp, mv,
228
+ # rm, install} adjacent to a hook-config path on the same
229
+ # command line". Read-only patterns (``cat hooks.json``,
230
+ # ``jq . hooks.json``, ``grep ... hooks.json``) are NOT
231
+ # matched — they don't carry a mutator verb in front of the
232
+ # path, so the alternation never triggers.
233
+ #
234
+ # Edge case: ``python ... > hooks.json`` is already caught
235
+ # by §5 via the interpreter alternation. No double-deny harm
236
+ # since this is the deny side of the contract anyway.
237
+
238
+ - desc: "Host agent must not redirect / sed / tee / mv / rm an IDE hook / MCP wiring file"
239
+ G:
240
+ pattern: arg_blacklist
241
+ args:
242
+ - Bash
243
+ - command
244
+ - - "(>\\s*|>>\\s*|\\btee\\b[^|\\n]*|\\bsed\\b\\s+-i[^|\\n]*|\\bawk\\b[^|\\n]*-i[^|\\n]*|\\bcp\\b[^|\\n]+|\\bmv\\b[^|\\n]+|\\brm\\b[^|\\n]+|\\binstall\\b[^|\\n]+)(\\.cursor/(hooks|mcp)\\.json|\\.claude/(settings(\\.local)?\\.json|hooks/[^\\s|]+)|\\.codex/hooks\\.json|\\.windsurf/hooks\\.json)"
245
+ source: "library:tier1.host-config-integrity"
246
+
247
+ # -----------------------------------------------------------------------------
248
+ # Integration requirements
249
+ # -----------------------------------------------------------------------------
250
+ #
251
+ # - This pack assumes the host agent's Edit / Write / MultiEdit
252
+ # tool exposes ``file_path`` (Claude Code, Cursor, Codex all
253
+ # currently do). Hosts using a different param name will need
254
+ # the per-host adjustment that ``self-modify.yaml`` already
255
+ # documents.
256
+ #
257
+ # - The path set is the union of every Sponsio-supported host's
258
+ # wiring files. A given per-host bucket only needs the entries
259
+ # matching ITS host, but keeping the union here means the pack
260
+ # stays a single drop-in include with no per-host customization
261
+ # required at the call site. False-positive cost is zero —
262
+ # ``.cursor/hooks.json`` is only present in Cursor projects, so
263
+ # a Claude Code agent's edits to a non-existent path will never
264
+ # match anyway.
265
+ #
266
+ # - The ``"*"`` agent scope means these rules apply to every agent
267
+ # in any library that includes this pack. Recommended include
268
+ # site is the per-host bucket (``_host_cursor`` /
269
+ # ``_host_claude_code``), so the rules fire on the host that
270
+ # actually has the wiring file in question.
271
+ #
272
+ # - The bash mutator regex in §6 is intentionally broader than
273
+ # self-modify §5's interpreter-only regex. That's correct: hook
274
+ # config files are JSON, so non-interpreter shell mutators
275
+ # (sed, tee, cp) are the natural attack surface and they don't
276
+ # apply to .sponsio/plugins/*.yaml the same way (yaml requires
277
+ # careful editing that bash one-liners typically don't produce
278
+ # correctly, so the attack-shape distribution differs).
279
+ #
280
+ # - Read of hook config files is permitted. If a future incident
281
+ # pack wants to deny reads (e.g. for a defense-in-depth recon
282
+ # block similar to subagent-escape §4), add it as a separate
283
+ # ``incident/host-config-recon.yaml`` rather than expanding
284
+ # this capability pack — capability packs stay narrowly scoped
285
+ # to a single privilege boundary.