checkpoint: document undo-delete secret-preserving fix (2026-09-10)
This commit is contained in:
parent
d101b8e236
commit
8780ef3fbb
1 changed files with 94 additions and 0 deletions
|
|
@ -1,3 +1,97 @@
|
||||||
|
# Checkpoint — Undo-delete restores working profiles (2026-09-10)
|
||||||
|
|
||||||
|
## Where things are
|
||||||
|
- Project: `/home/avi/Projects/Keynctr`
|
||||||
|
- Branch: `master` @ **`d101b8e`** ("fix(undo): restore full profile with secret key on undo-delete").
|
||||||
|
- Working tree: **clean for tracked files.** Only untracked entries are the pre-existing
|
||||||
|
hygiene leftovers plus two Rust scratch files (all intentionally untracked — see
|
||||||
|
"Still untracked").
|
||||||
|
|
||||||
|
## What was completed (this session)
|
||||||
|
|
||||||
|
**Step 6 (undo history) — the hollow-undo bug is fixed, landed as `d101b8e`.**
|
||||||
|
Deleting a profile used to keep only a `ProfileSummary` on the undo stack, so
|
||||||
|
undo re-created the profile with `secret_key = ""` — a dead shell that could never
|
||||||
|
sign. The undo stack now keeps the full stored record:
|
||||||
|
|
||||||
|
- **`src/profiles.rs`** — new `DeletedProfile { summary, stored }` struct;
|
||||||
|
`delete_profile_record()` returns the real stored secret (plaintext or encrypted
|
||||||
|
blob, exactly as on disk) plus the safe UI summary; `delete_profile()` stays as
|
||||||
|
the summary-only wrapper for callers that keep no undo entry.
|
||||||
|
- **`src/app.rs`** — `App.undo_history` is now `Vec<DeletedProfile>` (secret material
|
||||||
|
never leaves the backend); `undo_delete()` restores the real `StoredProfile`,
|
||||||
|
refuses to create a hollow profile (empty secret → entry handed back + error),
|
||||||
|
and `state_view()` still exposes only `summary` items so the renderer never sees
|
||||||
|
a secret. New regression test
|
||||||
|
`undo_delete_restores_working_profile_without_leaking_secret` locks this in.
|
||||||
|
- **`src/ipc.rs`** — `DeleteProfile` routes through `delete_profile_record` so the
|
||||||
|
GUI undo entry carries the secret (previously it pushed a summary-only entry,
|
||||||
|
so GUI undo was still hollow).
|
||||||
|
- **`src/main.rs`** — CLI `delete-profile`/`undo-delete` use the same record path
|
||||||
|
(`delete_profile_direct` → `delete_profile_record`, `cli_undo_delete` →
|
||||||
|
`app.undo_delete()`); also fixes the old "label looked up after removal" bug by
|
||||||
|
capturing the label before deletion, and drops the now-unused imports.
|
||||||
|
- Compile fixes included: the inherited work-in-progress did not build (`DeletedProfile`
|
||||||
|
vs `ProfileSummary` mismatch in `ipc.rs`, partial moves in `undo_delete`); both
|
||||||
|
resolved, plus `cargo fmt` applied.
|
||||||
|
|
||||||
|
Security properties: secret material stays backend-only (`AppStateView.undo_history`
|
||||||
|
is still `Vec<ProfileSummary>`); undo restores the exact stored blob (no re-derivation,
|
||||||
|
no logging); empty-secret entries fail closed instead of writing hollow profiles.
|
||||||
|
|
||||||
|
## Commits added this session (newest first)
|
||||||
|
| Hash | Message |
|
||||||
|
|------|---------|
|
||||||
|
| `d101b8e` | fix(undo): restore full profile with secret key on undo-delete |
|
||||||
|
|
||||||
|
(Parent chain — `1d5940f` display/icons checkpoint, `d580139` icon alpha fix,
|
||||||
|
`0814a53` Linux display compat, `715c99c`/`510cb65` connection-secrets vault
|
||||||
|
integration — is unchanged.)
|
||||||
|
|
||||||
|
## Verification (run this session, on top of `d101b8e`)
|
||||||
|
- **Rust**: `cargo test` → **197 passed**, 0 failed (196 pre-existing + 1 new
|
||||||
|
undo regression test); `cargo clippy --all-targets` → clean (exit 0);
|
||||||
|
`cargo fmt --check` → clean (exit 0); `cargo build --release` → Finished, exit 0.
|
||||||
|
- **Frontend** (in `frontend/`, Rust-only change so no frontend files touched):
|
||||||
|
`npm test` → **116/116 passed**; `npm run typecheck` → exit 0;
|
||||||
|
`npm run lint` → exit 0; `npm run electron:build` → exit 0; `npm run build` →
|
||||||
|
exit 0. `npm run format:check` → warns on the same 5 pre-existing files
|
||||||
|
(`ExportSecretKeyModal.tsx`, `SignerModeScreen.tsx`, `AppProvider.tsx`,
|
||||||
|
`ExportSecretKey.test.tsx`, `fakeBackend.ts`) documented in earlier checkpoints —
|
||||||
|
not introduced here, left untouched.
|
||||||
|
|
||||||
|
## How to reproduce / exercise
|
||||||
|
- Backend: `cargo run --release -- serve` (JSON-lines IPC on stdio) or the CLI in
|
||||||
|
`src/main.rs`.
|
||||||
|
- GUI: from `frontend/`, `npm run electron:build && electron .` (prod) or `npm run
|
||||||
|
start:dev` with `NOSTR_GUI_DEV_URL`.
|
||||||
|
- Exercise undo: Profiles → delete a profile → Undo delete → the restored profile
|
||||||
|
signs/publishes (previously it came back secret-less). CLI equivalent:
|
||||||
|
`keynectr delete-profile <npub>` then `keynectr undo-delete`.
|
||||||
|
|
||||||
|
## Still untracked (do NOT lose; do NOT commit the hygiene junk)
|
||||||
|
- **Source JPEG** `KeynectrAppIconPossibility02.jpeg` — intentionally untracked.
|
||||||
|
- Pre-existing untracked hygiene leftovers: `COSMIC_THEME.md`, `.opencode/`,
|
||||||
|
`.impeccable/critique/`, `.directory`, `deferred/SignerConnectionPanel.tsx.wip/`.
|
||||||
|
- Rust scratch files (unreferenced, harmless — neither is wired into the build):
|
||||||
|
`src/signer/nip46_external.rs` (dead stub, not declared in `src/signer/mod.rs`),
|
||||||
|
`src/publish.rs.bak` (backup copy). Left alone this session; delete or wire up
|
||||||
|
in a later pass.
|
||||||
|
- Build artifacts `release/` and `dist/` are gitignored and not committed.
|
||||||
|
- `profiles_vault.json*` and `target/` remain correctly untracked and uncommitted.
|
||||||
|
|
||||||
|
## Deferred / next steps (unchanged, minus the undo item)
|
||||||
|
- Step 3 sub-step 2 (IPC reroute) remains the next signer milestone; external
|
||||||
|
(remote) signing in the publish path still returns "not yet supported".
|
||||||
|
- External-signer permissions (Step 4), deferred security (Step 5: KDF upgrade,
|
||||||
|
`--allow-env-secret`, gate deprecated `RevealSecretKey`), hygiene (Step 7:
|
||||||
|
Keynctr rename incl. `package.json` → `homepage`, legacy Python removal, vault
|
||||||
|
relocation, Prettier pass over the 5 known files).
|
||||||
|
- Open question carried forward: `migrate_vault_signer_modes` reports a change on
|
||||||
|
every load (always `changed = true`), so `App::load` re-saves each start.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
# Checkpoint — NIP-46 Connection Secrets in the Vault (2026-09-04)
|
# Checkpoint — NIP-46 Connection Secrets in the Vault (2026-09-04)
|
||||||
|
|
||||||
## Where things are
|
## Where things are
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue