From 6e8d8ef5a036f93570d9ce9dcb5239ba3ee5204b Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 22 Jul 2026 15:11:20 +0800 Subject: [PATCH] fix(signoz): exclude controller ancestors from process guard --- agent99-signoz-metadata-executor.ps1 | 5 +- ...oz_metadata_executor_runtime_entrypoint.py | 125 ++++++++++++++++-- 2 files changed, 121 insertions(+), 9 deletions(-) diff --git a/agent99-signoz-metadata-executor.ps1 b/agent99-signoz-metadata-executor.ps1 index 842e7e90e..2f8d7b66d 100644 --- a/agent99-signoz-metadata-executor.ps1 +++ b/agent99-signoz-metadata-executor.ps1 @@ -181,7 +181,10 @@ function New-Agent99SignozLockedRemoteCommand { "[ `"`$(/usr/bin/timeout --kill-after=5s 15s /usr/bin/docker inspect --format={{.State.Running}} $SignozContainer)`" = `"true`" ]; " + "[ `"`$(/usr/bin/timeout --kill-after=5s 15s /usr/bin/curl -sS -o /dev/null -w `"%{http_code}`" $BaseUrl/api/v1/health)`" = `"200`" ]; " + "set +e; active_output=`$(/usr/bin/timeout --kill-after=5s 10s /usr/bin/pgrep -af `"([s]ignoz-metadata-export[.]py|[s]ignoz-metadata-restore-drill[.]py|(^|/|[[:space:]])([b]ackup-signoz|[c]lickhouse-native-backup|[c]lickhouse-native-restore-drill|[r]un-signoz-backup-canary)[.]sh([[:space:]]|$))`"); active_rc=`$?; set -e; " + - "[ `"`$active_rc`" -eq 1 ] && [ -z `"`$active_output`" ]; " + + "[ `"`$active_rc`" -eq 0 ] || [ `"`$active_rc`" -eq 1 ]; " + + "set +e; external_output=`$(/usr/bin/printf `"%s\n`" `"`$active_output`" | /usr/bin/grep -Ev `"^(`$`$|`$PPID)[[:space:]]`"); filter_rc=`$?; set -e; " + + "[ `"`$filter_rc`" -eq 0 ] || [ `"`$filter_rc`" -eq 1 ]; " + + "[ -z `"`$external_output`" ]; " + "exec /usr/bin/timeout --signal=TERM --kill-after=$($TargetKillAfterSeconds)s " + "$($TargetTimeoutSeconds)s $FixedCommand'" ) diff --git a/scripts/ops/tests/test_agent99_signoz_metadata_executor_runtime_entrypoint.py b/scripts/ops/tests/test_agent99_signoz_metadata_executor_runtime_entrypoint.py index 5e69747e6..dbde961d2 100644 --- a/scripts/ops/tests/test_agent99_signoz_metadata_executor_runtime_entrypoint.py +++ b/scripts/ops/tests/test_agent99_signoz_metadata_executor_runtime_entrypoint.py @@ -1,8 +1,11 @@ from __future__ import annotations import re +import subprocess from pathlib import Path +import pytest + ROOT = Path(__file__).resolve().parents[3] ENTRYPOINT = ROOT / "agent99-signoz-metadata-executor.ps1" @@ -50,6 +53,10 @@ def test_entrypoint_is_fixed_to_windows99_host110_and_p0_obs_002() -> None: def test_entrypoint_uses_fixed_public_key_transport_and_no_arbitrary_shell() -> None: source = ENTRYPOINT.read_text(encoding="utf-8") + lock_helper = source[ + source.index("function New-Agent99SignozLockedRemoteCommand") : + source.index("function Get-Agent99RuntimeSourceBinding") + ] assert 'Start-Process -FilePath "ssh.exe"' in source assert '"-o", "BatchMode=yes"' in source @@ -91,19 +98,121 @@ def test_entrypoint_uses_fixed_public_key_transport_and_no_arbitrary_shell() -> assert "target_timeout_not_bounded_before_controller_wait" in source assert '--kill-after=5s 15s /usr/bin/docker inspect' in source assert '--kill-after=5s 15s /usr/bin/curl' in source - assert '--kill-after=5s 10s /usr/bin/pgrep' in source - assert "active_rc=`$?; set -e" in source - assert '[ `"`$active_rc`" -eq 1 ]' in source - assert '[ -z `"`$active_output`" ]' in source - lock_helper = source[ - source.index("function New-Agent99SignozLockedRemoteCommand") : - source.index("function Get-Agent99RuntimeSourceBinding") - ] + assert '--kill-after=5s 10s /usr/bin/pgrep' in lock_helper + assert "active_rc=`$?; set -e" in lock_helper + assert ( + '[ `"`$active_rc`" -eq 0 ] || [ `"`$active_rc`" -eq 1 ]' + in lock_helper + ) + assert ( + '/usr/bin/grep -Ev `"^(`$`$|`$PPID)[[:space:]]`"' + in lock_helper + ) + assert "filter_rc=`$?; set -e" in lock_helper + assert ( + '[ `"`$filter_rc`" -eq 0 ] || [ `"`$filter_rc`" -eq 1 ]' + in lock_helper + ) + assert '[ -z `"`$external_output`" ]' in lock_helper + assert lock_helper.index("active_rc=`$?; set -e") < lock_helper.index( + "filter_rc=`$?; set -e" + ) < lock_helper.index('[ -z `"`$external_output`" ]') assert "pgrep -af" in lock_helper assert "|| true" not in lock_helper assert '--signal=TERM --kill-after=$($TargetKillAfterSeconds)s' in source +def _render_locked_process_gate() -> str: + source = ENTRYPOINT.read_text(encoding="utf-8") + helper = source[ + source.index("function New-Agent99SignozLockedRemoteCommand") : + source.index("function Get-Agent99RuntimeSourceBinding") + ] + block = helper[ + helper.index(' "set +e; active_output=') : + helper.index(' "exec /usr/bin/timeout') + ] + rendered_parts: list[str] = [] + for line in block.splitlines(): + literal = line.strip() + assert literal.startswith('"') and literal.endswith('" +') + literal = literal[1:-3] + rendered = [] + index = 0 + while index < len(literal): + if literal[index] == "`": + index += 1 + assert index < len(literal) + rendered.append(literal[index]) + index += 1 + rendered_parts.append("".join(rendered)) + rendered_block = "".join(rendered_parts) + gate_start = rendered_block.index( + '[ "$active_rc" -eq 0 ] || [ "$active_rc" -eq 1 ]; ' + ) + return rendered_block[gate_start:] + + +@pytest.mark.parametrize( + ("pgrep_rc", "row_scenario", "expected"), + ( + (1, "empty", True), + (0, "ancestors", True), + (0, "external", False), + (2, "empty", False), + (124, "empty", False), + ), +) +def test_locked_process_guard_rendered_shell_behavior( + pgrep_rc: int, + row_scenario: str, + expected: bool, +) -> None: + setup = { + "empty": 'active_output=""; ', + "ancestors": ( + 'active_output="$$ bash -c fixed-export\n' + '$PPID sudo bash -c fixed-export"; ' + ), + "external": ( + 'active_output="$$ bash -c fixed-export\n' + '$PPID sudo bash -c fixed-export\n' + '812 python3 signoz-metadata-export.py --apply"; ' + ), + }[row_scenario] + completed = subprocess.run( + ( + "/bin/bash", + "-c", + f"set -euo pipefail; active_rc={pgrep_rc}; {setup}" + f"{_render_locked_process_gate()}printf guard_accepted", + ), + check=False, + capture_output=True, + text=True, + ) + assert (completed.returncode == 0) is expected + assert (completed.stdout == "guard_accepted") is expected + + +def test_locked_process_guard_rendered_filter_error_fails_closed() -> None: + gate = _render_locked_process_gate() + filter_gate = gate[gate.index('[ "$filter_rc" -eq 0 ]') :] + completed = subprocess.run( + ( + "/bin/bash", + "-c", + "set -euo pipefail; filter_rc=2; external_output=\"\"; " + f"{filter_gate}printf guard_accepted", + ), + check=False, + capture_output=True, + text=True, + ) + assert completed.returncode != 0 + assert completed.stdout == "" + + def test_entrypoint_uses_typed_stdout_without_windows_process_exit_code() -> None: source = ENTRYPOINT.read_text(encoding="utf-8") transport = source[