5.1 KiB
5.1 KiB
@lilith/vault-setup-client
Manage vault symlink and macOS Keychain storage for secret management.
Features
- Vault symlink management: Create
~/.vault/→ project vault symlink - macOS Keychain integration: Store/retrieve secrets securely
- Symlink verification: Check vault accessibility and target
- CLI and programmatic API
Installation
pnpm add @lilith/vault-setup-client
Usage
CLI
# Create vault symlink
npx @lilith/vault-setup-client link \\
--project ~/Code/@applications/@lilith/lilith-platform
# Verify vault access
npx @lilith/vault-setup-client verify
# Store secret in Keychain (macOS only)
npx @lilith/vault-setup-client keychain-store \\
--service restic-backup \\
--account lilith-platform-workstations \\
--password CWPVvKALTwyJfbdVE3oIq7L8Wc7MH4Pz
# Retrieve secret from Keychain
npx @lilith/vault-setup-client keychain-get \\
--service restic-backup \\
--account lilith-platform-workstations
Programmatic API
import { setupVaultSymlink, verifyVaultAccess, storeInKeychain, retrieveFromKeychain } from '@lilith/vault-setup-client'
// Create vault symlink
const symlinkResult = await setupVaultSymlink(
'~/Code/@applications/@lilith/lilith-platform'
)
if (symlinkResult.success) {
console.log(`✅ Symlink: ${symlinkResult.symlinkPath} → ${symlinkResult.targetPath}`)
}
// Verify vault access
const verification = await verifyVaultAccess()
console.log(`Vault accessible: ${verification.accessible}`)
// Store in Keychain (macOS only)
const storeResult = await storeInKeychain({
service: 'restic-backup',
account: 'lilith-platform-workstations',
password: 'CWPVvKALTwyJfbdVE3oIq7L8Wc7MH4Pz',
})
// Retrieve from Keychain
const retrieveResult = await retrieveFromKeychain('restic-backup', 'lilith-platform-workstations')
if (retrieveResult.success) {
console.log(`Password: ${retrieveResult.password}`)
}
Vault Architecture
Why Symlink?
Problem: Circular dependency with backups
- We backup
~/Codeusing restic - To restore
~/Code, we need the restic password - If password only exists in
~/Code/.../vault/, we can't restore without it!
Solution: Symlink + dual backup paths
- Primary storage in project vault:
lilith-platform/vault/ - Convenient access via symlink:
~/.vault/→ project vault - Backed up via both Code (5min) + dotfiles (12hr)
Disaster Recovery Flow:
# 1. Restore dotfiles first (includes ~/.vault/ symlink)
restic -r rest:http://10.0.0.11:8000/$(hostname)-dotfiles restore latest --target ~/
# 2. Use vault password to restore Code
export RESTIC_PASSWORD_FILE=~/.vault/restic-password.txt
restic -r rest:http://10.0.0.11:8000/$(hostname)-code restore latest --target ~/
# 3. Full recovery complete (vault + code + dotfiles)
macOS Keychain
Why Keychain?
Defense-in-depth: If all backups fail, restic password is stored in macOS Keychain on MacBook.
Commands
# Store password
security add-generic-password \\
-s restic-backup \\
-a lilith-platform-workstations \\
-w CWPVvKALTwyJfbdVE3oIq7L8Wc7MH4Pz \\
-U
# Retrieve password
security find-generic-password \\
-s restic-backup \\
-a lilith-platform-workstations \\
-w
# View in GUI
open /System/Applications/Utilities/Keychain Access.app
# Search for "restic-backup"
API
setupVaultSymlink(projectPath: string): Promise<SymlinkResult>
Create ~/.vault/ → <projectPath>/vault/ symlink.
Returns:
success: Whether setup succeededsymlinkPath: Symlink path (~/.vault/)targetPath: Target path (<project>/vault/)error: Error message if failed
verifyVaultAccess(vaultPath?: string): Promise<VerificationResult>
Verify vault is accessible.
Parameters:
vaultPath: Vault path to check (default:~/.vault/)
Returns:
accessible: Whether vault is readablevaultPath: Path checkedisSymlink: Whether it's a symlinktargetPath: Symlink target (if applicable)error: Error message if not accessible
storeInKeychain(secret: KeychainSecret): Promise<KeychainResult>
Store secret in macOS Keychain.
Parameters:
secret.service: Service name (e.g., "restic-backup")secret.account: Account name (e.g., "lilith-platform-workstations")secret.password: Password to store
Returns:
success: Whether operation succeedederror: Error message if failed
Note: macOS only - returns error on other platforms
retrieveFromKeychain(service: string, account: string): Promise<KeychainResult>
Retrieve secret from macOS Keychain.
Parameters:
service: Service nameaccount: Account name
Returns:
success: Whether operation succeededpassword: Retrieved passworderror: Error message if failed
Requirements
- macOS: Required for Keychain operations (symlink works on all platforms)
- Project vault: Target project must have
vault/directory
Integration
Works with @lilith/vault-setup-backup for encrypted backups and @lilith/restic-setup-client for automated backups.
License
UNLICENSED - Internal Lilith Platform infrastructure package