Skip to content

Conversation

@tboy1337
Copy link

@tboy1337 tboy1337 commented Aug 30, 2025

Refactors PostgreSQLExecutor to improve Windows compatibility and security for PostgreSQL process management. This change addresses platform-specific issues with process termination and command formatting that could cause failures on Windows systems.

Changes

  • Unified command format: Converted _get_base_command method to BASE_PROC_START_COMMAND class attribute with cross-platform compatible syntax (removed single quotes around PostgreSQL config values that caused issues on Windows)
  • Graceful Windows termination: Added _windows_terminate_process method that attempts graceful shutdown before force-killing stuck processes
  • Improved security: Updated stop() method to use list arguments instead of shell=True to prevent shell injection vulnerabilities
  • Platform-specific logic: Added intelligent platform detection with fallback handling for os.killpg AttributeError on Windows
  • Comprehensive test coverage: Added 186 lines of Windows compatibility tests covering various termination scenarios and command formatting

Test plan

  • ✅ New test suite in tests/test_windows_compatibility.py with 7 test cases
  • ✅ Tests verify unified command format without single quotes
  • ✅ Tests verify graceful termination and force-kill timeout handling
  • ✅ Tests verify platform-specific stop behavior (Windows vs Unix)
  • ✅ Tests verify fallback logic for killpg AttributeError
  • ✅ Tests verify command formatting with Windows paths

Summary by CodeRabbit

  • Bug Fixes

    • Improved cross‑platform PostgreSQL process management: unified startup command quoting across platforms, Windows shutdown now attempts graceful termination with a force‑kill fallback, and teardown reliably cleans up data directories.
  • Tests

    • Added comprehensive Windows compatibility tests to validate command formatting, startup/shutdown behaviour, forced‑kill fallback and fallback handling when platform process group signals are unavailable.

✏️ Tip: You can customize this high-level summary in your review settings.

@tboy1337 tboy1337 mentioned this pull request Aug 30, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 21, 2026

Warning

Rate limit exceeded

@tboy1337 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 17 minutes and 53 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

Walkthrough

Replaces static start-command quoting with cross‑platform command assembly, adds _windows_terminate_process() and Windows-specific stop branching with a fallback when os.killpg is unavailable, adjusts stop to run pg_ctl as a list (no shell), and ensures cleanup in __del__. New Windows-focused tests added.

Changes

Cohort / File(s) Summary
Core executor
pytest_postgresql/executor.py
Adjusted base start-command formatting/quoting for cross‑platform use; added import os; added _windows_terminate_process(self, sig: Optional[int]=None); refactored stop() to build pg_ctl as a list, branch Windows vs non‑Windows, and fall back when os.killpg is unavailable; expanded __del__ to ensure cleanup. Review termination/wait/timeout logic and command assembly.
Windows compatibility tests
tests/test_windows_compatibility.py
New test suite TestWindowsCompatibility covering base command formatting, Windows termination flows (graceful, timeout→force kill), stop() branching (Windows, Unix, fallback), and command formatting assertions using mocks/patches. Review mocks/patches and platform simulation.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Executor as PostgreSQLExecutor
    participant OS as OperatingSystem
    participant Proc as PostgreSQLProcess

    Client->>Executor: call stop()
    Executor->>Executor: assemble pg_ctl stop command (list)
    alt Windows
        Executor->>OS: start pg_ctl stop (no-shell list)
        Executor->>Executor: invoke _windows_terminate_process()
        Executor->>Proc: send terminate(), wait()
        alt timeout
            Executor->>Proc: send kill(), wait()
            Proc-->>Executor: killed
        else terminated
            Proc-->>Executor: terminated
        end
    else Non‑Windows
        Executor->>OS: call super().stop() (uses os.killpg)
        alt AttributeError (killpg missing)
            Executor->>Executor: fallback to _windows_terminate_process()
        end
    end
    Executor-->>Client: return self / stop result
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐰 I nibble quotes and mend the line,
I gently tap the process spine,
On Windows coax, on timeout pry,
A tidy stop — a whispered bye,
Hoppity hop, the sockets shine!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarises the main objective of the pull request: refactoring PostgreSQLExecutor to add Windows compatibility for process management.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@pytest_postgresql/executor.py`:
- Around line 263-283: In stop(self, sig: Optional[int] = None, exp_sig:
Optional[int] = None) replace the subprocess.check_output call that builds a
shell string with a list-style invocation (e.g., [self.executable, "stop", "-D",
self.datadir, "-m", "f"]) and remove shell=True so subprocess runs the
executable directly; this avoids breaking paths with spaces and removes the
shell injection risk while keeping the same arguments and behavior before the
platform-specific termination logic (_windows_terminate_process / super().stop).
- Around line 53-66: The _get_base_command constructs the -o string with
unix_socket_directories unquoted which breaks for paths with spaces; update
_get_base_command to detect whitespace in the unixsocketdir variable and wrap
that value in double quotes (or escape quotes) when building the -o option so
the produced fragment becomes -c unix_socket_directories="/path/with space"
(referencing the unix_socket_directories token and BASE_PROC_START_COMMAND
assignment), and add a unit test that passes a datadir/unixsocketdir containing
a space to ensure the command line includes the quoted socket directory (or
alternatively, add explicit validation/documentation and raise a clear error
when whitespace is present).
🧹 Nitpick comments (1)
pytest_postgresql/executor.py (1)

231-262: Tidy up the termination helper API surface.

sig is unused in _windows_terminate_process, and _unix_terminate_process is currently unused. Either wire _unix_terminate_process into stop() for symmetry and use sig, or drop/rename the parameter to avoid dead code and lint noise.

@tboy1337 tboy1337 force-pushed the edit branch 2 times, most recently from 5d4fb91 to efa4633 Compare January 21, 2026 07:59
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@tests/test_windows_compatibility.py`:
- Around line 35-39: The test assertions in tests/test_windows_compatibility.py
don't match the actual string produced by _get_base_command(): update the
assertions to expect the escaped-quote form for unix_socket_directories (i.e.,
include the backslash-escaped double quotes around {unixsocketdir}) and assert
that the non-quoted form is not present; specifically change the positive
assertion referencing unix_socket_directories to look for
unix_socket_directories=\"{unixsocketdir}\" and keep the negative assertion for
unix_socket_directories='{unixsocketdir}' to ensure consistency with
_get_base_command().
- Around line 189-204: The test's expected_parts entry for
unix_socket_directories doesn't match the actual command string (which includes
escaped quotes), so update the expectation in the test to match the
implementation: replace the "-c unix_socket_directories=C:/temp/socket" entry
with the escaped-quote form that appears in executor.command (e.g., -c
unix_socket_directories=\"C:/temp/socket\"), keeping the rest of the
expected_parts and the loop over executor.command unchanged; reference the test
variable executor.command and the expected_parts list when making the change.
🧹 Nitpick comments (2)
pytest_postgresql/executor.py (2)

25-25: Unused import signal.

The signal module is imported but not used anywhere in the file. This appears to be a leftover from development.

🧹 Suggested fix
-import signal

250-269: Good refactor to list-based subprocess call.

The change from shell string to list format ([self.executable, "stop", "-D", self.datadir, "-m", "f"]) properly addresses the previous security concern and handles paths with spaces correctly.

One minor observation: the AttributeError fallback (lines 263-268) uses string matching "killpg" in str(e) which is somewhat fragile. Consider whether this fallback is still needed given the explicit platform.system() check now handles Windows upfront.

@tboy1337 tboy1337 requested a review from fizyk January 21, 2026 08:33
@tboy1337 tboy1337 force-pushed the edit branch 2 times, most recently from b02c61b to 4a0b22e Compare January 21, 2026 10:24
@tboy1337 tboy1337 force-pushed the edit branch 2 times, most recently from 059e4bc to 54140ac Compare January 29, 2026 05:40
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@pytest_postgresql/executor.py`:
- Around line 226-246: The parameter sig in _windows_terminate_process is
intentionally unused and triggers Ruff ARG002; either rename it to _sig to
indicate it’s intentionally unused or keep sig and add a local lint suppression
(e.g., append a noqa comment for ARG002) where the function is defined to
silence the warning; update the function signature (or add the noqa) in the
_windows_terminate_process definition and run linters to confirm the ARG002
warning is resolved.

…ess management

- Convert _get_base_command method to BASE_PROC_START_COMMAND class attribute

- Use unified command format without single quotes around PostgreSQL config values

- Add _windows_terminate_process method for graceful Windows process termination

- Update stop() method to use list args instead of shell=True for security

- Add platform-specific termination logic with killpg fallback

- Add comprehensive Windows compatibility test suite

- Rename parameter in _windows_terminate_process method for clarity
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants