168aefd415
Realign fermata around redaction (PostToolUse) as the primary security layer, with access control (PreToolUse) as supplementary write/bash protection. Remove botignore.toml — policy rules now live in .botsecrets [policy] section. Add fermata.toml as an alias for .botsecrets. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
208 lines
6.0 KiB
Markdown
208 lines
6.0 KiB
Markdown
# CLI Command Reference
|
|
|
|
Fermata is a policy gate and secret filtering engine for AI coding agents. It ships two subcommands: `check` for interactive path validation and `hook` for integration with AI harness hook systems.
|
|
|
|
---
|
|
|
|
## fermata check
|
|
|
|
Check whether one or more paths are allowed for a given operation. Fermata locates the nearest project root (a directory containing `.botsecrets`, `.botignore`, or `.git`) and evaluates the policy defined there.
|
|
|
|
**Usage**
|
|
|
|
```
|
|
fermata check [OPTIONS] <PATHS>...
|
|
```
|
|
|
|
**Options**
|
|
|
|
| Option | Description | Default |
|
|
|--------|-------------|---------|
|
|
| `--op <OP>` | Operation to check: `read`, `write`, or `execute` | `read` |
|
|
| `--json` | Print the full decision as JSON instead of a human message | off |
|
|
|
|
**Exit codes**
|
|
|
|
| Code | Meaning |
|
|
|------|---------|
|
|
| 0 | Allowed (or Ask -- the agent may prompt the user) |
|
|
| 1 | Denied -- the policy blocks this operation |
|
|
| 2 | Internal error (could not load policy, bad arguments, etc.) |
|
|
|
|
When multiple paths are provided, fermata evaluates each one independently and returns the **worst** result. If any path is denied, the exit code is 1.
|
|
|
|
**Examples**
|
|
|
|
```bash
|
|
# Check if the agent can read .env
|
|
fermata check --op read .env
|
|
|
|
# Check if the agent can write to a source file
|
|
fermata check --op write src/main.rs
|
|
|
|
# Check multiple paths at once; exits 1 if any are denied
|
|
fermata check --op read .env src/main.rs config/secrets.yaml
|
|
|
|
# Get a machine-readable JSON decision
|
|
fermata check --op read .env --json
|
|
```
|
|
|
|
---
|
|
|
|
## fermata hook
|
|
|
|
Read a harness hook payload from stdin, evaluate the policy (PreToolUse) or redact secrets from tool output (PostToolUse), and write the response to stdout. This is the command you wire into your AI agent's hook configuration.
|
|
|
|
**Usage**
|
|
|
|
```
|
|
fermata hook [OPTIONS]
|
|
```
|
|
|
|
The hook payload is always read from **stdin** as JSON. The response is written to **stdout** as JSON.
|
|
|
|
**Options**
|
|
|
|
| Option | Description | Default |
|
|
|--------|-------------|---------|
|
|
| `--event <EVENT>` | Hook event type. Accepted values: `pre-tool-use`, `PreToolUse`, `post-tool-use`, `PostToolUse` | `pre-tool-use` |
|
|
| `--harness <HARNESS>` | Harness adapter name. Currently supported: `claude` | `claude` |
|
|
|
|
**Exit codes**
|
|
|
|
| Code | Meaning |
|
|
|------|---------|
|
|
| 0 | Success. The JSON response on stdout tells the harness what to do. |
|
|
| 2 | Internal error (unknown harness, unknown event type, stdin read failure) |
|
|
|
|
Fermata follows a **fail-open** policy for hooks: if the payload cannot be parsed or the policy cannot be loaded, it writes `{}` to stdout and exits 0 so the agent can continue. Errors are reported on stderr.
|
|
|
|
**Event types**
|
|
|
|
- **pre-tool-use** -- Runs before the tool executes. Fermata checks the requested path or command against `.botsecrets [policy]` / `.botignore` and returns an allow, deny, or ask decision to the harness.
|
|
- **post-tool-use** -- Runs after the tool executes. Fermata loads `.botsecrets`, builds a manifest of known secret values, and redacts any matches from the tool output before it enters the LLM context. A heuristic scanner (regex patterns derived from gitleaks) catches undeclared secrets as a safety net.
|
|
|
|
**Examples**
|
|
|
|
```bash
|
|
# PreToolUse: pipe a Claude Code hook payload through fermata
|
|
echo '{"tool_name":"Read","tool_input":{"file_path":"/project/.env"}}' \
|
|
| fermata hook --harness claude
|
|
|
|
# PostToolUse: redact secrets from tool output
|
|
echo '{"tool_name":"Bash","tool_input":{"command":"cat .env"},"tool_output":"API_KEY=sk-live-abc123"}' \
|
|
| fermata hook --harness claude --event post-tool-use
|
|
```
|
|
|
|
---
|
|
|
|
## Configuration Files
|
|
|
|
Fermata does not have its own global config file. All configuration lives in your project directory alongside the code:
|
|
|
|
| File | Purpose |
|
|
|------|---------|
|
|
| `.botsecrets` | TOML file for secret redaction (`[files]`, `[heuristic]`, `[keys]`) **and** access-control policy (`[policy]` section with `[policy.read]`, `[policy.write]`, `[policy.bash]`). Unified config for most projects. `fermata.toml` is accepted as an alias (same format, `.botsecrets` takes priority). |
|
|
| `.botignore` | Gitignore-syntax patterns. Blocks both reads and writes to matched paths. |
|
|
|
|
Fermata discovers these files by walking up from the target path (or the current working directory for `hook`) until it finds a project root.
|
|
|
|
---
|
|
|
|
## Common Patterns
|
|
|
|
### Protect secrets from day one
|
|
|
|
Drop two files in your project root:
|
|
|
|
```gitignore
|
|
# .botignore
|
|
.env
|
|
.env.*
|
|
secrets/**
|
|
credentials/**
|
|
```
|
|
|
|
```toml
|
|
# .botsecrets
|
|
[files]
|
|
patterns = [".env", ".env.*"]
|
|
|
|
[heuristic]
|
|
enabled = true
|
|
```
|
|
|
|
The `.botignore` blocks direct reads. The `.botsecrets` catches secrets that leak through indirect paths (shell output, log files, error messages).
|
|
|
|
### Single-file setup with .botsecrets
|
|
|
|
You can consolidate both secret redaction and access policy into `.botsecrets` alone, replacing the need for a separate `.botignore`:
|
|
|
|
```toml
|
|
# .botsecrets
|
|
[files]
|
|
patterns = [".env", ".env.*"]
|
|
|
|
[heuristic]
|
|
enabled = true
|
|
|
|
[policy.read]
|
|
deny = [".env", ".env.*", "secrets/**", "credentials/**"]
|
|
|
|
[policy.bash]
|
|
deny = ["rm -rf /", "curl * | sh"]
|
|
```
|
|
|
|
### Wire fermata into Claude Code
|
|
|
|
Add both hook events to `.claude/settings.json`:
|
|
|
|
```json
|
|
{
|
|
"hooks": {
|
|
"PreToolUse": [
|
|
{
|
|
"matcher": "Bash|Read|Edit|Write",
|
|
"hooks": [
|
|
{ "type": "command", "command": "fermata hook --harness claude" }
|
|
]
|
|
}
|
|
],
|
|
"PostToolUse": [
|
|
{
|
|
"matcher": "Bash|Read|Edit|Write",
|
|
"hooks": [
|
|
{ "type": "command", "command": "fermata hook --harness claude --event post-tool-use" }
|
|
]
|
|
}
|
|
]
|
|
}
|
|
}
|
|
```
|
|
|
|
### Block dangerous shell commands
|
|
|
|
Use `.botsecrets [policy.bash]` to deny specific command patterns:
|
|
|
|
```toml
|
|
[policy.bash]
|
|
deny = ["rm -rf /", "curl * | sh", "wget * | bash"]
|
|
```
|
|
|
|
### Quick smoke test
|
|
|
|
After installing fermata, verify it works against your project:
|
|
|
|
```bash
|
|
# Should exit 0 (allowed)
|
|
fermata check --op read src/main.rs
|
|
echo $?
|
|
|
|
# Should exit 1 (denied) if .botignore blocks .env
|
|
fermata check --op read .env
|
|
echo $?
|
|
|
|
# JSON output for scripting
|
|
fermata check --op read .env --json
|
|
```
|