diff options
| author | Your Name <you@example.com> | 2026-05-27 15:32:38 +0530 |
|---|---|---|
| committer | Your Name <you@example.com> | 2026-05-27 15:32:38 +0530 |
| commit | d889b890f9e63815c178853ed98a1e31f6cec7f8 (patch) | |
| tree | 3eda17e8edaf61cc6dba640ae12a24e90c9d8b8c /NIP46-PLAN.md | |
| parent | d60fa03de6edae0667a93ac36be4206e76255a2c (diff) | |
Fix compile issues for NIP-46 build
- nip46.rs: match on owned RelayPoolNotification (not .as_ref())
- git_mirror.rs: accept shared nostr_sdk::Client for state event publishing
- main.rs: pass nostr_client to mirror_repo_to_servers
- NIP46-PLAN.md: full implementation checklist and roadmap
- PLAN.md: updated
Diffstat (limited to 'NIP46-PLAN.md')
| -rw-r--r-- | NIP46-PLAN.md | 111 |
1 files changed, 111 insertions, 0 deletions
diff --git a/NIP46-PLAN.md b/NIP46-PLAN.md new file mode 100644 index 0000000..8d8d56b --- /dev/null +++ b/NIP46-PLAN.md | |||
| @@ -0,0 +1,111 @@ | |||
| 1 | # GRASP Mirror NIP-46 Remote Signing — Implementation Plan | ||
| 2 | |||
| 3 | ## Goal | ||
| 4 | |||
| 5 | Build and deploy the grasp-mirror daemon with NIP-46 remote signing so it can publish authenticated `kind:30618` state events and push git data to GRASP servers, without storing nsec keys on the VPS. | ||
| 6 | |||
| 7 | ## Architecture | ||
| 8 | |||
| 9 | ``` | ||
| 10 | ┌─────────────┐ | ||
| 11 | │ Amber │ | ||
| 12 | │ (phone) │ | ||
| 13 | └──────┬──────┘ | ||
| 14 | │ NIP-46 (kind:24133) | ||
| 15 | │ NIP-04 encrypted | ||
| 16 | ┌──────┴──────┐ | ||
| 17 | │ Nostr Relay │ | ||
| 18 | │ (relay/ngit)│ | ||
| 19 | └──────┬──────┘ | ||
| 20 | │ | ||
| 21 | ┌──────┴──────┐ | ||
| 22 | │ grasp-mirror│ | ||
| 23 | │ daemon │ | ||
| 24 | │ (VPS) │ | ||
| 25 | └──────┬──────┘ | ||
| 26 | │ git push + kind:30618 | ||
| 27 | ┌──────┴──────┐ | ||
| 28 | │ GRASP │ | ||
| 29 | │ servers │ | ||
| 30 | └─────────────┘ | ||
| 31 | ``` | ||
| 32 | |||
| 33 | - Daemon generates client keypairs per npub, persists in SQLite | ||
| 34 | - Produces `nostrconnect://` pairing URIs shown in health endpoint | ||
| 35 | - User opens URI in Amber → NIP-46 session established | ||
| 36 | - Before git push, daemon builds unsigned `kind:30618` from repo refs | ||
| 37 | - Sends `sign_event` request to signer via NIP-46 relay protocol | ||
| 38 | - Amber signs on phone → daemon receives signed event → publishes + pushes | ||
| 39 | |||
| 40 | ## Checklist | ||
| 41 | |||
| 42 | ### Phase 1: Fix compile errors locally | ||
| 43 | |||
| 44 | - [ ] Fix `nip46.rs` — `notification.as_ref()` → match on owned `RelayPoolNotification` | ||
| 45 | - [ ] Fix `nip46.rs` — ensure `message.id()` borrow is cloned before consuming message | ||
| 46 | - [ ] Fix `git_mirror.rs` — accept shared `nostr_sdk::Client` instead of creating throwaway per server | ||
| 47 | - [ ] Fix `main.rs` — pass `nostr_client` to `git_mirror.mirror_repo_to_servers` | ||
| 48 | - [ ] Verify `db.rs` — `bool` FromRow works with sqlx 0.8 sqlite INTEGER | ||
| 49 | - [ ] Pin Rust 1.95.0 in Ansible role `tasks/main.yml` | ||
| 50 | - [ ] Commit and push to GRASP origin | ||
| 51 | |||
| 52 | ### Phase 2: Build on VPS | ||
| 53 | |||
| 54 | - [ ] GRASP server running on target VPS (dependency: migration session) | ||
| 55 | - [ ] Push SSH key to VPS for Ansible key-based auth | ||
| 56 | - [ ] Run `ansible-playbook playbooks/30-grasp-mirror.yml -v` | ||
| 57 | - [ ] Fix any remaining compile errors iteratively | ||
| 58 | - [ ] Binary installed at `/usr/local/bin/grasp-mirror` | ||
| 59 | - [ ] Systemd service `grasp-mirror` running | ||
| 60 | |||
| 61 | ### Phase 3: Verify and pair | ||
| 62 | |||
| 63 | - [ ] Health endpoint responds: `curl http://localhost:7335/health` | ||
| 64 | - [ ] Response includes `nip46` array with session statuses | ||
| 65 | - [ ] Each unpaired npub shows `pairing_uri` | ||
| 66 | - [ ] Pair npub 1 (`npub12m5...`) via Amber | ||
| 67 | - [ ] Pair npub 2 (`npub19jx...`) via Amber | ||
| 68 | - [ ] Pair npub 3 (`npub1c03...`) via Amber | ||
| 69 | - [ ] Health endpoint shows all 3 sessions `connected: true` | ||
| 70 | - [ ] Test signing: daemon builds and signs a `kind:30618` event | ||
| 71 | - [ ] Test push: git data pushes to a target GRASP server | ||
| 72 | |||
| 73 | ### Phase 4: Document roadmap | ||
| 74 | |||
| 75 | - [ ] Add QEMU/OpenWRT orchestration roadmap to PLAN.md or PROGRESS.md | ||
| 76 | |||
| 77 | ## Key Files | ||
| 78 | |||
| 79 | | File | Role | | ||
| 80 | |---|---| | ||
| 81 | | `src/nip46.rs` | NIP-46 client: sessions, NIP-04 encrypt/decrypt, relay listener, `sign_event()` | | ||
| 82 | | `src/db.rs` | `nip46_sessions` table + CRUD methods | | ||
| 83 | | `src/config.rs` | `Nip46Config` with relays + signing_timeout_secs | | ||
| 84 | | `src/git_mirror.rs` | Builds unsigned `kind:30618`, signs via NIP-46, publishes before push | | ||
| 85 | | `src/http_health.rs` | NIP-46 session status in `/health` JSON | | ||
| 86 | | `src/main.rs` | Wires NIP-46 init + listener into daemon startup | | ||
| 87 | | `ansible/roles/grasp_mirror/tasks/main.yml` | Ansible deploy tasks (build + install) | | ||
| 88 | | `ansible/roles/grasp_mirror/defaults/main.yml` | NIP-46 relay + timeout vars | | ||
| 89 | | `ansible/roles/grasp_mirror/templates/config.toml.j2` | Config with `[nip46]` section | | ||
| 90 | |||
| 91 | ## Constraints | ||
| 92 | |||
| 93 | - No `any` type in TypeScript (N/A — Rust project) | ||
| 94 | - No comments in code unless requested | ||
| 95 | - Use `pnpm` for JS, `cargo` for Rust | ||
| 96 | - Rust 1.95.0 required (nostr-sdk 0.39 doesn't compile on 1.85) | ||
| 97 | - NIP-04 encryption for NIP-46 messages (not NIP-44 — simpler, Amber supports it) | ||
| 98 | - Signing timeout: 7 days (604800 seconds) — queue-and-wait model | ||
| 99 | - GRASP push auth requires signed `kind:30618` by maintainer, not HTTP auth | ||
| 100 | |||
| 101 | ## Future Roadmap: QEMU/OpenWRT Test Orchestration | ||
| 102 | |||
| 103 | After migration, repurpose old VPS (2 vCPU, 8GB RAM, 99GB disk) as dedicated OpenWRT test runner: | ||
| 104 | |||
| 105 | 1. **Deploy loom-worker** on old VPS — decentralized compute marketplace via Nostr | ||
| 106 | 2. **Write QEMU execution adapter** for loom — Unix domain socket that spins up OpenWRT instances, runs tests, streams results | ||
| 107 | 3. **Use existing act-runner** custom pipeline to submit loom jobs from CI | ||
| 108 | 4. **Do NOT build custom orchestration** — loom already has standardized event kinds (5001/5100/5101), Cashu payments, Blossom result storage, encrypted communication | ||
| 109 | 5. **Evaluate loom from budabit** (`nostr://npub1hw6amg8p24ne08c9gdq8hhpqx0t0pwanpae9z25crn7m9uy7yarse465gr/relay.ngit.dev/loom-worker`) before building anything custom | ||
| 110 | |||
| 111 | Loom's pluggable adapter architecture means we write ~200 lines of Deno/TypeScript for the QEMU adapter and get the entire Nostr job queue, payment, and result streaming for free. | ||