fnox 1.25.1

A flexible secret management tool supporting multiple providers and encryption methods
Documentation
# OS Keychain

Store secrets in your operating system's native secure storage.

## Supported Platforms

- **macOS:** Keychain Access (built-in)
- **Windows:** Credential Manager (built-in)
- **Linux:** Secret Service (via libsecret - GNOME Keyring, KWallet)

## Quick Start

```bash
# 1. Linux only: Install libsecret
sudo apt-get install libsecret-1-0 libsecret-1-dev  # Ubuntu/Debian

# 2. Configure provider
cat >> fnox.toml << 'EOF'
[providers]
keychain = { type = "keychain", service = "fnox" }
EOF

# 3. Store a secret in OS keychain
fnox set DATABASE_URL "postgresql://localhost/mydb" --provider keychain

# 4. Retrieve from keychain
fnox get DATABASE_URL
```

## Linux Setup

On Linux, you need libsecret installed:

::: code-group

```bash [Ubuntu/Debian]
sudo apt-get install libsecret-1-0 libsecret-1-dev
```

```bash [Fedora/RHEL]
sudo dnf install libsecret libsecret-devel
```

```bash [Arch]
sudo pacman -S libsecret
```

:::

macOS and Windows have built-in support—no installation needed.

## Configuration

```toml
[providers]
keychain = { type = "keychain", service = "fnox", prefix = "myapp/" }  # Prefix is optional
```

### Service Name

The `service` acts as a namespace to isolate fnox secrets from other applications:

```toml
[providers]
keychain = { service = "fnox" }  # All fnox secrets under "fnox" service

# Or use project-specific service
keychain = { service = "myapp" }  # All secrets under "myapp" service
```

### Prefix

Optional prefix prepended to secret names:

```toml
[providers]
keychain = { service = "fnox", prefix = "myapp/" }  # "database-url" becomes "myapp/database-url"
```

## How It Works

1. **Storage:** Secrets are stored in the OS credential manager (encrypted by OS)
2. **Config:** `fnox.toml` contains only the secret name, not the value
3. **Retrieval:** fnox queries the OS keychain API
4. **Service:** Acts as a namespace (isolates fnox secrets from other apps)
5. **Prefix:** Additional namespacing within the service

## Usage

### Store a Secret

```bash
fnox set DATABASE_URL "postgresql://localhost/mydb" --provider keychain
```

Your `fnox.toml`:

```toml
[secrets]
DATABASE_URL = { provider = "keychain", value = "database-url" }  # ← Keychain entry name, not the actual secret
```

The actual secret is stored in the OS keychain, encrypted.

### Retrieve a Secret

```bash
fnox get DATABASE_URL
```

### Run Commands

```bash
fnox exec -- npm run dev
```

## Recommended: Use With Age, Not As Bulk Storage

The OS keychain is designed for **a few** long-lived secrets, not as the storage backend for every secret in a project. On macOS in particular, the system pops a Security dialog the first time each application accesses each keychain item — so if you store ten secrets directly in the keychain, you'll get up to ten "Always Allow / Allow / Deny" prompts the first time `fnox exec` runs.

The pattern that scales much better is to store a single **age private key** in the keychain and encrypt all your secrets with age:

```toml
[providers]
keychain = { type = "keychain", service = "fnox" }
age = { type = "age", recipients = ["age1..."], identity = { provider = "keychain", value = "age-key" } }

[secrets]
# Many secrets, all encrypted with age — only one keychain access (the age key)
DATABASE_URL = { provider = "age", value = "encrypted..." }
API_KEY      = { provider = "age", value = "encrypted..." }
STRIPE_KEY   = { provider = "age", value = "encrypted..." }
# ...
```

This way:

- **One keychain item, one dialog.** Hitting "Always Allow" once authorizes the age key for that machine.
- Adding more secrets is free — they go into the encrypted config, not into the keychain.
- Loss of the keychain item is recoverable from any other machine that holds the same age identity.

Reach for direct `provider = "keychain"` only for the handful of bootstrap secrets that don't have anything else to decrypt them (e.g., the age key itself, an OP service account token).

## Bootstrap Pattern

A common pattern is to store provider tokens in the keychain:

```toml
[providers]
keychain = { type = "keychain", service = "fnox" }
age = { type = "age", recipients = ["age1..."] }

[secrets]
OP_SERVICE_ACCOUNT_TOKEN = { provider = "keychain", value = "op-token" }  # Store 1Password token in keychain
DATABASE_URL = { provider = "age", value = "encrypted..." }  # Other secrets encrypted with age
```

