{"id":44422903,"url":"https://github.com/matanryngler/deployshield","last_synced_at":"2026-02-17T15:00:40.185Z","repository":{"id":337773029,"uuid":"1155111498","full_name":"matanryngler/deployshield","owner":"matanryngler","description":"Claude Code plugin — production safety guardrails that block write/mutating operations on cloud, database, IaC, and deployment CLIs","archived":false,"fork":false,"pushed_at":"2026-02-12T14:29:59.000Z","size":68,"stargazers_count":2,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-02-13T17:57:21.701Z","etag":null,"topics":["aws","claude-code","claude-code-plugin","cloud-safety","guardrails","kubernetes","security","terraform"],"latest_commit_sha":null,"homepage":"https://github.com/matanryngler/deployshield","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/matanryngler.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-11T06:10:45.000Z","updated_at":"2026-02-12T08:08:17.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/matanryngler/deployshield","commit_stats":null,"previous_names":["matanryngler/deployshield"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/matanryngler/deployshield","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/matanryngler%2Fdeployshield","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/matanryngler%2Fdeployshield/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/matanryngler%2Fdeployshield/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/matanryngler%2Fdeployshield/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/matanryngler","download_url":"https://codeload.github.com/matanryngler/deployshield/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/matanryngler%2Fdeployshield/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29443468,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-14T10:51:12.367Z","status":"ssl_error","status_checked_at":"2026-02-14T10:50:52.088Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aws","claude-code","claude-code-plugin","cloud-safety","guardrails","kubernetes","security","terraform"],"created_at":"2026-02-12T10:06:53.245Z","updated_at":"2026-02-14T12:01:11.107Z","avatar_url":"https://github.com/matanryngler.png","language":"Python","readme":"# DeployShield\n\nA Claude Code plugin that acts as a guardrail to prevent write/mutating commands against production environments. DeployShield intercepts Bash commands before execution using deterministic PreToolUse hooks and blocks dangerous operations while allowing read-only commands to pass through.\n\n## How It Works\n\n```mermaid\nflowchart LR\n    A[\"Claude runs\\na Bash command\"] --\u003e B{\"DeployShield\\nPreToolUse Hook\"}\n    B --\u003e|\"Recognized CLI +\\nread-only\"| C[\"Command executes\"]\n    B --\u003e|\"Not a\\nguarded CLI\"| C\n    B --\u003e|\"Recognized CLI +\\nwrite/mutate\"| D[\"Blocked with\\nreason message\"]\n```\n\nEvery Bash command Claude attempts to run is piped through DeployShield's validation script. If it detects a recognized CLI, it checks the subcommand against a curated safe-list of read-only operations. If the action isn't on the list, it's blocked. Unrecognized commands pass through untouched.\n\n## Supported Providers\n\n### Cloud\n\n| Provider | CLI | Allowed (read-only) | Blocked (examples) |\n|----------|-----|---------------------|-------------------|\n| **AWS** | `aws` | `describe`, `get`, `list`, `wait`, `help`, `sts get-*`, `s3 ls`, `s3 cp` (download), `configure list`, `sso login` | `run-instances`, `terminate-instances`, `s3 rm`, `s3 cp` (upload) |\n| **GCP** | `gcloud` | `describe`, `list`, `info`, `help`, `config list`, `config get-value`, `auth list`, `auth print-*` | `create`, `delete`, `update`, `deploy` |\n| **Azure** | `az` | `show`, `list`, `get`, `help`, `account show`, `account list`, `ad signed-in-user show` | `create`, `delete`, `update`, `start`, `stop` |\n| **Kubernetes** | `kubectl` | `get`, `describe`, `logs`, `explain`, `api-resources`, `api-versions`, `cluster-info`, `version`, `config view`, `config get-*`, `config current-context`, `auth can-i`, `diff`, `top`, `wait`, any command with `--dry-run` | `apply`, `delete`, `patch`, `edit`, `scale`, `rollout` |\n| **Helm** | `helm` | `list`, `ls`, `get`, `show`, `status`, `history`, `search`, `repo list`, `template`, `lint`, `verify`, `version`, `env`, any command with `--dry-run` | `install`, `upgrade`, `uninstall`, `rollback` |\n\n### Databases\n\n| Provider | CLI | Allowed (read-only) | Blocked (examples) |\n|----------|-----|---------------------|-------------------|\n| **PostgreSQL** | `psql` | `-l`, `-c \"SELECT ...\"`, `-c \"SHOW ...\"`, `-c \"\\dt\"` | `-c \"DROP TABLE ...\"`, `-c \"DELETE FROM ...\"`, `-f script.sql` |\n| **MySQL** | `mysql` | `-e \"SELECT ...\"`, `-e \"SHOW ...\"`, `-e \"EXPLAIN ...\"` | `-e \"DROP TABLE ...\"`, `-e \"DELETE FROM ...\"`, `-e \"INSERT ...\"` |\n| **MongoDB** | `mongosh` | `--eval \"db.col.find()\"`, `--eval \"show dbs\"` | `--eval \"db.col.drop()\"`, `--eval \"db.col.deleteMany()\"`, `-f script.js` |\n| **Redis** | `redis-cli` | `GET`, `KEYS`, `SCAN`, `INFO`, `PING`, `TTL`, `HGETALL` | `SET`, `DEL`, `FLUSHALL`, `FLUSHDB`, `CONFIG SET` |\n\n### IaC \u0026 Deployment Tools\n\n| Provider | CLI | Allowed (read-only) | Blocked (examples) |\n|----------|-----|---------------------|-------------------|\n| **Terraform** | `terraform` | `plan`, `show`, `output`, `state list`, `state show`, `state pull`, `validate`, `fmt`, `providers`, `version`, `graph`, `workspace list`, `workspace show`, `init` | `apply`, `destroy`, `import`, `taint`, `untaint` |\n| **Pulumi** | `pulumi` | `preview`, `stack ls`, `stack select`, `config get`, `whoami`, `version`, `about` | `up`, `destroy`, `cancel`, `import` |\n| **AWS CDK** | `cdk` | `diff`, `synth`, `list`, `doctor`, `version` | `deploy`, `destroy`, `bootstrap` |\n| **AWS SAM** | `sam` | `validate`, `build`, `local`, `logs`, `list` | `deploy`, `delete`, `sync` |\n| **Serverless** | `serverless`/`sls` | `info`, `print`, `package`, `invoke local` | `deploy`, `remove` |\n| **Ansible** | `ansible-playbook` | `--check`, `--syntax-check`, `--list-hosts`, `--list-tasks` | Running without `--check` |\n\n### Secrets, GitHub, Containers \u0026 Publishing\n\n| Provider | CLI | Allowed (read-only) | Blocked (examples) |\n|----------|-----|---------------------|-------------------|\n| **Vault** | `vault` | `read`, `list`, `status`, `version`, `login`, `token lookup`, `kv get` | `write`, `delete`, `seal`, `kv put` |\n| **GitHub** | `gh` | `pr view/list`, `issue view/list`, `api` (GET), `repo view/list/clone`, `auth`, `search` | `pr merge/close`, `issue close`, `release create`, `repo delete` |\n| **Docker** | `docker`/`podman` | `ps`, `images`, `logs`, `inspect`, `info`, `version`, `stats`, `compose ps/logs` | `rm`, `rmi`, `system prune`, `push`, `stop`, `kill` |\n| **npm** | `npm`/`yarn`/`pnpm` | Everything else | `publish`, `unpublish` |\n| **PyPI** | `twine` | Everything else | `upload` |\n| **RubyGems** | `gem` | Everything else | `push`, `yank` |\n| **Cargo** | `cargo` | Everything else | `publish` |\n\n## Edge Cases Handled\n\nDeployShield uses a quote-aware parser that correctly handles:\n\n- **Compound commands** — `echo ok \u0026\u0026 kubectl apply -f deploy.yaml` blocks the `kubectl apply`\n- **Piped commands** — `cat manifest.yaml | kubectl apply -f -` blocks the `kubectl apply`\n- **Quoted operators** — `echo \"hello \u0026\u0026 world\"` is not split on the `\u0026\u0026`\n- **Subshells** — `$(terraform output -json)` inside a larger command is parsed correctly\n- **Env var prefixes** — `AWS_PROFILE=prod aws s3 rm ...` is blocked\n- **Full binary paths** — `/usr/local/bin/aws ec2 run-instances` is blocked\n- **SQL injection in flags** — `psql -c \"DROP TABLE users\"` is caught and blocked\n- **Non-guarded commands** — `git push`, `make build`, etc. pass through without interference\n\n## Installation\n\n### Via Plugin Marketplace (recommended)\n\nRegister the marketplace and install:\n\n```bash\nclaude plugin marketplace add matanryngler/deployshield\nclaude plugin install deployshield@deployshield\n```\n\n### Manual\n\n```bash\ngit clone https://github.com/matanryngler/deployshield.git\nclaude --plugin-dir ./deployshield\n```\n\n### Verify it's working\n\nStart a new Claude Code session and try a write command — it should be blocked:\n\n```\n\u003e kubectl delete pod my-pod\n# =\u003e Blocked: kubectl 'delete' is not in the safe-list for kubernetes\n```\n\n## Project Structure\n\n```\ndeployshield/\n├── .claude-plugin/\n│   └── plugin.json                # Plugin manifest\n├── hooks/\n│   ├── hooks.json                 # Hook event configuration\n│   └── scripts/\n│       └── validate-cloud-command.py   # Core validation script\n├── skills/\n│   └── deployshield/\n│       └── SKILL.md               # Skill context for Claude\n└── README.md\n```\n\n| Component | Purpose |\n|-----------|---------|\n| **plugin.json** | Declares the plugin name, version, and metadata |\n| **hooks.json** | Registers two hooks: a PreToolUse hook on Bash commands (runs the validator) and a SessionStart hook (informs Claude that DeployShield is active) |\n| **validate-cloud-command.py** | The core validation engine. Parses commands from hook JSON stdin, splits compound commands respecting shell quoting, normalizes binaries, and checks against per-provider safe-lists |\n| **SKILL.md** | Activates on infrastructure files to remind Claude which operations are safe and to suggest `--dry-run` / `plan` alternatives |\n\n## How the Validator Works\n\n1. Reads JSON from stdin (`tool_input.command`)\n2. Splits the command on `\u0026\u0026`, `||`, `;`, `|` using a state machine that respects single quotes, double quotes, backticks, `$(...)` subshells, and escape characters\n3. For each segment, strips env-var prefixes and full binary paths using `shlex`\n4. Identifies the CLI binary and dispatches to the provider-specific checker\n5. The checker skips global flags to find the subcommand, then matches against the safe-list\n6. **Default-deny**: if a guarded CLI is recognized but the action isn't safe-listed, the command is blocked\n7. Non-guarded commands are always allowed\n\n## Requirements\n\n- Python 3.8+ (used by the validation script; ships with macOS and most Linux distros)\n- Claude Code with plugin support\n\n## Testing\n\nYou can test the validator directly by piping JSON to stdin:\n\n```bash\n# Should be allowed (exit 0, no output)\necho '{\"tool_input\":{\"command\":\"aws s3 ls\"}}' | ./hooks/scripts/validate-cloud-command.py\necho '{\"tool_input\":{\"command\":\"kubectl get pods\"}}' | ./hooks/scripts/validate-cloud-command.py\necho '{\"tool_input\":{\"command\":\"psql -c \\\"SELECT * FROM users\\\"\"}}' | ./hooks/scripts/validate-cloud-command.py\n\n# Should be denied (prints JSON with permissionDecision: deny)\necho '{\"tool_input\":{\"command\":\"terraform apply\"}}' | ./hooks/scripts/validate-cloud-command.py\necho '{\"tool_input\":{\"command\":\"psql -c \\\"DROP TABLE users\\\"\"}}' | ./hooks/scripts/validate-cloud-command.py\necho '{\"tool_input\":{\"command\":\"docker system prune\"}}' | ./hooks/scripts/validate-cloud-command.py\necho '{\"tool_input\":{\"command\":\"npm publish\"}}' | ./hooks/scripts/validate-cloud-command.py\necho '{\"tool_input\":{\"command\":\"gh pr merge 123\"}}' | ./hooks/scripts/validate-cloud-command.py\n\n# Non-guarded command - always allowed\necho '{\"tool_input\":{\"command\":\"npm test\"}}' | ./hooks/scripts/validate-cloud-command.py\n```\n\n## License\n\nMIT\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmatanryngler%2Fdeployshield","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmatanryngler%2Fdeployshield","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmatanryngler%2Fdeployshield/lists"}