# Development Safe Policy for agentsh # Optimized for local development workflows with sensible guardrails version: 1 name: dev-safe description: | Safe policy for local development. Allows project read/write, approves destructive operations, and blocks credential access. # ============================================================================= # FILE OPERATION RULES # ============================================================================= file_rules: # --------------------------------------------------------------------------- # Project - full access except deletes require approval # --------------------------------------------------------------------------- - name: allow-project-read description: Allow reading any file in project paths: - "${PROJECT_ROOT}" - "${PROJECT_ROOT}/**" operations: - read - open - stat - list - readlink decision: allow - name: allow-project-write description: Allow writing/creating files in project paths: - "${PROJECT_ROOT}/**" operations: - write - create - mkdir - chmod - rename decision: allow - name: approve-project-delete description: Require approval for deleting files in project paths: - "${PROJECT_ROOT}/**" operations: - delete - rmdir decision: approve message: "Delete {{.Path}}?" timeout: 5m # --------------------------------------------------------------------------- # Git root for monorepo read access # --------------------------------------------------------------------------- - name: allow-git-root-read description: Read-only access to git repository root (for monorepos) paths: - "${GIT_ROOT}/**" operations: - read - open - stat - list - readlink decision: allow # --------------------------------------------------------------------------- # Temporary directories - full access # --------------------------------------------------------------------------- - name: allow-tmp description: Full access to temp directories paths: - "/tmp/**" - "/private/tmp/**" - "/var/tmp/**" - "/private/var/tmp/**" operations: - "*" decision: allow # --------------------------------------------------------------------------- # System paths - read-only for development tools # --------------------------------------------------------------------------- - name: allow-system-read description: Read access to standard system paths paths: - "/usr" - "/lib" - "/lib64" - "/bin" - "/sbin" - "/opt" - "/usr/**" - "/lib/**" - "/lib64/**" - "/bin/**" - "/sbin/**" - "/opt/**" operations: - read - open - stat - list - readlink decision: allow - name: allow-etc-read description: Read common config files paths: - "/etc/hosts" - "/etc/resolv.conf" - "/etc/ssl/**" - "/etc/ca-certificates/**" - "/etc/localtime" - "/etc/timezone" - "/etc/mime.types" - "/etc/protocols" - "/etc/services" # Dynamic linker and libc runtime files - "/etc/ld.so.cache" - "/etc/ld.so.preload" - "/etc/ld.so.conf" - "/etc/ld.so.conf.d/**" - "/etc/nsswitch.conf" - "/etc/passwd" - "/etc/group" - "/etc/gai.conf" operations: - read - open - stat decision: allow # --------------------------------------------------------------------------- # Package manager caches - full access for dev workflows # --------------------------------------------------------------------------- - name: allow-npm-cache description: npm cache access paths: - "${HOME}/.npm/**" - "/root/.npm/**" operations: - "*" decision: allow - name: allow-pip-cache description: pip cache access paths: - "${HOME}/.cache/pip/**" - "/root/.cache/pip/**" operations: - "*" decision: allow - name: allow-cargo-cache description: Cargo cache access paths: - "${HOME}/.cargo/**" - "/root/.cargo/**" operations: - "*" decision: allow - name: allow-go-cache description: Go module cache access paths: - "${HOME}/go/**" - "/root/go/**" operations: - "*" decision: allow # --------------------------------------------------------------------------- # BLOCKED - credentials and secrets # --------------------------------------------------------------------------- - name: deny-ssh-keys description: Block access to SSH keys paths: - "${HOME}/.ssh/**" - "/root/.ssh/**" operations: - "*" decision: deny - name: deny-aws-credentials description: Block AWS credentials paths: - "${HOME}/.aws/**" - "/root/.aws/**" operations: - "*" decision: deny - name: deny-cloud-credentials description: Block cloud provider credentials paths: - "${HOME}/.gcloud/**" - "${HOME}/.azure/**" - "${HOME}/.config/gcloud/**" operations: - "*" decision: deny - name: deny-git-credentials description: Block git credentials paths: - "${HOME}/.git-credentials" - "**/.netrc" operations: - "*" decision: deny # --------------------------------------------------------------------------- # Default deny # --------------------------------------------------------------------------- - name: default-deny-files description: Deny all other file operations paths: - "**" operations: - "*" decision: deny # ============================================================================= # NETWORK OPERATION RULES # ============================================================================= network_rules: # --------------------------------------------------------------------------- # Package registries - allowed # --------------------------------------------------------------------------- - name: allow-npm description: npm registry access domains: - "registry.npmjs.org" - "*.npmjs.org" - "*.npmjs.com" ports: [443, 80] decision: allow - name: allow-pypi description: PyPI access domains: - "pypi.org" - "files.pythonhosted.org" - "*.pypi.org" ports: [443, 80] decision: allow - name: allow-cargo description: Cargo registry access domains: - "crates.io" - "*.crates.io" - "static.crates.io" ports: [443, 80] decision: allow - name: allow-go-proxy description: Go module proxy domains: - "proxy.golang.org" - "sum.golang.org" - "*.golang.org" ports: [443, 80] decision: allow # --------------------------------------------------------------------------- # Code hosting # --------------------------------------------------------------------------- - name: allow-github description: GitHub access domains: - "github.com" - "*.github.com" - "raw.githubusercontent.com" - "*.githubusercontent.com" - "api.github.com" ports: [443, 80, 22] decision: allow - name: allow-gitlab description: GitLab access domains: - "gitlab.com" - "*.gitlab.com" ports: [443, 80, 22] decision: allow # --------------------------------------------------------------------------- # CDNs # --------------------------------------------------------------------------- - name: allow-cdns description: Common CDNs domains: - "*.cloudflare.com" - "*.cloudfront.net" - "cdn.jsdelivr.net" - "unpkg.com" ports: [443, 80] decision: allow # --------------------------------------------------------------------------- # Blocked networks # --------------------------------------------------------------------------- - name: block-metadata-services description: Block cloud metadata services cidrs: - "169.254.169.254/32" decision: deny # --------------------------------------------------------------------------- # Require approval for other destinations # --------------------------------------------------------------------------- - name: approve-unknown-https description: Require approval for unknown HTTPS destinations ports: [443] decision: approve message: "Connect to {{.RemoteAddr}}:{{.RemotePort}}?" timeout: 2m - name: default-deny-network description: Deny all other network connections domains: - "*" decision: deny # ============================================================================= # COMMAND RULES # ============================================================================= command_rules: - name: allow-safe-commands description: Standard safe commands commands: - ls - cat - head - tail - grep - find - wc - sort - uniq - diff - pwd - echo - date - which - whoami - id - uname decision: allow - name: no-direct-push-to-main commands: [git] args_patterns: - "push.*(origin\\s+)?(main|master)" decision: redirect redirect_to: command: echo args: ["Push declined. Create a branch and open a pull request instead."] message: "Direct pushes to main/master are not allowed. Use feature branches and pull requests." - name: no-force-push commands: [git] args_patterns: - "push.*(--force|-f)" decision: redirect redirect_to: command: echo args: ["Force push blocked. Resolve conflicts through proper merge."] message: "Force pushing is not allowed—merge changes through the standard workflow." - name: no-hard-reset commands: [git] args_patterns: - "reset.*(--hard)" decision: redirect redirect_to: command: echo args: ["Hard reset blocked. Use git stash or git checkout to preserve changes."] message: "git reset --hard discards uncommitted work. Use non-destructive alternatives." - name: no-git-clean commands: [git] args_patterns: - "clean.*(-f|--force)" decision: redirect redirect_to: command: echo args: ["git clean blocked. Untracked files may be needed—review before deleting."] message: "git clean -fd permanently deletes untracked files. Review them manually first." - name: allow-dev-tools description: Development tools commands: - git - node - npm - npx - python - python3 - pip - pip3 - cargo - rustc - go - make decision: allow - name: block-dangerous-rm description: Block recursive force delete commands: - rm args_patterns: - ".*-rf.*" - ".*-fr.*" decision: deny - name: block-system-commands description: Block system administration commands commands: - shutdown - reboot - systemctl - service - mount - umount decision: deny # ============================================================================= # RESOURCE LIMITS # ============================================================================= resource_limits: max_memory_mb: 4096 cpu_quota_percent: 100 pids_max: 200 command_timeout: 10m session_timeout: 8h idle_timeout: 1h # ============================================================================= # AUDIT SETTINGS # ============================================================================= audit: log_allowed: false log_denied: true log_approved: true include_stdout: false include_stderr: true # ============================================================================= # SIGNAL RULES (Linux: enforced, macOS/Windows: audit only) # ============================================================================= signal_rules: # Allow signals to self - name: allow-self signals: ["@all"] target: type: self decision: allow # Allow signals to children - name: allow-children signals: ["@all"] target: type: children decision: allow # Allow signals within session - name: allow-session signals: ["SIGTERM", "SIGINT", "SIGHUP", "SIGUSR1", "SIGUSR2"] target: type: session decision: allow # Audit signals to parent (supervisor) - name: audit-parent signals: ["@all"] target: type: parent decision: audit # Deny fatal signals to external processes - name: deny-external-fatal signals: ["@fatal"] target: type: external decision: deny fallback: audit message: "Blocking signal to process outside session" # Deny all signals to system processes - name: deny-system signals: ["@all"] target: type: system decision: deny fallback: audit message: "Blocking signal to system process"