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>
410 lines
12 KiB
Markdown
410 lines
12 KiB
Markdown
# Configuration Reference
|
|
|
|
Fermata uses up to two configuration files to control what an AI coding agent
|
|
can access and what secret values it can see. `.botsecrets` is the primary
|
|
configuration file. Most projects need only this file.
|
|
|
|
| File | Purpose | Syntax |
|
|
|------|---------|--------|
|
|
| `.botsecrets` | Declare secrets, control redaction, and set policy rules | TOML |
|
|
| `.botignore` | Block agent access to matching paths (optional, gitignore syntax) | gitignore |
|
|
|
|
`fermata.toml` is accepted as an alias for `.botsecrets` (same format, `.botsecrets` takes priority when both exist).
|
|
|
|
Configuration is layered, with later (more specific) sources overriding earlier
|
|
ones. All files are optional. Without any configuration Fermata allows all
|
|
operations and performs no redaction.
|
|
|
|
---
|
|
|
|
## `.botsecrets` -- Secret Redaction and Policy
|
|
|
|
`.botsecrets` declares which files contain secrets, how Fermata should
|
|
redact them from tool output, and (optionally) access control policy rules.
|
|
This prevents secret values from leaking into the LLM context window even
|
|
when the agent reads files indirectly (via shell output, log files, error
|
|
messages, etc.).
|
|
|
|
### Layered Configuration
|
|
|
|
`.botsecrets` configuration is layered, with later sources overriding earlier
|
|
ones:
|
|
|
|
1. **Built-in defaults** -- sensible patterns that cover common secret files
|
|
and key names.
|
|
2. **User-global** -- `~/.config/fermata/.botsecrets` (Linux/macOS) or
|
|
`%APPDATA%\fermata\.botsecrets` (Windows). Applies to all projects.
|
|
3. **Project** -- `<project-root>/.botsecrets`. Checked into version control.
|
|
4. **Local overrides** -- `<project-root>/.botsecrets.local`. Git-ignored,
|
|
for machine-specific or developer-specific settings.
|
|
|
|
**Merge rules:**
|
|
|
|
- **Vec fields** (`files.patterns`, `heuristic.patterns`, `file_overrides`):
|
|
**replaced** by the more specific layer when present.
|
|
- **Key lists** (`keys.include`, `keys.exclude`): **accumulated** across
|
|
layers (appended, not replaced).
|
|
- **Scalar fields** (`redaction.style`, `heuristic.enabled`, `enforcement.mode`,
|
|
etc.): the most specific value wins.
|
|
|
|
### `[files]` -- Secret File Patterns
|
|
|
|
Declares which files contain secrets. Fermata parses these files, extracts
|
|
key-value pairs, and uses the values for exact-match redaction.
|
|
|
|
| Field | Type | Default | Description |
|
|
|-------|------|---------|-------------|
|
|
| `patterns` | `string[]` | See below | Glob patterns matching files that contain secrets. |
|
|
|
|
**Built-in default patterns** (active when `[files]` is not specified):
|
|
|
|
```
|
|
.env, .env.*, *.env, secrets.*, credentials.*, *.key, *.pem, *.p12, *.pfx,
|
|
id_rsa, id_ed25519, id_ecdsa, Secrets.toml, Secrets.*.toml,
|
|
terraform.tfvars, *.auto.tfvars, terraform.tfstate, *.tfstate,
|
|
.docker/config.json, config/master.key, config/credentials/*.key,
|
|
.aws/credentials, .netrc, .htpasswd, service-account.json,
|
|
service-account-key.json
|
|
```
|
|
|
|
Setting `files.patterns` in a layer **replaces** the defaults entirely.
|
|
|
|
```toml
|
|
[files]
|
|
patterns = [".env", ".env.*", "config/secrets.yaml"]
|
|
```
|
|
|
|
### `[keys]` -- Secret Key Name Patterns
|
|
|
|
Controls which key names within secret files are treated as sensitive.
|
|
Patterns use glob syntax and are matched case-insensitively.
|
|
|
|
| Field | Type | Default | Description |
|
|
|-------|------|---------|-------------|
|
|
| `include` | `string[]` | `[]` | Additional key name patterns to treat as secret. Accumulated across layers. |
|
|
| `exclude` | `string[]` | `[]` | Key name patterns to remove from the effective set. Exact string match against the pattern text. |
|
|
|
|
Fermata ships with ~30 built-in key patterns that are always active:
|
|
|
|
```
|
|
*PASSWORD*, *SECRET*, *API_KEY*, *APIKEY*, *TOKEN*, *ACCESS_KEY*,
|
|
*PRIVATE_KEY*, *AUTH*, *CREDENTIAL*, *CONNECTION_STRING*, DATABASE_URL,
|
|
AWS_SECRET_ACCESS_KEY, GITHUB_TOKEN, OPENAI_API_KEY, ANTHROPIC_API_KEY,
|
|
JWT_SECRET, ENCRYPTION_KEY, MASTER_KEY, SECRET_KEY_BASE, ...
|
|
```
|
|
|
|
Use `keys.include` to add project-specific patterns. Use `keys.exclude` to
|
|
suppress a built-in pattern that causes false positives.
|
|
|
|
```toml
|
|
[keys]
|
|
include = ["STRIPE_*", "MY_APP_SIGNING_*"]
|
|
exclude = ["*AUTH*"] # too broad for this project
|
|
```
|
|
|
|
### `[redaction]` -- Redaction Style
|
|
|
|
Controls how redacted values appear in tool output.
|
|
|
|
| Field | Type | Default | Description |
|
|
|-------|------|---------|-------------|
|
|
| `style` | `string` | `"masked"` | How to replace secret values. |
|
|
|
|
Available styles:
|
|
|
|
| Style | Output | Description |
|
|
|-------|--------|-------------|
|
|
| `masked` | `*****` | Replaces the value with asterisks. Default. |
|
|
| `typed` | `<secret:string>` | Shows the value type but not the content. |
|
|
| `named` | `<secret:DB_PASSWORD>` | Shows the key name but not the value. |
|
|
| `absent` | *(empty string)* | Removes the value entirely. |
|
|
|
|
```toml
|
|
[redaction]
|
|
style = "named"
|
|
```
|
|
|
|
### `[heuristic]` -- Heuristic Secret Scanning
|
|
|
|
In addition to known-value redaction, Fermata can scan all tool output for
|
|
patterns that look like secrets (AWS keys, JWTs, GitHub PATs, high-entropy
|
|
strings, database connection URLs). This catches secrets not covered by the
|
|
`.botsecrets` manifest.
|
|
|
|
| Field | Type | Default | Description |
|
|
|-------|------|---------|-------------|
|
|
| `enabled` | `bool` | `true` | Enable or disable heuristic scanning. |
|
|
| `mode` | `string` | `"enforce"` | What to do when a heuristic match is found. |
|
|
| `patterns` | `string[]` | `[]` | Additional regex patterns to scan for. Replaces the layer's custom patterns when set. |
|
|
|
|
Available modes:
|
|
|
|
| Mode | Behavior |
|
|
|------|----------|
|
|
| `enforce` | Redact heuristic matches from tool output. Default. |
|
|
| `report` | Log findings but do not redact. |
|
|
| `disabled` | Do not run heuristic scanning at all. |
|
|
|
|
```toml
|
|
[heuristic]
|
|
enabled = true
|
|
mode = "enforce"
|
|
patterns = ["MYAPP-[A-Za-z0-9]{32}"]
|
|
```
|
|
|
|
### `[enforcement]` -- Enforcement Behavior
|
|
|
|
Controls how strictly Fermata enforces redaction, especially in edge cases.
|
|
|
|
| Field | Type | Default | Description |
|
|
|-------|------|---------|-------------|
|
|
| `mode` | `string` | `"permissive"` | Global enforcement strictness. |
|
|
| `on_parse_error` | `string` | `"mask-entire-file"` | What to do when a secret file cannot be parsed. |
|
|
|
|
Enforcement modes:
|
|
|
|
| Mode | Behavior |
|
|
|------|----------|
|
|
| `strict` | Any error or ambiguity results in denial. |
|
|
| `permissive` | Best-effort redaction; non-fatal errors are tolerated. Default. |
|
|
| `audit` | Log all decisions but do not block or redact. |
|
|
|
|
Parse error actions:
|
|
|
|
| Action | Behavior |
|
|
|--------|----------|
|
|
| `mask-entire-file` | Treat the entire file content as a secret. Default and safest. |
|
|
| `allow` | Skip the unparseable file (secrets may leak). |
|
|
| `deny` | Block all access to the file. |
|
|
|
|
```toml
|
|
[enforcement]
|
|
mode = "strict"
|
|
on_parse_error = "deny"
|
|
```
|
|
|
|
### `[[file]]` -- Per-File Overrides
|
|
|
|
Override parsing behavior for specific secret files. Useful when a file uses a
|
|
non-standard format or you only want to redact specific keys.
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| `path` | `string` | Yes | Path to the file (relative to project root). |
|
|
| `format` | `string` | No | Force a specific parser: `"env"`, `"toml"`, `"yaml"`, `"json"`. Auto-detected if omitted. |
|
|
| `keys` | `string[]` | No | Only redact these specific keys from this file (instead of applying global key patterns). |
|
|
|
|
```toml
|
|
[[file]]
|
|
path = "config/database.yml"
|
|
format = "yaml"
|
|
keys = ["password", "secret_key_base"]
|
|
|
|
[[file]]
|
|
path = ".env.production"
|
|
format = "env"
|
|
```
|
|
|
|
### `[policy]` -- Access Control Rules
|
|
|
|
Optional access control rules embedded directly in `.botsecrets`.
|
|
|
|
#### `[policy.write]` -- Write Protection
|
|
|
|
Blocks the agent from writing to matching paths. This is the primary use case
|
|
for access control -- protecting vendored code, lock files, and policy files
|
|
from modification.
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `patterns` | `string[]` | Glob patterns for paths the agent cannot write to. |
|
|
|
|
```toml
|
|
[policy.write]
|
|
patterns = [".claude/**", "vendor/**", "*.lock", "dist/**"]
|
|
```
|
|
|
|
#### `[policy.bash]` -- Command Execution Rules
|
|
|
|
Controls which shell commands the agent can run.
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `deny` | `string[]` | Patterns that block commands outright. |
|
|
| `allow_prefixes` | `string[]` | Command prefixes always allowed. |
|
|
| `ask` | `string[]` | Patterns requiring user confirmation. |
|
|
|
|
```toml
|
|
[policy.bash]
|
|
deny = ["rm -rf /", "curl * | sh"]
|
|
allow_prefixes = ["cargo", "npm", "just"]
|
|
ask = ["docker", "kubectl"]
|
|
```
|
|
|
|
#### `[policy.read]` -- Read Restrictions (Rarely Needed)
|
|
|
|
Blocks reads of matching paths. Rarely needed -- secret values are redacted by
|
|
the PostToolUse layer regardless of whether the read is allowed. Use this only
|
|
for files the agent cannot usefully read (e.g., binary blobs, large data files).
|
|
|
|
```toml
|
|
[policy.read]
|
|
patterns = ["*.sqlite", "*.dat"]
|
|
```
|
|
|
|
---
|
|
|
|
## `.botignore` -- Path-Based Access Control
|
|
|
|
For most projects, `.botsecrets` with `[policy]` is sufficient. `.botignore`
|
|
remains useful for monorepo subtree exclusion or teams that prefer gitignore
|
|
syntax for simple path blocking.
|
|
|
|
A `.botignore` file uses **gitignore syntax** to block agent access to matching
|
|
paths. When a path matches, both reads and writes are denied. There is no
|
|
distinction between operations -- if you need per-operation control, use
|
|
the `[policy]` section in `.botsecrets` instead.
|
|
|
|
### Placement and Scoping
|
|
|
|
`.botignore` files can be placed at any level of your project directory tree.
|
|
Fermata walks the project root recursively and loads every `.botignore` it
|
|
finds. Each file is scoped to its own directory:
|
|
|
|
```
|
|
myproject/
|
|
.botignore # applies to the entire project
|
|
infra/
|
|
.botignore # applies only under infra/
|
|
src/
|
|
.botignore # applies only under src/
|
|
```
|
|
|
|
When multiple `.botignore` files match the same path, the **deepest
|
|
(most specific) file wins**. A negation pattern (`!`) at any depth overrides
|
|
an ignore from a shallower `.botignore`.
|
|
|
|
### Syntax
|
|
|
|
Standard gitignore rules apply:
|
|
|
|
- Blank lines and lines starting with `#` are ignored.
|
|
- `*` matches anything except `/`.
|
|
- `**` matches zero or more directories.
|
|
- A trailing `/` matches directories only.
|
|
- A leading `/` anchors the pattern to the `.botignore` file's directory.
|
|
- Prefix a pattern with `!` to negate (whitelist) a previously ignored path.
|
|
|
|
### Example
|
|
|
|
```gitignore
|
|
# Block entire subtrees in a monorepo
|
|
packages/legacy-app/
|
|
vendor/
|
|
|
|
# Block private keys
|
|
*.pem
|
|
*.key
|
|
id_rsa
|
|
id_ed25519
|
|
|
|
# But allow the public key
|
|
!id_ed25519.pub
|
|
```
|
|
|
|
---
|
|
|
|
## Examples
|
|
|
|
### Minimal: Just Redact Secrets (most projects)
|
|
|
|
```toml
|
|
# .botsecrets
|
|
[files]
|
|
patterns = [".env", ".env.*"]
|
|
```
|
|
|
|
### Standard: Redact Secrets + Write Protection
|
|
|
|
```toml
|
|
# .botsecrets
|
|
[files]
|
|
patterns = [".env", ".env.*", "secrets/*.yaml"]
|
|
|
|
[keys]
|
|
include = ["STRIPE_*"]
|
|
|
|
[policy.write]
|
|
patterns = [".claude/**", "vendor/**", "*.lock"]
|
|
|
|
[policy.bash]
|
|
deny = ["rm -rf /", "curl * | sh"]
|
|
```
|
|
|
|
### With .botignore: Simple Path Blocking + Redaction
|
|
|
|
For teams that prefer gitignore syntax:
|
|
|
|
```gitignore
|
|
# .botignore (optional)
|
|
node_modules/
|
|
build/
|
|
dist/
|
|
```
|
|
|
|
```toml
|
|
# .botsecrets
|
|
[files]
|
|
patterns = [".env", ".env.*"]
|
|
```
|
|
|
|
### Full-Featured: Complete Configuration
|
|
|
|
A production setup using `.botsecrets` for both redaction and policy:
|
|
|
|
```toml
|
|
# .botsecrets
|
|
[files]
|
|
patterns = [".env", ".env.*", "config/credentials.yaml"]
|
|
|
|
[keys]
|
|
include = ["STRIPE_*", "PLAID_*"]
|
|
exclude = ["*AUTH*"]
|
|
|
|
[redaction]
|
|
style = "named"
|
|
|
|
[heuristic]
|
|
enabled = true
|
|
mode = "enforce"
|
|
|
|
[enforcement]
|
|
mode = "strict"
|
|
on_parse_error = "mask-entire-file"
|
|
|
|
[policy.write]
|
|
patterns = [".claude/**", "vendor/**", "*.lock", "dist/**", "migrations/**"]
|
|
|
|
[policy.bash]
|
|
deny = ["rm -rf /", "curl * | sh"]
|
|
allow_prefixes = ["cargo", "npm", "just", "git"]
|
|
ask = ["docker", "terraform"]
|
|
|
|
[policy.read]
|
|
patterns = ["*.sqlite", "*.dat"]
|
|
|
|
[[file]]
|
|
path = "config/credentials.yaml"
|
|
format = "yaml"
|
|
keys = ["api_key", "webhook_secret"]
|
|
```
|
|
|
|
```toml
|
|
# .botsecrets.local (git-ignored, developer-specific)
|
|
[redaction]
|
|
style = "masked"
|
|
|
|
[enforcement]
|
|
mode = "permissive"
|
|
```
|