@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.
- package/bin/sponsio.cjs +11 -0
- package/contracts/capability/credentials.yaml +8 -8
- package/contracts/capability/database.yaml +6 -6
- package/contracts/capability/filesystem-strict.yaml +4 -4
- package/contracts/capability/filesystem.yaml +9 -9
- package/contracts/capability/host-config-integrity.yaml +285 -0
- package/contracts/capability/self-modify.yaml +214 -9
- package/contracts/capability/shell.yaml +25 -32
- package/contracts/capability/subagent.yaml +5 -5
- package/contracts/core/llm_safety.yaml +23 -13
- package/contracts/incident/claude-code-secret-bypass.yaml +10 -11
- package/contracts/incident/cursor-railway-wipe.yaml +3 -3
- package/contracts/incident/mcp-composition.yaml +12 -12
- package/contracts/incident/openclaw.yaml +53 -45
- package/contracts/incident/subagent-escape.yaml +4 -4
- package/dist/cli/check.d.ts +2 -0
- package/dist/cli/check.d.ts.map +1 -0
- package/dist/cli/check.js +283 -0
- package/dist/cli/check.js.map +1 -0
- package/dist/cli/cli.d.ts +25 -0
- package/dist/cli/cli.d.ts.map +1 -0
- package/dist/cli/cli.js +459 -0
- package/dist/cli/cli.js.map +1 -0
- package/dist/cli/config.d.ts +88 -0
- package/dist/cli/config.d.ts.map +1 -0
- package/dist/cli/config.js +243 -0
- package/dist/cli/config.js.map +1 -0
- package/dist/cli/demo.d.ts +12 -0
- package/dist/cli/demo.d.ts.map +1 -0
- package/dist/cli/demo.js +350 -0
- package/dist/cli/demo.js.map +1 -0
- package/dist/cli/doctor.d.ts +11 -0
- package/dist/cli/doctor.d.ts.map +1 -0
- package/dist/cli/doctor.js +201 -0
- package/dist/cli/doctor.js.map +1 -0
- package/dist/cli/eval.d.ts +2 -0
- package/dist/cli/eval.d.ts.map +1 -0
- package/dist/cli/eval.js +361 -0
- package/dist/cli/eval.js.map +1 -0
- package/dist/cli/explain.d.ts +2 -0
- package/dist/cli/explain.d.ts.map +1 -0
- package/dist/cli/explain.js +266 -0
- package/dist/cli/explain.js.map +1 -0
- package/dist/cli/export-sessions.d.ts +2 -0
- package/dist/cli/export-sessions.d.ts.map +1 -0
- package/dist/cli/export-sessions.js +182 -0
- package/dist/cli/export-sessions.js.map +1 -0
- package/dist/cli/export.d.ts +2 -0
- package/dist/cli/export.d.ts.map +1 -0
- package/dist/cli/export.js +222 -0
- package/dist/cli/export.js.map +1 -0
- package/dist/cli/extractors/common.d.ts +27 -0
- package/dist/cli/extractors/common.d.ts.map +1 -0
- package/dist/cli/extractors/common.js +107 -0
- package/dist/cli/extractors/common.js.map +1 -0
- package/dist/cli/extractors/generic.d.ts +37 -0
- package/dist/cli/extractors/generic.d.ts.map +1 -0
- package/dist/cli/extractors/generic.js +185 -0
- package/dist/cli/extractors/generic.js.map +1 -0
- package/dist/cli/extractors/langchain.d.ts +18 -0
- package/dist/cli/extractors/langchain.d.ts.map +1 -0
- package/dist/cli/extractors/langchain.js +86 -0
- package/dist/cli/extractors/langchain.js.map +1 -0
- package/dist/cli/extractors/vercel.d.ts +17 -0
- package/dist/cli/extractors/vercel.d.ts.map +1 -0
- package/dist/cli/extractors/vercel.js +46 -0
- package/dist/cli/extractors/vercel.js.map +1 -0
- package/dist/cli/index.d.ts +38 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +146 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/init.d.ts +2 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +177 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/mode.d.ts +2 -0
- package/dist/cli/mode.d.ts.map +1 -0
- package/dist/cli/mode.js +71 -0
- package/dist/cli/mode.js.map +1 -0
- package/dist/cli/onboard.d.ts +88 -0
- package/dist/cli/onboard.d.ts.map +1 -0
- package/dist/cli/onboard.js +758 -0
- package/dist/cli/onboard.js.map +1 -0
- package/dist/cli/otlp.d.ts +27 -0
- package/dist/cli/otlp.d.ts.map +1 -0
- package/dist/cli/otlp.js +79 -0
- package/dist/cli/otlp.js.map +1 -0
- package/dist/cli/package.json +1 -0
- package/dist/cli/packs.d.ts +16 -0
- package/dist/cli/packs.d.ts.map +1 -0
- package/dist/cli/packs.js +184 -0
- package/dist/cli/packs.js.map +1 -0
- package/dist/cli/patterns.d.ts +15 -0
- package/dist/cli/patterns.d.ts.map +1 -0
- package/dist/cli/patterns.js +135 -0
- package/dist/cli/patterns.js.map +1 -0
- package/dist/cli/prompt.d.ts +2 -0
- package/dist/cli/prompt.d.ts.map +1 -0
- package/dist/cli/prompt.js +54 -0
- package/dist/cli/prompt.js.map +1 -0
- package/dist/cli/replay.d.ts +2 -0
- package/dist/cli/replay.d.ts.map +1 -0
- package/dist/cli/replay.js +196 -0
- package/dist/cli/replay.js.map +1 -0
- package/dist/cli/report.d.ts +57 -0
- package/dist/cli/report.d.ts.map +1 -0
- package/dist/cli/report.js +298 -0
- package/dist/cli/report.js.map +1 -0
- package/dist/cli/scan.d.ts +2 -0
- package/dist/cli/scan.d.ts.map +1 -0
- package/dist/cli/scan.js +172 -0
- package/dist/cli/scan.js.map +1 -0
- package/dist/cli/skill.d.ts +15 -0
- package/dist/cli/skill.d.ts.map +1 -0
- package/dist/cli/skill.js +131 -0
- package/dist/cli/skill.js.map +1 -0
- package/dist/cli/tokens.d.ts +31 -0
- package/dist/cli/tokens.d.ts.map +1 -0
- package/dist/cli/tokens.js +73 -0
- package/dist/cli/tokens.js.map +1 -0
- package/dist/cli/types.d.ts +46 -0
- package/dist/cli/types.d.ts.map +1 -0
- package/dist/cli/types.js +3 -0
- package/dist/cli/types.js.map +1 -0
- package/dist/cli/validate.d.ts +19 -0
- package/dist/cli/validate.d.ts.map +1 -0
- package/dist/cli/validate.js +205 -0
- package/dist/cli/validate.js.map +1 -0
- package/dist/cli/zod.d.ts +36 -0
- package/dist/cli/zod.d.ts.map +1 -0
- package/dist/cli/zod.js +226 -0
- package/dist/cli/zod.js.map +1 -0
- package/dist/contract.d.ts +13 -13
- package/dist/contract.d.ts.map +1 -1
- package/dist/contract.js +21 -21
- package/dist/contract.js.map +1 -1
- package/dist/core/config-loader.d.ts +1 -1
- package/dist/core/config-loader.js +35 -17
- package/dist/core/config-loader.js.map +1 -1
- package/dist/core/grounding.d.ts +49 -2
- package/dist/core/grounding.d.ts.map +1 -1
- package/dist/core/grounding.js +302 -142
- package/dist/core/grounding.js.map +1 -1
- package/dist/core/nl-parser.d.ts.map +1 -1
- package/dist/core/nl-parser.js +74 -2
- package/dist/core/nl-parser.js.map +1 -1
- package/dist/core/pattern-factory.d.ts +4 -4
- package/dist/core/pattern-factory.d.ts.map +1 -1
- package/dist/core/pattern-factory.js +46 -4
- package/dist/core/pattern-factory.js.map +1 -1
- package/dist/core/patterns.d.ts +78 -4
- package/dist/core/patterns.d.ts.map +1 -1
- package/dist/core/patterns.js +211 -3
- package/dist/core/patterns.js.map +1 -1
- package/dist/core/spans.d.ts +1 -1
- package/dist/core/spans.d.ts.map +1 -1
- package/dist/core/spans.js.map +1 -1
- package/dist/core/sto.d.ts +32 -62
- package/dist/core/sto.d.ts.map +1 -1
- package/dist/core/sto.js +32 -90
- package/dist/core/sto.js.map +1 -1
- package/dist/index.d.ts +77 -32
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +172 -133
- package/dist/index.js.map +1 -1
- package/dist/integrations/openai-agents.d.ts.map +1 -1
- package/dist/integrations/openai-agents.js +5 -4
- package/dist/integrations/openai-agents.js.map +1 -1
- package/dist/render/tokens.d.ts.map +1 -1
- package/dist/render/tokens.js +1 -0
- package/dist/render/tokens.js.map +1 -1
- package/package.json +28 -4
- package/prompts/onboard.md +250 -0
- package/prompts/refresh.md +118 -0
- package/prompts/scan.md +125 -0
- package/skills/SKILL.md +502 -0
package/bin/sponsio.cjs
ADDED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|