SQLite-backed dotfiles manager for silly cats.
cattery docs secrets.md
5.0 kB · 134 lines
Markdown
at main

Secrets #

Cattery uses SOPS for file-level secrets. You keep control of recipients and identities; Cattery keeps encrypted files in the repository and writes plaintext only to its intended target under $HOME.

Before you begin #

Install sops and your chosen key backend, such as age, and make them available on PATH. Define recipients in .sops.yaml at the repository root.

creation_rules:
  - path_regex: .*
    age: age1replace-with-your-public-recipient

Keep private identities outside the repository. Make sure more than one trusted recovery path can decrypt important secrets; Cattery cannot recover a lost identity for you.

If you install Cattery through its Nix package, the packaged command includes sops and age on its runtime path. Other installations use the tools from your shell’s PATH.

Add a secret #

Adopt an existing file as an encrypted source:

cattery add --secret ~/.config/example/token

The source is stored below _secrets/ while keeping its target path:

repo/app/_secrets/.config/example/token -> ~/.config/example/token

For a platform-specific secret, put _secrets/ inside _darwin/ or _linux/:

repo/app/_darwin/_secrets/.config/example/token

Use --group or --platform with add when you need to choose where the source belongs. Run cattery status and cattery apply as usual afterward.

To deploy ordinary files while leaving every secret target and secret baseline untouched, run:

cattery apply --skip-secrets

The flag also prevents secret decryption and SOPS dependency checks. Group selection still applies normally to the remaining ordinary files and aliases.

cattery add --secret is the adoption workflow. The lifecycle commands below inventory, verify, or rotate sources that are already managed; they do not create, edit, or delete plaintext secrets.

Inventory and verification #

List every managed encrypted source across base, Linux, and macOS layers:

cattery secrets list
cattery secrets verify

Both commands accept group arguments and repeatable exact source selectors. Selectors are combined as a union:

cattery secrets verify work --source _secrets/.config/example/root-token

list reads repository metadata only and does not invoke SOPS. verify decrypts each selected source in memory, reports only verified or failed, continues after independent failures, and never reads the corresponding file under $HOME.

Rotate recipients or creation rules #

SOPS and .sops.yaml remain the authority for recipients. A practical rotation is:

  1. Edit the repository's .sops.yaml creation rules or recipients.
  2. Run cattery secrets verify to confirm the existing identities work.
  3. Preview with cattery secrets reencrypt (or explicitly add --dry-run).
  4. Apply with cattery secrets reencrypt --yes.
  5. Review and commit the encrypted repository changes.

Re-encryption decrypts the source in memory, encrypts the same bytes using the repository-relative source path as SOPS's filename override, then decrypts the new ciphertext and compares it with the original plaintext before publishing. Publication preserves the source mode and uses Cattery's atomic replacement path. Each source is processed independently, so a failure does not prevent other selected sources from being checked or rotated.

The command never synchronizes or inspects $HOME, runs hooks, or writes plaintext state. A successful replacement refreshes only a matching active baseline's raw encrypted-source fingerprint; inactive platform sources and secrets without a baseline do not change state.

What Cattery protects #

  • Encrypted source files stay encrypted in the repository.
  • Secret plaintext is not printed by status, diff, or interactive prompts.
  • Plaintext is not stored in Cattery’s state database, logs, command arguments, errors, or a general temporary directory.
  • Secret targets are always mode 0600, or 0700 when executable.

Cattery treats a secret as bytes, not as YAML, JSON, or an environment file. Re-encrypting a file without changing its plaintext does not create a content conflict.

Plaintext necessarily exists briefly in memory while Cattery encrypts, decrypts, compares, or writes it. Cattery minimizes that exposure, but no Go program can promise that every memory copy is erased.

Backup and recovery #

Back up both your SOPS identities and Cattery’s local state directory. The state directory includes a local key used to recognize unchanged secret plaintext across applies. If that key no longer matches existing secret state, Cattery stops safely rather than guessing.

If sops is missing when an operation needs it, Cattery exits with code 4 without changing the repository, target, or state.

See repository layout for placement and reconciliation for apply behavior.