diff --git a/src/core/src/core_logic/ServiceManager.py b/src/core/src/core_logic/ServiceManager.py index 6e865a6e..00f87e15 100644 --- a/src/core/src/core_logic/ServiceManager.py +++ b/src/core/src/core_logic/ServiceManager.py @@ -101,7 +101,7 @@ def create_service_unit_file(self, exec_start, desc, after="network.target", ser service_unit_content = service_unit_content_template.format(desc, after, service_type, exec_start, wanted_by) service_unit_path = self.__systemd_service_unit_path.format(self.service_name) self.env_layer.file_system.write_with_retry(service_unit_path, service_unit_content) - self.env_layer.run_command_output("sudo chmod a+x " + service_unit_path) + self.env_layer.run_command_output("sudo chmod 644 " + service_unit_path) # 644 = Owner: RW; Group: R; Others: R # endregion diff --git a/src/core/src/core_logic/TimerManager.py b/src/core/src/core_logic/TimerManager.py index e10fa0ca..df9556b5 100644 --- a/src/core/src/core_logic/TimerManager.py +++ b/src/core/src/core_logic/TimerManager.py @@ -114,5 +114,5 @@ def create_timer_unit_file(self, desc, on_unit_active_sec="3h", on_boot_sec="15m timer_unit_content = timer_unit_content_template.format(desc, on_boot_sec, on_unit_active_sec) timer_unit_path = self.__systemd_timer_unit_path.format(self.service_name) self.env_layer.file_system.write_with_retry(timer_unit_path, timer_unit_content) - self.env_layer.run_command_output("sudo chmod a+x " + timer_unit_path) - # endregion \ No newline at end of file + self.env_layer.run_command_output("sudo chmod 644 " + timer_unit_path) # 644 = Owner: RW; Group: R; Others: R + # endregion diff --git a/src/core/tests/Test_ServiceManager.py b/src/core/tests/Test_ServiceManager.py new file mode 100644 index 00000000..7de69a68 --- /dev/null +++ b/src/core/tests/Test_ServiceManager.py @@ -0,0 +1,50 @@ +# Copyright 2025 Microsoft Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Requires Python 2.7+ + +import unittest + +from core.tests.library.ArgumentComposer import ArgumentComposer +from core.tests.library.RuntimeCompositor import RuntimeCompositor +from core.src.core_logic.ServiceManager import ServiceManager +from core.src.core_logic.ServiceManager import ServiceInfo + +class TestServiceManager(unittest.TestCase): + def setUp(self): + self.runtime = RuntimeCompositor(ArgumentComposer().get_composed_arguments(), legacy_mode=True) + self.container = self.runtime.container + + def tearDown(self): + self.runtime.stop() + + def mock_run_command_to_set_service_file_permission(self, cmd, no_output=False, chk_err=False): + parts = cmd.split() + if parts[1] == "chmod" and parts[2] == "644": + return 0, "permissions set" + else: + raise Exception + + def mock_write_with_retry_valid(self, file_path_or_handle, data, mode='a+'): + return + + def test_create_service_unit_file(self): + service_manager = ServiceManager(self.runtime.env_layer, self.runtime.execution_config, self.runtime.composite_logger, self.runtime.telemetry_writer, ServiceInfo("AutoAssessment","Auto assessment service","path")) + service_manager.env_layer.run_command_output = self.mock_run_command_to_set_service_file_permission + service_manager.env_layer.file_system.write_with_retry = self.mock_write_with_retry_valid + service_manager.create_service_unit_file(exec_start="/bin/bash " + service_manager.service_exec_path, desc="Microsoft Azure Linux Patch Extension - Auto Assessment") + + +if __name__ == '__main__': + unittest.main() diff --git a/src/core/tests/Test_TimerManager.py b/src/core/tests/Test_TimerManager.py new file mode 100644 index 00000000..8dcf49b4 --- /dev/null +++ b/src/core/tests/Test_TimerManager.py @@ -0,0 +1,50 @@ +# Copyright 2025 Microsoft Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Requires Python 2.7+ + +import unittest + +from core.tests.library.ArgumentComposer import ArgumentComposer +from core.tests.library.RuntimeCompositor import RuntimeCompositor +from core.src.core_logic.TimerManager import TimerManager +from core.src.core_logic.ServiceManager import ServiceInfo + +class TestTimerManager(unittest.TestCase): + def setUp(self): + self.runtime = RuntimeCompositor(ArgumentComposer().get_composed_arguments(), legacy_mode=True) + self.container = self.runtime.container + + def tearDown(self): + self.runtime.stop() + + def mock_run_command_to_set_service_file_permission(self, cmd, no_output=False, chk_err=False): + parts = cmd.split() + if parts[1] == "chmod" and parts[2] == "644": + return 0, "permissions set" + else: + raise Exception + + def mock_write_with_retry_valid(self, file_path_or_handle, data, mode='a+'): + return + + def test_create_timer_unit_file(self): + service_manager = TimerManager(self.runtime.env_layer, self.runtime.execution_config, self.runtime.composite_logger, self.runtime.telemetry_writer, ServiceInfo("AutoAssessment","Auto assessment service","path")) + service_manager.env_layer.run_command_output = self.mock_run_command_to_set_service_file_permission + service_manager.env_layer.file_system.write_with_retry = self.mock_write_with_retry_valid + service_manager.create_timer_unit_file(desc="Microsoft Azure Linux Patch Extension - Auto Assessment Timer") + + +if __name__ == '__main__': + unittest.main() diff --git a/src/extension/src/ActionHandler.py b/src/extension/src/ActionHandler.py index 9e753c6d..98ca85ba 100644 --- a/src/extension/src/ActionHandler.py +++ b/src/extension/src/ActionHandler.py @@ -352,7 +352,7 @@ def disable(self): "\r\n# Copyright 2021 Microsoft Corporation" + \ "\r\n printf \"Auto-assessment was paused by the Azure Linux Patch Extension.\"" self.env_layer.file_system.write_with_retry(auto_assess_sh_path, auto_assess_sh_data) - self.env_layer.run_command_output("chmod a+x " + auto_assess_sh_path) + self.env_layer.run_command_output("chmod 744 " + auto_assess_sh_path) # 744 = Owner: RWX; Group: R; Others: R # Clear temp folder self.ext_env_handler.delete_temp_folder_contents() diff --git a/src/extension/src/ProcessHandler.py b/src/extension/src/ProcessHandler.py index da140603..93e8e252 100644 --- a/src/extension/src/ProcessHandler.py +++ b/src/extension/src/ProcessHandler.py @@ -126,7 +126,7 @@ def stage_auto_assess_sh_safely(self, core_process_command): if os.path.exists(auto_assess_sh_path): os.remove(auto_assess_sh_path) self.env_layer.file_system.write_with_retry(auto_assess_sh_path, auto_assess_sh_data) - self.env_layer.run_command_output("chmod a+x " + auto_assess_sh_path) + self.env_layer.run_command_output("chmod 744 " + auto_assess_sh_path) # 744 = Owner: RWX; Group: R; Others: R self.logger.log_debug("Completed staging auto assessment shell script with latest config.") except Exception as error: