Repository navigation
ShellGuard v0.0.2.1
π¦ ShellGuard β Release v0.0.2.1
"The Deep Storage Molt" β Phase 19: Attachment SQLite BLOB Migration & Streaming Architecture
ClawStack Studios Β©β’ Β· 2026-09-18 Β· AGPL-3.0
The attachment grotto goes native. Encrypted file payloads move from base64
TEXT strings into native SQLite BLOB storage, uploads and downloads become
streamed wire contracts (Busboy multipart in, chunked substr reads out),
and the grotto gains real limits: a 50MB per-file ceiling and a 500MB
per-owner quota, both failing closed with 413. The vault UI gains live
upload progress with cancel, on-demand streamed decryption, encrypted inline
previews for images and PDFs β and the Eye-beside-Copy control ergonomics
pulled forward from Phase 22.
Key Themes
- Native BLOB Storage β migration 0005 rebuilds
vault_secure_attachments
withfile_data BLOB+size_bytes INTEGER; legacy TEXT rows are
re-encoded in code (idempotent, transactional, VACUUM'd β no byte-level
ghosts). Base64's 33% storage inflation is gone. - The Streaming Wire Contract β uploads are multipart: the ShellCryption
envelope streams as already-encrypted bytes (zero-knowledge untouched, no
base64 inflation); the list endpoint is metadata-only β payload BLOBs
leave exclusively viaGET /api/attachments/:id/filein 1MB chunks, so a
vault listing never carries bulk ciphertext and downloads never spike RSS. - Limits & Quotas, Fail-Closed β 50MB per-file ceiling aborts mid-stream
(ATTACHMENT_MAX_MB); 500MB grotto quota perowner_uuid
(GROTTO_QUOTA_MB) via an exactSUM(size_bytes)aggregate; both yield
413and store nothing. - Streaming UI β real-time upload progress with cancel (XHR
onprogress/abort), on-demand decryption (the client decrypts with the
shellKey; the server never sees plaintext), and encrypted inline previews:
images render from the decrypted payload, PDFs from a Blob object URL
(never adata:URI on insecure origins). - Eye-beside-Copy Ergonomics (folded forward from P22/T44) β the Unmask
(Eye/EyeOff) toggle sits immediately LEFT of Copy in the right-hand action
cluster on every masked field row (password, SSH private key, hidden custom
fields); the full-value mask invariant holds (every character ββ’).
Verification
- Full test oracle: 19 files / 230 tests green, 1 skipped (the
Phase-24-targeted fallback-parity test) β including the new
tests/attachments-blob.test.ts(6 tests: migration, backfill idempotence,
multi-chunk streaming, per-file 413, quota 413, quota release) tsc --noEmit,vite build,docs:buildβ all cleandocsLinks+mermaidDiagramssuites β 10/10tsc --noEmit,vite build, VitePress build β all clean
Deployment
docker compose pull && docker compose up -d --wait
# or
docker compose up -d --buildData lives in ./data (db.sqlite + audit.sqlite). Set DB_ENCRYPTION_KEY
(strongly recommended). See QUICKSTART.md for the first-hatch walkthrough.
Commit Ledger (v0.0.2.0 β v0.0.2.1)
dee897f docs: sync Phase 19 BLOB/quota/streaming truth across the corpus
27df54b feat: streamed progress uploads, on-demand decryption & encrypted previews + Eye-beside-Copy (Phase 19 Task 38)
f4f6073 feat: attachment BLOB storage, streaming handlers & grotto quota (Phase 19 Task 37)
Your reef. Your keys. Your secrets. β Trust the Shell. π¦