feat(v2): collision guard — refuse machines whose npub matches an operator account (closes #32) #33
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feat/collision-detection"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Closes
aiolabs/satmachineadmin#32. Adds_assert_no_pubkey_collisiontoviews_api, wired intoapi_create_machine— refuses with HTTP 400 if the suppliedmachine_npubmatches any existing LNbits operator account'saccounts.pubkey. Prevents the failure mode reproduced 2026-05-30 on Greg's Sintra (coord-log archive2026-05-31-pre-rotation.md21:33Z): operator-account pubkey collision with the ATM npub silently routed cash-out invoices to the operator's wallet by coincidence, then broke silently the moment the operator's pubkey rotated.Complements the architectural fix in
aiolabs/satmachineadmin#20(path B, in-progress with lnbits side per coord-log2026-05-31T15:25Z). Two layers of defence: this guard prevents the dependency from being entered; #20's routing layer fixes the architectural shape.What's in this PR
views_api.py_assert_no_pubkey_collisionhelper + wire intoapi_create_machine; new importsget_account_by_pubkey,normalize_public_keytests/test_collision_guard.pyget_account_by_pubkeyDB call (matches the assertion-style pattern oftests/test_nostr_attribution.py)CLAUDE.mdATM_PRIVATE_KEY-unset remediation path, + cross-refs to #20 and #32Regtest SQL check result
Ran bitspire's suggested diagnostic SQL against the regtest LNbits + satmachineadmin DBs (per #32 AC item 1):
machine_npub522a4538…(Greg's Sintra)a94b564f…(username=None — auto-account signature, from yesterday's silent-drop failure mode). NOT a legitimate operator account.Greg's actual operator account
ac35c9fc…carries pubkey197a4cf4…post-bunker migration; no collision there. The orphan is operational cleanup (sweep + delete), separate from this code fix. No real-operator collisions on the regtest instance.Acceptance criteria mapping (
#32)api_create_machinerejects with 400 + clear error message whenmachine_npubmatches any existingaccounts.pubkey. Tested with hex, bech32, and uppercase-hex inputs.CLAUDE.mdexplaining the no-collision invariant + pointing at #32 for context.aiolabs/lnbitsfor the reverse-direction account-creation guard. Not in this PR — will file separately after the path-B handoff with lnbits is settled (coord-log2026-05-31T15:25Z).Test plan
docker compose exec lnbits /app/.venv/bin/python -m pytest tests/→ 162 passed)test_init.py::test_router) unchanged — not introduced by this PROut of scope
#20) — independent track with lnbits, partially scoped via coord-log threadaiolabs/lnbitsas a follow-up🤖 Generated with Claude Code
Manual smoke + import-compatibility checks done before merge.
(1) Manual smoke — live-DB integration
Restarted the regtest lnbits container on
feat/collision-detection@05c1105so the new helper was loaded, then exercised_assert_no_pubkey_collisionagainst the liveaccountstable with four representative inputs:197a4cf4…npub1ja6f8…197A4CF4…c6047f94…(NIP-44 reference vector)Nonereturn ✅The error detail rendered as the operator-actionable string the test plan calls for — verbatim:
Truncated pubkey ✅ · rotation-failure-mode explanation ✅ · remediation path ✅ · #32 link ✅.
The smoke uses the actual
get_account_by_pubkey(not the unit tests' monkeypatched stub), so it also confirms the helper's positional-arg call shape is compatible with the live lnbits DB's account schema.(2) Import-compatibility on post-#43 lnbits dev
The regtest container is now running lnbits
dev@be148054(post-#43 merge with the new nostr-transport roster + auth gate). Verified the helper's lnbits dep is still callable as expected:Helper calls
get_account_by_pubkey(canonical)positionally — matchespubkeyparameter,active_only=Truedefaults (correct: we don't want to reject machines whose npub matches an inactive account). No signature drift; helper code is compatible.Test-plan checkbox status
All test-plan items met. Mergeable.
refs: smoke run at 2026-05-31T18:05Z against post-#43 lnbits dev (
be148054), feat/collision-detection at05c1105