nsecbunkerd/docs/runbook-migrations.md
Padreug 87e99e487e
Some checks failed
Docker image / build-and-push-image (push) Has been cancelled
docs: correct prisma-engines + migrate-on-boot accuracy in runbook
- nix devShell uses nixos-25.05's prisma-engines 6.7.0 (has
  libquery_engine.node) — the 7.x problem is the system/unstable channel
  only, not the flake's devShell (corrects an earlier overstatement; #30
  closed as invalid).
- start.js migrate-on-boot is a no-op on nix but IS the migration path on
  docker (image ENTRYPOINT) — don't assume it's dead everywhere (#31).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 20:50:21 +02:00

71 lines
3.5 KiB
Markdown

# nsecbunkerd migration & DB-maintenance runbook
Operational notes for applying schema migrations and ACL/pairing maintenance on
deployed, **LNbits-connected** nsecbunkerd instances.
## ⚠️ Never full-wipe `nsecbunker.db` on an LNbits-connected instance
The nsecbunkerd ↔ LNbits pairing is **split across both systems**:
- **Bunker** (`nsecbunker.db`): per-account `KeyUser` binding (keyed by LNbits's
stable client pubkey) + redeemed `Token` + a shared `Policy`.
- **LNbits** (`accounts.signer_config`, `RemoteBunkerSigner`):
`{token, client_nsec, policy_id}`.
`RemoteBunkerSigner.sign_event()` signs **directly with the stored `client_nsec`**
— it does NOT re-connect/re-redeem, and there is **no auto-repair** on restart or
sign-failure. `provision()` runs only at new-account creation and mints a NEW
npub (which changes the user's nostr identity).
**Consequence of a full `nsecbunker.db` wipe:** the `KeyUser` bindings are
deleted → every LNbits account's stored config dangles → all signing fails, and
the only standard "repair" (`provision()`) changes identities. **Do not do it.**
### Correct way to strip the #24 materialized photocopies
Post-#27, token grants are evaluated live via the ACL step-4 `Token → Policy →
PolicyRule` join, so the old materialized `SigningCondition` rows are redundant
— and, written with `expiresAt = NULL`, they would keep granting past a token's
expiry (silently re-opening #24 for already-paired clients). Strip them with a
**targeted delete** that preserves the pairing:
```sql
-- Verify first.
SELECT COUNT(*) FROM Token WHERE redeemedAt IS NOT NULL; -- bindings to preserve
SELECT COUNT(*) FROM SigningCondition; -- photocopies to strip
-- Keeps KeyUser + Token + Policy intact. Live-token clients keep working
-- untouched; only the stale photocopies are removed.
DELETE FROM SigningCondition;
```
Run against each instance's `nsecbunker.db`. If an instance was already
full-wiped, recover by restoring the pre-wipe `nsecbunker.db` backup, then run
the targeted delete.
> Manual-override grants (`add_signing_condition`, web-approval) also live in
> `SigningCondition`. On an LNbits-only bunker there typically are none, so a
> blanket `DELETE FROM SigningCondition` is safe. If an instance uses manual
> overrides, delete only the policy-derived rows you intend to strip.
## Keys are never in the DB
Key material lives in `nsecbunker.json` (`keys`), never in `nsecbunker.db`. A DB
wipe loses ACL/pairing state, never keys. LNbits holds the bunker **admin nsec**
(`LNBITS_NSEC_BUNKER_ADMIN_NSEC`) and is the sole admin client.
## Schema migrations
On the **nix deploy**, migrations are applied by the deploy's `prisma migrate
deploy`, not by the daemon — `start.js`'s `npm run prisma:migrate` step fails in
the read-only nix store (no `npm` on PATH) and is a redundant no-op there (#31).
On **docker**, by contrast, `start.js` IS the migration path (it's the image
`ENTRYPOINT`), so the step is not dead everywhere. After adding a migration, make
sure the path that applies for your target actually runs it.
Prisma on NixOS: the flake pins **nixos-25.05**, whose `prisma-engines` is
**6.7.0** (ships `libquery_engine.node`) — both the devShell and the deploy's
`package.nix` use it, so `prisma` (and the `npm run test:integration` suite) work
in `nix develop` out of the box. Heads-up: on **nixos-unstable / a system
`<nixpkgs>` channel**, the bare `prisma-engines` attr is 7.x with no
`libquery_engine.node`; don't run the repo's prisma against an unstable channel.