agedir

command module
v0.5.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 4, 2026 License: MIT Imports: 1 Imported by: 0

README

agedir

A CLI tool to bulk-encrypt, decrypt, and place multiple secret files across a project using age encryption and a simple YAML mapping config.

Overview

Projects often contain multiple secret files scattered across directories — API keys, certificates, Firebase configs, and more. agedir manages them all through a single agedir.yaml configuration, letting you:

  • Encrypt raw files into a storage directory with one command
  • Decrypt and place them back to their original paths with one command
  • Rekey all encrypted files when team members join or leave
  • Init a project by auto-detecting common secret file patterns

agedir ships as a single statically-linked binary (no external age installation required) and runs on Windows, macOS, and Linux.

Installation

Download binary

Download the latest binary for your platform from the Releases page.

Build from source
go install github.com/asmz/agedir@latest

Or clone and build:

git clone https://github.com/asmz/agedir.git
cd agedir
make build

Requires Go 1.21 or later.

Prerequisites: Generating an age Key Pair

Each team member needs an age key pair. Install age and generate one:

# macOS
brew install age

# other platforms: https://github.com/FiloSottile/age#installation
age-keygen -o ~/.age/key.txt
# Public key: age1xxxx...xxxx

Share the public key (age1...) with your team to add to agedir.yaml. Keep the private key file (~/.age/key.txt) secret and never commit it.

For more details, see the age documentation.

Quick Start

1. Initialize a project
agedir init

Scans the current directory for common secret file patterns and generates an agedir.yaml template. Detected file paths are automatically appended to .gitignore.

2. Edit agedir.yaml

Add your team's age public keys to recipients:

version: "1"
recipients:
  - age1xxxx...xxxx  # alice
  - age1yyyy...yyyy  # bob
storage_dir: .agedir/secrets
mapping:
  - raw: android/app/google-services.json
    enc: google-services.json.age
  - raw: ios/Runner/GoogleService-Info.plist
    enc: GoogleService-Info.plist.age
3. Encrypt
agedir encrypt

Reads each raw file and writes the age-encrypted output to storage_dir/enc. Commit the storage_dir contents to your repository.

4. Decrypt
agedir decrypt -i ~/.age/key.txt

Decrypts each encrypted file and places it at the configured raw path. Run this when setting up a new environment.

Commands

agedir init

Scan the project and generate an initial agedir.yaml.

agedir init [--config agedir.yaml]

Prompts for confirmation before overwriting an existing config.

agedir encrypt

Encrypt all raw files according to the config.

agedir encrypt [--config agedir.yaml] [--dry-run]
agedir decrypt

Decrypt all encrypted files according to the config.

agedir decrypt [--identity|-i <keyfile>] [--passphrase|-p] \
               [--verify] [--dry-run] [--config agedir.yaml]
Flag Description
-i, --identity Path to age private key file
-p, --passphrase Decrypt using passphrase (reads from AGEDIR_PASSPHRASE env or terminal prompt)
--verify Skip writing if the existing file's SHA-256 hash matches
--dry-run Print files to be processed without writing anything
--config Path to agedir.yaml (default: current directory)
agedir rekey

Re-encrypt all files with the current recipients list.

agedir rekey [--config agedir.yaml]

Use this after adding or removing team members from recipients.

Configuration

agedir.yaml schema:

version: "1"               # required
recipients:                # required; one or more age public keys
  - age1...
storage_dir: .agedir/secrets  # optional; default: .agedir/secrets
mapping:                   # required; one or more raw/enc pairs
  - raw: path/to/secret.txt  # path relative to project root (original file)
    enc: secret.txt.age      # path relative to storage_dir (encrypted file)

Identity Resolution

agedir decrypt resolves the decryption identity in the following order:

  1. --identity flag (private key file path)
  2. AGEDIR_IDENTITY environment variable (private key file path)
  3. AGEDIR_PASSPHRASE environment variable (passphrase, when -p is set)
  4. Interactive terminal prompt (passphrase, when -p is set)

Security Notes

  • Raw files (raw paths) are added to .gitignore by agedir init — never commit them.
  • Encrypted files (storage_dir) are safe to commit.
  • Passphrases are never passed as command-line arguments (avoids exposure via ps).
  • Private key bytes are zeroed from memory after use.
  • Encrypted files are written atomically (temp file + rename) to prevent corruption on interruption.

Default Scan Patterns

agedir init detects the following file patterns:

Pattern Example
*.jks Android Keystore
*.p12 PKCS#12 certificate
google-services*.json Firebase Android config
GoogleService-Info*.plist Firebase iOS config
*.pem, *.key TLS certificates / private keys

Cross-Platform Builds

make cross-build

Produces binaries for darwin/amd64, darwin/arm64, linux/amd64, linux/arm64, windows/amd64, and windows/arm64 in the dist/ directory. All builds use CGO_ENABLED=0 for pure Go static linking.

License

MIT — see LICENSE.

Documentation

The Go Gopher

There is no documentation for this package.

Directories

Path Synopsis
internal
config
Package config provides loading, validation, and generation of agedir.yaml configuration.
Package config provides loading, validation, and generation of agedir.yaml configuration.
fileops
Package fileops provides placement, SHA-256 verification, and atomic writes for secret files.
Package fileops provides placement, SHA-256 verification, and atomic writes for secret files.
scanner
Package scanner provides detection of sensitive file candidates within a project.
Package scanner provides detection of sensitive file candidates within a project.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL