diff --git a/.github/workflows/formatting.yml b/.github/workflows/lint.yml similarity index 61% rename from .github/workflows/formatting.yml rename to .github/workflows/lint.yml index bdfea4e..c03c02e 100644 --- a/.github/workflows/formatting.yml +++ b/.github/workflows/lint.yml @@ -1,16 +1,16 @@ -name: Formatting +name: Lint on: # Triggers the workflow on push or pull request events but only for the main branch push: branches: [main, release**] pull_request: - branches: [main, release**] + branches: [main, dev, release**] # Allows us to run the workflow manually from the Actions tab workflow_dispatch: jobs: - check-formatting: + fmt: runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v3 @@ -21,3 +21,15 @@ jobs: uses: DeterminateSystems/nix-installer-action@main - run: nix fmt -- --check . + + test: + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v3 + with: + submodules: recursive + + - name: Install Nix + uses: DeterminateSystems/nix-installer-action@main + + - run: nix flake check diff --git a/flake.nix b/flake.nix index a2eb5ae..c496f9b 100644 --- a/flake.nix +++ b/flake.nix @@ -29,7 +29,7 @@ forAllSystems = f: nixpkgs.lib.genAttrs supportedSystems (system: f { - pkgs = import nixpkgs {inherit system;}; + pkgs = import nixpkgs { inherit system; config.allowUnfree = true; }; }); in { nixosModules.default.imports = [./nixarr vpnconfinement.nixosModules.default]; @@ -39,9 +39,12 @@ permissions-test = pkgs.callPackage ./tests/permissions-test.nix { inherit (self) nixosModules; }; - vpn-confinement-test = pkgs.callPackage ./tests/vpn-confinement-test.nix { + simple-test = pkgs.callPackage ./tests/simple-test.nix { inherit (self) nixosModules; }; + # vpn-confinement-test = pkgs.callPackage ./tests/vpn-confinement-test.nix { + # inherit (self) nixosModules; + # }; }); devShells = forAllSystems ({pkgs}: { diff --git a/nixarr/transmission/cross-seed/default.nix b/nixarr/transmission/cross-seed/default.nix index 929b12b..061cd3f 100644 --- a/nixarr/transmission/cross-seed/default.nix +++ b/nixarr/transmission/cross-seed/default.nix @@ -85,7 +85,6 @@ in { systemd.tmpfiles.rules = [ - "L+ '${cfg.dataDir}'/config.js - - - - ${configJs}" "d '${cfg.dataDir}' 0700 ${cfg.user} root - -" ] ++ ( @@ -109,6 +108,10 @@ in { + pkgs.writeShellScript "transmission-prestart" '' ${pkgs.jq}/bin/jq --slurp add ${settingsFile} '${cfg.credentialsFile}' | install -D -m 600 -o '${cfg.user}' /dev/stdin '${cfg.dataDir}/config.json' + + cp "${configJs}" "${cfg.dataDir}/config.js" + chmod 600 "${cfg.dataDir}/config.js" + chown "${cfg.user}:${cfg.group}" "${cfg.dataDir}/config.js" '' ) ]; diff --git a/tests/simple-test.nix b/tests/simple-test.nix new file mode 100644 index 0000000..a402456 --- /dev/null +++ b/tests/simple-test.nix @@ -0,0 +1,120 @@ +{ + pkgs, + nixosModules, + lib ? pkgs.lib, +}: +pkgs.nixosTest { + name = "simple-test"; + + nodes.machine = { + config, + pkgs, + ... + }: { + imports = [nixosModules.default]; + + networking.firewall.enable = false; + + nixarr = { + enable = true; + + jellyfin.enable = true; + jellyseerr.enable = true; + audiobookshelf.enable = true; + plex.enable = true; + + transmission = { + enable = true; + privateTrackers.cross-seed.enable = true; + }; + + autobrr.enable = true; + bazarr.enable = true; + sonarr.enable = true; + radarr.enable = true; + readarr.enable = true; + readarr-audiobook.enable = true; + sabnzbd.enable = true; + lidarr.enable = true; + prowlarr.enable = true; + recyclarr = { + enable = true; + configuration = { + sonarr.series = { + base_url = "http://localhost:8989"; + api_key = "!env_var SONARR_API_KEY"; + quality_definition.type = "series"; + delete_old_custom_formats = true; + custom_formats = [ + { + trash_ids = [ + "85c61753df5da1fb2aab6f2a47426b09" # BR-DISK + "9c11cd3f07101cdba90a2d81cf0e56b4" # LQ + ]; + assign_scores_to = [ + { + name = "WEB-DL (1080p)"; + score = -10000; + } + ]; + } + ]; + }; + radarr.movies = { + base_url = "http://localhost:7878"; + api_key = "!env_var RADARR_API_KEY"; + quality_definition.type = "movie"; + delete_old_custom_formats = true; + custom_formats = [ + { + trash_ids = [ + "570bc9ebecd92723d2d21500f4be314c" # Remaster + "eca37840c13c6ef2dd0262b141a5482f" # 4K Remaster + ]; + assign_scores_to = [ + { + name = "HD Bluray + WEB"; + score = 25; + } + ]; + } + ]; + }; + }; + }; + }; + + # Create a test user to verify mediaUsers functionality + users.users.testuser = { + isNormalUser = true; + home = "/home/testuser"; + }; + }; + + testScript = '' + machine.wait_for_unit("multi-user.target") + + # Check that all services are operational + machine.succeed("systemctl is-active jellyfin") + machine.succeed("systemctl is-active jellyseerr") + machine.succeed("systemctl is-active audiobookshelf") + machine.succeed("systemctl is-active plex") + machine.succeed("systemctl is-active transmission") + machine.succeed("systemctl is-active autobrr") + machine.succeed("systemctl is-active bazarr") + machine.succeed("systemctl is-active sonarr") + machine.succeed("systemctl is-active radarr") + machine.succeed("systemctl is-active readarr") + machine.succeed("systemctl is-active readarr-audiobook") + machine.succeed("systemctl is-active sabnzbd") + machine.succeed("systemctl is-active lidarr") + machine.succeed("systemctl is-active prowlarr") + machine.succeed("systemctl is-active recyclarr") + + machine.succeed("nixarr list-api-keys") + machine.succeed("nixarr fix-permissions") + machine.succeed("nixarr wipe-uids-gids") + + print("\n=== Nixarr Simple Test Completed ===") + ''; +} diff --git a/tests/vpn-confinement-test.nix b/tests/vpn-confinement-test.nix index 3a3b7f6..ce9c96d 100644 --- a/tests/vpn-confinement-test.nix +++ b/tests/vpn-confinement-test.nix @@ -1,38 +1,38 @@ /* -VPN Confinement Integration Test + VPN Confinement Integration Test -This test validates that Nixarr services are properly confined to a VPN namespace -and cannot leak traffic when the VPN connection fails. It uses a 3-VM topology -to simulate real-world network conditions. + This test validates that Nixarr services are properly confined to a VPN namespace + and cannot leak traffic when the VPN connection fails. It uses a 3-VM topology + to simulate real-world network conditions. -Network Topology: -┌──────────────┐ VLAN 2 ┌─────────────┐ VLAN 1 ┌─────────────┐ -│internetClient│ ◄──────────── │ gateway │ ◄──────────── │ nixarrHost │ -│ 10.0.1.2 │ │ 10.0.1.1 │ │192.168.1.2 │ -│ fd00:2::2 │ │192.168.1.1 │ │ fd00:1::2 │ -└──────────────┘ │ fd00:2::1 │ └─────────────┘ - │ fd00:1::1 │ │ - └─────────────┘ │ - │ │ - WireGuard tunnel │ - 10.100.0.1 ◄────────────────────────┘ - fd00:100::1 VPN namespace - (10.100.0.2, fd00:100::2) + Network Topology: + ┌──────────────┐ VLAN 2 ┌─────────────┐ VLAN 1 ┌─────────────┐ + │internetClient│ ◄──────────── │ gateway │ ◄──────────── │ nixarrHost │ + │ 10.0.1.2 │ │ 10.0.1.1 │ │192.168.1.2 │ + │ fd00:2::2 │ │192.168.1.1 │ │ fd00:1::2 │ + └──────────────┘ │ fd00:2::1 │ └─────────────┘ + │ fd00:1::1 │ │ + └─────────────┘ │ + │ │ + WireGuard tunnel │ + 10.100.0.1 ◄────────────────────────┘ + fd00:100::1 VPN namespace + (10.100.0.2, fd00:100::2) -Test Coverage: -- VPN namespace isolation (transmission confined to wg namespace) -- IPv4 and IPv6 traffic routing through VPN tunnel -- Traffic leak prevention when VPN is down -- Port forwarding from external clients through gateway to VPN services -- DNS configuration in VPN namespace -- Service recovery after VPN reconnection + Test Coverage: + - VPN namespace isolation (transmission confined to wg namespace) + - IPv4 and IPv6 traffic routing through VPN tunnel + - Traffic leak prevention when VPN is down + - Port forwarding from external clients through gateway to VPN services + - DNS configuration in VPN namespace + - Service recovery after VPN reconnection -The test ensures that: -1. All transmission traffic goes through the VPN tunnel -2. Source IP is preserved (shows VPN client IP: 10.100.0.2/fd00:100::2) -3. No traffic leaks to host network when VPN fails -4. External port forwarding works correctly -5. Both IPv4 and IPv6 work identically through the tunnel + The test ensures that: + 1. All transmission traffic goes through the VPN tunnel + 2. Source IP is preserved (shows VPN client IP: 10.100.0.2/fd00:100::2) + 3. No traffic leaks to host network when VPN fails + 4. External port forwarding works correctly + 5. Both IPv4 and IPv6 work identically through the tunnel */ { pkgs,