diff --git a/hbd/client/plugins/nagios_runner.py b/hbd/client/plugins/nagios_runner.py index 8a0e37c..d2b0c22 100644 --- a/hbd/client/plugins/nagios_runner.py +++ b/hbd/client/plugins/nagios_runner.py @@ -89,12 +89,29 @@ class NagiosRunnerPlugin(MonitorPlugin): if not self.commands: self.skip_reason = "no commands configured (add nagios_runner.commands to config)" return False - + self.logger.info(f"Configured to run {len(self.commands)} Nagios plugin(s)") for cmd_config in self.commands: name = cmd_config.get("name", "unnamed") self.logger.info(f" - {name}: {cmd_config.get('command', 'N/A')}") - + + # Validate absolute command paths early + for cmd_config in self.commands: + name = cmd_config.get("name", "unnamed") + command = cmd_config.get("command", "") + if not command: + continue + exe = command.split()[0] + if os.path.isabs(exe): + if not os.path.isfile(exe): + self.logger.warning( + f"Command '{name}': executable not found: {exe}" + ) + elif not os.access(exe, os.X_OK): + self.logger.warning( + f"Command '{name}': executable not executable: {exe}" + ) + return True async def _collect_metrics(self) -> Dict[str, Any]: diff --git a/tests/test_nagios_runner.py b/tests/test_nagios_runner.py index b2e05c9..8cc6aba 100644 --- a/tests/test_nagios_runner.py +++ b/tests/test_nagios_runner.py @@ -60,3 +60,42 @@ def test_negative_returncode_maps_to_unknown(): assert data["t_status_code"] == NAGIOS_UNKNOWN assert "signal" in data["t_output"].lower() + + +def test_absolute_path_not_found_warns(caplog): + fake_cmd = "/nonexistent_hbc_test_path/check_something" + config = {"commands": [{"name": "t", "command": fake_cmd}]} + plugin = NagiosRunnerPlugin(config=config) + + with caplog.at_level(logging.WARNING, logger="plugin.nagios_runner"): + asyncio.run(plugin.initialize()) + + assert any("not found" in r.message for r in caplog.records) + + +def test_absolute_path_not_executable_warns(caplog, tmp_path): + non_exec = tmp_path / "check_test" + non_exec.write_text("#!/bin/sh\necho OK\n") + non_exec.chmod(0o644) # readable but not executable + + config = {"commands": [{"name": "t", "command": str(non_exec)}]} + plugin = NagiosRunnerPlugin(config=config) + + with caplog.at_level(logging.WARNING, logger="plugin.nagios_runner"): + asyncio.run(plugin.initialize()) + + assert any("not executable" in r.message for r in caplog.records) + + +def test_relative_path_not_checked(caplog): + # Relative paths (resolved via PATH) must not generate warnings + config = {"commands": [{"name": "t", "command": "echo OK"}]} + plugin = NagiosRunnerPlugin(config=config) + + with caplog.at_level(logging.WARNING, logger="plugin.nagios_runner"): + asyncio.run(plugin.initialize()) + + assert not any( + "not found" in r.message or "not executable" in r.message + for r in caplog.records + )