# Rule recipes

> Copy-pasteable deny rules for common cases: sensitive paths, destructive commands, network egress, and git push guards.

These rules are ready to drop into a policy file. Each covers a common
scenario. Adjust the strings and messages to fit your setup.

For the fields each rule references, see [The input schema](/docs/policies/input-schema).

## Block access to sensitive paths

Deny any Bash command that touches `~/.ssh`:

```rego
deny[msg] {
  input.tool_name == "Bash"
  contains(input.tool_input.command, "/.ssh/")
  msg := "Blocked: command targets ~/.ssh/"
}
```

Deny access to `.env` files:

```rego
deny[msg] {
  input.tool_name == "Bash"
  contains(input.tool_input.command, ".env")
  msg := "Blocked: command references a .env file"
}
```

Deny access to `~/.aws` credentials:

```rego
deny[msg] {
  input.tool_name == "Bash"
  contains(input.tool_input.command, "/.aws/")
  msg := "Blocked: command targets ~/.aws/ credentials"
}
```

You can also block file-tool access to sensitive paths:

```rego
deny[msg] {
  input.tool_name == "Read"
  contains(input.tool_input.file_path, "/.ssh/")
  msg := "Blocked: read from ~/.ssh/ is not allowed"
}

deny[msg] {
  input.tool_name == "Write"
  endswith(input.tool_input.file_path, ".pem")
  msg := "Blocked: write to a .pem file is not allowed"
}
```

## Block destructive commands

Deny `rm -rf` invocations:

```rego
deny[msg] {
  input.tool_name == "Bash"
  contains(input.tool_input.command, "rm -rf")
  msg := "Blocked: rm -rf is not allowed"
}
```

Deny pipe-to-shell patterns (a common exfiltration or supply-chain vector):

```rego
deny[msg] {
  input.tool_name == "Bash"
  contains(input.tool_input.command, "| sh")
  msg := "Blocked: pipe-to-shell pattern detected"
}

deny[msg] {
  input.tool_name == "Bash"
  contains(input.tool_input.command, "| bash")
  msg := "Blocked: pipe-to-bash pattern detected"
}
```

## Block unexpected network egress

There is no dedicated network tool. `curl`, `wget`, and similar commands run
through the `Bash` tool, so match on the command string:

```rego
deny[msg] {
  input.tool_name == "Bash"
  contains(input.tool_input.command, "curl")
  not contains(input.tool_input.command, "api.yourcompany.com")
  msg := "Blocked: curl to an unexpected host"
}
```

Apply the same pattern for `wget`:

```rego
deny[msg] {
  input.tool_name == "Bash"
  contains(input.tool_input.command, "wget")
  not contains(input.tool_input.command, "api.yourcompany.com")
  msg := "Blocked: wget to an unexpected host"
}
```

## Block git push to protected remotes

There is no dedicated git tool. Git commands run through the `Bash` tool, so
match on the command string.

Deny any `git push` that targets `origin` (adjust to your protected remote
name):

```rego
deny[msg] {
  input.tool_name == "Bash"
  contains(input.tool_input.command, "git push")
  contains(input.tool_input.command, "origin")
  msg := "Blocked: git push to origin requires manual approval"
}
```

Deny force-push specifically:

```rego
deny[msg] {
  input.tool_name == "Bash"
  contains(input.tool_input.command, "git push")
  contains(input.tool_input.command, "--force")
  msg := "Blocked: force push is not allowed"
}

deny[msg] {
  input.tool_name == "Bash"
  contains(input.tool_input.command, "git push")
  contains(input.tool_input.command, "-f ")
  msg := "Blocked: force push is not allowed"
}
```

## Combining conditions

Rules are conjunctions: all lines in the body must hold. You can combine
conditions freely:

```rego
deny[msg] {
  input.tool_name == "Bash"
  contains(input.tool_input.command, "curl")
  contains(input.tool_input.command, "/.ssh/")
  msg := "Blocked: curl with SSH path looks like exfiltration"
}
```

This fires only when both `curl` and `/.ssh/` appear in the same command.

For testing that these rules fire correctly, see [Testing policies](/docs/policies/testing).