Then bootstrap:

```bash
export OP_SERVICE_ACCOUNT_TOKEN=$(fnox get OP_SERVICE_ACCOUNT_TOKEN)
# Now can access 1Password secrets
fnox exec -- ./start.sh
```

## Example Configurations

### Personal Project

```toml
[providers]
keychain = { type = "keychain", service = "myapp" }

[secrets]
DATABASE_URL = { provider = "keychain", value = "database-url" }
API_KEY = { provider = "keychain", value = "api-key" }
```

### Bootstrap Tokens

```toml
[providers]
keychain = { type = "keychain", service = "fnox-tokens" }

[secrets]
GITHUB_TOKEN = { provider = "keychain", value = "github" }
NPM_TOKEN = { provider = "keychain", value = "npm" }
```

### Machine-Specific Secrets

```toml
# fnox.local.toml (gitignored)
[providers]
keychain = { type = "keychain", service = "fnox-local" }

[secrets]
LAPTOP_DB_URL = { provider = "keychain", value = "laptop-db" }
```

## Platform Details

### macOS Keychain

Secrets stored in:

- **Login Keychain** (default)
- **System Keychain** (requires admin)

View in Keychain Access app:

1. Open Keychain Access
2. Search for service name (e.g., "fnox")
3. Double-click to view/edit

### Windows Credential Manager

Secrets stored in Windows Credential Manager.

View in Control Panel:

1. Control Panel → User Accounts → Credential Manager
2. Windows Credentials
3. Look for fnox entries

### Linux Secret Service

Secrets stored in:

- **GNOME Keyring** (GNOME desktop)
- **KWallet** (KDE desktop)
- **Other Secret Service implementations**

View with Seahorse (GNOME):

```bash
sudo apt install seahorse
seahorse
```

## Pros

- ✅ OS-managed encryption
- ✅ Cross-platform (macOS, Windows, Linux)
- ✅ No external dependencies
- ✅ Free
- ✅ Built into operating system
- ✅ Secure by default

## Cons

- ❌ Requires GUI/interactive session (doesn't work in headless CI)
- ❌ Not suitable for teams (secrets are per-machine)
- ❌ Keyring must be unlocked
- ❌ No audit logs
- ❌ No centralized management

## Limitations

### Headless Environments

Keychain provider requires a GUI session and doesn't work in:

- CI/CD (GitHub Actions, GitLab CI, etc.)
- Docker containers (without X11/Wayland)
- SSH sessions (without forwarding)
- Headless servers

For CI/CD, use age encryption or cloud providers instead.

### Tests Auto-Skip in CI

fnox's keychain tests automatically skip in CI environments:

```bash
# Runs locally
mise run test:bats

# Skips keychain tests in CI
# GitHub Actions, GitLab CI, etc.
```

## Security

- **Encryption:** OS handles encryption (typically AES-256)
- **Access control:** OS enforces access (user/session isolation)
- **Keyring unlock:** May require password entry on first access
- **Memory protection:** OS manages secure memory handling

## Troubleshooting

### "Keyring is locked"

Unlock your keyring:

**macOS:**

- Keyring unlocks automatically on login

**Linux (GNOME):**

```bash
# Unlock manually
gnome-keyring-daemon --unlock
```

**Windows:**

- Credential Manager unlocks on login

### "Access denied"

Check that the process has access:

- **macOS:** May prompt for Keychain Access permission
- **Linux:** Ensure Secret Service is running
- **Windows:** Check User Account Control settings

### "Service not available" (Linux)

Install and start Secret Service:

```bash
# Ubuntu/Debian
sudo apt-get install gnome-keyring
gnome-keyring-daemon --start

# Or use KWallet
sudo apt-get install kwalletmanager
```

## Best Practices

1. **Use for local development only** - Not for teams or CI
2. **Bootstrap provider tokens** - Store 1Password/AWS tokens
3. **Machine-specific overrides** - Use in `fnox.local.toml`
4. **Descriptive service names** - Use project-specific services
5. **Keep keyring unlocked** - Unlock on login for convenience

## Next Steps

- [Age Encryption]/providers/age - Team-friendly alternative
- [Hierarchical Config]/guide/hierarchical-config - Per-machine configuration with fnox.local.toml
- [1Password]/providers/1password - Team password manager