From 51e31d8854d0727ddf4b19da452e3027a170ff93 Mon Sep 17 00:00:00 2001 From: Adam Outler Date: Fri, 9 Jan 2026 01:34:31 +0000 Subject: [PATCH] Fixes for coderabbit. --- .../aufs-capabilities.md | 16 ++++-- .../test_container_environment.py | 2 +- test/docker_tests/test_puid_pgid.py | 50 ++++++++++--------- 3 files changed, 39 insertions(+), 29 deletions(-) diff --git a/docs/docker-troubleshooting/aufs-capabilities.md b/docs/docker-troubleshooting/aufs-capabilities.md index 8098f187..3fc48329 100644 --- a/docs/docker-troubleshooting/aufs-capabilities.md +++ b/docs/docker-troubleshooting/aufs-capabilities.md @@ -26,8 +26,11 @@ The container is designed to inspect the runtime environment at startup (`/root- ### Warning Log When AUFS is detected without root privileges, the system emits the following warning during startup: -> ⚠️ **WARNING:** Legacy AUFS storage driver detected. AUFS strips file capabilities (setcap). Layer-2 scanners will fail. -> **Action:** Set PUID=0 in your config or migrate off AUFS. +> ⚠️ WARNING: Reduced functionality (AUFS + non-root user). +> +> AUFS strips Linux file capabilities, so tools like arp-scan, nmap, and nbtscan fail when NetAlertX runs as a non-root PUID. +> +> **Action:** Set PUID=0 on AUFS hosts for full functionality. ## Security Ramifications @@ -144,12 +147,15 @@ docker exec netalertx getcap /usr/sbin/arp-scan ``` **3. Simulating AUFS (Dev/Test)** -Developers can force the AUFS logic path on a modern machine by mocking the mounts file: +Developers can force the AUFS logic path on a modern machine by mocking the mounts file. Note: Docker often restricts direct bind-mounts of host `/proc` paths, so the test suite uses an environment-variable injection instead (see `test_puid_pgid.py`). ```bash -echo "none / aufs rw,relatime 0 0" > /tmp/mock_mounts -docker run --rm -v /tmp/mock_mounts:/proc/mounts:ro netalertx/netalertx +# Create mock mounts content and encode it as base64 +echo "none / aufs rw,relatime 0 0" | base64 +# Run the container passing the encoded mounts via NETALERTX_PROC_MOUNTS_B64 +# (the entrypoint decodes this and uses it instead of reading /proc/mounts directly) +docker run --rm -e NETALERTX_PROC_MOUNTS_B64="bm9uZSAvIGF1ZnMgcncs..." netalertx/netalertx ``` ## Additional Resources diff --git a/test/docker_tests/test_container_environment.py b/test/docker_tests/test_container_environment.py index d9bc956b..a20b770b 100644 --- a/test/docker_tests/test_container_environment.py +++ b/test/docker_tests/test_container_environment.py @@ -665,7 +665,7 @@ def _run_container( stdout=subprocess.PIPE, # MUST capture stdout for test assertions and debugging stderr=subprocess.PIPE, # MUST capture stderr for test assertions and debugging text=True, - timeout=max(SUBPROCESS_TIMEOUT_SECONDS, sleep_seconds), # Coderabbit - please stop trying to increase the length of timeout. + timeout=max(SUBPROCESS_TIMEOUT_SECONDS, sleep_seconds), # Coderabbit - please stop trying to increase the length of timeout. check=False, ) diff --git a/test/docker_tests/test_puid_pgid.py b/test/docker_tests/test_puid_pgid.py index 024aa4db..a7df8a2b 100644 --- a/test/docker_tests/test_puid_pgid.py +++ b/test/docker_tests/test_puid_pgid.py @@ -248,20 +248,22 @@ def test_aufs_explicit_root_no_warning() -> None: mock_file_path = f"/tmp/mock_mounts_{uuid.uuid4().hex[:8]}" with open(mock_file_path, "w") as f: f.write(mock_mounts_content) - # Run with explicit PUID=0 - should not warn about non-root - result = _run_root_entrypoint( - env={"PUID": "0", "PGID": "0", "SKIP_TESTS": "1"}, - volumes=[f"{volume}:/data", f"{mock_file_path}:/proc/mounts:ro"], - ) + try: + # Run with explicit PUID=0 - should not warn about non-root + result = _run_root_entrypoint( + env={"PUID": "0", "PGID": "0", "SKIP_TESTS": "1"}, + volumes=[f"{volume}:/data", f"{mock_file_path}:/proc/mounts:ro"], + ) - combined = (result.stdout or "") + (result.stderr or "") - assert result.returncode == 0, f"Container should start: {combined}" - assert "Running as root (PUID=0)" in combined, f"Should confirm running as root: {combined}" - # Should NOT have the AUFS reduced functionality warning when running as root - assert "Reduced functionality (AUFS + non-root user)" not in combined, f"Should not warn when explicitly using root: {combined}" - - # Clean up mock file - os.unlink(mock_file_path) + combined = (result.stdout or "") + (result.stderr or "") + assert result.returncode == 0, f"Container should start: {combined}" + assert "Running as root (PUID=0)" in combined, f"Should confirm running as root: {combined}" + # Should NOT have the AUFS reduced functionality warning when running as root + assert "Reduced functionality (AUFS + non-root user)" not in combined, f"Should not warn when explicitly using root: {combined}" + finally: + # Clean up mock file + if os.path.exists(mock_file_path): + os.unlink(mock_file_path) finally: subprocess.run(["docker", "volume", "rm", "-f", volume], check=False, capture_output=True, text=True, timeout=15) @@ -281,17 +283,19 @@ def test_aufs_non_root_warns() -> None: with open(mock_file_path, "w") as f: f.write(mock_mounts_content) - result = _run_root_entrypoint( - env={"PUID": "20211", "PGID": "20211"}, - volumes=[f"{volume}:/data", f"{mock_file_path}:/proc/mounts:ro"], - ) + try: + result = _run_root_entrypoint( + env={"PUID": "20211", "PGID": "20211"}, + volumes=[f"{volume}:/data", f"{mock_file_path}:/proc/mounts:ro"], + ) - combined = (result.stdout or "") + (result.stderr or "") - assert result.returncode == 0, f"Container should continue with warnings: {combined}" - assert "Reduced functionality (AUFS + non-root user)" in combined, f"AUFS warning missing: {combined}" - assert "aufs-capabilities" in combined, "Warning should link to troubleshooting guide" - - os.unlink(mock_file_path) + combined = (result.stdout or "") + (result.stderr or "") + assert result.returncode == 0, f"Container should continue with warnings: {combined}" + assert "Reduced functionality (AUFS + non-root user)" in combined, f"AUFS warning missing: {combined}" + assert "aufs-capabilities" in combined, "Warning should link to troubleshooting guide" + finally: + if os.path.exists(mock_file_path): + os.unlink(mock_file_path) finally: subprocess.run(["docker", "volume", "rm", "-f", volume], check=False, capture_output=True, text=True, timeout=15)