@trac3er/oh-my-god 2.0.2 → 2.0.4
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/.agents/skills/omg/AGENTS.fragment.md +5 -0
- package/.agents/skills/omg/codex-mcp.toml +4 -0
- package/.agents/skills/omg/control-plane/SKILL.md +11 -0
- package/.agents/skills/omg/control-plane/openai.yaml +14 -0
- package/.agents/skills/omg/hook-governor/SKILL.md +11 -0
- package/.agents/skills/omg/hook-governor/openai.yaml +11 -0
- package/.agents/skills/omg/lsp-pack/SKILL.md +11 -0
- package/.agents/skills/omg/lsp-pack/openai.yaml +11 -0
- package/.agents/skills/omg/mcp-fabric/SKILL.md +11 -0
- package/.agents/skills/omg/mcp-fabric/openai.yaml +13 -0
- package/.agents/skills/omg/secure-worktree-pipeline/SKILL.md +11 -0
- package/.agents/skills/omg/secure-worktree-pipeline/openai.yaml +12 -0
- package/.claude-plugin/marketplace.json +3 -3
- package/.claude-plugin/plugin.json +1 -1
- package/.mcp.json +20 -4
- package/CHANGELOG.md +16 -0
- package/OMG-setup.sh +9 -3
- package/OMG_COMPAT_CONTRACT.md +92 -0
- package/README.md +26 -8
- package/SECURITY.md +6 -0
- package/commands/OMG:api-twin.md +22 -0
- package/commands/OMG:preflight.md +26 -0
- package/commands/OMG:security-check.md +28 -0
- package/commands/OMG:setup.md +1 -2
- package/dist/enterprise/bundle/.agents/skills/omg/AGENTS.fragment.md +5 -0
- package/dist/enterprise/bundle/.agents/skills/omg/codex-mcp.toml +4 -0
- package/dist/enterprise/bundle/.agents/skills/omg/control-plane/SKILL.md +11 -0
- package/dist/enterprise/bundle/.agents/skills/omg/control-plane/openai.yaml +14 -0
- package/dist/enterprise/bundle/.agents/skills/omg/hook-governor/SKILL.md +11 -0
- package/dist/enterprise/bundle/.agents/skills/omg/hook-governor/openai.yaml +11 -0
- package/dist/enterprise/bundle/.agents/skills/omg/lsp-pack/SKILL.md +11 -0
- package/dist/enterprise/bundle/.agents/skills/omg/lsp-pack/openai.yaml +11 -0
- package/dist/enterprise/bundle/.agents/skills/omg/mcp-fabric/SKILL.md +11 -0
- package/dist/enterprise/bundle/.agents/skills/omg/mcp-fabric/openai.yaml +13 -0
- package/dist/enterprise/bundle/.agents/skills/omg/secure-worktree-pipeline/SKILL.md +11 -0
- package/dist/enterprise/bundle/.agents/skills/omg/secure-worktree-pipeline/openai.yaml +12 -0
- package/dist/enterprise/bundle/.claude-plugin/marketplace.json +36 -0
- package/dist/enterprise/bundle/.claude-plugin/plugin.json +23 -0
- package/dist/enterprise/bundle/.mcp.json +40 -0
- package/dist/enterprise/bundle/OMG_COMPAT_CONTRACT.md +92 -0
- package/dist/enterprise/bundle/settings.json +366 -0
- package/dist/enterprise/manifest.json +99 -0
- package/dist/public/bundle/.agents/skills/omg/AGENTS.fragment.md +5 -0
- package/dist/public/bundle/.agents/skills/omg/codex-mcp.toml +4 -0
- package/dist/public/bundle/.agents/skills/omg/control-plane/SKILL.md +11 -0
- package/dist/public/bundle/.agents/skills/omg/control-plane/openai.yaml +14 -0
- package/dist/public/bundle/.agents/skills/omg/hook-governor/SKILL.md +11 -0
- package/dist/public/bundle/.agents/skills/omg/hook-governor/openai.yaml +11 -0
- package/dist/public/bundle/.agents/skills/omg/lsp-pack/SKILL.md +11 -0
- package/dist/public/bundle/.agents/skills/omg/lsp-pack/openai.yaml +11 -0
- package/dist/public/bundle/.agents/skills/omg/mcp-fabric/SKILL.md +11 -0
- package/dist/public/bundle/.agents/skills/omg/mcp-fabric/openai.yaml +13 -0
- package/dist/public/bundle/.agents/skills/omg/secure-worktree-pipeline/SKILL.md +11 -0
- package/dist/public/bundle/.agents/skills/omg/secure-worktree-pipeline/openai.yaml +12 -0
- package/dist/public/bundle/.claude-plugin/marketplace.json +36 -0
- package/dist/public/bundle/.claude-plugin/plugin.json +23 -0
- package/dist/public/bundle/.mcp.json +40 -0
- package/dist/public/bundle/OMG_COMPAT_CONTRACT.md +92 -0
- package/dist/public/bundle/settings.json +366 -0
- package/dist/public/manifest.json +99 -0
- package/hooks/policy_engine.py +38 -7
- package/hooks/post-write.py +1 -1
- package/hooks/prompt-enhancer.py +2 -2
- package/hooks/security_validators.py +75 -0
- package/hooks/setup_wizard.py +44 -20
- package/hooks/shadow_manager.py +22 -2
- package/package.json +1 -1
- package/plugins/README.md +4 -2
- package/plugins/advanced/commands/OMG:deep-plan.md +1 -1
- package/plugins/advanced/commands/OMG:security-review.md +10 -113
- package/plugins/advanced/commands/OMG:ship.md +1 -1
- package/plugins/advanced/plugin.json +1 -10
- package/plugins/core/plugin.json +25 -2
- package/pyproject.toml +1 -1
- package/runtime/adoption.py +1 -1
- package/runtime/api_twin.py +130 -0
- package/runtime/compat.py +21 -1
- package/runtime/contract_compiler.py +698 -0
- package/runtime/domain_packs.py +34 -0
- package/runtime/guide_assert.py +45 -0
- package/runtime/mcp_config_writers.py +145 -39
- package/runtime/omg_compat_contract_snapshot.json +8 -7
- package/runtime/omg_contract_snapshot.json +8 -7
- package/runtime/omg_mcp_server.py +205 -0
- package/runtime/preflight.py +52 -0
- package/runtime/providers/codex_provider.py +2 -12
- package/runtime/providers/gemini_provider.py +2 -21
- package/runtime/providers/kimi_provider.py +2 -21
- package/runtime/runtime_profile.py +61 -0
- package/runtime/security_check.py +347 -0
- package/runtime/subagent_dispatcher.py +117 -10
- package/runtime/team_router.py +3 -3
- package/runtime/untrusted_content.py +102 -0
- package/scripts/omg.py +174 -1
- package/settings.json +66 -18
- package/tools/python_repl.py +33 -3
- package/runtime/providers/opencode_provider.py +0 -144
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json.schemastore.org/claude-code-settings.json",
|
|
3
|
+
"_comment": "OMG 2.0.4 - project-level config with hook registrations, presets, and feature flags.",
|
|
4
|
+
"permissions": {
|
|
5
|
+
"allow": [
|
|
6
|
+
"Agent",
|
|
7
|
+
"Read",
|
|
8
|
+
"Write",
|
|
9
|
+
"Edit",
|
|
10
|
+
"MultiEdit",
|
|
11
|
+
"Grep",
|
|
12
|
+
"Glob",
|
|
13
|
+
"Bash(ls *)",
|
|
14
|
+
"Bash(cat *)",
|
|
15
|
+
"Bash(head *)",
|
|
16
|
+
"Bash(tail *)",
|
|
17
|
+
"Bash(wc *)",
|
|
18
|
+
"Bash(grep *)",
|
|
19
|
+
"Bash(find *)",
|
|
20
|
+
"Bash(which *)",
|
|
21
|
+
"Bash(echo *)",
|
|
22
|
+
"Bash(printf *)",
|
|
23
|
+
"Bash(pwd)",
|
|
24
|
+
"Bash(whoami)",
|
|
25
|
+
"Bash(date *)",
|
|
26
|
+
"Bash(basename *)",
|
|
27
|
+
"Bash(dirname *)",
|
|
28
|
+
"Bash(realpath *)",
|
|
29
|
+
"Bash(stat *)",
|
|
30
|
+
"Bash(file *)",
|
|
31
|
+
"Bash(diff *)",
|
|
32
|
+
"Bash(sort *)",
|
|
33
|
+
"Bash(uniq *)",
|
|
34
|
+
"Bash(awk *)",
|
|
35
|
+
"Bash(sed *)",
|
|
36
|
+
"Bash(tr *)",
|
|
37
|
+
"Bash(cut *)",
|
|
38
|
+
"Bash(tee *)",
|
|
39
|
+
"Bash(xargs *)",
|
|
40
|
+
"Bash(jq *)",
|
|
41
|
+
"Bash(yq *)",
|
|
42
|
+
"Bash(tree *)",
|
|
43
|
+
"Bash(du *)",
|
|
44
|
+
"Bash(df *)",
|
|
45
|
+
"Bash(type *)",
|
|
46
|
+
"Bash(command *)",
|
|
47
|
+
"Bash(test *)",
|
|
48
|
+
"Bash([ *)",
|
|
49
|
+
"Bash(mkdir *)",
|
|
50
|
+
"Bash(touch *)",
|
|
51
|
+
"Bash(ln *)",
|
|
52
|
+
"Bash(cp *)",
|
|
53
|
+
"Bash(mv *)",
|
|
54
|
+
"Bash(git *)",
|
|
55
|
+
"Bash(npm *)",
|
|
56
|
+
"Bash(npx *)",
|
|
57
|
+
"Bash(yarn *)",
|
|
58
|
+
"Bash(pnpm *)",
|
|
59
|
+
"Bash(bun *)",
|
|
60
|
+
"Bash(pip *)",
|
|
61
|
+
"Bash(pip3 *)",
|
|
62
|
+
"Bash(uv *)",
|
|
63
|
+
"Bash(go *)",
|
|
64
|
+
"Bash(cargo *)",
|
|
65
|
+
"Bash(rustc *)",
|
|
66
|
+
"Bash(tsc *)",
|
|
67
|
+
"Bash(eslint *)",
|
|
68
|
+
"Bash(prettier *)",
|
|
69
|
+
"Bash(mypy *)",
|
|
70
|
+
"Bash(ruff *)",
|
|
71
|
+
"Bash(ruff format *)",
|
|
72
|
+
"Bash(pytest *)",
|
|
73
|
+
"Bash(jest *)",
|
|
74
|
+
"Bash(vitest *)",
|
|
75
|
+
"Bash(shellcheck *)",
|
|
76
|
+
"Bash(terraform validate *)",
|
|
77
|
+
"Bash(terraform fmt *)",
|
|
78
|
+
"Bash(terraform plan *)",
|
|
79
|
+
"Bash(terraform show *)",
|
|
80
|
+
"Bash(terraform state list *)",
|
|
81
|
+
"Bash(tmux *)",
|
|
82
|
+
"Bash(zip *)",
|
|
83
|
+
"Bash(unzip *)",
|
|
84
|
+
"Bash(tar *)",
|
|
85
|
+
"Bash(gzip *)",
|
|
86
|
+
"Bash(rg *)",
|
|
87
|
+
"Bash(gh *)"
|
|
88
|
+
],
|
|
89
|
+
"ask": [
|
|
90
|
+
"Bash(curl *)",
|
|
91
|
+
"Bash(wget *)",
|
|
92
|
+
"Bash(ssh *)",
|
|
93
|
+
"Bash(scp *)",
|
|
94
|
+
"Bash(rsync *)",
|
|
95
|
+
"Bash(rm *)",
|
|
96
|
+
"Bash(sudo *)",
|
|
97
|
+
"Bash(kill *)",
|
|
98
|
+
"Bash(pkill *)",
|
|
99
|
+
"Bash(systemctl *)",
|
|
100
|
+
"Bash(reboot)",
|
|
101
|
+
"Bash(shutdown *)",
|
|
102
|
+
"Bash(dd *)",
|
|
103
|
+
"Bash(fdisk *)",
|
|
104
|
+
"Bash(mkfs *)",
|
|
105
|
+
"Bash(mount *)",
|
|
106
|
+
"Bash(umount *)",
|
|
107
|
+
"Bash(iptables *)",
|
|
108
|
+
"Bash(ufw *)",
|
|
109
|
+
"Bash(terraform apply *)",
|
|
110
|
+
"Bash(terraform destroy *)",
|
|
111
|
+
"Bash(terraform import *)",
|
|
112
|
+
"Bash(env *)",
|
|
113
|
+
"Bash(node *)",
|
|
114
|
+
"Bash(python *)",
|
|
115
|
+
"Bash(python3 *)",
|
|
116
|
+
"Bash(chmod *)",
|
|
117
|
+
"Bash(chown *)",
|
|
118
|
+
"Bash(docker *)",
|
|
119
|
+
"Bash(docker-compose *)",
|
|
120
|
+
"Bash(kubectl get *)",
|
|
121
|
+
"Bash(kubectl describe *)",
|
|
122
|
+
"Bash(kubectl logs *)",
|
|
123
|
+
"Bash(kubectl apply *)",
|
|
124
|
+
"Bash(kubectl exec *)",
|
|
125
|
+
"Bash(kubectl edit *)",
|
|
126
|
+
"Bash(kubectl patch *)",
|
|
127
|
+
"Bash(kubectl rollout *)",
|
|
128
|
+
"Bash(kubectl scale *)",
|
|
129
|
+
"Bash(kubectl port-forward *)",
|
|
130
|
+
"Bash(kubectl config *)",
|
|
131
|
+
"Bash(kubectl top *)",
|
|
132
|
+
"Bash(kubectl delete *)"
|
|
133
|
+
],
|
|
134
|
+
"deny": [
|
|
135
|
+
"Bash(rm -rf /)",
|
|
136
|
+
"Bash(rm -rf /*)",
|
|
137
|
+
"Bash(rm -rf ~)",
|
|
138
|
+
"Bash(rm -rf ~/*)",
|
|
139
|
+
"Bash(sudo rm *)",
|
|
140
|
+
"Bash(sudo dd *)",
|
|
141
|
+
"Bash(sudo mkfs *)",
|
|
142
|
+
"Bash(:(){ :|:& };:)",
|
|
143
|
+
"Read(./.env)",
|
|
144
|
+
"Read(./secrets/**)",
|
|
145
|
+
"Read(**/.env)",
|
|
146
|
+
"Read(**/secrets/**)",
|
|
147
|
+
"Read(**/.aws/credentials)",
|
|
148
|
+
"Read(**/.aws/config)",
|
|
149
|
+
"Read(**/.kube/config)",
|
|
150
|
+
"Read(**/.ssh/*)",
|
|
151
|
+
"Read(**/*.pem)",
|
|
152
|
+
"Read(**/*.key)",
|
|
153
|
+
"Read(**/*.p12)",
|
|
154
|
+
"Read(**/*.pfx)",
|
|
155
|
+
"Read(**/.npmrc)",
|
|
156
|
+
"Read(**/.pypirc)",
|
|
157
|
+
"Read(**/.netrc)",
|
|
158
|
+
"Read(**/id_rsa*)",
|
|
159
|
+
"Read(**/id_ed25519*)",
|
|
160
|
+
"Read(**/id_ecdsa*)",
|
|
161
|
+
"Write(./.env)",
|
|
162
|
+
"Read(./.env.*)",
|
|
163
|
+
"Read(**/.env.*)",
|
|
164
|
+
"Write(./.env.*)",
|
|
165
|
+
"Write(./secrets/**)"
|
|
166
|
+
]
|
|
167
|
+
},
|
|
168
|
+
"hooks": {
|
|
169
|
+
"SessionStart": [
|
|
170
|
+
{
|
|
171
|
+
"hooks": [
|
|
172
|
+
{
|
|
173
|
+
"type": "command",
|
|
174
|
+
"command": "python3 \"$HOME/.claude/hooks/session-start.py\"",
|
|
175
|
+
"timeout": 10
|
|
176
|
+
}
|
|
177
|
+
]
|
|
178
|
+
}
|
|
179
|
+
],
|
|
180
|
+
"SessionEnd": [
|
|
181
|
+
{
|
|
182
|
+
"hooks": [
|
|
183
|
+
{
|
|
184
|
+
"type": "command",
|
|
185
|
+
"command": "python3 \"$HOME/.claude/hooks/session-end-capture.py\""
|
|
186
|
+
}
|
|
187
|
+
]
|
|
188
|
+
}
|
|
189
|
+
],
|
|
190
|
+
"PreToolUse": [
|
|
191
|
+
{
|
|
192
|
+
"hooks": [
|
|
193
|
+
{
|
|
194
|
+
"type": "command",
|
|
195
|
+
"command": "python3 \"$HOME/.claude/hooks/firewall.py\"",
|
|
196
|
+
"timeout": 10
|
|
197
|
+
}
|
|
198
|
+
],
|
|
199
|
+
"matcher": "Bash"
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
"hooks": [
|
|
203
|
+
{
|
|
204
|
+
"type": "command",
|
|
205
|
+
"command": "python3 \"$HOME/.claude/hooks/secret-guard.py\"",
|
|
206
|
+
"timeout": 10
|
|
207
|
+
}
|
|
208
|
+
],
|
|
209
|
+
"matcher": "Read|Write|Edit|MultiEdit"
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
"hooks": [
|
|
213
|
+
{
|
|
214
|
+
"type": "command",
|
|
215
|
+
"command": "python3 \"$HOME/.claude/hooks/pre-tool-inject.py\""
|
|
216
|
+
}
|
|
217
|
+
],
|
|
218
|
+
"matcher": ""
|
|
219
|
+
}
|
|
220
|
+
],
|
|
221
|
+
"PostToolUse": [
|
|
222
|
+
{
|
|
223
|
+
"hooks": [
|
|
224
|
+
{
|
|
225
|
+
"type": "command",
|
|
226
|
+
"command": "python3 \"$HOME/.claude/hooks/circuit-breaker.py\"",
|
|
227
|
+
"timeout": 10
|
|
228
|
+
}
|
|
229
|
+
],
|
|
230
|
+
"matcher": "Bash"
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
"hooks": [
|
|
234
|
+
{
|
|
235
|
+
"type": "command",
|
|
236
|
+
"command": "python3 \"$HOME/.claude/hooks/tool-ledger.py\"",
|
|
237
|
+
"timeout": 10
|
|
238
|
+
}
|
|
239
|
+
],
|
|
240
|
+
"matcher": "Write|Edit|MultiEdit"
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
"hooks": [
|
|
244
|
+
{
|
|
245
|
+
"type": "command",
|
|
246
|
+
"command": "python3 \"$HOME/.claude/hooks/test_generator_hook.py\"",
|
|
247
|
+
"timeout": 10
|
|
248
|
+
}
|
|
249
|
+
],
|
|
250
|
+
"matcher": "Write|Edit|MultiEdit"
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
"hooks": [
|
|
254
|
+
{
|
|
255
|
+
"type": "command",
|
|
256
|
+
"command": "python3 \"$HOME/.claude/hooks/budget_governor.py\"",
|
|
257
|
+
"timeout": 10
|
|
258
|
+
}
|
|
259
|
+
],
|
|
260
|
+
"matcher": ""
|
|
261
|
+
}
|
|
262
|
+
],
|
|
263
|
+
"PostToolUseFailure": [
|
|
264
|
+
{
|
|
265
|
+
"hooks": [
|
|
266
|
+
{
|
|
267
|
+
"type": "command",
|
|
268
|
+
"command": "python3 \"$HOME/.claude/hooks/post-tool-failure.py\""
|
|
269
|
+
}
|
|
270
|
+
]
|
|
271
|
+
}
|
|
272
|
+
],
|
|
273
|
+
"Stop": [
|
|
274
|
+
{
|
|
275
|
+
"hooks": [
|
|
276
|
+
{
|
|
277
|
+
"type": "command",
|
|
278
|
+
"command": "python3 \"$HOME/.claude/hooks/stop_dispatcher.py\"",
|
|
279
|
+
"timeout": 90
|
|
280
|
+
}
|
|
281
|
+
],
|
|
282
|
+
"matcher": ""
|
|
283
|
+
}
|
|
284
|
+
]
|
|
285
|
+
},
|
|
286
|
+
"_omg": {
|
|
287
|
+
"_version": "2.0.4",
|
|
288
|
+
"preset": "safe",
|
|
289
|
+
"default_mode": "ulw+ralph",
|
|
290
|
+
"vision_auto": true,
|
|
291
|
+
"false_fix_detection": true,
|
|
292
|
+
"cost_budget": {
|
|
293
|
+
"session_limit_usd": 5.0,
|
|
294
|
+
"thresholds": [
|
|
295
|
+
50,
|
|
296
|
+
80,
|
|
297
|
+
95
|
|
298
|
+
],
|
|
299
|
+
"pricing": {
|
|
300
|
+
"input_per_mtok": 3.0,
|
|
301
|
+
"output_per_mtok": 15.0
|
|
302
|
+
}
|
|
303
|
+
},
|
|
304
|
+
"context_budget": {
|
|
305
|
+
"session_start_max_chars": 2000,
|
|
306
|
+
"prompt_enhancer_max_chars": 800,
|
|
307
|
+
"prompt_enhancer_max_injections": 10,
|
|
308
|
+
"full_turns": 10,
|
|
309
|
+
"summarize_turns": 50,
|
|
310
|
+
"batch_size": 21
|
|
311
|
+
},
|
|
312
|
+
"credentials": {
|
|
313
|
+
"rotation_schedule_days": 90,
|
|
314
|
+
"expiry_warning_days": 14
|
|
315
|
+
},
|
|
316
|
+
"features": {
|
|
317
|
+
"memory": false,
|
|
318
|
+
"ralph_loop": true,
|
|
319
|
+
"planning_enforcement": true,
|
|
320
|
+
"compound_learning": false,
|
|
321
|
+
"simplifier": true,
|
|
322
|
+
"model_routing": true,
|
|
323
|
+
"agent_registry": true,
|
|
324
|
+
"circuit_breaker_v2": true,
|
|
325
|
+
"cognitive_modes": true,
|
|
326
|
+
"agent_routing": true,
|
|
327
|
+
"SETUP": false,
|
|
328
|
+
"SETUP_WIZARD": false,
|
|
329
|
+
"MEMORY_SERVER": false,
|
|
330
|
+
"MEMORY_AUTOSTART": false,
|
|
331
|
+
"COST_TRACKING": false,
|
|
332
|
+
"GIT_WORKFLOW": false,
|
|
333
|
+
"SESSION_ANALYTICS": false,
|
|
334
|
+
"TEST_GENERATION": false,
|
|
335
|
+
"DEP_HEALTH": false,
|
|
336
|
+
"CODEBASE_VIZ": false,
|
|
337
|
+
"CONTEXT_MANAGER": false
|
|
338
|
+
},
|
|
339
|
+
"generated": {
|
|
340
|
+
"contract_version": "2.0.4",
|
|
341
|
+
"channel": "public",
|
|
342
|
+
"required_bundles": [
|
|
343
|
+
"control-plane",
|
|
344
|
+
"hook-governor",
|
|
345
|
+
"mcp-fabric",
|
|
346
|
+
"lsp-pack",
|
|
347
|
+
"secure-worktree-pipeline"
|
|
348
|
+
],
|
|
349
|
+
"protected_paths": [
|
|
350
|
+
".omg/**",
|
|
351
|
+
".agents/**",
|
|
352
|
+
".codex/**",
|
|
353
|
+
".claude/**"
|
|
354
|
+
],
|
|
355
|
+
"emulated_events": [
|
|
356
|
+
"PreCompact",
|
|
357
|
+
"ConfigChange",
|
|
358
|
+
"WorktreeCreate",
|
|
359
|
+
"WorktreeRemove",
|
|
360
|
+
"SubagentStart",
|
|
361
|
+
"SubagentStop",
|
|
362
|
+
"TaskCompleted"
|
|
363
|
+
]
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema": "OmgCompiledArtifactManifest",
|
|
3
|
+
"channel": "public",
|
|
4
|
+
"contract_version": "2.0.4",
|
|
5
|
+
"artifacts": [
|
|
6
|
+
{
|
|
7
|
+
"path": "bundle/.agents/skills/omg/AGENTS.fragment.md",
|
|
8
|
+
"sha256": "603430cb291632105fda7444ae018da521cc3a57c71c1a1c98179efea42ce0f2"
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"path": "bundle/.agents/skills/omg/codex-mcp.toml",
|
|
12
|
+
"sha256": "a56de208a369a2b318d2e66e150eef4cba1fac1ecf32bda6db1a1e4b65db7311"
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"path": "bundle/.agents/skills/omg/control-plane/SKILL.md",
|
|
16
|
+
"sha256": "fe281985ffbfb4d324d0ae421653c96d501bfda4ef1462865e2868276c40a3c2"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"path": "bundle/.agents/skills/omg/control-plane/openai.yaml",
|
|
20
|
+
"sha256": "a7ba723d34839c6a444b6ee4416223103cd9b2bbd9caed0d4c0aa1e7d5a523fc"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"path": "bundle/.agents/skills/omg/hook-governor/SKILL.md",
|
|
24
|
+
"sha256": "852df4b5f787f2a885e87cb8ad8dbb8d877e018e14083cfd5e5b98deb9dd19b5"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"path": "bundle/.agents/skills/omg/hook-governor/openai.yaml",
|
|
28
|
+
"sha256": "8b4e219662bd9a12e89cdcd9a1828c1ff14810fa09cbfff9a6d9f932fb42ec85"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"path": "bundle/.agents/skills/omg/lsp-pack/SKILL.md",
|
|
32
|
+
"sha256": "86890c6671441f8687ad7d71dedd7d61574c42aa6e109aa8dd6ceb4b6a139879"
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"path": "bundle/.agents/skills/omg/lsp-pack/openai.yaml",
|
|
36
|
+
"sha256": "14000aec9cc9ff630b7354ae101cc43ed90c4e1ecd0fa719013741ca14598142"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"path": "bundle/.agents/skills/omg/mcp-fabric/SKILL.md",
|
|
40
|
+
"sha256": "e741baf4fa5f09957fe37349b79fe6831afe0352eefa945f3e53514ea313bc36"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"path": "bundle/.agents/skills/omg/mcp-fabric/openai.yaml",
|
|
44
|
+
"sha256": "18dc35b4d6fb598b572ec933153e80de5449be9e07ef07178e4f875e39a8915c"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"path": "bundle/.agents/skills/omg/secure-worktree-pipeline/SKILL.md",
|
|
48
|
+
"sha256": "1eebd557d77cc084161c3ffe11ed3a9ea5d78caa65b1021a992ac8b835fc6a0d"
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"path": "bundle/.agents/skills/omg/secure-worktree-pipeline/openai.yaml",
|
|
52
|
+
"sha256": "1f82a05b2fcad17c126e34541c995dedf3ed242fa499539ab693cc60a0d41c77"
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"path": "bundle/.claude-plugin/marketplace.json",
|
|
56
|
+
"sha256": "cf1a17ce1e8db6814209126a79d5a05d057f354ef3ee49a74da4f18f2ec04597"
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"path": "bundle/.claude-plugin/plugin.json",
|
|
60
|
+
"sha256": "6ad6db257f9e46528d94760ef895b6ffc87c78a8ec5ca05b430a46b46ee3dc08"
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"path": "bundle/.mcp.json",
|
|
64
|
+
"sha256": "d8249fdd26e0df0a9b7cabcb34256d7e33578e1d0e9878cc91d43452a10f7c24"
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"path": "bundle/OMG_COMPAT_CONTRACT.md",
|
|
68
|
+
"sha256": "fa91ec0dbff58d543df5a9e3a86a1fe1629104a383d4e1bd440a36cb5522189c"
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"path": "bundle/registry/bundles/control-plane.yaml",
|
|
72
|
+
"sha256": "bb58e1d21a7f545548da10e7f9b83898d6ece8010a921b66d0f94a08c8ae0d8e"
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"path": "bundle/registry/bundles/hook-governor.yaml",
|
|
76
|
+
"sha256": "93b13ea1e2098328349d33373595144f2f863274548bef47fd266d6cab210260"
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
"path": "bundle/registry/bundles/lsp-pack.yaml",
|
|
80
|
+
"sha256": "6c2ca235bdca31635d89c428c48a35a5414250e98c7349cd67ba900870203d9a"
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"path": "bundle/registry/bundles/mcp-fabric.yaml",
|
|
84
|
+
"sha256": "2cb71fc331820b19c60c3275f521fb49d099ed7c31539fab9959a55d29ae0fe9"
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"path": "bundle/registry/bundles/secure-worktree-pipeline.yaml",
|
|
88
|
+
"sha256": "b93e752cef8b5cbc76fb7aa32ebe80d30ce390193183bb0c79dedfa1ce89c4e9"
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
"path": "bundle/registry/omg-capability.schema.json",
|
|
92
|
+
"sha256": "b5a52c03c6d42c0ce0297a2d8c22f34ed1075062cc5434d3a85b9f4fa6a0f121"
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"path": "bundle/settings.json",
|
|
96
|
+
"sha256": "60fb4f9e2bedd4d67af41a2e442ef37c9a89cd2077bf6dfe40761eec01586824"
|
|
97
|
+
}
|
|
98
|
+
]
|
|
99
|
+
}
|
package/hooks/policy_engine.py
CHANGED
|
@@ -115,6 +115,23 @@ ASK_PATTERNS = [
|
|
|
115
115
|
(r"node\s+-e\s+", "Inline Node execution"),
|
|
116
116
|
]
|
|
117
117
|
|
|
118
|
+
UNTRUSTED_MUTATION_PATTERNS = [
|
|
119
|
+
r"\bgit\s+(commit|push|tag)\b",
|
|
120
|
+
r"\bnpm\s+(install|publish)\b",
|
|
121
|
+
r"\bpython[23]?\s+.*\b(setup\.py|manage\.py)\b",
|
|
122
|
+
r"\b(mv|cp|tee|sed\s+-i|touch|mkdir)\b",
|
|
123
|
+
]
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def _is_untrusted_content_mode_active() -> bool:
|
|
127
|
+
try:
|
|
128
|
+
from runtime.untrusted_content import is_untrusted_content_mode_active
|
|
129
|
+
|
|
130
|
+
project_dir = os.environ.get("CLAUDE_PROJECT_DIR", os.getcwd())
|
|
131
|
+
return is_untrusted_content_mode_active(project_dir)
|
|
132
|
+
except Exception:
|
|
133
|
+
return False
|
|
134
|
+
|
|
118
135
|
|
|
119
136
|
def evaluate_bash_command(cmd: str) -> PolicyDecision:
|
|
120
137
|
if not cmd:
|
|
@@ -158,6 +175,15 @@ def evaluate_bash_command(cmd: str) -> PolicyDecision:
|
|
|
158
175
|
if re.search(pat, cmd):
|
|
159
176
|
return ask(f"{label}: {cmd[:120]}", "med", ["human-approval"])
|
|
160
177
|
|
|
178
|
+
if _is_untrusted_content_mode_active():
|
|
179
|
+
for pat in UNTRUSTED_MUTATION_PATTERNS:
|
|
180
|
+
if re.search(pat, cmd):
|
|
181
|
+
return ask(
|
|
182
|
+
"Untrusted external content mode is active. Review before running state-changing commands.",
|
|
183
|
+
"high",
|
|
184
|
+
["manual-approval", "review-provenance"],
|
|
185
|
+
)
|
|
186
|
+
|
|
161
187
|
return allow("command allowed")
|
|
162
188
|
|
|
163
189
|
|
|
@@ -409,8 +435,8 @@ def evaluate_file_access(
|
|
|
409
435
|
) -> PolicyDecision:
|
|
410
436
|
"""Evaluate file access policy.
|
|
411
437
|
|
|
412
|
-
If an allowlist is provided, matching entries override
|
|
413
|
-
for the given path and tool combination.
|
|
438
|
+
If an allowlist is provided, matching entries may override non-secret-file
|
|
439
|
+
deny decisions for the given path and tool combination.
|
|
414
440
|
"""
|
|
415
441
|
if not file_path:
|
|
416
442
|
return allow("no file")
|
|
@@ -424,11 +450,6 @@ def evaluate_file_access(
|
|
|
424
450
|
basename = os.path.basename(normalized).lower()
|
|
425
451
|
lowpath = normalized.lower()
|
|
426
452
|
|
|
427
|
-
# --- Allowlist check (before deny rules) ---
|
|
428
|
-
# Check allowlist early: if path+tool is allowlisted, override deny.
|
|
429
|
-
if allowlist and is_allowlisted(file_path, tool, allowlist):
|
|
430
|
-
return allow(f"Allowlisted: {file_path}")
|
|
431
|
-
|
|
432
453
|
if basename in EXAMPLE_FILES and tool in ("Write", "Edit", "MultiEdit"):
|
|
433
454
|
return deny(
|
|
434
455
|
f"Modifying example env file blocked (Read is allowed): {file_path}",
|
|
@@ -451,6 +472,16 @@ def evaluate_file_access(
|
|
|
451
472
|
if re.search(pat, lowpath):
|
|
452
473
|
return deny(f"Sensitive path blocked: {file_path}", "critical", ["secret-access"])
|
|
453
474
|
|
|
475
|
+
if tool in {"Write", "Edit", "MultiEdit"} and _is_untrusted_content_mode_active():
|
|
476
|
+
return ask(
|
|
477
|
+
"Untrusted external content mode is active. Review before mutating files.",
|
|
478
|
+
"high",
|
|
479
|
+
["manual-approval", "review-provenance"],
|
|
480
|
+
)
|
|
481
|
+
|
|
482
|
+
if allowlist and is_allowlisted(file_path, tool, allowlist):
|
|
483
|
+
return allow(f"Allowlisted: {file_path}")
|
|
484
|
+
|
|
454
485
|
return allow("file allowed")
|
|
455
486
|
|
|
456
487
|
|
package/hooks/post-write.py
CHANGED
|
@@ -213,7 +213,7 @@ for i, line in enumerate(content.split("\n"), 1):
|
|
|
213
213
|
|
|
214
214
|
if sec_warnings:
|
|
215
215
|
msg = f"SECURITY WARNINGS in {file_path}:\n" + "\n".join(sec_warnings[:5])
|
|
216
|
-
msg += "\n\nConsider running /OMG:security-
|
|
216
|
+
msg += "\n\nConsider running /OMG:security-check for the canonical audit pipeline."
|
|
217
217
|
print(msg, file=sys.stderr)
|
|
218
218
|
|
|
219
219
|
sys.exit(0)
|
package/hooks/prompt-enhancer.py
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"""
|
|
3
3
|
UserPromptSubmit Hook — OMG v1
|
|
4
4
|
|
|
5
|
-
Inspired by
|
|
5
|
+
Inspired by earlier OMG routing experiments. Key upgrades:
|
|
6
6
|
1. Intent classification BEFORE acting (IntentGate)
|
|
7
7
|
2. Discipline enforcement — never stop halfway
|
|
8
8
|
3. Agent-aware routing — Codex/Gemini/Claude orchestration
|
|
@@ -386,7 +386,7 @@ SECURITY_SIGNALS = [
|
|
|
386
386
|
]
|
|
387
387
|
if not route_lock and any(signal_matches_text(sig, prompt) for sig in SECURITY_SIGNALS) and budget_ok():
|
|
388
388
|
if detected_intent in ("fix", "implement", "refactor"):
|
|
389
|
-
add("@security: CRITICAL DOMAIN — No hardcoded secrets. Run /OMG:security-
|
|
389
|
+
add("@security: CRITICAL DOMAIN — No hardcoded secrets. Run /OMG:security-check after.")
|
|
390
390
|
|
|
391
391
|
# ═══════════════════════════════════════════════════════════
|
|
392
392
|
# 5. VISION DETECTION
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"""Shared validation helpers for security-sensitive filesystem and config writes."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import re
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from urllib.parse import urlparse
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
_OPAQUE_IDENTIFIER_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._-]*$")
|
|
10
|
+
_SERVER_NAME_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9_-]*$")
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def validate_opaque_identifier(value: str, field_name: str, max_length: int = 64) -> str:
|
|
14
|
+
"""Validate an opaque identifier used in filenames or paths."""
|
|
15
|
+
if not isinstance(value, str):
|
|
16
|
+
raise ValueError(f"Invalid {field_name}: must be a string")
|
|
17
|
+
|
|
18
|
+
normalized = value.strip()
|
|
19
|
+
if not normalized:
|
|
20
|
+
raise ValueError(f"Invalid {field_name}: value is required")
|
|
21
|
+
if len(normalized) > max_length:
|
|
22
|
+
raise ValueError(f"Invalid {field_name}: exceeds {max_length} characters")
|
|
23
|
+
if ".." in normalized or not _OPAQUE_IDENTIFIER_RE.fullmatch(normalized):
|
|
24
|
+
raise ValueError(
|
|
25
|
+
f"Invalid {field_name}: use only ASCII letters, numbers, dot, underscore, and dash"
|
|
26
|
+
)
|
|
27
|
+
return normalized
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def ensure_path_within_dir(base_dir: str | Path, candidate_path: str | Path) -> str:
|
|
31
|
+
"""Return a resolved path and reject traversal outside the intended base directory."""
|
|
32
|
+
base = Path(base_dir).resolve(strict=False)
|
|
33
|
+
candidate = Path(candidate_path).resolve(strict=False)
|
|
34
|
+
try:
|
|
35
|
+
candidate.relative_to(base)
|
|
36
|
+
except ValueError as exc:
|
|
37
|
+
raise ValueError(f"Resolved path escapes base directory: {candidate}") from exc
|
|
38
|
+
return str(candidate)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def validate_server_name(server_name: str, max_length: int = 64) -> str:
|
|
42
|
+
"""Validate an MCP server identifier suitable for JSON keys and TOML table names."""
|
|
43
|
+
if not isinstance(server_name, str):
|
|
44
|
+
raise ValueError("Invalid server_name: must be a string")
|
|
45
|
+
|
|
46
|
+
normalized = server_name.strip()
|
|
47
|
+
if not normalized:
|
|
48
|
+
raise ValueError("Invalid server_name: value is required")
|
|
49
|
+
if len(normalized) > max_length:
|
|
50
|
+
raise ValueError(f"Invalid server_name: exceeds {max_length} characters")
|
|
51
|
+
if not _SERVER_NAME_RE.fullmatch(normalized):
|
|
52
|
+
raise ValueError("Invalid server_name: use only ASCII letters, numbers, underscore, and dash")
|
|
53
|
+
return normalized
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def validate_server_url(server_url: str) -> str:
|
|
57
|
+
"""Validate an MCP server URL and reject newline/control injection."""
|
|
58
|
+
if not isinstance(server_url, str):
|
|
59
|
+
raise ValueError("Invalid server_url: must be a string")
|
|
60
|
+
|
|
61
|
+
normalized = server_url.strip()
|
|
62
|
+
if not normalized:
|
|
63
|
+
raise ValueError("Invalid server_url: value is required")
|
|
64
|
+
if "\n" in normalized or "\r" in normalized:
|
|
65
|
+
raise ValueError("Invalid server_url: newline characters are not allowed")
|
|
66
|
+
|
|
67
|
+
parsed = urlparse(normalized)
|
|
68
|
+
if parsed.scheme not in {"http", "https"} or not parsed.netloc:
|
|
69
|
+
raise ValueError("Invalid server_url: must be an http or https URL")
|
|
70
|
+
return normalized
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def toml_quote_string(value: str) -> str:
|
|
74
|
+
"""Escape TOML basic string content."""
|
|
75
|
+
return value.replace("\\", "\\\\").replace('"', '\\"')
|