cc-safety-net 1.0.6 → 2.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/LICENSE +1 -1
- package/README.md +177 -877
- package/THIRD_PARTY_LICENSES.txt +23 -0
- package/dist/amp/cc-safety-net.ts +102 -0
- package/dist/bin/cc-safety-net.js +4825 -10427
- package/dist/chunks/index-25nh5wqs.js +45 -0
- package/dist/chunks/index-9s8cwhj0.js +64 -0
- package/dist/index.d.ts +2 -15
- package/dist/index.js +1 -6404
- package/dist/openclaw/cc-safety-net/index.js +101 -0
- package/dist/openclaw/cc-safety-net/openclaw.plugin.json +14 -0
- package/dist/openclaw/cc-safety-net/package.json +11 -0
- package/dist/pi/index.js +2 -6540
- package/package.json +55 -30
- package/dist/bin/cc-safety-net.d.ts +0 -2
- package/dist/bin/commands/doctor.d.ts +0 -11
- package/dist/bin/commands/explain.d.ts +0 -16
- package/dist/bin/commands/hook.d.ts +0 -14
- package/dist/bin/commands/index.d.ts +0 -82
- package/dist/bin/commands/rule.d.ts +0 -14
- package/dist/bin/commands/statusline.d.ts +0 -10
- package/dist/bin/commands/types.d.ts +0 -45
- package/dist/bin/doctor/activity.d.ts +0 -5
- package/dist/bin/doctor/config.d.ts +0 -15
- package/dist/bin/doctor/environment.d.ts +0 -5
- package/dist/bin/doctor/flags.d.ts +0 -5
- package/dist/bin/doctor/format.d.ts +0 -37
- package/dist/bin/doctor/hooks.d.ts +0 -25
- package/dist/bin/doctor/index.d.ts +0 -6
- package/dist/bin/doctor/system-info.d.ts +0 -29
- package/dist/bin/doctor/types.d.ts +0 -159
- package/dist/bin/doctor/updates.d.ts +0 -5
- package/dist/bin/explain/analyze.d.ts +0 -5
- package/dist/bin/explain/config.d.ts +0 -25
- package/dist/bin/explain/flags.d.ts +0 -9
- package/dist/bin/explain/format-helpers.d.ts +0 -35
- package/dist/bin/explain/format.d.ts +0 -8
- package/dist/bin/explain/index.d.ts +0 -7
- package/dist/bin/explain/redact.d.ts +0 -20
- package/dist/bin/explain/segment.d.ts +0 -11
- package/dist/bin/help.d.ts +0 -19
- package/dist/bin/hook/claude-code.d.ts +0 -1
- package/dist/bin/hook/common.d.ts +0 -18
- package/dist/bin/hook/config-edit.d.ts +0 -11
- package/dist/bin/hook/constants.d.ts +0 -6
- package/dist/bin/hook/copilot-cli.d.ts +0 -1
- package/dist/bin/hook/gemini-cli.d.ts +0 -1
- package/dist/bin/hook/install/kimi-code.d.ts +0 -3
- package/dist/bin/hook/install/types.d.ts +0 -4
- package/dist/bin/hook/install.d.ts +0 -3
- package/dist/bin/hook/integrations.d.ts +0 -12
- package/dist/bin/hook/kimi-code.d.ts +0 -1
- package/dist/bin/integration-metadata.d.ts +0 -68
- package/dist/bin/rule/doc.d.ts +0 -1
- package/dist/bin/rule/format.d.ts +0 -14
- package/dist/bin/rule/index.d.ts +0 -1
- package/dist/bin/rule/migrate.d.ts +0 -6
- package/dist/bin/rule/verify.d.ts +0 -9
- package/dist/bin/statusline.d.ts +0 -1
- package/dist/bin/utils/colors.d.ts +0 -36
- package/dist/builtin-commands/templates/cc-safety-net.d.ts +0 -1
- package/dist/core/analyze/analyze-command.d.ts +0 -6
- package/dist/core/analyze/awk.d.ts +0 -3
- package/dist/core/analyze/child-analyzer.d.ts +0 -16
- package/dist/core/analyze/child-command.d.ts +0 -15
- package/dist/core/analyze/constants.d.ts +0 -1
- package/dist/core/analyze/dangerous-text.d.ts +0 -1
- package/dist/core/analyze/find.d.ts +0 -8
- package/dist/core/analyze/index.d.ts +0 -4
- package/dist/core/analyze/interpreters.d.ts +0 -2
- package/dist/core/analyze/parallel.d.ts +0 -13
- package/dist/core/analyze/rm-flags.d.ts +0 -1
- package/dist/core/analyze/rm.d.ts +0 -9
- package/dist/core/analyze/segment.d.ts +0 -11
- package/dist/core/analyze/shell-git-env.d.ts +0 -10
- package/dist/core/analyze/shell-wrappers.d.ts +0 -1
- package/dist/core/analyze/tmpdir.d.ts +0 -1
- package/dist/core/analyze/xargs.d.ts +0 -16
- package/dist/core/audit.d.ts +0 -20
- package/dist/core/config.d.ts +0 -14
- package/dist/core/env.d.ts +0 -39
- package/dist/core/format.d.ts +0 -11
- package/dist/core/git/config.d.ts +0 -1
- package/dist/core/git/env.d.ts +0 -15
- package/dist/core/git/index.d.ts +0 -3
- package/dist/core/git/parse.d.ts +0 -9
- package/dist/core/git/rules.d.ts +0 -8
- package/dist/core/git/worktree-relaxation.d.ts +0 -11
- package/dist/core/git/worktree.d.ts +0 -11
- package/dist/core/path.d.ts +0 -1
- package/dist/core/rules/custom-rule-validation.d.ts +0 -5
- package/dist/core/rules/custom.d.ts +0 -2
- package/dist/core/rules/policy/config-file.d.ts +0 -19
- package/dist/core/rules/policy/index.d.ts +0 -5
- package/dist/core/rules/policy/lockfile.d.ts +0 -5
- package/dist/core/rules/policy/paths.d.ts +0 -32
- package/dist/core/rules/policy/resolver.d.ts +0 -16
- package/dist/core/rules/policy/scope-policy.d.ts +0 -19
- package/dist/core/rules/policy/sources.d.ts +0 -28
- package/dist/core/rules/policy/sync.d.ts +0 -10
- package/dist/core/rules/policy/types.d.ts +0 -76
- package/dist/core/rules/rulebook.d.ts +0 -30
- package/dist/core/shell/command.d.ts +0 -2
- package/dist/core/shell/index.d.ts +0 -4
- package/dist/core/shell/options.d.ts +0 -3
- package/dist/core/shell/segments.d.ts +0 -6
- package/dist/core/shell/shared.d.ts +0 -4
- package/dist/core/shell/wrappers.d.ts +0 -17
- package/dist/opencode/builtin-commands/commands.d.ts +0 -2
- package/dist/opencode/builtin-commands/index.d.ts +0 -2
- package/dist/opencode/builtin-commands/types.d.ts +0 -6
- package/dist/pi/builtin-commands/commands.d.ts +0 -16
- package/dist/pi/builtin-commands/index.d.ts +0 -1
- package/dist/pi/index.d.ts +0 -5
- package/dist/pi/tool-call.d.ts +0 -21
- package/dist/types.d.ts +0 -275
package/README.md
CHANGED
|
@@ -1,954 +1,254 @@
|
|
|
1
|
-
|
|
1
|
+
<h1>
|
|
2
|
+
<picture>
|
|
3
|
+
<source media="(prefers-color-scheme: dark)" srcset="./.github/assets/cc-safety-net-header-logo-dark.svg">
|
|
4
|
+
<source media="(prefers-color-scheme: light)" srcset="./.github/assets/cc-safety-net-header-logo-light.svg">
|
|
5
|
+
<img alt="CC Safety Net" src="./.github/assets/cc-safety-net-header-logo-light.svg">
|
|
6
|
+
</picture>
|
|
7
|
+
</h1>
|
|
2
8
|
|
|
3
9
|
[](https://github.com/kenryu42/cc-safety-net/actions/workflows/ci.yml)
|
|
4
10
|
[](https://codecov.io/github/kenryu42/cc-safety-net)
|
|
5
11
|
[](https://github.com/kenryu42/cc-safety-net)
|
|
6
|
-
[](https://ccsafetynet.com/docs/installation#amp-code-installation)
|
|
13
|
+
[](https://ccsafetynet.com/docs/installation#antigravity-cli-installation)
|
|
14
|
+
[](https://ccsafetynet.com/docs/installation#claude-code-installation)
|
|
15
|
+
[](https://ccsafetynet.com/docs/installation#codex-installation)
|
|
16
|
+
[](https://ccsafetynet.com/docs/installation#cursor-installation)
|
|
17
|
+
[](https://ccsafetynet.com/docs/installation#gemini-cli-installation)
|
|
18
|
+
[](https://ccsafetynet.com/docs/installation#github-copilot-cli-installation)
|
|
19
|
+
[](#hermes-agent-and-openclaw)
|
|
20
|
+
[](https://ccsafetynet.com/docs/installation#kimi-code-installation)
|
|
21
|
+
[](#hermes-agent-and-openclaw)
|
|
22
|
+
[](https://ccsafetynet.com/docs/installation#opencode-installation)
|
|
23
|
+
[](https://ccsafetynet.com/docs/installation#pi-installation)
|
|
13
24
|
[](https://opensource.org/licenses/MIT)
|
|
14
25
|
|
|
15
26
|
<div align="center">
|
|
16
27
|
|
|
17
|
-
[](./.github/assets/cc-safety-net.png)
|
|
28
|
+
[](./.github/assets/cc-safety-net-v2.png)
|
|
18
29
|
|
|
19
30
|
</div>
|
|
20
31
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
## Contents
|
|
24
|
-
|
|
25
|
-
- [Why This Exists](#why-this-exists)
|
|
26
|
-
- [Why Use This Instead of Permission Deny Rules?](#why-use-this-instead-of-permission-deny-rules)
|
|
27
|
-
- [What About Sandboxing?](#what-about-sandboxing)
|
|
28
|
-
- [Prerequisites](#prerequisites)
|
|
29
|
-
- [Quick Start](#quick-start)
|
|
30
|
-
- [Codex Installation](#codex-installation)
|
|
31
|
-
- [Claude Code Installation](#claude-code-installation)
|
|
32
|
-
- [Gemini CLI Installation](#gemini-cli-installation)
|
|
33
|
-
- [GitHub Copilot CLI Installation](#github-copilot-cli-installation)
|
|
34
|
-
- [Kimi Code Installation](#kimi-code-installation)
|
|
35
|
-
- [OpenCode Installation](#opencode-installation)
|
|
36
|
-
- [Pi Installation](#pi-installation)
|
|
37
|
-
- [Status Line Integration](#status-line-integration)
|
|
38
|
-
- [Emoji Mode Indicators](#emoji-mode-indicators)
|
|
39
|
-
- [Diagnostics](#diagnostics)
|
|
40
|
-
- [Explain (Debug Analysis)](#explain-debug-analysis)
|
|
41
|
-
- [Commands Blocked](#commands-blocked)
|
|
42
|
-
- [Commands Allowed](#commands-allowed)
|
|
43
|
-
- [What Happens When Blocked](#what-happens-when-blocked)
|
|
44
|
-
- [Testing the Hook](#testing-the-hook)
|
|
45
|
-
- [Breaking Change: Custom Rules Migration](#breaking-change-custom-rules-migration)
|
|
46
|
-
- [Custom Rules](#custom-rules)
|
|
47
|
-
- [Config File Location](#config-file-location)
|
|
48
|
-
- [Rule Schema](#rule-schema)
|
|
49
|
-
- [Matching Behavior](#matching-behavior)
|
|
50
|
-
- [Rule Examples](#rule-examples)
|
|
51
|
-
- [Error Handling](#error-handling)
|
|
52
|
-
- [Advanced Features](#advanced-features)
|
|
53
|
-
- [Strict Mode](#strict-mode)
|
|
54
|
-
- [Paranoid Mode](#paranoid-mode)
|
|
55
|
-
- [Worktree Mode](#worktree-mode)
|
|
56
|
-
- [Shell Wrapper Detection](#shell-wrapper-detection)
|
|
57
|
-
- [Interpreter One-Liner Detection](#interpreter-one-liner-detection)
|
|
58
|
-
- [Secret Redaction](#secret-redaction)
|
|
59
|
-
- [Audit Logging](#audit-logging)
|
|
60
|
-
- [Development](#development)
|
|
61
|
-
- [License](#license)
|
|
62
|
-
|
|
63
|
-
## Why This Exists
|
|
64
|
-
|
|
65
|
-
We learned the [hard way](https://www.reddit.com/r/ClaudeAI/comments/1pgxckk/claude_cli_deleted_my_entire_home_directory_wiped/) that instructions aren't enough to keep AI agents in check.
|
|
66
|
-
After Claude Code silently wiped out hours of progress with a single `rm -rf ~/` or `git checkout --`, it became evident that **soft** rules in an `CLAUDE.md` or `AGENTS.md` file cannot replace **hard** technical constraints.
|
|
67
|
-
The current approach is to use a dedicated hook to programmatically prevent agents from running destructive commands.
|
|
68
|
-
|
|
69
|
-
## Why Use This Instead of Permission Deny Rules?
|
|
70
|
-
|
|
71
|
-
Claude Code's `.claude/settings.json` supports [deny rules](https://code.claude.com/docs/en/iam#tool-specific-permission-rules) with wildcard matching (e.g., `Bash(git reset --hard:*)`). Here's how this plugin differs:
|
|
72
|
-
|
|
73
|
-
### At a Glance
|
|
74
|
-
|
|
75
|
-
| | Permission Deny Rules | CC Safety Net |
|
|
76
|
-
|---|---|---|
|
|
77
|
-
| **Setup** | Manual configuration required | Works out of the box |
|
|
78
|
-
| **Parsing** | Wildcard pattern matching | Semantic command analysis |
|
|
79
|
-
| **Execution order** | Runs second | Runs first (PreToolUse hook) |
|
|
80
|
-
| **Shell wrappers** | Not handled automatically (must match wrapper forms) | Recursively analyzed (up to 10 levels) |
|
|
81
|
-
| **Interpreter one-liners** | Not handled automatically (must match interpreter forms) | Detected and blocked |
|
|
82
|
-
|
|
83
|
-
### Permission Rules Have Known Bypass Vectors
|
|
84
|
-
|
|
85
|
-
Even with wildcard matching, Bash permission patterns are intentionally limited and can be bypassed in many ways:
|
|
86
|
-
|
|
87
|
-
| Bypass Method | Example |
|
|
88
|
-
|---------------|---------|
|
|
89
|
-
| Options before value | `curl -X GET http://evil.com` bypasses `Bash(curl http://evil.com:*)` |
|
|
90
|
-
| Shell variables | `URL=http://evil.com && curl $URL` bypasses URL pattern |
|
|
91
|
-
| Flag reordering | `rm -r -f /` bypasses `Bash(rm -rf:*)` |
|
|
92
|
-
| Extra whitespace | `rm -rf /` (double space) bypasses pattern |
|
|
93
|
-
| Shell wrappers | `sh -c "rm -rf /"` bypasses `Bash(rm:*)` entirely |
|
|
94
|
-
|
|
95
|
-
### CC Safety Net Handles What Patterns Can't
|
|
96
|
-
|
|
97
|
-
| Scenario | Permission Rules | CC Safety Net |
|
|
98
|
-
|----------|------------------|------------|
|
|
99
|
-
| `git checkout -b feature` (safe) | Blocked by `Bash(git checkout:*)` | Allowed |
|
|
100
|
-
| `git checkout -- file` (dangerous) | Blocked by `Bash(git checkout:*)` | Blocked |
|
|
101
|
-
| `rm -rf /tmp/cache` (safe) | Blocked by `Bash(rm -rf:*)` | Allowed |
|
|
102
|
-
| `rm -r -f /` (dangerous) | Allowed (flag order) | Blocked |
|
|
103
|
-
| `bash -c 'git reset --hard'` | Allowed (wrapper) | Blocked |
|
|
104
|
-
| `python -c 'os.system("rm -rf /")'` | Allowed (interpreter) | Blocked |
|
|
105
|
-
|
|
106
|
-
### Defense in Depth
|
|
107
|
-
|
|
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.
|
|
109
|
-
|
|
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.
|
|
111
|
-
|
|
112
|
-
## What About Sandboxing?
|
|
113
|
-
|
|
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:
|
|
115
|
-
|
|
116
|
-
### Different Layers of Protection
|
|
117
|
-
|
|
118
|
-
| | Sandboxing | CC Safety Net |
|
|
119
|
-
|---|---|---|
|
|
120
|
-
| **Enforcement** | OS-level (Seatbelt/bubblewrap) | Application-level (PreToolUse hook) |
|
|
121
|
-
| **Approach** | Containment — restricts filesystem + network access | Command analysis — blocks destructive operations |
|
|
122
|
-
| **Filesystem** | Writes restricted (default: cwd); reads are broad by default | Only destructive operations blocked |
|
|
123
|
-
| **Network** | Domain-based proxy filtering | None |
|
|
124
|
-
| **Git awareness** | None | Explicit rules for destructive git operations |
|
|
125
|
-
| **Bypass resistance** | High — OS enforces boundaries | Lower — analyzes command strings only |
|
|
126
|
-
|
|
127
|
-
### Why Sandboxing Isn't Enough
|
|
128
|
-
|
|
129
|
-
Sandboxing restricts filesystem + network access, but it doesn't understand whether an operation is destructive within those boundaries. These commands are not blocked by the sandbox boundary:
|
|
32
|
+
CC Safety Net — short for **Coding CLI** Safety Net — is a PreToolUse hook that blocks destructive commands and access to secrets like SSH keys and `.env` files, before AI coding agents run them. It parses command **semantics**, so flag reordering, shell wrappers, and interpreter one-liners can't bypass it.
|
|
130
33
|
|
|
131
34
|
> [!NOTE]
|
|
132
|
-
>
|
|
35
|
+
> **[Full documentation →](https://ccsafetynet.com/docs)** — installation, configuration, reference, guides, and the security model live on the docs site. This README is the short version.
|
|
133
36
|
|
|
134
|
-
|
|
135
|
-
|---------|------------|------------|
|
|
136
|
-
| `git reset --hard` | Allowed (within cwd) | **Blocked** |
|
|
137
|
-
| `git checkout -- .` | Allowed (within cwd) | **Blocked** |
|
|
138
|
-
| `git stash clear` | Allowed (within cwd) | **Blocked** |
|
|
139
|
-
| `git push --force` | Allowed (if remote domain is allowed) | **Blocked** |
|
|
140
|
-
| `rm -rf .` | Allowed (within cwd) | **Blocked** |
|
|
37
|
+
## Why this exists
|
|
141
38
|
|
|
142
|
-
|
|
39
|
+
We learned the [hard way](https://www.reddit.com/r/ClaudeAI/comments/1pgxckk/claude_cli_deleted_my_entire_home_directory_wiped/) that instructions aren't enough to keep AI agents in check. After an agent silently wiped hours of progress with a single `rm -rf ~/` or `git checkout --`, it became clear that **soft** rules in a `CLAUDE.md` or `AGENTS.md` file cannot replace **hard** technical constraints. CC Safety Net is that constraint: it observes relevant tool calls and blocks destructive commands and secret access before they reach the shell. See [What Is CC Safety Net](https://ccsafetynet.com/docs/introduction) for the full background.
|
|
143
40
|
|
|
144
|
-
|
|
41
|
+
## What's new in v2.0.0
|
|
145
42
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
- **Prompt injection attacks** — Reduces exfiltration risk by restricting outbound domains (depends on your allowed-domain policy)
|
|
149
|
-
- **Malicious dependencies** — Limits filesystem writes and network access by default (subject to your sandbox configuration)
|
|
150
|
-
- **Untrusted code execution** — OS-level containment is stronger than pattern matching
|
|
151
|
-
- **Network control** — CC Safety Net has no network protection
|
|
152
|
-
|
|
153
|
-
### Recommended: Use Both
|
|
154
|
-
|
|
155
|
-
They protect against different threats:
|
|
156
|
-
|
|
157
|
-
- **Sandboxing** contains blast radius — even if something goes wrong, damage is limited to cwd and approved network domains
|
|
158
|
-
- **CC Safety Net** prevents footguns — catches git-specific mistakes that are technically "safe" from the sandbox's perspective
|
|
159
|
-
|
|
160
|
-
Running both together provides defense-in-depth. Sandboxing handles unknown threats; CC Safety Net handles known destructive patterns that sandboxing permits.
|
|
161
|
-
|
|
162
|
-
## Prerequisites
|
|
163
|
-
|
|
164
|
-
- **Node.js**: Version 18 or higher is required to run this plugin
|
|
165
|
-
|
|
166
|
-
## Quick Start
|
|
167
|
-
|
|
168
|
-
### Codex Installation
|
|
169
|
-
|
|
170
|
-
1. Enable Codex plugin hooks in `~/.codex/config.toml`:
|
|
171
|
-
|
|
172
|
-
```toml
|
|
173
|
-
[features]
|
|
174
|
-
plugin_hooks = true
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
2. Add the marketplace:
|
|
43
|
+
> [!TIP]
|
|
44
|
+
> **Already running v1?** One command upgrades every installed integration to v2: `npx -y cc-safety-net@latest update`. If you defined custom rules under v1, also read [Upgrading from an older version](#upgrading-from-an-older-version).
|
|
178
45
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
46
|
+
- **Rebuilt evaluation engine** — canonical command IR, deeply immutable policy snapshots, and an ordered guard pipeline with intrinsic decision tracing behind `explain`.
|
|
47
|
+
- **Secret protection** — built-in rules block content access to SSH keys, `.env` files, cloud credentials, and coding-CLI credential stores, across shell commands and file tools alike.
|
|
48
|
+
- **Always-on catastrophic protections** — recursive deletion of root or home, Git metadata mutation (`.git` control plane, hooks, worktrees, submodules), and mutation of the user policy file are blocked in every mode, regardless of overrides.
|
|
49
|
+
- **Safety presets** — `standard`/`strict`/`paranoid` levels with per-rule overrides, trusted delete allow-paths, and env vars that can only raise protection.
|
|
50
|
+
- **Policy GUI** — `cc-safety-net gui` serves a local, token-authenticated editor with live preset preview.
|
|
51
|
+
- **Universal installer** — interactive `install`/`uninstall` across all twelve supported agent CLIs, with an `update` command for installed integrations.
|
|
52
|
+
- **Command-decision audit trail** — allowed and blocked command decisions recorded by default to local per-project JSONL with secret redaction, retained for 30 days by default, browsable via `cc-safety-net logs`.
|
|
53
|
+
- **Documented threat model** — the [SECURITY.md](SECURITY.md) mode contract, explicit resource limits, and a residual-risk registry of adjudicated bypass families.
|
|
182
54
|
|
|
183
|
-
|
|
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.
|
|
55
|
+
## Quick start
|
|
188
56
|
|
|
189
|
-
|
|
57
|
+
**Prerequisite:** Node.js 18 or higher.
|
|
190
58
|
|
|
191
|
-
|
|
59
|
+
Run the interactive selector to install CC Safety Net into one or more installed coding CLIs:
|
|
192
60
|
|
|
193
61
|
```bash
|
|
194
|
-
|
|
195
|
-
/plugin install safety-net@cc-marketplace
|
|
196
|
-
/reload-plugins
|
|
62
|
+
npx -y cc-safety-net@latest install
|
|
197
63
|
```
|
|
198
64
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
1. Run `/plugin` → Select `Marketplaces` → Choose `cc-marketplace` → Enable auto-update
|
|
202
|
-
|
|
203
|
-
---
|
|
204
|
-
|
|
205
|
-
### Gemini CLI Installation
|
|
65
|
+
To update every installed integration:
|
|
206
66
|
|
|
207
67
|
```bash
|
|
208
|
-
|
|
68
|
+
npx -y cc-safety-net@latest update
|
|
209
69
|
```
|
|
210
70
|
|
|
211
|
-
|
|
71
|
+
The `@latest` qualifier matters: a bare `cc-safety-net` spec can re-run an older
|
|
72
|
+
cached copy from the npx cache instead of the current release.
|
|
212
73
|
|
|
213
|
-
|
|
74
|
+
To remove integrations interactively:
|
|
214
75
|
|
|
215
76
|
```bash
|
|
216
|
-
|
|
77
|
+
npx -y cc-safety-net uninstall
|
|
217
78
|
```
|
|
218
79
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
### Kimi Code Installation
|
|
222
|
-
|
|
223
|
-
Install CC Safety Net into your Kimi Code config:
|
|
80
|
+
If you use the CLI often, install it globally to get `ccsn`, a shorter alias for the same commands:
|
|
224
81
|
|
|
225
82
|
```bash
|
|
226
|
-
|
|
83
|
+
npm install -g cc-safety-net
|
|
84
|
+
ccsn doctor
|
|
227
85
|
```
|
|
228
86
|
|
|
229
|
-
|
|
87
|
+
CC Safety Net works across twelve coding agent CLIs — **Claude Code, Antigravity CLI, Codex, Gemini CLI, GitHub Copilot CLI, Kimi Code, OpenCode, Pi, Cursor, Amp Code, Hermes Agent, and OpenClaw** — on **Windows, macOS, and Linux** (the Hermes Agent and OpenClaw integrations are macOS and Linux only; see [Hermes Agent and OpenClaw](#hermes-agent-and-openclaw)). Per-agent instructions, the target flags for scripted non-interactive installs, post-install steps, and per-agent caveats are on [Installation](https://ccsafetynet.com/docs/installation); how each integration hooks its agent is on [Integration Architecture](https://ccsafetynet.com/docs/guides/integration-architecture).
|
|
230
88
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
### OpenCode Installation
|
|
235
|
-
|
|
236
|
-
Install CC Safety Net with OpenCode's native plugin command:
|
|
237
|
-
|
|
238
|
-
```bash
|
|
239
|
-
opencode plugin -g cc-safety-net
|
|
240
|
-
```
|
|
89
|
+
## Hermes Agent and OpenClaw
|
|
241
90
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
> anomalyco/opencode#25293 for the current tracking issue.
|
|
245
|
-
>
|
|
246
|
-
> To force OpenCode to reinstall `cc-safety-net`, remove its cached package and
|
|
247
|
-
> install the version you want:
|
|
248
|
-
>
|
|
249
|
-
> ```sh
|
|
250
|
-
> rm -rf ~/.cache/opencode/packages/cc-safety-net@latest
|
|
251
|
-
> opencode plugin -g -f cc-safety-net@latest
|
|
252
|
-
>
|
|
253
|
-
> If you prefer pinning a specific version:
|
|
254
|
-
>
|
|
255
|
-
> rm -rf ~/.cache/opencode/packages/cc-safety-net@latest
|
|
256
|
-
> opencode plugin -g -f cc-safety-net@<version>
|
|
257
|
-
>
|
|
258
|
-
> Restart OpenCode after updating so the plugin is loaded from the refreshed
|
|
259
|
-
> cache.
|
|
260
|
-
|
|
261
|
-
---
|
|
262
|
-
|
|
263
|
-
### Pi Installation
|
|
264
|
-
|
|
265
|
-
Install CC Safety Net with Pi's package installer:
|
|
91
|
+
These two integrations are newer than the docs site, so their setup steps and coverage
|
|
92
|
+
boundaries live here.
|
|
266
93
|
|
|
267
94
|
```bash
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
---
|
|
272
|
-
|
|
273
|
-
## Status Line Integration
|
|
274
|
-
|
|
275
|
-
CC Safety Net can display its status in Claude Code's status line, showing whether protection is active and which modes are enabled.
|
|
276
|
-
|
|
277
|
-
Add the following to your `~/.claude/settings.json`:
|
|
278
|
-
|
|
279
|
-
**Using Bun (recommended):**
|
|
280
|
-
|
|
281
|
-
```json
|
|
282
|
-
{
|
|
283
|
-
"statusLine": {
|
|
284
|
-
"type": "command",
|
|
285
|
-
"command": "bunx cc-safety-net statusline --claude-code"
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
```
|
|
289
|
-
|
|
290
|
-
**Using Claude X:**
|
|
291
|
-
|
|
292
|
-
```json
|
|
293
|
-
{
|
|
294
|
-
"statusLine": {
|
|
295
|
-
"type": "command",
|
|
296
|
-
"command": "BUN_BE_BUN=1 claude x cc-safety-net statusline --claude-code"
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
```
|
|
300
|
-
> [!NOTE]
|
|
301
|
-
> The `claude x` command is only compatible with the native version of Claude Code. If you installed via npm, please use `npx` or `bunx` instead.
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
**Using NPM:**
|
|
306
|
-
|
|
307
|
-
```json
|
|
308
|
-
{
|
|
309
|
-
"statusLine": {
|
|
310
|
-
"type": "command",
|
|
311
|
-
"command": "npx -y cc-safety-net statusline --claude-code"
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
```
|
|
95
|
+
# Hermes Agent — installs a managed Python plugin, then restart Hermes
|
|
96
|
+
npx -y cc-safety-net@latest install --hermes-agent
|
|
97
|
+
npx -y cc-safety-net@latest uninstall --hermes-agent
|
|
315
98
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
```json
|
|
321
|
-
{
|
|
322
|
-
"statusLine": {
|
|
323
|
-
"type": "command",
|
|
324
|
-
"command": "your-existing-command | bunx cc-safety-net statusline --claude-code"
|
|
325
|
-
}
|
|
326
|
-
}
|
|
99
|
+
# OpenClaw — installs a bundled plugin through OpenClaw's own CLI, then restart the Gateway
|
|
100
|
+
npx -y cc-safety-net@latest install --openclaw
|
|
101
|
+
npx -y cc-safety-net@latest uninstall --openclaw
|
|
327
102
|
```
|
|
328
103
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
104
|
+
Run `npx cc-safety-net doctor` after either install: it is the only surface that reports a plugin
|
|
105
|
+
that is present but not enabled, not ours, or out of date. It reads disk and config only and never
|
|
106
|
+
asks a running host whether the plugin loaded, so a stopped OpenClaw Gateway is not reported as a
|
|
107
|
+
failure — the OpenClaw install verifies the load itself.
|
|
332
108
|
|
|
333
|
-
|
|
109
|
+
**Hermes Agent.** Install writes a managed plugin to `$HERMES_HOME/plugins/cc-safety-net/`
|
|
110
|
+
(`~/.hermes` when `HERMES_HOME` is unset) and then
|
|
111
|
+
runs `hermes plugins enable cc-safety-net --no-allow-tool-override`. It is an ordinary Hermes user
|
|
112
|
+
plugin: it runs inside the Hermes process with the trust Hermes grants user plugins, and it is
|
|
113
|
+
inert until Hermes is restarted. On every `pre_tool_call` it shells out to
|
|
114
|
+
`npx -y cc-safety-net hook --hermes-agent` with a 30-second timeout, and blocks the call itself
|
|
115
|
+
whenever that analysis cannot complete — missing `npx`, spawn failure, timeout, unreadable output,
|
|
116
|
+
or a Hermes session directory it cannot read.
|
|
117
|
+
Protected tools are `terminal`, `read_file`, `write_file`, and `patch`; calls to any other Hermes
|
|
118
|
+
tool are not forwarded and get no decision. Uninstall runs `hermes plugins disable cc-safety-net`
|
|
119
|
+
first — Hermes only resolves a plugin that is still on disk — and then removes the managed files,
|
|
120
|
+
so the config entry goes with them; a failing or missing `hermes` is reported as a warning and the
|
|
121
|
+
files are removed anyway.
|
|
334
122
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
123
|
+
**OpenClaw.** Install runs `openclaw plugins install <bundled plugin dir> --force` followed by
|
|
124
|
+
`openclaw plugins enable cc-safety-net`, then verifies the plugin actually loaded. **Restart the
|
|
125
|
+
OpenClaw Gateway afterwards, and if `plugins.allow` is set in `openclaw.json` it must also list
|
|
126
|
+
`cc-safety-net`** — until both are true the plugin never runs and nothing is blocked. The plugin
|
|
127
|
+
registers `before_tool_call` for the canonical `exec` tool only and returns a plain allow or
|
|
128
|
+
block; it never rewrites tool parameters. It resolves the agent workspace as the policy and
|
|
129
|
+
execution directory, and denies a call whose `workdir` resolves outside that workspace or whose
|
|
130
|
+
agent or workspace context cannot be established. Live end-to-end tests (`bun run test:e2e:live`,
|
|
131
|
+
run before a release) drive the real `openclaw` binary against a throwaway state directory: our
|
|
132
|
+
CLI installs the plugin, the host reports it loaded with the hook registered, and a real Gateway
|
|
133
|
+
agent turn puts a real `exec` call through it — a harmless command runs, `git reset --hard` is
|
|
134
|
+
blocked before it can touch the workspace.
|
|
345
135
|
|
|
346
|
-
|
|
136
|
+
**What is not covered.**
|
|
347
137
|
|
|
348
|
-
|
|
138
|
+
- **Hermes bang-shell.** A `!command` you type yourself does not raise `pre_tool_call`; it goes
|
|
139
|
+
straight to Hermes' own command guard. CC Safety Net sees model-generated tool calls only, not
|
|
140
|
+
every subprocess Hermes starts.
|
|
141
|
+
- **Hermes shell hooks fail open.** Hermes' `hooks:` dispatcher allows the tool call when a hook
|
|
142
|
+
cannot start, times out, or returns unparseable output. That is why the shipped integration is
|
|
143
|
+
the Python plugin, which blocks on its own failures, and why `hooks:` is a diagnostic path only.
|
|
144
|
+
One case stays outside our reach either way: if Hermes never loads the plugin, nothing blocks
|
|
145
|
+
and only `doctor` will say so.
|
|
146
|
+
- **OpenClaw execution hosts.** `exec` calls with no `host`, `host: "auto"`, or `host: "gateway"`
|
|
147
|
+
are analysed as local Gateway calls. Explicit `host: "sandbox"` and `host: "node"` are blocked
|
|
148
|
+
as unsupported, because no test proves a correct path mapping for them. When a sandbox runtime
|
|
149
|
+
is active, an `auto` call runs in the sandbox filesystem while paths are still analysed against
|
|
150
|
+
the Gateway workspace — command rules are unaffected, path rules can be evaluated against the
|
|
151
|
+
wrong filesystem. The same applies when a call carries no `host` and your configured
|
|
152
|
+
`tools.exec.host` default is `node` or `sandbox`: the call is still analysed as a local Gateway
|
|
153
|
+
call.
|
|
154
|
+
- **OpenClaw Codex-native relay.** Untested, and therefore unclaimed. The live end-to-end tests
|
|
155
|
+
drive OpenClaw's own agent runtime, so they say nothing about a Codex-native shell, patch, or
|
|
156
|
+
MCP call.
|
|
157
|
+
- **OpenClaw file tools.** `apply_patch` and OpenClaw's read/write/edit tools are not protected;
|
|
158
|
+
only `exec` is.
|
|
159
|
+
- **Windows.** Both integrations assume the POSIX layout. Relocated state is handled the way the
|
|
160
|
+
hosts resolve it — `HERMES_HOME` for Hermes, then `OPENCLAW_STATE_DIR` and the directory of
|
|
161
|
+
`OPENCLAW_CONFIG_PATH` for OpenClaw, falling back to `~/.hermes` and `~/.openclaw`. The Windows
|
|
162
|
+
defaults are not: install and detection target the POSIX path there, so Hermes writes to the
|
|
163
|
+
wrong directory and OpenClaw's own CLI installs correctly while `doctor` misreports the state.
|
|
349
164
|
|
|
350
|
-
|
|
165
|
+
## What it does
|
|
351
166
|
|
|
352
|
-
|
|
167
|
+
| Capability | What it catches |
|
|
168
|
+
|---|---|
|
|
169
|
+
| **Semantic command analysis** | `rm -rf` on destructive targets, `git reset --hard`, `git checkout --`, `git push --force`, `git stash clear`, `git clean -f`, unsafe `find -delete`, `dd`/`mkfs`/`shred` — by intent, not string pattern. `git checkout -b feature` (safe) is allowed while `git checkout -- file` (destructive) is blocked. |
|
|
170
|
+
| **Shell wrapper detection** | Destructive commands hidden in `bash -c`, `sh -c`, and similar wrappers, recursively analyzed up to 10 levels deep. |
|
|
171
|
+
| **Interpreter one-liners** | Destructive code in `python -c`, `node -e`, `ruby -e`, `perl -e` one-liners (e.g. `os.system("rm -rf /")`). |
|
|
172
|
+
| **Fail-closed by default** | Malformed hook input and unparseable commands (in strict mode) block rather than allow. Invalid config never blocks: an unverifiable rule source is dropped and an unreadable `policy.json` falls back to protective defaults, both with a warning on every reporting surface. |
|
|
173
|
+
| **Secret protection** | Content access to SSH keys, `.env` files, `~/.aws`, kube/docker/gcloud configs, and coding-CLI credential stores — enforced on shell commands and file tools (read/edit/write/search) alike. |
|
|
174
|
+
| **Custom rules via rulebooks** | Add your own blocking rules at user or project scope, pinned by SHA-256 digest when fetched from GitHub. |
|
|
175
|
+
| **Audit logging** | Allowed and blocked command decisions written to local per-project JSONL with secrets auto-redacted, retained for 30 days by default. Browse them with `npx cc-safety-net logs`, or triage them in the **Activity** view of `npx cc-safety-net gui`. |
|
|
176
|
+
|
|
177
|
+
Full rule catalogs: [Blocked Commands](https://ccsafetynet.com/docs/reference/blocked-commands) · [Allowed Commands](https://ccsafetynet.com/docs/reference/allowed-commands) · [Secret Protection](https://ccsafetynet.com/docs/reference/secret-protection).
|
|
178
|
+
|
|
179
|
+
## Why not just use a sandbox?
|
|
180
|
+
|
|
181
|
+
A workspace-writable sandbox still permits `git reset --hard`, `git push --force`, and `rm -rf .` *inside* the project directory, because the OS only sees writes to an allowed path. Sandboxing contains blast radius; CC Safety Net catches the destructive operations sandboxing permits — use both for defense-in-depth. See [vs Sandboxing](https://ccsafetynet.com/docs/guides/vs-sandboxing).
|
|
182
|
+
|
|
183
|
+
## Safety presets
|
|
184
|
+
|
|
185
|
+
Set a session safety preset with `CC_SAFETY_NET_LEVEL=standard|strict|paranoid`:
|
|
186
|
+
|
|
187
|
+
| Preset | Effect |
|
|
188
|
+
|---|---|
|
|
189
|
+
| Standard | Blocks recognizable destructive Git and filesystem commands. Allows metadata-only checks of built-in sensitive paths while continuing to block content access. Recommended for normal coding. |
|
|
190
|
+
| Strict | Standard, plus blocks dynamic or unparseable commands the analyzer cannot verify safely and metadata-only discovery of built-in sensitive paths. Occasional false positives on advanced shell. |
|
|
191
|
+
| Paranoid | Strict, plus blocks `rm -rf` inside your project and interpreter one-liners. Expect friction; for untrusted agents or high-stakes repos. |
|
|
192
|
+
|
|
193
|
+
Presets supply inherited defaults; `policy.json` stores only your explicit deviations — per-rule overrides, allow paths, deny paths, worktree mode, and audit retention. Environment variables can only raise protection, never lower it. The full contract is on [Modes](https://ccsafetynet.com/docs/configuration/modes), [Policy](https://ccsafetynet.com/docs/configuration/policy), and [Environment](https://ccsafetynet.com/docs/configuration/environment), or edit everything visually with the [local GUI](https://ccsafetynet.com/docs/guides/dashboard).
|
|
194
|
+
|
|
195
|
+
## Diagnostics and tracing
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
# Summarize what is being enforced right now
|
|
199
|
+
npx cc-safety-net status
|
|
200
|
+
# Verify your installation and run a self-test
|
|
353
201
|
npx cc-safety-net doctor
|
|
354
|
-
#
|
|
355
|
-
bunx cc-safety-net doctor
|
|
356
|
-
```
|
|
357
|
-
|
|
358
|
-
The doctor command checks:
|
|
359
|
-
|
|
360
|
-
| Check | Description |
|
|
361
|
-
|-------|-------------|
|
|
362
|
-
| Hook Integration | Verifies the plugin is properly configured for each supported platform |
|
|
363
|
-
| Self-Test | Runs sample commands to confirm blocking works correctly |
|
|
364
|
-
| Configuration | Validates custom rules in user and project configs |
|
|
365
|
-
| Environment | Shows status of mode flags (`CC_SAFETY_NET_STRICT`, `CC_SAFETY_NET_PARANOID`, etc.; legacy `SAFETY_NET_*` also listed when set) |
|
|
366
|
-
| Recent Activity | Summarizes blocked commands from the last 7 days |
|
|
367
|
-
| System Info | Displays versions of all relevant tools |
|
|
368
|
-
| Update Check | Checks if a newer version is available |
|
|
369
|
-
|
|
370
|
-
### Options
|
|
371
|
-
|
|
372
|
-
| Flag | Description |
|
|
373
|
-
|------|-------------|
|
|
374
|
-
| `--json` | Output in JSON format (useful for sharing in bug reports) |
|
|
375
|
-
| `--skip-update-check` | Skip the npm version check |
|
|
376
|
-
|
|
377
|
-
## Explain (Debug Analysis)
|
|
378
|
-
|
|
379
|
-
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.
|
|
380
|
-
|
|
381
|
-
```bash
|
|
202
|
+
# Trace how a command is analyzed step-by-step
|
|
382
203
|
npx cc-safety-net explain "git reset --hard"
|
|
383
|
-
#
|
|
384
|
-
|
|
204
|
+
# Browse recorded denials from the audit trail (add --all to include allowed commands)
|
|
205
|
+
npx cc-safety-net logs
|
|
206
|
+
# Review what was blocked and edit your policy in a local web GUI
|
|
207
|
+
npx cc-safety-net gui
|
|
385
208
|
```
|
|
386
209
|
|
|
387
|
-
|
|
210
|
+
`doctor`, `explain`, and `logs` support `--json` for machine-readable output. The audit trail records command decisions only — never command output or prompts — and stays on your machine. Invalid configuration never blocks your agent: unverifiable rule sources are dropped and every degraded state is reported on the next block message, `doctor`, the status line, and the GUI banner.
|
|
388
211
|
|
|
389
|
-
|
|
390
|
-
|------|-------------|
|
|
391
|
-
| `--json` | Output analysis as JSON |
|
|
392
|
-
| `--cwd <path>` | Use custom working directory for analysis |
|
|
212
|
+
Details: [CLI Commands](https://ccsafetynet.com/docs/reference/cli-commands) · [Explain Trace](https://ccsafetynet.com/docs/reference/explain-trace) · [Audit Log](https://ccsafetynet.com/docs/reference/audit-log) · [Dashboard](https://ccsafetynet.com/docs/guides/dashboard) · [Configuration Recovery](https://ccsafetynet.com/docs/configuration/recovery).
|
|
393
213
|
|
|
394
|
-
|
|
214
|
+
## Limitations
|
|
395
215
|
|
|
396
|
-
|
|
397
|
-
npx cc-safety-net explain "rm -rf /"
|
|
398
|
-
npx cc-safety-net explain --json "git checkout -- file.txt"
|
|
399
|
-
npx cc-safety-net explain --cwd /tmp "git status"
|
|
400
|
-
```
|
|
216
|
+
CC Safety Net denies a tool call before it runs; it does not enforce filesystem permissions, inspect network egress, or contain a process. Two v2 bounds worth knowing up front: the policy and sensitive-path command extractors remain primarily POSIX-oriented, so native PowerShell path expressions such as `Get-Content $HOME\.ssh\id_rsa` can evade static path extraction; and policy-file protection is a best-effort exact-path guard, not command emulation. Use operating-system permissions, a sandbox, or equivalent runtime enforcement when complete protection is required.
|
|
401
217
|
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
| Command Pattern | Why It's Dangerous |
|
|
405
|
-
|-----------------|-------------------|
|
|
406
|
-
| git checkout -- files | Discards uncommitted changes permanently |
|
|
407
|
-
| git checkout \<ref\> -- \<path\> | Overwrites working tree with ref version |
|
|
408
|
-
| git checkout \<ref\> \<path\> | May overwrite working tree when Git disambiguates ref vs pathspec |
|
|
409
|
-
| git restore files | Discards uncommitted changes |
|
|
410
|
-
| git restore --worktree | Explicitly discards working tree changes |
|
|
411
|
-
| git switch --discard-changes | Discards uncommitted changes when switching branches |
|
|
412
|
-
| git switch --force / -f | Discards uncommitted changes (force switch) |
|
|
413
|
-
| git reset --hard | Destroys all uncommitted changes |
|
|
414
|
-
| git reset --merge | Can lose uncommitted changes |
|
|
415
|
-
| git clean -f | Removes untracked files permanently |
|
|
416
|
-
| git push --force / -f | Destroys remote history |
|
|
417
|
-
| git branch -D | Force-deletes branch without merge check |
|
|
418
|
-
| git stash drop | Permanently deletes stashed changes |
|
|
419
|
-
| git stash clear | Deletes ALL stashed changes |
|
|
420
|
-
| git worktree remove --force | Force-deletes worktree without checking for changes |
|
|
421
|
-
| rm -rf (destructive targets) | Recursive file deletion of root, home, parent, absolute, or non-temp paths outside cwd |
|
|
422
|
-
| rm -rf / or ~ or $HOME | Root/home deletion is extremely dangerous |
|
|
423
|
-
| find ... -delete | Permanently removes files matching criteria |
|
|
424
|
-
| xargs rm -rf | Dynamic input makes targets unpredictable |
|
|
425
|
-
| xargs \<shell\> -c | Can execute arbitrary commands |
|
|
426
|
-
| parallel rm -rf | Dynamic input makes targets unpredictable |
|
|
427
|
-
| parallel \<shell\> -c | Can execute arbitrary commands |
|
|
428
|
-
| dd writing to block devices | Can overwrite disks or partitions |
|
|
429
|
-
| mkfs on block devices | Formats disks or partitions |
|
|
430
|
-
| shred | Permanently destroys file contents |
|
|
431
|
-
|
|
432
|
-
## Commands Allowed
|
|
433
|
-
|
|
434
|
-
| Command Pattern | Why It's Safe |
|
|
435
|
-
|-----------------|--------------|
|
|
436
|
-
| git checkout -b branch | Creates new branch |
|
|
437
|
-
| git checkout --orphan | Creates orphan branch |
|
|
438
|
-
| git restore --staged | Only unstages, doesn't discard |
|
|
439
|
-
| git restore --help/--version | Help/version output |
|
|
440
|
-
| git branch -d | Safe delete with merge check |
|
|
441
|
-
| git clean -n / --dry-run | Preview only |
|
|
442
|
-
| git push --force-with-lease | Safe force push |
|
|
443
|
-
| rm -rf /tmp/... | Temp directories are ephemeral |
|
|
444
|
-
| rm -rf /var/tmp/... | System temp directory |
|
|
445
|
-
| rm -rf $TMPDIR/... | User's temp directory |
|
|
446
|
-
| rm -rf ./... (within cwd) | Limited to current working directory |
|
|
447
|
-
| git restore / checkout -- / reset --hard / clean -f (in linked worktree) | Relaxed only when `CC_SAFETY_NET_WORKTREE=1` and cwd is a linked worktree |
|
|
448
|
-
|
|
449
|
-
## What Happens When Blocked
|
|
450
|
-
|
|
451
|
-
When a destructive command is detected, the plugin blocks the tool execution and provides a reason.
|
|
452
|
-
|
|
453
|
-
Example output:
|
|
454
|
-
```text
|
|
455
|
-
BLOCKED by CC Safety Net
|
|
456
|
-
|
|
457
|
-
Reason: git checkout -- discards uncommitted changes permanently. Use 'git stash' first.
|
|
458
|
-
|
|
459
|
-
Command: git checkout -- src/main.py
|
|
460
|
-
|
|
461
|
-
If this operation is truly needed, ask the user for explicit permission and have them run the command manually.
|
|
462
|
-
```
|
|
218
|
+
The full residual-risk registry lives in [SECURITY.md](SECURITY.md); the practical consequences are on [Known Limitations](https://ccsafetynet.com/docs/guides/known-limitations).
|
|
463
219
|
|
|
464
|
-
##
|
|
220
|
+
## Upgrading from an older version
|
|
465
221
|
|
|
466
|
-
|
|
222
|
+
Upgrade every installed integration to the current release with one command:
|
|
467
223
|
|
|
468
224
|
```bash
|
|
469
|
-
|
|
470
|
-
git checkout -- README.md
|
|
471
|
-
|
|
472
|
-
# This should be allowed
|
|
473
|
-
git checkout -b test-branch
|
|
225
|
+
npx -y cc-safety-net@latest update
|
|
474
226
|
```
|
|
475
227
|
|
|
476
|
-
## Breaking Change: Custom Rules Migration
|
|
477
|
-
|
|
478
228
|
> [!WARNING]
|
|
479
|
-
>
|
|
229
|
+
> If you previously defined custom rules in a legacy inline config (`.safety-net.json` or `~/.cc-safety-net/config.json`), those files are **no longer loaded at runtime** and **their rules are not enforcing anything**. Nothing is blocked, so you will not notice this from normal use — the commands those rules used to block now run. Run `npx -y cc-safety-net rule migrate` to convert them to the rulebook layout, then `npx -y cc-safety-net doctor` to confirm the runtime is `ready`. See the [migration guide](https://ccsafetynet.com/docs/configuration/custom-rules#migration-from-legacy-config).
|
|
480
230
|
|
|
481
|
-
|
|
231
|
+
## Full documentation
|
|
482
232
|
|
|
483
|
-
|
|
484
|
-
- **Not affected**: users with no custom rules. All built-in destructive-command protections are unchanged and continue to work out of the box.
|
|
233
|
+
All details live on the docs site at **[ccsafetynet.com/docs](https://ccsafetynet.com/docs)**:
|
|
485
234
|
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
|
489
|
-
|
|
490
|
-
|
|
|
491
|
-
|
|
|
492
|
-
|
|
|
493
|
-
|
|
494
|
-
"Fail closed" means commands stay blocked until the legacy rules are migrated to the new layout.
|
|
495
|
-
|
|
496
|
-
### How to Migrate
|
|
497
|
-
|
|
498
|
-
```bash
|
|
499
|
-
# Convert legacy inline rules into the new rulebook layout
|
|
500
|
-
npx -y cc-safety-net rule migrate
|
|
501
|
-
|
|
502
|
-
# Optionally delete verified legacy files after migration
|
|
503
|
-
npx -y cc-safety-net rule migrate --cleanup
|
|
504
|
-
|
|
505
|
-
# Validate the migrated rules
|
|
506
|
-
npx -y cc-safety-net rule verify
|
|
507
|
-
npx -y cc-safety-net rule test
|
|
508
|
-
```
|
|
509
|
-
|
|
510
|
-
### Before / After
|
|
511
|
-
|
|
512
|
-
**Before** — a single inline config with rules embedded:
|
|
513
|
-
|
|
514
|
-
```text
|
|
515
|
-
.safety-net.json # project rules (inline)
|
|
516
|
-
~/.cc-safety-net/config.json # user rules (inline)
|
|
517
|
-
```
|
|
518
|
-
|
|
519
|
-
**After** — `rule migrate` creates a rulebook-based layout automatically:
|
|
520
|
-
|
|
521
|
-
```text
|
|
522
|
-
.cc-safety-net/rules/rule.json # project rulebook sources + overrides
|
|
523
|
-
.cc-safety-net/rules/project-rules/rulebook.json # migrated project rules
|
|
524
|
-
~/.cc-safety-net/rules/rule.json # user rulebook sources + overrides
|
|
525
|
-
~/.cc-safety-net/rules/user-rules/rulebook.json # migrated user rules
|
|
526
|
-
```
|
|
527
|
-
|
|
528
|
-
See [Custom Rules](#custom-rules) for the full authoring guide and [Error Handling](#error-handling) for fail-closed details.
|
|
529
|
-
|
|
530
|
-
## Custom Rules
|
|
531
|
-
|
|
532
|
-
Beyond the built-in protections, you can define your own blocking rules to enforce team conventions or project-specific safety policies.
|
|
533
|
-
|
|
534
|
-
> [!TIP]
|
|
535
|
-
> The best way to create custom rules is to use the `/cc-safety-net` skill to create custom rules interactively with natural language.
|
|
536
|
-
|
|
537
|
-
### Examples
|
|
538
|
-
|
|
539
|
-
```
|
|
540
|
-
/cc-safety-net read my package.json and suggest blocking rules
|
|
541
|
-
/cc-safety-net set up rules to block all terraform destroy commands
|
|
542
|
-
/cc-safety-net verify my rules and fix any errors
|
|
543
|
-
```
|
|
544
|
-
|
|
545
|
-
> [!NOTE]
|
|
546
|
-
> If your agent does not support skills, prompt it with:
|
|
547
|
-
> ```
|
|
548
|
-
> run npx -y cc-safety-net rule doc and help me set up custom rules
|
|
549
|
-
> ```
|
|
550
|
-
|
|
551
|
-
### Create Rules Manually
|
|
552
|
-
|
|
553
|
-
Create a starter project rule config and rulebook:
|
|
554
|
-
|
|
555
|
-
```bash
|
|
556
|
-
npx -y cc-safety-net rule init
|
|
557
|
-
```
|
|
558
|
-
|
|
559
|
-
This creates `.cc-safety-net/rules/rule.json`:
|
|
560
|
-
|
|
561
|
-
```json
|
|
562
|
-
{
|
|
563
|
-
"version": 1,
|
|
564
|
-
"rules": ["project-rules"],
|
|
565
|
-
"overrides": {}
|
|
566
|
-
}
|
|
567
|
-
```
|
|
568
|
-
|
|
569
|
-
Rule definitions live in `.cc-safety-net/rules/project-rules/rulebook.json`:
|
|
570
|
-
|
|
571
|
-
```json
|
|
572
|
-
{
|
|
573
|
-
"rulebook_version": 1,
|
|
574
|
-
"name": "project-rules",
|
|
575
|
-
"version": "1.0.0",
|
|
576
|
-
"description": "Project-specific CC Safety Net rules.",
|
|
577
|
-
"author": "project",
|
|
578
|
-
"allowed_commands": ["git"],
|
|
579
|
-
"rules": [
|
|
580
|
-
{
|
|
581
|
-
"name": "block-git-add-all",
|
|
582
|
-
"command": "git",
|
|
583
|
-
"subcommand": "add",
|
|
584
|
-
"block_args": ["-A", "--all", "."],
|
|
585
|
-
"reason": "Use 'git add <specific-files>' instead of blanket add."
|
|
586
|
-
}
|
|
587
|
-
],
|
|
588
|
-
"tests": [
|
|
589
|
-
{
|
|
590
|
-
"command": "git add -A",
|
|
591
|
-
"expect": "blocked",
|
|
592
|
-
"rule": "block-git-add-all"
|
|
593
|
-
},
|
|
594
|
-
{
|
|
595
|
-
"command": "git add README.md",
|
|
596
|
-
"expect": "allowed"
|
|
597
|
-
}
|
|
598
|
-
]
|
|
599
|
-
}
|
|
600
|
-
```
|
|
601
|
-
|
|
602
|
-
After editing rulebooks, run:
|
|
603
|
-
|
|
604
|
-
```bash
|
|
605
|
-
npx -y cc-safety-net rule sync
|
|
606
|
-
npx -y cc-safety-net rule verify
|
|
607
|
-
npx -y cc-safety-net rule test
|
|
608
|
-
```
|
|
609
|
-
|
|
610
|
-
Now `git add -A`, `git add --all`, and `git add .` will be blocked with your custom message.
|
|
611
|
-
|
|
612
|
-
### Config File Location
|
|
613
|
-
|
|
614
|
-
Config files are loaded from two scopes and merged:
|
|
615
|
-
|
|
616
|
-
1. **User scope**: `~/.cc-safety-net/rules/rule.json` (use `rule init --global`)
|
|
617
|
-
2. **Project scope**: `.cc-safety-net/rules/rule.json` in the current working directory
|
|
618
|
-
|
|
619
|
-
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.
|
|
620
|
-
|
|
621
|
-
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.
|
|
622
|
-
|
|
623
|
-
**Merging behavior**:
|
|
624
|
-
- Rulebooks from both scopes are combined
|
|
625
|
-
- Duplicate active rulebook names are invalid
|
|
626
|
-
- Project overrides win over user overrides for the same `<rulebook-name>/<rule-name>` key
|
|
627
|
-
|
|
628
|
-
This allows you to define personal defaults in user scope while letting projects disable or replace reasons for specific rules.
|
|
629
|
-
|
|
630
|
-
If no config file is found in either location, only built-in rules apply.
|
|
631
|
-
|
|
632
|
-
### Config Schema
|
|
633
|
-
|
|
634
|
-
| Field | Type | Required | Description |
|
|
635
|
-
|-------|------|----------|-------------|
|
|
636
|
-
| `version` | integer | Yes | Schema version (must be `1`) |
|
|
637
|
-
| `rules` | array | No | List of rulebook source strings (defaults to empty) |
|
|
638
|
-
| `overrides` | object | No | Rule overrides keyed by `<rulebook-name>/<rule-name>` |
|
|
639
|
-
|
|
640
|
-
Override values are either `"off"` to disable a rule or `{ "reason": "..." }` to replace the rule reason.
|
|
641
|
-
|
|
642
|
-
### Rulebook Schema
|
|
643
|
-
|
|
644
|
-
| Field | Type | Required | Description |
|
|
645
|
-
|-------|------|----------|-------------|
|
|
646
|
-
| `rulebook_version` | integer | Yes | Rulebook schema version (must be `1`) |
|
|
647
|
-
| `name` | string | Yes | Rulebook name; must match the local directory name or GitHub source name |
|
|
648
|
-
| `version` | string | Yes | Rulebook version |
|
|
649
|
-
| `description` | string | No | Human-readable description |
|
|
650
|
-
| `author` | string | No | Rulebook author |
|
|
651
|
-
| `allowed_commands` | array | Yes | Commands this rulebook is allowed to define rules for |
|
|
652
|
-
| `rules` | array | Yes | Custom blocking rules |
|
|
653
|
-
| `tests` | array | Yes | Rulebook fixtures |
|
|
654
|
-
|
|
655
|
-
### Rule Schema
|
|
656
|
-
|
|
657
|
-
| Field | Type | Required | Description |
|
|
658
|
-
|-------|------|----------|-------------|
|
|
659
|
-
| `name` | string | Yes | Unique within the rulebook (letters, numbers, hyphens, underscores; max 64 chars) |
|
|
660
|
-
| `command` | string | Yes | Base command to match; must be listed in `allowed_commands` |
|
|
661
|
-
| `subcommand` | string | No | Subcommand to match (e.g., `add`, `install`). If omitted, matches any. |
|
|
662
|
-
| `block_args` | array | Yes | Arguments that trigger the block (at least one required) |
|
|
663
|
-
| `reason` | string | Yes | Message shown when blocked (max 256 chars) |
|
|
664
|
-
|
|
665
|
-
### Fixture Schema
|
|
666
|
-
|
|
667
|
-
| Field | Type | Required | Description |
|
|
668
|
-
|-------|------|----------|-------------|
|
|
669
|
-
| `command` | string | Yes | Shell command fixture |
|
|
670
|
-
| `expect` | string | Yes | Either `blocked` or `allowed` |
|
|
671
|
-
| `rule` | string | For blocked fixtures | Rule expected to block the command |
|
|
672
|
-
|
|
673
|
-
Every rule must have at least one blocked fixture. Add allowed fixtures for close-but-safe commands.
|
|
674
|
-
|
|
675
|
-
### Matching Behavior
|
|
676
|
-
|
|
677
|
-
- **Commands** are normalized to basename (`/usr/bin/git` → `git`)
|
|
678
|
-
- **Subcommand** is the first non-option argument after the command
|
|
679
|
-
- **Arguments** are matched literally (no regex, no glob), with short option expansion
|
|
680
|
-
- A command is blocked if **any** argument in `block_args` is present
|
|
681
|
-
- **Short options** are expanded: `-Ap` matches `-A` (bundled flags are unbundled)
|
|
682
|
-
- **Long options** use exact match: `--all-files` does NOT match `--all`
|
|
683
|
-
- Custom rules only add restrictions—they cannot bypass built-in protections
|
|
684
|
-
|
|
685
|
-
#### Known Limitations
|
|
686
|
-
|
|
687
|
-
- **Short option expansion**: `-Cfoo` is treated as `-C -f -o -o`, not `-C foo`. Blocking `-f` may false-positive on attached option values.
|
|
688
|
-
|
|
689
|
-
### Rule Examples
|
|
690
|
-
|
|
691
|
-
#### Block global npm installs
|
|
692
|
-
|
|
693
|
-
`.cc-safety-net/rules/rule.json`:
|
|
694
|
-
|
|
695
|
-
```json
|
|
696
|
-
{
|
|
697
|
-
"version": 1,
|
|
698
|
-
"rules": ["project-rules"],
|
|
699
|
-
"overrides": {}
|
|
700
|
-
}
|
|
701
|
-
```
|
|
702
|
-
|
|
703
|
-
`.cc-safety-net/rules/project-rules/rulebook.json`:
|
|
704
|
-
|
|
705
|
-
```json
|
|
706
|
-
{
|
|
707
|
-
"rulebook_version": 1,
|
|
708
|
-
"name": "project-rules",
|
|
709
|
-
"version": "1.0.0",
|
|
710
|
-
"allowed_commands": ["npm"],
|
|
711
|
-
"rules": [
|
|
712
|
-
{
|
|
713
|
-
"name": "block-npm-global",
|
|
714
|
-
"command": "npm",
|
|
715
|
-
"subcommand": "install",
|
|
716
|
-
"block_args": ["-g", "--global"],
|
|
717
|
-
"reason": "Global npm installs can cause version conflicts. Use npx or local install."
|
|
718
|
-
}
|
|
719
|
-
],
|
|
720
|
-
"tests": [
|
|
721
|
-
{
|
|
722
|
-
"command": "npm install -g typescript",
|
|
723
|
-
"expect": "blocked",
|
|
724
|
-
"rule": "block-npm-global"
|
|
725
|
-
},
|
|
726
|
-
{
|
|
727
|
-
"command": "npm install typescript",
|
|
728
|
-
"expect": "allowed"
|
|
729
|
-
}
|
|
730
|
-
]
|
|
731
|
-
}
|
|
732
|
-
```
|
|
733
|
-
|
|
734
|
-
#### Block dangerous docker commands
|
|
735
|
-
|
|
736
|
-
```json
|
|
737
|
-
{
|
|
738
|
-
"rulebook_version": 1,
|
|
739
|
-
"name": "project-rules",
|
|
740
|
-
"version": "1.0.0",
|
|
741
|
-
"allowed_commands": ["docker"],
|
|
742
|
-
"rules": [
|
|
743
|
-
{
|
|
744
|
-
"name": "block-docker-system-prune",
|
|
745
|
-
"command": "docker",
|
|
746
|
-
"subcommand": "system",
|
|
747
|
-
"block_args": ["prune"],
|
|
748
|
-
"reason": "docker system prune removes all unused data. Use targeted cleanup instead."
|
|
749
|
-
}
|
|
750
|
-
],
|
|
751
|
-
"tests": [
|
|
752
|
-
{
|
|
753
|
-
"command": "docker system prune",
|
|
754
|
-
"expect": "blocked",
|
|
755
|
-
"rule": "block-docker-system-prune"
|
|
756
|
-
},
|
|
757
|
-
{
|
|
758
|
-
"command": "docker ps",
|
|
759
|
-
"expect": "allowed"
|
|
760
|
-
}
|
|
761
|
-
]
|
|
762
|
-
}
|
|
763
|
-
```
|
|
764
|
-
|
|
765
|
-
#### Multiple rules
|
|
766
|
-
|
|
767
|
-
```json
|
|
768
|
-
{
|
|
769
|
-
"rulebook_version": 1,
|
|
770
|
-
"name": "project-rules",
|
|
771
|
-
"version": "1.0.0",
|
|
772
|
-
"allowed_commands": ["git", "npm"],
|
|
773
|
-
"rules": [
|
|
774
|
-
{
|
|
775
|
-
"name": "block-git-add-all",
|
|
776
|
-
"command": "git",
|
|
777
|
-
"subcommand": "add",
|
|
778
|
-
"block_args": ["-A", "--all", ".", "-u", "--update"],
|
|
779
|
-
"reason": "Use 'git add <specific-files>' instead of blanket add."
|
|
780
|
-
},
|
|
781
|
-
{
|
|
782
|
-
"name": "block-npm-global",
|
|
783
|
-
"command": "npm",
|
|
784
|
-
"subcommand": "install",
|
|
785
|
-
"block_args": ["-g", "--global"],
|
|
786
|
-
"reason": "Use npx or local install instead of global."
|
|
787
|
-
}
|
|
788
|
-
],
|
|
789
|
-
"tests": [
|
|
790
|
-
{
|
|
791
|
-
"command": "git add -A",
|
|
792
|
-
"expect": "blocked",
|
|
793
|
-
"rule": "block-git-add-all"
|
|
794
|
-
},
|
|
795
|
-
{
|
|
796
|
-
"command": "npm install -g typescript",
|
|
797
|
-
"expect": "blocked",
|
|
798
|
-
"rule": "block-npm-global"
|
|
799
|
-
}
|
|
800
|
-
]
|
|
801
|
-
}
|
|
802
|
-
```
|
|
803
|
-
|
|
804
|
-
### Error Handling
|
|
805
|
-
|
|
806
|
-
Rulebook-backed custom rules fail closed when configured rulebooks cannot be loaded safely:
|
|
807
|
-
|
|
808
|
-
| Scenario | Behavior |
|
|
809
|
-
|----------|----------|
|
|
810
|
-
| Config file not found | Silent — use built-in rules only |
|
|
811
|
-
| Invalid rule config | Fail closed until fixed |
|
|
812
|
-
| Empty legacy config | Silent — use built-in rules only |
|
|
813
|
-
| Legacy config with rules and no migrated rule config | Fail closed until `rule migrate` creates the new rule config |
|
|
814
|
-
| Invalid legacy config | Fail closed until fixed or removed |
|
|
815
|
-
| Missing or stale lock/cache | Fail closed until `rule sync` repairs it |
|
|
816
|
-
| Invalid local rulebook | Fail closed until the rulebook is fixed and synced |
|
|
817
|
-
| Invalid GitHub rulebook | Fail closed until the source is fixed or removed |
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
> [!IMPORTANT]
|
|
821
|
-
> 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`.
|
|
822
|
-
|
|
823
|
-
### Block Output Format
|
|
824
|
-
|
|
825
|
-
When a custom rule blocks a command, the output includes the rule name:
|
|
826
|
-
|
|
827
|
-
```text
|
|
828
|
-
BLOCKED by CC Safety Net
|
|
829
|
-
|
|
830
|
-
Reason: [block-git-add-all] Use 'git add <specific-files>' instead of blanket add.
|
|
831
|
-
|
|
832
|
-
Command: git add -A
|
|
833
|
-
```
|
|
834
|
-
|
|
835
|
-
## Advanced Features
|
|
836
|
-
|
|
837
|
-
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.
|
|
838
|
-
|
|
839
|
-
### Strict Mode
|
|
840
|
-
|
|
841
|
-
Malformed or missing hook input JSON always fails closed. By default, ambiguous shell
|
|
842
|
-
command parsing is allowed through. Enable strict mode to fail closed when a shell
|
|
843
|
-
command cannot be safely analyzed (e.g., unterminated quotes or malformed `bash -c`
|
|
844
|
-
wrappers):
|
|
845
|
-
|
|
846
|
-
```bash
|
|
847
|
-
export CC_SAFETY_NET_STRICT=1
|
|
848
|
-
```
|
|
849
|
-
|
|
850
|
-
### Paranoid Mode
|
|
851
|
-
|
|
852
|
-
Paranoid mode enables stricter safety checks that may be disruptive to normal workflows.
|
|
853
|
-
You can enable it globally or via focused toggles:
|
|
854
|
-
|
|
855
|
-
```bash
|
|
856
|
-
# Enable all paranoid checks
|
|
857
|
-
export CC_SAFETY_NET_PARANOID=1
|
|
858
|
-
|
|
859
|
-
# Or enable specific paranoid checks
|
|
860
|
-
export CC_SAFETY_NET_PARANOID_RM=1
|
|
861
|
-
export CC_SAFETY_NET_PARANOID_INTERPRETERS=1
|
|
862
|
-
```
|
|
863
|
-
|
|
864
|
-
Paranoid behavior:
|
|
865
|
-
|
|
866
|
-
- **rm**: blocks non-temp `rm -rf` even within the current working directory.
|
|
867
|
-
- **interpreters**: blocks interpreter one-liners like `python -c`, `node -e`, `ruby -e`,
|
|
868
|
-
and `perl -e` (these can hide destructive commands).
|
|
869
|
-
|
|
870
|
-
### Worktree Mode
|
|
871
|
-
|
|
872
|
-
Linked git worktrees are designed as disposable, isolated workspaces — discarding
|
|
873
|
-
changes inside one doesn't risk the main working tree. Worktree mode relaxes
|
|
874
|
-
local-discard rules when (and only when) the command is proven to run inside a
|
|
875
|
-
linked worktree:
|
|
876
|
-
|
|
877
|
-
```bash
|
|
878
|
-
export CC_SAFETY_NET_WORKTREE=1
|
|
879
|
-
```
|
|
880
|
-
|
|
881
|
-
When enabled, these commands are allowed inside a linked worktree:
|
|
882
|
-
|
|
883
|
-
- `git restore <file>` and `git restore --worktree <file>`
|
|
884
|
-
- `git checkout -- <file>`, `git checkout <ref> -- <file>`, `git checkout --force`,
|
|
885
|
-
and ambiguous multi-positional checkout forms
|
|
886
|
-
- `git switch --discard-changes` and `git switch -f / --force`
|
|
887
|
-
- `git reset --hard` and `git reset --merge`
|
|
888
|
-
- `git clean -f` (and combined short flags like `-fd`)
|
|
889
|
-
|
|
890
|
-
These remain blocked even in linked worktrees because they reach beyond the
|
|
891
|
-
local working tree:
|
|
892
|
-
|
|
893
|
-
- `git push --force` (affects remote)
|
|
894
|
-
- `git branch -D` (affects shared refs)
|
|
895
|
-
- `git stash drop` / `git stash clear` (stash is shared across worktrees)
|
|
896
|
-
- `git worktree remove --force` (could delete another worktree)
|
|
897
|
-
|
|
898
|
-
Detection is fail-closed and mostly filesystem-based:
|
|
899
|
-
|
|
900
|
-
- A linked worktree is identified by a `.git` *file* containing `gitdir:` whose
|
|
901
|
-
resolved git directory contains a `commondir` file. Main worktrees and
|
|
902
|
-
submodules don't satisfy this and are not relaxed.
|
|
903
|
-
- The cwd walk uses `realpath` so symlinked paths resolve correctly.
|
|
904
|
-
- `git -C <path>` (including chained `-C` and attached `-Cpath`) is honored;
|
|
905
|
-
unresolved targets keep the command blocked.
|
|
906
|
-
- Relaxation is disabled if cwd becomes unknown (e.g., after `cd`/`pushd`),
|
|
907
|
-
if `--git-dir` / `--work-tree` is passed, or if `GIT_DIR` / `GIT_WORK_TREE`
|
|
908
|
-
/ `GIT_COMMON_DIR` is set in the environment.
|
|
909
|
-
- Git may be invoked from a trusted system path to inspect effective config that
|
|
910
|
-
could make submodule operations recursive.
|
|
911
|
-
|
|
912
|
-
### Shell Wrapper Detection
|
|
913
|
-
|
|
914
|
-
The guard recursively analyzes commands wrapped in shells:
|
|
915
|
-
|
|
916
|
-
```bash
|
|
917
|
-
bash -c 'git reset --hard' # Blocked
|
|
918
|
-
sh -lc 'rm -rf /' # Blocked
|
|
919
|
-
bash -c 'git stash drop' # Blocked
|
|
920
|
-
```
|
|
921
|
-
|
|
922
|
-
### Interpreter One-Liner Detection
|
|
923
|
-
|
|
924
|
-
Detects destructive commands hidden in Python/Node/Ruby/Perl one-liners:
|
|
925
|
-
|
|
926
|
-
```bash
|
|
927
|
-
python -c 'import os; os.system("rm -rf /")' # Blocked
|
|
928
|
-
python -c 'import os; os.system("git stash drop")' # Blocked
|
|
929
|
-
python -c 'import os; os.system("dd if=/dev/zero of=/dev/sda")' # Blocked
|
|
930
|
-
python -c 'import os; os.system("mkfs.ext4 /dev/sda1")' # Blocked
|
|
931
|
-
python -c 'import os; os.system("shred -u secret.txt")' # Blocked
|
|
932
|
-
```
|
|
933
|
-
|
|
934
|
-
### Secret Redaction
|
|
935
|
-
|
|
936
|
-
Block messages automatically redact sensitive data (tokens, passwords, API keys) to prevent leaking secrets in logs.
|
|
937
|
-
|
|
938
|
-
### Audit Logging
|
|
939
|
-
|
|
940
|
-
All blocked commands are logged to `~/.cc-safety-net/logs/<session_id>.jsonl` for audit purposes:
|
|
941
|
-
|
|
942
|
-
```json
|
|
943
|
-
{"ts": "2025-01-15T10:30:00Z", "command": "git reset --hard", "segment": "git reset --hard", "reason": "...", "cwd": "/path/to/project"}
|
|
944
|
-
```
|
|
945
|
-
|
|
946
|
-
Sensitive data in log entries is automatically redacted.
|
|
235
|
+
| Area | Pages |
|
|
236
|
+
|---|---|
|
|
237
|
+
| Get started | [Introduction](https://ccsafetynet.com/docs/introduction) · [Installation](https://ccsafetynet.com/docs/installation) · [Quickstart](https://ccsafetynet.com/docs/quickstart) · [How It Works](https://ccsafetynet.com/docs/guides/how-it-works) · [Dashboard](https://ccsafetynet.com/docs/guides/dashboard) |
|
|
238
|
+
| Configuration | [Modes](https://ccsafetynet.com/docs/configuration/modes) · [Policy](https://ccsafetynet.com/docs/configuration/policy) · [Environment](https://ccsafetynet.com/docs/configuration/environment) · [Custom Rules](https://ccsafetynet.com/docs/configuration/custom-rules) · [Status Line](https://ccsafetynet.com/docs/configuration/status-line) · [Configuration Recovery](https://ccsafetynet.com/docs/configuration/recovery) |
|
|
239
|
+
| Reference | [Blocked Commands](https://ccsafetynet.com/docs/reference/blocked-commands) · [Allowed Commands](https://ccsafetynet.com/docs/reference/allowed-commands) · [Secret Protection](https://ccsafetynet.com/docs/reference/secret-protection) · [Audit Log](https://ccsafetynet.com/docs/reference/audit-log) · [CLI Commands](https://ccsafetynet.com/docs/reference/cli-commands) · [Explain Trace](https://ccsafetynet.com/docs/reference/explain-trace) · [Glossary](https://ccsafetynet.com/docs/reference/glossary) |
|
|
240
|
+
| Guides | [Architecture](https://ccsafetynet.com/docs/guides/architecture) · [Analysis Engine](https://ccsafetynet.com/docs/guides/analysis-engine) · [Design Principles](https://ccsafetynet.com/docs/guides/design-principles) · [Security Model](https://ccsafetynet.com/docs/guides/security-model) · [vs Sandboxing](https://ccsafetynet.com/docs/guides/vs-sandboxing) · [Integration Architecture](https://ccsafetynet.com/docs/guides/integration-architecture) · [Known Limitations](https://ccsafetynet.com/docs/guides/known-limitations) · [Troubleshooting](https://ccsafetynet.com/docs/guides/troubleshooting) |
|
|
241
|
+
| Project | [Contributing](https://ccsafetynet.com/docs/contributing) · [Security Policy](https://ccsafetynet.com/docs/security) |
|
|
947
242
|
|
|
948
243
|
## Development
|
|
949
244
|
|
|
950
245
|
See [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to contribute to this project.
|
|
951
246
|
|
|
247
|
+
Generated distribution ownership is intentionally narrow. Only `dist/index.js`,
|
|
248
|
+
`dist/index.d.ts`, `dist/bin/cc-safety-net.js`, and `dist/pi/index.js` are tracked. Run
|
|
249
|
+
`bun run verify:build`, `bun run verify:package`, and `bun run verify:repository-plugin` when
|
|
250
|
+
changing packaging, integrations, or release automation.
|
|
251
|
+
|
|
952
252
|
## License
|
|
953
253
|
|
|
954
254
|
MIT
|