# Copyright 2026 SigmaSRC, Inc. All Rights Reserved.

"""Suppress console windows for child processes on Windows.

The agent runs many external commands every gather cycle -- the "command"
gatherer (gather_command.py), individual gathers, and engine rule code -- via
``os.popen(...)`` and ``subprocess.Popen(..., shell=True)``. On Windows each of
those launches ``cmd.exe``, and unless the ``CREATE_NO_WINDOW`` creation flag is
set the console pops a **visible window**. When the agent runs as a service that
means a cmd window flashes on the interactive user's desktop on every cycle --
disruptive, and it makes the agent look like something is wrong.

There are ~20 command call sites across gather/runtime and ``os.popen()`` can't
take ``creationflags`` at all, so rather than edit every site we patch
``subprocess.Popen`` once -- ``os.popen`` is implemented on top of it -- to add
``CREATE_NO_WINDOW`` unless the caller explicitly asked for a specific console.
The agent never needs a visible console for a child process, so this is safe.

The scheduler's own task launcher (sched/winprocess.py) already hides its
children via ``STARTUPINFO``/``SW_HIDE``; this covers the ``subprocess``/
``os.popen`` calls those tasks make, which SW_HIDE does not.

Call ``suppress_child_windows()`` once at each agent entrypoint, right after
``ensure_utf8_mode()``. It is a no-op off Windows and idempotent.
"""

import sys

# CreateProcess flags (winbase.h). Not all are exposed by subprocess on every
# Python, so define the one we need and detect the "caller wants a console"
# flags defensively.
CREATE_NO_WINDOW = 0x08000000


def suppress_child_windows():
    """Make subprocess/os.popen child processes run without a console window."""
    if sys.platform != "win32":
        return

    import subprocess

    orig_init = subprocess.Popen.__init__
    if getattr(orig_init, "_sigma_no_window", False):
        return  # already patched

    # If the caller explicitly chose console behaviour, don't override it.
    respect = (CREATE_NO_WINDOW
               | getattr(subprocess, "CREATE_NEW_CONSOLE", 0x00000010)
               | getattr(subprocess, "DETACHED_PROCESS", 0x00000008))

    def __init__(self, *args, **kwargs):
        flags = kwargs.get("creationflags", 0)
        if not (flags & respect):
            kwargs["creationflags"] = flags | CREATE_NO_WINDOW
        orig_init(self, *args, **kwargs)

    __init__._sigma_no_window = True
    subprocess.Popen.__init__ = __init__


# This module cannot be used as a main program
if __name__ == "__main__":
    sys.stderr.write("ERROR: This module cannot be used as a main program\n")
    sys.exit(2)
