{ "tests": [ { "file": "conftest.py", "testname": "build_netalertx_test_image", "conditions": "normal", "expected_results": [ "* Docker test image 'netalertx-test' is built using docker buildx before any docker-based tests run", "* If docker buildx fails, all docker tests are skipped with failure message" ] }, { "file": "test_container_environment.py", "testname": "test_nonroot_custom_uid_logs_note", "conditions": [ "* Container run with arbitrary non-root UID/GID (1001:1001 or 1502:1502)", "* Fresh named volume at /data" ], "expected_results": [ "* Container logs message about current UID/GID", "* Log contains 'expected UID' guidance", "* Container exits with returncode 0" ] }, { "file": "test_container_environment.py", "testname": "test_missing_capabilities_triggers_warning", "conditions": [ "* All capabilities dropped (cap_drop: ALL)", "* No NET_ADMIN, NET_RAW, NET_BIND_SERVICE" ], "expected_results": [ "* 'exec /bin/sh: operation not permitted' error in output", "* Non-zero return code" ] }, { "file": "test_container_environment.py", "testname": "test_running_as_root_is_blocked", "conditions": [ "* Container run as user: 0 (root)" ], "expected_results": [ "* Warning 'NetAlertX is running as ROOT' in output", "* Message 'Permissions fixed for read-write paths.' in output", "* Container exits with returncode 0 (warns but continues)" ] }, { "file": "test_container_environment.py", "testname": "test_missing_host_network_warns", "conditions": [ "* Container run without network_mode: host (bridge/default network)" ], "expected_results": [ "* Warning 'not running with --network=host' in output" ] }, { "file": "test_container_environment.py", "testname": "test_missing_app_conf_triggers_seed", "conditions": [ "* Fresh named volume with no app.conf file" ], "expected_results": [ "* 'Default configuration written to' message in output", "* Container exits with returncode 0" ] }, { "file": "test_container_environment.py", "testname": "test_missing_app_db_triggers_seed", "conditions": [ "* Named volume with app.conf but no app.db file" ], "expected_results": [ "* Database file /data/db/app.db is created", "* Container exits with returncode 0" ] }, { "file": "test_container_environment.py", "testname": "test_custom_port_without_writable_conf", "conditions": [ "* Custom PORT=24444 and LISTEN_ADDR=127.0.0.1 environment variables set", "* Nginx config mount (/tmp/nginx/active-config) is read-only (mode=500)" ], "expected_results": [ "* 'Unable to write to' message in output", "* Reference to '/tmp/nginx/active-config/netalertx.conf' in output", "* Non-zero return code" ] }, { "file": "test_container_environment.py", "testname": "test_excessive_capabilities_warning", "conditions": [ "* Container run with extra capabilities beyond required (SYS_ADMIN, NET_BROADCAST)" ], "expected_results": [ "* 'Excessive capabilities detected' message in output", "* 'bounding caps:' list in output" ] }, { "file": "test_container_environment.py", "testname": "test_appliance_integrity_read_write_mode", "conditions": [ "* Container root filesystem is read-write (not read-only mode)" ], "expected_results": [ "* 'Container is running as read-write, not in read-only mode' warning in output" ] }, { "file": "test_container_environment.py", "testname": "test_zero_permissions_app_db_dir", "conditions": [ "* /data/db directory has chmod 000 (no permissions)" ], "expected_results": [ "* Mounts table shows ❌ for writeable status on /data/db", "* 'Configuration issues detected' message in output", "* Non-zero return code" ] }, { "file": "test_container_environment.py", "testname": "test_zero_permissions_app_config_dir", "conditions": [ "* /data/config directory has chmod 000 (no permissions)" ], "expected_results": [ "* Mounts table shows ❌ for writeable status on /data/config", "* 'Configuration issues detected' message in output", "* Non-zero return code" ] }, { "file": "test_container_environment.py", "testname": "test_mandatory_folders_creation", "conditions": [ "* Plugins log directory (/tmp/log/plugins) is missing" ], "expected_results": [ "* 'Creating Plugins log' message in output", "* Mandatory folders are automatically created" ] }, { "file": "test_container_environment.py", "testname": "test_writable_config_validation", "conditions": [ "* app.conf is a directory instead of a regular file" ], "expected_results": [ "* 'ATTENTION: Path is not a regular file.' warning in output" ] }, { "file": "test_container_environment.py", "testname": "test_mount_analysis_ram_disk_performance", "conditions": [ "* Persistent paths (/data/db, /data/config) mounted on tmpfs RAM disk" ], "expected_results": [ "* Mounts table shows ✅ writeable, ✅ mount, ❌ ramdisk, ❌ dataloss for db and config paths", "* 'Configuration issues detected' message in output", "* Non-zero return code" ] }, { "file": "test_container_environment.py", "testname": "test_mount_analysis_dataloss_risk", "conditions": [ "* Persistent database/config paths mounted on non-persistent tmpfs filesystem" ], "expected_results": [ "* Mounts table shows dataloss risk warnings for persistent paths", "* 'Configuration issues detected' message in output", "* Non-zero return code" ] }, { "file": "test_container_environment.py", "testname": "test_restrictive_permissions_handling", "conditions": [ "* Directory mounted with restrictive permissions (root:root, 755)" ], "expected_results": [ "* Non-root user case: fails to write or shows 'Permission denied'/'Unable to write'", "* Root user case: 'NetAlertX is running as ROOT' and 'Permissions fixed for read-write paths' messages", "* After root fix: netalertx user can write to directory" ] }, { "file": "test_docker_compose_scenarios.py", "testname": "test_missing_capabilities_compose", "conditions": [ "* Docker compose with cap_drop: ALL (all capabilities dropped)", "* Uses docker-compose.missing-caps.yml" ], "expected_results": [ "* 'exec /root-entrypoint.sh: operation not permitted' error in output", "* Non-zero return code" ] }, { "file": "test_docker_compose_scenarios.py", "testname": "test_custom_port_with_unwritable_nginx_config_compose", "conditions": [ "* Custom PORT=24444 environment variable", "* Unwritable nginx config mount", "* Uses docker-compose.mount-test.active_config_unwritable.yml" ], "expected_results": [ "* 'unable to write' or 'nginx' message in output", "* 'failed to chown' message in output", "* 'cap_chown' reference in output", "* 'missing-capabilities.md' documentation link in output", "* Container exits with returncode 0 (warns but continues)" ] }, { "file": "test_docker_compose_scenarios.py", "testname": "test_host_network_compose", "conditions": "normal", "expected_results": [ "* Container starts successfully with host networking", "* No 'not running with --network=host' warning", "* Container exits with returncode 0" ] }, { "file": "test_docker_compose_scenarios.py", "testname": "test_normal_startup_no_warnings_compose", "conditions": "normal", "expected_results": [ "* 'Startup pre-checks' message in output", "* No ❌ symbols in output", "* /data row in mounts table shows ✅ for readable and writeable", "* No 'Write permission denied' message", "* No 'CRITICAL' messages", "* No ⚠️ warning symbols", "* No 'arning' or 'rror' text (case insensitive partial match for Warning/Error)" ] }, { "file": "test_docker_compose_scenarios.py", "testname": "test_ram_disk_mount_analysis_compose", "conditions": [ "* /data path mounted as tmpfs (RAM disk)", "* Persistent data on non-persistent storage" ], "expected_results": [ "* 'Configuration issues detected' message in output", "* /data path appears in mounts table", "* Non-zero return code due to dataloss risk" ] }, { "file": "test_docker_compose_scenarios.py", "testname": "test_dataloss_risk_mount_analysis_compose", "conditions": [ "* Persistent /data path mounted on tmpfs with uid=20211,gid=20211", "* Non-persistent filesystem for persistent data" ], "expected_results": [ "* 'Configuration issues detected' message in output", "* /data path appears in output", "* Non-zero return code due to dataloss risk" ] }, { "file": "test_entrypoint.py", "testname": "test_skip_tests_env_var", "conditions": [ "* SKIP_TESTS=1 environment variable set" ], "expected_results": [ "* 'Skipping startup checks as SKIP_TESTS is set.' message in stdout", "* No ' --> ' check output markers", "* Container exits with returncode 0" ] }, { "file": "test_entrypoint.py", "testname": "test_app_conf_override_from_graphql_port", "conditions": [ "* GRAPHQL_PORT=20212 environment variable set", "* APP_CONF_OVERRIDE is not set", "* SKIP_TESTS=1 to skip checks" ], "expected_results": [ "* 'APP_CONF_OVERRIDE detected' message in stderr", "* No 'Setting APP_CONF_OVERRIDE to' message in stdout", "* Container exits with returncode 0" ] }, { "file": "test_entrypoint.py", "testname": "test_app_conf_override_not_overridden", "conditions": [ "* Both GRAPHQL_PORT=20212 and APP_CONF_OVERRIDE={\"OTHER\":\"value\"} set", "* SKIP_TESTS=1 to skip checks" ], "expected_results": [ "* No 'Setting APP_CONF_OVERRIDE to' message (existing override preserved)", "* Container exits with returncode 0" ] }, { "file": "test_entrypoint.py", "testname": "test_no_app_conf_override_when_no_graphql_port", "conditions": [ "* GRAPHQL_PORT is not set", "* SKIP_TESTS=1 to skip checks" ], "expected_results": [ "* No 'Setting APP_CONF_OVERRIDE to' message", "* Container exits with returncode 0" ] }, { "file": "test_mount_diagnostics_pytest.py", "testname": "test_mount_diagnostic", "conditions": [ "* Parameterized test for each mount configuration scenario", "* Scenarios: no-mount, ramdisk, mounted, unwritable for each path (db, config, api, log, run, active_config)", "* Additional noread scenarios: data_noread, db_noread, tmp_noread, api_noread" ], "expected_results": [ "* For issue scenarios: diagnostic table shows appropriate ❌/✅/➖ symbols", "* For issue scenarios: troubleshooting URL present in output", "* For issue scenarios: ⚠️ warning symbol in output", "* For good config scenarios: table output with 'Path' header", "* For good config scenarios: no ⚠️ warning symbol", "* Container exit code matches expected (usually 0)" ] }, { "file": "test_mount_diagnostics_pytest.py", "testname": "test_table_parsing", "conditions": "normal", "expected_results": [ "* parse_mount_table correctly parses sample mount diagnostic table", "* assert_table_row correctly validates row values", "* ✅=True, ❌=False, ➖=None emoji mapping works" ] }, { "file": "test_mount_diagnostics_pytest.py", "testname": "test_cap_chown_required_when_caps_dropped", "conditions": [ "* CAP_CHOWN capability is missing", "* Uses docker-compose.mount-test.cap_chown_missing.yml" ], "expected_results": [ "* Container continues with warnings (exit code 0)", "* 'failed to chown' message in logs", "* 'CAP_CHOWN' reference in logs", "* Troubleshooting URL present in logs" ] }, { "file": "test_ports_available.py", "testname": "test_ports_available_normal_case", "conditions": [ "* PORT=99991 and GRAPHQL_PORT=99992 (non-conflicting, unused ports)" ], "expected_results": [ "* No 'Configuration Warning: Both ports are set to' message", "* No 'Port Warning: Application port' message", "* No 'Port Warning: GraphQL API port' message", "* Container exits with returncode 0" ] }, { "file": "test_ports_available.py", "testname": "test_ports_conflict_same_number", "conditions": [ "* PORT=20211 and GRAPHQL_PORT=20211 (both set to same port)" ], "expected_results": [ "* 'Configuration Warning: Both ports are set to 20211' message", "* 'The Application port ($PORT) and the GraphQL API port' message", "* 'are configured to use the' and 'same port. This will cause a conflict.' messages", "* Container exits with returncode 0 (warns but continues)" ] }, { "file": "test_ports_available.py", "testname": "test_ports_in_use_warning", "conditions": [ "* Dummy container already occupying ports 20211 and 20212", "* PORT=20211 and GRAPHQL_PORT=20212 configured" ], "expected_results": [ "* 'Port Warning: Application port 20211 is already in use' message", "* 'Port Warning: GraphQL API port 20212 is already in use' message", "* Container exits with returncode 0 (warns but continues)" ] }, { "file": "test_puid_pgid.py", "testname": "test_default_puid_pgid_ok", "conditions": [ "* SKIP_TESTS=1 to skip startup checks", "* Default PUID/PGID values" ], "expected_results": [ "* Container exits with returncode 0" ] }, { "file": "test_puid_pgid.py", "testname": "test_invalid_puid_pgid_rejected", "conditions": [ "* Various invalid PUID/PGID values:", " - PUID='0;rm -rf /' (shell injection attempt)", " - PUID='$(id)' (command substitution attempt)", " - PUID='-1' (negative value)", " - PUID='99999999' (out of range)", " - PGID='99999999' (out of range)" ], "expected_results": [ "* Non-zero return code", "* 'invalid characters' or 'out of range' message in output depending on test case" ] }, { "file": "test_puid_pgid.py", "testname": "test_legacy_user_mode_skips_puid_pgid", "conditions": [ "* PUID=1000 and PGID=1000 environment variables set", "* Container run with --user 20211:20211 (legacy mode)" ], "expected_results": [ "* 'PUID/PGID (1000:1000) will not be applied' message in output", "* Container exits with returncode 0" ] }, { "file": "test_puid_pgid.py", "testname": "test_synology_like_fresh_volume_is_primed", "conditions": [ "* Fresh named volume with root-owned directories (simulating Synology behavior)", "* PUID=1000 and PGID=1000 target ownership" ], "expected_results": [ "* Container exits with returncode 0", "* Volume ownership changed to 1000:1000 for /data, /data/config, /data/db" ] }, { "file": "test_puid_pgid.py", "testname": "test_missing_cap_chown_fails_priming", "conditions": [ "* Named volume with UID 1000 ownership", "* PUID=20212, PGID=20212 (needs chown)", "* CAP_CHOWN capability removed" ], "expected_results": [ "* Container continues with warnings (exit code 0)", "* 'failed to chown' message in output", "* 'missing-capabilities' reference in output", "* 'docs/docker-troubleshooting/missing-capabilities.md' documentation link" ] }, { "file": "test_docker_compose_scenarios.py", "testname": "test_missing_net_admin_compose", "conditions": [ "* docker-compose.missing-net-admin.yml", "* Missing NET_ADMIN capability" ], "expected_results": [ "* 'Raw network capabilities are missing' warning in output", "* Container exits with returncode 0" ] }, { "file": "test_docker_compose_scenarios.py", "testname": "test_missing_net_raw_compose", "conditions": [ "* docker-compose.missing-net-raw.yml", "* Missing NET_RAW capability" ], "expected_results": [ "* 'Raw network capabilities are missing' warning in output", "* Container exits with returncode 0" ] } ] }