{"id":28610976,"url":"https://github.com/zachcheung/agevault","last_synced_at":"2026-03-11T00:01:12.622Z","repository":{"id":298445712,"uuid":"999985378","full_name":"zachcheung/agevault","owner":"zachcheung","description":"A simple shell utility for managing age-encrypted secrets with ease.","archived":false,"fork":false,"pushed_at":"2025-11-05T22:30:28.000Z","size":148,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-11-06T00:17:39.471Z","etag":null,"topics":["age","age-encryption","encryption","gitops","secrets","secrets-management","security","security-tools"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zachcheung.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-06-11T05:14:11.000Z","updated_at":"2025-11-05T22:30:32.000Z","dependencies_parsed_at":"2025-08-15T06:09:33.393Z","dependency_job_id":"c092bb69-0967-4578-a2d8-527bfe022aee","html_url":"https://github.com/zachcheung/agevault","commit_stats":null,"previous_names":["zachcheung/agevault"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/zachcheung/agevault","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zachcheung%2Fagevault","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zachcheung%2Fagevault/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zachcheung%2Fagevault/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zachcheung%2Fagevault/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zachcheung","download_url":"https://codeload.github.com/zachcheung/agevault/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zachcheung%2Fagevault/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30362679,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-10T21:41:54.280Z","status":"ssl_error","status_checked_at":"2026-03-10T21:40:59.357Z","response_time":106,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["age","age-encryption","encryption","gitops","secrets","secrets-management","security","security-tools"],"created_at":"2025-06-11T23:11:12.227Z","updated_at":"2026-03-11T00:01:12.612Z","avatar_url":"https://github.com/zachcheung.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# agevault\n\n`agevault` is a simple shell utility for managing [age](https://github.com/FiloSottile/age)-encrypted secrets with ease.\n\n### 📦 Installation\n\n```sh\nsudo curl -fsSL https://raw.githubusercontent.com/zachcheung/agevault/main/agevault.sh -o /usr/local/bin/agevault \u0026\u0026 sudo chmod +x /usr/local/bin/agevault\n```\n\n#### 🧠 Shell Completion\n\n- **Bash**\n\nTo install completion globally:\n\n```sh\nagevault completion bash | sudo tee /usr/share/bash-completion/completions/agevault \u003e /dev/null\n```\n\nOr, to configure it in your `~/.bashrc` for per-user usage (recommended):\n\n```sh\n# ~/.bashrc\nsource \u003c(agevault completion bash)\n```\n\n- **Zsh**\n\n```sh\nmkdir -p ~/.zsh/completions\nagevault completion zsh \u003e ~/.zsh/completions/_agevault\n```\n\nThen add to your `~/.zshrc`:\n\n```sh\n# ~/.zshrc\nfpath=(~/.zsh/completions $fpath)\nautoload -Uz compinit\ncompinit\n```\n\n### 🚀 Usage\n\nBy default, agevault expects an age recipients file named `.age.txt` in the same directory as the secret file. You can override this behavior by setting the `AGE_RECIPIENTS` or `AGE_RECIPIENTS_FILE` environment variable.\n\n| Command    | Description                                                    | Example                                              |\n| ---------- | -------------------------------------------------------------- | ---------------------------------------------------- |\n| encrypt    | Encrypt file(s)                                                | agevault encrypt secrets                             |\n|            | Options: `--self` - Encrypt using identity (secret key)        | agevault encrypt --self secrets                      |\n| decrypt    | Decrypt .age file(s)                                           | agevault decrypt secrets.age                         |\n| cat        | Decrypt and print to stdout                                    | agevault cat secrets.age                             |\n| reencrypt  | Re-encrypt file(s) with updated recipients file                | agevault reencrypt secrets.age                       |\n| rotate     | Re-encrypt file(s) with a new key (and update recipients file) | agevault rotate secrets.age                          |\n|            | Options: `--keep-old-key` - Keep old key in recipients         | agevault rotate --keep-old-key secrets.age           |\n| edit       | Edit encrypted file(s) securely                                | agevault edit secrets.age                            |\n| run        | Decrypt and load file(s) into environment, then run command    | agevault run env.age -- npm start                    |\n|            | Options: `--env` - Load files as environment variables         | agevault run --env secrets.env.age -- npm start      |\n|            | Options: `--decrypt` - Decrypt files without loading env       | agevault run --decrypt secrets.age -- npm start      |\n| key-add    | Add public key(s) to recipients file                           | agevault key-add alice                               |\n| key-readd  | Reset and add public key(s)                                    | agevault key-readd alice bob                         |\n| completion | Generate shell completion (bash/zsh)                           | agevault completion zsh                              |\n| git-setup  | Set up Git integration for agevault diff viewing               | agevault git-setup                                   |\n\nIn most cases, you can simply use `agevault edit` — it handles encryption, decryption, and editing of secrets in one step.\n\n#### 📂 Example\n\n```console\n~ $ export PS1='$ '\n$ cd $(mktemp -d)\n$ mkdir -pm 0700 ~/.age\n$ age-keygen -o ~/.age/age.key \u0026\u0026 age-keygen -y -o ~/.age/age.pub ~/.age/age.key\n$ cp ~/.age/age.pub .age.txt\n$ echo \"my secret\" \u003e secrets\n\n$ agevault encrypt secrets\n'secrets' is encrypted to 'secrets.age'.\n$ rm secrets\n\n# Encrypt using your own identity (no recipients file needed)\n$ agevault encrypt --self secrets\n'secrets' is encrypted to 'secrets.age'.\n\n$ agevault decrypt secrets.age\n'secrets.age' is decrypted to 'secrets'.\n\n$ cat secrets \u0026\u0026 rm secrets\nmy secret\n\n$ agevault cat secrets.age\nmy secret\n\n$ agevault edit secrets.age\n'secrets.age' is updated.\n\n$ agevault cat secrets.age\nmy new secret\n\n$ age-keygen -o ./age.key\n$ age-keygen -y -o ./age.pub ./age.key\n\n# Try decrypting with the new key (should fail because old pubkey was used for encryption)\n$ AGE_SECRET_KEY_FILE=./age.key agevault cat secrets.age\nage: error: no identity matched any of the recipients\n\n$ cat ./age.pub \u003e\u003e .age.txt\n# Re-encrypt the file with the updated recipients\n$ agevault reencrypt secrets.age\n'secrets.age' is reencrypted.\n\n# Now decryption with the new key works\n$ AGE_SECRET_KEY_FILE=./age.key agevault cat secrets.age\nmy new secret\n```\n\n#### 🏃 Run Command Examples\n\nThe `run` command supports multiple modes of operation:\n\n**Environment Mode (default - backwards compatible):**\n\n```console\n$ echo \"API_KEY=secret123\" \u003e .env\n$ agevault encrypt .env\n$ agevault run .env.age -- curl -H \"Authorization: Bearer $API_KEY\" api.example.com\n```\n\n**Explicit Environment Mode:**\n\n```console\n$ echo \"DB_PASSWORD=secret\" \u003e database.env\n$ agevault encrypt database.env\n$ agevault run --env database.env.age -- ./deploy.sh\n```\n\n**Decrypt-only Mode:**\n\n```console\n$ echo \"sensitive data\" \u003e secret.txt\n$ agevault encrypt secret.txt\n$ agevault run --decrypt secret.txt.age -- cat secret.txt\nsensitive data\n```\n\n**Combined Mode (environment + decryption):**\n\n```console\n$ agevault run --env config.env.age --decrypt cert.pem.age -- docker run -v $(pwd):/data myapp\n```\n\n**Comma-separated Files:**\n\n```console\n$ agevault run --env \"app.env.age,db.env.age\" --decrypt \"cert.pem.age,key.pem.age\" -- ./start-server.sh\n```\n\n- `--env` loads files as environment variables\n- `--decrypt` decrypts files to their original locations without loading as environment variables\n- Files without flags are treated as environment files (backwards compatibility)\n- Both options support comma-separated file lists\n\n### 🔐 Configuration\n\nYou can configure `agevault` with the following environment variables.\n\n**Note:** These must be **exported** in your shell session or shell profile (`~/.bashrc`, `~/.zshrc`, etc.) for `agevault` to read them:\n\n| Variable              | Description                                           | Default                                            |\n| --------------------- | ----------------------------------------------------- | -------------------------------------------------- |\n| `AGE_SECRET_KEY`      | Inline private key string (takes precedence)          | (unset)                                            |\n| `AGE_SECRET_KEY_FILE` | Path to your age private key                          | `~/.age/age.key`                                   |\n| `AGE_RECIPIENTS`      | Comma-separated list of recipients (takes precedence) | (unset)                                            |\n| `AGE_RECIPIENTS_FILE` | Path to the recipients list                           | `.age.txt` in same directory as the encrypted file |\n| `AGE_KEY_SERVER`      | Base URL for remote public keys                       | (must be set if using key commands)                |\n| `AGE_PUBKEY_EXT`      | Extension for Age public keys in the key server       | `pub`                                              |\n\n\u003e [!NOTE]\n\u003e `AGE_KEY_SERVER` **must be set** if you intend to use `key-add`, `key-get`, or `key-readd`.\n\u003e\n\u003e For best security practices, prefer using `AGE_SECRET_KEY_FILE` over `AGE_SECRET_KEY`.\n\n#### 🌐 Key Management\n\nTo enable key management, set the key server URL:\n\n```sh\nexport AGE_KEY_SERVER=\"https://keys.example.com\"\n```\n\nBy default, agevault expects each key at `$AGE_KEY_SERVER/\u003cusername\u003e.pub`.\n\n### License\n\n[MIT](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzachcheung%2Fagevault","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzachcheung%2Fagevault","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzachcheung%2Fagevault/lists"}