harbor notes encrypt deletes a note's version history without asking, then prints that the history is still readable.
What happens
Encrypting a note deletes every version snapshot that disagrees with the note's new state — the plaintext history is hard-deleted server-side, not tombstoned, and it is not recoverable. Decrypting does the same thing in reverse to the encrypted snapshots.
The CLI does neither of the two things a user needs here:
-
It doesn't warn. The confirmation for this is client-side, and harbor notes encrypt doesn't have one. It runs, the history is gone, and the user finds out later — if ever. (notes decrypt already asks for a typed yes; notes encrypt asks for nothing.)
-
It then tells the user the opposite of what just happened. cmd/notes_convert.go:605, printed after every run that seals something and carried in --help:
• It does not clear the plaintext ALREADY ON THE SERVER. The note's earlier versions were snapshotted as plaintext and stay readable (harbor history list <id>). …
That paragraph goes on to describe history coalescing as a rare exception "not to plan around." The exception is now the rule: every earlier version is deleted, every time.
So the message actively reassures someone that data still exists, moments after the CLI destroyed it. A user who encrypts a note because they want the old versions kept safe gets the exact opposite, silently.
Why it's wrong now
The copy predates the server change that made history and encryption state agree. Authoritative description: app.harbor.my/docs/encryption.md → "Changing encryption discards history", plus the code in internal/notes/. Short version:
- Every snapshot of a note must agree with that note's
is_encrypted. The write that changes the flag deletes every snapshot that disagrees.
- Hard
DELETE, not a tombstone. note_history doesn't sync and isn't indexed, so there is nothing to propagate and nothing to recover.
- It is deliberate — sealing old snapshots instead would need a per-version crypto pass in all five clients, and the guarantee would only be as good as the weakest one.
- The deletion is server-side; the confirmation is client-side.
docs/encryption.md names harbor notes encrypt explicitly as a caller that "will discard history without asking," accepted as a known interim state — with the intended end state being that every client warns first.
⚠️ Don't verify this against the other clients
The same false sentence was copy-pasted into several repos. Three of them are not independent confirmation — they are the same stale claim:
| Repo |
Status |
app.harbor.my (web) |
✅ Fixed — PR #1293 |
harbor-swift |
✅ Fixed — PR #842 |
harbor-windows |
❌ Still wrong — HarborCore/Ui/EncryptionDialogSpec.cs:63 |
harbor.my help docs |
❌ Still wrong — encrypted-notes.md, encrypt-or-decrypt-a-single-note.md, developers/cli.md |
docs/encryption.md and the server code are the source of truth. Note in particular that harbor.my/developers/cli.md:197 describes this CLI's caveat text — so fixing this issue makes that page wrong too, and it needs its own change.
What to do
- Warn before encrypting.
notes encrypt should say plainly that the note's version history will be deleted and that it cannot be recovered, and require confirmation — same shape as notes decrypt's typed yes, with a --yes escape for scripts. Applies to the bulk --notebook form too, which can wipe the history of every note in a notebook in one command.
- Warn before decrypting too.
notes decrypt already confirms, but for the wrong reason (publishing plaintext back). It also destroys the encrypted history and doesn't say so.
- Replace the false caveat in
cmd/notes_convert.go — the post-run message and --help. State that earlier versions are deleted. Delete the history-coalescing paragraph; it described a rare exception to a rule that no longer exists.
- The attachment-bytes caveat in the same block is still true — keep it. The CLI genuinely does not re-encrypt attachment bytes.
- Check
cmd/history.go and anywhere else that implies a note's history survives an encryption change.
Acceptance criteria
harbor notes encryptdeletes a note's version history without asking, then prints that the history is still readable.What happens
Encrypting a note deletes every version snapshot that disagrees with the note's new state — the plaintext history is hard-deleted server-side, not tombstoned, and it is not recoverable. Decrypting does the same thing in reverse to the encrypted snapshots.
The CLI does neither of the two things a user needs here:
It doesn't warn. The confirmation for this is client-side, and
harbor notes encryptdoesn't have one. It runs, the history is gone, and the user finds out later — if ever. (notes decryptalready asks for a typedyes;notes encryptasks for nothing.)It then tells the user the opposite of what just happened.
cmd/notes_convert.go:605, printed after every run that seals something and carried in--help:That paragraph goes on to describe history coalescing as a rare exception "not to plan around." The exception is now the rule: every earlier version is deleted, every time.
So the message actively reassures someone that data still exists, moments after the CLI destroyed it. A user who encrypts a note because they want the old versions kept safe gets the exact opposite, silently.
Why it's wrong now
The copy predates the server change that made history and encryption state agree. Authoritative description:
app.harbor.my/docs/encryption.md→ "Changing encryption discards history", plus the code ininternal/notes/. Short version:is_encrypted. The write that changes the flag deletes every snapshot that disagrees.DELETE, not a tombstone.note_historydoesn't sync and isn't indexed, so there is nothing to propagate and nothing to recover.docs/encryption.mdnamesharbor notes encryptexplicitly as a caller that "will discard history without asking," accepted as a known interim state — with the intended end state being that every client warns first.The same false sentence was copy-pasted into several repos. Three of them are not independent confirmation — they are the same stale claim:
app.harbor.my(web)harbor-swiftharbor-windowsHarborCore/Ui/EncryptionDialogSpec.cs:63harbor.myhelp docsencrypted-notes.md,encrypt-or-decrypt-a-single-note.md,developers/cli.mddocs/encryption.mdand the server code are the source of truth. Note in particular thatharbor.my/developers/cli.md:197describes this CLI's caveat text — so fixing this issue makes that page wrong too, and it needs its own change.What to do
notes encryptshould say plainly that the note's version history will be deleted and that it cannot be recovered, and require confirmation — same shape asnotes decrypt's typedyes, with a--yesescape for scripts. Applies to the bulk--notebookform too, which can wipe the history of every note in a notebook in one command.notes decryptalready confirms, but for the wrong reason (publishing plaintext back). It also destroys the encrypted history and doesn't say so.cmd/notes_convert.go— the post-run message and--help. State that earlier versions are deleted. Delete the history-coalescing paragraph; it described a rare exception to a rule that no longer exists.cmd/history.goand anywhere else that implies a note's history survives an encryption change.Acceptance criteria
harbor notes encryptrefuses to run unattended without confirmation, and the prompt names the history deletion in plain words.--yes(or equivalent) bypasses it for scripts.--notebookform confirms once, and says how many notes' histories it will delete.harbor notes decrypt's confirmation mentions the encrypted history being deleted, not only the plaintext downgrade.--help, or long description — claims earlier versions stay readable or stay plaintext after encrypting.harbor history list <id>and show they're gone.