cc-safety-net 0.9.0 → 1.0.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/README.md +335 -122
- package/dist/bin/cc-safety-net.js +7974 -4618
- package/dist/bin/commands/doctor.d.ts +11 -2
- package/dist/bin/commands/explain.d.ts +16 -2
- package/dist/bin/commands/hook.d.ts +14 -0
- package/dist/bin/commands/index.d.ts +67 -3
- package/dist/bin/commands/rule.d.ts +14 -0
- package/dist/bin/commands/statusline.d.ts +10 -2
- package/dist/bin/commands/types.d.ts +11 -0
- package/dist/bin/doctor/config.d.ts +1 -1
- package/dist/bin/doctor/hooks.d.ts +2 -1
- package/dist/bin/doctor/system-info.d.ts +6 -2
- package/dist/bin/doctor/types.d.ts +26 -1
- package/dist/bin/explain/config.d.ts +3 -1
- package/dist/bin/hook/common.d.ts +20 -0
- package/dist/bin/hook/config-edit.d.ts +11 -0
- package/dist/bin/hook/constants.d.ts +6 -0
- package/dist/bin/hook/install/kimi-cli.d.ts +3 -0
- package/dist/bin/hook/install/types.d.ts +4 -0
- package/dist/bin/hook/install.d.ts +3 -0
- package/dist/bin/hook/integrations.d.ts +12 -0
- package/dist/bin/hook/kimi-cli.d.ts +1 -0
- package/dist/bin/integration-metadata.d.ts +68 -0
- package/dist/bin/rule/doc.d.ts +1 -0
- package/dist/bin/rule/format.d.ts +21 -0
- package/dist/bin/rule/index.d.ts +1 -0
- package/dist/bin/rule/migrate.d.ts +6 -0
- package/dist/bin/rule/verify.d.ts +9 -0
- package/dist/builtin-commands/templates/cc-safety-net.d.ts +1 -0
- package/dist/core/analyze/analyze-command.d.ts +0 -10
- package/dist/core/analyze/awk.d.ts +3 -0
- package/dist/core/analyze/child-analyzer.d.ts +16 -0
- package/dist/core/analyze/child-command.d.ts +15 -0
- package/dist/core/analyze/find.d.ts +8 -6
- package/dist/core/analyze/index.d.ts +4 -0
- package/dist/core/{rules-rm.d.ts → analyze/rm.d.ts} +0 -1
- package/dist/core/analyze/shell-git-env.d.ts +10 -0
- package/dist/core/analyze/xargs.d.ts +0 -1
- package/dist/core/audit.d.ts +3 -0
- package/dist/core/config.d.ts +5 -3
- package/dist/core/env.d.ts +39 -1
- package/dist/core/format.d.ts +1 -0
- package/dist/core/git/config.d.ts +1 -0
- package/dist/core/git/env.d.ts +12 -0
- package/dist/core/git/index.d.ts +3 -0
- package/dist/core/git/parse.d.ts +9 -0
- package/dist/core/git/rules.d.ts +8 -0
- package/dist/core/git/worktree-relaxation.d.ts +11 -0
- package/dist/core/{worktree.d.ts → git/worktree.d.ts} +1 -5
- package/dist/core/rules/custom-rule-validation.d.ts +5 -0
- package/dist/core/rules/policy/config-file.d.ts +19 -0
- package/dist/core/rules/policy/index.d.ts +6 -0
- package/dist/core/rules/policy/lockfile.d.ts +5 -0
- package/dist/core/rules/policy/paths.d.ts +31 -0
- package/dist/core/rules/policy/resolver.d.ts +16 -0
- package/dist/core/rules/policy/scope-policy.d.ts +18 -0
- package/dist/core/rules/policy/sources.d.ts +28 -0
- package/dist/core/rules/policy/sync.d.ts +10 -0
- package/dist/core/rules/policy/types.d.ts +77 -0
- package/dist/core/rules/rulebook.d.ts +28 -0
- package/dist/core/shell/command.d.ts +2 -0
- package/dist/core/shell/index.d.ts +4 -0
- package/dist/core/shell/options.d.ts +3 -0
- package/dist/core/shell/segments.d.ts +6 -0
- package/dist/core/shell/shared.d.ts +4 -0
- package/dist/core/{shell.d.ts → shell/wrappers.d.ts} +0 -6
- package/dist/index.d.ts +1 -1
- package/dist/index.js +4205 -2231
- package/dist/{features → opencode}/builtin-commands/commands.d.ts +1 -1
- package/dist/opencode/builtin-commands/index.d.ts +2 -0
- package/dist/{features → opencode}/builtin-commands/types.d.ts +1 -1
- package/dist/pi/builtin-commands/commands.d.ts +15 -0
- package/dist/pi/builtin-commands/index.d.ts +1 -0
- package/dist/pi/index.d.ts +5 -0
- package/dist/pi/index.js +6405 -0
- package/dist/pi/tool-use.d.ts +20 -0
- package/dist/types.d.ts +32 -2
- package/package.json +16 -8
- package/dist/bin/commands/claude-code.d.ts +0 -2
- package/dist/bin/commands/copilot-cli.d.ts +0 -2
- package/dist/bin/commands/custom-rules-doc.d.ts +0 -2
- package/dist/bin/commands/gemini-cli.d.ts +0 -2
- package/dist/bin/commands/verify-config.d.ts +0 -2
- package/dist/bin/custom-rules-doc.d.ts +0 -1
- package/dist/bin/verify-config.d.ts +0 -12
- package/dist/core/analyze.d.ts +0 -21
- package/dist/core/rules-git.d.ts +0 -20
- package/dist/features/builtin-commands/index.d.ts +0 -2
- package/dist/features/builtin-commands/templates/set-custom-rules.d.ts +0 -1
- package/dist/features/builtin-commands/templates/verify-custom-rules.d.ts +0 -1
- /package/dist/bin/{hooks → hook}/claude-code.d.ts +0 -0
- /package/dist/bin/{hooks → hook}/copilot-cli.d.ts +0 -0
- /package/dist/bin/{hooks → hook}/gemini-cli.d.ts +0 -0
- /package/dist/core/{rules-custom.d.ts → rules/custom.d.ts} +0 -0
package/README.md
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
#
|
|
1
|
+
# CC Safety Net
|
|
2
2
|
|
|
3
|
-
[](https://github.com/kenryu42/cc-safety-net/actions/workflows/ci.yml)
|
|
4
|
+
[](https://codecov.io/github/kenryu42/cc-safety-net)
|
|
5
|
+
[](https://github.com/kenryu42/cc-safety-net)
|
|
6
|
+
[](#codex-installation)
|
|
6
7
|
[](#claude-code-installation)
|
|
7
|
-
[](#opencode-installation)
|
|
8
|
-
[](#gemini-cli-installation)
|
|
9
8
|
[](#github-copilot-cli-installation)
|
|
10
|
-
[](#gemini-cli-installation)
|
|
10
|
+
[](#kimi-cli-installation)
|
|
11
|
+
[](#opencode-installation)
|
|
12
|
+
[](#pi-installation)
|
|
11
13
|
[](https://opensource.org/licenses/MIT)
|
|
12
14
|
|
|
13
15
|
<div align="center">
|
|
@@ -16,7 +18,7 @@
|
|
|
16
18
|
|
|
17
19
|
</div>
|
|
18
20
|
|
|
19
|
-
A
|
|
21
|
+
A Coding Agent CLI plugin that acts as a safety net, catching destructive git and filesystem commands before they execute.
|
|
20
22
|
|
|
21
23
|
## Contents
|
|
22
24
|
|
|
@@ -25,14 +27,14 @@ A Claude Code plugin that acts as a safety net, catching destructive git and fil
|
|
|
25
27
|
- [What About Sandboxing?](#what-about-sandboxing)
|
|
26
28
|
- [Prerequisites](#prerequisites)
|
|
27
29
|
- [Quick Start](#quick-start)
|
|
30
|
+
- [Codex Installation](#codex-installation)
|
|
28
31
|
- [Claude Code Installation](#claude-code-installation)
|
|
29
|
-
- [OpenCode Installation](#opencode-installation)
|
|
30
32
|
- [Gemini CLI Installation](#gemini-cli-installation)
|
|
31
33
|
- [GitHub Copilot CLI Installation](#github-copilot-cli-installation)
|
|
32
|
-
- [
|
|
34
|
+
- [Kimi CLI Installation](#kimi-cli-installation)
|
|
35
|
+
- [OpenCode Installation](#opencode-installation)
|
|
36
|
+
- [Pi Installation](#pi-installation)
|
|
33
37
|
- [Status Line Integration](#status-line-integration)
|
|
34
|
-
- [Setup via Slash Command](#setup-via-slash-command)
|
|
35
|
-
- [Manual Setup](#manual-setup)
|
|
36
38
|
- [Emoji Mode Indicators](#emoji-mode-indicators)
|
|
37
39
|
- [Diagnostics](#diagnostics)
|
|
38
40
|
- [Explain (Debug Analysis)](#explain-debug-analysis)
|
|
@@ -40,12 +42,12 @@ A Claude Code plugin that acts as a safety net, catching destructive git and fil
|
|
|
40
42
|
- [Commands Allowed](#commands-allowed)
|
|
41
43
|
- [What Happens When Blocked](#what-happens-when-blocked)
|
|
42
44
|
- [Testing the Hook](#testing-the-hook)
|
|
43
|
-
- [
|
|
44
|
-
- [Custom Rules
|
|
45
|
+
- [Breaking Change: Custom Rules Migration](#breaking-change-custom-rules-migration)
|
|
46
|
+
- [Custom Rules](#custom-rules)
|
|
45
47
|
- [Config File Location](#config-file-location)
|
|
46
48
|
- [Rule Schema](#rule-schema)
|
|
47
49
|
- [Matching Behavior](#matching-behavior)
|
|
48
|
-
- [Examples](#examples)
|
|
50
|
+
- [Rule Examples](#rule-examples)
|
|
49
51
|
- [Error Handling](#error-handling)
|
|
50
52
|
- [Advanced Features](#advanced-features)
|
|
51
53
|
- [Strict Mode](#strict-mode)
|
|
@@ -55,6 +57,7 @@ A Claude Code plugin that acts as a safety net, catching destructive git and fil
|
|
|
55
57
|
- [Interpreter One-Liner Detection](#interpreter-one-liner-detection)
|
|
56
58
|
- [Secret Redaction](#secret-redaction)
|
|
57
59
|
- [Audit Logging](#audit-logging)
|
|
60
|
+
- [Development](#development)
|
|
58
61
|
- [License](#license)
|
|
59
62
|
|
|
60
63
|
## Why This Exists
|
|
@@ -69,12 +72,12 @@ Claude Code's `.claude/settings.json` supports [deny rules](https://code.claude.
|
|
|
69
72
|
|
|
70
73
|
### At a Glance
|
|
71
74
|
|
|
72
|
-
| | Permission Deny Rules | Safety Net |
|
|
75
|
+
| | Permission Deny Rules | CC Safety Net |
|
|
73
76
|
|---|---|---|
|
|
74
77
|
| **Setup** | Manual configuration required | Works out of the box |
|
|
75
78
|
| **Parsing** | Wildcard pattern matching | Semantic command analysis |
|
|
76
79
|
| **Execution order** | Runs second | Runs first (PreToolUse hook) |
|
|
77
|
-
| **Shell wrappers** | Not handled automatically (must match wrapper forms) | Recursively analyzed (
|
|
80
|
+
| **Shell wrappers** | Not handled automatically (must match wrapper forms) | Recursively analyzed (up to 10 levels) |
|
|
78
81
|
| **Interpreter one-liners** | Not handled automatically (must match interpreter forms) | Detected and blocked |
|
|
79
82
|
|
|
80
83
|
### Permission Rules Have Known Bypass Vectors
|
|
@@ -89,9 +92,9 @@ Even with wildcard matching, Bash permission patterns are intentionally limited
|
|
|
89
92
|
| Extra whitespace | `rm -rf /` (double space) bypasses pattern |
|
|
90
93
|
| Shell wrappers | `sh -c "rm -rf /"` bypasses `Bash(rm:*)` entirely |
|
|
91
94
|
|
|
92
|
-
### Safety Net Handles What Patterns Can't
|
|
95
|
+
### CC Safety Net Handles What Patterns Can't
|
|
93
96
|
|
|
94
|
-
| Scenario | Permission Rules | Safety Net |
|
|
97
|
+
| Scenario | Permission Rules | CC Safety Net |
|
|
95
98
|
|----------|------------------|------------|
|
|
96
99
|
| `git checkout -b feature` (safe) | Blocked by `Bash(git checkout:*)` | Allowed |
|
|
97
100
|
| `git checkout -- file` (dangerous) | Blocked by `Bash(git checkout:*)` | Blocked |
|
|
@@ -102,17 +105,17 @@ Even with wildcard matching, Bash permission patterns are intentionally limited
|
|
|
102
105
|
|
|
103
106
|
### Defense in Depth
|
|
104
107
|
|
|
105
|
-
PreToolUse hooks run [**before**](https://code.claude.com/docs/en/iam#additional-permission-control-with-hooks) the permission system. This means Safety Net inspects every command first, regardless of your permission configuration. Even if you misconfigure deny rules, Safety Net provides a fallback layer of protection.
|
|
108
|
+
PreToolUse hooks run [**before**](https://code.claude.com/docs/en/iam#additional-permission-control-with-hooks) the permission system. This means CC Safety Net inspects every command first, regardless of your permission configuration. Even if you misconfigure deny rules, CC Safety Net provides a fallback layer of protection.
|
|
106
109
|
|
|
107
|
-
**Use both together**: Permission deny rules for quick, user-configurable blocks; Safety Net for robust, bypass-resistant protection that works out of the box.
|
|
110
|
+
**Use both together**: Permission deny rules for quick, user-configurable blocks; CC Safety Net for robust, bypass-resistant protection that works out of the box.
|
|
108
111
|
|
|
109
112
|
## What About Sandboxing?
|
|
110
113
|
|
|
111
|
-
Claude Code offers [native sandboxing](https://code.claude.com/docs/en/sandboxing) that provides OS-level filesystem and network isolation. Here's how it compares to Safety Net:
|
|
114
|
+
Claude Code offers [native sandboxing](https://code.claude.com/docs/en/sandboxing) that provides OS-level filesystem and network isolation. Here's how it compares to CC Safety Net:
|
|
112
115
|
|
|
113
116
|
### Different Layers of Protection
|
|
114
117
|
|
|
115
|
-
| | Sandboxing | Safety Net |
|
|
118
|
+
| | Sandboxing | CC Safety Net |
|
|
116
119
|
|---|---|---|
|
|
117
120
|
| **Enforcement** | OS-level (Seatbelt/bubblewrap) | Application-level (PreToolUse hook) |
|
|
118
121
|
| **Approach** | Containment — restricts filesystem + network access | Command analysis — blocks destructive operations |
|
|
@@ -128,7 +131,7 @@ Sandboxing restricts filesystem + network access, but it doesn't understand whet
|
|
|
128
131
|
> [!NOTE]
|
|
129
132
|
> Whether they're auto-run or require confirmation depends on your sandbox mode (auto-allow vs regular permissions), and network access still depends on your allowed-domain policy. Claude Code can also retry a command outside the sandbox via `dangerouslyDisableSandbox` (with user permission); this can be disabled with `allowUnsandboxedCommands: false`.
|
|
130
133
|
|
|
131
|
-
| Command | Sandboxing | Safety Net |
|
|
134
|
+
| Command | Sandboxing | CC Safety Net |
|
|
132
135
|
|---------|------------|------------|
|
|
133
136
|
| `git reset --hard` | Allowed (within cwd) | **Blocked** |
|
|
134
137
|
| `git checkout -- .` | Allowed (within cwd) | **Blocked** |
|
|
@@ -145,16 +148,16 @@ Sandboxing is the better choice when your primary concern is:
|
|
|
145
148
|
- **Prompt injection attacks** — Reduces exfiltration risk by restricting outbound domains (depends on your allowed-domain policy)
|
|
146
149
|
- **Malicious dependencies** — Limits filesystem writes and network access by default (subject to your sandbox configuration)
|
|
147
150
|
- **Untrusted code execution** — OS-level containment is stronger than pattern matching
|
|
148
|
-
- **Network control** — Safety Net has no network protection
|
|
151
|
+
- **Network control** — CC Safety Net has no network protection
|
|
149
152
|
|
|
150
153
|
### Recommended: Use Both
|
|
151
154
|
|
|
152
155
|
They protect against different threats:
|
|
153
156
|
|
|
154
157
|
- **Sandboxing** contains blast radius — even if something goes wrong, damage is limited to cwd and approved network domains
|
|
155
|
-
- **Safety Net** prevents footguns — catches git-specific mistakes that are technically "safe" from the sandbox's perspective
|
|
158
|
+
- **CC Safety Net** prevents footguns — catches git-specific mistakes that are technically "safe" from the sandbox's perspective
|
|
156
159
|
|
|
157
|
-
Running both together provides defense-in-depth. Sandboxing handles unknown threats; Safety Net handles known destructive patterns that sandboxing permits.
|
|
160
|
+
Running both together provides defense-in-depth. Sandboxing handles unknown threats; CC Safety Net handles known destructive patterns that sandboxing permits.
|
|
158
161
|
|
|
159
162
|
## Prerequisites
|
|
160
163
|
|
|
@@ -162,39 +165,40 @@ Running both together provides defense-in-depth. Sandboxing handles unknown thre
|
|
|
162
165
|
|
|
163
166
|
## Quick Start
|
|
164
167
|
|
|
165
|
-
###
|
|
168
|
+
### Codex Installation
|
|
166
169
|
|
|
167
|
-
|
|
168
|
-
/plugin marketplace add kenryu42/cc-marketplace
|
|
169
|
-
/plugin install safety-net@cc-marketplace
|
|
170
|
-
/reload-plugins
|
|
171
|
-
```
|
|
170
|
+
1. Enable Codex plugin hooks in `~/.codex/config.toml`:
|
|
172
171
|
|
|
173
|
-
|
|
172
|
+
```toml
|
|
173
|
+
[features]
|
|
174
|
+
plugin_hooks = true
|
|
175
|
+
```
|
|
174
176
|
|
|
175
|
-
|
|
177
|
+
2. Add the marketplace:
|
|
176
178
|
|
|
177
|
-
|
|
179
|
+
```bash
|
|
180
|
+
codex plugin marketplace add kenryu42/cc-marketplace
|
|
181
|
+
```
|
|
178
182
|
|
|
179
|
-
|
|
183
|
+
3. Start Codex.
|
|
184
|
+
4. In the TUI, run `/plugins`.
|
|
185
|
+
5. Use arrow keys to select `[cc-marketplace]`.
|
|
186
|
+
6. Press Enter to install the plugin.
|
|
187
|
+
7. run `/hooks` and select the safety-net PreToolUse hook and press `t` to trust it.
|
|
180
188
|
|
|
181
|
-
|
|
189
|
+
---
|
|
182
190
|
|
|
183
|
-
|
|
191
|
+
### Claude Code Installation
|
|
184
192
|
|
|
193
|
+
```bash
|
|
194
|
+
/plugin marketplace add kenryu42/cc-marketplace
|
|
195
|
+
/plugin install safety-net@cc-marketplace
|
|
196
|
+
/reload-plugins
|
|
185
197
|
```
|
|
186
|
-
Install the cc-safety-net plugin in `~/.config/opencode/opencode.json` (or `.jsonc`) according to the schema at: https://opencode.ai/config.json
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
**Option B: Manual setup**
|
|
190
198
|
|
|
191
|
-
|
|
199
|
+
### Claude Code Auto-Update
|
|
192
200
|
|
|
193
|
-
|
|
194
|
-
{
|
|
195
|
-
"plugin": ["cc-safety-net"]
|
|
196
|
-
}
|
|
197
|
-
```
|
|
201
|
+
1. Run `/plugin` → Select `Marketplaces` → Choose `cc-marketplace` → Enable auto-update
|
|
198
202
|
|
|
199
203
|
---
|
|
200
204
|
|
|
@@ -212,36 +216,42 @@ gemini extensions install https://github.com/kenryu42/gemini-safety-net
|
|
|
212
216
|
/plugin install kenryu42/copilot-safety-net
|
|
213
217
|
```
|
|
214
218
|
|
|
215
|
-
|
|
216
|
-
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
### Kimi CLI Installation
|
|
222
|
+
|
|
223
|
+
Install CC Safety Net into your Kimi CLI config:
|
|
224
|
+
|
|
225
|
+
```bash
|
|
226
|
+
npx -y cc-safety-net hook install --kimi-cli
|
|
227
|
+
```
|
|
217
228
|
|
|
218
229
|
---
|
|
219
230
|
|
|
220
|
-
### Codex Installation
|
|
221
231
|
|
|
222
|
-
|
|
232
|
+
### OpenCode Installation
|
|
223
233
|
|
|
224
|
-
|
|
225
|
-
[features]
|
|
226
|
-
plugin_hooks = true
|
|
227
|
-
```
|
|
234
|
+
Install CC Safety Net with OpenCode's native plugin command:
|
|
228
235
|
|
|
229
|
-
|
|
236
|
+
```bash
|
|
237
|
+
opencode plugin -g cc-safety-net
|
|
238
|
+
```
|
|
230
239
|
|
|
231
|
-
|
|
232
|
-
codex plugin marketplace add kenryu42/cc-marketplace
|
|
233
|
-
```
|
|
240
|
+
---
|
|
234
241
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
242
|
+
### Pi Installation
|
|
243
|
+
|
|
244
|
+
Install CC Safety Net with Pi's package installer:
|
|
245
|
+
|
|
246
|
+
```bash
|
|
247
|
+
pi install npm:cc-safety-net
|
|
248
|
+
```
|
|
239
249
|
|
|
240
250
|
---
|
|
241
251
|
|
|
242
252
|
## Status Line Integration
|
|
243
253
|
|
|
244
|
-
Safety Net can display its status in Claude Code's status line, showing whether protection is active and which modes are enabled.
|
|
254
|
+
CC Safety Net can display its status in Claude Code's status line, showing whether protection is active and which modes are enabled.
|
|
245
255
|
|
|
246
256
|
Add the following to your `~/.claude/settings.json`:
|
|
247
257
|
|
|
@@ -251,7 +261,7 @@ Add the following to your `~/.claude/settings.json`:
|
|
|
251
261
|
{
|
|
252
262
|
"statusLine": {
|
|
253
263
|
"type": "command",
|
|
254
|
-
"command": "bunx cc-safety-net --
|
|
264
|
+
"command": "bunx cc-safety-net statusline --claude-code"
|
|
255
265
|
}
|
|
256
266
|
}
|
|
257
267
|
```
|
|
@@ -262,7 +272,7 @@ Add the following to your `~/.claude/settings.json`:
|
|
|
262
272
|
{
|
|
263
273
|
"statusLine": {
|
|
264
274
|
"type": "command",
|
|
265
|
-
"command": "BUN_BE_BUN=1 claude x cc-safety-net --
|
|
275
|
+
"command": "BUN_BE_BUN=1 claude x cc-safety-net statusline --claude-code"
|
|
266
276
|
}
|
|
267
277
|
}
|
|
268
278
|
```
|
|
@@ -277,20 +287,20 @@ Add the following to your `~/.claude/settings.json`:
|
|
|
277
287
|
{
|
|
278
288
|
"statusLine": {
|
|
279
289
|
"type": "command",
|
|
280
|
-
"command": "npx -y cc-safety-net --
|
|
290
|
+
"command": "npx -y cc-safety-net statusline --claude-code"
|
|
281
291
|
}
|
|
282
292
|
}
|
|
283
293
|
```
|
|
284
294
|
|
|
285
295
|
**Piping with existing status line:**
|
|
286
296
|
|
|
287
|
-
If you already have a status line command, you can pipe Safety Net at the end:
|
|
297
|
+
If you already have a status line command, you can pipe CC Safety Net at the end:
|
|
288
298
|
|
|
289
299
|
```json
|
|
290
300
|
{
|
|
291
301
|
"statusLine": {
|
|
292
302
|
"type": "command",
|
|
293
|
-
"command": "your-existing-command | bunx cc-safety-net --
|
|
303
|
+
"command": "your-existing-command | bunx cc-safety-net statusline --claude-code"
|
|
294
304
|
}
|
|
295
305
|
}
|
|
296
306
|
```
|
|
@@ -303,16 +313,16 @@ The status line displays different emojis based on the current configuration:
|
|
|
303
313
|
|
|
304
314
|
| Status | Display | Meaning |
|
|
305
315
|
|--------|---------|---------|
|
|
306
|
-
| Plugin disabled | `🛡️ Safety Net ❌` | Safety Net plugin is not enabled |
|
|
307
|
-
| Default mode | `🛡️ Safety Net ✅` | Protection active with default settings |
|
|
308
|
-
| Strict mode | `🛡️ Safety Net 🔒` | `
|
|
309
|
-
| Paranoid mode | `🛡️ Safety Net 👁️` | `
|
|
310
|
-
| Paranoid RM only | `🛡️ Safety Net 🗑️` | `
|
|
311
|
-
| Paranoid interpreters only | `🛡️ Safety Net 🐚` | `
|
|
312
|
-
| Worktree mode | `🛡️ Safety Net 🌳` | `
|
|
313
|
-
| Strict + Paranoid | `🛡️ Safety Net 🔒👁️` | Both strict and paranoid modes enabled |
|
|
316
|
+
| Plugin disabled | `🛡️ CC Safety Net ❌` | CC Safety Net plugin is not enabled |
|
|
317
|
+
| Default mode | `🛡️ CC Safety Net ✅` | Protection active with default settings |
|
|
318
|
+
| Strict mode | `🛡️ CC Safety Net 🔒` | `CC_SAFETY_NET_STRICT=1` — fail-closed on unparseable commands |
|
|
319
|
+
| Paranoid mode | `🛡️ CC Safety Net 👁️` | `CC_SAFETY_NET_PARANOID=1` — all paranoid checks enabled |
|
|
320
|
+
| Paranoid RM only | `🛡️ CC Safety Net 🗑️` | `CC_SAFETY_NET_PARANOID_RM=1` — blocks `rm -rf` even within cwd |
|
|
321
|
+
| Paranoid interpreters only | `🛡️ CC Safety Net 🐚` | `CC_SAFETY_NET_PARANOID_INTERPRETERS=1` — blocks interpreter one-liners |
|
|
322
|
+
| Worktree mode | `🛡️ CC Safety Net 🌳` | `CC_SAFETY_NET_WORKTREE=1` — relax local git discards inside linked worktrees |
|
|
323
|
+
| Strict + Paranoid | `🛡️ CC Safety Net 🔒👁️` | Both strict and paranoid modes enabled |
|
|
314
324
|
|
|
315
|
-
Multiple mode emojis are combined when multiple environment variables are set.
|
|
325
|
+
Multiple mode emojis are combined when multiple environment variables are set. Mode flags use `CC_SAFETY_NET_*` names; legacy `SAFETY_NET_*` names are still accepted.
|
|
316
326
|
|
|
317
327
|
## Diagnostics
|
|
318
328
|
|
|
@@ -331,7 +341,7 @@ The doctor command checks:
|
|
|
331
341
|
| Hook Integration | Verifies the plugin is properly configured for each supported platform |
|
|
332
342
|
| Self-Test | Runs sample commands to confirm blocking works correctly |
|
|
333
343
|
| Configuration | Validates custom rules in user and project configs |
|
|
334
|
-
| Environment | Shows status of mode flags (
|
|
344
|
+
| Environment | Shows status of mode flags (`CC_SAFETY_NET_STRICT`, `CC_SAFETY_NET_PARANOID`, etc.; legacy `SAFETY_NET_*` also listed when set) |
|
|
335
345
|
| Recent Activity | Summarizes blocked commands from the last 7 days |
|
|
336
346
|
| System Info | Displays versions of all relevant tools |
|
|
337
347
|
| Update Check | Checks if a newer version is available |
|
|
@@ -345,7 +355,7 @@ The doctor command checks:
|
|
|
345
355
|
|
|
346
356
|
## Explain (Debug Analysis)
|
|
347
357
|
|
|
348
|
-
Trace how Safety Net analyzes a command step-by-step. Useful for debugging why a command is blocked or allowed, or when developing custom rules.
|
|
358
|
+
Trace how CC Safety Net analyzes a command step-by-step. Useful for debugging why a command is blocked or allowed, or when developing custom rules.
|
|
349
359
|
|
|
350
360
|
```bash
|
|
351
361
|
npx cc-safety-net explain "git reset --hard"
|
|
@@ -377,6 +387,8 @@ npx cc-safety-net explain --cwd /tmp "git status"
|
|
|
377
387
|
| git checkout \<ref\> \<path\> | May overwrite working tree when Git disambiguates ref vs pathspec |
|
|
378
388
|
| git restore files | Discards uncommitted changes |
|
|
379
389
|
| git restore --worktree | Explicitly discards working tree changes |
|
|
390
|
+
| git switch --discard-changes | Discards uncommitted changes when switching branches |
|
|
391
|
+
| git switch --force / -f | Discards uncommitted changes (force switch) |
|
|
380
392
|
| git reset --hard | Destroys all uncommitted changes |
|
|
381
393
|
| git reset --merge | Can lose uncommitted changes |
|
|
382
394
|
| git clean -f | Removes untracked files permanently |
|
|
@@ -385,13 +397,16 @@ npx cc-safety-net explain --cwd /tmp "git status"
|
|
|
385
397
|
| git stash drop | Permanently deletes stashed changes |
|
|
386
398
|
| git stash clear | Deletes ALL stashed changes |
|
|
387
399
|
| git worktree remove --force | Force-deletes worktree without checking for changes |
|
|
388
|
-
| rm -rf (
|
|
400
|
+
| rm -rf (destructive targets) | Recursive file deletion of root, home, parent, absolute, or non-temp paths outside cwd |
|
|
389
401
|
| rm -rf / or ~ or $HOME | Root/home deletion is extremely dangerous |
|
|
390
402
|
| find ... -delete | Permanently removes files matching criteria |
|
|
391
403
|
| xargs rm -rf | Dynamic input makes targets unpredictable |
|
|
392
404
|
| xargs \<shell\> -c | Can execute arbitrary commands |
|
|
393
405
|
| parallel rm -rf | Dynamic input makes targets unpredictable |
|
|
394
406
|
| parallel \<shell\> -c | Can execute arbitrary commands |
|
|
407
|
+
| dd writing to block devices | Can overwrite disks or partitions |
|
|
408
|
+
| mkfs on block devices | Formats disks or partitions |
|
|
409
|
+
| shred | Permanently destroys file contents |
|
|
395
410
|
|
|
396
411
|
## Commands Allowed
|
|
397
412
|
|
|
@@ -408,7 +423,7 @@ npx cc-safety-net explain --cwd /tmp "git status"
|
|
|
408
423
|
| rm -rf /var/tmp/... | System temp directory |
|
|
409
424
|
| rm -rf $TMPDIR/... | User's temp directory |
|
|
410
425
|
| rm -rf ./... (within cwd) | Limited to current working directory |
|
|
411
|
-
| git restore / checkout -- / reset --hard / clean -f (in linked worktree) | Relaxed only when `
|
|
426
|
+
| git restore / checkout -- / reset --hard / clean -f (in linked worktree) | Relaxed only when `CC_SAFETY_NET_WORKTREE=1` and cwd is a linked worktree |
|
|
412
427
|
|
|
413
428
|
## What Happens When Blocked
|
|
414
429
|
|
|
@@ -416,7 +431,7 @@ When a destructive command is detected, the plugin blocks the tool execution and
|
|
|
416
431
|
|
|
417
432
|
Example output:
|
|
418
433
|
```text
|
|
419
|
-
BLOCKED by Safety Net
|
|
434
|
+
BLOCKED by CC Safety Net
|
|
420
435
|
|
|
421
436
|
Reason: git checkout -- discards uncommitted changes permanently. Use 'git stash' first.
|
|
422
437
|
|
|
@@ -437,29 +452,109 @@ git checkout -- README.md
|
|
|
437
452
|
git checkout -b test-branch
|
|
438
453
|
```
|
|
439
454
|
|
|
440
|
-
##
|
|
455
|
+
## Breaking Change: Custom Rules Migration
|
|
441
456
|
|
|
442
|
-
|
|
457
|
+
> [!WARNING]
|
|
458
|
+
> The custom rules system has moved from legacy inline config files to a rulebook-based layout. Legacy inline config files (`.safety-net.json` and `~/.cc-safety-net/config.json`) are **no longer loaded at runtime**. If they contain rules, commands now **fail closed** (stay blocked) until you migrate.
|
|
459
|
+
|
|
460
|
+
### Who Is Affected
|
|
461
|
+
|
|
462
|
+
- **Affected**: users who previously defined custom rules in `.safety-net.json` (project scope) or `~/.cc-safety-net/config.json` (user scope).
|
|
463
|
+
- **Not affected**: users with no custom rules. All built-in destructive-command protections are unchanged and continue to work out of the box.
|
|
464
|
+
|
|
465
|
+
### What Breaks
|
|
466
|
+
|
|
467
|
+
| Legacy file state | New behavior |
|
|
468
|
+
|-------------------|--------------|
|
|
469
|
+
| Empty legacy file | Silently ignored — built-in rules only |
|
|
470
|
+
| Legacy file with rules | Fail closed until migrated with `rule migrate` |
|
|
471
|
+
| Invalid legacy file | Fail closed until fixed and migrated, or removed |
|
|
443
472
|
|
|
444
|
-
|
|
473
|
+
"Fail closed" means commands stay blocked until the legacy rules are migrated to the new layout.
|
|
474
|
+
|
|
475
|
+
### How to Migrate
|
|
476
|
+
|
|
477
|
+
```bash
|
|
478
|
+
# Convert legacy inline rules into the new rulebook layout
|
|
479
|
+
npx -y cc-safety-net rule migrate
|
|
480
|
+
|
|
481
|
+
# Optionally delete verified legacy files after migration
|
|
482
|
+
npx -y cc-safety-net rule migrate --cleanup
|
|
483
|
+
|
|
484
|
+
# Validate the migrated rules
|
|
485
|
+
npx -y cc-safety-net rule verify
|
|
486
|
+
npx -y cc-safety-net rule test
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
### Before / After
|
|
490
|
+
|
|
491
|
+
**Before** — a single inline config with rules embedded:
|
|
492
|
+
|
|
493
|
+
```text
|
|
494
|
+
.safety-net.json # project rules (inline)
|
|
495
|
+
~/.cc-safety-net/config.json # user rules (inline)
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
**After** — `rule migrate` creates a rulebook-based layout automatically:
|
|
499
|
+
|
|
500
|
+
```text
|
|
501
|
+
.cc-safety-net/rules/rule.json # project rulebook sources + overrides
|
|
502
|
+
.cc-safety-net/rules/project-rules/rulebook.json # migrated project rules
|
|
503
|
+
~/.cc-safety-net/rules/rule.json # user rulebook sources + overrides
|
|
504
|
+
~/.cc-safety-net/rules/user-rules/rulebook.json # migrated user rules
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
See [Custom Rules](#custom-rules) for the full authoring guide and [Error Handling](#error-handling) for fail-closed details.
|
|
508
|
+
|
|
509
|
+
## Custom Rules
|
|
445
510
|
|
|
446
511
|
Beyond the built-in protections, you can define your own blocking rules to enforce team conventions or project-specific safety policies.
|
|
447
512
|
|
|
448
513
|
> [!TIP]
|
|
449
|
-
>
|
|
450
|
-
|
|
514
|
+
> The best way to create custom rules is to use the `/cc-safety-net` skill to create custom rules interactively with natural language.
|
|
515
|
+
|
|
516
|
+
### Examples
|
|
517
|
+
|
|
518
|
+
```
|
|
519
|
+
/cc-safety-net read my package.json and suggest blocking rules
|
|
520
|
+
/cc-safety-net set up rules to block all terraform destroy commands
|
|
521
|
+
/cc-safety-net verify my rules and fix any errors
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
> [!NOTE]
|
|
451
525
|
> If your agent does not support skills, prompt it with:
|
|
452
|
-
> ```text
|
|
453
|
-
> run npx cc-safety-net --custom-rules-doc and help me set up custom rules
|
|
454
526
|
> ```
|
|
527
|
+
> run npx -y cc-safety-net rule doc and help me set up custom rules
|
|
528
|
+
> ```
|
|
529
|
+
|
|
530
|
+
### Create Rules Manually
|
|
455
531
|
|
|
456
|
-
|
|
532
|
+
Create a starter project rule config and rulebook:
|
|
457
533
|
|
|
458
|
-
|
|
534
|
+
```bash
|
|
535
|
+
npx -y cc-safety-net rule init
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
This creates `.cc-safety-net/rules/rule.json`:
|
|
459
539
|
|
|
460
540
|
```json
|
|
461
541
|
{
|
|
462
542
|
"version": 1,
|
|
543
|
+
"rules": ["project-rules"],
|
|
544
|
+
"overrides": {}
|
|
545
|
+
}
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
Rule definitions live in `.cc-safety-net/rules/project-rules/rulebook.json`:
|
|
549
|
+
|
|
550
|
+
```json
|
|
551
|
+
{
|
|
552
|
+
"rulebook_version": 1,
|
|
553
|
+
"name": "project-rules",
|
|
554
|
+
"version": "1.0.0",
|
|
555
|
+
"description": "Project-specific CC Safety Net rules.",
|
|
556
|
+
"author": "project",
|
|
557
|
+
"allowed_commands": ["git"],
|
|
463
558
|
"rules": [
|
|
464
559
|
{
|
|
465
560
|
"name": "block-git-add-all",
|
|
@@ -468,25 +563,48 @@ Create `.safety-net.json` in your project root:
|
|
|
468
563
|
"block_args": ["-A", "--all", "."],
|
|
469
564
|
"reason": "Use 'git add <specific-files>' instead of blanket add."
|
|
470
565
|
}
|
|
566
|
+
],
|
|
567
|
+
"tests": [
|
|
568
|
+
{
|
|
569
|
+
"command": "git add -A",
|
|
570
|
+
"expect": "blocked",
|
|
571
|
+
"rule": "block-git-add-all"
|
|
572
|
+
},
|
|
573
|
+
{
|
|
574
|
+
"command": "git add README.md",
|
|
575
|
+
"expect": "allowed"
|
|
576
|
+
}
|
|
471
577
|
]
|
|
472
578
|
}
|
|
473
579
|
```
|
|
474
580
|
|
|
581
|
+
After editing rulebooks, run:
|
|
582
|
+
|
|
583
|
+
```bash
|
|
584
|
+
npx -y cc-safety-net rule sync
|
|
585
|
+
npx -y cc-safety-net rule verify
|
|
586
|
+
npx -y cc-safety-net rule test
|
|
587
|
+
```
|
|
588
|
+
|
|
475
589
|
Now `git add -A`, `git add --all`, and `git add .` will be blocked with your custom message.
|
|
476
590
|
|
|
477
591
|
### Config File Location
|
|
478
592
|
|
|
479
593
|
Config files are loaded from two scopes and merged:
|
|
480
594
|
|
|
481
|
-
1. **User scope**: `~/.cc-safety-net/
|
|
482
|
-
2. **Project scope**: `.safety-net.json` in the current working directory
|
|
595
|
+
1. **User scope**: `~/.cc-safety-net/rules/rule.json` (use `rule init --global`)
|
|
596
|
+
2. **Project scope**: `.cc-safety-net/rules/rule.json` in the current working directory
|
|
597
|
+
|
|
598
|
+
Local rulebook sources are bare names like `project-rules`. GitHub rulebook sources use `owner/repo#ref/<rulebook-name>` and point to `.cc-safety-net/rules/<rulebook-name>/rulebook.json` in that repository.
|
|
599
|
+
|
|
600
|
+
Legacy inline config files (`.safety-net.json` and `~/.cc-safety-net/config.json`) are no longer loaded at runtime. Empty legacy files are ignored, but legacy files with rules and invalid legacy files fail closed until migrated or fixed. Convert existing legacy rules with `npx -y cc-safety-net rule migrate`; use `npx -y cc-safety-net rule migrate --cleanup` if you also want to delete verified legacy files after migration. See [Breaking Change: Custom Rules Migration](#breaking-change-custom-rules-migration) for the full upgrade guide.
|
|
483
601
|
|
|
484
602
|
**Merging behavior**:
|
|
485
|
-
-
|
|
486
|
-
-
|
|
487
|
-
-
|
|
603
|
+
- Rulebooks from both scopes are combined
|
|
604
|
+
- Duplicate active rulebook names are invalid
|
|
605
|
+
- Project overrides win over user overrides for the same `<rulebook-name>/<rule-name>` key
|
|
488
606
|
|
|
489
|
-
This allows you to define personal defaults in user scope while letting projects
|
|
607
|
+
This allows you to define personal defaults in user scope while letting projects disable or replace reasons for specific rules.
|
|
490
608
|
|
|
491
609
|
If no config file is found in either location, only built-in rules apply.
|
|
492
610
|
|
|
@@ -495,18 +613,44 @@ If no config file is found in either location, only built-in rules apply.
|
|
|
495
613
|
| Field | Type | Required | Description |
|
|
496
614
|
|-------|------|----------|-------------|
|
|
497
615
|
| `version` | integer | Yes | Schema version (must be `1`) |
|
|
498
|
-
| `rules` | array | No | List of
|
|
616
|
+
| `rules` | array | No | List of rulebook source strings (defaults to empty) |
|
|
617
|
+
| `overrides` | object | No | Rule overrides keyed by `<rulebook-name>/<rule-name>` |
|
|
618
|
+
|
|
619
|
+
Override values are either `"off"` to disable a rule or `{ "reason": "..." }` to replace the rule reason.
|
|
620
|
+
|
|
621
|
+
### Rulebook Schema
|
|
622
|
+
|
|
623
|
+
| Field | Type | Required | Description |
|
|
624
|
+
|-------|------|----------|-------------|
|
|
625
|
+
| `rulebook_version` | integer | Yes | Rulebook schema version (must be `1`) |
|
|
626
|
+
| `name` | string | Yes | Rulebook name; must match the local directory name or GitHub source name |
|
|
627
|
+
| `version` | string | Yes | Rulebook version |
|
|
628
|
+
| `description` | string | No | Human-readable description |
|
|
629
|
+
| `author` | string | No | Rulebook author |
|
|
630
|
+
| `allowed_commands` | array | Yes | Commands this rulebook is allowed to define rules for |
|
|
631
|
+
| `rules` | array | Yes | Custom blocking rules |
|
|
632
|
+
| `tests` | array | Yes | Rulebook fixtures |
|
|
499
633
|
|
|
500
634
|
### Rule Schema
|
|
501
635
|
|
|
502
636
|
| Field | Type | Required | Description |
|
|
503
637
|
|-------|------|----------|-------------|
|
|
504
|
-
| `name` | string | Yes | Unique
|
|
505
|
-
| `command` | string | Yes | Base command to match
|
|
638
|
+
| `name` | string | Yes | Unique within the rulebook (letters, numbers, hyphens, underscores; max 64 chars) |
|
|
639
|
+
| `command` | string | Yes | Base command to match; must be listed in `allowed_commands` |
|
|
506
640
|
| `subcommand` | string | No | Subcommand to match (e.g., `add`, `install`). If omitted, matches any. |
|
|
507
641
|
| `block_args` | array | Yes | Arguments that trigger the block (at least one required) |
|
|
508
642
|
| `reason` | string | Yes | Message shown when blocked (max 256 chars) |
|
|
509
643
|
|
|
644
|
+
### Fixture Schema
|
|
645
|
+
|
|
646
|
+
| Field | Type | Required | Description |
|
|
647
|
+
|-------|------|----------|-------------|
|
|
648
|
+
| `command` | string | Yes | Shell command fixture |
|
|
649
|
+
| `expect` | string | Yes | Either `blocked` or `allowed` |
|
|
650
|
+
| `rule` | string | For blocked fixtures | Rule expected to block the command |
|
|
651
|
+
|
|
652
|
+
Every rule must have at least one blocked fixture. Add allowed fixtures for close-but-safe commands.
|
|
653
|
+
|
|
510
654
|
### Matching Behavior
|
|
511
655
|
|
|
512
656
|
- **Commands** are normalized to basename (`/usr/bin/git` → `git`)
|
|
@@ -521,13 +665,28 @@ If no config file is found in either location, only built-in rules apply.
|
|
|
521
665
|
|
|
522
666
|
- **Short option expansion**: `-Cfoo` is treated as `-C -f -o -o`, not `-C foo`. Blocking `-f` may false-positive on attached option values.
|
|
523
667
|
|
|
524
|
-
### Examples
|
|
668
|
+
### Rule Examples
|
|
525
669
|
|
|
526
670
|
#### Block global npm installs
|
|
527
671
|
|
|
672
|
+
`.cc-safety-net/rules/rule.json`:
|
|
673
|
+
|
|
528
674
|
```json
|
|
529
675
|
{
|
|
530
676
|
"version": 1,
|
|
677
|
+
"rules": ["project-rules"],
|
|
678
|
+
"overrides": {}
|
|
679
|
+
}
|
|
680
|
+
```
|
|
681
|
+
|
|
682
|
+
`.cc-safety-net/rules/project-rules/rulebook.json`:
|
|
683
|
+
|
|
684
|
+
```json
|
|
685
|
+
{
|
|
686
|
+
"rulebook_version": 1,
|
|
687
|
+
"name": "project-rules",
|
|
688
|
+
"version": "1.0.0",
|
|
689
|
+
"allowed_commands": ["npm"],
|
|
531
690
|
"rules": [
|
|
532
691
|
{
|
|
533
692
|
"name": "block-npm-global",
|
|
@@ -536,6 +695,17 @@ If no config file is found in either location, only built-in rules apply.
|
|
|
536
695
|
"block_args": ["-g", "--global"],
|
|
537
696
|
"reason": "Global npm installs can cause version conflicts. Use npx or local install."
|
|
538
697
|
}
|
|
698
|
+
],
|
|
699
|
+
"tests": [
|
|
700
|
+
{
|
|
701
|
+
"command": "npm install -g typescript",
|
|
702
|
+
"expect": "blocked",
|
|
703
|
+
"rule": "block-npm-global"
|
|
704
|
+
},
|
|
705
|
+
{
|
|
706
|
+
"command": "npm install typescript",
|
|
707
|
+
"expect": "allowed"
|
|
708
|
+
}
|
|
539
709
|
]
|
|
540
710
|
}
|
|
541
711
|
```
|
|
@@ -544,7 +714,10 @@ If no config file is found in either location, only built-in rules apply.
|
|
|
544
714
|
|
|
545
715
|
```json
|
|
546
716
|
{
|
|
547
|
-
"
|
|
717
|
+
"rulebook_version": 1,
|
|
718
|
+
"name": "project-rules",
|
|
719
|
+
"version": "1.0.0",
|
|
720
|
+
"allowed_commands": ["docker"],
|
|
548
721
|
"rules": [
|
|
549
722
|
{
|
|
550
723
|
"name": "block-docker-system-prune",
|
|
@@ -553,6 +726,17 @@ If no config file is found in either location, only built-in rules apply.
|
|
|
553
726
|
"block_args": ["prune"],
|
|
554
727
|
"reason": "docker system prune removes all unused data. Use targeted cleanup instead."
|
|
555
728
|
}
|
|
729
|
+
],
|
|
730
|
+
"tests": [
|
|
731
|
+
{
|
|
732
|
+
"command": "docker system prune",
|
|
733
|
+
"expect": "blocked",
|
|
734
|
+
"rule": "block-docker-system-prune"
|
|
735
|
+
},
|
|
736
|
+
{
|
|
737
|
+
"command": "docker ps",
|
|
738
|
+
"expect": "allowed"
|
|
739
|
+
}
|
|
556
740
|
]
|
|
557
741
|
}
|
|
558
742
|
```
|
|
@@ -561,7 +745,10 @@ If no config file is found in either location, only built-in rules apply.
|
|
|
561
745
|
|
|
562
746
|
```json
|
|
563
747
|
{
|
|
564
|
-
"
|
|
748
|
+
"rulebook_version": 1,
|
|
749
|
+
"name": "project-rules",
|
|
750
|
+
"version": "1.0.0",
|
|
751
|
+
"allowed_commands": ["git", "npm"],
|
|
565
752
|
"rules": [
|
|
566
753
|
{
|
|
567
754
|
"name": "block-git-add-all",
|
|
@@ -577,33 +764,47 @@ If no config file is found in either location, only built-in rules apply.
|
|
|
577
764
|
"block_args": ["-g", "--global"],
|
|
578
765
|
"reason": "Use npx or local install instead of global."
|
|
579
766
|
}
|
|
767
|
+
],
|
|
768
|
+
"tests": [
|
|
769
|
+
{
|
|
770
|
+
"command": "git add -A",
|
|
771
|
+
"expect": "blocked",
|
|
772
|
+
"rule": "block-git-add-all"
|
|
773
|
+
},
|
|
774
|
+
{
|
|
775
|
+
"command": "npm install -g typescript",
|
|
776
|
+
"expect": "blocked",
|
|
777
|
+
"rule": "block-npm-global"
|
|
778
|
+
}
|
|
580
779
|
]
|
|
581
780
|
}
|
|
582
781
|
```
|
|
583
782
|
|
|
584
783
|
### Error Handling
|
|
585
784
|
|
|
586
|
-
|
|
785
|
+
Rulebook-backed custom rules fail closed when configured rulebooks cannot be loaded safely:
|
|
587
786
|
|
|
588
787
|
| Scenario | Behavior |
|
|
589
788
|
|----------|----------|
|
|
590
789
|
| Config file not found | Silent — use built-in rules only |
|
|
591
|
-
|
|
|
592
|
-
|
|
|
593
|
-
|
|
|
594
|
-
| Invalid
|
|
595
|
-
|
|
|
790
|
+
| Invalid rule config | Fail closed until fixed |
|
|
791
|
+
| Empty legacy config | Silent — use built-in rules only |
|
|
792
|
+
| Legacy config with rules and no migrated rule config | Fail closed until `rule migrate` creates the new rule config |
|
|
793
|
+
| Invalid legacy config | Fail closed until fixed or removed |
|
|
794
|
+
| Missing or stale lock/cache | Fail closed until `rule sync` repairs it |
|
|
795
|
+
| Invalid local rulebook | Fail closed until the rulebook is fixed and synced |
|
|
796
|
+
| Invalid GitHub rulebook | Fail closed until the source is fixed or removed |
|
|
596
797
|
|
|
597
798
|
|
|
598
799
|
> [!IMPORTANT]
|
|
599
|
-
> If you add or modify custom rules manually, always validate them with `npx -y cc-safety-net
|
|
800
|
+
> If you add or modify custom rules manually, always validate them with `npx -y cc-safety-net rule verify` and `npx -y cc-safety-net rule test`.
|
|
600
801
|
|
|
601
802
|
### Block Output Format
|
|
602
803
|
|
|
603
804
|
When a custom rule blocks a command, the output includes the rule name:
|
|
604
805
|
|
|
605
806
|
```text
|
|
606
|
-
BLOCKED by Safety Net
|
|
807
|
+
BLOCKED by CC Safety Net
|
|
607
808
|
|
|
608
809
|
Reason: [block-git-add-all] Use 'git add <specific-files>' instead of blanket add.
|
|
609
810
|
|
|
@@ -612,14 +813,17 @@ Command: git add -A
|
|
|
612
813
|
|
|
613
814
|
## Advanced Features
|
|
614
815
|
|
|
816
|
+
Mode and debug flags use **`CC_SAFETY_NET_*`** environment variables. Older **`SAFETY_NET_*`** names (without the `CC_` prefix) still work for strict, paranoid, and worktree toggles.
|
|
817
|
+
|
|
615
818
|
### Strict Mode
|
|
616
819
|
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
unterminated quotes
|
|
820
|
+
Malformed or missing hook input JSON always fails closed. By default, ambiguous shell
|
|
821
|
+
command parsing is allowed through. Enable strict mode to fail closed when a shell
|
|
822
|
+
command cannot be safely analyzed (e.g., unterminated quotes or malformed `bash -c`
|
|
823
|
+
wrappers):
|
|
620
824
|
|
|
621
825
|
```bash
|
|
622
|
-
export
|
|
826
|
+
export CC_SAFETY_NET_STRICT=1
|
|
623
827
|
```
|
|
624
828
|
|
|
625
829
|
### Paranoid Mode
|
|
@@ -629,11 +833,11 @@ You can enable it globally or via focused toggles:
|
|
|
629
833
|
|
|
630
834
|
```bash
|
|
631
835
|
# Enable all paranoid checks
|
|
632
|
-
export
|
|
836
|
+
export CC_SAFETY_NET_PARANOID=1
|
|
633
837
|
|
|
634
838
|
# Or enable specific paranoid checks
|
|
635
|
-
export
|
|
636
|
-
export
|
|
839
|
+
export CC_SAFETY_NET_PARANOID_RM=1
|
|
840
|
+
export CC_SAFETY_NET_PARANOID_INTERPRETERS=1
|
|
637
841
|
```
|
|
638
842
|
|
|
639
843
|
Paranoid behavior:
|
|
@@ -650,7 +854,7 @@ local-discard rules when (and only when) the command is proven to run inside a
|
|
|
650
854
|
linked worktree:
|
|
651
855
|
|
|
652
856
|
```bash
|
|
653
|
-
export
|
|
857
|
+
export CC_SAFETY_NET_WORKTREE=1
|
|
654
858
|
```
|
|
655
859
|
|
|
656
860
|
When enabled, these commands are allowed inside a linked worktree:
|
|
@@ -691,6 +895,7 @@ The guard recursively analyzes commands wrapped in shells:
|
|
|
691
895
|
```bash
|
|
692
896
|
bash -c 'git reset --hard' # Blocked
|
|
693
897
|
sh -lc 'rm -rf /' # Blocked
|
|
898
|
+
bash -c 'git stash drop' # Blocked
|
|
694
899
|
```
|
|
695
900
|
|
|
696
901
|
### Interpreter One-Liner Detection
|
|
@@ -699,6 +904,10 @@ Detects destructive commands hidden in Python/Node/Ruby/Perl one-liners:
|
|
|
699
904
|
|
|
700
905
|
```bash
|
|
701
906
|
python -c 'import os; os.system("rm -rf /")' # Blocked
|
|
907
|
+
python -c 'import os; os.system("git stash drop")' # Blocked
|
|
908
|
+
python -c 'import os; os.system("dd if=/dev/zero of=/dev/sda")' # Blocked
|
|
909
|
+
python -c 'import os; os.system("mkfs.ext4 /dev/sda1")' # Blocked
|
|
910
|
+
python -c 'import os; os.system("shred -u secret.txt")' # Blocked
|
|
702
911
|
```
|
|
703
912
|
|
|
704
913
|
### Secret Redaction
|
|
@@ -715,6 +924,10 @@ All blocked commands are logged to `~/.cc-safety-net/logs/<session_id>.jsonl` fo
|
|
|
715
924
|
|
|
716
925
|
Sensitive data in log entries is automatically redacted.
|
|
717
926
|
|
|
927
|
+
## Development
|
|
928
|
+
|
|
929
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to contribute to this project.
|
|
930
|
+
|
|
718
931
|
## License
|
|
719
932
|
|
|
720
933
|
MIT
|