From 14c686191890c8c7ce210fc028ee8138955f280d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 27 Jul 2026 05:00:37 +0000 Subject: [PATCH 1/2] Initial plan From b9485c18dcf64fcf63d57a938a81d3c705da2647 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 27 Jul 2026 05:10:07 +0000 Subject: [PATCH 2/2] Fix AlbyHub executable and switch Wallet Connections to official NWC logo --- app/icons/nwc.svg | 1 + app/tests/test_wallet_connections.py | 76 ++++++++++++++++++++++++++++ docs/wallet-connections.md | 13 ++++- modules/core/sovran-hub.nix | 2 +- modules/nwc-wallets.nix | 2 +- 5 files changed, 91 insertions(+), 3 deletions(-) create mode 100644 app/icons/nwc.svg diff --git a/app/icons/nwc.svg b/app/icons/nwc.svg new file mode 100644 index 0000000..d995567 --- /dev/null +++ b/app/icons/nwc.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/tests/test_wallet_connections.py b/app/tests/test_wallet_connections.py index 5012778..676d2d5 100644 --- a/app/tests/test_wallet_connections.py +++ b/app/tests/test_wallet_connections.py @@ -26,6 +26,8 @@ Tests cover: import json import re +import shutil +import subprocess import sys import tempfile import types @@ -186,6 +188,13 @@ class FeatureRegistryTests(unittest.TestCase): self.assertIn(("80", "TCP"), ports) self.assertIn(("443", "TCP"), ports) + def test_wallet_connections_tile_icon_is_nwc(self): + repo_root = Path(__file__).resolve().parents[2] + hub_module = repo_root / "modules" / "core" / "sovran-hub.nix" + text = hub_module.read_text() + self.assertIn('{ name = "Wallet Connections"; unit = "albyhub.service"; type = "system"; icon = "nwc";', text) + self.assertIn('{ name = "Zeus Connect"; unit = "zeus-connect-setup.service"; type = "system"; icon = "zeus";', text) + def test_service_map_points_to_albyhub(self): self.assertEqual(server.FEATURE_SERVICE_MAP["nwc-wallets"], "albyhub.service") @@ -1096,6 +1105,18 @@ class LnurlHandlerAmountTests(unittest.TestCase): class NixPatchContractTests(unittest.TestCase): + @staticmethod + def _patched_albyhub_nix_expr(result_expr: str) -> str: + return ( + "let flake = builtins.getFlake (toString ./.); " + "pkgs = import flake.inputs.nixpkgs { system = builtins.currentSystem; }; " + "patchedAlbyHub = pkgs.albyhub.overrideAttrs (old: { patches = (old.patches or []) ++ [ " + "./packages/albyhub/0001-private-route-hints.patch " + "./packages/albyhub/0002-isolated-invoice-app-id.patch " + "]; }); " + f"in {result_expr}" + ) + def test_nwc_module_uses_non_placeholder_albyhub_strategy(self): repo_root = Path(__file__).resolve().parents[2] module_path = repo_root / "modules" / "nwc-wallets.nix" @@ -1108,6 +1129,61 @@ class NixPatchContractTests(unittest.TestCase): self.assertIn("AUTO_UNLOCK_PASSWORD", text) self.assertNotIn("AUTO_UNLOCK_PASSWORD_FILE", text) + def test_nwc_module_uses_lib_getexe_for_albyhub_binary(self): + repo_root = Path(__file__).resolve().parents[2] + module_path = repo_root / "modules" / "nwc-wallets.nix" + text = module_path.read_text() + self.assertIn("exec ${lib.getExe patchedAlbyHub}", text) + self.assertNotIn("${patchedAlbyHub}/bin/hub", text) + + def test_official_nwc_icon_asset_is_committed(self): + repo_root = Path(__file__).resolve().parents[2] + icon_path = repo_root / "app" / "icons" / "nwc.svg" + self.assertTrue(icon_path.exists()) + text = icon_path.read_text() + self.assertIn("linearGradient", text) + self.assertIn("#F7931A", text) + + def test_albyhub_main_program_via_nix_eval(self): + if shutil.which("nix") is None: + self.skipTest("nix not installed in this environment") + repo_root = Path(__file__).resolve().parents[2] + get_exe_expr = self._patched_albyhub_nix_expr("pkgs.lib.getExe patchedAlbyHub") + get_exe_result = subprocess.run( + [ + "nix", + "eval", + "--raw", + "--impure", + "--expr", + get_exe_expr, + ], + check=True, + capture_output=True, + text=True, + cwd=repo_root, + ) + exe_path = get_exe_result.stdout.strip() + self.assertIn("/nix/store/", exe_path) + self.assertTrue(exe_path.endswith("/bin/albyhub")) + self.assertNotIn("/bin/hub", exe_path) + + main_program_result = subprocess.run( + [ + "nix", + "eval", + "--raw", + "--impure", + "--expr", + self._patched_albyhub_nix_expr("patchedAlbyHub.meta.mainProgram"), + ], + check=True, + capture_output=True, + text=True, + cwd=repo_root, + ) + self.assertEqual(main_program_result.stdout.strip(), "albyhub") + def test_private_route_hint_patch_exact_change(self): repo_root = Path(__file__).resolve().parents[2] patch_path = repo_root / "packages" / "albyhub" / "0001-private-route-hints.patch" diff --git a/docs/wallet-connections.md b/docs/wallet-connections.md index 54bbf2f..2b02bce 100644 --- a/docs/wallet-connections.md +++ b/docs/wallet-connections.md @@ -80,9 +80,20 @@ No placeholder source/vendor hashes are used in the Wallet Connections module. | Service | User | Description | |---|---|---| | `albyhub.service` | `albyhub` | Headless Alby Hub NWC wallet server | -| `nwc-lnurl.service` | `nwc-lnurl` | Dedicated LNURL discovery and callback service | +| `nwc-lnurl.service` | `albyhub` | Dedicated LNURL discovery and callback service | | `albyhub-init.service` | `root` (oneshot) | Generates `unlock-password` once on first boot | +`nwc-lnurl.service` runs as `albyhub` so it can traverse `/var/lib/albyhub` (0700) and read `/var/lib/albyhub/unlock-password` (0600) without weakening permissions. + +## Wallet Connections icon asset + +- Hub service icon identifier: `nwc` (feature name remains **Wallet Connections**) +- Asset path in this repository: `app/icons/nwc.svg` +- Official source: `https://raw.githubusercontent.com/getAlby/nostr-wallet-connect/5fb6831739c7e6b089cd7205e11910ef542432ad/public/images/nwc-logo.svg` +- Upstream repository: `https://github.com/getAlby/nostr-wallet-connect` +- Upstream license: Apache-2.0 (`https://github.com/getAlby/nostr-wallet-connect/blob/5fb6831739c7e6b089cd7205e11910ef542432ad/LICENSE`) +- Attribution/redistribution note: Apache-2.0 permits redistribution; preserve upstream license notices in distributions. + ## API Management (authenticated): diff --git a/modules/core/sovran-hub.nix b/modules/core/sovran-hub.nix index ba5a1b7..08b796b 100644 --- a/modules/core/sovran-hub.nix +++ b/modules/core/sovran-hub.nix @@ -61,7 +61,7 @@ let { label = "Server"; value = "tcp://127.0.0.1:50001 (Electrs)"; } { label = "Status"; value = "Auto-configured on first boot"; } ]; } - { name = "Wallet Connections"; unit = "albyhub.service"; type = "system"; icon = "zeus"; enabled = cfg.features."nwc-wallets"; category = "bitcoin-apps"; credentials = [ + { name = "Wallet Connections"; unit = "albyhub.service"; type = "system"; icon = "nwc"; enabled = cfg.features."nwc-wallets"; category = "bitcoin-apps"; credentials = [ { label = "Lightning Address Domain"; file = "/var/lib/domains/lightning"; } ]; } { name = "Mempool"; unit = "mempool.service"; type = "system"; icon = "mempool"; enabled = cfg.features.mempool; category = "bitcoin-apps"; credentials = [ diff --git a/modules/nwc-wallets.nix b/modules/nwc-wallets.nix index e19ab5c..4c01c58 100644 --- a/modules/nwc-wallets.nix +++ b/modules/nwc-wallets.nix @@ -20,7 +20,7 @@ let ${pkgs.openssl}/bin/openssl rand -hex 32 > "$password_file" fi export AUTO_UNLOCK_PASSWORD="$(cat "$password_file")" - exec ${patchedAlbyHub}/bin/hub + exec ${lib.getExe patchedAlbyHub} ''; in lib.mkIf config.sovran_systemsOS.features."nwc-wallets" {