# ๐ EnvSync
## ๐ง Under Development
### Encrypted `.env` Collaboration โ Git for your secrets.
[](https://nextjs.org/)
[](https://spring.io/projects/spring-boot)
[](https://www.rust-lang.org/)
[](https://www.postgresql.org/)
[](https://redis.io/)
[](https://min.io/)
[](https://www.keycloak.org/)
[](https://www.docker.com/)
> Stop sending `.env` files over Slack. Stop wondering if your teammate has the latest secrets. EnvSync is a CLI + web dashboard that gives your team a single encrypted source of truth for environment variables โ with diffing, versioning, and real-time notifications. **100% self-hosted. Zero cloud dependencies.**
---
## ๐จ The Problem
Every dev team has this conversation:
> _"Hey did you add the new `STRIPE_WEBHOOK_SECRET` to your `.env`?"_
> _"Wait there's a new one? Since when?"_
Environment variable drift causes bugs that are impossible to reproduce, broken local setups, and secrets leaking through Slack DMs. EnvSync fixes this โ and keeps everything on your own infrastructure.
---
## โจ Features
- **CLI-first workflow** โ `envsync push`, `envsync pull`, `envsync diff` โ feels like git for your `.env`
- **End-to-end encryption** โ secrets encrypted client-side with `libsodium` (XSalsa20-Poly1305) before ever hitting the server
- **Zero-knowledge by design** โ server only stores ciphertext; no one can read your secrets without your passphrase
- **Argon2id key derivation** โ memory-hard KDF protects against brute force
- **Versioned snapshots** โ every push creates an immutable version; rollback to any previous state
- **Environment scoping** โ separate vaults for `development`, `staging`, `production`
- **Web dashboard** โ manage projects, browse snapshot history, and copy CLI commands
- **Audit trail** โ every push records who pushed it and when
- **Keycloak SSO** โ enterprise-grade identity: OIDC login, MFA, LDAP, team provisioning
- **100% self-hosted** โ Docker Compose one-liner; nothing phones home
---
## ๐๏ธ Architecture
```
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ CLI Tool (Rust) โ
โ envsync push / pull / diff / rollback / log โ
โ XSalsa20-Poly1305 + Argon2id (client-side) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ HTTPS ยท E2E Encrypted Payload
โโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Spring Boot API (port 8081) โ
โ Auth ยท Vault CRUD ยท Snapshot versioning โ
โโโโโโโโฌโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโ
โ โ โ
โโโโโโโโผโโโโโโโ โโโโโโโโโผโโโโโโโ โโโโโโโโผโโโโโโโ
โ PostgreSQL โ โ Redis โ โ MinIO โ
โ Vaults & โ โ Pub/Sub โ โ Encrypted โ
โ Snapshots โ โ (planned) โ โ Backups โ
โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Keycloak (port 8180) โ
โ SSO ยท OIDC ยท OAuth2 Device Code Flow โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Next.js Dashboard (port 3000) โ
โ Projects ยท Snapshot history ยท CLI guide โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
```
---
## ๐ ๏ธ Tech Stack
| Layer | Technology | Version |
|---|---|---|
| **Frontend** | Next.js (App Router) | 15/16 |
| **Backend** | Spring Boot | 3.x / Java 21 |
| **CLI** | Rust | 2024 Edition |
| **Database** | PostgreSQL | 15 |
| **Cache / Pub-Sub** | Redis | 7 |
| **Object Storage** | MinIO | latest |
| **Identity / Auth** | Keycloak (OIDC) | latest |
| **CLI Encryption** | libsodium (sodiumoxide) | XSalsa20-Poly1305 |
| **Key Derivation** | Argon2id | 64 MB, 3 iterations |
---
## ๐ Getting Started
### Prerequisites
- Docker & Docker Compose
- Java 21+ (for backend development)
- Node.js 20+ (for frontend development)
- Rust toolchain (for CLI development)
### 1. Clone & Start Infrastructure
```bash
git clone https://github.com/yourusername/envsync.git
cd envsync
docker compose up -d
# Starts: PostgreSQL (5432), Redis (6379), MinIO (9000/9001),
# Keycloak (8180), pgAdmin (5050)
```
### 2. Configure Keycloak
```
Open http://localhost:8180
Admin credentials: admin / admin
1. Create realm: "envsync"
2. Create client: "envsync-app"
- Client authentication: ON
- Valid redirect URIs: http://localhost:3000/*
3. Create client: "envsync-app-cli"
- OAuth 2.0 Device Authorization Grant: enabled
4. Create a test user in the realm
```
### 3. Start the Backend
```bash
cd backend
./mvnw spring-boot:run
# API at http://localhost:8081
```
The backend auto-creates tables via Hibernate DDL (`ddl-auto=update`). No migrations needed.
### 4. Start the Frontend
```bash
cd frontend
cp .env.example .env.local # fill in Keycloak client credentials
npm install
npm run dev
# Dashboard at http://localhost:3000
```
Required environment variables (`.env.local`):
```bash
NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=
KEYCLOAK_CLIENT_ID=envsync-frontend
KEYCLOAK_CLIENT_SECRET=
KEYCLOAK_ISSUER=http://localhost:8180/realms/envsync
NEXT_PUBLIC_API_URL=http://localhost:8081
```
### 5. Build & Use the CLI
```bash
cd cli/envsync-cli
cargo build --release
# Binary at: ./target/release/envsync
# Or add to PATH:
cargo install --path .
```
---
## ๐ CLI Reference
```bash
# Authentication
envsync login # OAuth2 device code flow via Keycloak
envsync logout # clear stored credentials
envsync status # show auth status, project, token expiry
# Project initialization (run in your project directory)
envsync init # interactive โ prompts for name & env
envsync init --project my-app --env development
# Vault operations
envsync push # encrypt & push local .env โ vault
envsync push -m "add stripe webhook" # with a commit message
envsync push --force # skip conflict check
envsync pull # pull latest snapshot โ local .env
envsync pull --force # skip confirmation prompt
# Inspection
envsync diff # diff local .env vs latest remote snapshot
envsync diff --show-values # show actual values (not masked)
envsync log # snapshot history (last 20)
envsync log --limit 50
# Mutation helpers
envsync set DATABASE_URL "postgres://..." -m "update db url"
envsync unset OLD_API_KEY
# History
envsync rollback --version 12 # restore vault to v12 content (creates new snapshot)
envsync rollback --version 12 --yes # skip confirmation
```
**Global flags:**
```bash
envsync --api-url http://my-server:8081
# or: export ENVSYNC_API_URL=http://my-server:8081
```
---
## ๐ Security Model
EnvSync uses a **zero-knowledge encryption** model:
1. **Key derivation** โ your passphrase โ 32-byte secret key via Argon2id (64 MB, 3 iterations, 1 thread)
2. **Client-side encrypt** โ `.env` โ JSON โ XSalsa20-Poly1305 encryption with a random nonce; ciphertext is base64-encoded
3. **Server stores ciphertext only** โ PostgreSQL never sees plaintext; the server physically cannot read your secrets
4. **X25519 keypair** โ generated on first login, private key encrypted with your master key; public key registered with the server for future team-sharing features
5. **Identity via Keycloak** โ supports MFA, LDAP federation, social login; CLI uses OAuth2 Device Code flow (no browser required)
6. **Token auto-refresh** โ CLI automatically refreshes expired access tokens using the stored refresh token
---
## ๐ Project Structure
```
envsync/
โโโ frontend/ # Next.js dashboard
โ โโโ src/
โ โโโ app/
โ โ โโโ page.tsx # Landing page
โ โ โโโ dashbaord/ # Dashboard (authenticated)
โ โ โ โโโ page.tsx # Projects list
โ โ โ โโโ layout.tsx # Sidebar navigation
โ โ โ โโโ projects/[id]/ # Project detail + snapshots
โ โ โโโ api/auth/ # NextAuth Keycloak handler
โ โโโ lib/
โ โโโ auth.ts # NextAuth options
โ โโโ api.ts # Backend API client
โ
โโโ backend/ # Spring Boot 3 REST API
โ โโโ src/main/java/com/envsync/backend/
โ โโโ controller/ # ProjectController, SnapshotController, UserController
โ โโโ service/ # ProjectService, SnapshotService, UserPubkeyService
โ โโโ model/ # JPA entities: Project, Snapshot, UserPubkey
โ โโโ repository/ # Spring Data JPA repositories
โ โโโ dto/ # Request/Response DTOs
โ โโโ SecurityConfig.java # CORS + JWT + OAuth2 Resource Server
โ โโโ GlobalExceptionHandler.java # Validation + error responses
โ
โโโ cli/envsync-cli/ # Rust CLI
โโโ src/
โโโ commands/ # login, logout, init, push, pull, diff,
โ # log, set, unset, rollback, status
โโโ api/ # vault.rs (HTTP client), auth.rs (device code + refresh)
โโโ crypto.rs # Argon2id + XSalsa20-Poly1305 + X25519
โโโ config.rs # Config persistence + auto token refresh
โโโ cli.rs # clap CLI definition
```
---
## ๐ API Reference
All endpoints require `Authorization: Bearer `.
| Method | Path | Description |
|--------|------|-------------|
| `POST` | `/api/projects` | Create project |
| `GET` | `/api/projects` | List my projects |
| `GET` | `/api/projects/{id}` | Get project |
| `DELETE` | `/api/projects/{id}` | Delete project |
| `POST` | `/api/projects/{id}/snapshots` | Push snapshot |
| `GET` | `/api/projects/{id}/snapshots` | List snapshots (`?limit=N`) |
| `GET` | `/api/projects/{id}/snapshots/latest` | Get latest snapshot |
| `GET` | `/api/projects/{id}/snapshots/{snapId}` | Get snapshot by ID |
| `PUT` | `/api/users/me/pubkey` | Register X25519 public key |
---
## ๐งช Testing
```bash
# CLI tests (crypto roundtrips)
cd cli/envsync-cli
cargo test
# Backend unit tests (no database required)
cd backend
./mvnw test
# Frontend type-check + build
cd frontend
npm run build
```
---
Built to solve a real problem every dev team faces. No cloud required.