netbox_4_5: init at 4.5.5 (#485109)
This commit is contained in:
@@ -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).
|
||||
|
||||
@@ -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`";
|
||||
}
|
||||
];
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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 { };
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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}");
|
||||
}
|
||||
)
|
||||
|
||||
@@ -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 '<title>Home | NetBox</title>'"
|
||||
)
|
||||
|
||||
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 '<title>Home | NetBox</title>'"
|
||||
)
|
||||
|
||||
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"])
|
||||
|
||||
@@ -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
|
||||
];
|
||||
};
|
||||
}
|
||||
@@ -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'),
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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 = ''
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user