Phase log 3: 2026-06-05 - Phase 5.1 + Docker (Handoff v2)
Salvaged from the Session History of
CLAUDE.original.md, a rolling log that held every session before Phase 12 in one file. That file was split up and deleted on 2026-08-25; its pitfalls and decisions live inCLAUDE.md. This entry is its text verbatim - written as a log, not to the handoff template, so it has no Goal/Next Steps sections.
Goal: Security hardening + Docker deployment + post-5 polish.
Security Hardening Applied
- Sub-user password hashing (
vault-core/src/users.rs): SHA-256 → Argon2id PHC (m=32768,t=2,p=1). Legacy<salt_hex>:<hash_hex>transparently upgraded on login. - TOTP anti-replay (
vault-core/src/users.rs):totp_last_step INTEGERcolumn; rejects any code whose counter step ≤ last accepted step. - Rate limiter: failures only, real IP (
envv-server/src/main.rs):rate_is_allowed()+record_auth_failure()split. IP fromConnectInfo<SocketAddr>(not spoofableX-Forwarded-For). - CORS restricted (
envv-server/src/main.rs):CorsLayer::permissive()→ explicit allow-list (http://localhost,http://127.0.0.1,tauri://localhost, port variants).
TypeScript Fixes
modals.ts:certificatekeyLabel'API Key'→'Certificate';file_blob→'File Reference'modals.ts:formToEntry()always includes'Universal'inprojectIdsmodals.ts:pushUndo()removes by object reference (notpop()- multiple deletes within 5s had wrong entry removed)lock.ts: Master password minimum 8 → 12 characters for new vaultslock.ts: Auto-lock timer resets on user activity (mousemove, keydown, mousedown, touchstart)vault.ts:entry.providerHTML-escaped before context menu dropdown labelrender.ts:api_url/callback_urlonly linked when protocol ishttp://orhttps://(preventsjavascript:XSS);rel="noopener noreferrer"
Docker Deployment
Dockerfile- multi-stage (rust:1.85-bookworm + debian:bookworm-slim); non-rootenvvuser (uid 1001); SQLCipher dynamic link (libsqlcipher0)docker-compose.ymlin project root; storage: bind mount./envv:/dataauto_unlock(state, password)inenvv-server/main.rs- readsENVV_PASSWORDenv var, derives key via Argon2id, opens DB, inserts owner session before server bindsdb_path.parent()fix - was trying to create system dirs as non-root; parent of db path always existsGET /api/stats- no auth;{ secrets_stored, users_total, users_connected, vault_unlocked }for Homepage/Homarr widgets
Docker Operations Reference
cd ~/docker && docker compose up -d # full stack start
docker compose up -d --build envv-server # rebuild after code changes
docker logs envv-server # check logs
docker compose down envv-server && docker volume rm docker_envv_data # reset vault
curl -X POST http://localhost:8743/api/unlock -H 'Content-Type: application/json' \
-d '{"password":"master-password"}' # manual unlock
Critical Bug Fixes
- Ctrl+Shift+V global hotkey removed - intercepted system-wide paste, caused vault lock and apparent data wipe for remote sessions
- Lock-on-hide skipped for remote vault (
state.ts):visibilitychangeskipslockVault()whenst.store.isRemote- remote lock destroys in-memory session token - Reset vault removed from unlock modal - was accessible without any authentication
Nginx + Chunk Improvements
chunkFieldCopyText()- context-aware copy format per chunk type (nginx:key value;, WG:Key = Value, SSH:Key Value, env:KEY=VALUE, k8s/Traefik:key: value)parseNginxConf(text)- full tokenizer respecting quoted strings; handlesserver {},upstream {}insidehttp {}/stream {}- nginx smart display:
renderListenBadge,renderServerNameBadges,renderReturnBadge,renderCertPanel - SSL cert auto-linking via
findLinkedCert()(by${REF}or letsencrypt path pattern) nginx_keychunk type - PEM cert/key display with green=cert, amber=key coloured blocksshowPromptLarge- textarea prompt for multi-line paste;Ctrl+Enterto confirm
Docker Project Overhaul
- Two-column layout (
3fr 2fr) - Left column:
renderDockerServicesCard()aggregates alldocker_servicechunks with nested YAML display; per-service scalar fields, ports, environment, volumes; hover-reveal action buttons - Right column: networks, volumes, env files
serviceChunkToYaml(),exportServicesSection()added tochunk-ops.tsexportDockerComposerewritten: proper- KEY=valueenv format, YAML port/volume lists,yamlStr()quoting helper