@sponsio/sdk 0.1.0 → 0.2.0-alpha.10
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/contracts/benchmark/agentdojo.yaml +551 -0
- package/contracts/benchmark/odcv_bench.yaml +393 -0
- package/contracts/benchmark/redcode_exec.yaml +488 -0
- package/contracts/benchmark/swebench.yaml +176 -0
- package/contracts/benchmark/tau2_bench.yaml +984 -0
- package/contracts/capability/destructive.yaml +213 -0
- package/contracts/capability/factual-claims.yaml +79 -0
- package/contracts/capability/host-config-integrity.yaml +42 -9
- package/contracts/capability/self-modify.yaml +58 -12
- package/contracts/capability/shell.yaml +19 -10
- package/contracts/incident/claude-code-secret-bypass.yaml +48 -16
- package/contracts/incident/cursor-railway-wipe.yaml +60 -4
- package/contracts/incident/openclaw.yaml +9 -62
- package/contracts/premium/.gitkeep +5 -6
- package/dist/cli/cli.js +32 -0
- package/dist/cli/cli.js.map +1 -1
- package/dist/cli/packs.d.ts.map +1 -1
- package/dist/cli/packs.js +14 -8
- package/dist/cli/packs.js.map +1 -1
- package/dist/cli/patterns.d.ts +5 -4
- package/dist/cli/patterns.d.ts.map +1 -1
- package/dist/cli/patterns.js +11 -10
- package/dist/cli/patterns.js.map +1 -1
- package/dist/cli/prompt.js +5 -5
- package/dist/cli/prompt.js.map +1 -1
- package/dist/cli/scan.js +2 -2
- package/dist/cli/skill.d.ts +1 -1
- package/dist/cli/skill.js +1 -1
- package/dist/cli/validate.js +5 -5
- package/dist/cli/validate.js.map +1 -1
- package/dist/cloud/client.d.ts +76 -0
- package/dist/cloud/client.d.ts.map +1 -0
- package/dist/cloud/client.js +204 -0
- package/dist/cloud/client.js.map +1 -0
- package/dist/cloud/evidence.d.ts +108 -0
- package/dist/cloud/evidence.d.ts.map +1 -0
- package/dist/cloud/evidence.js +184 -0
- package/dist/cloud/evidence.js.map +1 -0
- package/dist/cloud/privacy.d.ts +67 -0
- package/dist/cloud/privacy.d.ts.map +1 -0
- package/dist/cloud/privacy.js +170 -0
- package/dist/cloud/privacy.js.map +1 -0
- package/dist/cloud/view-model.d.ts +49 -0
- package/dist/cloud/view-model.d.ts.map +1 -0
- package/dist/cloud/view-model.js +172 -0
- package/dist/cloud/view-model.js.map +1 -0
- package/dist/core/config-loader.d.ts.map +1 -1
- package/dist/core/config-loader.js +81 -9
- package/dist/core/config-loader.js.map +1 -1
- package/dist/core/evaluator.d.ts +11 -1
- package/dist/core/evaluator.d.ts.map +1 -1
- package/dist/core/evaluator.js +275 -13
- package/dist/core/evaluator.js.map +1 -1
- package/dist/core/formula.d.ts +76 -17
- package/dist/core/formula.d.ts.map +1 -1
- package/dist/core/formula.js +95 -1
- package/dist/core/formula.js.map +1 -1
- package/dist/core/grounding.d.ts +44 -8
- package/dist/core/grounding.d.ts.map +1 -1
- package/dist/core/grounding.js +208 -26
- package/dist/core/grounding.js.map +1 -1
- package/dist/core/nl-parser.d.ts +2 -2
- package/dist/core/nl-parser.d.ts.map +1 -1
- package/dist/core/nl-parser.js +617 -41
- package/dist/core/nl-parser.js.map +1 -1
- package/dist/core/pack-loader.d.ts.map +1 -1
- package/dist/core/pack-loader.js +14 -2
- package/dist/core/pack-loader.js.map +1 -1
- package/dist/core/parser.d.ts.map +1 -1
- package/dist/core/parser.js +30 -1
- package/dist/core/parser.js.map +1 -1
- package/dist/core/pattern-factory.d.ts.map +1 -1
- package/dist/core/pattern-factory.js +14 -1
- package/dist/core/pattern-factory.js.map +1 -1
- package/dist/core/patterns.d.ts +118 -1
- package/dist/core/patterns.d.ts.map +1 -1
- package/dist/core/patterns.js +189 -10
- package/dist/core/patterns.js.map +1 -1
- package/dist/core/session-log.d.ts.map +1 -1
- package/dist/core/session-log.js +20 -1
- package/dist/core/session-log.js.map +1 -1
- package/dist/core/sto.d.ts +21 -27
- package/dist/core/sto.d.ts.map +1 -1
- package/dist/core/sto.js +30 -33
- package/dist/core/sto.js.map +1 -1
- package/dist/core/tool-names.d.ts +59 -0
- package/dist/core/tool-names.d.ts.map +1 -0
- package/dist/core/tool-names.js +128 -0
- package/dist/core/tool-names.js.map +1 -0
- package/dist/index.d.ts +181 -32
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +415 -67
- package/dist/index.js.map +1 -1
- package/dist/integrations/claude-agent.d.ts +5 -0
- package/dist/integrations/claude-agent.d.ts.map +1 -1
- package/dist/integrations/claude-agent.js +42 -13
- package/dist/integrations/claude-agent.js.map +1 -1
- package/dist/integrations/google-adk.d.ts +5 -3
- package/dist/integrations/google-adk.d.ts.map +1 -1
- package/dist/integrations/google-adk.js +9 -5
- package/dist/integrations/google-adk.js.map +1 -1
- package/dist/integrations/langchain.d.ts +7 -0
- package/dist/integrations/langchain.d.ts.map +1 -1
- package/dist/integrations/langchain.js +21 -3
- package/dist/integrations/langchain.js.map +1 -1
- package/dist/integrations/openai-agents.d.ts +22 -10
- package/dist/integrations/openai-agents.d.ts.map +1 -1
- package/dist/integrations/openai-agents.js +55 -15
- package/dist/integrations/openai-agents.js.map +1 -1
- package/dist/integrations/openai.d.ts +11 -0
- package/dist/integrations/openai.d.ts.map +1 -1
- package/dist/integrations/openai.js +130 -48
- package/dist/integrations/openai.js.map +1 -1
- package/dist/integrations/vercel-ai.d.ts +20 -9
- package/dist/integrations/vercel-ai.d.ts.map +1 -1
- package/dist/integrations/vercel-ai.js +131 -32
- package/dist/integrations/vercel-ai.js.map +1 -1
- package/package.json +17 -9
- package/prompts/onboard.md +26 -17
- package/prompts/scan.md +3 -5
- package/skills/SKILL.md +13 -83
- package/contracts/core/llm_safety.yaml +0 -140
- package/prompts/refresh.md +0 -118
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# sponsio/contracts/capability/destructive.yaml
|
|
3
|
+
#
|
|
4
|
+
# Capability pack — destructive / irreversible operations that the
|
|
5
|
+
# other capability packs don't already cover. Two LTL shapes, both
|
|
6
|
+
# using existing grounding atoms (``called_with``, ``count``,
|
|
7
|
+
# ``count_with``).
|
|
8
|
+
#
|
|
9
|
+
# § A — unconditional deny. ``G: arg_blacklist(...)`` compiles to
|
|
10
|
+
# ``G(called_with(tool, param, regex) -> false)``. No
|
|
11
|
+
# override path; the only way to allow is an operator
|
|
12
|
+
# ``overrides:`` with ``disabled: true``.
|
|
13
|
+
#
|
|
14
|
+
# § B — gated by per-call confirm marker. Raw LTL of the form
|
|
15
|
+
# ``G(called_with(<tool>, <regex>) ->
|
|
16
|
+
# count(confirm_destructive_action) >=
|
|
17
|
+
# count_with(<tool>, <regex>))``.
|
|
18
|
+
# Every destructive call must be matched by a fresh
|
|
19
|
+
# ``confirm_destructive_action`` marker — agent cannot
|
|
20
|
+
# reuse one confirm to cover multiple destructives.
|
|
21
|
+
# Violation = host adapter's choice of how to surface
|
|
22
|
+
# (deny / ask). Mode A hosts (Claude Code,
|
|
23
|
+
# OpenClaw) translate to ``permissionDecision: ask`` /
|
|
24
|
+
# ``requireApproval`` independently of the contract layer.
|
|
25
|
+
#
|
|
26
|
+
# Scope (deliberately narrow):
|
|
27
|
+
#
|
|
28
|
+
# This pack only covers categories the other capability packs
|
|
29
|
+
# miss. Specifically, it does NOT re-cover:
|
|
30
|
+
#
|
|
31
|
+
# - DROP / TRUNCATE / DELETE / dropdb / FLUSHALL / alembic
|
|
32
|
+
# downgrade base / data-dir deletes ── ``database.yaml``
|
|
33
|
+
# already bans these unconditionally; a confirm-marker
|
|
34
|
+
# version would be strictly weaker.
|
|
35
|
+
# - rm -rf of system roots, dd, mkfs, fork bomb ── ``shell.yaml``
|
|
36
|
+
# already bans these unconditionally.
|
|
37
|
+
# - SSH key / dotenv / credentials reads or overwrites ──
|
|
38
|
+
# ``credentials.yaml`` / ``filesystem.yaml``.
|
|
39
|
+
#
|
|
40
|
+
# What this pack adds is the *infra control plane*, *git history*,
|
|
41
|
+
# *mass-file*, and *MCP-tool* layers — categories where the blast
|
|
42
|
+
# radius is "wipe production" but the surface (cloud CLI / HTTP
|
|
43
|
+
# API / MCP tool / git mutation) isn't a shell builtin or SQL
|
|
44
|
+
# statement and so isn't caught by the existing packs.
|
|
45
|
+
#
|
|
46
|
+
# Real-world incidents this pack defends against:
|
|
47
|
+
#
|
|
48
|
+
# - PocketOS / Cursor / Claude Opus 4.6 (2026-04-27): agent in
|
|
49
|
+
# staging deleted production Railway volume + all backups in
|
|
50
|
+
# 9 seconds. § B gating on the Railway CLI form
|
|
51
|
+
# (``railway volume delete``) AND the HTTP API form
|
|
52
|
+
# (``curl -X DELETE backboard.railway.app/...``) would have
|
|
53
|
+
# demanded a per-call confirm marker first. The third form —
|
|
54
|
+
# in-process SDK call from a Python/Node script — sits outside
|
|
55
|
+
# the shell-tool boundary; catching that requires Mode B
|
|
56
|
+
# (`sponsio.Sponsio()` wrapping the agent loop where the SDK
|
|
57
|
+
# `delete_volume` tool call is visible directly).
|
|
58
|
+
# - claude-code issue #30475 (closed-as-duplicate, recurring):
|
|
59
|
+
# "Agent commits and pushes changes without waiting for user
|
|
60
|
+
# approval." § B on force-push to protected branches.
|
|
61
|
+
#
|
|
62
|
+
# Marker convention:
|
|
63
|
+
# ``confirm_destructive_action`` is the integration's signal that
|
|
64
|
+
# the user has explicitly approved a destructive operation
|
|
65
|
+
# through the host UI. Sub-agents are not expected to emit it
|
|
66
|
+
# directly — their work product flows back to the main agent,
|
|
67
|
+
# which surfaces an ``ask``-style confirmation prompt and emits
|
|
68
|
+
# the marker on user approval. Without the marker, every § B
|
|
69
|
+
# call fails the per-call count comparison.
|
|
70
|
+
#
|
|
71
|
+
# This marker is independent of ``shell.yaml``'s
|
|
72
|
+
# ``confirm_reconfirmed`` marker — each pack defines its own so
|
|
73
|
+
# a single user click can't unintentionally satisfy multiple
|
|
74
|
+
# distinct gates.
|
|
75
|
+
#
|
|
76
|
+
# Include via:
|
|
77
|
+
# include:
|
|
78
|
+
# - sponsio:capability/destructive
|
|
79
|
+
#
|
|
80
|
+
# Tool naming:
|
|
81
|
+
# The pack uses canonical ``exec`` for the shell tool. Both
|
|
82
|
+
# ``_host.yaml`` and ``_host_subagent.yaml`` rename ``exec: Bash``;
|
|
83
|
+
# ``_host_openclaw.yaml`` uses canonical ``exec`` directly. For
|
|
84
|
+
# plugin tools (``mcp__<server>__<tool>``) the rule references
|
|
85
|
+
# the namespaced name verbatim.
|
|
86
|
+
#
|
|
87
|
+
# Source tag convention:
|
|
88
|
+
# library:tier1.destructive.{always,confirm}
|
|
89
|
+
# =============================================================================
|
|
90
|
+
|
|
91
|
+
version: "1"
|
|
92
|
+
|
|
93
|
+
tools:
|
|
94
|
+
- name: exec
|
|
95
|
+
description: "Shell command execution"
|
|
96
|
+
params: "command: str"
|
|
97
|
+
- name: confirm_destructive_action
|
|
98
|
+
description: "Marker tool the integration emits when the user explicitly approves a destructive operation."
|
|
99
|
+
params: "operation: str"
|
|
100
|
+
|
|
101
|
+
agents:
|
|
102
|
+
"*":
|
|
103
|
+
contracts:
|
|
104
|
+
|
|
105
|
+
# ===================================================================
|
|
106
|
+
# § A — unconditional deny (G(¬destructive))
|
|
107
|
+
# ===================================================================
|
|
108
|
+
|
|
109
|
+
- desc: "Ban git history rewrites that obliterate state silently (filter-branch / filter-repo)"
|
|
110
|
+
G:
|
|
111
|
+
pattern: arg_blacklist
|
|
112
|
+
args:
|
|
113
|
+
- exec
|
|
114
|
+
- command
|
|
115
|
+
- - "\\bgit\\b[^|;&]*?\\bfilter-(branch|repo)\\b"
|
|
116
|
+
source: "library:tier1.destructive.always"
|
|
117
|
+
|
|
118
|
+
# ===================================================================
|
|
119
|
+
# § B — per-call confirm marker required
|
|
120
|
+
# ===================================================================
|
|
121
|
+
#
|
|
122
|
+
# LTL idiom: G(called_with(t, r) ->
|
|
123
|
+
# count(confirm_destructive_action)
|
|
124
|
+
# >= count_with(t, r))
|
|
125
|
+
#
|
|
126
|
+
# Every match of the destructive regex must be matched by a
|
|
127
|
+
# fresh confirm marker — confirms are not reusable across
|
|
128
|
+
# different destructive ops within the same session.
|
|
129
|
+
|
|
130
|
+
- desc: "git force-push to protected branches needs per-call confirm_destructive_action (PocketOS-class blast radius)"
|
|
131
|
+
G:
|
|
132
|
+
ltl: >-
|
|
133
|
+
G(called_with(exec, "\\bgit\\b[^|;&]*?\\bpush\\b[^|;&]*?(--force|--force-with-lease|\\s-f\\b)[^|;&]*?\\b(main|master|release|prod|production)\\b")
|
|
134
|
+
-> count(confirm_destructive_action)
|
|
135
|
+
>= count_with(exec, "\\bgit\\b[^|;&]*?\\bpush\\b[^|;&]*?(--force|--force-with-lease|\\s-f\\b)[^|;&]*?\\b(main|master|release|prod|production)\\b"))
|
|
136
|
+
source: "library:tier1.destructive.confirm"
|
|
137
|
+
|
|
138
|
+
- desc: "git reset --hard / clean -fdx needs per-call confirm_destructive_action (drops local work)"
|
|
139
|
+
G:
|
|
140
|
+
ltl: >-
|
|
141
|
+
G(called_with(exec, "\\bgit\\b[^|;&]*?\\b(reset\\b[^|;&]*?\\b--hard|clean\\b[^|;&]*?\\b-[fdx]+)\\b")
|
|
142
|
+
-> count(confirm_destructive_action)
|
|
143
|
+
>= count_with(exec, "\\bgit\\b[^|;&]*?\\b(reset\\b[^|;&]*?\\b--hard|clean\\b[^|;&]*?\\b-[fdx]+)\\b"))
|
|
144
|
+
source: "library:tier1.destructive.confirm"
|
|
145
|
+
|
|
146
|
+
- desc: "Cloud volume / cluster delete needs per-call confirm_destructive_action (PocketOS Railway pattern)"
|
|
147
|
+
G:
|
|
148
|
+
ltl: >-
|
|
149
|
+
G(called_with(exec, "\\b(railway\\s+(volume|service|environment|project)\\s+delete|aws\\s+ec2\\s+delete-volume|aws\\s+rds\\s+delete-(db-instance|db-cluster|db-snapshot)|aws\\s+s3\\s+rb|gcloud\\s+(sql|compute|container)\\s+\\S+\\s+delete|kubectl\\s+delete\\s+(pv|pvc|namespace|cluster)|fly\\s+(volumes|apps)\\s+destroy|heroku\\s+apps:destroy|terraform\\s+destroy|pulumi\\s+destroy|docker\\s+volume\\s+rm)\\b")
|
|
150
|
+
-> count(confirm_destructive_action)
|
|
151
|
+
>= count_with(exec, "\\b(railway\\s+(volume|service|environment|project)\\s+delete|aws\\s+ec2\\s+delete-volume|aws\\s+rds\\s+delete-(db-instance|db-cluster|db-snapshot)|aws\\s+s3\\s+rb|gcloud\\s+(sql|compute|container)\\s+\\S+\\s+delete|kubectl\\s+delete\\s+(pv|pvc|namespace|cluster)|fly\\s+(volumes|apps)\\s+destroy|heroku\\s+apps:destroy|terraform\\s+destroy|pulumi\\s+destroy|docker\\s+volume\\s+rm)\\b"))
|
|
152
|
+
source: "library:tier1.destructive.confirm"
|
|
153
|
+
|
|
154
|
+
- desc: "GitHub MCP delete_repository needs per-call confirm_destructive_action"
|
|
155
|
+
G:
|
|
156
|
+
ltl: >-
|
|
157
|
+
G(called(mcp__github__delete_repository)
|
|
158
|
+
-> count(confirm_destructive_action) >= count(mcp__github__delete_repository))
|
|
159
|
+
source: "library:tier1.destructive.confirm"
|
|
160
|
+
|
|
161
|
+
- desc: "Railway MCP delete_volume needs per-call confirm_destructive_action (PocketOS pattern)"
|
|
162
|
+
G:
|
|
163
|
+
ltl: >-
|
|
164
|
+
G(called(mcp__railway__delete_volume)
|
|
165
|
+
-> count(confirm_destructive_action) >= count(mcp__railway__delete_volume))
|
|
166
|
+
source: "library:tier1.destructive.confirm"
|
|
167
|
+
|
|
168
|
+
- desc: "AWS MCP delete_volume needs per-call confirm_destructive_action"
|
|
169
|
+
G:
|
|
170
|
+
ltl: >-
|
|
171
|
+
G(called(mcp__aws__delete_volume)
|
|
172
|
+
-> count(confirm_destructive_action) >= count(mcp__aws__delete_volume))
|
|
173
|
+
source: "library:tier1.destructive.confirm"
|
|
174
|
+
|
|
175
|
+
- desc: "Supabase MCP delete_database needs per-call confirm_destructive_action"
|
|
176
|
+
G:
|
|
177
|
+
ltl: >-
|
|
178
|
+
G(called(mcp__supabase__delete_database)
|
|
179
|
+
-> count(confirm_destructive_action) >= count(mcp__supabase__delete_database))
|
|
180
|
+
source: "library:tier1.destructive.confirm"
|
|
181
|
+
|
|
182
|
+
- desc: "GitHub repo deletion via gh CLI needs per-call confirm_destructive_action"
|
|
183
|
+
G:
|
|
184
|
+
ltl: >-
|
|
185
|
+
G(called_with(exec, "\\b(gh\\s+repo\\s+delete|hub\\s+delete)\\b")
|
|
186
|
+
-> count(confirm_destructive_action)
|
|
187
|
+
>= count_with(exec, "\\b(gh\\s+repo\\s+delete|hub\\s+delete)\\b"))
|
|
188
|
+
source: "library:tier1.destructive.confirm"
|
|
189
|
+
|
|
190
|
+
- desc: "Mass file delete (find -delete / xargs rm) needs per-call confirm_destructive_action"
|
|
191
|
+
G:
|
|
192
|
+
ltl: >-
|
|
193
|
+
G(called_with(exec, "\\bfind\\s+\\S+[^|;&]*?(\\s-delete|\\|\\s*xargs\\s+rm)\\b")
|
|
194
|
+
-> count(confirm_destructive_action)
|
|
195
|
+
>= count_with(exec, "\\bfind\\s+\\S+[^|;&]*?(\\s-delete|\\|\\s*xargs\\s+rm)\\b"))
|
|
196
|
+
source: "library:tier1.destructive.confirm"
|
|
197
|
+
|
|
198
|
+
# PocketOS / Cursor (2026-04-27) almost certainly went through
|
|
199
|
+
# the Railway HTTP API, not the CLI — "single API call to
|
|
200
|
+
# Railway" is the operative wording. curl / wget / httpie / xh
|
|
201
|
+
# carrying DELETE to known infra endpoints (Railway, AWS,
|
|
202
|
+
# GCP, Heroku, Fly, Vercel, DO, Linode, Cloudflare, Supabase)
|
|
203
|
+
# gates on the same confirm marker. Generic curl with DELETE
|
|
204
|
+
# to arbitrary URLs is intentionally NOT gated here — too many
|
|
205
|
+
# legitimate REST API uses; users get the gate exactly where
|
|
206
|
+
# the blast radius is "wipe production infra".
|
|
207
|
+
- desc: "HTTP DELETE to cloud infra control planes needs per-call confirm_destructive_action (PocketOS API path)"
|
|
208
|
+
G:
|
|
209
|
+
ltl: >-
|
|
210
|
+
G(called_with(exec, "\\b(curl|wget|http|https|httpie|xh)\\b[^|;&]*?(-X\\s+DELETE|--request\\s+DELETE|\\sDELETE\\b)[^|;&]*?(railway\\.app|amazonaws\\.com|googleapis\\.com|heroku\\.com|fly\\.io|vercel\\.com|digitalocean\\.com|linode\\.com|cloudflare\\.com|supabase\\.co|planetscale\\.com|neon\\.tech|render\\.com|fly\\.dev|backboard\\.railway\\.app)")
|
|
211
|
+
-> count(confirm_destructive_action)
|
|
212
|
+
>= count_with(exec, "\\b(curl|wget|http|https|httpie|xh)\\b[^|;&]*?(-X\\s+DELETE|--request\\s+DELETE|\\sDELETE\\b)[^|;&]*?(railway\\.app|amazonaws\\.com|googleapis\\.com|heroku\\.com|fly\\.io|vercel\\.com|digitalocean\\.com|linode\\.com|cloudflare\\.com|supabase\\.co|planetscale\\.com|neon\\.tech|render\\.com|fly\\.dev|backboard\\.railway\\.app)"))
|
|
213
|
+
source: "library:tier1.destructive.confirm"
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# sponsio/contracts/capability/factual-claims.yaml
|
|
3
|
+
#
|
|
4
|
+
# Capability pack — evidence obligations for factual claims.
|
|
5
|
+
#
|
|
6
|
+
# REQUIRES A SPONSIO CLOUD KEY. Verdicts are produced by the cloud
|
|
7
|
+
# evidence API (POST /v1/evidence/verify); the runtime computes none of
|
|
8
|
+
# them. The integration calls ``client.evidence.verify(...)`` and feeds
|
|
9
|
+
# ``EvidenceResult.to_event(...)`` into the trace; that grounds three
|
|
10
|
+
# atom families this pack composes:
|
|
11
|
+
#
|
|
12
|
+
# claim_emitted(pred) a claim of this predicate was emitted
|
|
13
|
+
# evidence_verdict(pred, V) the server's verdict for it (PASS /
|
|
14
|
+
# MISMATCH / UNDERDETERMINED /
|
|
15
|
+
# NO_EVIDENCE / STALE /
|
|
16
|
+
# SOURCE_UNAVAILABLE /
|
|
17
|
+
# EXTRACTION_AMBIGUOUS)
|
|
18
|
+
# evidence_action(pred, a) the server's policy action
|
|
19
|
+
# (release / block / clarify /
|
|
20
|
+
# re_resolve)
|
|
21
|
+
#
|
|
22
|
+
# Two shapes:
|
|
23
|
+
#
|
|
24
|
+
# § A — claim_requires_evidence(pred):
|
|
25
|
+
# G(claim_emitted(pred) -> evidence_verdict(pred, PASS)).
|
|
26
|
+
# Any claim whose verdict is not PASS violates at the timestep
|
|
27
|
+
# the verdict lands.
|
|
28
|
+
#
|
|
29
|
+
# § B — underdetermined_must_clarify(pred):
|
|
30
|
+
# G(evidence_verdict(pred, UNDERDETERMINED) ->
|
|
31
|
+
# evidence_action(pred, clarify)).
|
|
32
|
+
# Guards the policy wiring: ambiguous evidence must resolve to
|
|
33
|
+
# a clarify action, never a silent release.
|
|
34
|
+
#
|
|
35
|
+
# Without a cloud key no ``evidence`` events exist, both atom families
|
|
36
|
+
# stay un-grounded, and every rule below is vacuously satisfied — the
|
|
37
|
+
# pack does nothing rather than something wrong.
|
|
38
|
+
#
|
|
39
|
+
# The predicate names below are the two self-serve built-ins used across
|
|
40
|
+
# the docs; replace them with the predicates your project actually
|
|
41
|
+
# protects (GET /v1/evidence/predicates lists them).
|
|
42
|
+
#
|
|
43
|
+
# Include via:
|
|
44
|
+
# include:
|
|
45
|
+
# - sponsio:capability/factual-claims
|
|
46
|
+
# =============================================================================
|
|
47
|
+
|
|
48
|
+
agents:
|
|
49
|
+
"*":
|
|
50
|
+
contracts:
|
|
51
|
+
|
|
52
|
+
# ===================================================================
|
|
53
|
+
# § A — claims must verify (PASS or it doesn't ship)
|
|
54
|
+
# ===================================================================
|
|
55
|
+
|
|
56
|
+
- desc: "Weekday claims must match the calendar (cloud-verified)"
|
|
57
|
+
G:
|
|
58
|
+
pattern: claim_requires_evidence
|
|
59
|
+
args:
|
|
60
|
+
- date_weekday_agreement
|
|
61
|
+
source: "library:evidence.factual-claims"
|
|
62
|
+
|
|
63
|
+
- desc: "ZIP claims for a city must verify against reference data (cloud-verified)"
|
|
64
|
+
G:
|
|
65
|
+
pattern: claim_requires_evidence
|
|
66
|
+
args:
|
|
67
|
+
- city_zip_candidates
|
|
68
|
+
source: "library:evidence.factual-claims"
|
|
69
|
+
|
|
70
|
+
# ===================================================================
|
|
71
|
+
# § B — ambiguous evidence must clarify, never silently release
|
|
72
|
+
# ===================================================================
|
|
73
|
+
|
|
74
|
+
- desc: "Ambiguous city→ZIP evidence must trigger clarification"
|
|
75
|
+
G:
|
|
76
|
+
pattern: underdetermined_must_clarify
|
|
77
|
+
args:
|
|
78
|
+
- city_zip_candidates
|
|
79
|
+
source: "library:evidence.factual-claims"
|
|
@@ -42,6 +42,10 @@
|
|
|
42
42
|
# — bash redirect / mutator forms that the self-modify pack
|
|
43
43
|
# doesn't currently match because its regex anchors on
|
|
44
44
|
# ``.sponsio/plugins/...`` paths only.
|
|
45
|
+
# 6. ``truncate -s0 ~/.claude/settings.json`` / ``ln -sf /dev/null
|
|
46
|
+
# ~/.claude/settings.json`` / ``chmod 000 ~/.claude/settings.json``
|
|
47
|
+
# / ``rm -rf ~/.claude`` — no write at all, but the IDE reads an
|
|
48
|
+
# empty, foreign, or unreadable file and loads no hooks.
|
|
45
49
|
#
|
|
46
50
|
# What this pack denies:
|
|
47
51
|
#
|
|
@@ -222,26 +226,55 @@ agents:
|
|
|
222
226
|
# interpreter: ``echo '{}' > hooks.json``, ``cat /dev/null >
|
|
223
227
|
# settings.json``, ``: > hooks.json``, ``sed -i 's/true/false/'
|
|
224
228
|
# hooks.json``, ``tee hooks.json``, ``cp empty.json
|
|
225
|
-
# hooks.json``, ``mv x hooks.json``, ``rm hooks.json
|
|
229
|
+
# hooks.json``, ``mv x hooks.json``, ``rm hooks.json``,
|
|
230
|
+
# ``truncate -s0``, ``ln -sf /dev/null``, ``chmod 000``.
|
|
226
231
|
#
|
|
227
|
-
# The pattern is "
|
|
228
|
-
#
|
|
229
|
-
#
|
|
230
|
-
# ``
|
|
231
|
-
#
|
|
232
|
-
#
|
|
232
|
+
# The pattern is "a mutator verb, then anything up to the next
|
|
233
|
+
# pipe / separator, then a hook-config path on the same command
|
|
234
|
+
# line". The gap between verb and path is what ``~/``, ``$HOME/``,
|
|
235
|
+
# ``"${HOME}/``, and an absolute prefix sit in: an earlier version
|
|
236
|
+
# required the path to follow the redirect operator immediately,
|
|
237
|
+
# so ``> .claude/settings.json`` was denied and ``> ~/.claude/
|
|
238
|
+
# settings.json`` was not (reported by kta1kri, 2026-10).
|
|
239
|
+
# ``truncate``, ``ln``, ``chmod``, ``chown`` and ``chattr`` are
|
|
240
|
+
# mutators too: an emptied, replaced, or unreadable settings file
|
|
241
|
+
# removes the hook exactly as an edited one does.
|
|
242
|
+
#
|
|
243
|
+
# Read-only patterns (``cat hooks.json``, ``jq . hooks.json``,
|
|
244
|
+
# ``grep ... hooks.json``, ``jq . settings.json > /tmp/backup``)
|
|
245
|
+
# are NOT matched — they carry no mutator verb in front of the
|
|
246
|
+
# path, and a redirect to a different file stops at that file.
|
|
247
|
+
# ``cp`` with the file as the *source* does match; a backup is
|
|
248
|
+
# the price of catching ``cp empty.json settings.json``.
|
|
233
249
|
#
|
|
234
250
|
# Edge case: ``python ... > hooks.json`` is already caught
|
|
235
251
|
# by §5 via the interpreter alternation. No double-deny harm
|
|
236
252
|
# since this is the deny side of the contract anyway.
|
|
237
253
|
|
|
238
|
-
- desc: "Host agent must not redirect / sed / tee / mv / rm an IDE hook / MCP wiring file"
|
|
254
|
+
- desc: "Host agent must not redirect / sed / tee / mv / rm / truncate / ln / chmod an IDE hook / MCP wiring file"
|
|
255
|
+
G:
|
|
256
|
+
pattern: arg_blacklist
|
|
257
|
+
args:
|
|
258
|
+
- Bash
|
|
259
|
+
- command
|
|
260
|
+
- - ">{1,2}\\|?\\s*[^|&;<>\\n]*(\\.cursor/(hooks|mcp)\\.json|\\.claude/(settings(\\.local)?\\.json|hooks/[^\\s|]+)|\\.codex/hooks\\.json|\\.windsurf/hooks\\.json)"
|
|
261
|
+
- "\\b(tee|cp|mv|rm|install|truncate|ln|chmod|chown|chattr|shred|unlink|rsync|dd|sponge|patch|ed|ex|vi|vim|nvim)\\b[^|&;\\n]*(\\.cursor/(hooks|mcp)\\.json|\\.claude/(settings(\\.local)?\\.json|hooks/[^\\s|]+)|\\.codex/hooks\\.json|\\.windsurf/hooks\\.json)"
|
|
262
|
+
- "\\bsed\\b[^|&;\\n]*\\s-[a-zA-Z]*i[^|&;\\n]*(\\.cursor/(hooks|mcp)\\.json|\\.claude/(settings(\\.local)?\\.json|hooks/[^\\s|]+)|\\.codex/hooks\\.json|\\.windsurf/hooks\\.json)"
|
|
263
|
+
- "\\bawk\\b[^|&;\\n]*\\s-i[^|&;\\n]*(\\.cursor/(hooks|mcp)\\.json|\\.claude/(settings(\\.local)?\\.json|hooks/[^\\s|]+)|\\.codex/hooks\\.json|\\.windsurf/hooks\\.json)"
|
|
264
|
+
source: "library:tier1.host-config-integrity"
|
|
265
|
+
|
|
266
|
+
# The rules above name the wiring FILE. Removing, moving, or making
|
|
267
|
+
# unreadable the directory that holds it (``rm -rf ~/.claude``,
|
|
268
|
+
# ``chmod 000 ~/.claude``, ``mv .cursor /tmp``) takes the hook
|
|
269
|
+
# registration with it. The lookahead stops at the directory name
|
|
270
|
+
# so ``~/.claude-backup`` and ``.claude/commands/x.md`` stay open.
|
|
271
|
+
- desc: "Host agent must not remove, move, or lock the IDE config directory that holds the hook wiring"
|
|
239
272
|
G:
|
|
240
273
|
pattern: arg_blacklist
|
|
241
274
|
args:
|
|
242
275
|
- Bash
|
|
243
276
|
- command
|
|
244
|
-
- - "
|
|
277
|
+
- - "\\b(rm|rmdir|mv|chmod|chown|chattr|ln)\\b[^|&;\\n]*(\\.claude|\\.cursor|\\.codex|\\.windsurf)/?(?![\\w./-])"
|
|
245
278
|
source: "library:tier1.host-config-integrity"
|
|
246
279
|
|
|
247
280
|
# -----------------------------------------------------------------------------
|
|
@@ -40,8 +40,8 @@
|
|
|
40
40
|
# ``sponsio/contracts/**/*.yaml`` and the evaluation-engine
|
|
41
41
|
# Python files (``guard_stdin``, ``config``, ``core``, plus
|
|
42
42
|
# anything under ``runtime/``, ``patterns/``, ``formulas/``,
|
|
43
|
-
# ``tracer/``, ``integrations/``). Without
|
|
44
|
-
#
|
|
43
|
+
# ``tracer/``, ``integrations/``, ``daemon/``, ``shim/``). Without
|
|
44
|
+
# this, an agent can ``import sponsio; print(sponsio.__file__)`` to locate
|
|
45
45
|
# the package, then edit a capability bundle (or monkey-patch
|
|
46
46
|
# the loader) to delete the rule about to fire — bypassing the
|
|
47
47
|
# per-bucket protection above.
|
|
@@ -155,7 +155,7 @@ agents:
|
|
|
155
155
|
# site-packages, --user installs, conda/venv all the same.
|
|
156
156
|
- "(^|/)sponsio/contracts/[^/]+/[^/]+\\.yaml$"
|
|
157
157
|
- "(^|/)sponsio/(guard_stdin|config|core)\\.py$"
|
|
158
|
-
- "(^|/)sponsio/(runtime|patterns|formulas|tracer|integrations)/[^/]+\\.py$"
|
|
158
|
+
- "(^|/)sponsio/(runtime|patterns|formulas|tracer|integrations|daemon|shim)/[^/]+\\.py$"
|
|
159
159
|
source: "library:tier1.self-modify"
|
|
160
160
|
|
|
161
161
|
# =================================================================
|
|
@@ -177,7 +177,7 @@ agents:
|
|
|
177
177
|
- "(^|/)\\.sponsio/plugins/[^_/][^/]*/sponsio\\.yaml$"
|
|
178
178
|
- "(^|/)sponsio/contracts/[^/]+/[^/]+\\.yaml$"
|
|
179
179
|
- "(^|/)sponsio/(guard_stdin|config|core)\\.py$"
|
|
180
|
-
- "(^|/)sponsio/(runtime|patterns|formulas|tracer|integrations)/[^/]+\\.py$"
|
|
180
|
+
- "(^|/)sponsio/(runtime|patterns|formulas|tracer|integrations|daemon|shim)/[^/]+\\.py$"
|
|
181
181
|
source: "library:tier1.self-modify"
|
|
182
182
|
|
|
183
183
|
# =================================================================
|
|
@@ -194,7 +194,7 @@ agents:
|
|
|
194
194
|
- "(^|/)\\.sponsio/plugins/[^_/][^/]*/sponsio\\.yaml$"
|
|
195
195
|
- "(^|/)sponsio/contracts/[^/]+/[^/]+\\.yaml$"
|
|
196
196
|
- "(^|/)sponsio/(guard_stdin|config|core)\\.py$"
|
|
197
|
-
- "(^|/)sponsio/(runtime|patterns|formulas|tracer|integrations)/[^/]+\\.py$"
|
|
197
|
+
- "(^|/)sponsio/(runtime|patterns|formulas|tracer|integrations|daemon|shim)/[^/]+\\.py$"
|
|
198
198
|
source: "library:tier1.self-modify"
|
|
199
199
|
|
|
200
200
|
# =================================================================
|
|
@@ -235,7 +235,7 @@ agents:
|
|
|
235
235
|
args:
|
|
236
236
|
- Write
|
|
237
237
|
- content
|
|
238
|
-
- - "(?s)(?=.*(\\.sponsio/plugins/(_host[^/]*|[^_/][^/]*)/sponsio\\.yaml|sponsio/contracts/[^/]+/[^/]+\\.yaml|sponsio/(guard_stdin|config|core)\\.py|sponsio/(runtime|patterns|formulas|tracer|integrations)/[^/]+\\.py)).*(\\.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)"
|
|
238
|
+
- - "(?s)(?=.*(\\.sponsio/plugins/(_host[^/]*|[^_/][^/]*)/sponsio\\.yaml|sponsio/contracts/[^/]+/[^/]+\\.yaml|sponsio/(guard_stdin|config|core)\\.py|sponsio/(runtime|patterns|formulas|tracer|integrations|daemon|shim)/[^/]+\\.py)).*(\\.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)"
|
|
239
239
|
source: "library:tier1.self-modify"
|
|
240
240
|
|
|
241
241
|
- desc: "Host agent must not edit a script that mutates a sponsio guard config or engine file — use `sponsio plugin append`/`install`"
|
|
@@ -244,7 +244,7 @@ agents:
|
|
|
244
244
|
args:
|
|
245
245
|
- Edit
|
|
246
246
|
- new_string
|
|
247
|
-
- - "(?s)(?=.*(\\.sponsio/plugins/(_host[^/]*|[^_/][^/]*)/sponsio\\.yaml|sponsio/contracts/[^/]+/[^/]+\\.yaml|sponsio/(guard_stdin|config|core)\\.py|sponsio/(runtime|patterns|formulas|tracer|integrations)/[^/]+\\.py)).*(\\.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)"
|
|
247
|
+
- - "(?s)(?=.*(\\.sponsio/plugins/(_host[^/]*|[^_/][^/]*)/sponsio\\.yaml|sponsio/contracts/[^/]+/[^/]+\\.yaml|sponsio/(guard_stdin|config|core)\\.py|sponsio/(runtime|patterns|formulas|tracer|integrations|daemon|shim)/[^/]+\\.py)).*(\\.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)"
|
|
248
248
|
source: "library:tier1.self-modify"
|
|
249
249
|
|
|
250
250
|
# =================================================================
|
|
@@ -280,7 +280,7 @@ agents:
|
|
|
280
280
|
# across pipelines, but keeps ``;`` permitted because
|
|
281
281
|
# Python's ``-c "..."`` payloads commonly use it as a
|
|
282
282
|
# statement separator (``python -c "import x; x.do()"``).
|
|
283
|
-
- - "\\b(python|python2|python3|node|deno|bun|ruby|perl|php|lua|tclsh|R|Rscript)\\b[^|\\n]*(\\.sponsio/plugins/(_host[^/]*|[^_/][^/]*)/sponsio\\.yaml|sponsio/contracts/[^/]+/[^/]+\\.yaml|sponsio/(guard_stdin|config|core)\\.py|sponsio/(runtime|patterns|formulas|tracer|integrations)/[^/]+\\.py)"
|
|
283
|
+
- - "\\b(python|python2|python3|node|deno|bun|ruby|perl|php|lua|tclsh|R|Rscript)\\b[^|\\n]*(\\.sponsio/plugins/(_host[^/]*|[^_/][^/]*)/sponsio\\.yaml|sponsio/contracts/[^/]+/[^/]+\\.yaml|sponsio/(guard_stdin|config|core)\\.py|sponsio/(runtime|patterns|formulas|tracer|integrations|daemon|shim)/[^/]+\\.py)"
|
|
284
284
|
source: "library:tier1.self-modify"
|
|
285
285
|
|
|
286
286
|
# =================================================================
|
|
@@ -306,7 +306,7 @@ agents:
|
|
|
306
306
|
args:
|
|
307
307
|
- Bash
|
|
308
308
|
- command
|
|
309
|
-
- - "
|
|
309
|
+
- - ">{1,2}\\|?\\s*[^|&;<>\\n]*(\\.sponsio/plugins/(_host[^/]*|[^_/][^/]*)/sponsio\\.yaml|sponsio/contracts/[^/]+/[^/]+\\.yaml|sponsio/(guard_stdin|config|core)\\.py|sponsio/(runtime|patterns|formulas|tracer|integrations|daemon|shim)/[^/]+\\.py)"
|
|
310
310
|
source: "library:tier1.self-modify"
|
|
311
311
|
|
|
312
312
|
- desc: "Host agent must not `tee` into a sponsio guard config or engine file"
|
|
@@ -315,7 +315,7 @@ agents:
|
|
|
315
315
|
args:
|
|
316
316
|
- Bash
|
|
317
317
|
- command
|
|
318
|
-
- - "\\btee\\b\\s+[^|&;]*(\\.sponsio/plugins/(_host[^/]*|[^_/][^/]*)/sponsio\\.yaml|sponsio/contracts/[^/]+/[^/]+\\.yaml|sponsio/(guard_stdin|config|core)\\.py|sponsio/(runtime|patterns|formulas|tracer|integrations)/[^/]+\\.py)"
|
|
318
|
+
- - "\\btee\\b\\s+[^|&;]*(\\.sponsio/plugins/(_host[^/]*|[^_/][^/]*)/sponsio\\.yaml|sponsio/contracts/[^/]+/[^/]+\\.yaml|sponsio/(guard_stdin|config|core)\\.py|sponsio/(runtime|patterns|formulas|tracer|integrations|daemon|shim)/[^/]+\\.py)"
|
|
319
319
|
source: "library:tier1.self-modify"
|
|
320
320
|
|
|
321
321
|
- desc: "Host agent must not `sed -i` a sponsio guard config or engine file"
|
|
@@ -324,7 +324,7 @@ agents:
|
|
|
324
324
|
args:
|
|
325
325
|
- Bash
|
|
326
326
|
- command
|
|
327
|
-
- - "\\bsed\\b\\s+-i\\b[^|&;]*(\\.sponsio/plugins/(_host[^/]*|[^_/][^/]*)/sponsio\\.yaml|sponsio/contracts/[^/]+/[^/]+\\.yaml|sponsio/(guard_stdin|config|core)\\.py|sponsio/(runtime|patterns|formulas|tracer|integrations)/[^/]+\\.py)"
|
|
327
|
+
- - "\\bsed\\b\\s+-i\\b[^|&;]*(\\.sponsio/plugins/(_host[^/]*|[^_/][^/]*)/sponsio\\.yaml|sponsio/contracts/[^/]+/[^/]+\\.yaml|sponsio/(guard_stdin|config|core)\\.py|sponsio/(runtime|patterns|formulas|tracer|integrations|daemon|shim)/[^/]+\\.py)"
|
|
328
328
|
source: "library:tier1.self-modify"
|
|
329
329
|
|
|
330
330
|
- desc: "Host agent must not `cp` / `mv` / `rm` / `dd` against a sponsio guard config or engine file"
|
|
@@ -333,7 +333,53 @@ agents:
|
|
|
333
333
|
args:
|
|
334
334
|
- Bash
|
|
335
335
|
- command
|
|
336
|
-
- - "\\b(cp|mv|rm|dd)\\b\\s+[^|&;]*(\\.sponsio/plugins/(_host[^/]*|[^_/][^/]*)/sponsio\\.yaml|sponsio/contracts/[^/]+/[^/]+\\.yaml|sponsio/(guard_stdin|config|core)\\.py|sponsio/(runtime|patterns|formulas|tracer|integrations)/[^/]+\\.py)"
|
|
336
|
+
- - "\\b(cp|mv|rm|dd)\\b\\s+[^|&;]*(\\.sponsio/plugins/(_host[^/]*|[^_/][^/]*)/sponsio\\.yaml|sponsio/contracts/[^/]+/[^/]+\\.yaml|sponsio/(guard_stdin|config|core)\\.py|sponsio/(runtime|patterns|formulas|tracer|integrations|daemon|shim)/[^/]+\\.py)"
|
|
337
|
+
source: "library:tier1.self-modify"
|
|
338
|
+
|
|
339
|
+
# A file can be emptied, replaced, or made unreadable without a
|
|
340
|
+
# write operator: ``truncate -s0``, ``ln -sf /dev/null``,
|
|
341
|
+
# ``chmod 000`` (reported by kta1kri, 2026-10, against the hook
|
|
342
|
+
# wiring; the rule file has the same exposure). The hook fails
|
|
343
|
+
# closed on an empty or unreadable library, so for the rule file
|
|
344
|
+
# these are denial of service rather than bypass, but they are
|
|
345
|
+
# the agent reaching for its own guard all the same.
|
|
346
|
+
- desc: "Host agent must not truncate / link over / lock a sponsio guard config or engine file"
|
|
347
|
+
G:
|
|
348
|
+
pattern: arg_blacklist
|
|
349
|
+
args:
|
|
350
|
+
- Bash
|
|
351
|
+
- command
|
|
352
|
+
- - "\\b(truncate|ln|chmod|chown|chattr|shred|unlink|install|rsync|sponge|patch|ed|ex|vi|vim|nvim)\\b\\s+[^|&;]*(\\.sponsio/plugins/(_host[^/]*|[^_/][^/]*)/sponsio\\.yaml|sponsio/contracts/[^/]+/[^/]+\\.yaml|sponsio/(guard_stdin|config|core)\\.py|sponsio/(runtime|patterns|formulas|tracer|integrations|daemon|shim)/[^/]+\\.py)"
|
|
353
|
+
source: "library:tier1.self-modify"
|
|
354
|
+
|
|
355
|
+
# The rules above name the rule FILE. Removing or moving a directory
|
|
356
|
+
# that contains it (``rm -rf ~/.sponsio``, ``mv ~/.sponsio/plugins
|
|
357
|
+
# /tmp``) took every library with it, after which each tool was
|
|
358
|
+
# "unconfigured" and ran, and ``defaults.unconfigured: deny`` went
|
|
359
|
+
# too, since it lives in the host library. The lookahead stops at
|
|
360
|
+
# the directory name so ``~/.sponsio-backup`` stays allowed.
|
|
361
|
+
- desc: "Host agent must not remove, move, or lock the sponsio config directory or a library bucket"
|
|
362
|
+
G:
|
|
363
|
+
pattern: arg_blacklist
|
|
364
|
+
args:
|
|
365
|
+
- Bash
|
|
366
|
+
- command
|
|
367
|
+
- - "\\b(rm|mv|rmdir|chmod|chown|chattr|ln)\\b[^|&;\\n]*\\.sponsio(/plugins(/[\\w-]+)?)?/?(?![\\w./-])"
|
|
368
|
+
source: "library:tier1.self-modify"
|
|
369
|
+
|
|
370
|
+
# The daemon holds a rule change that removes a contract until
|
|
371
|
+
# someone runs `sponsio rules reload`. At Tier 1 that someone could
|
|
372
|
+
# be the agent, approving its own weakening; the same goes for
|
|
373
|
+
# starting a daemon that applies every change (`--watch`), switching
|
|
374
|
+
# a host to observe, or removing the hooks. These belong to the
|
|
375
|
+
# person at their own terminal.
|
|
376
|
+
- desc: "Host agent must not approve its own rule changes, or switch Sponsio to observe or off"
|
|
377
|
+
G:
|
|
378
|
+
pattern: arg_blacklist
|
|
379
|
+
args:
|
|
380
|
+
- Bash
|
|
381
|
+
- command
|
|
382
|
+
- - "\\bsponsio\\b[^|&;\\n]*\\b(rules\\s+reload|admin\\b|daemon\\s+run\\b[^|&;\\n]*--watch|host\\s+uninstall|host\\s+install\\b[^|&;\\n]*--mode[\\s=]+observe)"
|
|
337
383
|
source: "library:tier1.self-modify"
|
|
338
384
|
|
|
339
385
|
# -----------------------------------------------------------------------------
|
|
@@ -65,10 +65,19 @@ agents:
|
|
|
65
65
|
# rm -rf /home/... (direct home path)
|
|
66
66
|
# rm -rf /root/...
|
|
67
67
|
# rm -rf /Users/... (macOS home)
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
68
|
+
#
|
|
69
|
+
# Flag grammar: ``rm`` followed by any options, at least one
|
|
70
|
+
# of which is a short cluster containing r/R/f (``-rf``,
|
|
71
|
+
# ``-fr``, ``-Rfv``, ``-r -f``) or the long spelling
|
|
72
|
+
# (``--recursive`` / ``--force``), then any further options
|
|
73
|
+
# (``--no-preserve-root``, ``--``), then the target.
|
|
74
|
+
# ``arg_blacklist`` is a raw regex with no argv parsing, so
|
|
75
|
+
# the long forms must be spelled out here or
|
|
76
|
+
# ``rm --recursive --force /`` walks straight through.
|
|
77
|
+
- - "\\brm(?:\\s+(?:-[a-zA-Z]+|--[a-z-]+))*\\s+(?:-[a-zA-Z]*[rRf][a-zA-Z]*|--recursive|--force)(?:\\s+(?:-[a-zA-Z]+|--[a-z-]+|--))*\\s+(/|\\$HOME|~)/?(\\s|;|&|\\||$)"
|
|
78
|
+
- "\\brm(?:\\s+(?:-[a-zA-Z]+|--[a-z-]+))*\\s+(?:-[a-zA-Z]*[rRf][a-zA-Z]*|--recursive|--force)(?:\\s+(?:-[a-zA-Z]+|--[a-z-]+|--))*\\s+/\\*"
|
|
79
|
+
- "\\brm(?:\\s+(?:-[a-zA-Z]+|--[a-z-]+))*\\s+(?:-[a-zA-Z]*[rRf][a-zA-Z]*|--recursive|--force)(?:\\s+(?:-[a-zA-Z]+|--[a-z-]+|--))*\\s+/(home|root|Users)"
|
|
80
|
+
- "\\brm(?:\\s+(?:-[a-zA-Z]+|--[a-z-]+))*\\s+(?:-[a-zA-Z]*[rRf][a-zA-Z]*|--recursive|--force)(?:\\s+(?:-[a-zA-Z]+|--[a-z-]+|--))*\\s+\\$\\{?HOME\\}?"
|
|
72
81
|
source: "library:tier1.shell"
|
|
73
82
|
|
|
74
83
|
- desc: "Ban fork-bomb and obvious denial-of-service patterns"
|
|
@@ -124,8 +133,8 @@ agents:
|
|
|
124
133
|
args:
|
|
125
134
|
- exec
|
|
126
135
|
- command
|
|
127
|
-
- - "\\\\\\n\\s*(sudo|su\\s|rm\\s
|
|
128
|
-
- "\\\\\\r?\\n\\s*(sudo|su\\s|rm\\s
|
|
136
|
+
- - "\\\\\\n\\s*(sudo|su\\s|rm\\s+(?:-[a-zA-Z]*[rRf][a-zA-Z]*|--recursive|--force)|dd\\s+if=|chmod\\s|chown\\s|mount\\s|curl\\s|wget\\s)"
|
|
137
|
+
- "\\\\\\r?\\n\\s*(sudo|su\\s|rm\\s+(?:-[a-zA-Z]*[rRf][a-zA-Z]*|--recursive|--force)|dd\\s+if=|chmod\\s|chown\\s|mount\\s|curl\\s|wget\\s)"
|
|
129
138
|
source: "library:tier1.shell"
|
|
130
139
|
|
|
131
140
|
- desc: "Ban undefined-variable-looking patterns that expand to empty in shell"
|
|
@@ -135,8 +144,8 @@ agents:
|
|
|
135
144
|
args:
|
|
136
145
|
- exec
|
|
137
146
|
- command
|
|
138
|
-
- - "
|
|
139
|
-
- "
|
|
147
|
+
- - "\\brm(?:\\s+(?:-[a-zA-Z]+|--[a-z-]+))*\\s+(?:-[a-zA-Z]*[rRf][a-zA-Z]*|--recursive|--force)(?:\\s+(?:-[a-zA-Z]+|--[a-z-]+|--))*\\s+\\{[^}]*\\}/?"
|
|
148
|
+
- "\\brm(?:\\s+(?:-[a-zA-Z]+|--[a-z-]+))*\\s+(?:-[a-zA-Z]*[rRf][a-zA-Z]*|--recursive|--force)(?:\\s+(?:-[a-zA-Z]+|--[a-z-]+|--))*\\s+\\$\\{[^}]*\\}/?"
|
|
140
149
|
source: "library:tier1.shell"
|
|
141
150
|
|
|
142
151
|
# =================================================================
|
|
@@ -235,5 +244,5 @@ agents:
|
|
|
235
244
|
# - The LTL contracts in §3 and §4 depend on the `ltl:` schema field
|
|
236
245
|
# being supported by the config parser. Until the LTL parser lands,
|
|
237
246
|
# these can be temporarily commented out; the arg_blacklist contracts
|
|
238
|
-
# in §1 and the arg_length_limit
|
|
239
|
-
#
|
|
247
|
+
# in §1 and the arg_length_limit contract in §2 work on current
|
|
248
|
+
# master.
|