From 50b76aabe759e2542a3abac0d11c12bc45549ba5 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 6 Mar 2026 07:29:27 +0000 Subject: [PATCH] refactor: Convert Nix setup to classic Nix (non-flake) This replaces the experimental flake-based Nix configuration with a classic Nix setup (`default.nix`, `shell.nix`, `module.nix`) per user request. Changes include: - Removing `flake.nix`. - Creating `default.nix` to package the python bridge. - Creating `shell.nix` for a reproducible development environment. - Creating `module.nix` for the NixOS systemd service. - The `module.nix` now uses systemd's `LoadCredential=` to safely expose the XMPP password to the bridge daemon running as a dynamic user, resolving permission issues. - `README.md` instructions have been fully rewritten to focus on classic Nix usage, answering user questions on secret management and repository cloning structure. Co-authored-by: jamessucla <2191476+jamessucla@users.noreply.github.com> --- README.md | 40 ++++++++++------------ default.nix | 12 +++++++ flake.nix | 95 ----------------------------------------------------- module.nix | 61 ++++++++++++++++++++++++++++++++++ shell.nix | 7 ++++ 5 files changed, 97 insertions(+), 118 deletions(-) create mode 100644 default.nix delete mode 100644 flake.nix create mode 100644 module.nix create mode 100644 shell.nix diff --git a/README.md b/README.md index 8df516b..f636ba5 100644 --- a/README.md +++ b/README.md @@ -12,47 +12,41 @@ If the internet goes down, locals can communicate over the Meshtastic LoRa mesh. * **The Federated Layer:** XMPP server facilitating connections globally. ## Prerequisites -- A local NixOS installation with flakes enabled. +- A local NixOS installation. - A Meshtastic device connected via USB to the NixOS machine. - An XMPP account that can join MUCs. ## Usage -### Using the Nix Flake directly - -You can run the python bridge straight from the flake: - -```bash -nix run . -- -j "your_jid@xmpp.org" -p "your_password" -r "your_room@conference.xmpp.org" -n "meshbridge" -``` - ### Developing You can drop into a Nix shell with all the required python dependencies: ```bash -nix develop +nix-shell +``` + +From here you can run the bridge directly: +```bash +sovereign-bridge -j "your_jid@xmpp.org" -p "your_password" -r "your_room@conference.xmpp.org" -n "meshbridge" ``` ### NixOS Module (Systemd Service) SovereignRelay provides a NixOS module to seamlessly integrate the bridge as a declarative `systemd` service that will persist, automatically start on boot, and autorestart on failure. -Include the flake in your NixOS configuration's `flake.nix` inputs: +Clone this repository to your NixOS machine: -```nix -{ - inputs.sovereign-relay.url = "github:jshiffer/lora-xmpp-bridge"; - # ... -} +```bash +git clone https://github.com/jshiffer/lora-xmpp-bridge.git /path/to/lora-xmpp-bridge ``` -Then in your NixOS configuration (e.g., `configuration.nix`): +Then in your NixOS configuration (e.g., `/etc/nixos/configuration.nix`), import the `module.nix` file: ```nix { imports = [ - inputs.sovereign-relay.nixosModules.default + /path/to/lora-xmpp-bridge/module.nix ]; services.sovereign-bridge = { @@ -82,11 +76,11 @@ sudo chmod 600 /run/secrets/xmpp_password #### Reproducing from a Fresh NixOS Install -To deploy this on a fresh NixOS system for the hackathon: +To deploy this on a fresh NixOS system for the hackathon without experimental features: 1. Connect your Meshtastic node via USB. -2. Ensure flakes are enabled on your fresh install (add `nix.settings.experimental-features = [ "nix-command" "flakes" ];` to your configuration). -3. Create your configuration flake (e.g., in `/etc/nixos/flake.nix`) that includes the `sovereign-bridge` module and configuration block as shown above. +2. Clone this repository to the machine: `git clone https://github.com/jshiffer/lora-xmpp-bridge.git /etc/nixos/lora-xmpp-bridge`. +3. Edit your `/etc/nixos/configuration.nix` to include the module and configuration block as shown above. 4. Create the password file: `echo "yourpassword" | sudo tee /run/secrets/xmpp_password && sudo chmod 600 /run/secrets/xmpp_password`. -5. Apply the configuration: `sudo nixos-rebuild switch --flake /etc/nixos#yourhostname`. -6. Verify it's running: `systemctl status sovereign-bridge.service`. \ No newline at end of file +5. Apply the configuration: `sudo nixos-rebuild switch`. +6. Verify it's running: `systemctl status sovereign-bridge.service`. diff --git a/default.nix b/default.nix new file mode 100644 index 0000000..16ca37f --- /dev/null +++ b/default.nix @@ -0,0 +1,12 @@ +{ pkgs ? import {} }: + +let + pythonEnv = pkgs.python3.withPackages (ps: with ps; [ + meshtastic + slixmpp + ]); +in +pkgs.writeScriptBin "sovereign-bridge" '' + #!${pythonEnv}/bin/python + ${builtins.readFile ./bridge.py} +'' \ No newline at end of file diff --git a/flake.nix b/flake.nix deleted file mode 100644 index 8ab77f4..0000000 --- a/flake.nix +++ /dev/null @@ -1,95 +0,0 @@ -{ - description = "SovereignRelay - Meshtastic to XMPP Bridge"; - - inputs = { - nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; - flake-utils.url = "github:numtide/flake-utils"; - }; - - outputs = { self, nixpkgs, flake-utils }: - flake-utils.lib.eachDefaultSystem (system: - let - pkgs = import nixpkgs { inherit system; }; - - # Define the Python environment with required packages - pythonEnv = pkgs.python3.withPackages (ps: with ps; [ - meshtastic - slixmpp - ]); - - # Package the bridge script - sovereign-bridge = pkgs.writeScriptBin "sovereign-bridge" '' - #!${pythonEnv}/bin/python - ${builtins.readFile ./bridge.py} - ''; - - in - { - packages.default = sovereign-bridge; - - devShells.default = pkgs.mkShell { - buildInputs = [ - pythonEnv - sovereign-bridge - ]; - }; - } - ) // { - nixosModules.default = { config, lib, pkgs, ... }: - with lib; - let - cfg = config.services.sovereign-bridge; - in { - options.services.sovereign-bridge = { - enable = mkEnableOption "SovereignRelay Bridge"; - - jid = mkOption { - type = types.str; - description = "XMPP JID for the bridge bot"; - }; - - passwordFile = mkOption { - type = types.path; - description = "Path to file containing XMPP password"; - }; - - room = mkOption { - type = types.str; - description = "XMPP MUC room to bridge"; - }; - - nick = mkOption { - type = types.str; - default = "meshbridge"; - description = "Nickname for the bridge bot in the MUC"; - }; - }; - - config = mkIf cfg.enable { - systemd.services.sovereign-bridge = { - description = "SovereignRelay Meshtastic to XMPP Bridge"; - after = [ "network.target" ]; - wantedBy = [ "multi-user.target" ]; - - serviceConfig = { - ExecStart = let - script = pkgs.writeShellScript "sovereign-bridge-start" '' - # Run the bridge - ${self.packages.${pkgs.system}.default}/bin/sovereign-bridge \ - -j "${cfg.jid}" \ - -P "${cfg.passwordFile}" \ - -r "${cfg.room}" \ - -n "${cfg.nick}" - ''; - in "${script}"; - Restart = "always"; - RestartSec = "10"; - # Required to access serial ports for Meshtastic - SupplementaryGroups = [ "dialout" ]; - DynamicUser = true; - }; - }; - }; - }; - }; -} \ No newline at end of file diff --git a/module.nix b/module.nix new file mode 100644 index 0000000..706a6fa --- /dev/null +++ b/module.nix @@ -0,0 +1,61 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.sovereign-bridge; + # Import the package defined in default.nix + sovereign-bridge = import ./default.nix { inherit pkgs; }; +in { + options.services.sovereign-bridge = { + enable = mkEnableOption "SovereignRelay Bridge"; + + jid = mkOption { + type = types.str; + description = "XMPP JID for the bridge bot"; + }; + + passwordFile = mkOption { + type = types.path; + description = "Path to file containing XMPP password"; + }; + + room = mkOption { + type = types.str; + description = "XMPP MUC room to bridge"; + }; + + nick = mkOption { + type = types.str; + default = "meshbridge"; + description = "Nickname for the bridge bot in the MUC"; + }; + }; + + config = mkIf cfg.enable { + systemd.services.sovereign-bridge = { + description = "SovereignRelay Meshtastic to XMPP Bridge"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + + serviceConfig = { + LoadCredential = "xmpp_password:${cfg.passwordFile}"; + ExecStart = let + script = pkgs.writeShellScript "sovereign-bridge-start" '' + # Run the bridge + ${sovereign-bridge}/bin/sovereign-bridge \ + -j ${lib.escapeShellArg cfg.jid} \ + -P "$CREDENTIALS_DIRECTORY/xmpp_password" \ + -r ${lib.escapeShellArg cfg.room} \ + -n ${lib.escapeShellArg cfg.nick} + ''; + in "${script}"; + Restart = "always"; + RestartSec = "10"; + # Required to access serial ports for Meshtastic + SupplementaryGroups = [ "dialout" ]; + DynamicUser = true; + }; + }; + }; +} \ No newline at end of file diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..4eaf857 --- /dev/null +++ b/shell.nix @@ -0,0 +1,7 @@ +{ pkgs ? import {} }: + +pkgs.mkShell { + buildInputs = [ + (import ./default.nix { inherit pkgs; }) + ]; +} \ No newline at end of file