crypt-sync
v1.0.3
Published
Keep .env and secret files encrypted in git, synced across machines via age
Maintainers
Readme
Hızlı Başlangıç • Özellikler • Kurulum • Kullanım • Nasıl Çalışır • Sorun Giderme
crypt-sync
.env ve gizli dosyaları age ile şifrele, git üzerinden makineler arasında senkronize et.
🇬🇧 For English see README.md
crypt-sync, secretlarını git'te şifreli tutar. Dosyaları .gitignore'layıp senkronu kaybetmek yerine, crypt-sync her dosyayı age ile şifreler ve .age blob'unu repo'na commit'ler. Herhangi bir makinede git pull yap, passphrase ile çöz. Kopyalanacak anahtar dosyası yok. Çalıştırılacak secret manager yok.
Hızlı Başlangıç
İlk makine (yeni proje):
npm install -g crypt-sync
crypt-sync init # makine başına bir kez — passphrase gir
cd proje-dizini
crypt-sync setup # interaktif: dosyaları gez → seç → şifrele → hook kur
git commit -m "add encrypted secrets"
git pushBaşka bir makine (mevcut proje):
npm install -g crypt-sync
git clone <repo> && cd <repo>
crypt-sync init # aynı passphrase → hook'lar kurulur + dosyalar otomatik çözülürnpm install -g crypt-sync güncellemesi sonrası:
# @latest kullan — npm update -g önbelleğe alınmış metadata kullanabilir
npm install -g crypt-sync@latest
cd proje-dizini
crypt-sync update-hooks # .git/hooks/ dosyalarını yeni versiyona güncelleÖzellikler
| Özellik | Açıklama |
|---|---|
| age şifreleme | X25519 + ChaCha20-Poly1305 — modern, denetimli, hızlı |
| Passphrase'den türetilen anahtar | Aynı passphrase → her makinede aynı anahtar. Anahtar dosyası kopyalanmaz |
| Git-native senkron | Şifreli blob'lar repo'nda yaşar. git push = senkron |
| Otomatik hook'lar | Push'ta şifreler, pull'da çözer (git hook'ları) |
| Akıllı init | Proje tespit edince hook'ları kurar ve dosyaları otomatik çözer |
| İnteraktif setup | Proje ağacını gez, dosya seç, alt dizinlere gir (b geri, q çık) |
| Tam path artifact'ları | apps/web/.env → apps/web/.env.age — plaintext olmadan fresh clone'da da çalışır |
| update-hooks | npm install -g crypt-sync@latest sonrası .git/hooks/ dosyalarını günceller |
Gereksinimler
- Node.js ≥ 16
- Git
- age —
npm installsırasında otomatik indirilir
Desteklenen platformlar: macOS (arm64, x64), Linux (x64, arm64), Windows (x64).
Kurulum
npm install -g crypt-syncPostinstall scripti, platformuna uygun age binary'sini indirir ve SHA256 checksum'ını resmi release ile doğrular.
Güncellemek için:
npm install -g crypt-sync@latest # her zaman @latest kullan, npm update -g değilKaldırma
# Global paketi kaldır
npm uninstall -g crypt-sync
# Identity dosyasını sil
rm -rf ~/.config/crypt-syncKullanım
crypt-sync <komut> [seçenekler]
init Passphrase'den şifreleme identity'si türet (makine başına bir kez)
setup İnteraktif setup: dosyaları gez, şifrele, hook kur
lock [--all] [--wipe] Değişen entry'leri şifrele ve blob'ları git-add yap
unlock [--force] Tüm blob'ları plaintext'e çöz
status Tüm entry'lerin şifreleme durumunu göster
clean Manifest'te olmayan orphan .age blob'larını temizle
update-hooks Git hook'larını mevcut versiyona güncelle (npm update sonrası çalıştır)
export-key <yol> Identity anahtarını dosyaya aktar
import-key <yol> Identity anahtarını dosyadan içe aktarinit
Makine başına bir kez çalıştırılır. scrypt kullanarak passphrase'den deterministik bir age identity türetir. Aynı passphrase her zaman aynı anahtarı üretir — makineler arasında anahtar dosyası transferi gerekmez.
crypt-sync init
# Passphrase (min 8 karakter): ••••••••••
# Identity kaydedildi: ~/.config/crypt-sync/identity.txt
# Recipient: age1...Bir proje içinde çalıştırılırsa (.cryptsync dosyası bulunursa), init git hook'larını otomatik kurar ve unlock çalıştırır. Yani yeni bir makinede tek komut yeterlidir:
git clone <repo> && cd <repo>
crypt-sync init # passphrase → hook'lar kurulur → dosyalar çözülürMevcut identity'nin üzerine yazmak için --force kullanılır.
setup
İnteraktif proje kurulumu. Proje ağacını tarar, alt dizinlere girmeye izin verir ve .cryptsync manifest dosyasını tam relative path'lerle yazar.
cd proje-dizini
crypt-sync setupDizin: /
──────────────────────────────────────────
1. .mcp.json ← secret?
d1. apps/
> d1 ← apps/ dizinine gir
> d1 ← apps/bot/ dizinine gir
> 1 ← apps/bot/.env seç (tam path eklenir)
> b ← bir üst dizine çık
> q ← iptal et ve çık
> [Enter] ← bitir → şifreler + hook kurarNavigasyon tuşları:
| Tuş | Eylem |
|---|---|
| <numara> | Dosya seç / kaldır (tam relative path olarak eklenir) |
| d<numara> | Alt dizine gir |
| b veya .. | Bir üst dizine çık |
| q | Setup'ı iptal et ve çık |
| Enter | Seçimi bitir → şifrele + hook kur |
.cryptsync zaten mevcutsa (örn. crypt-sync kullanan bir repo clone'ladıysan), setup dosya seçim wizard'ını atlar, hook'ları kurar ve unlock çalıştırır. Wizard'ı yeniden çalıştırmak için --force kullan.
lock
Son lock'tan bu yana içeriği değişen entry'leri şifreler. Değişmeyen entry'ler atlanır. Blob'ları ve metadata dosyalarını otomatik olarak git add yapar.
crypt-sync lock # değişen entry'leri şifrele
crypt-sync lock --all # ledger'a bakmaksızın tüm entry'leri yeniden şifrele
crypt-sync lock --wipe # şifreledikten sonra plaintext'i de sil
crypt-sync lock --no-add # git add'i atla (hook'lar tarafından dahili olarak kullanılır)unlock
Manifest'teki tüm .age blob'larını plaintext'e çözer. Plaintext dosya mevcut olmasa bile oluşturur (fresh clone'da güvenli). Yerel olarak değiştirilmiş dosyaların üzerine --force olmadan yazmaz.
crypt-sync unlock
crypt-sync unlock --force # yerel plaintext'in üzerine şifresi çözülmüş versiyonu yazÇıktı mesajları:
unlocking apps/bot/.env... done # blob bulundu → çözüldü
not locked: apps/bot/.env # plaintext var ama blob yok → çalıştır: crypt-sync lock
missing: apps/bot/.env.age # ne blob ne plaintext var → kaynak makinede lock + push yapstatus
Entry başına durumu gösterir ve orphan blob'lar hakkında uyarır.
crypt-sync status
# .mcp.json locked (unchanged)
# apps/web/.env locked (changed — run lock)
# apps/api/.env missing blob — run lockupdate-hooks
.git/hooks/ dizinindeki git hook'larını mevcut crypt-sync versiyonuyla eşleşecek şekilde günceller. Hem yeni (# crypt-sync hook) hem eski (# env-crypt hook) sentinel formatlarını tanır. crypt-sync güncelledikten sonra çalıştır.
crypt-sync update-hooks
# hook pre-commit: updated
# hook pre-push: updated
# hook post-merge: updated
# hook post-checkout: updatedexport-key / import-key
Identity'yi passphrase'den yeniden türetmeden başka bir makineye taşır.
crypt-sync export-key ~/key-backup.txt # bu dosyayı güvende tut
crypt-sync import-key ~/key-backup.txtYapılandırma
Proje kökünde bir .cryptsync dosyası oluştur. # ile başlayan satırlar yorum satırıdır. Bu dosyayı commit'le — tüm makinelerin neyin yönetildiğinde hemfikir olması gerekir.
# crypt-sync manifest
apps/bot/.env
apps/bot/.env.development
apps/dashboard-api/.env
apps/dashboard-api/.env.development
.mcp.json
secrets/ # dizinin tamamını tek archive olarak şifrele
*.pem # glob deseniDesen kuralları:
| Desen | Davranış |
|---|---|
| apps/bot/.env (slash var) | Proje köküne göre tam path — önerilen yöntem |
| .env (slash yok) | Basename eşleşmesi — ağaçtaki her .env'i şifreler |
| secrets/ (sonda slash) | Dizin — tek bir .cryptsync.tar.age archive'ı üretir |
| *.pem | Glob — yalnızca proje kökündeki dosyaları eşleştirir |
| **/*.pem | Özyinelemeli glob |
İpucu: Basename pattern (
.env) yerine tam relative path (apps/bot/.env) kullan. Basename pattern'lar çözümleme için plaintext dosyanın disk'te mevcut olmasına bağımlıdır; bu durum ilkunlocköncesi fresh clone'larda bozulur.
Nasıl Çalışır
passphrase
│ scrypt(N=65536, r=8, p=1)
▼
32-byte key → X25519 clamp → Bech32 → AGE-SECRET-KEY-1…
│
├── age encrypt -r <recipient> → apps/bot/.env.age (git'e commit'lenir)
│
└── age decrypt -i identity.txt ← apps/bot/.env.age (pull sonrası)init— scrypt kullanarak passphrase'den deterministik bir age identity türetir.~/.config/crypt-sync/identity.txtdosyasına kaydedilir (mod 0600, dizin modu 0700)..cryptsyncprojesi tespit edilirse hook'ları kurar veunlockçalıştırır.setup— proje ağacını tarar, interaktif browser ile tam path'lerle dosya seçimi yapar,.cryptsync'i yazar, hook'ları kurar, ilklock'u çalıştırır..cryptsynczaten varsa wizard'ı atlar, hook kur +unlockyapar.lock— her değişen entry için: SHA256 hesaplar, ledger (.cryptsync.state) ile karşılaştırır,age -r <recipient>ile şifreler, blob'larıgit addyapar.unlock— her.ageblob'unu geçici dosya + yeniden adlandırma yöntemiyle atomik olarak çözer. Gerekirse parent dizinleri oluşturur. Bir sonrakilock'ın no-op olması için ledger'ı günceller.- Hook'lar —
pre-pushlock --no-addçalıştırır;post-merge/post-checkoutunlockçalıştırır.pre-commityönetilen bir plaintext dosyası stage'lenmişse commit'i durdurur. - Ledger —
.cryptsync.state(gitignore'lı) her plaintext entry'nin SHA256 hash'ini takip eder. Değişmeyen dosyalar hiçbir zaman yeniden şifrelenmez; bu sayede gereksiz git diff'leri önlenir.
Sorun Giderme
age binary not found — Postinstall scripti sessizce başarısız oldu. Yeniden çalıştır:
npm rebuild crypt-syncYa da age'i github.com/FiloSottile/age/releases adresinden manuel olarak kur ve PATH'inde olduğundan emin ol.
Error: identity not found — Önce bu makinede crypt-sync init komutunu çalıştır.
unlock missing: .env.age diyorsa — Blob git'e hiç commit'lenmemiş. Kaynak makinede:
crypt-sync lock
git add apps/bot/.env.age
git pushunlock not locked: .env diyorsa — Plaintext dosyası yerel olarak mevcut ama hiç şifrelenmemiş. Çalıştır:
crypt-sync lockgit pull sonrası dosyalar çözülmüyorsa — Git hook'ları kurulmamış veya güncel değil. Çalıştır:
crypt-sync update-hooksnpm install -g crypt-sync@latest sonrası hook'lar eski davranışı sürdürüyorsa — npm install paketi günceller ama .git/hooks/ içindeki hook dosyalarına dokunmaz. Her projede crypt-sync update-hooks çalıştır.
unlock yanlış plaintext üretiyor / şifre çözme başarısız — crypt-sync status recipient fingerprint'ini yazdırır. lock çalıştıran makinedeki fingerprint ile karşılaştır. Farklılarsa passphrase'ler farklıdır.
pre-commit "Plaintext secret file staged" mesajıyla durdu — Yönetilen bir plaintext dosyası yanlışlıkla stage'lendi:
git reset HEAD .env # stage'den çıkar
crypt-sync lock # önce şifrele
git add .env.age # blob'u stage'e ekle
git commitunlock yerel dosyamın üzerine yazmayı reddediyor — unlock, varsayılan olarak yerel olarak farklılaşmış dosyaları atlar. Yalnızca yerel değişikliklerini kasıtlı olarak değiştirmek istediğinde --force kullan:
crypt-sync unlock --forceLisans
MIT — bkz. LICENSE.
