diff --git a/doc/release-notes/rl-2605.section.md b/doc/release-notes/rl-2605.section.md
index 9ad7fdcb9e5c..54c1f3d750c5 100644
--- a/doc/release-notes/rl-2605.section.md
+++ b/doc/release-notes/rl-2605.section.md
@@ -165,6 +165,10 @@
- The `programs.captive-browser` module no longer falls back on a setcap wrapper around udhcpc to discover your network's DNS server due to [GHSA-wc3r-c66x-8xmc](https://github.com/NixOS/nixpkgs/security/advisories/GHSA-wc3r-c66x-8xmc) (CVE-2026-25740). If you're using this module, you must either configure `programs.captive-browser.dhcp-dns` manually or enable one of NetworkManager, dhcpcd, or systemd-networkd.
+- NetBox was updated to `>= 4.5.5`. Have a look at the breaking changes
+ of the [4.5 release](https://github.com/netbox-community/netbox/releases/tag/v4.5.0),
+ make the required changes to your database, if needed, then upgrade by setting `services.netbox.package = pkgs.netbox_4_5;` in your configuration.
+
- The `services.yggdrasil` module has been refactored with the following breaking changes:
- The `services.yggdrasil.configFile` option has been removed. Configuration should now be specified directly via `services.yggdrasil.settings`.
- The `services.yggdrasil.persistentKeys` option has been removed. To maintain persistent keys and IPv6 addresses across reboots, use `services.yggdrasil.settings.PrivateKeyPath` to securely load your private key from a file via systemd credentials. The private key must be in PEM format (PKCS #8).
diff --git a/nixos/modules/services/web-apps/netbox.nix b/nixos/modules/services/web-apps/netbox.nix
index f49b8271928d..d380ab60bc41 100644
--- a/nixos/modules/services/web-apps/netbox.nix
+++ b/nixos/modules/services/web-apps/netbox.nix
@@ -119,11 +119,11 @@ in
package = lib.mkOption {
type = lib.types.package;
default =
- if lib.versionAtLeast config.system.stateVersion "25.11" then pkgs.netbox_4_4 else pkgs.netbox_4_2;
+ if lib.versionAtLeast config.system.stateVersion "26.05" then pkgs.netbox_4_5 else pkgs.netbox_4_4;
defaultText = lib.literalExpression ''
- if lib.versionAtLeast config.system.stateVersion "25.11"
- then pkgs.netbox_4_4
- else pkgs.netbox_4_2;
+ if lib.versionAtLeast config.system.stateVersion "26.05"
+ then pkgs.netbox_4_5
+ else pkgs.netbox_4_4;
'';
description = ''
NetBox package to use.
@@ -165,6 +165,15 @@ in
'';
};
+ apiTokenPeppersFile = lib.mkOption {
+ type = with lib.types; nullOr path;
+ description = ''
+ Path to a file containing the API_TOKEN_PEPPER that will be configured for the pepper_id with the id 1.
+ This is required for netbox >= 4.5. For generating this pepper,
+ [consider using `$INSTALL_ROOT/netbox/generate_secret_key.py`](https://netboxlabs.com/docs/netbox/configuration/required-parameters/#api_token_peppers)
+ '';
+ };
+
extraConfig = lib.mkOption {
type = lib.types.lines;
default = "";
@@ -237,10 +246,12 @@ in
GIT_PATH = "${pkgs.gitMinimal}/bin/git";
- DATABASE = {
- NAME = "netbox";
- USER = "netbox";
- HOST = "/run/postgresql";
+ DATABASES = {
+ "default" = {
+ NAME = "netbox";
+ USER = "netbox";
+ HOST = "/run/postgresql";
+ };
};
# Redis database settings. Redis is used for caching and for queuing
@@ -283,6 +294,12 @@ in
with open("${cfg.secretKeyFile}", "r") as file:
SECRET_KEY = file.readline()
''
+ + (lib.optionalString (cfg.apiTokenPeppersFile != null) ''
+ with open("${cfg.apiTokenPeppersFile}", "r") as pepper_file:
+ API_TOKEN_PEPPERS = {
+ 1: pepper_file.readline(),
+ };
+ '')
+ (lib.optionalString (cfg.keycloakClientSecret != null) ''
with open("${cfg.keycloakClientSecret}", "r") as file:
SOCIAL_AUTH_KEYCLOAK_SECRET = file.readline()
@@ -446,5 +463,12 @@ in
};
users.groups.netbox = { };
users.groups."${config.services.redis.servers.netbox.user}".members = [ "netbox" ];
+
+ assertions = [
+ {
+ assertion = (lib.versionAtLeast cfg.package.version "4.5") -> (cfg.apiTokenPeppersFile != null);
+ message = "NetBox 4.5 or newer require setting `services.netbox.apiTokenPeppersFile`";
+ }
+ ];
};
}
diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix
index 32c49bf3a0e9..ad85b07f30ce 100644
--- a/nixos/tests/all-tests.nix
+++ b/nixos/tests/all-tests.nix
@@ -1054,9 +1054,8 @@ in
neo4j = runTest ./neo4j.nix;
netbird = runTest ./netbird.nix;
netbox-upgrade = runTest ./web-apps/netbox-upgrade.nix;
- netbox_4_2 = handleTest ./web-apps/netbox/default.nix { netbox = pkgs.netbox_4_2; };
- netbox_4_3 = handleTest ./web-apps/netbox/default.nix { netbox = pkgs.netbox_4_3; };
netbox_4_4 = handleTest ./web-apps/netbox/default.nix { netbox = pkgs.netbox_4_4; };
+ netbox_4_5 = handleTest ./web-apps/netbox/default.nix { netbox = pkgs.netbox_4_5; };
netdata = runTest ./netdata.nix;
networking.networkd = handleTest ./networking/networkd-and-scripted.nix { networkd = true; };
networking.networkmanager = handleTest ./networking/networkmanager.nix { };
diff --git a/nixos/tests/web-apps/netbox-upgrade.nix b/nixos/tests/web-apps/netbox-upgrade.nix
index 5b60e8939ccb..ee84a6b34fd8 100644
--- a/nixos/tests/web-apps/netbox-upgrade.nix
+++ b/nixos/tests/web-apps/netbox-upgrade.nix
@@ -1,7 +1,7 @@
{ lib, pkgs, ... }:
let
- oldNetbox = "netbox_4_3";
- newNetbox = "netbox_4_4";
+ oldNetbox = "netbox_4_4";
+ newNetbox = "netbox_4_5";
apiVersion =
version:
@@ -38,6 +38,9 @@ in
secretKeyFile = pkgs.writeText "secret" ''
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789
'';
+ apiTokenPeppersFile = pkgs.writeText "pepper" ''
+ kp7ht*76fiQAhUi5dHfASLlYUE_S^gI^(7J^K5M!LfoH@vl&b_
+ '';
};
services.nginx = {
diff --git a/nixos/tests/web-apps/netbox/default.nix b/nixos/tests/web-apps/netbox/default.nix
index b614b965ae6d..803cf5c25ed3 100644
--- a/nixos/tests/web-apps/netbox/default.nix
+++ b/nixos/tests/web-apps/netbox/default.nix
@@ -37,6 +37,10 @@ import ../../make-test-python.nix (
secretKeyFile = pkgs.writeText "secret" ''
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789
'';
+ # Value from https://netbox.readthedocs.io/en/feature/configuration/required-parameters/#api_token_peppers
+ apiTokenPeppersFile = pkgs.writeText "pepper" ''
+ kp7ht*76fiQAhUi5dHfASLlYUE_S^gI^(7J^K5M!LfoH@vl&b_
+ '';
enableLdap = true;
ldapConfigPath = pkgs.writeText "ldap_config.py" ''
@@ -155,10 +159,32 @@ import ../../make-test-python.nix (
u.set_password('netbox')
u.save()
'';
+ createToken = pkgs.writeText "create-token-v2.py" ''
+ from users.models import Token, User
+ from users.choices import TokenVersionChoices
+ u = User.objects.first()
+ t = Token.objects.create(user=u, token="0123456789abcdef0123456789abcdef01234567", version=TokenVersionChoices.V2)
+ print(t.get_auth_header_prefix())
+ '';
+ netboxVersion = netbox.version;
in
builtins.replaceStrings
- [ "\${changePassword}" "\${testUser}" "\${testPassword}" "\${testGroup}" ]
- [ "${changePassword}" "${testUser}" "${testPassword}" "${testGroup}" ]
+ [
+ "\${changePassword}"
+ "\${testUser}"
+ "\${testPassword}"
+ "\${testGroup}"
+ "\${createToken}"
+ "\${netboxVersion}"
+ ]
+ [
+ "${changePassword}"
+ "${testUser}"
+ "${testPassword}"
+ "${testGroup}"
+ "${createToken}"
+ "${netboxVersion}"
+ ]
(lib.readFile "${./testScript.py}");
}
)
diff --git a/nixos/tests/web-apps/netbox/testScript.py b/nixos/tests/web-apps/netbox/testScript.py
index f6c2c9821e12..4ff035a1f0cf 100644
--- a/nixos/tests/web-apps/netbox/testScript.py
+++ b/nixos/tests/web-apps/netbox/testScript.py
@@ -73,18 +73,7 @@ with subtest("Superuser can be created"):
"netbox-manage createsuperuser --noinput --username netbox --email netbox@example.com"
)
# Django doesn't have a "clean" way of inputting the password from the command line
- machine.succeed("cat '${changePassword}' | netbox-manage shell")
-
-machine.wait_for_unit("network.target")
-
-with subtest("Home screen loads from nginx"):
- machine.succeed(
- "curl -sSfL http://localhost | grep '
Home | NetBox'"
- )
-
-with subtest("Staticfiles can be fetched"):
- machine.succeed("curl -sSfL http://localhost/static/netbox.js")
- machine.succeed("curl -sSfL http://localhost/static/docs/")
+ machine.succeed("cat '${changePassword}' | netbox-manage shell --interface python")
def login(username: str, password: str):
encoded_data = json.dumps({"username": username, "password": password})
@@ -101,8 +90,29 @@ def login(username: str, password: str):
)
return result["key"]
-with subtest("Can login"):
- auth_token = login("netbox", "netbox")
+
+netbox_version = "${netboxVersion}"
+if compare(netbox_version, '4.5.2') < 0:
+ with subtest("Can login"):
+ auth_token = login("netbox", "netbox")
+
+else:
+ with subtest("Superusertoken can be created"):
+ full_token = "0123456789abcdef0123456789abcdef01234567"
+ stdout = machine.succeed("cat ${createToken} | netbox-manage shell")
+ token_prefix = stdout.split(r"Bearer ")[-1].lstrip().rstrip()
+ auth_token = f"{token_prefix}{full_token}"
+
+machine.wait_for_unit("network.target")
+
+with subtest("Home screen loads from nginx"):
+ machine.succeed(
+ "curl -sSfL http://localhost | grep 'Home | NetBox'"
+ )
+
+with subtest("Staticfiles can be fetched"):
+ machine.succeed("curl -sSfL http://localhost/static/netbox.js")
+ machine.succeed("curl -sSfL http://localhost/static/docs/")
def get(uri: str):
return json.loads(
@@ -144,8 +154,8 @@ def post(uri: str, data: Dict[str, Any]):
def patch(uri: str, data: Dict[str, Any]):
return data_request(uri, "PATCH", data)
-# Retrieve netbox version
-netbox_version = get("/status/")["netbox-version"]
+with subtest("Can retrieve netbox version"):
+ assert netbox_version == get("/status/")["netbox-version"]
with subtest("Can create objects"):
result = post("/dcim/sites/", {"name": "Test site", "slug": "test-site"})
@@ -263,12 +273,15 @@ if compare(netbox_version, '4.2.0') < 0:
assert result["data"]["prefix_list"][0]["prefix"] == test_objects["prefixes"]["v4-with-updated-desc"]["prefix"]
assert int(result["data"]["prefix_list"][0]["site"]["id"]) == int(test_objects["prefixes"]["v4-with-updated-desc"]["scope"]["id"])
-with subtest("Can login with LDAP"):
- machine.wait_for_unit("openldap.service")
- login("alice", "${testPassword}")
+# With 4.5.2 and higher, obtaining a session cookie or token without supplying
+# proper CSRF tokens on the frontend /login/ endpoint is no longer possible
+if compare(netbox_version, '4.5.2') < 0:
+ with subtest("Can login with LDAP"):
+ machine.wait_for_unit("openldap.service")
+ login("alice", "${testPassword}")
-with subtest("Can associate LDAP groups"):
- result = get("/users/users/?username=${testUser}")
+ with subtest("Can associate LDAP groups"):
+ result = get("/users/users/?username=${testUser}")
- assert result["count"] == 1
- assert any(group["name"] == "${testGroup}" for group in result["results"][0]["groups"])
+ assert result["count"] == 1
+ assert any(group["name"] == "${testGroup}" for group in result["results"][0]["groups"])
diff --git a/pkgs/by-name/ne/netbox_4_2/package.nix b/pkgs/by-name/ne/netbox_4_2/package.nix
deleted file mode 100644
index ec7d07d0b243..000000000000
--- a/pkgs/by-name/ne/netbox_4_2/package.nix
+++ /dev/null
@@ -1,132 +0,0 @@
-{
- lib,
- fetchFromGitHub,
- python3,
- plugins ? _ps: [ ],
- nixosTests,
- nix-update-script,
-}:
-let
- py = python3.override {
- packageOverrides = _final: prev: { django = prev.django_5; };
- };
-
- extraBuildInputs = plugins py.pkgs;
-in
-py.pkgs.buildPythonApplication rec {
- pname = "netbox";
- version = "4.2.9";
-
- pyproject = false;
-
- src = fetchFromGitHub {
- owner = "netbox-community";
- repo = "netbox";
- tag = "v${version}";
- hash = "sha256-uVe4YTZoxRMBfvItFa9SMHu4AaVvygfAg9GDB115TFc=";
- };
-
- patches = [
- ./custom-static-root.patch
- ];
-
- propagatedBuildInputs =
- (
- with py.pkgs;
- [
- django
- django-cors-headers
- django-debug-toolbar
- django-filter
- django-graphiql-debug-toolbar
- django-htmx
- django-mptt
- django-pglocks
- django-prometheus
- django-redis
- django-rq
- django-tables2
- django-taggit
- django-timezone-field
- djangorestframework
- drf-spectacular
- drf-spectacular-sidecar
- feedparser
- jinja2
- markdown
- netaddr
- nh3
- pillow
- psycopg
- psycopg.optional-dependencies.c
- psycopg.optional-dependencies.pool
- pyyaml
- requests
- social-auth-core
- social-auth-app-django
- strawberry-graphql
- strawberry-django
- svgwrite
- tablib
-
- # Optional dependencies, kept here for backward compatibility
-
- # for the S3 data source backend
- boto3
- # for Git data source backend
- dulwich
- # for error reporting
- sentry-sdk
- ]
- ++ social-auth-core.passthru.optional-dependencies.openidconnect
- )
- ++ extraBuildInputs;
-
- buildInputs = with py.pkgs; [
- mkdocs-material
- mkdocs-material-extensions
- mkdocstrings
- mkdocstrings-python
- ];
-
- nativeBuildInputs = [ py.pkgs.mkdocs ];
-
- postBuild = ''
- PYTHONPATH=$PYTHONPATH:netbox/
- python -m mkdocs build
- '';
-
- installPhase = ''
- mkdir -p $out/opt/netbox
- cp -r . $out/opt/netbox
- chmod +x $out/opt/netbox/netbox/manage.py
- makeWrapper $out/opt/netbox/netbox/manage.py $out/bin/netbox \
- --prefix PYTHONPATH : "$PYTHONPATH"
- '';
-
- passthru = {
- python = python3;
- # PYTHONPATH of all dependencies used by the package
- pythonPath = py.pkgs.makePythonPath propagatedBuildInputs;
- inherit (py.pkgs) gunicorn;
- tests = {
- netbox = nixosTests.netbox_4_2;
- inherit (nixosTests) netbox-upgrade;
- };
- updateScript = nix-update-script { };
- };
-
- meta = {
- homepage = "https://github.com/netbox-community/netbox";
- description = "IP address management (IPAM) and data center infrastructure management (DCIM) tool";
- mainProgram = "netbox";
- license = lib.licenses.asl20;
- knownVulnerabilities = [
- "Netbox Version ${version} is EOL; please upgrade by following the current release notes instructions"
- ];
- maintainers = with lib.maintainers; [
- minijackson
- raitobezarius
- ];
- };
-}
diff --git a/pkgs/by-name/ne/netbox_4_3/custom-static-root.patch b/pkgs/by-name/ne/netbox_4_3/custom-static-root.patch
deleted file mode 100644
index c9219fa2b871..000000000000
--- a/pkgs/by-name/ne/netbox_4_3/custom-static-root.patch
+++ /dev/null
@@ -1,13 +0,0 @@
-diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py
-index 2de06dd10..00406af48 100644
---- a/netbox/netbox/settings.py
-+++ b/netbox/netbox/settings.py
-@@ -410,7 +412,7 @@ USE_X_FORWARDED_HOST = True
- X_FRAME_OPTIONS = 'SAMEORIGIN'
-
- # Static files (CSS, JavaScript, Images)
--STATIC_ROOT = BASE_DIR + '/static'
-+STATIC_ROOT = getattr(configuration, 'STATIC_ROOT', os.path.join(BASE_DIR, 'static')).rstrip('/')
- STATIC_URL = f'/{BASE_PATH}static/'
- STATICFILES_DIRS = (
- os.path.join(BASE_DIR, 'project-static', 'dist'),
diff --git a/pkgs/by-name/ne/netbox_4_4/package.nix b/pkgs/by-name/ne/netbox_4_4/package.nix
index 1a6bea9d66bf..80abaa7093f8 100644
--- a/pkgs/by-name/ne/netbox_4_4/package.nix
+++ b/pkgs/by-name/ne/netbox_4_4/package.nix
@@ -111,7 +111,7 @@ py.pkgs.buildPythonApplication rec {
pythonPath = py.pkgs.makePythonPath dependencies;
inherit (py.pkgs) gunicorn;
tests = {
- netbox = nixosTests.netbox_4_3;
+ netbox = nixosTests.netbox_4_4;
inherit (nixosTests) netbox-upgrade;
};
updateScript = nix-update-script { };
@@ -123,6 +123,9 @@ py.pkgs.buildPythonApplication rec {
description = "IP address management (IPAM) and data center infrastructure management (DCIM) tool";
mainProgram = "netbox";
license = lib.licenses.asl20;
+ knownVulnerabilities = [
+ "Netbox Version ${version} is EOL; please upgrade by following the current release notes instructions"
+ ];
maintainers = with lib.maintainers; [
minijackson
raitobezarius
diff --git a/pkgs/by-name/ne/netbox_4_2/custom-static-root.patch b/pkgs/by-name/ne/netbox_4_5/custom-static-root.patch
similarity index 100%
rename from pkgs/by-name/ne/netbox_4_2/custom-static-root.patch
rename to pkgs/by-name/ne/netbox_4_5/custom-static-root.patch
diff --git a/pkgs/by-name/ne/netbox_4_3/package.nix b/pkgs/by-name/ne/netbox_4_5/package.nix
similarity index 91%
rename from pkgs/by-name/ne/netbox_4_3/package.nix
rename to pkgs/by-name/ne/netbox_4_5/package.nix
index 3689a4177415..f080e6294209 100644
--- a/pkgs/by-name/ne/netbox_4_3/package.nix
+++ b/pkgs/by-name/ne/netbox_4_5/package.nix
@@ -16,14 +16,14 @@ let
in
py.pkgs.buildPythonApplication rec {
pname = "netbox";
- version = "4.3.7";
+ version = "4.5.5";
pyproject = false;
src = fetchFromGitHub {
owner = "netbox-community";
repo = "netbox";
tag = "v${version}";
- hash = "sha256-xVOP1D3C12M0M8oTrCA0M17NLuor+46UwiaKymSAVJM=";
+ hash = "sha256-he+WNbzIZSc2q97YjnAKHeFR0MDZCkDuAF/mfgAZuU4=";
};
patches = [
@@ -34,6 +34,7 @@ py.pkgs.buildPythonApplication rec {
(
with py.pkgs;
[
+ colorama
django
django-cors-headers
django-debug-toolbar
@@ -63,6 +64,7 @@ py.pkgs.buildPythonApplication rec {
requests
social-auth-core
social-auth-app-django
+ sorl-thumbnail
strawberry-graphql
strawberry-django
svgwrite
@@ -109,7 +111,7 @@ py.pkgs.buildPythonApplication rec {
pythonPath = py.pkgs.makePythonPath dependencies;
inherit (py.pkgs) gunicorn;
tests = {
- netbox = nixosTests.netbox_4_3;
+ netbox = nixosTests.netbox_4_5;
inherit (nixosTests) netbox-upgrade;
};
updateScript = nix-update-script { };
@@ -121,9 +123,6 @@ py.pkgs.buildPythonApplication rec {
description = "IP address management (IPAM) and data center infrastructure management (DCIM) tool";
mainProgram = "netbox";
license = lib.licenses.asl20;
- knownVulnerabilities = [
- "Netbox Version ${version} is EOL; please upgrade by following the current release notes instructions"
- ];
maintainers = with lib.maintainers; [
minijackson
raitobezarius
diff --git a/pkgs/development/python-modules/strawberry-django/default.nix b/pkgs/development/python-modules/strawberry-django/default.nix
index 777e3ebccbd2..b7b256cc71c7 100644
--- a/pkgs/development/python-modules/strawberry-django/default.nix
+++ b/pkgs/development/python-modules/strawberry-django/default.nix
@@ -34,14 +34,14 @@
buildPythonPackage rec {
pname = "strawberry-django";
- version = "0.74.1";
+ version = "0.75.1";
pyproject = true;
src = fetchFromGitHub {
owner = "strawberry-graphql";
repo = "strawberry-django";
tag = version;
- hash = "sha256-8T5lYM5JrxbeDCgvSGvBsimsF+tMwjS1hroqw2Gf7aA=";
+ hash = "sha256-vosD0JZYZzzl6Mp+AAxdXVox/7ay4FqnwqE6f1lSw3s=";
};
postPatch = ''
diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix
index f5046a7f2fea..4380dac2f84f 100644
--- a/pkgs/top-level/all-packages.nix
+++ b/pkgs/top-level/all-packages.nix
@@ -2996,7 +2996,7 @@ with pkgs;
};
# Not in aliases because it wouldn't get picked up by callPackage
- netbox = netbox_4_4;
+ netbox = netbox_4_5;
netcap-nodpi = callPackage ../by-name/ne/netcap/package.nix {
withDpi = false;