Commit Graph

1 Commits

Author SHA1 Message Date
Reuven 98aa2560e5 feat(encryption): ADR-096 Phase 2 — wire vault into session-tools
End-to-end opt-in encryption for the .claude-flow/sessions/*.json store.
The session writer is the smallest of the three high-tier targets, so it
ships first to bound the blast radius. Terminal stores and the
sql.js memory DB land in follow-up iterations.

Mechanics:

  src/fs-secure.ts
    - writeFileRestricted gains an options object: { encoding, encrypt }
      Legacy positional encoding signature still works, so all 5 existing
      call sites keep compiling unchanged.
    - When encrypt:true AND CLAUDE_FLOW_ENCRYPT_AT_REST is set, payload
      is run through encryptBuffer() before writeFileSync. Otherwise the
      flag is silently ignored — legacy plaintext path runs unchanged.
    - New readFileMaybeEncrypted(path, encoding?) — magic-byte sniff,
      decrypt-if-RFE1, otherwise pass-through. Two-overload signature
      mirrors fs.readFileSync (string default, Buffer with encoding=null).

  src/mcp-tools/session-tools.ts
    - saveSession passes { encrypt: true } unconditionally. The vault
      gate decides whether the bytes actually get encrypted.
    - loadSession + listSessions switch to readFileMaybeEncrypted, so
      a mixed plaintext+encrypted dir enumerates cleanly during the
      migration window.

Tests (__tests__/session-encryption.test.ts, 7 cases):

  encryption disabled
    - writes plaintext JSON (first byte '{', not 'R')
    - round-trips save → restore
  encryption enabled
    - on-disk blob starts with RFE1 magic
    - plaintext name is NOT present anywhere in the on-disk bytes
      (defense-in-depth: confirms encryption actually ran)
    - round-trips save → restore using the same key
  migration
    - a legacy plaintext file written before the gate flipped is
      still readable AFTER the gate flips on (sniff path)
  mixed dir
    - listSessions enumerates plain-1 + encrypted-1 in one call

Verified:
  tsc --noEmit clean (0 errors)
  Vault + fs-secure + session-encryption: 60/60
  Full vitest suite: 1917/1917 passing, 46 skipped, 0 failures
  (was 1910; +7 from the new test file)

Phase 3 wires terminal-tools.saveTerminalStore. Phase 4 wires the
seven memory-initializer DB writes.
2026-05-03 21:05:26 -04:00