{"id":47965074,"url":"https://github.com/mhiro2/envdesk","last_synced_at":"2026-04-04T10:29:03.859Z","repository":{"id":346237253,"uuid":"1188008447","full_name":"mhiro2/envdesk","owner":"mhiro2","description":"Git-friendly, local-first CLI for schema-aware encrypted env file workflows with SOPS + age.","archived":false,"fork":false,"pushed_at":"2026-04-04T02:28:38.000Z","size":641,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-04T04:21:45.816Z","etag":null,"topics":["cli","configuration-management","devops","dotenv","go","sops"],"latest_commit_sha":null,"homepage":"","language":"Go","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/mhiro2.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":"2026-03-21T13:49:34.000Z","updated_at":"2026-04-04T02:28:41.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/mhiro2/envdesk","commit_stats":null,"previous_names":["mhiro2/envdesk"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/mhiro2/envdesk","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mhiro2%2Fenvdesk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mhiro2%2Fenvdesk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mhiro2%2Fenvdesk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mhiro2%2Fenvdesk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mhiro2","download_url":"https://codeload.github.com/mhiro2/envdesk/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mhiro2%2Fenvdesk/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31397051,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-04T10:20:44.708Z","status":"ssl_error","status_checked_at":"2026-04-04T10:20:06.846Z","response_time":60,"last_error":"SSL_read: 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":["cli","configuration-management","devops","dotenv","go","sops"],"created_at":"2026-04-04T10:29:03.329Z","updated_at":"2026-04-04T10:29:03.829Z","avatar_url":"https://github.com/mhiro2.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"assets/logo.png\" width=\"256\" height=\"256\" alt=\"envdesk logo\"\u003e\n\u003c/p\u003e\n\n\u003ch1 align=\"center\"\u003eenvdesk\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cstrong\u003eGit-friendly env operations for teams.\u003c/strong\u003e\u003cbr\u003e\n  \u003ccode\u003eenvdesk\u003c/code\u003e is a local-first CLI for managing encrypted env files across services and environments.\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/mhiro2/envdesk/actions/workflows/ci.yaml\"\u003e\n    \u003cimg src=\"https://github.com/mhiro2/envdesk/actions/workflows/ci.yaml/badge.svg\" alt=\"CI\"\u003e\n  \u003c/a\u003e\n  \u003cimg src=\"https://img.shields.io/badge/license-MIT-green?style=flat-square\" alt=\"MIT License\"\u003e\n\u003c/p\u003e\n\n---\n\n## ✨ Why envdesk?\n\n- lighter than a full secrets platform when you want encrypted env files in Git\n- safer than passing `.env` files by hand because edit and export stay explicit\n- team-oriented because review, lint, diff, and drift checks are built into the CLI\n\n## 🎯 Positioning\n\n- `envdesk` is not a vault and does not replace a hosted secrets manager\n- `envdesk` is a thin UX layer over SOPS + age for repository-local env workflows\n- `envdesk` focuses on schema-aware editing, review, drift detection, and key sync for teams\n\nNext to [dotenvx](https://dotenvx.com/) (encrypt dotenv-style files and keep an app-side `dotenv` workflow), `envdesk` is more opinionated about Git review workflows, schema validation, drift checks, and SOPS-based encryption. Next to [git-crypt](https://github.com/AGWA/git-crypt) (transparent encryption for selected paths in a Git repo), `envdesk` keeps env operations explicit and adds env-aware diff, lint, sync, and example generation.\n\n## 📦 Install\n\nInstall with:\n\n```bash\n# Homebrew (macOS / Linux) — [third-party tap](https://github.com/mhiro2/homebrew-tap)\nbrew install --cask mhiro2/tap/envdesk\n```\n\n```bash\n# Go toolchain\ngo install github.com/mhiro2/envdesk/cmd/envdesk@latest\n```\n\nRelease builds embed version metadata, so `envdesk --version` reports the build identity from the release workflow.\n\n## 📋 Prerequisites\n\n- **Encrypted workflows:** `sops` and `age` on your `PATH`, plus keys your team can decrypt with. Install them with your package manager or from releases ([SOPS](https://github.com/getsops/sops/releases), [age](https://github.com/FiloSottile/age/releases)). With [Homebrew](https://brew.sh) (macOS or Linux):\n\n  ```bash\n  brew install sops age\n  ```\n\n  Keys, `SOPS_AGE_KEY_FILE`, and a full walkthrough live in [docs/getting-started.md](./docs/getting-started.md). Read that before `init --sops` or `edit` if you are new to the stack.\n- **`edit`:** set `EDITOR` or pass `--editor` (on Windows, values such as `notepad.exe` or `code.cmd --wait` work).\n\n## 🚀 Getting started\n\nThis is the shortest path from an empty repository to a reviewable encrypted env workflow.\n\n### 1. Scaffold one service and one environment\n\n```bash\nenvdesk init --services api --envs dev --sops\n```\n\n`init` creates a minimal repository layout:\n\n```text\nenvdesk.yaml\n.sops.yaml\nenv/\n  api/\n    dev.env\nenv.schema/\n  api.yaml\n```\n\nGenerated `envdesk.yaml`:\n\n```yaml\nversion: 1\n\nservices:\n  - name: api\n    schema: env.schema/api.yaml\n    files:\n      dev: env/api/dev.env\n```\n\nGenerated `.sops.yaml`:\n\n```yaml\ncreation_rules:\n  - path_regex: ^env/.*\\.env$\n    age: \"\"\n```\n\nThe scaffolded schema starts with `APP_ENV`.\n\nIf you want the initial env file encrypted from the first write, add `--encrypt --age \u003crecipient\u003e`.\nThe `recipient` is your team's age public key such as `age1...`.\n\n### 2. Edit the encrypted env file\n\n```bash\nenvdesk edit api dev\n```\n\n`edit` decrypts through `sops`, opens the plaintext in your editor, validates the result, and re-encrypts it on success.\n\n### 3. Export plaintext only when you need it locally\n\n```bash\nenvdesk export api dev --out .env.local\n```\n\nUse `export` as the explicit plaintext escape hatch for short-lived local workflows.\n\n### 4. Review structure before committing\n\n```bash\nenvdesk lint --service api\nenvdesk check-sync --strict-required-only\n```\n\n`lint` checks env files against the schema. `check-sync` catches required-key drift across environments (more valuable once you add `stg` and `prod`).\n`envdesk check-sync --json` still exits non-zero when drift is present so CI can consume JSON without losing failure signals.\n`envdesk status` combines per-environment lint state, sync state, and last updated time into one dashboard.\n`envdesk audit` shows the history view: who last changed a key, how schema metadata moved, and when the current drift state started.\n\nOther review and maintenance commands are in the [quick reference](#command-quick-reference) below; the full flow is in [docs/guide.md](./docs/guide.md).\n\n### 5. When the repository grows\n\nAfter the first setup, common next steps include:\n\n- compare environments with `envdesk diff api dev stg --value-mode public`\n- align missing keys with `envdesk sync-keys api dev --to stg --placeholders`\n- inspect when drift started with `envdesk audit --service api --env dev --key DATABASE_URL`\n- manage access with `envdesk member add alice.pub --scope api --dry-run` and `envdesk rekey`\n- generate onboarding examples with `envdesk example generate`\n\n## 🛠️ Command quick reference\n\n| Goal | Example |\n| --- | --- |\n| Edit one environment (decrypt → editor → validate → encrypt) | `envdesk edit api dev` |\n| Export plaintext for local use | `envdesk export api dev --out .env.local` |\n| Schema validation | `envdesk lint --service api` |\n| Required-key drift across environments | `envdesk check-sync --strict-required-only` |\n| Lint + sync + last-updated overview | `envdesk status --service api` |\n| Trace key ownership, schema changes, and drift start dates | `envdesk audit --service api --env dev --key DATABASE_URL` |\n| Compare two environments (secrets hidden by default) | `envdesk diff api dev stg --value-mode public` |\n| Preview recipient / scope changes | `envdesk member add alice.pub --scope api --dry-run` |\n| Re-encrypt after key changes | `envdesk rekey --service api --env dev --dry-run` |\n| Generate `.env.example` for onboarding | `envdesk example generate --service api --out env/api/.env.example` |\n| Local tool and repo safety | `envdesk doctor --json` |\n\nFor every subcommand, flags, and workflows, see [docs/guide.md](./docs/guide.md).\n\n## ⚙️ Project config (`envdesk.yaml`)\n\nThis file maps **services** and **environments** to on-disk env paths and to a **schema file per service**. It does not define the syntax of lines inside `*.env` files (see **Env file syntax** below).\n\n`envdesk.yaml` uses a strict schema:\n\n```yaml\nversion: 1\n\nservices:\n  - name: api\n    schema: env.schema/api.yaml\n    files:\n      dev: env/api/dev.env\n      stg: env/api/stg.env\n      prod: env/api/prod.env\n```\n\nAll configured `schema` and env file paths must stay inside the repository root that contains `envdesk.yaml`.\nPaths that escape with absolute locations or `../` are rejected during config load.\n\nPer-service schema files (`env.schema/*.yaml`) declare keys, types, requiredness, and secret-ness. Commands such as `diff`, `check-sync`, `status`, `audit`, `sync-keys`, and `example generate` use that metadata for safer output, drift classification, audit timelines, placeholders, and commented examples. See [docs/guide.md](./docs/guide.md) for the schema model and behavior.\n\n## 📝 Env file syntax (`*.env` files)\n\nThis section is about **assignments inside env files** (for example `KEY=value` or `export KEY=value`), not about `envdesk.yaml` or schema YAML.\n\n`envdesk` supports a **small** dotenv-style subset: blank lines and full-line `#` comments, `KEY=value` / `export KEY=value`, and common quoting rules. It does **not** implement shell expansion, command substitution, multiline values, or full compatibility with every dotenv variant.\n\n`edit` keeps your validated plaintext formatting on save; `sync-keys` and `example generate` emit normalized output instead. Writes use atomic replacement where applicable.\n\nDetails: [Env file dialect and normalization](./docs/guide.md#env-file-dialect-and-normalization) in [docs/guide.md](./docs/guide.md).\n\n## ✅ CI and hooks\n\nSample Git hooks live under [`hooks/`](./hooks); [`scripts/check-env-conventions.sh`](./scripts/check-env-conventions.sh) is a small guard for what gets committed. Those samples assume a Bash-compatible shell. The envdesk CLI itself supports Windows; adapt hooks or run the same checks in CI on runners that match your stack.\n\n**Checks to run in CI (or locally before push)** — each step catches a different class of problem:\n\n1. **No accidental plaintext env in Git** — `bash scripts/check-env-conventions.sh` walks tracked `*.env` paths (skipping `*.example`) and fails if a file lacks SOPS markers (`ENC[` or `sops:`), so plaintext secrets are not committed by mistake.\n2. **Schema match** — `envdesk lint` validates every configured env file against its service schema (types, required keys, secrets metadata).\n3. **Cross-environment drift** — `envdesk check-sync --strict-required-only --json` compares required keys across environments; JSON is easy to log in CI and the process still exits non-zero when drift exists.\n\n```bash\nbash scripts/check-env-conventions.sh\nenvdesk lint\nenvdesk check-sync --strict-required-only --json\n```\n\nEncrypted files need `sops` and an age identity in that environment (for example `SOPS_AGE_KEY_FILE`). Step-by-step jobs for **GitHub Actions** and **GitLab** are in [docs/ci-integration.md](./docs/ci-integration.md).\n\n**Local developer sanity check:** `envdesk doctor` reports missing tools, weak `.gitignore` coverage for plaintext exports, tracked risky files, file modes, and whether the tree looks `encrypted`, `plaintext`, or `mixed`.\n\n## 📚 Learn more\n\n- [docs/getting-started.md](./docs/getting-started.md): SOPS and age from zero, first encrypted layout, and Git hygiene\n- [docs/guide.md](./docs/guide.md): step-by-step workflows, command usage, local hooks, onboarding, and operational guidance\n- [docs/ci-integration.md](./docs/ci-integration.md): GitHub Actions and GitLab CI job examples\n- [ARCHITECTURE.md](./ARCHITECTURE.md): package layout, data flow, command responsibilities, and security model\n\n## 📝 License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmhiro2%2Fenvdesk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmhiro2%2Fenvdesk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmhiro2%2Fenvdesk/lists"}