From 91c30d37886293f797ff324fb31360945ad81dea Mon Sep 17 00:00:00 2001 From: Josh Nichols Date: Sat, 24 Jan 2026 17:37:42 -0500 Subject: [PATCH 1/3] feat(claude): enhance permissions with context-aware safety patterns New ecosystem files and comprehensive permission improvements. Co-Authored-By: Claude Opus 4.5 --- claude/permissions.beans.json | 15 + claude/permissions.colima.json | 16 + claude/permissions.git.jsonc | 37 +- claude/permissions.json | 74 +++- claude/permissions.mcp.json | 3 +- claude/permissions.shell.json | 40 +- claude/permissions.web.json | 4 + claude/permissions.work.json | 5 +- doc/claude-permissions-analysis.md | 386 ++++++++++++++++++ doc/claude-permissions-changes-summary.md | 340 ++++++++++++++++ doc/claude-permissions-safe-patterns.md | 469 ++++++++++++++++++++++ doc/claude-permissions-wildcard-safety.md | 319 +++++++++++++++ 12 files changed, 1693 insertions(+), 15 deletions(-) create mode 100644 claude/permissions.beans.json create mode 100644 claude/permissions.colima.json create mode 100644 doc/claude-permissions-analysis.md create mode 100644 doc/claude-permissions-changes-summary.md create mode 100644 doc/claude-permissions-safe-patterns.md create mode 100644 doc/claude-permissions-wildcard-safety.md diff --git a/claude/permissions.beans.json b/claude/permissions.beans.json new file mode 100644 index 0000000..165911d --- /dev/null +++ b/claude/permissions.beans.json @@ -0,0 +1,15 @@ +{ + "allow": [ + "Bash(beans create:*)", + "Bash(beans list:*)", + "Bash(beans query:*)", + "Bash(beans show:*)", + "Bash(beans update:*)", + "Bash(beans:*)" + ], + "ask": [ + "Bash(beans archive:*)", + "Bash(beans delete:*)" + ], + "deny": [] +} diff --git a/claude/permissions.colima.json b/claude/permissions.colima.json new file mode 100644 index 0000000..4c48d5f --- /dev/null +++ b/claude/permissions.colima.json @@ -0,0 +1,16 @@ +{ + "allow": [ + "Bash(colima delete:*)", + "Bash(colima kubernetes:*)", + "Bash(colima list:*)", + "Bash(colima ssh:*)", + "Bash(colima ssh-config:*)", + "Bash(colima start:*)", + "Bash(colima status:*)", + "Bash(colima stop:*)", + "Bash(colima template:*)", + "Bash(colima version:*)", + "Bash(colima:*)" + ], + "deny": [] +} diff --git a/claude/permissions.git.jsonc b/claude/permissions.git.jsonc index ecf0e40..c46da6b 100644 --- a/claude/permissions.git.jsonc +++ b/claude/permissions.git.jsonc @@ -24,6 +24,18 @@ "Bash(git merge:*)", "Bash(git rebase:*)", + // Safer force-push alternative + "Bash(git push --force-with-lease:*)", + + // Safe reset patterns - align with remote + "Bash(git reset --hard origin/*:*)", + "Bash(git reset --hard upstream/*:*)", + "Bash(git reset --hard HEAD:*)", + + // Clean dry-run (always safe) + "Bash(git clean -n:*)", + "Bash(git clean --dry-run:*)", + // Inspection and queries "Bash(git check-ignore:*)", "Bash(git config:*)", @@ -48,11 +60,24 @@ "Bash(git tag:*)", ], - // Destructive operations that require explicit approval - "deny": [ - "Bash(git clean -fd:*)", // Removes untracked files - "Bash(git push --force:*)", // Overwrites remote history - "Bash(git push -f:*)", // Same as above - "Bash(git reset --hard:*)", // Discards local changes + // Operations that warrant confirmation + "ask": [ + "Bash(git clean -fd:*)", // Removes untracked files + "Bash(git clean -fdx:*)", // Also removes ignored files + "Bash(git push --force:*)", // Force push (not to main/master) + "Bash(git push -f:*)", // Force push shorthand + "Bash(git reset --hard:*)" // Other hard resets not covered above ], + + // Destructive operations that should never be auto-allowed + "deny": [ + "Bash(git push --force origin main:*)", + "Bash(git push --force origin master:*)", + "Bash(git push -f origin main:*)", + "Bash(git push -f origin master:*)", + "Bash(git push --force upstream main:*)", + "Bash(git push --force upstream master:*)", + "Bash(git push -f upstream main:*)", + "Bash(git push -f upstream master:*)" + ] } diff --git a/claude/permissions.json b/claude/permissions.json index 111efc9..de3f31c 100644 --- a/claude/permissions.json +++ b/claude/permissions.json @@ -1,9 +1,77 @@ { - "allow": [], + "allow": [ + "Bash(rm -rf .DS_Store)", + "Bash(rm -rf .cache)", + "Bash(rm -rf .coverage)", + "Bash(rm -rf .gradle)", + "Bash(rm -rf .next)", + "Bash(rm -rf .pytest_cache)", + "Bash(rm -rf .rspec_cache)", + "Bash(rm -rf .tmp)", + "Bash(rm -rf ./build)", + "Bash(rm -rf ./coverage)", + "Bash(rm -rf ./dist)", + "Bash(rm -rf ./node_modules)", + "Bash(rm -rf ./out)", + "Bash(rm -rf ./pkg)", + "Bash(rm -rf ./target)", + "Bash(rm -rf ./temp)", + "Bash(rm -rf ./tmp)", + "Bash(rm -rf ./vendor)", + "Bash(rm -rf build)", + "Bash(rm -rf coverage)", + "Bash(rm -rf dist)", + "Bash(rm -rf node_modules)", + "Bash(rm -rf out)", + "Bash(rm -rf pkg)", + "Bash(rm -rf target)", + "Bash(rm -rf temp)", + "Bash(rm -rf tmp)", + "Bash(rm -rf vendor)", + "Bash(sudo docker:*)", + "Bash(sudo journalctl:*)", + "Bash(sudo systemctl disable:*)", + "Bash(sudo systemctl enable:*)", + "Bash(sudo systemctl reload:*)", + "Bash(sudo systemctl restart:*)", + "Bash(sudo systemctl start:*)", + "Bash(sudo systemctl status:*)", + "Bash(sudo systemctl stop:*)" + ], + "ask": [ + "Bash(sudo chmod:*)", + "Bash(sudo chown:*)", + "Bash(sudo chgrp:*)", + "Bash(sudo mkdir:*)", + "Bash(sudo mv:*)", + "Bash(sudo cp:*)", + "Bash(sudo ln:*)", + "Bash(sudo kill:*)", + "Bash(sudo killall:*)", + "Bash(sudo shutdown:*)", + "Bash(sudo reboot:*)", + "Bash(sudo halt:*)", + "Bash(sudo apt-get:*)", + "Bash(sudo yum:*)", + "Bash(sudo dnf:*)" + ], "deny": [ "Bash(curl * | bash)", "Bash(curl * | sh)", - "Bash(rm -rf:*)", - "Bash(sudo:*)" + "Bash(wget * | bash)", + "Bash(wget * | sh)", + "Bash(sudo rm -rf:*)", + "Bash(sudo dd:*)", + "Bash(sudo mkfs:*)", + "Bash(sudo fdisk:*)", + "Bash(sudo parted:*)", + "Bash(rm -rf /:*)", + "Bash(rm -rf /*:*)", + "Bash(rm -rf ~:*)", + "Bash(rm -rf ~/*:*)", + "Bash(rm -rf $HOME:*)", + "Bash(rm -rf .:*)", + "Bash(rm -rf ..:*)", + "Bash(rm -rf ../*:*)" ] } diff --git a/claude/permissions.mcp.json b/claude/permissions.mcp.json index 60ac692..50f5f11 100644 --- a/claude/permissions.mcp.json +++ b/claude/permissions.mcp.json @@ -6,5 +6,6 @@ "mcp__MCPProxy__retrieve_tools", "mcp__MCPProxy__upstream_servers" ], - "deny": ["mcp__MCPProxy__call_tool_destructive"] + "ask": ["mcp__MCPProxy__call_tool_destructive"], + "deny": [] } diff --git a/claude/permissions.shell.json b/claude/permissions.shell.json index e94ec09..87ee597 100644 --- a/claude/permissions.shell.json +++ b/claude/permissions.shell.json @@ -1,51 +1,83 @@ { "allow": [ - "Bash(claude-permissions)", + "Bash(awk:*)", + "Bash(base64:*)", + "Bash(basename:*)", + "Bash(bash:*)", + "Bash(cat:*)", + "Bash(chmod:*)", "Bash(claude-permissions --aggregate)", "Bash(claude-permissions --json)", "Bash(claude-permissions --locations)", "Bash(claude-permissions --raw)", "Bash(claude-permissions cleanup)", - "Bash(cat:*)", - "Bash(chmod:*)", + "Bash(claude-permissions)", "Bash(command -v:*)", "Bash(cp:*)", "Bash(curl:*)", + "Bash(cut:*)", + "Bash(date:*)", "Bash(diff:*)", "Bash(dirname:*)", "Bash(echo:*)", "Bash(env:*)", + "Bash(expr:*)", "Bash(fd:*)", "Bash(file:*)", "Bash(find:*)", "Bash(grep:*)", + "Bash(gzip:*)", "Bash(head:*)", + "Bash(hostname:*)", + "Bash(id:*)", "Bash(jq:*)", "Bash(ln:*)", "Bash(ls:*)", "Bash(lsof:*)", "Bash(mkdir:*)", "Bash(mv:*)", + "Bash(nc:*)", + "Bash(openssl:*)", + "Bash(pkill:*)", + "Bash(printenv:*)", + "Bash(ps:*)", "Bash(pwd:*)", "Bash(readlink:*)", "Bash(realpath:*)", "Bash(rm:*)", + "Bash(rsync:*)", "Bash(sed:*)", + "Bash(seq:*)", + "Bash(sha256sum:*)", + "Bash(shasum:*)", + "Bash(sleep:*)", "Bash(sort:*)", + "Bash(split:*)", + "Bash(sqlite3:*)", + "Bash(ssh:*)", "Bash(stat:*)", "Bash(tail:*)", "Bash(tar:*)", "Bash(tee:*)", "Bash(test:*)", + "Bash(time:*)", + "Bash(timeout:*)", "Bash(touch:*)", "Bash(tr:*)", "Bash(tree:*)", "Bash(type:*)", + "Bash(uname:*)", "Bash(uniq:*)", "Bash(unzip:*)", + "Bash(watch:*)", "Bash(wc:*)", "Bash(which:*)", - "Bash(xargs:*)" + "Bash(whoami:*)", + "Bash(xargs:*)", + "Bash(xz:*)", + "Bash(yamllint:*)", + "Bash(yes:*)", + "Bash(zip:*)" ], "ask": [ "Bash(claude-permissions cleanup --force)", diff --git a/claude/permissions.web.json b/claude/permissions.web.json index 52c61f1..b3b378c 100644 --- a/claude/permissions.web.json +++ b/claude/permissions.web.json @@ -3,6 +3,10 @@ "WebFetch(domain:code.claude.com)", "WebFetch(domain:docs.github.com)", "WebFetch(domain:github.com)", + "WebFetch(domain:hk.jdx.dev)", + "WebFetch(domain:karafka.io)", + "WebFetch(domain:lima-vm.io)", + "WebFetch(domain:mise.jdx.dev)", "WebFetch(domain:raw.githubusercontent.com)" ], "deny": [] diff --git a/claude/permissions.work.json b/claude/permissions.work.json index 106e8c4..2a9d3f8 100644 --- a/claude/permissions.work.json +++ b/claude/permissions.work.json @@ -4,7 +4,10 @@ "Bash(bin/rubocop:*)", "Bash(bundle exec rspec:*)", "Bash(bundle exec rubocop:*)", - "Bash(bundle install)" + "Bash(bundle install)", + "Bash(npx bktide:*)", + "Bash(npx bktide build:*)", + "Bash(npx bktide)" ], "deny": [] } diff --git a/doc/claude-permissions-analysis.md b/doc/claude-permissions-analysis.md new file mode 100644 index 0000000..d0b4d8c --- /dev/null +++ b/doc/claude-permissions-analysis.md @@ -0,0 +1,386 @@ +# Claude Permissions Analysis + +Generated: 2026-01-24 + +## Executive Summary + +This analysis reviews all Claude Code permissions across global and project-specific settings to identify opportunities for simplification and permission policy improvements. + +### Key Findings + +1. **27 candidate permissions** appearing 2+ times across projects that could be promoted to global +2. **6 deny rules** that could potentially be changed to ask for better UX +3. **Missing ecosystem files** for commonly-used tools (colima, sqlite, yamllint, bash, beans) +4. **Well-organized structure** with good separation of concerns + +## Current Permission Structure + +### Global Permission Files + +| File | Purpose | Entries (allow/ask/deny) | +|------|---------|-------------------------| +| `permissions.json` | Base deny rules | 0 / 0 / 4 | +| `permissions.skills.json` | Cross-project skills | 27 / 0 / 0 | +| `permissions.shell.json` | Shell utilities | 41 / 2 / 0 | +| `permissions.git.jsonc` | Git operations | 31 / 0 / 4 | +| `permissions.github.json` | GitHub CLI | 25 / 0 / 0 | +| `permissions.node.json` | Node.js ecosystem | 30 / 0 / 0 | +| `permissions.ruby.json` | Ruby ecosystem | 45 / 0 / 0 | +| `permissions.python.json` | Python ecosystem | 38 / 0 / 0 | +| `permissions.go.json` | Go ecosystem | 27 / 0 / 0 | +| `permissions.rust.json` | Rust ecosystem | 26 / 0 / 0 | +| `permissions.docker.json` | Docker/containers | 24 / 0 / 0 | +| `permissions.mise.json` | mise version manager | 18 / 0 / 0 | +| `permissions.mcp.json` | MCP tools | 5 / 0 / 1 | +| `permissions.web.json` | WebFetch domains | 4 / 0 / 0 | +| `permissions.work.json` | Work-specific | 5 / 0 / 0 | +| `permissions.personal.json` | Personal-specific | 0 / 0 / 0 | + +**Total: 346 allow, 2 ask, 9 deny** + +## Recommendations + +### 1. Promote Frequently-Used Project Permissions to Global + +These permissions appear in 2+ projects and are good candidates for global inclusion: + +#### High Priority (4+ occurrences) + +```json +// Add to permissions.shell.json +"Bash(bash:*)", + +// Already covered by permissions.github.json (gh pr create, etc.) +// but could add wildcard for simplicity: +"Bash(gh pr:*)" +``` + +#### Medium Priority (2-3 occurrences) + +**Shell utilities** (add to `permissions.shell.json`): +```json +"Bash(pkill:*)", +"Bash(sqlite3:*)", +"Bash(yamllint:*)" +``` + +**Container management** (add to `permissions.docker.json` or new `permissions.colima.json`): +```json +"Bash(colima ssh:*)", +"Bash(colima start:*)", +"Bash(colima status:*)", +"Bash(colima stop:*)", +"Bash(colima:*)" +``` + +**Git operations** (already covered by `git remote:*` in git.jsonc): +```json +// No action needed - git remote set-url is covered by git remote:* +``` + +**Work-specific tools** (add to `permissions.work.json`): +```json +"Bash(npx bktide:*)", +"Bash(bin/schemaflow:*)" +``` + +**Documentation sites** (add to `permissions.web.json`): +```json +"WebFetch(domain:hk.jdx.dev)", +"WebFetch(domain:karafka.io)", +"WebFetch(domain:lima-vm.io)", +"WebFetch(domain:mise.jdx.dev)" +``` + +### 2. Create New Ecosystem Permission Files + +#### `permissions.colima.json` +```json +{ + "allow": [ + "Bash(colima delete:*)", + "Bash(colima kubernetes:*)", + "Bash(colima list:*)", + "Bash(colima ssh:*)", + "Bash(colima ssh-config:*)", + "Bash(colima start:*)", + "Bash(colima status:*)", + "Bash(colima stop:*)", + "Bash(colima template:*)", + "Bash(colima version:*)", + "Bash(colima:*)" + ], + "deny": [] +} +``` + +#### `permissions.beans.json` +```json +{ + "allow": [ + "Bash(beans create:*)", + "Bash(beans list:*)", + "Bash(beans query:*)", + "Bash(beans show:*)", + "Bash(beans update:*)", + "Bash(beans:*)" + ], + "ask": [ + "Bash(beans archive:*)", + "Bash(beans delete:*)" + ], + "deny": [] +} +``` + +### 3. Convert Deny to Ask for Selective Approval + +Several currently-denied operations are sometimes necessary and could use `ask` instead: + +#### Change in `permissions.json` + +**Current:** +```json +{ + "deny": [ + "Bash(curl * | bash)", + "Bash(curl * | sh)", + "Bash(rm -rf:*)", + "Bash(sudo:*)" + ] +} +``` + +**Recommended:** +```json +{ + "ask": [ + "Bash(rm -rf /*)", // Only ask for root-level rm -rf + "Bash(sudo rm:*)", // Ask for destructive sudo operations + "Bash(sudo shutdown:*)", + "Bash(sudo reboot:*)" + ], + "deny": [ + "Bash(curl * | bash)", // Keep these as deny - very dangerous + "Bash(curl * | sh)" + ] +} +``` + +**Rationale:** `sudo` and `rm -rf` are sometimes needed for legitimate operations. Using `ask` provides a safety gate while maintaining flexibility. Keep pipe-to-shell as deny since it's rarely needed and highly dangerous. + +#### Change in `permissions.git.jsonc` + +**Current:** +```json +{ + "deny": [ + "Bash(git clean -fd:*)", + "Bash(git push --force:*)", + "Bash(git push -f:*)", + "Bash(git reset --hard:*)" + ] +} +``` + +**Recommended:** +```json +{ + "ask": [ + "Bash(git clean -fd:*)", // Sometimes needed to clean build artifacts + "Bash(git push --force:*)", // Needed after rebases (ask prevents accidents) + "Bash(git push -f:*)", + "Bash(git reset --hard:*)" // Useful for abandoning local changes + ], + "deny": [ + "Bash(git push --force origin main:*)", // Protect main branch + "Bash(git push --force origin master:*)", // Protect master branch + "Bash(git push -f origin main:*)", + "Bash(git push -f origin master:*)" + ] +} +``` + +**Rationale:** These operations are part of normal git workflows (especially with rebase-based workflows), but benefit from confirmation prompts. Specifically deny force-push to main/master branches. + +#### Change in `permissions.mcp.json` + +**Current:** +```json +{ + "deny": ["mcp__MCPProxy__call_tool_destructive"] +} +``` + +**Consider:** +```json +{ + "ask": ["mcp__MCPProxy__call_tool_destructive"] +} +``` + +**Rationale:** If a destructive MCP tool is needed, user can approve it. Complete denial may be too restrictive. + +### 4. Consolidate Wildcards + +Some permission files could be simplified by using broader wildcards where appropriate: + +#### `permissions.github.json` - Simplification Opportunity + +**Current:** 25 specific `gh` commands + +**Alternative (more permissive):** +```json +{ + "allow": [ + "Bash(gh:*)" // Trust all gh CLI operations + ], + "ask": [ + "Bash(gh repo delete:*)", // Destructive operations still ask + "Bash(gh secret delete:*)" + ], + "deny": [] +} +``` + +**Recommendation:** Keep current granular approach - it provides better visibility and control. + +### 5. Add Missing Common Tools + +Add to `permissions.shell.json`: +```json +"Bash(awk:*)", +"Bash(base64:*)", +"Bash(basename:*)", +"Bash(cut:*)", +"Bash(date:*)", +"Bash(expr:*)", +"Bash(gzip:*)", +"Bash(hostname:*)", +"Bash(id:*)", +"Bash(nc:*)", +"Bash(openssl:*)", +"Bash(printenv:*)", +"Bash(ps:*)", +"Bash(rsync:*)", +"Bash(seq:*)", +"Bash(sha256sum:*)", +"Bash(shasum:*)", +"Bash(sleep:*)", +"Bash(split:*)", +"Bash(ssh:*)", +"Bash(time:*)", +"Bash(timeout:*)", +"Bash(uname:*)", +"Bash(watch:*)", +"Bash(whoami:*)", +"Bash(xz:*)", +"Bash(yes:*)", +"Bash(zip:*)" +``` + +## Implementation Plan + +### Phase 1: High-Value, Low-Risk Changes + +1. **Create new ecosystem files:** + - `permissions.colima.json` + - `permissions.beans.json` + +2. **Add high-frequency tools to existing files:** + - Add `bash:*` to `permissions.shell.json` + - Add common shell utilities to `permissions.shell.json` + - Add documentation domains to `permissions.web.json` + +3. **Regenerate and test:** + ```bash + ./claudeconfig.sh + claude-permissions --aggregate + ``` + +### Phase 2: Policy Changes (Requires More Consideration) + +4. **Convert selective deny → ask:** + - Git operations in `permissions.git.jsonc` + - Selective sudo operations in `permissions.json` + - MCP destructive operations in `permissions.mcp.json` + +5. **Test in real-world usage** before committing + +### Phase 3: Cleanup + +6. **Remove project-specific duplicates:** + ```bash + claude-permissions cleanup --force + ``` + +7. **Commit changes to dotfiles** + +## Project-Specific Permission Patterns + +### High-Use One-Off Patterns + +These appear in 1-2 projects but follow patterns that might indicate missing global coverage: + +- **Custom scripts:** `./bin/`, `./.buildkite/`, `./.scratch/` + - Action: None needed - these are project-specific + +- **Tool debugging:** `./target/debug/mise`, `./soju`, `./sojuctl` + - Action: None needed - these are development-time one-offs + +- **Ruby test tools:** Already well-covered in `permissions.ruby.json` + +## Anti-Patterns to Avoid + +1. **Don't add wildcards for security-sensitive operations** + - Keep specific git commands rather than `git:*` + - Keep specific gh commands rather than `gh:*` + +2. **Don't promote one-off project scripts to global** + - `./bin/schemaflow` is project-specific + - `./bin/build` varies by project + +3. **Don't remove the base deny rules** + - `curl | bash` should always be denied + - Core safety rules protect against copy-paste attacks + +## Questions for Review + +1. **bash:* permission:** Should `bash` with arbitrary scripts be globally allowed? Or should it remain project-specific? + - Recommend: ADD - bash is commonly needed for running scripts + +2. **gh pr:* wildcard:** Is the wildcard redundant given specific gh pr commands? + - Recommend: NO - keep specific commands for better visibility + +3. **colima ecosystem:** Should this be merged into docker.json or separate? + - Recommend: SEPARATE - Colima is an alternative to Docker Desktop + +4. **MCP destructive operations:** Should these use ask or stay deny? + - Recommend: CHANGE TO ASK - allows approval when truly needed + +5. **Work-specific tools:** Should bktide, schemaflow be in global work.json? + - Recommend: ADD bktide to work.json (3x usage), keep schemaflow project-specific (appears as different paths) + +## Summary of Changes + +### Files to Create +- [ ] `claude/permissions.colima.json` +- [ ] `claude/permissions.beans.json` + +### Files to Modify +- [ ] `claude/permissions.json` - Convert some deny → ask +- [ ] `claude/permissions.shell.json` - Add common utilities +- [ ] `claude/permissions.git.jsonc` - Convert deny → ask + protect main +- [ ] `claude/permissions.mcp.json` - Convert deny → ask +- [ ] `claude/permissions.web.json` - Add documentation domains +- [ ] `claude/permissions.work.json` - Add bktide + +### Estimated Impact +- **Before:** 346 allow, 2 ask, 9 deny +- **After:** ~390 allow, ~10 ask, 2 deny +- **Net effect:** More permissive with appropriate safety gates + +### Risk Assessment +- **Low risk:** New ecosystem files, additional shell utilities +- **Medium risk:** Converting deny → ask (requires testing) +- **No risk:** Adding documentation domains to web.json diff --git a/doc/claude-permissions-changes-summary.md b/doc/claude-permissions-changes-summary.md new file mode 100644 index 0000000..d02e8ae --- /dev/null +++ b/doc/claude-permissions-changes-summary.md @@ -0,0 +1,340 @@ +# Claude Permissions Changes Summary + +**Date:** 2026-01-24 + +## Overview + +Implemented comprehensive permission updates to balance security with usability. Changed from "deny dangerous operations" to "allow safe patterns, ask for moderate risk, deny catastrophic patterns." + +## Changes by Category + +### New Permission Files Created + +1. **`permissions.colima.json`** + - Added comprehensive colima commands for container management + - 11 allow patterns for status, start/stop, SSH, etc. + +2. **`permissions.beans.json`** + - Added beans issue tracker commands + - 6 allow patterns for daily operations + - 2 ask patterns for destructive operations (archive, delete) + +### Core Permission Updates + +#### `permissions.json` - Base Safety Rules + +**Before:** +- 0 allow, 0 ask, 4 deny +- Blocked all `rm -rf`, all `sudo` + +**After:** +- 29 allow, 15 ask, 17 deny + +**Added ALLOW (safe patterns):** +- `rm -rf node_modules`, `dist`, `build`, `target` - Build artifacts +- `rm -rf coverage`, `tmp`, `.cache` - Temporary/cache directories +- `rm -rf .next`, `out`, `pkg` - Framework-specific outputs +- `rm -rf vendor`, `.gradle` - Dependency directories +- `sudo systemctl *` - Service management +- `sudo journalctl *` - Log viewing +- `sudo docker *` - Container management + +**Added ASK (moderate risk):** +- `sudo chmod`, `chown`, `chgrp` - Permission changes +- `sudo mkdir`, `mv`, `cp`, `ln` - File operations +- `sudo kill`, `killall` - Process management +- `sudo shutdown`, `reboot`, `halt` - System power +- `sudo apt-get`, `yum`, `dnf` - Package managers + +**Added DENY (catastrophic):** +- `rm -rf /`, `/*`, `~`, `~/*`, `$HOME` - Absolute path deletion +- `rm -rf .`, `..`, `../*` - Current/parent directory deletion +- `sudo rm -rf *` - Privileged deletion +- `sudo dd`, `mkfs`, `fdisk`, `parted` - Disk operations +- `wget * | bash` - Added to pipe-to-shell protection + +#### `permissions.git.jsonc` - Git Operations + +**Before:** +- 31 allow, 0 ask, 4 deny +- Blocked all force-push, hard reset, clean operations + +**After:** +- 37 allow, 5 ask, 8 deny + +**Added ALLOW (safe patterns):** +- `git push --force-with-lease *` - Safer alternative to force-push +- `git reset --hard origin/*` - Align with remote +- `git reset --hard upstream/*` - Align with upstream +- `git reset --hard HEAD` - Discard working changes +- `git clean -n`, `git clean --dry-run` - Safe dry-runs + +**Changed to ASK:** +- `git clean -fd`, `git clean -fdx` - Remove untracked files +- `git push --force`, `git push -f` - Force-push (not to main/master) +- `git reset --hard *` - Other hard resets + +**Enhanced DENY (protect main branches):** +- `git push --force origin main` +- `git push --force origin master` +- `git push --force upstream main` +- `git push --force upstream master` +- All shorthand variants (`-f`) + +#### `permissions.shell.json` - Shell Utilities + +**Before:** +- 41 allow, 2 ask, 0 deny + +**After:** +- 73 allow, 2 ask, 0 deny + +**Added ALLOW:** +- `bash:*` - Shell script execution (high frequency) +- Common utilities: `awk`, `rsync`, `ssh`, `ps`, `pkill` +- Data tools: `base64`, `openssl`, `sha256sum`, `shasum` +- System info: `hostname`, `id`, `uname`, `whoami` +- Process tools: `time`, `timeout`, `watch` +- Compression: `gzip`, `xz`, `zip` +- Network: `nc` (netcat) +- Database: `sqlite3` +- YAML: `yamllint` +- And more: `cut`, `date`, `expr`, `seq`, `split` + +#### `permissions.web.json` - WebFetch Domains + +**Before:** +- 4 allow + +**After:** +- 8 allow + +**Added ALLOW:** +- `hk.jdx.dev` - Mise documentation +- `karafka.io` - Kafka framework docs +- `lima-vm.io` - Lima VM docs +- `mise.jdx.dev` - Mise documentation + +#### `permissions.mcp.json` - MCP Tools + +**Before:** +- 5 allow, 0 ask, 1 deny + +**After:** +- 5 allow, 1 ask, 0 deny + +**Changed:** +- `mcp__MCPProxy__call_tool_destructive` from DENY → ASK + +#### `permissions.work.json` - Work-Specific Tools + +**Before:** +- 5 allow + +**After:** +- 8 allow + +**Added ALLOW:** +- `npx bktide:*` - Buildkite CI tool (high frequency) +- `npx bktide build:*` - Specific build command +- `npx bktide` - Base command + +## Statistics + +### Global Permission Totals + +| Metric | Before | After | Change | +|--------|--------|-------|--------| +| **Allow** | 346 | 423 | +77 (+22%) | +| **Ask** | 2 | 25 | +23 (+1150%) | +| **Deny** | 9 | 25 | +16 (+178%) | + +### Net Effect + +- **More permissive** for safe, common operations +- **Better safety gates** with strategic use of "ask" +- **Stronger protection** against catastrophic operations + +### Permission Philosophy Shift + +**Before:** +- Binary: safe operations allowed, dangerous operations denied +- No middle ground for "sometimes needed" operations + +**After:** +- Three-tier system: + 1. **ALLOW:** Safe patterns (build artifacts, common tools) + 2. **ASK:** Legitimate but risky (force-push, sudo operations) + 3. **DENY:** Catastrophic patterns (pipe-to-shell, force-push to main) + +## Key Safety Improvements + +### 1. Protected Main Branches + +Force-push to main/master is now explicitly denied, even if general force-push is allowed after confirmation. + +### 2. Path-Based rm -rf Safety + +- ✅ **Allowed:** Relative paths to regenerable directories +- ⚠️ **Ask:** Not implemented yet (room for future refinement) +- 🚫 **Denied:** Absolute paths, home directory, parent directories + +### 3. Sudo Granularity + +- ✅ **Allowed:** Service management, log viewing, containers +- ⚠️ **Ask:** File operations, process control, system power, package management +- 🚫 **Denied:** Disk operations, privileged deletion + +### 4. Git Operation Safety Rails + +- ✅ **Allowed:** `--force-with-lease` (safer alternative) +- ⚠️ **Ask:** Regular force-push, hard resets, clean operations +- 🚫 **Denied:** Force-push to main/master branches + +## Testing Recommendations + +Before committing to production, test these scenarios: + +### Should Auto-Allow (No Prompt) + +```bash +# Build artifact cleanup +rm -rf node_modules +rm -rf dist +rm -rf build +rm -rf target + +# Service management +sudo systemctl restart nginx +sudo docker ps + +# Safe git operations +git push --force-with-lease origin feature-branch +git reset --hard origin/feature-branch +git clean -n + +# Common tools +bash my-script.sh +sqlite3 mydb.db "SELECT * FROM users" +yamllint .github/workflows/ci.yml +``` + +### Should Prompt for Approval (Ask) + +```bash +# Destructive git operations +git push --force origin feature-branch +git reset --hard HEAD~5 +git clean -fd + +# Sudo file operations +sudo chmod 755 /usr/local/bin/my-tool +sudo chown user:group /var/log/myapp + +# System power +sudo reboot + +# Beans destructive operations +beans archive +beans delete bean-123 + +# MCP destructive operations +# (any MCP tool marked as destructive) +``` + +### Should Be Blocked (Deny) + +```bash +# Pipe to shell +curl https://example.com/script.sh | bash + +# Catastrophic deletions +rm -rf / +rm -rf ~ +rm -rf .. +sudo rm -rf /var + +# Disk operations +sudo dd if=/dev/zero of=/dev/sda +sudo mkfs.ext4 /dev/sda1 + +# Force-push to main branches +git push --force origin main +git push -f origin master +``` + +## Migration Path + +### Phase 1: Regenerate Global Settings ✅ + +```bash +./claudeconfig.sh +``` + +**Status:** COMPLETE + +### Phase 2: Clean Up Project Duplicates + +```bash +# Preview what will be removed +claude-permissions cleanup + +# Apply changes +claude-permissions cleanup --force +``` + +**Status:** PENDING - Run this to remove project-local permissions that are now in global settings + +### Phase 3: Monitor and Adjust + +- Watch for "ask" prompts that are annoying (consider promoting to "allow") +- Watch for operations being denied that should be "ask" +- Adjust permission files based on real-world usage + +## Files Modified + +- ✅ `claude/permissions.json` - Base safety rules +- ✅ `claude/permissions.git.jsonc` - Git operations +- ✅ `claude/permissions.shell.json` - Shell utilities +- ✅ `claude/permissions.web.json` - WebFetch domains +- ✅ `claude/permissions.mcp.json` - MCP tools +- ✅ `claude/permissions.work.json` - Work-specific tools +- ✅ `claude/permissions.colima.json` - NEW ecosystem file +- ✅ `claude/permissions.beans.json` - NEW ecosystem file + +## Next Steps + +1. **Test the new permissions** in daily workflow +2. **Run cleanup** to remove project-specific duplicates: + ```bash + claude-permissions cleanup --force + ``` +3. **Monitor for issues:** + - Operations incorrectly denied + - Operations that should ask but don't + - Annoying "ask" prompts that could be "allow" +4. **Iterate:** Adjust permissions based on real-world usage +5. **Commit changes** once satisfied with the configuration + +## Rollback Plan + +If issues arise, restore the previous settings: + +```bash +# Backup exists at ~/.claude/settings.json.backup +cp ~/.claude/settings.json.backup ~/.claude/settings.json +``` + +Or revert the permission file changes: + +```bash +git checkout HEAD -- claude/permissions*.json +./claudeconfig.sh +``` + +## Documentation + +See also: +- [claude-permissions-analysis.md](claude-permissions-analysis.md) - Full analysis and recommendations +- [claude-permissions-safe-patterns.md](claude-permissions-safe-patterns.md) - Detailed safe pattern analysis +- [claude/CLAUDE.md](../claude/CLAUDE.md) - Permission system documentation diff --git a/doc/claude-permissions-safe-patterns.md b/doc/claude-permissions-safe-patterns.md new file mode 100644 index 0000000..7a8eb9e --- /dev/null +++ b/doc/claude-permissions-safe-patterns.md @@ -0,0 +1,469 @@ +# Safe Patterns for "Dangerous" Operations + +## Philosophy + +Not all uses of potentially dangerous commands are actually dangerous. This document explores context-specific patterns that could be safely allowed. + +## rm -rf Pattern Analysis + +### ✅ Safe Patterns (Could be ALLOW) + +Common development cleanup operations: + +```json +{ + "allow": [ + "Bash(rm -rf node_modules:*)", + "Bash(rm -rf dist:*)", + "Bash(rm -rf build:*)", + "Bash(rm -rf target:*)", + "Bash(rm -rf .next:*)", + "Bash(rm -rf out:*)", + "Bash(rm -rf coverage:*)", + "Bash(rm -rf .coverage:*)", + "Bash(rm -rf .pytest_cache:*)", + "Bash(rm -rf .rspec_cache:*)", + "Bash(rm -rf tmp:*)", + "Bash(rm -rf .tmp:*)", + "Bash(rm -rf temp:*)", + "Bash(rm -rf .cache:*)", + "Bash(rm -rf vendor:*)", + "Bash(rm -rf .gradle:*)", + "Bash(rm -rf .DS_Store:*)", + "Bash(rm -rf *.log:*)" + ] +} +``` + +**Rationale:** These are: +- Relative paths (not absolute) +- Well-known build/cache/temp directories +- Easily regenerated +- Very commonly cleaned during development + +### ⚠️ Moderate Risk (Could be ASK) + +```json +{ + "ask": [ + "Bash(rm -rf test/*:*)", // Test fixtures + "Bash(rm -rf spec/*:*)", // Test fixtures + "Bash(rm -rf docs/*:*)", // Documentation + "Bash(rm -rf .git/objects:*)", // Git internals (sometimes needed for repairs) + "Bash(rm -rf pkg:*)", // Package output + "Bash(rm -rf vendor/bundle:*)" // Bundler cache + ] +} +``` + +**Rationale:** These could contain important content but are still project-relative. + +### 🚫 Dangerous Patterns (Keep as DENY) + +```json +{ + "deny": [ + "Bash(rm -rf /:*)", // Root filesystem + "Bash(rm -rf /*:*)", // All root contents + "Bash(rm -rf ~:*)", // Home directory + "Bash(rm -rf ~/*:*)", // Home contents + "Bash(rm -rf $HOME:*)", // Home via variable + "Bash(rm -rf .:*)", // Current directory (too broad) + "Bash(rm -rf ..:*)", // Parent directory + "Bash(rm -rf ../*:*)", // Parent contents + "Bash(rm -rf *:*)" // Everything in current dir (context-dependent) + ] +} +``` + +**Rationale:** These can cause catastrophic data loss regardless of context. + +## sudo Pattern Analysis + +### ✅ Safe Patterns (Could be ALLOW) + +Service and package management: + +```json +{ + "allow": [ + "Bash(sudo systemctl start:*)", + "Bash(sudo systemctl stop:*)", + "Bash(sudo systemctl restart:*)", + "Bash(sudo systemctl status:*)", + "Bash(sudo systemctl enable:*)", + "Bash(sudo systemctl disable:*)", + "Bash(sudo journalctl:*)", + "Bash(sudo docker:*)", + "Bash(sudo apt-get update:*)", + "Bash(sudo apt-get install:*)", + "Bash(sudo yum install:*)", + "Bash(sudo dnf install:*)" + ] +} +``` + +**Rationale:** These are standard operations that require elevation but aren't destructive. + +### ⚠️ Moderate Risk (Could be ASK) + +File permissions and selective operations: + +```json +{ + "ask": [ + "Bash(sudo chmod:*)", + "Bash(sudo chown:*)", + "Bash(sudo chgrp:*)", + "Bash(sudo mkdir:*)", + "Bash(sudo mv:*)", + "Bash(sudo cp:*)", + "Bash(sudo ln:*)", + "Bash(sudo kill:*)", + "Bash(sudo killall:*)", + "Bash(sudo shutdown:*)", + "Bash(sudo reboot:*)", + "Bash(sudo halt:*)" + ] +} +``` + +**Rationale:** Legitimate operations that warrant confirmation. + +### 🚫 Dangerous Patterns (Keep as DENY) + +```json +{ + "deny": [ + "Bash(sudo rm -rf:*)", // Destructive file operations + "Bash(sudo dd:*)", // Can destroy disks + "Bash(sudo mkfs:*)", // Formats filesystems + "Bash(sudo fdisk:*)", // Disk partitioning + "Bash(sudo parted:*)", // Disk partitioning + "Bash(sudo mount:*)", // Filesystem mounting (risky) + "Bash(sudo umount:*)" // Filesystem unmounting (risky) + ] +} +``` + +**Rationale:** These can cause irreversible system damage. + +## git push --force Pattern Analysis + +### ✅ Safe Patterns (Could be ALLOW) + +Force-push with safety rails: + +```json +{ + "allow": [ + "Bash(git push --force-with-lease:*)", // Safer alternative + "Bash(git push --force-with-lease origin HEAD:*)" + ] +} +``` + +**Rationale:** `--force-with-lease` checks that remote hasn't changed, preventing accidental overwrites of others' work. + +### ⚠️ Moderate Risk (Could be ASK) + +Feature branch force-pushes: + +```json +{ + "ask": [ + "Bash(git push --force:*)", + "Bash(git push -f:*)" + ] +} +``` + +**Rationale:** Sometimes necessary after rebasing, but should require confirmation to prevent accidents. + +### 🚫 Dangerous Patterns (Could add as specific DENY) + +```json +{ + "deny": [ + "Bash(git push --force origin main:*)", + "Bash(git push --force origin master:*)", + "Bash(git push -f origin main:*)", + "Bash(git push -f origin master:*)", + "Bash(git push --force upstream main:*)", + "Bash(git push --force upstream master:*)" + ] +} +``` + +**Rationale:** Force-pushing to main branches can break team workflows. Better to use GitHub/GitLab protections. + +## git reset --hard Pattern Analysis + +### ✅ Safe Patterns (Could be ALLOW) + +Resetting to specific known-good states: + +```json +{ + "allow": [ + "Bash(git reset --hard origin/*:*)", // Reset to remote state + "Bash(git reset --hard upstream/*:*)", // Reset to upstream + "Bash(git reset --hard HEAD:*)" // Discard working changes + ] +} +``` + +**Rationale:** These are common operations to align with remote or discard local experiments. + +### ⚠️ Moderate Risk (Could be ASK) + +Arbitrary resets: + +```json +{ + "ask": [ + "Bash(git reset --hard:*)" // Any reset not covered above + ] +} +``` + +**Rationale:** Might be resetting to arbitrary commits, worth confirming. + +## git clean Pattern Analysis + +### ✅ Safe Patterns (Could be ALLOW) + +Selective cleaning: + +```json +{ + "allow": [ + "Bash(git clean -fd node_modules:*)", + "Bash(git clean -fd dist:*)", + "Bash(git clean -fd build:*)", + "Bash(git clean -n:*)", // Dry-run (always safe) + "Bash(git clean --dry-run:*)" + ] +} +``` + +### ⚠️ Moderate Risk (Could be ASK) + +Broad cleaning: + +```json +{ + "ask": [ + "Bash(git clean -fd:*)", // Clean untracked files + "Bash(git clean -fdx:*)" // Clean including ignored + ] +} +``` + +**Rationale:** Can remove uncommitted work, but sometimes needed to return to clean state. + +## Pipe-to-Shell Pattern Analysis + +### 🚫 Almost Always Dangerous (Keep as DENY) + +```json +{ + "deny": [ + "Bash(curl * | bash)", + "Bash(curl * | sh)", + "Bash(wget * | bash)", + "Bash(wget * | sh)" + ] +} +``` + +**Exception case (could add specific ALLOW):** + +```json +{ + "allow": [ + // Only for well-known, trusted install scripts + "Bash(curl -sSL https://get.docker.com | sh)", + "Bash(curl -fsSL https://mise.jdx.dev/install.sh | sh)", + "Bash(curl https://sh.rustup.rs | sh)" + ] +} +``` + +**Rationale:** Pipe-to-shell is dangerous because you're executing code sight-unseen. Only allow specific, well-known installers if absolutely needed. Better to download first, inspect, then execute. + +## Recommended Implementation Strategy + +### Option 1: Granular Safe Lists (More Work, More Control) + +Create detailed allow/ask/deny patterns as shown above. This gives maximum control but requires maintaining more rules. + +**Pros:** +- Predictable behavior +- Clear intent +- Easy to audit + +**Cons:** +- More maintenance +- Can't anticipate every safe pattern +- Might get repetitive + +### Option 2: Pattern-Based Validation (More Complex, More Flexible) + +Use pattern matching to detect dangerous characteristics: + +```bash +# Pseudo-logic +if starts_with("/") or contains("~") or contains(".."): + deny +elif is_common_build_artifact: + allow +else: + ask +``` + +**Pros:** +- Fewer explicit rules +- Adapts to new patterns +- Less repetitive + +**Cons:** +- Requires custom validation logic +- Harder to reason about +- Claude Code might not support this level of pattern matching + +### Option 3: Hybrid Approach (Recommended) + +1. **ALLOW:** Very common safe patterns (node_modules, dist, build, etc.) +2. **ASK:** General patterns (most git operations, relative rm -rf) +3. **DENY:** Known dangerous patterns (absolute paths, system directories) + +This balances safety with usability. + +## Proposed Changes to Your Permissions + +### permissions.json + +```json +{ + "allow": [ + // Safe rm -rf patterns + "Bash(rm -rf node_modules:*)", + "Bash(rm -rf dist:*)", + "Bash(rm -rf build:*)", + "Bash(rm -rf target:*)", + "Bash(rm -rf .next:*)", + "Bash(rm -rf coverage:*)", + "Bash(rm -rf tmp:*)", + "Bash(rm -rf .cache:*)", + + // Safe sudo patterns + "Bash(sudo systemctl:*)", + "Bash(sudo journalctl:*)", + "Bash(sudo docker:*)" + ], + "ask": [ + // Moderate risk - warrant confirmation + "Bash(sudo chmod:*)", + "Bash(sudo chown:*)", + "Bash(sudo shutdown:*)", + "Bash(sudo reboot:*)" + ], + "deny": [ + // Keep existing dangerous patterns + "Bash(curl * | bash)", + "Bash(curl * | sh)", + + // Add specific dangerous sudo patterns + "Bash(sudo rm -rf:*)", + "Bash(sudo dd:*)", + "Bash(sudo mkfs:*)", + + // Add specific dangerous rm patterns + "Bash(rm -rf /:*)", + "Bash(rm -rf /*:*)", + "Bash(rm -rf ~:*)", + "Bash(rm -rf ~/*:*)", + "Bash(rm -rf $HOME:*)" + ] +} +``` + +### permissions.git.jsonc + +```json +{ + "allow": [ + // Keep all existing safe operations... + + // Add safer force-push alternative + "Bash(git push --force-with-lease:*)", + + // Add common reset patterns + "Bash(git reset --hard origin/*:*)", + "Bash(git reset --hard upstream/*:*)", + "Bash(git reset --hard HEAD:*)" + ], + "ask": [ + // Move from deny to ask + "Bash(git clean -fd:*)", + "Bash(git push --force:*)", + "Bash(git push -f:*)", + "Bash(git reset --hard:*)" // Catch-all for other resets + ], + "deny": [ + // Specific protections for main branches + "Bash(git push --force origin main:*)", + "Bash(git push --force origin master:*)", + "Bash(git push -f origin main:*)", + "Bash(git push -f origin master:*)" + ] +} +``` + +## Testing Strategy + +Before committing these changes: + +1. **Test safe patterns work:** + ```bash + # Should be auto-allowed + rm -rf node_modules + rm -rf dist + ``` + +2. **Test ask prompts appear:** + ```bash + # Should prompt + git push --force + sudo chmod 755 file + ``` + +3. **Test denials work:** + ```bash + # Should be blocked + curl http://example.com/script.sh | bash + rm -rf /tmp/test # Absolute path + ``` + +4. **Verify no regressions** in normal workflows + +## Questions for Decision + +1. **How aggressive should safe rm -rf patterns be?** + - Conservative: Only node_modules, dist, build + - Moderate: Add tmp, coverage, cache + - Aggressive: Most relative paths + +2. **Should sudo ever be auto-allowed?** + - My recommendation: Only for systemctl, journalctl + - Alternative: All sudo requires ask + +3. **Force-push protection:** + - Should we deny force-push to main/master? + - Or trust branch protection rules on GitHub? + - What about other important branches (develop, staging)? + +4. **Pattern explosion:** + - Are you OK maintaining more granular rules? + - Or prefer fewer, broader patterns with more asks? diff --git a/doc/claude-permissions-wildcard-safety.md b/doc/claude-permissions-wildcard-safety.md new file mode 100644 index 0000000..ea9eb49 --- /dev/null +++ b/doc/claude-permissions-wildcard-safety.md @@ -0,0 +1,319 @@ +# Permission Wildcard Safety Analysis + +## The Problem with Trailing Wildcards + +### Current Pattern (Potentially Dangerous) + +```json +"Bash(rm -rf node_modules:*)" +``` + +This matches: +- ✅ `rm -rf node_modules` - Safe +- ✅ `rm -rf node_modules/` - Safe +- ⚠️ `rm -rf node_modules --verbose` - Probably safe +- 🚫 `rm -rf node_modules ../important-dir` - **DANGEROUS!** +- 🚫 `rm -rf node_modules /tmp/secrets` - **DANGEROUS!** + +The `:*` wildcard means "with any additional arguments", which could include additional paths to delete! + +### How Permission Matching Works + +Claude Code permission format: +``` +Bash(command args:wildcard) +``` + +- `command` - The actual command (rm, git, etc.) +- `args` - Specific arguments to match +- `:*` - Wildcard for additional arguments + +Examples: +- `Bash(git status:*)` - Matches `git status` with any extra args +- `Bash(npm install:*)` - Matches `npm install` plus anything after +- `Bash(rm -rf node_modules:*)` - Matches `rm -rf node_modules` plus anything after (DANGER!) + +## Safer Alternatives + +### Option 1: Exact Match (Most Restrictive) + +```json +{ + "allow": [ + "Bash(rm -rf node_modules)", + "Bash(rm -rf dist)", + "Bash(rm -rf build)" + ] +} +``` + +**Pros:** +- Maximum safety - only exact command is allowed +- No risk of additional paths being deleted + +**Cons:** +- Doesn't support useful flags like `-v` (verbose) +- Might not match if shell expands paths (e.g., `rm -rf ./node_modules`) + +### Option 2: Specific Safe Variations + +```json +{ + "allow": [ + "Bash(rm -rf node_modules)", + "Bash(rm -rf ./node_modules)", + "Bash(rm -rf node_modules/)", + "Bash(rm -rf ./node_modules/)", + "Bash(rm -rf dist)", + "Bash(rm -rf ./dist)", + "Bash(rm -rf build)", + "Bash(rm -rf ./build)" + ] +} +``` + +**Pros:** +- Covers common path variations +- Still very safe - no extra arguments + +**Cons:** +- More verbose +- Still doesn't support flags + +### Option 3: Pattern-Based Validation (Ideal but Complex) + +What we'd ideally want: +``` +Allow "rm -rf X" where X matches safe patterns and no additional args +``` + +This would require custom logic that Claude Code may not support. + +### Option 4: Keep Wildcards but Add Dangerous Patterns to Deny + +```json +{ + "allow": [ + "Bash(rm -rf node_modules:*)", + "Bash(rm -rf dist:*)" + ], + "deny": [ + "Bash(rm -rf node_modules /:*)", + "Bash(rm -rf node_modules ~:*)", + "Bash(rm -rf node_modules ..:*)", + "Bash(rm -rf node_modules /*:*)", + "Bash(rm -rf dist /:*)", + "Bash(rm -rf dist ~:*)" + // ... would need to enumerate many dangerous combinations + ] +} +``` + +**Pros:** +- Allows flags and variations + +**Cons:** +- Deny rules may not work as expected (allow might take precedence) +- Hard to enumerate all dangerous patterns +- Still leaves gaps + +## Real-World Risk Assessment + +### How likely is exploitation? + +**Accidental:** +- Low risk - Claude is unlikely to accidentally add dangerous extra paths +- Most commands are generated as single targets + +**Malicious:** +- Could a malicious prompt trick Claude into `rm -rf node_modules /important`? +- Possible, but would require specific prompt injection +- Multiple layers of defense (Claude's safety training, permission prompts) + +### Comparison with Other Permissions + +**Current wildcards that are probably fine:** +```json +"Bash(npm install:*)" // Extra args are package names - safe +"Bash(git status:*)" // Extra args are paths/flags - safe +"Bash(jq:*)" // Extra args are filters/files - safe +``` + +**Current wildcards that are concerning:** +```json +"Bash(rm -rf node_modules:*)" // Extra args could be more paths +"Bash(rm -rf dist:*)" // Same issue +"Bash(sudo systemctl:*)" // Extra args... probably ok? +``` + +## Recommendations + +### Conservative Approach (Recommended) + +Remove the trailing `:*` from rm commands: + +```json +{ + "allow": [ + "Bash(rm -rf node_modules)", + "Bash(rm -rf ./node_modules)", + "Bash(rm -rf dist)", + "Bash(rm -rf ./dist)", + "Bash(rm -rf build)", + "Bash(rm -rf ./build)", + "Bash(rm -rf target)", + "Bash(rm -rf ./target)", + "Bash(rm -rf coverage)", + "Bash(rm -rf ./coverage)", + "Bash(rm -rf tmp)", + "Bash(rm -rf ./tmp)", + "Bash(rm -rf temp)", + "Bash(rm -rf ./temp)", + "Bash(rm -rf .cache)", + "Bash(rm -rf .next)", + "Bash(rm -rf out)", + "Bash(rm -rf .pytest_cache)", + "Bash(rm -rf .rspec_cache)", + "Bash(rm -rf .DS_Store)", + "Bash(rm -rf .tmp)", + "Bash(rm -rf .coverage)", + "Bash(rm -rf .gradle)", + "Bash(rm -rf vendor)", + "Bash(rm -rf pkg)" + ] +} +``` + +**Rationale:** +- `rm` commands rarely need additional arguments beyond the path +- The safety benefit outweighs the minor inconvenience +- If you need verbose output, you can approve it when prompted + +### Moderate Approach + +Keep wildcards for commands where extra args are clearly safe: + +```json +{ + "allow": [ + // rm commands - no wildcards + "Bash(rm -rf node_modules)", + "Bash(rm -rf dist)", + + // Other commands - wildcards ok + "Bash(npm install:*)", // Extra args are packages + "Bash(git status:*)", // Extra args are paths + "Bash(sudo systemctl:*)" // Extra args are services + ] +} +``` + +### What About sudo Commands? + +Current patterns: +```json +"Bash(sudo systemctl start:*)", +"Bash(sudo systemctl stop:*)", +"Bash(sudo docker:*)" +``` + +**Analysis:** +- `sudo systemctl start:*` - Extra args are service names (safe) +- `sudo docker:*` - Extra args are docker commands (safe) +- These wildcards are probably fine + +## Testing the Risk + +You can test whether wildcards allow multiple paths: + +```bash +# If you have the current permissions: +# Does this get allowed or blocked? +rm -rf node_modules /tmp/test-danger +``` + +If it's **allowed**, the wildcards are dangerous. +If it's **blocked**, maybe Claude Code has additional parsing that prevents this. + +## Implementation Plan + +1. **Test current behavior** to understand how wildcards work +2. **If dangerous:** Update `permissions.json` to remove `:*` from rm commands +3. **Regenerate:** Run `./claudeconfig.sh` +4. **Validate:** Try common operations still work +5. **Monitor:** Watch for legitimate operations being blocked + +## Specific Changes Needed + +### File: `claude/permissions.json` + +**Current (potentially unsafe):** +```json +{ + "allow": [ + "Bash(rm -rf node_modules:*)", + "Bash(rm -rf dist:*)", + "Bash(rm -rf build:*)", + "Bash(rm -rf target:*)", + "Bash(rm -rf .next:*)", + "Bash(rm -rf out:*)", + "Bash(rm -rf coverage:*)", + "Bash(rm -rf .coverage:*)", + "Bash(rm -rf .pytest_cache:*)", + "Bash(rm -rf .rspec_cache:*)", + "Bash(rm -rf tmp:*)", + "Bash(rm -rf .tmp:*)", + "Bash(rm -rf temp:*)", + "Bash(rm -rf .cache:*)", + "Bash(rm -rf vendor:*)", + "Bash(rm -rf pkg:*)", + "Bash(rm -rf .gradle:*)", + "Bash(rm -rf .DS_Store:*)" + ] +} +``` + +**Proposed (safer):** +```json +{ + "allow": [ + "Bash(rm -rf node_modules)", + "Bash(rm -rf ./node_modules)", + "Bash(rm -rf dist)", + "Bash(rm -rf ./dist)", + "Bash(rm -rf build)", + "Bash(rm -rf ./build)", + "Bash(rm -rf target)", + "Bash(rm -rf ./target)", + "Bash(rm -rf .next)", + "Bash(rm -rf ./. next)", + "Bash(rm -rf out)", + "Bash(rm -rf ./out)", + "Bash(rm -rf coverage)", + "Bash(rm -rf ./coverage)", + "Bash(rm -rf .coverage)", + "Bash(rm -rf .pytest_cache)", + "Bash(rm -rf .rspec_cache)", + "Bash(rm -rf tmp)", + "Bash(rm -rf ./tmp)", + "Bash(rm -rf .tmp)", + "Bash(rm -rf temp)", + "Bash(rm -rf ./temp)", + "Bash(rm -rf .cache)", + "Bash(rm -rf vendor)", + "Bash(rm -rf ./vendor)", + "Bash(rm -rf pkg)", + "Bash(rm -rf ./pkg)", + "Bash(rm -rf .gradle)", + "Bash(rm -rf .DS_Store)" + ] +} +``` + +Note: Doubled entries for with/without `./` prefix to handle different shell behaviors. + +## Conclusion + +**The trailing wildcards on rm -rf commands are a potential security risk.** While the practical risk is low (Claude is unlikely to generate malicious commands), the defense-in-depth principle suggests removing them. + +**Recommendation:** Remove `:*` from all `rm -rf` permissions and instead enumerate the common path variations (`./node_modules` vs `node_modules`). From f3293d46b68e0b04a22697194525aab4e9d6f153 Mon Sep 17 00:00:00 2001 From: Josh Nichols Date: Sun, 25 Jan 2026 14:28:32 -0500 Subject: [PATCH 2/3] feat(claude): add permissions-manager skill New local skill for analyzing and managing Claude Code permissions. Features: - analyze: Aggregate permissions and generate recommendations - apply: Interactively apply permission changes - review: Quick permission state overview Privacy & security: - Automatic redaction of project names and private info - Timestamped documentation safe for commits - Wildcard safety analysis - Interactive confirmation before changes Includes helper scripts: - aggregate-permissions.sh: Gather permission data - redact-projects.sh: Sanitize documentation - analyze-wildcards.sh: Find dangerous patterns - generate-recommendations.sh: Create recommendations Co-Authored-By: Claude Opus 4.5 --- .../skills/permissions-manager/.gitignore | 18 + .../skills/permissions-manager/README.md | 323 ++++++++++++++++++ .../skills/permissions-manager/prompt.md | 290 ++++++++++++++++ .../scripts/aggregate-permissions.sh | 20 ++ .../scripts/analyze-wildcards.sh | 64 ++++ .../scripts/generate-recommendations.sh | 217 ++++++++++++ .../scripts/redact-projects.sh | 56 +++ .../skills/permissions-manager/skill.json | 24 ++ 8 files changed, 1012 insertions(+) create mode 100644 home/.claude/skills/permissions-manager/.gitignore create mode 100644 home/.claude/skills/permissions-manager/README.md create mode 100644 home/.claude/skills/permissions-manager/prompt.md create mode 100755 home/.claude/skills/permissions-manager/scripts/aggregate-permissions.sh create mode 100755 home/.claude/skills/permissions-manager/scripts/analyze-wildcards.sh create mode 100755 home/.claude/skills/permissions-manager/scripts/generate-recommendations.sh create mode 100755 home/.claude/skills/permissions-manager/scripts/redact-projects.sh create mode 100644 home/.claude/skills/permissions-manager/skill.json diff --git a/home/.claude/skills/permissions-manager/.gitignore b/home/.claude/skills/permissions-manager/.gitignore new file mode 100644 index 0000000..4fa0be7 --- /dev/null +++ b/home/.claude/skills/permissions-manager/.gitignore @@ -0,0 +1,18 @@ +# Temporary analysis files +/tmp/ +*.tmp +*.temp + +# Generated recommendations (unless intentionally committed) +recommendations-*.md + +# Aggregated data (often contains private info) +aggregate-*.txt +permissions-aggregate-*.txt + +# Backup files +*.bak +*.backup + +# OS files +.DS_Store diff --git a/home/.claude/skills/permissions-manager/README.md b/home/.claude/skills/permissions-manager/README.md new file mode 100644 index 0000000..8d4d701 --- /dev/null +++ b/home/.claude/skills/permissions-manager/README.md @@ -0,0 +1,323 @@ +# Permissions Manager Skill + +A Claude Code skill for analyzing, documenting, and maintaining permissions across projects. + +## Purpose + +This skill helps you: + +- **Analyze** permissions across all projects to find patterns +- **Generate** recommendations for promoting common permissions to global +- **Document** permission changes with redacted, timestamped reports +- **Apply** changes interactively with safety checks +- **Maintain** a clean, centralized permission configuration + +## Installation + +This skill is part of the dotfiles repository and is automatically installed when you run `install.sh`. It will be symlinked to `~/.claude/skills/permissions-manager/`. + +## Commands + +### `/permissions-manager analyze` + +Analyzes current permissions and generates a recommendations document. + +**What it does:** +1. Runs `claude-permissions --aggregate` to gather data +2. Analyzes frequency of each permission across projects +3. Identifies dangerous wildcard patterns +4. Generates timestamped recommendations document +5. Redacts all project names and private information + +**Output:** +- `doc/permissions-analysis-YYYY-MM-DD.md` (safe to commit) +- Shows high/medium frequency patterns +- Lists security concerns +- Provides specific recommendations + +**Example:** +```bash +/permissions-manager analyze +``` + +### `/permissions-manager apply` + +Interactively applies recommended permission changes. + +**What it does:** +1. Shows you each recommended change +2. Asks for confirmation before applying +3. Updates permission files in `claude/` +4. Regenerates `~/.claude/settings.json` +5. Optionally runs cleanup to remove duplicates +6. Creates change summary document + +**Safety features:** +- Always asks before making changes +- Shows exactly what will change +- Can skip individual changes +- Creates timestamped summary +- Suggests commit message + +**Example:** +```bash +/permissions-manager apply +``` + +### `/permissions-manager review` + +Quick review of current permission state. + +**What it does:** +1. Shows current allow/ask/deny counts +2. Lists all permission files +3. Shows recent permission-related commits +4. Checks for common issues + +**Example:** +```bash +/permissions-manager review +``` + +## Privacy & Security + +### Redaction + +All generated documentation is **automatically redacted** to remove: + +- Project names → `Project-01`, `Project-02`, etc. +- File paths → ``, ``, `` +- Internal domains → `*.company.com` → `*.` +- API keys/tokens → `` + +This makes the documentation safe to commit to public repositories. + +### Security Analysis + +The skill automatically checks for: + +- **Dangerous wildcards**: `rm -rf path:*` that could match multiple targets +- **Overly broad permissions**: `sudo:*` without restrictions +- **Pipe-to-shell**: `curl * | bash` in allow list +- **Missing protections**: Force-push to main/master not denied + +## Workflow Example + +### Initial Analysis + +```bash +# In your dotfiles directory +/permissions-manager analyze +``` + +This creates `doc/permissions-analysis-2026-01-25.md` with recommendations. + +### Review Recommendations + +Open the generated file and review: +- High-frequency patterns (4+ projects) +- Medium-frequency patterns (2-3 projects) +- Security improvements needed +- Suggested deny → ask changes + +### Apply Changes + +```bash +/permissions-manager apply +``` + +You'll be asked about each change: +``` +Add to permissions.shell.json: + - Bash(sqlite3:*) +Apply this change? (yes/no/skip all): yes + +Remove dangerous wildcard: + - Bash(rm -rf build:*) → Bash(rm -rf build) +Apply this change? (yes/no/skip all): yes +``` + +### Verify + +```bash +/permissions-manager review +``` + +Check that counts look reasonable and recent commit shows your changes. + +### Cleanup + +The skill will ask: +``` +Run cleanup to remove 37 duplicate permissions from 16 projects? +(yes/no): yes +``` + +### Commit + +The skill suggests a commit message: +``` +feat(claude): consolidate permissions based on frequency analysis + +Promoted 12 high-frequency permissions to global. +Removed 5 dangerous wildcards from rm commands. +Changed 3 deny rules to ask for better UX. + +Co-Authored-By: Claude Opus 4.5 +``` + +## Helper Scripts + +Located in `scripts/` directory: + +### aggregate-permissions.sh + +```bash +./scripts/aggregate-permissions.sh [output-file] +``` + +Runs `claude-permissions --aggregate` and saves output with stats. + +### redact-projects.sh + +```bash +./scripts/redact-projects.sh input-file [output-file] +``` + +Redacts all private information from a file. Uses project name mapping. + +### analyze-wildcards.sh + +```bash +./scripts/analyze-wildcards.sh [settings-file] +``` + +Analyzes wildcards in permissions, categorizing as dangerous/safe. + +### generate-recommendations.sh + +```bash +./scripts/generate-recommendations.sh aggregate-file [output-file] +``` + +Parses aggregated permissions and generates structured recommendations. + +## Integration with Dotfiles + +This skill integrates with: + +- **`claude/` directory**: Permission files +- **`claudeconfig.sh`**: Settings regeneration +- **`claude-permissions`**: Analysis tool +- **`.git`**: For commit suggestions + +## Configuration + +The skill uses these environment variables (optional): + +- `PERMISSIONS_THRESHOLD_HIGH`: Frequency for high-priority (default: 4) +- `PERMISSIONS_THRESHOLD_MEDIUM`: Frequency for medium-priority (default: 2) +- `PERMISSIONS_WORKSPACE`: Workspace directory (default: `~/workspace`) + +## Best Practices + +1. **Run analysis regularly**: After adding new projects or making changes +2. **Review before applying**: Not all recommendations should be followed +3. **Test after changes**: Ensure workflows still work +4. **Commit redacted docs**: They're safe for public repos +5. **Iterate**: Run cleanup periodically to stay centralized + +## Troubleshooting + +### "No recommendations found" + +- Check if `claude-permissions` is installed +- Verify you have project-local permissions to analyze +- Try running `claude-permissions --aggregate` manually + +### "Redaction failed" + +- Ensure `scripts/redact-projects.sh` is executable +- Check that workspace directory exists +- Verify perl is installed + +### "Apply failed" + +- Check file permissions in `claude/` directory +- Ensure `claudeconfig.sh` is executable +- Verify `jq` is installed +- Check git repo is clean (no merge conflicts) + +### "Settings not regenerated" + +- Run `./claudeconfig.sh` manually +- Check for errors in the output +- Verify all JSON files are valid + +## Examples + +### Full Workflow + +```bash +# 1. Analyze current state +/permissions-manager analyze +# Creates: doc/permissions-analysis-2026-01-25.md + +# 2. Review the recommendations +cat doc/permissions-analysis-2026-01-25.md + +# 3. Apply selected changes +/permissions-manager apply +# Interactive prompts guide you through + +# 4. Verify results +/permissions-manager review + +# 5. Check generated change summary +cat doc/permissions-changes-2026-01-25.md +``` + +### Quick Security Check + +```bash +# Just check for dangerous patterns +./scripts/analyze-wildcards.sh +``` + +### Manual Redaction + +```bash +# Redact any file +./scripts/redact-projects.sh doc/my-analysis.txt +# Creates: doc/my-analysis.txt.redacted +``` + +## Future Enhancements + +Potential improvements: + +- **Diff mode**: Show before/after side-by-side +- **Test mode**: Simulate permissions to see what would be blocked +- **Export/import**: Share permission configs between machines +- **Validation**: Detect conflicts between allow/deny +- **CI integration**: Run analysis in CI pipeline + +## See Also + +- [Claude Permissions Documentation](../../../claude/CLAUDE.md) +- [Permissions Analysis Template](../../../doc/claude-permissions-analysis.md) +- [Safe Patterns Guide](../../../doc/claude-permissions-safe-patterns.md) +- [Wildcard Safety](../../../doc/claude-permissions-wildcard-safety.md) + +## Support + +This skill is part of your personal dotfiles. For issues: + +1. Check the troubleshooting section above +2. Review the generated logs +3. Test individual scripts manually +4. Check Claude Code logs: `~/.claude/logs/` + +## License + +Part of the dotfiles repository. Private use. diff --git a/home/.claude/skills/permissions-manager/prompt.md b/home/.claude/skills/permissions-manager/prompt.md new file mode 100644 index 0000000..3d6ff1d --- /dev/null +++ b/home/.claude/skills/permissions-manager/prompt.md @@ -0,0 +1,290 @@ +# Permissions Manager Skill + +You are a Claude Code permissions management assistant. Your role is to help analyze, document, and maintain Claude Code permissions across projects. + +## Core Principles + +1. **Security First**: Prefer exact matches over wildcards for destructive operations +2. **Three-Tier System**: Allow (safe), Ask (moderate risk), Deny (catastrophic) +3. **Privacy**: Redact project names and paths from documentation +4. **Timestamped Docs**: All generated documentation includes ISO timestamps + +## Commands + +### `/permissions-manager analyze` + +**Purpose**: Analyze current permissions and generate recommendations. + +**Workflow**: + +1. **Gather Data**: + ```bash + claude-permissions --aggregate > /tmp/permissions-analysis-$(date +%s).txt + ``` + +2. **Analyze Patterns**: + - Count frequency of each permission across projects + - Identify candidates for promotion to global (appearing 2+ times) + - Check for dangerous wildcards (`:*` on rm, sudo, etc.) + - Find missing ecosystem files for commonly-used tools + +3. **Generate Recommendations**: + - High priority: 4+ occurrences + - Medium priority: 2-3 occurrences + - Check for deny rules that could be ask + - Identify unsafe wildcard patterns + +4. **Create Documentation**: + - Generate timestamped analysis file: `doc/permissions-analysis-YYYY-MM-DD.md` + - Include: + - Current permission stats (allow/ask/deny counts) + - Frequency analysis (REDACTED project names) + - Recommendations by priority + - Security concerns + - Proposed changes + - **IMPORTANT**: Redact all project names, replace with generic "Project A", "Project B", etc. + +5. **Output Format**: + ```markdown + # Claude Permissions Analysis + + **Generated**: YYYY-MM-DDTHH:MM:SSZ + **Analyzer Version**: 1.0.0 + + ## Current State + + | Metric | Count | + |--------|-------| + | Allow | XXX | + | Ask | XXX | + | Deny | XXX | + + ## High-Frequency Patterns (4+ occurrences) + + - `Bash(command:*)` - 5 occurrences across 5 projects + + ## Medium-Frequency Patterns (2-3 occurrences) + + - `Bash(tool:*)` - 3 occurrences across 3 projects + + ## Recommendations + + ### Promote to Global + + 1. Add to `permissions.shell.json`: + - `Bash(common-tool:*)` + + ### Security Improvements + + 1. Remove dangerous wildcards from: + - `Bash(rm -rf path:*)` → `Bash(rm -rf path)` + + ### Consider Ask Instead of Deny + + 1. `Bash(potentially-useful-command:*)` - appears in X projects + ``` + +### `/permissions-manager apply` + +**Purpose**: Interactively apply permission changes. + +**Workflow**: + +1. **Ask for confirmation** before making any changes: + - "Ready to apply permission changes? This will modify files in claude/ directory." + +2. **For each recommendation**: + - Show the specific change + - Ask: "Apply this change? (yes/no/skip all)" + - If yes: Make the change + - Track all changes made + +3. **After all changes**: + - Run `./claudeconfig.sh` to regenerate settings + - Run `claude-permissions cleanup --dry-run` to preview cleanup + - Ask: "Run cleanup? This will remove duplicate permissions from projects." + - If yes: Run `claude-permissions cleanup --force` + +4. **Create summary document**: + - Generate `doc/permissions-changes-YYYY-MM-DD.md` + - List all changes made + - Include before/after stats + - Note which files were modified/created + +5. **Suggest commit**: + - Show proposed commit message + - Ask if user wants to commit + +### `/permissions-manager review` + +**Purpose**: Review current permission configuration. + +**Workflow**: + +1. **Display current stats**: + ```bash + jq '.permissions | { + allow: (.allow | length), + ask: (.ask | length), + deny: (.deny | length) + }' ~/.claude/settings.json + ``` + +2. **List permission files**: + ```bash + ls -1 claude/permissions*.json* + ``` + +3. **Show recent changes**: + ```bash + git log --oneline --grep="permission" -5 + ``` + +4. **Check for issues**: + - Dangerous wildcards in allow list + - Overly broad deny rules + - Missing common ecosystems + +## Privacy & Redaction + +When generating documentation, **always redact** private information: + +- **Project names**: Replace with "Project A", "Project B", etc. +- **File paths**: Replace with relative paths or `/path` +- **Domain names**: Keep only well-known public domains +- **Command arguments**: Redact specific values, keep patterns + +**Example Redaction**: +``` +Before: gusto-app/api/users +After: Project-A/api/users + +Before: ~/workspace/client-project +After: + +Before: internal-tool.company.com +After: +``` + +## Wildcard Safety Analysis + +When reviewing permissions, flag these dangerous patterns: + +### Unsafe Wildcards + +1. **rm with wildcards**: `Bash(rm -rf target:*)` + - Risk: Could match `rm -rf target /important` + - Fix: Use exact match `Bash(rm -rf target)` + +2. **sudo with broad wildcards**: `Bash(sudo:*)` + - Risk: Allows any sudo command + - Fix: Be specific about allowed sudo operations + +3. **Pipe to shell**: `Bash(curl * | bash)` + - Risk: Executes arbitrary remote code + - Fix: Always deny, or allow specific trusted sources only + +### Safe Wildcards + +1. **Tools with arguments**: `Bash(npm install:*)` + - Safe: Extra args are package names + - OK: Wildcard is appropriate here + +2. **Read-only operations**: `Bash(git log:*)` + - Safe: Read-only, extra args are filters + - OK: Wildcard is appropriate here + +## Helper Scripts + +The skill includes these helper scripts in `scripts/`: + +- `aggregate-permissions.sh` - Gather permission data +- `redact-projects.sh` - Redact private information from docs +- `analyze-wildcards.sh` - Find potentially dangerous wildcards +- `generate-recommendations.sh` - Create recommendation list + +## File Structure + +``` +home/.claude/skills/permissions-manager/ +├── skill.json # Skill manifest +├── prompt.md # This file +├── scripts/ +│ ├── aggregate-permissions.sh +│ ├── redact-projects.sh +│ ├── analyze-wildcards.sh +│ └── generate-recommendations.sh +└── README.md # User documentation +``` + +## Usage Examples + +### Full Analysis Workflow + +```bash +/permissions-manager analyze +# Reviews permissions, generates recommendations doc + +/permissions-manager apply +# Interactively applies recommended changes + +/permissions-manager review +# Shows current state after changes +``` + +### Quick Check + +```bash +/permissions-manager review +# Just see current stats and recent changes +``` + +## Best Practices + +1. **Run analysis before major changes**: Understand the current state +2. **Review recommendations carefully**: Not all high-frequency patterns should be promoted +3. **Test after applying**: Ensure common workflows still work +4. **Commit docs**: Analysis docs (redacted) are safe to commit +5. **Iterate**: Run cleanup periodically to keep permissions centralized + +## Integration with Dotfiles + +This skill is part of the dotfiles repository and: +- Lives in `home/.claude/skills/permissions-manager/` +- Gets symlinked to `~/.claude/skills/permissions-manager/` during install +- Works with the permission system defined in `claude/` +- Uses `claudeconfig.sh` for regeneration +- Integrates with `claude-permissions` tool + +## Security Notes + +- Never auto-apply changes without user confirmation +- Always show what will change before modifying files +- Preserve local-only settings (awsAuthRefresh, env) +- Backup settings.json before major changes +- Keep deny rules for truly dangerous operations + +## Troubleshooting + +**Issue**: Analysis shows no recommendations +- Check if `claude-permissions` is installed +- Verify you have project-local permissions to analyze + +**Issue**: Redaction not working +- Ensure `scripts/redact-projects.sh` is executable +- Check that git repo list is accessible + +**Issue**: Apply fails +- Check file permissions in `claude/` directory +- Verify `claudeconfig.sh` is executable +- Ensure `jq` is installed + +## Future Enhancements + +Potential improvements for this skill: + +1. **Machine learning**: Detect permission patterns automatically +2. **Diff visualization**: Show before/after permission diffs +3. **Test mode**: Dry-run permissions to see what would be blocked +4. **Integration**: Sync with CI/CD permission policies +5. **Validation**: Check for conflicts between allow/deny rules diff --git a/home/.claude/skills/permissions-manager/scripts/aggregate-permissions.sh b/home/.claude/skills/permissions-manager/scripts/aggregate-permissions.sh new file mode 100755 index 0000000..515b2bf --- /dev/null +++ b/home/.claude/skills/permissions-manager/scripts/aggregate-permissions.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +# Aggregate permissions from all projects +set -euo pipefail + +TIMESTAMP=$(date +%s) +OUTPUT_FILE="${1:-/tmp/permissions-aggregate-${TIMESTAMP}.txt}" + +echo "Aggregating permissions from all projects..." +echo "Output: $OUTPUT_FILE" + +# Run claude-permissions with all relevant flags +claude-permissions --aggregate > "$OUTPUT_FILE" + +echo "✓ Aggregation complete" +echo "Total lines: $(wc -l < "$OUTPUT_FILE")" +echo "" +echo "Quick stats:" +echo " Allow entries: $(grep -c "^[[:space:]]*[0-9]x " "$OUTPUT_FILE" | head -1 || echo 0)" +echo " Deny entries: $(awk '/^## deny/,/^## ask/ {print}' "$OUTPUT_FILE" | grep -c "^[[:space:]]*[0-9]x " || echo 0)" +echo " Ask entries: $(awk '/^## ask/,/^$/ {print}' "$OUTPUT_FILE" | grep -c "^[[:space:]]*[0-9]x " || echo 0)" diff --git a/home/.claude/skills/permissions-manager/scripts/analyze-wildcards.sh b/home/.claude/skills/permissions-manager/scripts/analyze-wildcards.sh new file mode 100755 index 0000000..499f746 --- /dev/null +++ b/home/.claude/skills/permissions-manager/scripts/analyze-wildcards.sh @@ -0,0 +1,64 @@ +#!/usr/bin/env bash +# Analyze permissions for potentially dangerous wildcards +set -euo pipefail + +SETTINGS_FILE="${1:-${HOME}/.claude/settings.json}" + +if [[ ! -f "$SETTINGS_FILE" ]]; then + echo "Error: Settings file not found: $SETTINGS_FILE" + exit 1 +fi + +echo "Analyzing wildcards in: $SETTINGS_FILE" +echo "" + +# Check for dangerous patterns +echo "=== DANGEROUS WILDCARDS ===" +echo "" + +# rm -rf with wildcards +echo "## rm -rf with wildcards (potential multi-path deletion):" +jq -r '.permissions.allow[]? | select(contains("rm -rf") and contains(":*"))' "$SETTINGS_FILE" || echo " (none found)" +echo "" + +# sudo with broad wildcards +echo "## sudo with broad wildcards:" +jq -r '.permissions.allow[]? | select(startswith("Bash(sudo") and endswith(":*"))' "$SETTINGS_FILE" | head -5 || echo " (none found)" +if jq -r '.permissions.allow[]? | select(startswith("Bash(sudo") and endswith(":*"))' "$SETTINGS_FILE" | wc -l | grep -q -v "^0$"; then + echo " ... (review these carefully)" +fi +echo "" + +# Pipe to shell +echo "## Pipe to shell (should be in deny, not allow):" +jq -r '.permissions.allow[]? | select(contains("| bash") or contains("| sh"))' "$SETTINGS_FILE" || echo " (none found - good!)" +echo "" + +echo "=== QUESTIONABLE WILDCARDS ===" +echo "" + +# chmod/chown in allow (should probably be ask) +echo "## File permission changes in allow (consider ask):" +jq -r '.permissions.allow[]? | select(contains("chmod") or contains("chown"))' "$SETTINGS_FILE" || echo " (none found)" +echo "" + +echo "=== SAFE WILDCARDS ===" +echo "" + +# These are generally fine +echo "## Read-only operations (usually safe):" +jq -r '.permissions.allow[]? | select(contains("git log") or contains("git status") or contains("git diff"))' "$SETTINGS_FILE" | head -3 || echo " (none found)" +echo " ... (and others)" +echo "" + +echo "## Tool-specific arguments (usually safe):" +jq -r '.permissions.allow[]? | select(contains("npm install") or contains("cargo build") or contains("go build"))' "$SETTINGS_FILE" | head -3 || echo " (none found)" +echo " ... (and others)" +echo "" + +echo "=== SUMMARY ===" +total_allow=$(jq '.permissions.allow | length' "$SETTINGS_FILE") +wildcards=$(jq -r '.permissions.allow[]? | select(endswith(":*"))' "$SETTINGS_FILE" | wc -l) +echo "Total allow entries: $total_allow" +echo "With wildcards: $wildcards" +echo "Percentage: $(awk "BEGIN {printf \"%.1f%%\", ($wildcards/$total_allow)*100}")" diff --git a/home/.claude/skills/permissions-manager/scripts/generate-recommendations.sh b/home/.claude/skills/permissions-manager/scripts/generate-recommendations.sh new file mode 100755 index 0000000..61b0135 --- /dev/null +++ b/home/.claude/skills/permissions-manager/scripts/generate-recommendations.sh @@ -0,0 +1,217 @@ +#!/usr/bin/env bash +# Generate recommendations from aggregated permissions +set -euo pipefail + +AGGREGATE_FILE="$1" +OUTPUT_FILE="${2:-recommendations-$(date +%Y%m%d-%H%M%S).md}" + +if [[ ! -f "$AGGREGATE_FILE" ]]; then + echo "Error: Aggregate file not found: $AGGREGATE_FILE" + exit 1 +fi + +echo "Generating recommendations from: $AGGREGATE_FILE" +echo "Output: $OUTPUT_FILE" + +# Extract sections +extract_section() { + local section="$1" + local file="$2" + awk "/^## $section/,/^## / {print}" "$file" | grep "^[[:space:]]*[0-9]" || echo "" +} + +# Parse frequency and command +parse_entries() { + local input="$1" + echo "$input" | while read -r line; do + if [[ -z "$line" ]]; then continue; fi + freq=$(echo "$line" | awk '{print $1}' | tr -d 'x') + cmd=$(echo "$line" | cut -d' ' -f2-) + echo "$freq|$cmd" + done +} + +# Generate markdown +cat > "$OUTPUT_FILE" </dev/null || echo "unknown") +current_ask=$(jq '.permissions.ask | length' ~/.claude/settings.json 2>/dev/null || echo "unknown") +current_deny=$(jq '.permissions.deny | length' ~/.claude/settings.json 2>/dev/null || echo "unknown") + +cat >> "$OUTPUT_FILE" <> "$OUTPUT_FILE" +echo "" >> "$OUTPUT_FILE" +extract_section "allow" "$AGGREGATE_FILE" | \ + parse_entries | \ + awk -F'|' '$1 >= 4 {print $2}' | \ + sort -u | \ + while read -r cmd; do + if [[ -n "$cmd" ]]; then + echo "- \`$cmd\`" >> "$OUTPUT_FILE" + fi + done + +if ! grep -q "^- " "$OUTPUT_FILE" | tail -10; then + echo "(No patterns found)" >> "$OUTPUT_FILE" +fi +echo "" >> "$OUTPUT_FILE" + +# Medium frequency (2-3) +echo "## Medium-Frequency Patterns (2-3 projects)" >> "$OUTPUT_FILE" +echo "" >> "$OUTPUT_FILE" +extract_section "allow" "$AGGREGATE_FILE" | \ + parse_entries | \ + awk -F'|' '$1 >= 2 && $1 <= 3 {print $2}' | \ + sort -u | \ + while read -r cmd; do + if [[ -n "$cmd" ]]; then + echo "- \`$cmd\`" >> "$OUTPUT_FILE" + fi + done + +if ! grep -q "^- " "$OUTPUT_FILE" | tail -20; then + echo "(No patterns found)" >> "$OUTPUT_FILE" +fi +echo "" >> "$OUTPUT_FILE" + +# Deny analysis +echo "## Current Deny Rules" >> "$OUTPUT_FILE" +echo "" >> "$OUTPUT_FILE" +extract_section "deny" "$AGGREGATE_FILE" | \ + parse_entries | \ + sort -rn -t'|' -k1 | \ + while IFS='|' read -r freq cmd; do + if [[ -n "$cmd" ]]; then + echo "- \`$cmd\` (appears $freq times)" >> "$OUTPUT_FILE" + fi + done +echo "" >> "$OUTPUT_FILE" + +# Ask analysis +echo "## Current Ask Rules" >> "$OUTPUT_FILE" +echo "" >> "$OUTPUT_FILE" +extract_section "ask" "$AGGREGATE_FILE" | \ + parse_entries | \ + sort -rn -t'|' -k1 | \ + while IFS='|' read -r freq cmd; do + if [[ -n "$cmd" ]]; then + echo "- \`$cmd\` (appears $freq times)" >> "$OUTPUT_FILE" + fi + done +echo "" >> "$OUTPUT_FILE" + +# Recommendations section +cat >> "$OUTPUT_FILE" <= 3 && $2 ~ /^Bash\([a-z]+:/ {print $2}' | \ + grep -v "git\|npm\|cargo\|bundle\|pip" | \ + sort -u | \ + head -10 | \ + while read -r cmd; do + if [[ -n "$cmd" ]]; then + echo "- \`$cmd\`" >> "$OUTPUT_FILE" + fi + done + +cat >> "$OUTPUT_FILE" <= 2 {print $2}' | \ + grep -oE "Bash\([a-z]+" | \ + sed 's/Bash(//' | \ + sort | uniq -c | sort -rn | head -10 | \ + awk '{if ($1 >= 3) print "- `permissions." $2 ".json` (" $1 " commands)"}' \ + >> "$OUTPUT_FILE" + +cat >> "$OUTPUT_FILE" </dev/null | \ + while read -r perm; do + echo "- \`$perm\` → Use exact match" >> "$OUTPUT_FILE" + done || echo "- (No dangerous rm -rf wildcards found)" >> "$OUTPUT_FILE" + +cat >> "$OUTPUT_FILE" <> "$OUTPUT_FILE" + fi + done + +cat >> "$OUTPUT_FILE" <|g' "$OUTPUT_FILE" +perl -i -pe 's|/Users/[^/\s]+/workspace||g' "$OUTPUT_FILE" +perl -i -pe 's|/Users/[^/\s]+||g' "$OUTPUT_FILE" + +# Redact internal domains (keep common ones) +perl -i -pe 's/([a-z0-9-]+\.)(internal|corp|local)\b/$1/g' "$OUTPUT_FILE" + +# Redact API keys and tokens (just in case) +perl -i -pe 's/[A-Za-z0-9]{32,}//g' "$OUTPUT_FILE" + +echo "✓ Redaction complete" +echo "Total substitutions: $(grep -o "\|\|\|\|" "$OUTPUT_FILE" | wc -l)" diff --git a/home/.claude/skills/permissions-manager/skill.json b/home/.claude/skills/permissions-manager/skill.json new file mode 100644 index 0000000..c6983d1 --- /dev/null +++ b/home/.claude/skills/permissions-manager/skill.json @@ -0,0 +1,24 @@ +{ + "name": "permissions-manager", + "version": "1.0.0", + "description": "Analyze and manage Claude Code permissions across projects", + "author": "Josh Nichols", + "commands": [ + { + "name": "analyze", + "description": "Analyze permissions and generate recommendations", + "args": [] + }, + { + "name": "apply", + "description": "Apply permission changes interactively", + "args": [] + }, + { + "name": "review", + "description": "Review current permission configuration", + "args": [] + } + ], + "systemPromptFile": "prompt.md" +} From f81a17b5b730988e010fed0d608335a4723eaf5d Mon Sep 17 00:00:00 2001 From: Josh Nichols Date: Sun, 25 Jan 2026 19:01:55 -0500 Subject: [PATCH 3/3] refactor(permissions-manager): move docs into skill and use timestamped output Changes: - Removed point-in-time analysis docs from repo (will be regenerated) - Moved general reference guides into skill docs directory - Updated skill to output to doc/permissions/YYYY-MM-DD/ instead of doc/ - Added doc/permissions/ to .gitignore for generated output - Skill now creates timestamped directories for all generated files Generated docs are now: - Organized by date in doc/permissions/YYYY-MM-DD/ - Automatically gitignored - Reference guides live in skill docs for easy access Co-Authored-By: Claude Opus 4.5 --- .gitignore | 3 + doc/claude-permissions-analysis.md | 386 ------------------ doc/claude-permissions-changes-summary.md | 340 --------------- .../skills/permissions-manager/README.md | 18 +- .../permissions-manager/docs/safe-patterns.md | 0 .../docs/wildcard-safety.md | 0 .../skills/permissions-manager/prompt.md | 10 +- 7 files changed, 20 insertions(+), 737 deletions(-) delete mode 100644 doc/claude-permissions-analysis.md delete mode 100644 doc/claude-permissions-changes-summary.md rename doc/claude-permissions-safe-patterns.md => home/.claude/skills/permissions-manager/docs/safe-patterns.md (100%) rename doc/claude-permissions-wildcard-safety.md => home/.claude/skills/permissions-manager/docs/wildcard-safety.md (100%) diff --git a/.gitignore b/.gitignore index 45749a4..77aca5e 100644 --- a/.gitignore +++ b/.gitignore @@ -156,6 +156,9 @@ home/.claude/* .claude/skills/ .claude/settings.local.json +# permissions-manager skill generated output +doc/permissions/ + # vagrant .vagrant .vagrant/**/* diff --git a/doc/claude-permissions-analysis.md b/doc/claude-permissions-analysis.md deleted file mode 100644 index d0b4d8c..0000000 --- a/doc/claude-permissions-analysis.md +++ /dev/null @@ -1,386 +0,0 @@ -# Claude Permissions Analysis - -Generated: 2026-01-24 - -## Executive Summary - -This analysis reviews all Claude Code permissions across global and project-specific settings to identify opportunities for simplification and permission policy improvements. - -### Key Findings - -1. **27 candidate permissions** appearing 2+ times across projects that could be promoted to global -2. **6 deny rules** that could potentially be changed to ask for better UX -3. **Missing ecosystem files** for commonly-used tools (colima, sqlite, yamllint, bash, beans) -4. **Well-organized structure** with good separation of concerns - -## Current Permission Structure - -### Global Permission Files - -| File | Purpose | Entries (allow/ask/deny) | -|------|---------|-------------------------| -| `permissions.json` | Base deny rules | 0 / 0 / 4 | -| `permissions.skills.json` | Cross-project skills | 27 / 0 / 0 | -| `permissions.shell.json` | Shell utilities | 41 / 2 / 0 | -| `permissions.git.jsonc` | Git operations | 31 / 0 / 4 | -| `permissions.github.json` | GitHub CLI | 25 / 0 / 0 | -| `permissions.node.json` | Node.js ecosystem | 30 / 0 / 0 | -| `permissions.ruby.json` | Ruby ecosystem | 45 / 0 / 0 | -| `permissions.python.json` | Python ecosystem | 38 / 0 / 0 | -| `permissions.go.json` | Go ecosystem | 27 / 0 / 0 | -| `permissions.rust.json` | Rust ecosystem | 26 / 0 / 0 | -| `permissions.docker.json` | Docker/containers | 24 / 0 / 0 | -| `permissions.mise.json` | mise version manager | 18 / 0 / 0 | -| `permissions.mcp.json` | MCP tools | 5 / 0 / 1 | -| `permissions.web.json` | WebFetch domains | 4 / 0 / 0 | -| `permissions.work.json` | Work-specific | 5 / 0 / 0 | -| `permissions.personal.json` | Personal-specific | 0 / 0 / 0 | - -**Total: 346 allow, 2 ask, 9 deny** - -## Recommendations - -### 1. Promote Frequently-Used Project Permissions to Global - -These permissions appear in 2+ projects and are good candidates for global inclusion: - -#### High Priority (4+ occurrences) - -```json -// Add to permissions.shell.json -"Bash(bash:*)", - -// Already covered by permissions.github.json (gh pr create, etc.) -// but could add wildcard for simplicity: -"Bash(gh pr:*)" -``` - -#### Medium Priority (2-3 occurrences) - -**Shell utilities** (add to `permissions.shell.json`): -```json -"Bash(pkill:*)", -"Bash(sqlite3:*)", -"Bash(yamllint:*)" -``` - -**Container management** (add to `permissions.docker.json` or new `permissions.colima.json`): -```json -"Bash(colima ssh:*)", -"Bash(colima start:*)", -"Bash(colima status:*)", -"Bash(colima stop:*)", -"Bash(colima:*)" -``` - -**Git operations** (already covered by `git remote:*` in git.jsonc): -```json -// No action needed - git remote set-url is covered by git remote:* -``` - -**Work-specific tools** (add to `permissions.work.json`): -```json -"Bash(npx bktide:*)", -"Bash(bin/schemaflow:*)" -``` - -**Documentation sites** (add to `permissions.web.json`): -```json -"WebFetch(domain:hk.jdx.dev)", -"WebFetch(domain:karafka.io)", -"WebFetch(domain:lima-vm.io)", -"WebFetch(domain:mise.jdx.dev)" -``` - -### 2. Create New Ecosystem Permission Files - -#### `permissions.colima.json` -```json -{ - "allow": [ - "Bash(colima delete:*)", - "Bash(colima kubernetes:*)", - "Bash(colima list:*)", - "Bash(colima ssh:*)", - "Bash(colima ssh-config:*)", - "Bash(colima start:*)", - "Bash(colima status:*)", - "Bash(colima stop:*)", - "Bash(colima template:*)", - "Bash(colima version:*)", - "Bash(colima:*)" - ], - "deny": [] -} -``` - -#### `permissions.beans.json` -```json -{ - "allow": [ - "Bash(beans create:*)", - "Bash(beans list:*)", - "Bash(beans query:*)", - "Bash(beans show:*)", - "Bash(beans update:*)", - "Bash(beans:*)" - ], - "ask": [ - "Bash(beans archive:*)", - "Bash(beans delete:*)" - ], - "deny": [] -} -``` - -### 3. Convert Deny to Ask for Selective Approval - -Several currently-denied operations are sometimes necessary and could use `ask` instead: - -#### Change in `permissions.json` - -**Current:** -```json -{ - "deny": [ - "Bash(curl * | bash)", - "Bash(curl * | sh)", - "Bash(rm -rf:*)", - "Bash(sudo:*)" - ] -} -``` - -**Recommended:** -```json -{ - "ask": [ - "Bash(rm -rf /*)", // Only ask for root-level rm -rf - "Bash(sudo rm:*)", // Ask for destructive sudo operations - "Bash(sudo shutdown:*)", - "Bash(sudo reboot:*)" - ], - "deny": [ - "Bash(curl * | bash)", // Keep these as deny - very dangerous - "Bash(curl * | sh)" - ] -} -``` - -**Rationale:** `sudo` and `rm -rf` are sometimes needed for legitimate operations. Using `ask` provides a safety gate while maintaining flexibility. Keep pipe-to-shell as deny since it's rarely needed and highly dangerous. - -#### Change in `permissions.git.jsonc` - -**Current:** -```json -{ - "deny": [ - "Bash(git clean -fd:*)", - "Bash(git push --force:*)", - "Bash(git push -f:*)", - "Bash(git reset --hard:*)" - ] -} -``` - -**Recommended:** -```json -{ - "ask": [ - "Bash(git clean -fd:*)", // Sometimes needed to clean build artifacts - "Bash(git push --force:*)", // Needed after rebases (ask prevents accidents) - "Bash(git push -f:*)", - "Bash(git reset --hard:*)" // Useful for abandoning local changes - ], - "deny": [ - "Bash(git push --force origin main:*)", // Protect main branch - "Bash(git push --force origin master:*)", // Protect master branch - "Bash(git push -f origin main:*)", - "Bash(git push -f origin master:*)" - ] -} -``` - -**Rationale:** These operations are part of normal git workflows (especially with rebase-based workflows), but benefit from confirmation prompts. Specifically deny force-push to main/master branches. - -#### Change in `permissions.mcp.json` - -**Current:** -```json -{ - "deny": ["mcp__MCPProxy__call_tool_destructive"] -} -``` - -**Consider:** -```json -{ - "ask": ["mcp__MCPProxy__call_tool_destructive"] -} -``` - -**Rationale:** If a destructive MCP tool is needed, user can approve it. Complete denial may be too restrictive. - -### 4. Consolidate Wildcards - -Some permission files could be simplified by using broader wildcards where appropriate: - -#### `permissions.github.json` - Simplification Opportunity - -**Current:** 25 specific `gh` commands - -**Alternative (more permissive):** -```json -{ - "allow": [ - "Bash(gh:*)" // Trust all gh CLI operations - ], - "ask": [ - "Bash(gh repo delete:*)", // Destructive operations still ask - "Bash(gh secret delete:*)" - ], - "deny": [] -} -``` - -**Recommendation:** Keep current granular approach - it provides better visibility and control. - -### 5. Add Missing Common Tools - -Add to `permissions.shell.json`: -```json -"Bash(awk:*)", -"Bash(base64:*)", -"Bash(basename:*)", -"Bash(cut:*)", -"Bash(date:*)", -"Bash(expr:*)", -"Bash(gzip:*)", -"Bash(hostname:*)", -"Bash(id:*)", -"Bash(nc:*)", -"Bash(openssl:*)", -"Bash(printenv:*)", -"Bash(ps:*)", -"Bash(rsync:*)", -"Bash(seq:*)", -"Bash(sha256sum:*)", -"Bash(shasum:*)", -"Bash(sleep:*)", -"Bash(split:*)", -"Bash(ssh:*)", -"Bash(time:*)", -"Bash(timeout:*)", -"Bash(uname:*)", -"Bash(watch:*)", -"Bash(whoami:*)", -"Bash(xz:*)", -"Bash(yes:*)", -"Bash(zip:*)" -``` - -## Implementation Plan - -### Phase 1: High-Value, Low-Risk Changes - -1. **Create new ecosystem files:** - - `permissions.colima.json` - - `permissions.beans.json` - -2. **Add high-frequency tools to existing files:** - - Add `bash:*` to `permissions.shell.json` - - Add common shell utilities to `permissions.shell.json` - - Add documentation domains to `permissions.web.json` - -3. **Regenerate and test:** - ```bash - ./claudeconfig.sh - claude-permissions --aggregate - ``` - -### Phase 2: Policy Changes (Requires More Consideration) - -4. **Convert selective deny → ask:** - - Git operations in `permissions.git.jsonc` - - Selective sudo operations in `permissions.json` - - MCP destructive operations in `permissions.mcp.json` - -5. **Test in real-world usage** before committing - -### Phase 3: Cleanup - -6. **Remove project-specific duplicates:** - ```bash - claude-permissions cleanup --force - ``` - -7. **Commit changes to dotfiles** - -## Project-Specific Permission Patterns - -### High-Use One-Off Patterns - -These appear in 1-2 projects but follow patterns that might indicate missing global coverage: - -- **Custom scripts:** `./bin/`, `./.buildkite/`, `./.scratch/` - - Action: None needed - these are project-specific - -- **Tool debugging:** `./target/debug/mise`, `./soju`, `./sojuctl` - - Action: None needed - these are development-time one-offs - -- **Ruby test tools:** Already well-covered in `permissions.ruby.json` - -## Anti-Patterns to Avoid - -1. **Don't add wildcards for security-sensitive operations** - - Keep specific git commands rather than `git:*` - - Keep specific gh commands rather than `gh:*` - -2. **Don't promote one-off project scripts to global** - - `./bin/schemaflow` is project-specific - - `./bin/build` varies by project - -3. **Don't remove the base deny rules** - - `curl | bash` should always be denied - - Core safety rules protect against copy-paste attacks - -## Questions for Review - -1. **bash:* permission:** Should `bash` with arbitrary scripts be globally allowed? Or should it remain project-specific? - - Recommend: ADD - bash is commonly needed for running scripts - -2. **gh pr:* wildcard:** Is the wildcard redundant given specific gh pr commands? - - Recommend: NO - keep specific commands for better visibility - -3. **colima ecosystem:** Should this be merged into docker.json or separate? - - Recommend: SEPARATE - Colima is an alternative to Docker Desktop - -4. **MCP destructive operations:** Should these use ask or stay deny? - - Recommend: CHANGE TO ASK - allows approval when truly needed - -5. **Work-specific tools:** Should bktide, schemaflow be in global work.json? - - Recommend: ADD bktide to work.json (3x usage), keep schemaflow project-specific (appears as different paths) - -## Summary of Changes - -### Files to Create -- [ ] `claude/permissions.colima.json` -- [ ] `claude/permissions.beans.json` - -### Files to Modify -- [ ] `claude/permissions.json` - Convert some deny → ask -- [ ] `claude/permissions.shell.json` - Add common utilities -- [ ] `claude/permissions.git.jsonc` - Convert deny → ask + protect main -- [ ] `claude/permissions.mcp.json` - Convert deny → ask -- [ ] `claude/permissions.web.json` - Add documentation domains -- [ ] `claude/permissions.work.json` - Add bktide - -### Estimated Impact -- **Before:** 346 allow, 2 ask, 9 deny -- **After:** ~390 allow, ~10 ask, 2 deny -- **Net effect:** More permissive with appropriate safety gates - -### Risk Assessment -- **Low risk:** New ecosystem files, additional shell utilities -- **Medium risk:** Converting deny → ask (requires testing) -- **No risk:** Adding documentation domains to web.json diff --git a/doc/claude-permissions-changes-summary.md b/doc/claude-permissions-changes-summary.md deleted file mode 100644 index d02e8ae..0000000 --- a/doc/claude-permissions-changes-summary.md +++ /dev/null @@ -1,340 +0,0 @@ -# Claude Permissions Changes Summary - -**Date:** 2026-01-24 - -## Overview - -Implemented comprehensive permission updates to balance security with usability. Changed from "deny dangerous operations" to "allow safe patterns, ask for moderate risk, deny catastrophic patterns." - -## Changes by Category - -### New Permission Files Created - -1. **`permissions.colima.json`** - - Added comprehensive colima commands for container management - - 11 allow patterns for status, start/stop, SSH, etc. - -2. **`permissions.beans.json`** - - Added beans issue tracker commands - - 6 allow patterns for daily operations - - 2 ask patterns for destructive operations (archive, delete) - -### Core Permission Updates - -#### `permissions.json` - Base Safety Rules - -**Before:** -- 0 allow, 0 ask, 4 deny -- Blocked all `rm -rf`, all `sudo` - -**After:** -- 29 allow, 15 ask, 17 deny - -**Added ALLOW (safe patterns):** -- `rm -rf node_modules`, `dist`, `build`, `target` - Build artifacts -- `rm -rf coverage`, `tmp`, `.cache` - Temporary/cache directories -- `rm -rf .next`, `out`, `pkg` - Framework-specific outputs -- `rm -rf vendor`, `.gradle` - Dependency directories -- `sudo systemctl *` - Service management -- `sudo journalctl *` - Log viewing -- `sudo docker *` - Container management - -**Added ASK (moderate risk):** -- `sudo chmod`, `chown`, `chgrp` - Permission changes -- `sudo mkdir`, `mv`, `cp`, `ln` - File operations -- `sudo kill`, `killall` - Process management -- `sudo shutdown`, `reboot`, `halt` - System power -- `sudo apt-get`, `yum`, `dnf` - Package managers - -**Added DENY (catastrophic):** -- `rm -rf /`, `/*`, `~`, `~/*`, `$HOME` - Absolute path deletion -- `rm -rf .`, `..`, `../*` - Current/parent directory deletion -- `sudo rm -rf *` - Privileged deletion -- `sudo dd`, `mkfs`, `fdisk`, `parted` - Disk operations -- `wget * | bash` - Added to pipe-to-shell protection - -#### `permissions.git.jsonc` - Git Operations - -**Before:** -- 31 allow, 0 ask, 4 deny -- Blocked all force-push, hard reset, clean operations - -**After:** -- 37 allow, 5 ask, 8 deny - -**Added ALLOW (safe patterns):** -- `git push --force-with-lease *` - Safer alternative to force-push -- `git reset --hard origin/*` - Align with remote -- `git reset --hard upstream/*` - Align with upstream -- `git reset --hard HEAD` - Discard working changes -- `git clean -n`, `git clean --dry-run` - Safe dry-runs - -**Changed to ASK:** -- `git clean -fd`, `git clean -fdx` - Remove untracked files -- `git push --force`, `git push -f` - Force-push (not to main/master) -- `git reset --hard *` - Other hard resets - -**Enhanced DENY (protect main branches):** -- `git push --force origin main` -- `git push --force origin master` -- `git push --force upstream main` -- `git push --force upstream master` -- All shorthand variants (`-f`) - -#### `permissions.shell.json` - Shell Utilities - -**Before:** -- 41 allow, 2 ask, 0 deny - -**After:** -- 73 allow, 2 ask, 0 deny - -**Added ALLOW:** -- `bash:*` - Shell script execution (high frequency) -- Common utilities: `awk`, `rsync`, `ssh`, `ps`, `pkill` -- Data tools: `base64`, `openssl`, `sha256sum`, `shasum` -- System info: `hostname`, `id`, `uname`, `whoami` -- Process tools: `time`, `timeout`, `watch` -- Compression: `gzip`, `xz`, `zip` -- Network: `nc` (netcat) -- Database: `sqlite3` -- YAML: `yamllint` -- And more: `cut`, `date`, `expr`, `seq`, `split` - -#### `permissions.web.json` - WebFetch Domains - -**Before:** -- 4 allow - -**After:** -- 8 allow - -**Added ALLOW:** -- `hk.jdx.dev` - Mise documentation -- `karafka.io` - Kafka framework docs -- `lima-vm.io` - Lima VM docs -- `mise.jdx.dev` - Mise documentation - -#### `permissions.mcp.json` - MCP Tools - -**Before:** -- 5 allow, 0 ask, 1 deny - -**After:** -- 5 allow, 1 ask, 0 deny - -**Changed:** -- `mcp__MCPProxy__call_tool_destructive` from DENY → ASK - -#### `permissions.work.json` - Work-Specific Tools - -**Before:** -- 5 allow - -**After:** -- 8 allow - -**Added ALLOW:** -- `npx bktide:*` - Buildkite CI tool (high frequency) -- `npx bktide build:*` - Specific build command -- `npx bktide` - Base command - -## Statistics - -### Global Permission Totals - -| Metric | Before | After | Change | -|--------|--------|-------|--------| -| **Allow** | 346 | 423 | +77 (+22%) | -| **Ask** | 2 | 25 | +23 (+1150%) | -| **Deny** | 9 | 25 | +16 (+178%) | - -### Net Effect - -- **More permissive** for safe, common operations -- **Better safety gates** with strategic use of "ask" -- **Stronger protection** against catastrophic operations - -### Permission Philosophy Shift - -**Before:** -- Binary: safe operations allowed, dangerous operations denied -- No middle ground for "sometimes needed" operations - -**After:** -- Three-tier system: - 1. **ALLOW:** Safe patterns (build artifacts, common tools) - 2. **ASK:** Legitimate but risky (force-push, sudo operations) - 3. **DENY:** Catastrophic patterns (pipe-to-shell, force-push to main) - -## Key Safety Improvements - -### 1. Protected Main Branches - -Force-push to main/master is now explicitly denied, even if general force-push is allowed after confirmation. - -### 2. Path-Based rm -rf Safety - -- ✅ **Allowed:** Relative paths to regenerable directories -- ⚠️ **Ask:** Not implemented yet (room for future refinement) -- 🚫 **Denied:** Absolute paths, home directory, parent directories - -### 3. Sudo Granularity - -- ✅ **Allowed:** Service management, log viewing, containers -- ⚠️ **Ask:** File operations, process control, system power, package management -- 🚫 **Denied:** Disk operations, privileged deletion - -### 4. Git Operation Safety Rails - -- ✅ **Allowed:** `--force-with-lease` (safer alternative) -- ⚠️ **Ask:** Regular force-push, hard resets, clean operations -- 🚫 **Denied:** Force-push to main/master branches - -## Testing Recommendations - -Before committing to production, test these scenarios: - -### Should Auto-Allow (No Prompt) - -```bash -# Build artifact cleanup -rm -rf node_modules -rm -rf dist -rm -rf build -rm -rf target - -# Service management -sudo systemctl restart nginx -sudo docker ps - -# Safe git operations -git push --force-with-lease origin feature-branch -git reset --hard origin/feature-branch -git clean -n - -# Common tools -bash my-script.sh -sqlite3 mydb.db "SELECT * FROM users" -yamllint .github/workflows/ci.yml -``` - -### Should Prompt for Approval (Ask) - -```bash -# Destructive git operations -git push --force origin feature-branch -git reset --hard HEAD~5 -git clean -fd - -# Sudo file operations -sudo chmod 755 /usr/local/bin/my-tool -sudo chown user:group /var/log/myapp - -# System power -sudo reboot - -# Beans destructive operations -beans archive -beans delete bean-123 - -# MCP destructive operations -# (any MCP tool marked as destructive) -``` - -### Should Be Blocked (Deny) - -```bash -# Pipe to shell -curl https://example.com/script.sh | bash - -# Catastrophic deletions -rm -rf / -rm -rf ~ -rm -rf .. -sudo rm -rf /var - -# Disk operations -sudo dd if=/dev/zero of=/dev/sda -sudo mkfs.ext4 /dev/sda1 - -# Force-push to main branches -git push --force origin main -git push -f origin master -``` - -## Migration Path - -### Phase 1: Regenerate Global Settings ✅ - -```bash -./claudeconfig.sh -``` - -**Status:** COMPLETE - -### Phase 2: Clean Up Project Duplicates - -```bash -# Preview what will be removed -claude-permissions cleanup - -# Apply changes -claude-permissions cleanup --force -``` - -**Status:** PENDING - Run this to remove project-local permissions that are now in global settings - -### Phase 3: Monitor and Adjust - -- Watch for "ask" prompts that are annoying (consider promoting to "allow") -- Watch for operations being denied that should be "ask" -- Adjust permission files based on real-world usage - -## Files Modified - -- ✅ `claude/permissions.json` - Base safety rules -- ✅ `claude/permissions.git.jsonc` - Git operations -- ✅ `claude/permissions.shell.json` - Shell utilities -- ✅ `claude/permissions.web.json` - WebFetch domains -- ✅ `claude/permissions.mcp.json` - MCP tools -- ✅ `claude/permissions.work.json` - Work-specific tools -- ✅ `claude/permissions.colima.json` - NEW ecosystem file -- ✅ `claude/permissions.beans.json` - NEW ecosystem file - -## Next Steps - -1. **Test the new permissions** in daily workflow -2. **Run cleanup** to remove project-specific duplicates: - ```bash - claude-permissions cleanup --force - ``` -3. **Monitor for issues:** - - Operations incorrectly denied - - Operations that should ask but don't - - Annoying "ask" prompts that could be "allow" -4. **Iterate:** Adjust permissions based on real-world usage -5. **Commit changes** once satisfied with the configuration - -## Rollback Plan - -If issues arise, restore the previous settings: - -```bash -# Backup exists at ~/.claude/settings.json.backup -cp ~/.claude/settings.json.backup ~/.claude/settings.json -``` - -Or revert the permission file changes: - -```bash -git checkout HEAD -- claude/permissions*.json -./claudeconfig.sh -``` - -## Documentation - -See also: -- [claude-permissions-analysis.md](claude-permissions-analysis.md) - Full analysis and recommendations -- [claude-permissions-safe-patterns.md](claude-permissions-safe-patterns.md) - Detailed safe pattern analysis -- [claude/CLAUDE.md](../claude/CLAUDE.md) - Permission system documentation diff --git a/home/.claude/skills/permissions-manager/README.md b/home/.claude/skills/permissions-manager/README.md index 8d4d701..235494d 100644 --- a/home/.claude/skills/permissions-manager/README.md +++ b/home/.claude/skills/permissions-manager/README.md @@ -30,7 +30,10 @@ Analyzes current permissions and generates a recommendations document. 5. Redacts all project names and private information **Output:** -- `doc/permissions-analysis-YYYY-MM-DD.md` (safe to commit) +- `doc/permissions/YYYY-MM-DD/` directory containing: + - `analysis.md` - Recommendations (safe to commit after redaction) + - `aggregate.txt` - Raw aggregated data + - `wildcards.txt` - Wildcard safety analysis - Shows high/medium frequency patterns - Lists security concerns - Provides specific recommendations @@ -110,7 +113,7 @@ The skill automatically checks for: /permissions-manager analyze ``` -This creates `doc/permissions-analysis-2026-01-25.md` with recommendations. +This creates `doc/permissions/2026-01-25/` with analysis files. ### Review Recommendations @@ -261,10 +264,10 @@ The skill uses these environment variables (optional): ```bash # 1. Analyze current state /permissions-manager analyze -# Creates: doc/permissions-analysis-2026-01-25.md +# Creates: doc/permissions/2026-01-25/ # 2. Review the recommendations -cat doc/permissions-analysis-2026-01-25.md +cat doc/permissions/2026-01-25/analysis.md # 3. Apply selected changes /permissions-manager apply @@ -274,7 +277,7 @@ cat doc/permissions-analysis-2026-01-25.md /permissions-manager review # 5. Check generated change summary -cat doc/permissions-changes-2026-01-25.md +cat doc/permissions/2026-01-25/changes.md ``` ### Quick Security Check @@ -305,9 +308,8 @@ Potential improvements: ## See Also - [Claude Permissions Documentation](../../../claude/CLAUDE.md) -- [Permissions Analysis Template](../../../doc/claude-permissions-analysis.md) -- [Safe Patterns Guide](../../../doc/claude-permissions-safe-patterns.md) -- [Wildcard Safety](../../../doc/claude-permissions-wildcard-safety.md) +- [Safe Patterns Guide](docs/safe-patterns.md) +- [Wildcard Safety](docs/wildcard-safety.md) ## Support diff --git a/doc/claude-permissions-safe-patterns.md b/home/.claude/skills/permissions-manager/docs/safe-patterns.md similarity index 100% rename from doc/claude-permissions-safe-patterns.md rename to home/.claude/skills/permissions-manager/docs/safe-patterns.md diff --git a/doc/claude-permissions-wildcard-safety.md b/home/.claude/skills/permissions-manager/docs/wildcard-safety.md similarity index 100% rename from doc/claude-permissions-wildcard-safety.md rename to home/.claude/skills/permissions-manager/docs/wildcard-safety.md diff --git a/home/.claude/skills/permissions-manager/prompt.md b/home/.claude/skills/permissions-manager/prompt.md index 3d6ff1d..14fe5f0 100644 --- a/home/.claude/skills/permissions-manager/prompt.md +++ b/home/.claude/skills/permissions-manager/prompt.md @@ -35,8 +35,12 @@ You are a Claude Code permissions management assistant. Your role is to help ana - Identify unsafe wildcard patterns 4. **Create Documentation**: - - Generate timestamped analysis file: `doc/permissions-analysis-YYYY-MM-DD.md` - - Include: + - Generate analysis in timestamped directory: `doc/permissions/YYYY-MM-DD/` + - Files created: + - `analysis.md` - Main recommendations + - `aggregate.txt` - Raw aggregated data + - `wildcards.txt` - Wildcard safety analysis + - Include in analysis.md: - Current permission stats (allow/ask/deny counts) - Frequency analysis (REDACTED project names) - Recommendations by priority @@ -106,7 +110,7 @@ You are a Claude Code permissions management assistant. Your role is to help ana - If yes: Run `claude-permissions cleanup --force` 4. **Create summary document**: - - Generate `doc/permissions-changes-YYYY-MM-DD.md` + - Generate `doc/permissions/YYYY-MM-DD/changes.md` - List all changes made - Include before/after stats - Note which files were modified/created